@plumeria/eslint-plugin 10.4.2 → 10.5.0
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 +23 -25
- package/dist/rules/no-unused-keys.js +13 -15
- package/dist/rules/sort-properties.js +142 -82
- package/dist/rules/validate-values.js +1674 -1602
- package/package.json +1 -1
|
@@ -14,11 +14,8 @@ function getPropertyName(property) {
|
|
|
14
14
|
}
|
|
15
15
|
return '';
|
|
16
16
|
}
|
|
17
|
-
function getPropertyIndex(property
|
|
17
|
+
function getPropertyIndex(property) {
|
|
18
18
|
const name = getPropertyName(property);
|
|
19
|
-
if (isTopLevel) {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
19
|
let lastGroupIndex = 0;
|
|
23
20
|
let maxPropIndex = 0;
|
|
24
21
|
for (let i = 0; i < propertyGroups_1.propertyGroups.length; i++) {
|
|
@@ -30,16 +27,14 @@ function getPropertyIndex(property, isTopLevel) {
|
|
|
30
27
|
lastGroupIndex = i;
|
|
31
28
|
maxPropIndex = Math.max(maxPropIndex, group.properties.length);
|
|
32
29
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return (propertyGroups_1.propertyGroups.length + 3) * 1000;
|
|
42
|
-
}
|
|
30
|
+
if (name.startsWith(':'))
|
|
31
|
+
return (propertyGroups_1.propertyGroups.length + 1) * 1000;
|
|
32
|
+
if (name.startsWith('&'))
|
|
33
|
+
return (propertyGroups_1.propertyGroups.length + 2) * 1000;
|
|
34
|
+
if (name.startsWith('@media'))
|
|
35
|
+
return (propertyGroups_1.propertyGroups.length + 3) * 1000;
|
|
36
|
+
if (name.startsWith('@container'))
|
|
37
|
+
return (propertyGroups_1.propertyGroups.length + 3) * 1000;
|
|
43
38
|
return lastGroupIndex * 1000 + maxPropIndex + 1;
|
|
44
39
|
}
|
|
45
40
|
function getLIS(arr) {
|
|
@@ -85,78 +80,143 @@ exports.sortProperties = {
|
|
|
85
80
|
},
|
|
86
81
|
},
|
|
87
82
|
create(context) {
|
|
83
|
+
const plumeriaAliases = {};
|
|
84
|
+
function checkStyleObject(node) {
|
|
85
|
+
const sourceCode = getSourceCode(context);
|
|
86
|
+
const properties = node.properties.filter((prop) => ('key' in prop && !!prop.key) || prop.type === 'SpreadElement');
|
|
87
|
+
const chunks = [];
|
|
88
|
+
let currentChunk = [];
|
|
89
|
+
properties.forEach((prop) => {
|
|
90
|
+
if (prop.type === 'SpreadElement') {
|
|
91
|
+
if (currentChunk.length > 0)
|
|
92
|
+
chunks.push(currentChunk);
|
|
93
|
+
chunks.push([prop]);
|
|
94
|
+
currentChunk = [];
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
currentChunk.push(prop);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (currentChunk.length > 0)
|
|
101
|
+
chunks.push(currentChunk);
|
|
102
|
+
const sorted = chunks
|
|
103
|
+
.map((chunk) => {
|
|
104
|
+
if (chunk.length === 1 && chunk[0].type === 'SpreadElement') {
|
|
105
|
+
return chunk;
|
|
106
|
+
}
|
|
107
|
+
return [...chunk].sort((a, b) => {
|
|
108
|
+
const indexA = getPropertyIndex(a);
|
|
109
|
+
const indexB = getPropertyIndex(b);
|
|
110
|
+
return indexA - indexB;
|
|
111
|
+
});
|
|
112
|
+
})
|
|
113
|
+
.flat();
|
|
114
|
+
const propertyToIndexInSorted = new Map();
|
|
115
|
+
sorted.forEach((prop, index) => {
|
|
116
|
+
propertyToIndexInSorted.set(prop, index);
|
|
117
|
+
});
|
|
118
|
+
const targetPositions = properties.map((prop) => propertyToIndexInSorted.get(prop));
|
|
119
|
+
const lisIndices = new Set(getLIS(targetPositions));
|
|
120
|
+
const misorderedIndices = properties
|
|
121
|
+
.map((_, i) => i)
|
|
122
|
+
.filter((i) => !lisIndices.has(i));
|
|
123
|
+
properties.forEach((prop) => {
|
|
124
|
+
if (prop.type === 'Property' &&
|
|
125
|
+
prop.value &&
|
|
126
|
+
prop.value.type === 'ObjectExpression') {
|
|
127
|
+
checkStyleObject(prop.value);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
if (misorderedIndices.length === 0)
|
|
131
|
+
return;
|
|
132
|
+
const match = sourceCode.getText(node).match(/^{\s*\n(\s*)/);
|
|
133
|
+
const indent = match ? match[1] : '';
|
|
134
|
+
const lineEnding = match ? '\n' : ' ';
|
|
135
|
+
const closingIndentMatch = sourceCode.getText(node).match(/\n(\s*)}$/);
|
|
136
|
+
const closingIndent = closingIndentMatch ? closingIndentMatch[1] : '';
|
|
137
|
+
misorderedIndices.forEach((i) => {
|
|
138
|
+
const prop = properties[i];
|
|
139
|
+
context.report({
|
|
140
|
+
node: prop.key,
|
|
141
|
+
messageId: 'sortProperties',
|
|
142
|
+
data: {
|
|
143
|
+
position: String(sorted.indexOf(prop) + 1),
|
|
144
|
+
property: getPropertyName(prop),
|
|
145
|
+
},
|
|
146
|
+
fix(fixer) {
|
|
147
|
+
const newText = sorted
|
|
148
|
+
.map((p) => {
|
|
149
|
+
return `${indent}${sourceCode.getText(p)}`;
|
|
150
|
+
})
|
|
151
|
+
.join(`,${lineEnding}`);
|
|
152
|
+
return fixer.replaceTextRange([
|
|
153
|
+
node.range[0] + 1,
|
|
154
|
+
node.range[1] - 1,
|
|
155
|
+
], `${lineEnding}${newText}${lineEnding}${closingIndent}`);
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
properties.forEach((prop) => {
|
|
160
|
+
if (prop.type === 'Property' &&
|
|
161
|
+
prop.value &&
|
|
162
|
+
prop.value.type === 'ObjectExpression') {
|
|
163
|
+
checkStyleObject(prop.value);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
88
167
|
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
168
|
+
ImportDeclaration(node) {
|
|
169
|
+
if (node.source.value === '@plumeria/core') {
|
|
170
|
+
node.specifiers.forEach((specifier) => {
|
|
171
|
+
if (specifier.type === 'ImportNamespaceSpecifier' ||
|
|
172
|
+
specifier.type === 'ImportDefaultSpecifier') {
|
|
173
|
+
plumeriaAliases[specifier.local.name] = 'NAMESPACE';
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const spec = specifier;
|
|
177
|
+
const importedName = spec.imported.type === 'Identifier'
|
|
178
|
+
? spec.imported.name
|
|
179
|
+
: String(spec.imported.value);
|
|
180
|
+
plumeriaAliases[specifier.local.name] = importedName;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
CallExpression(node) {
|
|
186
|
+
let isCssProperties = false;
|
|
187
|
+
if (node.callee.type === 'MemberExpression') {
|
|
188
|
+
if (node.callee.object.type === 'Identifier' &&
|
|
189
|
+
plumeriaAliases[node.callee.object.name] === 'NAMESPACE') {
|
|
190
|
+
const propertyName = node.callee.property.type === 'Identifier'
|
|
191
|
+
? node.callee.property.name
|
|
192
|
+
: null;
|
|
193
|
+
if (propertyName === 'create' ||
|
|
194
|
+
propertyName === 'keyframes' ||
|
|
195
|
+
propertyName === 'viewTransition') {
|
|
196
|
+
isCssProperties = true;
|
|
197
|
+
}
|
|
104
198
|
}
|
|
105
|
-
}
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
199
|
+
}
|
|
200
|
+
else if (node.callee.type === 'Identifier') {
|
|
201
|
+
const alias = plumeriaAliases[node.callee.name];
|
|
202
|
+
if (alias === 'create' ||
|
|
203
|
+
alias === 'keyframes' ||
|
|
204
|
+
alias === 'viewTransition') {
|
|
205
|
+
isCssProperties = true;
|
|
112
206
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
207
|
+
}
|
|
208
|
+
if (isCssProperties) {
|
|
209
|
+
node.arguments.forEach((arg) => {
|
|
210
|
+
if (arg.type === 'ObjectExpression') {
|
|
211
|
+
arg.properties.forEach((prop) => {
|
|
212
|
+
if (prop.type === 'Property' &&
|
|
213
|
+
prop.value.type === 'ObjectExpression') {
|
|
214
|
+
checkStyleObject(prop.value);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
117
218
|
});
|
|
118
|
-
}
|
|
119
|
-
.flat();
|
|
120
|
-
const propertyToIndexInSorted = new Map();
|
|
121
|
-
sorted.forEach((prop, index) => {
|
|
122
|
-
propertyToIndexInSorted.set(prop, index);
|
|
123
|
-
});
|
|
124
|
-
const targetPositions = properties.map((prop) => propertyToIndexInSorted.get(prop));
|
|
125
|
-
const lisIndices = new Set(getLIS(targetPositions));
|
|
126
|
-
const misorderedIndices = properties
|
|
127
|
-
.map((_, i) => i)
|
|
128
|
-
.filter((i) => !lisIndices.has(i));
|
|
129
|
-
if (misorderedIndices.length === 0)
|
|
130
|
-
return;
|
|
131
|
-
const match = sourceCode.getText(node).match(/^{\s*\n(\s*)/);
|
|
132
|
-
const indent = match ? match[1] : '';
|
|
133
|
-
const lineEnding = match ? '\n' : ' ';
|
|
134
|
-
const closingIndentMatch = sourceCode.getText(node).match(/\n(\s*)}$/);
|
|
135
|
-
const closingIndent = closingIndentMatch ? closingIndentMatch[1] : '';
|
|
136
|
-
misorderedIndices.forEach((i) => {
|
|
137
|
-
const prop = properties[i];
|
|
138
|
-
context.report({
|
|
139
|
-
node: 'key' in prop ? prop.key : prop,
|
|
140
|
-
messageId: 'sortProperties',
|
|
141
|
-
data: {
|
|
142
|
-
position: String(sorted.indexOf(prop) + 1),
|
|
143
|
-
property: prop.type === 'SpreadElement'
|
|
144
|
-
? '...spread'
|
|
145
|
-
: getPropertyName(prop),
|
|
146
|
-
},
|
|
147
|
-
fix(fixer) {
|
|
148
|
-
const newText = sorted
|
|
149
|
-
.map((p) => {
|
|
150
|
-
return `${indent}${sourceCode.getText(p)}`;
|
|
151
|
-
})
|
|
152
|
-
.join(`,${lineEnding}`);
|
|
153
|
-
return fixer.replaceTextRange([
|
|
154
|
-
node.range[0] + 1,
|
|
155
|
-
node.range[1] - 1,
|
|
156
|
-
], `${lineEnding}${newText}${lineEnding}${closingIndent}`);
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
|
-
});
|
|
219
|
+
}
|
|
160
220
|
},
|
|
161
221
|
};
|
|
162
222
|
},
|