From ba742ee0f81ba0c39f66c847854cd7c082becd86 Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 20:30:04 +0900 Subject: [PATCH 1/9] support regex --- .../src/rules/no-unused-class-name.ts | 13 ++++++++++++- .../invalid/allowed-class-names/_config.json | 2 +- .../partially-allowed-class-name01-errors.yaml | 4 ++++ .../partially-allowed-class-name01-input.svelte | 2 ++ .../valid/allowed-class-names/_config.json | 2 +- .../allowed-class-name01-input.svelte | 2 ++ 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts index ad03b5c95..c22b6af23 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts @@ -57,7 +57,18 @@ export default createRule('no-unused-class-name', { ? findClassesInPostCSSNode(styleContext.sourceAst, sourceCode.parserServices) : []; for (const className in classesUsedInTemplate) { - if (!allowedClassNames.includes(className) && !classesUsedInStyle.includes(className)) { + if ( + !allowedClassNames.includes(className) && + !allowedClassNames.some((allowedClassName: string) => { + const regex = /^\/(.*)\/$/.exec(allowedClassName); + if (regex == null || regex[1] == null) { + return false; + } + + return new RegExp(regex[1]).test(className); + }) && + !classesUsedInStyle.includes(className) + ) { context.report({ loc: classesUsedInTemplate[className], message: `Unused class "${className}".` diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/_config.json index 6f1145f9d..7f72e0dc3 100644 --- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/_config.json +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/_config.json @@ -1,3 +1,3 @@ { - "options": [{ "allowedClassNames": ["div-class"] }] + "options": [{ "allowedClassNames": ["div-class", "/^p-\\d{1,2}$/"] }] } diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-errors.yaml index 8f64dcba9..127f72bd4 100644 --- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-errors.yaml +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-errors.yaml @@ -2,3 +2,7 @@ line: 3 column: 1 suggestions: null +- message: Unused class "p-100". + line: 5 + column: 1 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-input.svelte index a486966cf..21e917faf 100644 --- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-input.svelte +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/invalid/allowed-class-names/partially-allowed-class-name01-input.svelte @@ -1,3 +1,5 @@
Hello
World! + +Regex! diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/_config.json index 12150540d..365e479bd 100644 --- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/_config.json +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/_config.json @@ -1,3 +1,3 @@ { - "options": [{ "allowedClassNames": ["div-class", "span-class"] }] + "options": [{ "allowedClassNames": ["div-class", "span-class", "/^p-\\d{1,2}$/"] }] } diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/allowed-class-name01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/allowed-class-name01-input.svelte index a486966cf..009527e66 100644 --- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/allowed-class-name01-input.svelte +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-class-name/valid/allowed-class-names/allowed-class-name01-input.svelte @@ -1,3 +1,5 @@
Hello
World! + +Regex! From b8341ac9d81b25ce3db3041dbf1a9c6f60ec4807 Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:11:14 +0900 Subject: [PATCH 2/9] update docs --- docs/rules/no-unused-class-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/no-unused-class-name.md b/docs/rules/no-unused-class-name.md index ecfef4888..249656cd3 100644 --- a/docs/rules/no-unused-class-name.md +++ b/docs/rules/no-unused-class-name.md @@ -53,7 +53,7 @@ This rule is aimed at reducing unused classes in the HTML template. While `svelt "svelte/no-unused-class-name": [ "error", { - "allowedClassNames": ["class-name-one", "class-name-two"] + "allowedClassNames": ["class-name-one", "class-name-two", "/^regex-.*$/"] // You can also use regex to match class names } ] } From 4bb242a55e5d700018b8a6c82e6c672ca557b33e Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:16:08 +0900 Subject: [PATCH 3/9] add changeset --- .changeset/fast-bottles-allow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fast-bottles-allow.md diff --git a/.changeset/fast-bottles-allow.md b/.changeset/fast-bottles-allow.md new file mode 100644 index 000000000..32ca0f2e7 --- /dev/null +++ b/.changeset/fast-bottles-allow.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-svelte': patch +--- + +feat: support regex for allowedClassNames of no-unused-class-name rule From 81fd63b1d1917c305d18a3f499868c44dd06c750 Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:22:33 +0900 Subject: [PATCH 4/9] update --- .changeset/fast-bottles-allow.md | 5 ----- .changeset/forty-signs-smoke.md | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 .changeset/fast-bottles-allow.md create mode 100644 .changeset/forty-signs-smoke.md diff --git a/.changeset/fast-bottles-allow.md b/.changeset/fast-bottles-allow.md deleted file mode 100644 index 32ca0f2e7..000000000 --- a/.changeset/fast-bottles-allow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'eslint-plugin-svelte': patch ---- - -feat: support regex for allowedClassNames of no-unused-class-name rule diff --git a/.changeset/forty-signs-smoke.md b/.changeset/forty-signs-smoke.md new file mode 100644 index 000000000..85ef670b9 --- /dev/null +++ b/.changeset/forty-signs-smoke.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-svelte': minor +--- + +feat(no-unused-class-name): Support Regex for allowedClassNames option From e4c983b9d0060a401a38fd3480f81f1020a4c5c7 Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:29:50 +0900 Subject: [PATCH 5/9] use toRegExp --- .../eslint-plugin-svelte/src/rules/no-unused-class-name.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts index c22b6af23..2bac0cd10 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts @@ -4,6 +4,7 @@ import type { AnyNode } from 'postcss'; import type { Node as SelectorNode } from 'postcss-selector-parser'; import { findClassesInAttribute } from '../utils/ast-utils.js'; import type { SourceCode } from '../types.js'; +import { isRegExp, toRegExp } from 'src/utils/regexp.js'; export default createRule('no-unused-class-name', { meta: { @@ -60,12 +61,11 @@ export default createRule('no-unused-class-name', { if ( !allowedClassNames.includes(className) && !allowedClassNames.some((allowedClassName: string) => { - const regex = /^\/(.*)\/$/.exec(allowedClassName); - if (regex == null || regex[1] == null) { + if (!isRegExp(allowedClassName)) { return false; } - return new RegExp(regex[1]).test(className); + return toRegExp(allowedClassName).test(className); }) && !classesUsedInStyle.includes(className) ) { From 06cbf3fdbd1004b026ef0c9ca5d70b4f19728a2d Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:43:22 +0900 Subject: [PATCH 6/9] simplifier --- .../src/rules/no-unused-class-name.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts index 2bac0cd10..a446d182a 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts @@ -59,14 +59,9 @@ export default createRule('no-unused-class-name', { : []; for (const className in classesUsedInTemplate) { if ( - !allowedClassNames.includes(className) && - !allowedClassNames.some((allowedClassName: string) => { - if (!isRegExp(allowedClassName)) { - return false; - } - - return toRegExp(allowedClassName).test(className); - }) && + !allowedClassNames.some((allowedClassName: string) => + toRegExp(allowedClassName).test(className) + ) && !classesUsedInStyle.includes(className) ) { context.report({ From be7c580e8455bae7346958cf0447a6efe3485228 Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:44:01 +0900 Subject: [PATCH 7/9] update --- .changeset/forty-signs-smoke.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/forty-signs-smoke.md b/.changeset/forty-signs-smoke.md index 85ef670b9..f72f3d6a0 100644 --- a/.changeset/forty-signs-smoke.md +++ b/.changeset/forty-signs-smoke.md @@ -2,4 +2,4 @@ 'eslint-plugin-svelte': minor --- -feat(no-unused-class-name): Support Regex for allowedClassNames option +feat(no-unused-class-name): support regex for `allowedClassNames` option From 1d6105d90e9a584f4e03b1ad9c1281169eb62925 Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:44:17 +0900 Subject: [PATCH 8/9] tidy --- packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts index a446d182a..927f53a8e 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts @@ -4,7 +4,7 @@ import type { AnyNode } from 'postcss'; import type { Node as SelectorNode } from 'postcss-selector-parser'; import { findClassesInAttribute } from '../utils/ast-utils.js'; import type { SourceCode } from '../types.js'; -import { isRegExp, toRegExp } from 'src/utils/regexp.js'; +import { toRegExp } from 'src/utils/regexp.js'; export default createRule('no-unused-class-name', { meta: { From 893b19f0c50b4ed0f1a4102d20f979cddda82ca8 Mon Sep 17 00:00:00 2001 From: tbashiyy Date: Thu, 26 Jun 2025 21:58:40 +0900 Subject: [PATCH 9/9] fix path --- packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts index 927f53a8e..090690577 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts @@ -4,7 +4,7 @@ import type { AnyNode } from 'postcss'; import type { Node as SelectorNode } from 'postcss-selector-parser'; import { findClassesInAttribute } from '../utils/ast-utils.js'; import type { SourceCode } from '../types.js'; -import { toRegExp } from 'src/utils/regexp.js'; +import { toRegExp } from '../utils/regexp.js'; export default createRule('no-unused-class-name', { meta: {