@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.
@@ -14,11 +14,8 @@ function getPropertyName(property) {
14
14
  }
15
15
  return '';
16
16
  }
17
- function getPropertyIndex(property, isTopLevel) {
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 (typeof name === 'string') {
34
- if (name.startsWith(':'))
35
- return (propertyGroups_1.propertyGroups.length + 1) * 1000;
36
- if (name.startsWith('&'))
37
- return (propertyGroups_1.propertyGroups.length + 2) * 1000;
38
- if (name.startsWith('@media'))
39
- return (propertyGroups_1.propertyGroups.length + 3) * 1000;
40
- if (name.startsWith('@container'))
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
- ObjectExpression(node) {
90
- const sourceCode = getSourceCode(context);
91
- const isTopLevel = !node.parent || node.parent.type !== 'Property';
92
- const properties = node.properties.filter((prop) => ('key' in prop && !!prop.key) || prop.type === 'SpreadElement');
93
- const chunks = [];
94
- let currentChunk = [];
95
- properties.forEach((prop) => {
96
- if (prop.type === 'SpreadElement') {
97
- if (currentChunk.length > 0)
98
- chunks.push(currentChunk);
99
- chunks.push([prop]);
100
- currentChunk = [];
101
- }
102
- else {
103
- currentChunk.push(prop);
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 (currentChunk.length > 0)
107
- chunks.push(currentChunk);
108
- const sorted = chunks
109
- .map((chunk) => {
110
- if (chunk.length === 1 && chunk[0].type === 'SpreadElement') {
111
- return chunk;
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
- return [...chunk].sort((a, b) => {
114
- const indexA = getPropertyIndex(a, isTopLevel);
115
- const indexB = getPropertyIndex(b, isTopLevel);
116
- return indexA === null || indexB === null ? 0 : indexA - indexB;
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
  },