@plumeria/eslint-plugin 10.4.3 → 10.5.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 +5 -1
- package/dist/index.js +5 -1
- package/dist/rules/format-properties.js +144 -87
- package/dist/rules/no-combinator.js +11 -14
- package/dist/rules/no-destructure.js +5 -4
- package/dist/rules/no-inline-object.d.ts +2 -0
- package/dist/rules/no-inline-object.js +54 -0
- package/dist/rules/no-inner-call.js +5 -4
- package/dist/rules/no-unknown-css-properties.js +30 -26
- package/dist/rules/no-unused-keys.js +13 -15
- package/dist/rules/sort-properties.js +142 -82
- package/dist/rules/validate-values.js +1210 -1681
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ The `plugin:@plumeria/recommended` config enables the following:
|
|
|
10
10
|
- `@plumeria/style-name-requires-import`: **error**
|
|
11
11
|
- `@plumeria/no-combinator`: **error**
|
|
12
12
|
- `@plumeria/no-destructure`: **error**
|
|
13
|
+
- `@plumeria/no-inline-object`: **error**
|
|
13
14
|
- `@plumeria/no-inner-call`: **error**
|
|
14
15
|
- `@plumeria/no-unknown-css-properties`: **error**
|
|
15
16
|
- `@plumeria/no-unused-keys`: **warn**
|
|
@@ -29,7 +30,6 @@ export default [plumeria.flatConfigs.recommended];
|
|
|
29
30
|
|
|
30
31
|
Disallow styleName prop in files without a @plumeria/core import.
|
|
31
32
|
|
|
32
|
-
|
|
33
33
|
### no-combinator
|
|
34
34
|
|
|
35
35
|
Disallow combinators `>`, `+`, `~` and descendant combinator (space) unless inside functional pseudo-classes.
|
|
@@ -38,6 +38,10 @@ Disallow combinators `>`, `+`, `~` and descendant combinator (space) unless insi
|
|
|
38
38
|
|
|
39
39
|
Disallow destructuring APIs.
|
|
40
40
|
|
|
41
|
+
### no-inline-object
|
|
42
|
+
|
|
43
|
+
Disallow passing inline object to `styleName` and `css.use()`. Only compiled styles from `css.create()` are allowed.
|
|
44
|
+
|
|
41
45
|
### no-inner-call
|
|
42
46
|
|
|
43
47
|
Disallow calling APIs inside functions.
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.plumeria = void 0;
|
|
4
|
+
const style_name_requires_import_1 = require("./rules/style-name-requires-import");
|
|
4
5
|
const no_combinator_1 = require("./rules/no-combinator");
|
|
5
6
|
const no_destructure_1 = require("./rules/no-destructure");
|
|
7
|
+
const no_inline_object_1 = require("./rules/no-inline-object");
|
|
6
8
|
const no_inner_call_1 = require("./rules/no-inner-call");
|
|
7
9
|
const no_unused_keys_1 = require("./rules/no-unused-keys");
|
|
8
10
|
const sort_properties_1 = require("./rules/sort-properties");
|
|
9
11
|
const format_properties_1 = require("./rules/format-properties");
|
|
10
12
|
const validate_values_1 = require("./rules/validate-values");
|
|
11
|
-
const style_name_requires_import_1 = require("./rules/style-name-requires-import");
|
|
12
13
|
const no_unknown_css_properties_1 = require("./rules/no-unknown-css-properties");
|
|
13
14
|
const rules = {
|
|
14
15
|
'style-name-requires-import': style_name_requires_import_1.styleNameRequiresImport,
|
|
15
16
|
'no-combinator': no_combinator_1.noCombinator,
|
|
16
17
|
'no-destructure': no_destructure_1.noDestructure,
|
|
18
|
+
'no-inline-object': no_inline_object_1.noInlineObject,
|
|
17
19
|
'no-inner-call': no_inner_call_1.noInnerCall,
|
|
18
20
|
'no-unknown-css-properties': no_unknown_css_properties_1.noUnknownCssProperties,
|
|
19
21
|
'no-unused-keys': no_unused_keys_1.noUnusedKeys,
|
|
@@ -28,6 +30,7 @@ const configs = {
|
|
|
28
30
|
'@plumeria/style-name-requires-import': 'error',
|
|
29
31
|
'@plumeria/no-combinator': 'error',
|
|
30
32
|
'@plumeria/no-destructure': 'error',
|
|
33
|
+
'@plumeria/no-inline-object': 'error',
|
|
31
34
|
'@plumeria/no-inner-call': 'error',
|
|
32
35
|
'@plumeria/no-unknown-css-properties': 'error',
|
|
33
36
|
'@plumeria/no-unused-keys': 'warn',
|
|
@@ -48,6 +51,7 @@ const flatConfigs = {
|
|
|
48
51
|
'@plumeria/style-name-requires-import': 'error',
|
|
49
52
|
'@plumeria/no-combinator': 'error',
|
|
50
53
|
'@plumeria/no-destructure': 'error',
|
|
54
|
+
'@plumeria/no-inline-object': 'error',
|
|
51
55
|
'@plumeria/no-inner-call': 'error',
|
|
52
56
|
'@plumeria/no-unknown-css-properties': 'error',
|
|
53
57
|
'@plumeria/no-unused-keys': 'warn',
|
|
@@ -18,106 +18,163 @@ exports.formatProperties = {
|
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
20
|
create(context) {
|
|
21
|
+
const plumeriaAliases = {};
|
|
21
22
|
const sourceCode = getSourceCode(context);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
function checkStyleObject(node) {
|
|
24
|
+
if (node.type !== 'ObjectExpression' || node.properties.length === 0)
|
|
25
|
+
return;
|
|
26
|
+
const properties = node.properties;
|
|
27
|
+
const parentLine = sourceCode.lines[node.parent.loc.start.line - 1];
|
|
28
|
+
const baseIndent = parentLine.match(/^(\s*)/)[1];
|
|
29
|
+
const innerIndent = baseIndent + ' ';
|
|
30
|
+
const countNewlines = (text) => (text.match(/\n/g) ?? []).length;
|
|
31
|
+
const isWhitespaceOnly = (text) => /^\s*$/.test(text);
|
|
32
|
+
const fullText = sourceCode.getText();
|
|
33
|
+
const openBrace = sourceCode.getFirstToken(node);
|
|
34
|
+
const closeBrace = sourceCode.getLastToken(node);
|
|
35
|
+
let hasError = false;
|
|
36
|
+
let hasBlankLines = false;
|
|
37
|
+
const textBeforeFirst = fullText.slice(openBrace.range[1], properties[0].range[0]);
|
|
38
|
+
const newlinesBeforeFirst = countNewlines(textBeforeFirst);
|
|
39
|
+
if (newlinesBeforeFirst === 0)
|
|
40
|
+
hasError = true;
|
|
41
|
+
for (let i = 0; i < properties.length - 1; i++) {
|
|
42
|
+
const current = properties[i];
|
|
43
|
+
const next = properties[i + 1];
|
|
44
|
+
const comma = sourceCode.getTokenAfter(current);
|
|
45
|
+
const sliceStart = comma.range[1];
|
|
46
|
+
const between = fullText.slice(sliceStart, next.range[0]);
|
|
47
|
+
const newlines = countNewlines(between);
|
|
48
|
+
if (newlines === 0)
|
|
42
49
|
hasError = true;
|
|
50
|
+
if (newlines > 1 && isWhitespaceOnly(between))
|
|
51
|
+
hasBlankLines = true;
|
|
52
|
+
}
|
|
53
|
+
const lastProp = properties[properties.length - 1];
|
|
54
|
+
const lastComma = sourceCode.getTokenAfter(lastProp);
|
|
55
|
+
const lastSliceStart = lastComma?.value === ',' ? lastComma.range[1] : lastProp.range[1];
|
|
56
|
+
const textAfterLast = fullText.slice(lastSliceStart, closeBrace.range[0]);
|
|
57
|
+
const newlinesAfterLast = countNewlines(textAfterLast);
|
|
58
|
+
if (newlinesAfterLast === 0)
|
|
59
|
+
hasError = true;
|
|
60
|
+
properties.forEach((prop) => {
|
|
61
|
+
if (prop.type === 'Property' &&
|
|
62
|
+
prop.value &&
|
|
63
|
+
prop.value.type === 'ObjectExpression') {
|
|
64
|
+
checkStyleObject(prop.value);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
if (!hasError && !hasBlankLines)
|
|
68
|
+
return;
|
|
69
|
+
const buildFixes = (fixer) => {
|
|
70
|
+
const fixes = [];
|
|
71
|
+
fixes.push(fixer.replaceTextRange([openBrace.range[1], properties[0].range[0]], `\n${innerIndent}`));
|
|
43
72
|
for (let i = 0; i < properties.length - 1; i++) {
|
|
44
73
|
const current = properties[i];
|
|
45
74
|
const next = properties[i + 1];
|
|
46
75
|
const comma = sourceCode.getTokenAfter(current);
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
hasError = true;
|
|
52
|
-
if (newlines > 1 && isWhitespaceOnly(between))
|
|
53
|
-
hasBlankLines = true;
|
|
76
|
+
const betweenText = fullText.slice(comma.range[1], next.range[0]);
|
|
77
|
+
if (isWhitespaceOnly(betweenText)) {
|
|
78
|
+
fixes.push(fixer.replaceTextRange([comma.range[1], next.range[0]], `\n${innerIndent}`));
|
|
79
|
+
}
|
|
54
80
|
}
|
|
55
|
-
const lastProp = properties[properties.length - 1];
|
|
56
81
|
const lastComma = sourceCode.getTokenAfter(lastProp);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
else {
|
|
83
|
-
fixes.push(fixer.replaceTextRange([lastProp.range[1], closeBrace.range[0]], `\n${baseIndent}`));
|
|
84
|
-
}
|
|
85
|
-
return fixes;
|
|
86
|
-
};
|
|
87
|
-
if (hasError) {
|
|
82
|
+
if (lastComma?.value === ',') {
|
|
83
|
+
fixes.push(fixer.replaceTextRange([lastComma.range[1], closeBrace.range[0]], `\n${baseIndent}`));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
fixes.push(fixer.replaceTextRange([lastProp.range[1], closeBrace.range[0]], `\n${baseIndent}`));
|
|
87
|
+
}
|
|
88
|
+
return fixes;
|
|
89
|
+
};
|
|
90
|
+
if (hasError) {
|
|
91
|
+
context.report({
|
|
92
|
+
node,
|
|
93
|
+
messageId: 'mustBeMultiline',
|
|
94
|
+
fix: buildFixes,
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
let reported = false;
|
|
99
|
+
for (let i = 0; i < properties.length - 1; i++) {
|
|
100
|
+
const current = properties[i];
|
|
101
|
+
const next = properties[i + 1];
|
|
102
|
+
const comma = sourceCode.getTokenAfter(current);
|
|
103
|
+
const sliceStart = comma.range[1];
|
|
104
|
+
const between = fullText.slice(sliceStart, next.range[0]);
|
|
105
|
+
if (countNewlines(between) > 1 && isWhitespaceOnly(between)) {
|
|
106
|
+
const blankLineNumber = current.loc.end.line + 1;
|
|
88
107
|
context.report({
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
108
|
+
loc: {
|
|
109
|
+
start: {
|
|
110
|
+
line: blankLineNumber,
|
|
111
|
+
column: 0,
|
|
112
|
+
},
|
|
113
|
+
end: {
|
|
114
|
+
line: blankLineNumber + 1,
|
|
115
|
+
column: 0,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
messageId: 'noEmptyLines',
|
|
119
|
+
fix: reported ? null : buildFixes,
|
|
92
120
|
});
|
|
93
|
-
|
|
121
|
+
reported = true;
|
|
94
122
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
ImportDeclaration(node) {
|
|
127
|
+
if (node.source.value === '@plumeria/core') {
|
|
128
|
+
node.specifiers.forEach((specifier) => {
|
|
129
|
+
if (specifier.type === 'ImportNamespaceSpecifier' ||
|
|
130
|
+
specifier.type === 'ImportDefaultSpecifier') {
|
|
131
|
+
plumeriaAliases[specifier.local.name] = 'NAMESPACE';
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const spec = specifier;
|
|
135
|
+
const importedName = spec.imported.type === 'Identifier'
|
|
136
|
+
? spec.imported.name
|
|
137
|
+
: String(spec.imported.value);
|
|
138
|
+
plumeriaAliases[specifier.local.name] = importedName;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
CallExpression(node) {
|
|
144
|
+
let isCssProperties = false;
|
|
145
|
+
if (node.callee.type === 'MemberExpression') {
|
|
146
|
+
if (node.callee.object.type === 'Identifier' &&
|
|
147
|
+
plumeriaAliases[node.callee.object.name] === 'NAMESPACE') {
|
|
148
|
+
const propertyName = node.callee.property.type === 'Identifier'
|
|
149
|
+
? node.callee.property.name
|
|
150
|
+
: null;
|
|
151
|
+
if (propertyName === 'create' ||
|
|
152
|
+
propertyName === 'keyframes' ||
|
|
153
|
+
propertyName === 'viewTransition') {
|
|
154
|
+
isCssProperties = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else if (node.callee.type === 'Identifier') {
|
|
159
|
+
const alias = plumeriaAliases[node.callee.name];
|
|
160
|
+
if (alias === 'create' ||
|
|
161
|
+
alias === 'keyframes' ||
|
|
162
|
+
alias === 'viewTransition') {
|
|
163
|
+
isCssProperties = true;
|
|
119
164
|
}
|
|
120
165
|
}
|
|
166
|
+
if (isCssProperties) {
|
|
167
|
+
node.arguments.forEach((arg) => {
|
|
168
|
+
if (arg.type === 'ObjectExpression') {
|
|
169
|
+
arg.properties.forEach((prop) => {
|
|
170
|
+
if (prop.type === 'Property' &&
|
|
171
|
+
prop.value.type === 'ObjectExpression') {
|
|
172
|
+
checkStyleObject(prop.value);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
121
178
|
},
|
|
122
179
|
};
|
|
123
180
|
},
|
|
@@ -43,13 +43,11 @@ exports.noCombinator = {
|
|
|
43
43
|
while (next < len && isSpace(s[next])) {
|
|
44
44
|
next++;
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
46
|
+
const nextChar = s[next];
|
|
47
|
+
const prevChar = s[i - 1];
|
|
48
|
+
if (!isCombinatorOrSeparator(prevChar) &&
|
|
49
|
+
!isCombinatorOrSeparator(nextChar)) {
|
|
50
|
+
return false;
|
|
53
51
|
}
|
|
54
52
|
i = next;
|
|
55
53
|
continue;
|
|
@@ -114,10 +112,11 @@ exports.noCombinator = {
|
|
|
114
112
|
specifier.type === 'ImportDefaultSpecifier') {
|
|
115
113
|
plumeriaAliases[specifier.local.name] = 'NAMESPACE';
|
|
116
114
|
}
|
|
117
|
-
else
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
else {
|
|
116
|
+
const spec = specifier;
|
|
117
|
+
const importedName = spec.imported.type === 'Identifier'
|
|
118
|
+
? spec.imported.name
|
|
119
|
+
: String(spec.imported.value);
|
|
121
120
|
plumeriaAliases[specifier.local.name] = importedName;
|
|
122
121
|
}
|
|
123
122
|
});
|
|
@@ -209,9 +208,7 @@ exports.noCombinator = {
|
|
|
209
208
|
found = '+';
|
|
210
209
|
else if (text.includes('~'))
|
|
211
210
|
found = '~';
|
|
212
|
-
else
|
|
213
|
-
text.includes('\t') ||
|
|
214
|
-
text.includes('\n'))
|
|
211
|
+
else
|
|
215
212
|
found = '(space)';
|
|
216
213
|
context.report({
|
|
217
214
|
node: node,
|
|
@@ -24,10 +24,11 @@ exports.noDestructure = {
|
|
|
24
24
|
else if (specifier.type === 'ImportDefaultSpecifier') {
|
|
25
25
|
plumeriaAliases[specifier.local.name] = 'NAMESPACE';
|
|
26
26
|
}
|
|
27
|
-
else
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
else {
|
|
28
|
+
const spec = specifier;
|
|
29
|
+
const importedName = spec.imported.type === 'Identifier'
|
|
30
|
+
? spec.imported.name
|
|
31
|
+
: String(spec.imported.value);
|
|
31
32
|
plumeriaAliases[specifier.local.name] = importedName;
|
|
32
33
|
}
|
|
33
34
|
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noInlineObject = void 0;
|
|
4
|
+
exports.noInlineObject = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Disallow inline objects in styleName and css.use',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
noInlineObjectInStyleName: 'Do not pass inline objects to styleName. It only accepts compiled styles from css.create().',
|
|
12
|
+
noInlineObjectInCssUse: 'Do not pass inline objects to css.use(). It only accepts compiled styles from css.create().',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
create(context) {
|
|
17
|
+
function isInsideOtherCall(node) {
|
|
18
|
+
let current = node.parent;
|
|
19
|
+
while (current && current.type !== 'JSXAttribute') {
|
|
20
|
+
if (current.type === 'CallExpression') {
|
|
21
|
+
const callee = current.callee;
|
|
22
|
+
if (callee.type === 'MemberExpression' &&
|
|
23
|
+
callee.object.type === 'Identifier' &&
|
|
24
|
+
callee.object.name === 'css' &&
|
|
25
|
+
callee.property.type === 'Identifier' &&
|
|
26
|
+
callee.property.name === 'use') {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
current = current.parent;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
'JSXAttribute[name.name="styleName"] ObjectExpression'(node) {
|
|
37
|
+
if (isInsideOtherCall(node))
|
|
38
|
+
return;
|
|
39
|
+
context.report({
|
|
40
|
+
node,
|
|
41
|
+
messageId: 'noInlineObjectInStyleName',
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
'CallExpression[callee.object.name="css"][callee.property.name="use"] ObjectExpression'(node) {
|
|
45
|
+
if (isInsideOtherCall(node))
|
|
46
|
+
return;
|
|
47
|
+
context.report({
|
|
48
|
+
node,
|
|
49
|
+
messageId: 'noInlineObjectInCssUse',
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
};
|
|
@@ -25,10 +25,11 @@ exports.noInnerCall = {
|
|
|
25
25
|
else if (specifier.type === 'ImportDefaultSpecifier') {
|
|
26
26
|
plumeriaAliases[specifier.local.name] = 'NAMESPACE';
|
|
27
27
|
}
|
|
28
|
-
else
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
else {
|
|
29
|
+
const spec = specifier;
|
|
30
|
+
const importedName = spec.imported.type === 'Identifier'
|
|
31
|
+
? spec.imported.name
|
|
32
|
+
: String(spec.imported.value);
|
|
32
33
|
plumeriaAliases[specifier.local.name] = importedName;
|
|
33
34
|
}
|
|
34
35
|
});
|
|
@@ -3,8 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.noUnknownCssProperties = void 0;
|
|
4
4
|
const known_css_properties_1 = require("known-css-properties");
|
|
5
5
|
const knownProperties = new Set(known_css_properties_1.all);
|
|
6
|
+
const kebabCache = new Map();
|
|
6
7
|
function toKebabCase(str) {
|
|
7
|
-
|
|
8
|
+
if (kebabCache.has(str)) {
|
|
9
|
+
return kebabCache.get(str);
|
|
10
|
+
}
|
|
11
|
+
const result = str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
12
|
+
kebabCache.set(str, result);
|
|
13
|
+
return result;
|
|
8
14
|
}
|
|
9
15
|
exports.noUnknownCssProperties = {
|
|
10
16
|
meta: {
|
|
@@ -27,9 +33,12 @@ exports.noUnknownCssProperties = {
|
|
|
27
33
|
specifier.type === 'ImportDefaultSpecifier') {
|
|
28
34
|
plumeriaAliases[specifier.local.name] = 'NAMESPACE';
|
|
29
35
|
}
|
|
30
|
-
else
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
else {
|
|
37
|
+
const spec = specifier;
|
|
38
|
+
const importedName = spec.imported.type === 'Identifier'
|
|
39
|
+
? spec.imported.name
|
|
40
|
+
: String(spec.imported.value);
|
|
41
|
+
plumeriaAliases[specifier.local.name] = importedName;
|
|
33
42
|
}
|
|
34
43
|
});
|
|
35
44
|
}
|
|
@@ -74,34 +83,29 @@ exports.noUnknownCssProperties = {
|
|
|
74
83
|
function checkStyleObject(node) {
|
|
75
84
|
node.properties.forEach((prop) => {
|
|
76
85
|
if (prop.type === 'Property') {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
keyName = prop.key.name;
|
|
80
|
-
}
|
|
81
|
-
else if (prop.key.type === 'Literal') {
|
|
82
|
-
keyName = String(prop.key.value);
|
|
86
|
+
if (prop.value.type === 'ObjectExpression') {
|
|
87
|
+
checkStyleObject(prop.value);
|
|
83
88
|
}
|
|
84
|
-
if (
|
|
89
|
+
if (!prop.computed) {
|
|
90
|
+
const keyName = prop.key.type === 'Identifier'
|
|
91
|
+
? prop.key.name
|
|
92
|
+
: String(prop.key.value);
|
|
85
93
|
if (!keyName.startsWith(':') &&
|
|
86
94
|
!keyName.startsWith('[') &&
|
|
87
|
-
!keyName.startsWith('@')
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
95
|
+
!keyName.startsWith('@') &&
|
|
96
|
+
!keyName.startsWith('--')) {
|
|
97
|
+
const kebabName = toKebabCase(keyName);
|
|
98
|
+
if (!knownProperties.has(kebabName)) {
|
|
99
|
+
context.report({
|
|
100
|
+
node: prop.key,
|
|
101
|
+
messageId: 'unknownProperty',
|
|
102
|
+
data: {
|
|
103
|
+
name: keyName,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
99
106
|
}
|
|
100
107
|
}
|
|
101
108
|
}
|
|
102
|
-
if (prop.value.type === 'ObjectExpression') {
|
|
103
|
-
checkStyleObject(prop.value);
|
|
104
|
-
}
|
|
105
109
|
}
|
|
106
110
|
});
|
|
107
111
|
}
|
|
@@ -11,6 +11,7 @@ function getRootObject(node) {
|
|
|
11
11
|
if (node.type === 'MemberExpression') {
|
|
12
12
|
return getRootObject(node.object);
|
|
13
13
|
}
|
|
14
|
+
return undefined;
|
|
14
15
|
}
|
|
15
16
|
exports.noUnusedKeys = {
|
|
16
17
|
meta: {
|
|
@@ -42,12 +43,11 @@ exports.noUnusedKeys = {
|
|
|
42
43
|
if (arg &&
|
|
43
44
|
arg.type === 'ObjectExpression' &&
|
|
44
45
|
node.parent.type === 'VariableDeclarator' &&
|
|
45
|
-
|
|
46
|
+
node.parent.id.type === 'Identifier') {
|
|
46
47
|
const variableName = node.parent.id.name;
|
|
47
48
|
const keyMap = new Map();
|
|
48
49
|
arg.properties.forEach((prop) => {
|
|
49
50
|
if (prop.type === 'Property' &&
|
|
50
|
-
prop.key &&
|
|
51
51
|
prop.key.type === 'Identifier' &&
|
|
52
52
|
prop.value.type === 'ObjectExpression') {
|
|
53
53
|
keyMap.set(prop.key.name, prop.key);
|
|
@@ -58,22 +58,20 @@ exports.noUnusedKeys = {
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
MemberExpression(node) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (rootObject && rootObject.type === 'Identifier') {
|
|
64
|
-
const variableName = rootObject.name;
|
|
65
|
-
dynamicallyAccessedVars.add(variableName);
|
|
66
|
-
definedKeys.delete(variableName);
|
|
67
|
-
}
|
|
61
|
+
const rootObject = getRootObject(node.object);
|
|
62
|
+
if (!rootObject)
|
|
68
63
|
return;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const normalKey = `${rootObject.name}.${node.property.name}`;
|
|
74
|
-
referencedKeys.add(normalKey);
|
|
64
|
+
if (node.computed) {
|
|
65
|
+
if (node.property.type === 'Identifier') {
|
|
66
|
+
dynamicallyAccessedVars.add(rootObject.name);
|
|
67
|
+
definedKeys.delete(rootObject.name);
|
|
75
68
|
}
|
|
69
|
+
else if (node.property.type === 'Literal') {
|
|
70
|
+
referencedKeys.add(`${rootObject.name}.${node.property.value}`);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
76
73
|
}
|
|
74
|
+
referencedKeys.add(`${rootObject.name}.${node.property.name}`);
|
|
77
75
|
},
|
|
78
76
|
'Program:exit'() {
|
|
79
77
|
definedKeys.forEach((keyMap, variableName) => {
|