@plumeria/eslint-plugin 11.2.0 → 11.2.1
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/README.md
CHANGED
|
@@ -12,7 +12,7 @@ The `plugin:@plumeria/recommended` config enables the following:
|
|
|
12
12
|
- `@plumeria/no-destructure`: **error**
|
|
13
13
|
- `@plumeria/no-inline-object`: **error**
|
|
14
14
|
- `@plumeria/no-inner-call`: **error**
|
|
15
|
-
- `@plumeria/no-invalid-selector
|
|
15
|
+
- `@plumeria/no-invalid-selector`: **error**
|
|
16
16
|
- `@plumeria/no-mixed-styling-props`: **error**
|
|
17
17
|
- `@plumeria/no-unknown-css-properties`: **error**
|
|
18
18
|
- `@plumeria/no-unused-keys`: **warn**
|
|
@@ -48,9 +48,10 @@ Disallow passing inline object to `styleName` and `css.use()`. Only compiled sty
|
|
|
48
48
|
|
|
49
49
|
Disallow calling APIs inside functions.
|
|
50
50
|
|
|
51
|
-
### no-invalid-selector
|
|
51
|
+
### no-invalid-selector
|
|
52
52
|
|
|
53
|
-
Disallow invalid selector
|
|
53
|
+
Disallow invalid selector inside `css.create()` and `css.keyframes()` and `css.viewTransition()`.
|
|
54
|
+
`create()` example: (Pseudo -> Query, Query -> Query)
|
|
54
55
|
|
|
55
56
|
### no-mixed-styling-props
|
|
56
57
|
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ const no_combinator_1 = require("./rules/no-combinator");
|
|
|
6
6
|
const no_destructure_1 = require("./rules/no-destructure");
|
|
7
7
|
const no_inline_object_1 = require("./rules/no-inline-object");
|
|
8
8
|
const no_inner_call_1 = require("./rules/no-inner-call");
|
|
9
|
-
const
|
|
9
|
+
const no_invalid_selector_1 = require("./rules/no-invalid-selector");
|
|
10
10
|
const no_mixed_styling_props_1 = require("./rules/no-mixed-styling-props");
|
|
11
11
|
const no_unknown_css_properties_1 = require("./rules/no-unknown-css-properties");
|
|
12
12
|
const no_unused_keys_1 = require("./rules/no-unused-keys");
|
|
@@ -19,7 +19,7 @@ const rules = {
|
|
|
19
19
|
'no-destructure': no_destructure_1.noDestructure,
|
|
20
20
|
'no-inline-object': no_inline_object_1.noInlineObject,
|
|
21
21
|
'no-inner-call': no_inner_call_1.noInnerCall,
|
|
22
|
-
'no-invalid-selector
|
|
22
|
+
'no-invalid-selector': no_invalid_selector_1.noInvalidSelector,
|
|
23
23
|
'no-mixed-styling-props': no_mixed_styling_props_1.noMixedStylingProps,
|
|
24
24
|
'no-unknown-css-properties': no_unknown_css_properties_1.noUnknownCssProperties,
|
|
25
25
|
'no-unused-keys': no_unused_keys_1.noUnusedKeys,
|
|
@@ -36,7 +36,7 @@ const configs = {
|
|
|
36
36
|
'@plumeria/no-destructure': 'error',
|
|
37
37
|
'@plumeria/no-inline-object': 'error',
|
|
38
38
|
'@plumeria/no-inner-call': 'error',
|
|
39
|
-
'@plumeria/no-invalid-selector
|
|
39
|
+
'@plumeria/no-invalid-selector': 'error',
|
|
40
40
|
'@plumeria/no-mixed-styling-props': 'error',
|
|
41
41
|
'@plumeria/no-unknown-css-properties': 'error',
|
|
42
42
|
'@plumeria/no-unused-keys': 'warn',
|
|
@@ -59,7 +59,7 @@ const flatConfigs = {
|
|
|
59
59
|
'@plumeria/no-destructure': 'error',
|
|
60
60
|
'@plumeria/no-inline-object': 'error',
|
|
61
61
|
'@plumeria/no-inner-call': 'error',
|
|
62
|
-
'@plumeria/no-invalid-selector
|
|
62
|
+
'@plumeria/no-invalid-selector': 'error',
|
|
63
63
|
'@plumeria/no-mixed-styling-props': 'error',
|
|
64
64
|
'@plumeria/no-unknown-css-properties': 'error',
|
|
65
65
|
'@plumeria/no-unused-keys': 'warn',
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.noInvalidSelector = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
-
exports.
|
|
5
|
+
exports.noInvalidSelector = {
|
|
6
6
|
meta: {
|
|
7
7
|
type: 'problem',
|
|
8
8
|
docs: {
|
|
9
9
|
description: 'Disallow invalid selector nesting (e.g. Pseudo -> Query, Query -> Query) based on Plumeria rules.',
|
|
10
10
|
},
|
|
11
11
|
messages: {
|
|
12
|
+
invalidKeySelector: 'Invalid key selector.',
|
|
12
13
|
noQueryInsidePseudo: 'Media/Container queries cannot be nested inside pseudo-selectors.',
|
|
13
14
|
noQueryInsideQuery: 'Media/Container queries cannot be nested inside other queries.',
|
|
14
15
|
noPseudoInsidePseudo: 'Pseudo-selectors cannot be nested inside other pseudo-selectors.',
|
|
16
|
+
invalidKeyframesKey: 'Keyframes keys must be "from", "to", or a percentage value (e.g. "0%", "50%", "100%").',
|
|
17
|
+
invalidViewTransitionKey: 'ViewTransition keys must be one of: "group", "imagePair", "new", "old".',
|
|
15
18
|
},
|
|
16
19
|
schema: [],
|
|
17
20
|
},
|
|
@@ -43,15 +46,8 @@ exports.noInvalidSelectorNesting = {
|
|
|
43
46
|
if (type.value.startsWith(':'))
|
|
44
47
|
return 'PSEUDO';
|
|
45
48
|
}
|
|
46
|
-
if (type.isUnion()) {
|
|
47
|
-
const types = type.types;
|
|
48
|
-
if (types.every((t) => t.isStringLiteral() && t.value.startsWith('@')))
|
|
49
|
-
return 'QUERY';
|
|
50
|
-
if (types.every((t) => t.isStringLiteral() && t.value.startsWith(':')))
|
|
51
|
-
return 'PSEUDO';
|
|
52
|
-
}
|
|
53
49
|
}
|
|
54
|
-
catch (
|
|
50
|
+
catch (error) {
|
|
55
51
|
}
|
|
56
52
|
}
|
|
57
53
|
return 'UNKNOWN';
|
|
@@ -61,6 +57,12 @@ exports.noInvalidSelectorNesting = {
|
|
|
61
57
|
if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
|
|
62
58
|
continue;
|
|
63
59
|
const currentType = getSelectorType(prop.key);
|
|
60
|
+
if (currentType === 'UNKNOWN') {
|
|
61
|
+
context.report({
|
|
62
|
+
node: prop.key,
|
|
63
|
+
messageId: 'invalidKeySelector',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
64
66
|
if (parentType === 'PSEUDO' && currentType === 'QUERY') {
|
|
65
67
|
context.report({
|
|
66
68
|
node: prop.key,
|
|
@@ -81,6 +83,77 @@ exports.noInvalidSelectorNesting = {
|
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
}
|
|
86
|
+
function checkOnlyProperties(node) {
|
|
87
|
+
for (const prop of node.properties) {
|
|
88
|
+
if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
|
|
89
|
+
continue;
|
|
90
|
+
const currentType = getSelectorType(prop.key);
|
|
91
|
+
if (currentType !== 'PROPERTY') {
|
|
92
|
+
context.report({
|
|
93
|
+
node: prop.key,
|
|
94
|
+
messageId: 'invalidKeySelector',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (prop.value.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
98
|
+
checkOnlyProperties(prop.value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function getKeyString(node) {
|
|
103
|
+
if (node.type === utils_1.TSESTree.AST_NODE_TYPES.Literal &&
|
|
104
|
+
typeof node.value === 'string') {
|
|
105
|
+
return node.value;
|
|
106
|
+
}
|
|
107
|
+
if (node.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
108
|
+
return node.name;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
function checkKeyframesKeys(node) {
|
|
113
|
+
for (const prop of node.properties) {
|
|
114
|
+
if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
|
|
115
|
+
continue;
|
|
116
|
+
const key = getKeyString(prop.key);
|
|
117
|
+
if (key == null) {
|
|
118
|
+
context.report({
|
|
119
|
+
node: prop.key,
|
|
120
|
+
messageId: 'invalidKeyframesKey',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (prop.value.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
124
|
+
checkOnlyProperties(prop.value);
|
|
125
|
+
}
|
|
126
|
+
if (key !== null &&
|
|
127
|
+
key !== 'from' &&
|
|
128
|
+
key !== 'to' &&
|
|
129
|
+
!/^\d+(\.\d+)?%$/.test(key)) {
|
|
130
|
+
context.report({ node: prop.key, messageId: 'invalidKeyframesKey' });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function checkViewTransitionKeys(node) {
|
|
135
|
+
const allowed = new Set(['group', 'imagePair', 'new', 'old']);
|
|
136
|
+
for (const prop of node.properties) {
|
|
137
|
+
if (prop.type !== utils_1.TSESTree.AST_NODE_TYPES.Property)
|
|
138
|
+
continue;
|
|
139
|
+
const key = getKeyString(prop.key);
|
|
140
|
+
if (key == null) {
|
|
141
|
+
context.report({
|
|
142
|
+
node: prop.key,
|
|
143
|
+
messageId: 'invalidViewTransitionKey',
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (prop.value.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
147
|
+
checkOnlyProperties(prop.value);
|
|
148
|
+
}
|
|
149
|
+
if (key !== null && !allowed.has(key)) {
|
|
150
|
+
context.report({
|
|
151
|
+
node: prop.key,
|
|
152
|
+
messageId: 'invalidViewTransitionKey',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
84
157
|
return {
|
|
85
158
|
ImportDeclaration(node) {
|
|
86
159
|
if (node.source.value === '@plumeria/core') {
|
|
@@ -101,6 +174,8 @@ exports.noInvalidSelectorNesting = {
|
|
|
101
174
|
},
|
|
102
175
|
CallExpression(node) {
|
|
103
176
|
let isCssCreate = false;
|
|
177
|
+
let isCssKeyframes = false;
|
|
178
|
+
let isCssViewTransition = false;
|
|
104
179
|
if (node.callee.type === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression) {
|
|
105
180
|
if (node.callee.object.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier &&
|
|
106
181
|
plumeriaAliases[node.callee.object.name] === 'NAMESPACE') {
|
|
@@ -109,23 +184,48 @@ exports.noInvalidSelectorNesting = {
|
|
|
109
184
|
: null;
|
|
110
185
|
if (propertyName === 'create')
|
|
111
186
|
isCssCreate = true;
|
|
187
|
+
if (propertyName === 'keyframes')
|
|
188
|
+
isCssKeyframes = true;
|
|
189
|
+
if (propertyName === 'viewTransition')
|
|
190
|
+
isCssViewTransition = true;
|
|
112
191
|
}
|
|
113
192
|
}
|
|
114
193
|
else if (node.callee.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
115
194
|
const alias = plumeriaAliases[node.callee.name];
|
|
116
195
|
if (alias === 'create')
|
|
117
196
|
isCssCreate = true;
|
|
197
|
+
if (alias === 'keyframes')
|
|
198
|
+
isCssKeyframes = true;
|
|
199
|
+
if (alias === 'viewTransition')
|
|
200
|
+
isCssViewTransition = true;
|
|
118
201
|
}
|
|
119
202
|
if (isCssCreate &&
|
|
120
203
|
node.arguments[0]?.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
121
204
|
const styleObj = node.arguments[0];
|
|
122
205
|
styleObj.properties.forEach((prop) => {
|
|
206
|
+
if (prop.type === utils_1.TSESTree.AST_NODE_TYPES.Property) {
|
|
207
|
+
const currentType = getSelectorType(prop.key);
|
|
208
|
+
if (currentType === 'UNKNOWN') {
|
|
209
|
+
context.report({
|
|
210
|
+
node: prop.key,
|
|
211
|
+
messageId: 'invalidKeySelector',
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
123
215
|
if (prop.type === utils_1.TSESTree.AST_NODE_TYPES.Property &&
|
|
124
216
|
prop.value.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
125
217
|
checkNesting(prop.value, 'CLASS');
|
|
126
218
|
}
|
|
127
219
|
});
|
|
128
220
|
}
|
|
221
|
+
if (isCssKeyframes &&
|
|
222
|
+
node.arguments[0]?.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
223
|
+
checkKeyframesKeys(node.arguments[0]);
|
|
224
|
+
}
|
|
225
|
+
if (isCssViewTransition &&
|
|
226
|
+
node.arguments[0]?.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
227
|
+
checkViewTransitionKeys(node.arguments[0]);
|
|
228
|
+
}
|
|
129
229
|
},
|
|
130
230
|
};
|
|
131
231
|
},
|
package/package.json
CHANGED