Skip to content

feat: Enhance Twig template handling with addClass() support for Drupal syntax #358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
/dist
.DS_Store
125 changes: 71 additions & 54 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,8 @@ function transformLiquid(ast: any, { env }: TransformerContext) {
}) {
return Array.isArray(node.name)
? node.name.every(
(n) => n.type === 'TextNode' && staticAttrs.has(n.value),
)
(n) => n.type === 'TextNode' && staticAttrs.has(n.value),
)
: staticAttrs.has(node.name)
}

Expand Down Expand Up @@ -549,18 +549,18 @@ function sortTemplateLiteral(
quasi.value.cooked = same
? quasi.value.raw
: sortClasses(quasi.value.cooked, {
env,
ignoreFirst: i > 0 && !/^\s/.test(quasi.value.cooked),
ignoreLast:
i < node.expressions.length && !/\s$/.test(quasi.value.cooked),
collapseWhitespace: collapseWhitespace && {
start: collapseWhitespace && collapseWhitespace.start && i === 0,
end:
collapseWhitespace &&
collapseWhitespace.end &&
i >= node.expressions.length,
},
})
env,
ignoreFirst: i > 0 && !/^\s/.test(quasi.value.cooked),
ignoreLast:
i < node.expressions.length && !/\s$/.test(quasi.value.cooked),
collapseWhitespace: collapseWhitespace && {
start: collapseWhitespace && collapseWhitespace.start && i === 0,
end:
collapseWhitespace &&
collapseWhitespace.end &&
i >= node.expressions.length,
},
})

if (
quasi.value.raw !== originalRaw ||
Expand Down Expand Up @@ -846,6 +846,23 @@ function transformTwig(ast: any, { env, changes }: TransformerContext) {

StringLiteral(node, path, meta) {
if (!meta.sortTextNodes) {
// Check for .addClass() calls in Drupal Twig templates
const isAddClassCall = path.some((entry) => {
return (
entry.parent &&
entry.parent.type === 'CallExpression' &&
entry.parent.callee &&
entry.parent.callee.type === 'MemberExpression' &&
entry.parent.callee.property &&
entry.parent.callee.property.name === 'addClass'
)
})

if (isAddClassCall) {
node.value = sortClasses(node.value, { env })
return
}

return
}

Expand Down Expand Up @@ -952,12 +969,12 @@ function transformSvelte(ast: any, { env, changes }: TransformerContext) {
value.data = same
? value.raw
: sortClasses(value.data, {
env,
ignoreFirst: i > 0 && !/^\s/.test(value.data),
ignoreLast: i < attr.value.length - 1 && !/\s$/.test(value.data),
removeDuplicates: false,
collapseWhitespace: false,
})
env,
ignoreFirst: i > 0 && !/^\s/.test(value.data),
ignoreLast: i < attr.value.length - 1 && !/\s$/.test(value.data),
removeDuplicates: false,
collapseWhitespace: false,
})
} else if (value.type === 'MustacheTag') {
visit(value.expression, {
Literal(node) {
Expand Down Expand Up @@ -1135,58 +1152,58 @@ export const parsers: Record<string, Parser> = {

...(base.parsers.svelte
? {
svelte: createParser('svelte', transformSvelte, {
staticAttrs: ['class'],
}),
}
svelte: createParser('svelte', transformSvelte, {
staticAttrs: ['class'],
}),
}
: {}),
...(base.parsers.astro
? {
astro: createParser('astro', transformAstro, {
staticAttrs: ['class', 'className'],
dynamicAttrs: ['class:list', 'className'],
}),
}
astro: createParser('astro', transformAstro, {
staticAttrs: ['class', 'className'],
dynamicAttrs: ['class:list', 'className'],
}),
}
: {}),
...(base.parsers.astroExpressionParser
? {
astroExpressionParser: createParser(
'astroExpressionParser',
transformJavaScript,
{
staticAttrs: ['class'],
dynamicAttrs: ['class:list'],
},
),
}
astroExpressionParser: createParser(
'astroExpressionParser',
transformJavaScript,
{
staticAttrs: ['class'],
dynamicAttrs: ['class:list'],
},
),
}
: {}),
...(base.parsers.marko
? {
marko: createParser('marko', transformMarko, {
staticAttrs: ['class'],
}),
}
marko: createParser('marko', transformMarko, {
staticAttrs: ['class'],
}),
}
: {}),
...(base.parsers.twig
? {
twig: createParser('twig', transformTwig, {
staticAttrs: ['class'],
}),
}
twig: createParser('twig', transformTwig, {
staticAttrs: ['class'],
}),
}
: {}),
...(base.parsers.pug
? {
pug: createParser('pug', transformPug, {
staticAttrs: ['class'],
}),
}
pug: createParser('pug', transformPug, {
staticAttrs: ['class'],
}),
}
: {}),
...(base.parsers['liquid-html']
? {
'liquid-html': createParser('liquid-html', transformLiquid, {
staticAttrs: ['class'],
}),
}
'liquid-html': createParser('liquid-html', transformLiquid, {
staticAttrs: ['class'],
}),
}
: {}),
}

Expand Down
32 changes: 30 additions & 2 deletions tests/plugins.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ let tests: PluginTest[] = [
plugins: ['@zackad/prettier-plugin-twig'],
options: {
twigAlwaysBreakObjects: false,
tailwindFunctions: ['addClass'],
},
tests: {
twig: [
Expand Down Expand Up @@ -162,6 +163,33 @@ let tests: PluginTest[] = [
`<div class="{{ ' flex ' + ' underline ' + ' block ' }}"></div>`,
`<div class="{{ 'flex ' + ' underline' + ' block' }}"></div>`,
],

// Drupal attributes.addClass() tests
[
`<div {{ attributes.addClass("sm:p-0 p-0") }}></div>`,
`<div {{ attributes.addClass('p-0 sm:p-0') }}></div>`,
],
[
`{{ attributes.addClass("sm:p-0 p-0") }}`,
`{{ attributes.addClass('p-0 sm:p-0') }}`,
],
[
`{% set className = "p-0 sm:p-0" %}
{{ attributes.addClass(className) }}`,
`{% set className = 'p-0 sm:p-0' %}
{{ attributes.addClass(className) }}`,
],
[
`{{ attributes.addClass("sm:p-0 " ~ variant ~ " p-0") }}`,
`{{ attributes.addClass('sm:p-0' ~ variant ~ 'p-0') }}`,
],
[
`{{ attributes
.addClass("sm:p-0 p-0")
.addClass("flex block")
.addClass("underline") }}`,
`{{ attributes.addClass('p-0 sm:p-0').addClass('block flex').addClass('underline') }}`,
],
],
},
},
Expand Down Expand Up @@ -207,7 +235,7 @@ let tests: PluginTest[] = [
import './three'
import '@one/file'
import '@two/file'
export default function Foo() { return <div className="sm:p-0 p-4"></div> }
export default function Foo() { return <div className="p-4 sm:p-0"></div> }
`,
`import '@one/file'\nimport '@two/file'\n\nimport './three'\n\nexport default function Foo() {\n return <div className="p-4 sm:p-0"></div>\n}`,
],
Expand All @@ -219,7 +247,7 @@ let tests: PluginTest[] = [
tests: {
babel: [
[
`/**\n * @param { string } param0 description\n */\n export default function Foo(param0) { return <div className="sm:p-0 p-4"></div> }`,
`/**\n * @param { string } param0 description\n */\n export default function Foo(param0) { return <div className="p-4 sm:p-0"></div> }`,
`/** @param {string} param0 Description */\nexport default function Foo(param0) {\n return <div className="p-4 sm:p-0"></div>\n}`,
],
],
Expand Down