diff --git a/packages/eslint-plugin/lib/rules/class-order.js b/packages/eslint-plugin/lib/rules/class-order.js
index 933315c1a..33b0986a4 100644
--- a/packages/eslint-plugin/lib/rules/class-order.js
+++ b/packages/eslint-plugin/lib/rules/class-order.js
@@ -123,8 +123,13 @@ module.exports = {
const w = whitespaces[i] ?? ''
const cls = orderedClassNames[i]
validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`
- if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
- validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? ''
+ if (cls) {
+ if (!tailSpace && i === orderedClassNames.length - 1) {
+ validatedClassNamesValue = validatedClassNamesValue.replace(/\s+$/, '')
+ }
+ if (headSpace && tailSpace && i === orderedClassNames.length - 1) {
+ validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? ''
+ }
}
}
diff --git a/packages/eslint-plugin/tests/order.test.js b/packages/eslint-plugin/tests/order.test.js
index 1ac4088f1..a50a15cd8 100644
--- a/packages/eslint-plugin/tests/order.test.js
+++ b/packages/eslint-plugin/tests/order.test.js
@@ -4,6 +4,7 @@ const RuleTester = require('eslint').RuleTester
new RuleTester({
parserOptions: {
+ ecmaVersion: 2019,
ecmaFeatures: {
jsx: true,
},
@@ -18,12 +19,95 @@ new RuleTester({
},
{
code: `
Simple, using 'test' prop
`,
+ settings: {
+ '@master/css': {
+ classMatching: '^test|class(Name)?$',
+ },
+ },
+ },
+ {
+ code: 'ctl + exp
',
+ },
+ {
+ code: 'ctl + var
',
+ },
+ {
+ code: 'Space trim issue
',
+ },
+ {
+ code: `
+ ctl(\`
+ flex align-items:center justify-content:center
+ \${ variant === SpinnerVariant.OVERLAY && \`rounded bg:gray-40 b:2 px:4 z:60 \${widthClass} \${heightClass}\`}
+ \${ variant === SpinnerVariant.FULLSCREEN &&
+ \`fixed bg:white@dark bottom:0 left:0 opacity:.6@dark px:4 right:0 top:0 z:60\`
+ }
+ \`)`,
+ },
+ {
+ code: `Simple quotes
`,
+ },
+ {
+ code: `Extra space at the end
`,
+ },
+ {
+ code: `Extra space at the end, but with 'tw' prop
`,
+ settings: {
+ '@master/css': {
+ classMatching: '^test|class(Name)?$',
+ },
+ },
+ },
+ {
+ code: `'p', then 'py' then 'px'
`,
+ },
+ {
+ code: `ctl(\`
+ container
+ flex
+ w:12
+ w:6@sm
+ w:4@lg
+ \`)`,
+ },
+ {
+ code: `Allowed arbitrary value
`,
+ },
+ {
+ code: `Stackable variants
`,
+ },
+ {
+ code: `clsx
`,
options: [
{
- classMatching: '^test$',
+ callees: ['clsx'],
},
],
},
+ {
+ code: `Number values
`,
+ settings: {
+ '@master/css': {
+ config: {
+ styles: { zDialog: 'z:10000' }
+ }
+ }
+ }
+ },
+ {
+ code: `Extra spaces
`,
+ },
+ {
+ code: `
+ Issue #131
+ `,
+ },
+ {
+ code: `No errors while typing
`,
+ },
+ {
+ code: `Do not treat full width space as class separator
`,
+ },
],
invalid: [
{
@@ -35,6 +119,335 @@ new RuleTester({
code: `Group
`,
output: `Group
`,
errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `Enhancing readability with 'test' prop
`,
+ output: `Enhancing readability with 'test' prop
`,
+ settings: {
+ '@master/css': {
+ classMatching: '^test|class(Name)?$',
+ },
+ },
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `:)...
`,
+ output: `:)...
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: 'ctl(`p:10 flex ${some}`)',
+ output: 'ctl(`flex p:10 ${some}`)',
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: 'Space trim issue with fix
',
+ output: 'Space trim issue with fix
',
+ errors: [
+ { messageId: 'invalidClassOrder' },
+ { messageId: 'invalidClassOrder' }
+ ],
+ },
+ {
+ code: `Simple quotes
`,
+ output: `Simple quotes
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ options: [
+ {
+ removeDuplicates: false,
+ },
+ ],
+ code: `removeDuplicates
`,
+ output: `removeDuplicates
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `Single line dups + no head/tail spaces
`,
+ output: `Single line dups + no head/tail spaces
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `Single dups line + head spaces
`,
+ output: `Single dups line + head spaces
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `Single line dups + tail spaces
`,
+ output: `Single line dups + tail spaces
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ // Multiline + both head/tail spaces
+ code: `
+ ctl(\`
+ hide
+ w:6@sm
+ block
+ hide
+ flex
+ block
+ w:12
+ flex
+ block
+ w:4@lg
+ w:4@lg
+ \`);`,
+ output: `
+ ctl(\`
+ block
+ flex
+ hide
+ w:12
+ w:6@sm
+ w:4@lg
+ \`);`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+ ctl(\`
+ invalid
+ w:6@sm
+ container
+ w:12
+ flex
+ w:4@lg
+ \`);`,
+ output: `
+ ctl(\`
+ invalid
+ container
+ flex
+ w:12
+ w:6@sm
+ w:4@lg
+ \`);`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+ const buttonClasses = ctl(\`
+ \${fullWidth ? "w:12" : "w:6"}
+ container
+ \${fullWidth ? "w:8@sm" : "w:4@sm"}
+ w:9@lg
+ flex
+ \${hasError && "bg:red"}
+ \`);`,
+ output: `
+ const buttonClasses = ctl(\`
+ \${fullWidth ? "w:12" : "w:6"}
+ container
+ \${fullWidth ? "w:8@sm" : "w:4@sm"}
+ flex
+ w:9@lg
+ \${hasError && "bg:red"}
+ \`);`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+ const buttonClasses = ctl(\`
+ \${fullWidth ? "w:12" : "w:6"}
+ flex
+ container
+ \${fullWidth ? "w:7@sm" : "w:4@sm"}
+ py:4@lg
+ py:6@sm
+ \${hasError && "bg:red"}
+ \`);`,
+ output: `
+ const buttonClasses = ctl(\`
+ \${fullWidth ? "w:12" : "w:6"}
+ container
+ flex
+ \${fullWidth ? "w:7@sm" : "w:4@sm"}
+ py:6@sm
+ py:4@lg
+ \${hasError && "bg:red"}
+ \`);`,
+ errors: [{ messageId: 'invalidClassOrder' }, { messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `Allowed arbitrary value but incorrect order
`,
+ output: `Allowed arbitrary value but incorrect order
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `clsx(\`abs bottom:0 w:full h:70px flex flex:col\`);`,
+ output: `clsx(\`abs flex bottom:0 flex:col h:70px w:full\`);`,
+ options: [
+ {
+ callees: ['clsx'],
+ },
+ ],
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `cva({
+ primary: ["abs bottom:0 w:full h:70px flex flex:col"],
+ })`,
+ output: `cva({
+ primary: ["abs flex bottom:0 flex:col h:70px w:full"],
+ })`,
+ options: [
+ {
+ callees: ['cva'],
+ },
+ ],
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `clsx
`,
+ output: `clsx
`,
+ options: [
+ {
+ callees: ['clsx'],
+ },
+ ],
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+ ctl(\`
+ px:2
+ flex
+ \${
+ !isDisabled &&
+ \`
+ top:0
+ flex
+ b:0
+ \`
+ }
+ \${
+ isDisabled &&
+ \`
+ mx:0
+ b:0
+ \`
+ }
+ \`)
+ `,
+ output: `
+ ctl(\`
+ flex
+ px:2
+ \${
+ !isDisabled &&
+ \`
+ flex
+ b:0
+ top:0
+ \`
}
+ \${
+ isDisabled &&
+ \`
+ b:0
+ mx:0
+ \`
+ }
+ \`)
+ `,
+ errors: [
+ { messageId: 'invalidClassOrder' },
+ { messageId: 'invalidClassOrder' },
+ { messageId: 'invalidClassOrder' }
+ ],
+ },
+ {
+ code: `...
`,
+ output: `...
`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `ctl(\`\${enabled && "px:2 flex"}\`)`,
+ output: `ctl(\`\${enabled && "flex px:2"}\`)`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `ctl(\`px:2 flex\`)`,
+ output: `ctl(\`flex px:2\`)`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+ ctl(\`
+ px:2
+ flex
+ \`)
+ `,
+ output: `
+ ctl(\`
+ flex
+ px:2
+ \`)
+ `,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+
+ `,
+ output: `
+
+ `,
+ errors: [{ messageId: 'invalidClassOrder' }, { messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+ classnames([
+ 'invalid w:4@lg w:6@sm',
+ ['w:12 flex'],
+ ])`,
+ output: `
+ classnames([
+ 'invalid w:6@sm w:4@lg',
+ ['flex w:12'],
+ ])`,
+ errors: [{ messageId: 'invalidClassOrder' }, { messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `
+ classnames({
+ invalid,
+ flex: myFlag,
+ 'w:4@lg w:6@sm': resize
+ })`,
+ output: `
+ classnames({
+ invalid,
+ flex: myFlag,
+ 'w:6@sm w:4@lg': resize
+ })`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `ctl(\`\${some} container animate-spin first:flex \${bool ? "flex:col flex" : ""}\`)`,
+ output: `ctl(\`\${some} container animate-spin first:flex \${bool ? "flex flex:col" : ""}\`)`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
+ {
+ code: `ctl(\`p:3 b:3|solid|gray m:4 h:24 p:4@lg flex b:2 m:4@lg\`)`,
+ output: `ctl(\`flex b:3|solid|gray b:2 h:24 m:4 m:4@lg p:3 p:4@lg\`)`,
+ errors: [{ messageId: 'invalidClassOrder' }],
+ },
],
})
\ No newline at end of file