@@ -9,18 +9,6 @@ import type {
9
9
import { findClassesInAttribute } from '../utils/ast-utils.js' ;
10
10
import { getSourceCode } from '../utils/compat.js' ;
11
11
import { createRule } from '../utils/index.js' ;
12
- import type { RuleContext , SourceCode } from '../types.js' ;
13
-
14
- interface RuleGlobals {
15
- checkGlobal : boolean ;
16
- style : string [ ] ;
17
- classSelections : Map < string , AST . SvelteHTMLElement [ ] > ;
18
- idSelections : Map < string , AST . SvelteHTMLElement [ ] > ;
19
- typeSelections : Map < string , AST . SvelteHTMLElement [ ] > ;
20
- context : RuleContext ;
21
- getStyleSelectorAST : NonNullable < SourceCode [ 'parserServices' ] [ 'getStyleSelectorAST' ] > ;
22
- styleSelectorNodeLoc : NonNullable < SourceCode [ 'parserServices' ] [ 'styleSelectorNodeLoc' ] > ;
23
- }
24
12
25
13
export default createRule ( 'consistent-selector-style' , {
26
14
meta : {
@@ -61,9 +49,15 @@ export default createRule('consistent-selector-style', {
61
49
} ,
62
50
create ( context ) {
63
51
const sourceCode = getSourceCode ( context ) ;
64
- if ( ! sourceCode . parserServices . isSvelte ) {
52
+ if (
53
+ ! sourceCode . parserServices . isSvelte ||
54
+ sourceCode . parserServices . getStyleSelectorAST === undefined ||
55
+ sourceCode . parserServices . styleSelectorNodeLoc === undefined
56
+ ) {
65
57
return { } ;
66
58
}
59
+ const getStyleSelectorAST = sourceCode . parserServices . getStyleSelectorAST ;
60
+ const styleSelectorNodeLoc = sourceCode . parserServices . styleSelectorNodeLoc ;
67
61
68
62
const checkGlobal = context . options [ 0 ] ?. checkGlobal ?? false ;
69
63
const style = context . options [ 0 ] ?. style ?? [ 'type' , 'id' , 'class' ] ;
@@ -72,6 +66,123 @@ export default createRule('consistent-selector-style', {
72
66
const idSelections : Map < string , AST . SvelteHTMLElement [ ] > = new Map ( ) ;
73
67
const typeSelections : Map < string , AST . SvelteHTMLElement [ ] > = new Map ( ) ;
74
68
69
+ /**
70
+ * Checks selectors in a given PostCSS node
71
+ */
72
+ function checkSelectorsInPostCSSNode ( node : AnyNode ) : void {
73
+ if ( node . type === 'rule' ) {
74
+ checkSelector ( getStyleSelectorAST ( node ) ) ;
75
+ }
76
+ if (
77
+ ( node . type === 'root' ||
78
+ ( node . type === 'rule' && ( node . selector !== ':global' || checkGlobal ) ) ||
79
+ node . type === 'atrule' ) &&
80
+ node . nodes !== undefined
81
+ ) {
82
+ node . nodes . flatMap ( ( node ) => checkSelectorsInPostCSSNode ( node ) ) ;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Checks an individual selector
88
+ */
89
+ function checkSelector ( node : SelectorNode ) : void {
90
+ if ( node . type === 'class' ) {
91
+ checkClassSelector ( node ) ;
92
+ }
93
+ if ( node . type === 'id' ) {
94
+ checkIdSelector ( node ) ;
95
+ }
96
+ if ( node . type === 'tag' ) {
97
+ checkTypeSelector ( node ) ;
98
+ }
99
+ if (
100
+ ( node . type === 'pseudo' && ( node . value !== ':global' || checkGlobal ) ) ||
101
+ node . type === 'root' ||
102
+ node . type === 'selector'
103
+ ) {
104
+ node . nodes . flatMap ( ( node ) => checkSelector ( node ) ) ;
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Checks a class selector
110
+ */
111
+ function checkClassSelector ( node : SelectorClass ) : void {
112
+ const selection = classSelections . get ( node . value ) ?? [ ] ;
113
+ for ( const styleValue of style ) {
114
+ if ( styleValue === 'class' ) {
115
+ return ;
116
+ }
117
+ if ( styleValue === 'id' && canUseIdSelector ( selection ) ) {
118
+ context . report ( {
119
+ messageId : 'classShouldBeId' ,
120
+ loc : styleSelectorNodeLoc ( node ) as AST . SourceLocation
121
+ } ) ;
122
+ return ;
123
+ }
124
+ if ( styleValue === 'type' && canUseTypeSelector ( selection , typeSelections ) ) {
125
+ context . report ( {
126
+ messageId : 'classShouldBeType' ,
127
+ loc : styleSelectorNodeLoc ( node ) as AST . SourceLocation
128
+ } ) ;
129
+ return ;
130
+ }
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Checks an ID selector
136
+ */
137
+ function checkIdSelector ( node : SelectorIdentifier ) : void {
138
+ const selection = idSelections . get ( node . value ) ?? [ ] ;
139
+ for ( const styleValue of style ) {
140
+ if ( styleValue === 'class' ) {
141
+ context . report ( {
142
+ messageId : 'idShouldBeClass' ,
143
+ loc : styleSelectorNodeLoc ( node ) as AST . SourceLocation
144
+ } ) ;
145
+ return ;
146
+ }
147
+ if ( styleValue === 'id' ) {
148
+ return ;
149
+ }
150
+ if ( styleValue === 'type' && canUseTypeSelector ( selection , typeSelections ) ) {
151
+ context . report ( {
152
+ messageId : 'idShouldBeType' ,
153
+ loc : styleSelectorNodeLoc ( node ) as AST . SourceLocation
154
+ } ) ;
155
+ return ;
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Checks a type selector
162
+ */
163
+ function checkTypeSelector ( node : SelectorTag ) : void {
164
+ const selection = typeSelections . get ( node . value ) ?? [ ] ;
165
+ for ( const styleValue of style ) {
166
+ if ( styleValue === 'class' ) {
167
+ context . report ( {
168
+ messageId : 'typeShouldBeClass' ,
169
+ loc : styleSelectorNodeLoc ( node ) as AST . SourceLocation
170
+ } ) ;
171
+ return ;
172
+ }
173
+ if ( styleValue === 'id' && canUseIdSelector ( selection ) ) {
174
+ context . report ( {
175
+ messageId : 'typeShouldBeId' ,
176
+ loc : styleSelectorNodeLoc ( node ) as AST . SourceLocation
177
+ } ) ;
178
+ return ;
179
+ }
180
+ if ( styleValue === 'type' ) {
181
+ return ;
182
+ }
183
+ }
184
+ }
185
+
75
186
return {
76
187
SvelteElement ( node ) {
77
188
if ( node . kind !== 'html' ) {
@@ -97,21 +208,11 @@ export default createRule('consistent-selector-style', {
97
208
const styleContext = sourceCode . parserServices . getStyleContext ! ( ) ;
98
209
if (
99
210
styleContext . status !== 'success' ||
100
- sourceCode . parserServices . getStyleSelectorAST === undefined ||
101
- sourceCode . parserServices . styleSelectorNodeLoc === undefined
211
+ sourceCode . parserServices . getStyleSelectorAST === undefined
102
212
) {
103
213
return ;
104
214
}
105
- checkSelectorsInPostCSSNode ( styleContext . sourceAst , {
106
- checkGlobal,
107
- style,
108
- classSelections,
109
- idSelections,
110
- typeSelections,
111
- context,
112
- getStyleSelectorAST : sourceCode . parserServices . getStyleSelectorAST ,
113
- styleSelectorNodeLoc : sourceCode . parserServices . styleSelectorNodeLoc
114
- } ) ;
215
+ checkSelectorsInPostCSSNode ( styleContext . sourceAst ) ;
115
216
}
116
217
} ;
117
218
}
@@ -128,134 +229,17 @@ function addToArrayMap(
128
229
map . set ( key , ( map . get ( key ) ?? [ ] ) . concat ( value ) ) ;
129
230
}
130
231
131
- /**
132
- * Checks selectors in a given PostCSS node
133
- */
134
- function checkSelectorsInPostCSSNode ( node : AnyNode , ruleGlobals : RuleGlobals ) : void {
135
- if ( node . type === 'rule' ) {
136
- checkSelector ( ruleGlobals . getStyleSelectorAST ( node ) , ruleGlobals ) ;
137
- }
138
- if (
139
- ( node . type === 'root' ||
140
- ( node . type === 'rule' && ( node . selector !== ':global' || ruleGlobals . checkGlobal ) ) ||
141
- node . type === 'atrule' ) &&
142
- node . nodes !== undefined
143
- ) {
144
- node . nodes . flatMap ( ( node ) => checkSelectorsInPostCSSNode ( node , ruleGlobals ) ) ;
145
- }
146
- }
147
-
148
- /**
149
- * Checks an individual selector
150
- */
151
- function checkSelector ( node : SelectorNode , ruleGlobals : RuleGlobals ) : void {
152
- if ( node . type === 'class' ) {
153
- checkClassSelector ( node , ruleGlobals ) ;
154
- }
155
- if ( node . type === 'id' ) {
156
- checkIdSelector ( node , ruleGlobals ) ;
157
- }
158
- if ( node . type === 'tag' ) {
159
- checkTypeSelector ( node , ruleGlobals ) ;
160
- }
161
- if (
162
- ( node . type === 'pseudo' && ( node . value !== ':global' || ruleGlobals . checkGlobal ) ) ||
163
- node . type === 'root' ||
164
- node . type === 'selector'
165
- ) {
166
- node . nodes . flatMap ( ( node ) => checkSelector ( node , ruleGlobals ) ) ;
167
- }
168
- }
169
-
170
- /**
171
- * Checks a class selector
172
- */
173
- function checkClassSelector ( node : SelectorClass , ruleGlobals : RuleGlobals ) : void {
174
- const selection = ruleGlobals . classSelections . get ( node . value ) ?? [ ] ;
175
- for ( const styleValue of ruleGlobals . style ) {
176
- if ( styleValue === 'class' ) {
177
- return ;
178
- }
179
- if ( styleValue === 'id' && couldBeId ( selection ) ) {
180
- ruleGlobals . context . report ( {
181
- messageId : 'classShouldBeId' ,
182
- loc : ruleGlobals . styleSelectorNodeLoc ( node ) as AST . SourceLocation
183
- } ) ;
184
- return ;
185
- }
186
- if ( styleValue === 'type' && couldBeType ( selection , ruleGlobals . typeSelections ) ) {
187
- ruleGlobals . context . report ( {
188
- messageId : 'classShouldBeType' ,
189
- loc : ruleGlobals . styleSelectorNodeLoc ( node ) as AST . SourceLocation
190
- } ) ;
191
- return ;
192
- }
193
- }
194
- }
195
-
196
- /**
197
- * Checks an ID selector
198
- */
199
- function checkIdSelector ( node : SelectorIdentifier , ruleGlobals : RuleGlobals ) : void {
200
- const selection = ruleGlobals . idSelections . get ( node . value ) ?? [ ] ;
201
- for ( const styleValue of ruleGlobals . style ) {
202
- if ( styleValue === 'class' ) {
203
- ruleGlobals . context . report ( {
204
- messageId : 'idShouldBeClass' ,
205
- loc : ruleGlobals . styleSelectorNodeLoc ( node ) as AST . SourceLocation
206
- } ) ;
207
- return ;
208
- }
209
- if ( styleValue === 'id' ) {
210
- return ;
211
- }
212
- if ( styleValue === 'type' && couldBeType ( selection , ruleGlobals . typeSelections ) ) {
213
- ruleGlobals . context . report ( {
214
- messageId : 'idShouldBeType' ,
215
- loc : ruleGlobals . styleSelectorNodeLoc ( node ) as AST . SourceLocation
216
- } ) ;
217
- return ;
218
- }
219
- }
220
- }
221
-
222
- /**
223
- * Checks a type selector
224
- */
225
- function checkTypeSelector ( node : SelectorTag , ruleGlobals : RuleGlobals ) : void {
226
- const selection = ruleGlobals . typeSelections . get ( node . value ) ?? [ ] ;
227
- for ( const styleValue of ruleGlobals . style ) {
228
- if ( styleValue === 'class' ) {
229
- ruleGlobals . context . report ( {
230
- messageId : 'typeShouldBeClass' ,
231
- loc : ruleGlobals . styleSelectorNodeLoc ( node ) as AST . SourceLocation
232
- } ) ;
233
- return ;
234
- }
235
- if ( styleValue === 'id' && couldBeId ( selection ) ) {
236
- ruleGlobals . context . report ( {
237
- messageId : 'typeShouldBeId' ,
238
- loc : ruleGlobals . styleSelectorNodeLoc ( node ) as AST . SourceLocation
239
- } ) ;
240
- return ;
241
- }
242
- if ( styleValue === 'type' ) {
243
- return ;
244
- }
245
- }
246
- }
247
-
248
232
/**
249
233
* Checks whether a given selection could be obtained using an ID selector
250
234
*/
251
- function couldBeId ( selection : AST . SvelteHTMLElement [ ] ) : boolean {
235
+ function canUseIdSelector ( selection : AST . SvelteHTMLElement [ ] ) : boolean {
252
236
return selection . length <= 1 ;
253
237
}
254
238
255
239
/**
256
240
* Checks whether a given selection could be obtained using a type selector
257
241
*/
258
- function couldBeType (
242
+ function canUseTypeSelector (
259
243
selection : AST . SvelteHTMLElement [ ] ,
260
244
typeSelections : Map < string , AST . SvelteHTMLElement [ ] >
261
245
) : boolean {
0 commit comments