@plumeria/eslint-plugin 18.2.13 → 18.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rules/expand-border-shorthands.js +6 -4
- package/dist/rules/format-properties.js +6 -4
- package/dist/rules/no-combinator.js +4 -3
- package/dist/rules/no-invalid-selector.js +6 -4
- package/dist/rules/no-order-dependent-overlap.js +67 -7
- package/dist/rules/no-unknown-css-properties.js +6 -4
- package/dist/rules/no-unused-keys.js +2 -1
- package/dist/rules/sort-properties.js +6 -4
- package/dist/rules/validate-pseudos.js +6 -4
- package/dist/rules/validate-values.js +6 -4
- package/dist/util/selector.d.ts +11 -0
- package/dist/util/selector.js +185 -0
- package/dist/util/spellingRule.js +6 -4
- package/dist/util/styleObject.d.ts +4 -0
- package/dist/util/styleObject.js +20 -0
- package/package.json +2 -2
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.expandBorderShorthands = void 0;
|
|
4
4
|
const borderShorthand_1 = require("../util/borderShorthand");
|
|
5
5
|
const logicalPhysical_1 = require("../util/logicalPhysical");
|
|
6
|
+
const styleObject_1 = require("../util/styleObject");
|
|
6
7
|
const BUNDLES = new Set(borderShorthand_1.BORDER_BUNDLES);
|
|
7
8
|
exports.expandBorderShorthands = {
|
|
8
9
|
meta: {
|
|
@@ -65,10 +66,11 @@ exports.expandBorderShorthands = {
|
|
|
65
66
|
node.arguments.forEach((arg) => {
|
|
66
67
|
if (arg.type === 'ObjectExpression') {
|
|
67
68
|
arg.properties.forEach((prop) => {
|
|
68
|
-
if (prop.type
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
if (prop.type !== 'Property')
|
|
70
|
+
return;
|
|
71
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
72
|
+
if (style)
|
|
73
|
+
checkStyleObject(style);
|
|
72
74
|
});
|
|
73
75
|
}
|
|
74
76
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatProperties = void 0;
|
|
4
|
+
const styleObject_1 = require("../util/styleObject");
|
|
4
5
|
exports.formatProperties = {
|
|
5
6
|
meta: {
|
|
6
7
|
type: 'layout',
|
|
@@ -164,10 +165,11 @@ exports.formatProperties = {
|
|
|
164
165
|
node.arguments.forEach((arg) => {
|
|
165
166
|
if (arg.type === 'ObjectExpression') {
|
|
166
167
|
arg.properties.forEach((prop) => {
|
|
167
|
-
if (prop.type
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
if (prop.type !== 'Property')
|
|
169
|
+
return;
|
|
170
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
171
|
+
if (style)
|
|
172
|
+
checkStyleObject(style);
|
|
171
173
|
});
|
|
172
174
|
}
|
|
173
175
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noCombinator = void 0;
|
|
4
|
+
const styleObject_1 = require("../util/styleObject");
|
|
4
5
|
exports.noCombinator = {
|
|
5
6
|
meta: {
|
|
6
7
|
type: 'problem',
|
|
@@ -177,9 +178,9 @@ exports.noCombinator = {
|
|
|
177
178
|
if (keyName) {
|
|
178
179
|
checkAndReport(keyName, prop.key);
|
|
179
180
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
182
|
+
if (style)
|
|
183
|
+
checkForCombinatorsRecursively(style);
|
|
183
184
|
}
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noInvalidSelector = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const styleObject_1 = require("../util/styleObject");
|
|
5
6
|
exports.noInvalidSelector = {
|
|
6
7
|
meta: {
|
|
7
8
|
type: 'problem',
|
|
@@ -216,10 +217,11 @@ exports.noInvalidSelector = {
|
|
|
216
217
|
});
|
|
217
218
|
}
|
|
218
219
|
}
|
|
219
|
-
if (prop.type
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
|
|
221
|
+
return;
|
|
222
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
223
|
+
if (style)
|
|
224
|
+
checkNesting(style, 'CLASS');
|
|
223
225
|
});
|
|
224
226
|
}
|
|
225
227
|
if (isCssKeyframes &&
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.noOrderDependentOverlap = void 0;
|
|
4
4
|
const zss_engine_1 = require("zss-engine");
|
|
5
5
|
const logicalPhysical_1 = require("../util/logicalPhysical");
|
|
6
|
+
const selector_1 = require("../util/selector");
|
|
7
|
+
const styleObject_1 = require("../util/styleObject");
|
|
6
8
|
const DIRECT_SHORTHANDS = {};
|
|
7
9
|
for (const [shorthand, longhands] of Object.entries(zss_engine_1.DIRECT_LONGHANDS)) {
|
|
8
10
|
for (const longhand of longhands) {
|
|
@@ -59,6 +61,7 @@ exports.noOrderDependentOverlap = {
|
|
|
59
61
|
alias: "'{{ first }}' and '{{ second }}' are the same property under two names, so neither outranks the other. The one written last wins.",
|
|
60
62
|
crossing: "'{{ first }}' and '{{ second }}' overlap, but neither property outranks the other. The result depends on the order they are written.",
|
|
61
63
|
condition: "'{{ narrow }}' matches only where '{{ broad }}' also matches, so it is the more specific of the two, and both set '{{ property }}'. Written first, it reads as though the broader one wins, which is the opposite of what the stylesheet does.",
|
|
64
|
+
state: "'{{ first }}' and '{{ second }}' can match at the same time and both set '{{ property }}', but neither outranks the other, so the result depends on the order they are written. Declare '{{ compound }}' if the intersection has a value of its own, or split them into separate styles and compose them in the order that should win.",
|
|
62
65
|
keep: "Keep '{{ keep }}'",
|
|
63
66
|
swap: "Write '{{ narrow }}' after '{{ broad }}'",
|
|
64
67
|
},
|
|
@@ -112,10 +115,11 @@ exports.noOrderDependentOverlap = {
|
|
|
112
115
|
node.arguments.forEach((arg) => {
|
|
113
116
|
if (arg.type === 'ObjectExpression') {
|
|
114
117
|
arg.properties.forEach((prop) => {
|
|
115
|
-
if (prop.type
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
if (prop.type !== 'Property')
|
|
119
|
+
return;
|
|
120
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
121
|
+
if (style)
|
|
122
|
+
checkStyleObject(style);
|
|
119
123
|
});
|
|
120
124
|
}
|
|
121
125
|
});
|
|
@@ -132,17 +136,31 @@ exports.noOrderDependentOverlap = {
|
|
|
132
136
|
? prop.key.value
|
|
133
137
|
: '';
|
|
134
138
|
}
|
|
135
|
-
function declaredNames(node) {
|
|
139
|
+
function declaredNames(node, withCustomProperties = false) {
|
|
136
140
|
const names = new Set();
|
|
137
141
|
node.properties.forEach((prop) => {
|
|
138
142
|
if (prop.type !== 'Property' || prop.value.type === 'ObjectExpression')
|
|
139
143
|
return;
|
|
140
144
|
const name = keyNameOf(prop);
|
|
141
|
-
if (
|
|
142
|
-
|
|
145
|
+
if (!name)
|
|
146
|
+
return;
|
|
147
|
+
if (name.startsWith('--')) {
|
|
148
|
+
if (withCustomProperties)
|
|
149
|
+
names.add(name);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
names.add(name);
|
|
143
153
|
});
|
|
144
154
|
return names;
|
|
145
155
|
}
|
|
156
|
+
function overlapsProperty(first, second) {
|
|
157
|
+
if (first.startsWith('--') || second.startsWith('--')) {
|
|
158
|
+
return first === second;
|
|
159
|
+
}
|
|
160
|
+
return ((0, logicalPhysical_1.canonicalProperty)((0, logicalPhysical_1.toKebabCase)(first)) ===
|
|
161
|
+
(0, logicalPhysical_1.canonicalProperty)((0, logicalPhysical_1.toKebabCase)(second)) ||
|
|
162
|
+
overlapOf((0, logicalPhysical_1.toKebabCase)(first), (0, logicalPhysical_1.toKebabCase)(second)) === 'crossing');
|
|
163
|
+
}
|
|
146
164
|
function swapProperties(fixer, first, second) {
|
|
147
165
|
return [
|
|
148
166
|
fixer.replaceText(first, sourceCode.getText(second)),
|
|
@@ -162,6 +180,7 @@ exports.noOrderDependentOverlap = {
|
|
|
162
180
|
function checkStyleObject(node) {
|
|
163
181
|
const declarations = [];
|
|
164
182
|
const conditions = [];
|
|
183
|
+
const states = [];
|
|
165
184
|
node.properties.forEach((prop) => {
|
|
166
185
|
if (prop.type !== 'Property')
|
|
167
186
|
return;
|
|
@@ -175,6 +194,13 @@ exports.noOrderDependentOverlap = {
|
|
|
175
194
|
sets: declaredNames(prop.value),
|
|
176
195
|
});
|
|
177
196
|
}
|
|
197
|
+
else if ((0, selector_1.isStateSelector)(condition)) {
|
|
198
|
+
states.push({
|
|
199
|
+
prop,
|
|
200
|
+
name: condition,
|
|
201
|
+
sets: declaredNames(prop.value, true),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
178
204
|
checkStyleObject(prop.value);
|
|
179
205
|
return;
|
|
180
206
|
}
|
|
@@ -215,6 +241,40 @@ exports.noOrderDependentOverlap = {
|
|
|
215
241
|
});
|
|
216
242
|
}
|
|
217
243
|
}
|
|
244
|
+
for (let i = 0; i < states.length; i++) {
|
|
245
|
+
for (let j = i + 1; j < states.length; j++) {
|
|
246
|
+
const first = states[i];
|
|
247
|
+
const second = states[j];
|
|
248
|
+
if ((0, zss_engine_1.getPseudoElement)(first.name) !== (0, zss_engine_1.getPseudoElement)(second.name)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if ((0, zss_engine_1.getSpecificity)(first.name).join() !==
|
|
252
|
+
(0, zss_engine_1.getSpecificity)(second.name).join()) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if ((0, selector_1.areExclusive)(first.name, second.name))
|
|
256
|
+
continue;
|
|
257
|
+
const shared = [...first.sets].find((name) => [...second.sets].some((other) => overlapsProperty(name, other)));
|
|
258
|
+
if (!shared)
|
|
259
|
+
continue;
|
|
260
|
+
if (states.some((state) => state !== first &&
|
|
261
|
+
state !== second &&
|
|
262
|
+
(0, selector_1.covers)(state.name, first.name, second.name) &&
|
|
263
|
+
[...state.sets].some((name) => overlapsProperty(name, shared)))) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
context.report({
|
|
267
|
+
node: second.prop.key,
|
|
268
|
+
messageId: 'state',
|
|
269
|
+
data: {
|
|
270
|
+
first: first.name,
|
|
271
|
+
second: second.name,
|
|
272
|
+
property: shared,
|
|
273
|
+
compound: (0, selector_1.compoundOf)(first.name, second.name),
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
218
278
|
for (let i = 0; i < declarations.length; i++) {
|
|
219
279
|
for (let j = i + 1; j < declarations.length; j++) {
|
|
220
280
|
const first = declarations[i];
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noUnknownCssProperties = void 0;
|
|
4
4
|
const known_css_properties_1 = require("known-css-properties");
|
|
5
|
+
const styleObject_1 = require("../util/styleObject");
|
|
5
6
|
const knownProperties = new Set(known_css_properties_1.all);
|
|
6
7
|
const kebabCache = new Map();
|
|
7
8
|
function toKebabCase(str) {
|
|
@@ -70,10 +71,11 @@ exports.noUnknownCssProperties = {
|
|
|
70
71
|
node.arguments.forEach((arg) => {
|
|
71
72
|
if (arg.type === 'ObjectExpression') {
|
|
72
73
|
arg.properties.forEach((prop) => {
|
|
73
|
-
if (prop.type
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
if (prop.type !== 'Property')
|
|
75
|
+
return;
|
|
76
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
77
|
+
if (style)
|
|
78
|
+
checkStyleObject(style);
|
|
77
79
|
});
|
|
78
80
|
}
|
|
79
81
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noUnusedKeys = void 0;
|
|
4
|
+
const styleObject_1 = require("../util/styleObject");
|
|
4
5
|
function getRootObject(node) {
|
|
5
6
|
if (node.type === 'Identifier') {
|
|
6
7
|
return node;
|
|
@@ -46,7 +47,7 @@ exports.noUnusedKeys = {
|
|
|
46
47
|
arg.properties.forEach((prop) => {
|
|
47
48
|
if (prop.type === 'Property' &&
|
|
48
49
|
prop.key.type === 'Identifier' &&
|
|
49
|
-
prop.value
|
|
50
|
+
(0, styleObject_1.styleObjectFromValue)(prop.value)) {
|
|
50
51
|
keyMap.set(prop.key.name, prop.key);
|
|
51
52
|
}
|
|
52
53
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.sortProperties = void 0;
|
|
4
|
+
const styleObject_1 = require("../util/styleObject");
|
|
4
5
|
const propertyGroups_1 = require("../util/propertyGroups");
|
|
5
6
|
function getPropertyName(property) {
|
|
6
7
|
if (property.key.type === 'Identifier') {
|
|
@@ -212,10 +213,11 @@ exports.sortProperties = {
|
|
|
212
213
|
node.arguments.forEach((arg) => {
|
|
213
214
|
if (arg.type === 'ObjectExpression') {
|
|
214
215
|
arg.properties.forEach((prop) => {
|
|
215
|
-
if (prop.type
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
if (prop.type !== 'Property')
|
|
217
|
+
return;
|
|
218
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
219
|
+
if (style)
|
|
220
|
+
checkStyleObject(style);
|
|
219
221
|
});
|
|
220
222
|
}
|
|
221
223
|
});
|
|
@@ -4,6 +4,7 @@ exports.validatePseudos = void 0;
|
|
|
4
4
|
exports.splitChainedPseudos = splitChainedPseudos;
|
|
5
5
|
exports.isValidPseudo = isValidPseudo;
|
|
6
6
|
const utils_1 = require("@typescript-eslint/utils");
|
|
7
|
+
const styleObject_1 = require("../util/styleObject");
|
|
7
8
|
const VALID_STATIC_PSEUDOS = new Set([
|
|
8
9
|
':hover',
|
|
9
10
|
':active',
|
|
@@ -235,10 +236,11 @@ exports.validatePseudos = {
|
|
|
235
236
|
node.arguments[0]?.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
236
237
|
const styleObj = node.arguments[0];
|
|
237
238
|
styleObj.properties.forEach((prop) => {
|
|
238
|
-
if (prop.type
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
239
|
+
if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
|
|
240
|
+
return;
|
|
241
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
242
|
+
if (style)
|
|
243
|
+
checkProperties(style);
|
|
242
244
|
});
|
|
243
245
|
}
|
|
244
246
|
},
|
|
@@ -5,6 +5,7 @@ const validData_1 = require("../util/validData");
|
|
|
5
5
|
const unitData_1 = require("../util/unitData");
|
|
6
6
|
const colorData_1 = require("../util/colorData");
|
|
7
7
|
const place_1 = require("../util/place");
|
|
8
|
+
const styleObject_1 = require("../util/styleObject");
|
|
8
9
|
const globalValues = ['inherit', 'initial', 'revert', 'revert-layer', 'unset'];
|
|
9
10
|
const lengthValueProperties = [
|
|
10
11
|
'width',
|
|
@@ -1674,10 +1675,11 @@ exports.validateValues = {
|
|
|
1674
1675
|
node.arguments.forEach((arg) => {
|
|
1675
1676
|
if (arg.type === 'ObjectExpression') {
|
|
1676
1677
|
arg.properties.forEach((prop) => {
|
|
1677
|
-
if (prop.type
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1678
|
+
if (prop.type !== 'Property')
|
|
1679
|
+
return;
|
|
1680
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
1681
|
+
if (style)
|
|
1682
|
+
checkStyleObject(style);
|
|
1681
1683
|
});
|
|
1682
1684
|
}
|
|
1683
1685
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface Token {
|
|
2
|
+
text: string;
|
|
3
|
+
isPseudoElement: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function tokenize(selector: string): Token[];
|
|
6
|
+
export declare function isStateSelector(selector: string): boolean;
|
|
7
|
+
export declare function areExclusive(first: string, second: string): boolean;
|
|
8
|
+
export declare function statesOf(selector: string): string[];
|
|
9
|
+
export declare function compoundOf(first: string, second: string): string;
|
|
10
|
+
export declare function covers(compound: string, first: string, second: string): boolean;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tokenize = tokenize;
|
|
4
|
+
exports.isStateSelector = isStateSelector;
|
|
5
|
+
exports.areExclusive = areExclusive;
|
|
6
|
+
exports.statesOf = statesOf;
|
|
7
|
+
exports.compoundOf = compoundOf;
|
|
8
|
+
exports.covers = covers;
|
|
9
|
+
const zss_engine_1 = require("zss-engine");
|
|
10
|
+
const LEGACY_PSEUDO_ELEMENTS = new Set([
|
|
11
|
+
'before',
|
|
12
|
+
'after',
|
|
13
|
+
'first-line',
|
|
14
|
+
'first-letter',
|
|
15
|
+
]);
|
|
16
|
+
const EXCLUSIVE_PAIRS = [
|
|
17
|
+
[':link', ':visited'],
|
|
18
|
+
[':enabled', ':disabled'],
|
|
19
|
+
[':read-only', ':read-write'],
|
|
20
|
+
[':valid', ':invalid'],
|
|
21
|
+
[':in-range', ':out-of-range'],
|
|
22
|
+
[':required', ':optional'],
|
|
23
|
+
].map((pair) => pair.slice().sort().join('\0'));
|
|
24
|
+
const isNameChar = (char) => /[\w-]/.test(char);
|
|
25
|
+
const skipName = (selector, from) => {
|
|
26
|
+
let index = from;
|
|
27
|
+
while (index < selector.length) {
|
|
28
|
+
if (selector[index] === '\\') {
|
|
29
|
+
index += 2;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (!isNameChar(selector[index]))
|
|
33
|
+
break;
|
|
34
|
+
index += 1;
|
|
35
|
+
}
|
|
36
|
+
return index;
|
|
37
|
+
};
|
|
38
|
+
const findClose = (selector, open) => {
|
|
39
|
+
let depth = 0;
|
|
40
|
+
for (let index = open; index < selector.length; index++) {
|
|
41
|
+
const char = selector[index];
|
|
42
|
+
if (char === '\\') {
|
|
43
|
+
index += 1;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (char === '"' || char === "'") {
|
|
47
|
+
index += 1;
|
|
48
|
+
while (index < selector.length && selector[index] !== char) {
|
|
49
|
+
if (selector[index] === '\\')
|
|
50
|
+
index += 1;
|
|
51
|
+
index += 1;
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (char === '(')
|
|
56
|
+
depth += 1;
|
|
57
|
+
else if (char === ')') {
|
|
58
|
+
depth -= 1;
|
|
59
|
+
if (depth === 0)
|
|
60
|
+
return index;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return selector.length;
|
|
64
|
+
};
|
|
65
|
+
const skipBracket = (selector, open) => {
|
|
66
|
+
for (let index = open + 1; index < selector.length; index++) {
|
|
67
|
+
const char = selector[index];
|
|
68
|
+
if (char === '\\') {
|
|
69
|
+
index += 1;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (char === '"' || char === "'") {
|
|
73
|
+
index += 1;
|
|
74
|
+
while (index < selector.length && selector[index] !== char) {
|
|
75
|
+
if (selector[index] === '\\')
|
|
76
|
+
index += 1;
|
|
77
|
+
index += 1;
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (char === ']')
|
|
82
|
+
return index + 1;
|
|
83
|
+
}
|
|
84
|
+
return selector.length;
|
|
85
|
+
};
|
|
86
|
+
function tokenize(selector) {
|
|
87
|
+
const tokens = [];
|
|
88
|
+
let index = 0;
|
|
89
|
+
while (index < selector.length) {
|
|
90
|
+
const char = selector[index];
|
|
91
|
+
const start = index;
|
|
92
|
+
if (char === '#' || char === '.') {
|
|
93
|
+
index = skipName(selector, index + 1);
|
|
94
|
+
tokens.push({
|
|
95
|
+
text: selector.slice(start, index),
|
|
96
|
+
isPseudoElement: false,
|
|
97
|
+
});
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (char === '[') {
|
|
101
|
+
index = skipBracket(selector, index);
|
|
102
|
+
tokens.push({
|
|
103
|
+
text: selector.slice(start, index),
|
|
104
|
+
isPseudoElement: false,
|
|
105
|
+
});
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (char === ':') {
|
|
109
|
+
const doubleColon = selector[index + 1] === ':';
|
|
110
|
+
const nameStart = index + (doubleColon ? 2 : 1);
|
|
111
|
+
const nameEnd = skipName(selector, nameStart);
|
|
112
|
+
const name = selector.slice(nameStart, nameEnd).toLowerCase();
|
|
113
|
+
index = nameEnd;
|
|
114
|
+
let inner = '';
|
|
115
|
+
if (selector[index] === '(') {
|
|
116
|
+
const close = findClose(selector, index);
|
|
117
|
+
inner = selector.slice(index + 1, close);
|
|
118
|
+
index = close + 1;
|
|
119
|
+
}
|
|
120
|
+
const text = selector.slice(start, index);
|
|
121
|
+
const argument = inner ? `(${inner})` : '';
|
|
122
|
+
if (doubleColon || LEGACY_PSEUDO_ELEMENTS.has(name)) {
|
|
123
|
+
tokens.push({
|
|
124
|
+
text: `::${name}${argument}`,
|
|
125
|
+
isPseudoElement: true,
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
tokens.push({ text, isPseudoElement: false });
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (isNameChar(char) || char === '\\') {
|
|
133
|
+
index = skipName(selector, index);
|
|
134
|
+
tokens.push({
|
|
135
|
+
text: selector.slice(start, index),
|
|
136
|
+
isPseudoElement: false,
|
|
137
|
+
});
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
index += 1;
|
|
141
|
+
}
|
|
142
|
+
return tokens;
|
|
143
|
+
}
|
|
144
|
+
function isStateSelector(selector) {
|
|
145
|
+
const tokens = tokenize(selector);
|
|
146
|
+
return (tokens.length > 0 &&
|
|
147
|
+
tokens.every((token) => token.isPseudoElement ||
|
|
148
|
+
token.text.startsWith(':') ||
|
|
149
|
+
token.text.startsWith('[')));
|
|
150
|
+
}
|
|
151
|
+
const negationOf = (state) => {
|
|
152
|
+
if (!state.startsWith(':not(') || !state.endsWith(')'))
|
|
153
|
+
return null;
|
|
154
|
+
return state.slice(5, -1).trim();
|
|
155
|
+
};
|
|
156
|
+
function areExclusive(first, second) {
|
|
157
|
+
const left = new Set(statesOf(first));
|
|
158
|
+
const right = new Set(statesOf(second));
|
|
159
|
+
for (const a of left) {
|
|
160
|
+
for (const b of right) {
|
|
161
|
+
if (a === b)
|
|
162
|
+
continue;
|
|
163
|
+
if (negationOf(a) === b || negationOf(b) === a)
|
|
164
|
+
return true;
|
|
165
|
+
if (EXCLUSIVE_PAIRS.includes([a, b].sort().join('\0')))
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
function statesOf(selector) {
|
|
172
|
+
return tokenize(selector)
|
|
173
|
+
.filter((token) => !token.isPseudoElement)
|
|
174
|
+
.map((token) => token.text);
|
|
175
|
+
}
|
|
176
|
+
function compoundOf(first, second) {
|
|
177
|
+
const states = [...new Set([...statesOf(first), ...statesOf(second)])];
|
|
178
|
+
return states.join('') + (0, zss_engine_1.getPseudoElement)(first);
|
|
179
|
+
}
|
|
180
|
+
function covers(compound, first, second) {
|
|
181
|
+
const declared = new Set(statesOf(compound));
|
|
182
|
+
if ((0, zss_engine_1.getPseudoElement)(compound) !== (0, zss_engine_1.getPseudoElement)(first))
|
|
183
|
+
return false;
|
|
184
|
+
return [...statesOf(first), ...statesOf(second)].every((state) => declared.has(state));
|
|
185
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createSpellingRule = void 0;
|
|
4
4
|
const logicalPhysical_1 = require("./logicalPhysical");
|
|
5
|
+
const styleObject_1 = require("./styleObject");
|
|
5
6
|
const DESCRIPTIONS = {
|
|
6
7
|
physical: 'Disallow the physical name of a property that also has a logical name',
|
|
7
8
|
logical: 'Disallow the logical name of a property that also has a physical name',
|
|
@@ -77,10 +78,11 @@ const createSpellingRule = (reject) => ({
|
|
|
77
78
|
node.arguments.forEach((arg) => {
|
|
78
79
|
if (arg.type === 'ObjectExpression') {
|
|
79
80
|
arg.properties.forEach((prop) => {
|
|
80
|
-
if (prop.type
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
if (prop.type !== 'Property')
|
|
82
|
+
return;
|
|
83
|
+
const style = (0, styleObject_1.styleObjectFromValue)(prop.value);
|
|
84
|
+
if (style)
|
|
85
|
+
checkStyleObject(style);
|
|
84
86
|
});
|
|
85
87
|
}
|
|
86
88
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.styleObjectFromValue = styleObjectFromValue;
|
|
4
|
+
function styleObjectFromValue(value) {
|
|
5
|
+
if (value.type === 'ObjectExpression')
|
|
6
|
+
return value;
|
|
7
|
+
if (value.type !== 'ArrowFunctionExpression' &&
|
|
8
|
+
value.type !== 'FunctionExpression')
|
|
9
|
+
return undefined;
|
|
10
|
+
const body = value.body;
|
|
11
|
+
if (body?.type === 'ObjectExpression')
|
|
12
|
+
return body;
|
|
13
|
+
if (body?.type !== 'BlockStatement')
|
|
14
|
+
return undefined;
|
|
15
|
+
const first = body.body?.[0];
|
|
16
|
+
return first?.type === 'ReturnStatement' &&
|
|
17
|
+
first.argument?.type === 'ObjectExpression'
|
|
18
|
+
? first.argument
|
|
19
|
+
: undefined;
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumeria/eslint-plugin",
|
|
3
|
-
"version": "18.2.
|
|
3
|
+
"version": "18.2.15",
|
|
4
4
|
"description": "Plumeria ESLint plugin",
|
|
5
5
|
"author": "Refirst 11",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@typescript-eslint/utils": "^8.60.0",
|
|
56
56
|
"known-css-properties": "^0.37.0",
|
|
57
|
-
"zss-engine": "2.
|
|
57
|
+
"zss-engine": "2.6.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "rimraf dist && pnpm cjs",
|