Skip to content

Commit 47760ad

Browse files
authored
chore: using svelte-eslint-parser for style selector parsing (#965)
1 parent d0e76a3 commit 47760ad

File tree

4 files changed

+25
-8
lines changed

4 files changed

+25
-8
lines changed

Diff for: .changeset/itchy-dragons-boil.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': patch
3+
---
4+
5+
chore: using svelte-eslint-parser for style selector parsing

Diff for: packages/eslint-plugin-svelte/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464
"postcss": "^8.4.49",
6565
"postcss-load-config": "^3.1.4",
6666
"postcss-safe-parser": "^7.0.0",
67-
"postcss-selector-parser": "^7.0.0",
6867
"semver": "^7.6.3",
6968
"svelte-eslint-parser": "^1.0.0-next.6"
7069
},
@@ -93,6 +92,7 @@
9392
"less": "^4.2.1",
9493
"mocha": "^11.0.0",
9594
"postcss-nested": "^7.0.2",
95+
"postcss-selector-parser": "^7.0.0",
9696
"sass": "^1.81.0",
9797
"source-map-js": "^1.2.1",
9898
"stylus": "^0.64.0",

Diff for: packages/eslint-plugin-svelte/src/rules/no-unused-class-name.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import type {
1010
SvelteStyleDirective
1111
} from 'svelte-eslint-parser/lib/ast';
1212
import type { AnyNode } from 'postcss';
13-
import { default as selectorParser, type Node as SelectorNode } from 'postcss-selector-parser';
13+
import type { Node as SelectorNode } from 'postcss-selector-parser';
1414
import { getSourceCode } from '../utils/compat.js';
15+
import type { SourceCode } from '../types.js';
1516

1617
export default createRule('no-unused-class-name', {
1718
meta: {
@@ -61,7 +62,9 @@ export default createRule('no-unused-class-name', {
6162
return;
6263
}
6364
const classesUsedInStyle =
64-
styleContext.status === 'success' ? findClassesInPostCSSNode(styleContext.sourceAst) : [];
65+
styleContext.status === 'success'
66+
? findClassesInPostCSSNode(styleContext.sourceAst, sourceCode.parserServices)
67+
: [];
6568
for (const className in classesUsedInTemplate) {
6669
if (!allowedClassNames.includes(className) && !classesUsedInStyle.includes(className)) {
6770
context.report({
@@ -102,15 +105,17 @@ function findClassesInAttribute(
102105
/**
103106
* Extract all class names used in a PostCSS node.
104107
*/
105-
function findClassesInPostCSSNode(node: AnyNode): string[] {
108+
function findClassesInPostCSSNode(
109+
node: AnyNode,
110+
parserServices: SourceCode['parserServices']
111+
): string[] {
106112
if (node.type === 'rule') {
107-
let classes = node.nodes.flatMap(findClassesInPostCSSNode);
108-
const processor = selectorParser();
109-
classes = classes.concat(findClassesInSelector(processor.astSync(node.selector)));
113+
let classes = node.nodes.flatMap((node) => findClassesInPostCSSNode(node, parserServices));
114+
classes = classes.concat(findClassesInSelector(parserServices.getStyleSelectorAST(node)));
110115
return classes;
111116
}
112117
if ((node.type === 'root' || node.type === 'atrule') && node.nodes !== undefined) {
113-
return node.nodes.flatMap(findClassesInPostCSSNode);
118+
return node.nodes.flatMap((node) => findClassesInPostCSSNode(node, parserServices));
114119
}
115120
return [];
116121
}

Diff for: packages/eslint-plugin-svelte/src/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import type { Linter, Rule, SourceCode as ESLintSourceCode } from 'eslint';
33
import type { AST, StyleContext, SvelteConfig } from 'svelte-eslint-parser';
44
import type { TSESTree } from '@typescript-eslint/types';
55
import type { ScopeManager, Scope, Variable } from '@typescript-eslint/scope-manager';
6+
import type { Rule as StyleRule, Node } from 'postcss';
7+
import type { Root as SelectorRoot, Node as SelectorNode } from 'postcss-selector-parser';
68
import type { ASTNode, ASTNodeWithParent, ASTNodeListener } from './types-for-node.js';
79
import type * as TS from 'typescript';
10+
import type { SourceLocation } from 'svelte-eslint-parser/lib/ast/common.js';
811

912
export type { ASTNode, ASTNodeWithParent, ASTNodeListener };
1013
export interface RuleListener extends ASTNodeListener {
@@ -207,6 +210,10 @@ export interface SourceCode {
207210
isSvelteScript?: boolean;
208211
getSvelteHtmlAst?: () => unknown;
209212
getStyleContext?: () => StyleContext;
213+
getStyleSelectorAST: (rule: StyleRule) => SelectorRoot;
214+
styleNodeLoc: (node: Node) => Partial<SourceLocation>;
215+
styleNodeRange: (node: Node) => [number | undefined, number | undefined];
216+
styleSelectorNodeLoc: (node: SelectorNode) => Partial<SourceLocation>;
210217
svelteParseContext?: {
211218
/**
212219
* Whether to use Runes mode.

0 commit comments

Comments
 (0)