From e0bd09a2462a3917164c63e69091ac620b777202 Mon Sep 17 00:00:00 2001
From: Maarten Sijm <9739541+mpsijm@users.noreply.github.com>
Date: Tue, 7 Jun 2022 15:41:12 +0200
Subject: [PATCH 1/3] Fix #127: Don't ignore removeDuplicates option when using
officialSorting
The check for removing duplicates is completely separate from the
sorting, even when {officialSorting: false}. Therefore, it shouldn't
harm to also execute this check when {officialSorting: true}.
---
docs/rules/classnames-order.md | 2 +-
lib/rules/classnames-order.js | 8 ++++----
tests/lib/rules/classnames-order.js | 10 ++++++++++
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/docs/rules/classnames-order.md b/docs/rules/classnames-order.md
index ffbfeb0e..2dfe3fe0 100644
--- a/docs/rules/classnames-order.md
+++ b/docs/rules/classnames-order.md
@@ -118,7 +118,7 @@ const customGroups = require('custom-groups').groups;
### `officialSorting` (default: `false`)
-Set `officialSorting` to `true` if you want to use the same ordering rules as the official plugin `prettier-plugin-tailwindcss`. Enabling this settings will cause `groupByResponsive`, `groups`, `prependCustom` and `removeDuplicates` options to be ignored.
+Set `officialSorting` to `true` if you want to use the same ordering rules as the official plugin `prettier-plugin-tailwindcss`. Enabling this setting will cause `groupByResponsive`, `groups`, and `prependCustom` options to be ignored.
### `prependCustom` (default: `false`)
diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js
index 96307043..b8c7c388 100644
--- a/lib/rules/classnames-order.js
+++ b/lib/rules/classnames-order.js
@@ -309,6 +309,10 @@ module.exports = {
return;
}
+ if (removeDuplicates) {
+ removeDuplicatesFromClassnamesAndWhitespaces(classNames, whitespaces, headSpace, tailSpace);
+ }
+
let orderedClassNames;
let validatedClassNamesValue = '';
@@ -323,10 +327,6 @@ module.exports = {
}
}
} else {
- if (removeDuplicates) {
- removeDuplicatesFromClassnamesAndWhitespaces(classNames, whitespaces, headSpace, tailSpace);
- }
-
// Sorting
const mergedSorted = [];
const mergedExtras = [];
diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js
index 130c5366..df79d70b 100644
--- a/tests/lib/rules/classnames-order.js
+++ b/tests/lib/rules/classnames-order.js
@@ -817,6 +817,16 @@ ruleTester.run("classnames-order", rule, {
},
],
},
+ {
+ code: `
Using official sorting, with duplicates
`,
+ output: `Using official sorting, with duplicates
`,
+ errors: errors,
+ options: [
+ {
+ officialSorting: true,
+ },
+ ],
+ },
{
code: `ctl(\`\${some} container animate-spin first:flex \${bool ? "flex-col flex" : ""}\`)`,
output: `ctl(\`\${some} container animate-spin first:flex \${bool ? "flex flex-col" : ""}\`)`,
From 9a979647b2abf3256ab10008ede167e9b1035e1c Mon Sep 17 00:00:00 2001
From: Maarten Sijm <9739541+mpsijm@users.noreply.github.com>
Date: Tue, 7 Jun 2022 15:53:06 +0200
Subject: [PATCH 2/3] Extract duplicate code that converts ordered classNames
back to attribute value
---
lib/rules/classnames-order.js | 32 +++++++++++++-------------------
1 file changed, 13 insertions(+), 19 deletions(-)
diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js
index b8c7c388..bae16b39 100644
--- a/lib/rules/classnames-order.js
+++ b/lib/rules/classnames-order.js
@@ -314,20 +314,11 @@ module.exports = {
}
let orderedClassNames;
- let validatedClassNamesValue = '';
+ // Sorting
if (officialSorting) {
orderedClassNames = order(classNames, contextFallback);
- for (let i = 0; i < orderedClassNames.length; i++) {
- 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] ?? '';
- }
- }
} else {
- // Sorting
const mergedSorted = [];
const mergedExtras = [];
if (groupByResponsive) {
@@ -343,18 +334,21 @@ module.exports = {
mergedExtras.push(...extras);
}
- // Generates the validated/sorted attribute value
const flatted = mergedSorted.flat();
- const union = prependCustom ? [...mergedExtras, ...flatted] : [...flatted, ...mergedExtras];
- for (let i = 0; i < union.length; i++) {
- const w = whitespaces[i] ?? '';
- const cls = union[i];
- validatedClassNamesValue += headSpace ? `${w}${cls}` : `${cls}${w}`;
- if (headSpace && tailSpace && i === union.length - 1) {
- validatedClassNamesValue += whitespaces[whitespaces.length - 1] ?? '';
- }
+ orderedClassNames = prependCustom ? [...mergedExtras, ...flatted] : [...flatted, ...mergedExtras];
+ }
+
+ // Generates the validated/sorted attribute value
+ let validatedClassNamesValue = '';
+ for (let i = 0; i < orderedClassNames.length; i++) {
+ 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 (originalClassNamesValue !== validatedClassNamesValue) {
validatedClassNamesValue = prefix + validatedClassNamesValue + suffix;
context.report({
From 3954659b8f7bd02fd6a430fe91eb3f75f602ad5c Mon Sep 17 00:00:00 2001
From: Maarten Sijm <9739541+mpsijm@users.noreply.github.com>
Date: Tue, 7 Jun 2022 16:08:31 +0200
Subject: [PATCH 3/3] #136: Remove duplicates from ordered classNames instead
of unordered classNames
---
lib/rules/classnames-order.js | 8 +++----
...eDuplicatesFromClassnamesAndWhitespaces.js | 24 +++++++++----------
tests/lib/rules/classnames-order.js | 6 ++---
3 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js
index bae16b39..051936c4 100644
--- a/lib/rules/classnames-order.js
+++ b/lib/rules/classnames-order.js
@@ -309,10 +309,6 @@ module.exports = {
return;
}
- if (removeDuplicates) {
- removeDuplicatesFromClassnamesAndWhitespaces(classNames, whitespaces, headSpace, tailSpace);
- }
-
let orderedClassNames;
// Sorting
@@ -338,6 +334,10 @@ module.exports = {
orderedClassNames = prependCustom ? [...mergedExtras, ...flatted] : [...flatted, ...mergedExtras];
}
+ if (removeDuplicates) {
+ removeDuplicatesFromClassnamesAndWhitespaces(orderedClassNames, whitespaces, headSpace, tailSpace);
+ }
+
// Generates the validated/sorted attribute value
let validatedClassNamesValue = '';
for (let i = 0; i < orderedClassNames.length; i++) {
diff --git a/lib/util/removeDuplicatesFromClassnamesAndWhitespaces.js b/lib/util/removeDuplicatesFromClassnamesAndWhitespaces.js
index 1b1ea51f..f660273c 100644
--- a/lib/util/removeDuplicatesFromClassnamesAndWhitespaces.js
+++ b/lib/util/removeDuplicatesFromClassnamesAndWhitespaces.js
@@ -1,20 +1,18 @@
'use strict';
-function removeDuplicatesFromClassnamesAndWhitespaces(classNames, whitespaces, headSpace, tailSpace) {
- const uniqueSet = new Set(classNames);
- if (uniqueSet.size === classNames.length) {
- return;
- }
+function removeDuplicatesFromClassnamesAndWhitespaces(orderedClassNames, whitespaces, headSpace, tailSpace) {
+ let previous = orderedClassNames[0];
const offset = (!headSpace && !tailSpace) || tailSpace ? -1 : 0;
- uniqueSet.forEach((cls) => {
- let duplicatedInstances = classNames.filter((el) => el === cls).length - 1;
- while (duplicatedInstances > 0) {
- const idx = classNames.lastIndexOf(cls);
- classNames.splice(idx, 1);
- whitespaces.splice(idx + offset, 1);
- duplicatedInstances--;
+ for (let i = 1; i < orderedClassNames.length; i++) {
+ const cls = orderedClassNames[i];
+ // This function assumes that the list of classNames is ordered, so just comparing to the previous className is enough
+ if (cls === previous) {
+ orderedClassNames.splice(i, 1);
+ whitespaces.splice(i + offset, 1);
+ i--;
}
- });
+ previous = cls;
+ }
}
module.exports = removeDuplicatesFromClassnamesAndWhitespaces;
diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js
index df79d70b..c67ea0fc 100644
--- a/tests/lib/rules/classnames-order.js
+++ b/tests/lib/rules/classnames-order.js
@@ -382,17 +382,17 @@ ruleTester.run("classnames-order", rule, {
},
{
code: `Single line dups + no head/tail spaces
`,
- output: `Single line dups + no head/tail spaces
`,
+ output: `Single line dups + no head/tail spaces
`,
errors: errors,
},
{
code: `Single dups line + head spaces
`,
- output: `Single dups line + head spaces
`,
+ output: `Single dups line + head spaces
`,
errors: errors,
},
{
code: `Single line dups + tail spaces
`,
- output: `Single line dups + tail spaces
`,
+ output: `Single line dups + tail spaces
`,
errors: errors,
},
{