@plumeria/eslint-plugin 21.1.4 → 21.1.5

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
@@ -101,7 +101,7 @@ elsewhere outrank it.
101
101
  ```js
102
102
  borderTop: '1px solid red'
103
103
  // becomes
104
- borderTopWidth: '1px', borderTopStyle: 'solid', borderTopColor: 'red'
104
+ borderTopColor: 'red', borderTopStyle: 'solid', borderTopWidth: '1px'
105
105
  ```
106
106
 
107
107
  A shorthand resets what it omits, so `borderBlock: 'solid'` expands with
@@ -150,7 +150,7 @@ exports.expandBorderShorthands = {
150
150
  : `\`${restored}\``;
151
151
  };
152
152
  const indent = ' '.repeat(prop.loc.start.column);
153
- const declarations = ['width', 'style', 'color']
153
+ const declarations = ['color', 'style', 'width']
154
154
  .map((part) => `${(0, zss_engine_1.kebabToCamelCase)(`${kebab}-${part}`)}: ${render(parts[part])}`)
155
155
  .join(`,\n${indent}`);
156
156
  context.report({
@@ -140,11 +140,47 @@ exports.sortProperties = {
140
140
  });
141
141
  if (misorderedIndices.length === 0)
142
142
  return;
143
- const match = sourceCode.getText(node).match(/^{\s*\n(\s*)/);
144
- const indent = match ? match[1] : '';
145
- const lineEnding = match ? '\n' : ' ';
146
- const closingIndentMatch = sourceCode.getText(node).match(/\n(\s*)}$/);
147
- const closingIndent = closingIndentMatch ? closingIndentMatch[1] : '';
143
+ const text = sourceCode.text;
144
+ const textOf = (comments) => comments
145
+ .map((c) => ` ${text.slice(c.range[0], c.range[1])}`)
146
+ .join('');
147
+ const indentOf = (line) => {
148
+ const lineText = sourceCode.lines[line - 1];
149
+ let i = 0;
150
+ while (lineText[i] === ' ' || lineText[i] === '\t')
151
+ i++;
152
+ return lineText.slice(0, i);
153
+ };
154
+ const slots = properties.map((prop) => {
155
+ const tokenBefore = sourceCode.getTokenBefore(prop);
156
+ const sameLineAsBefore = prop.loc.start.line === tokenBefore.loc.end.line;
157
+ const leading = sourceCode
158
+ .getCommentsBefore(prop)
159
+ .filter((c) => sameLineAsBefore || c.loc.start.line > tokenBefore.loc.end.line);
160
+ const tokenAfter = sourceCode.getTokenAfter(prop);
161
+ const hasComma = tokenAfter.value === ',';
162
+ const beforeComma = hasComma ? sourceCode.getCommentsAfter(prop) : [];
163
+ const anchor = hasComma ? tokenAfter : prop;
164
+ const next = sourceCode.getTokenAfter(anchor);
165
+ const nextOnSameLine = next.value !== '}' && next.loc.start.line === anchor.loc.end.line;
166
+ const afterComma = nextOnSameLine
167
+ ? []
168
+ : sourceCode
169
+ .getCommentsAfter(anchor)
170
+ .filter((c) => c.loc.start.line === anchor.loc.end.line);
171
+ const start = leading.length ? leading[0].range[0] : prop.range[0];
172
+ const last = afterComma[afterComma.length - 1] ?? anchor;
173
+ return {
174
+ prop,
175
+ start,
176
+ last,
177
+ hasComma,
178
+ lead: text.slice(start, prop.range[0]),
179
+ beforeComma,
180
+ afterComma,
181
+ };
182
+ });
183
+ const slotOf = new Map(slots.map((slot) => [slot.prop, slot]));
148
184
  misorderedIndices.forEach((i) => {
149
185
  const prop = properties[i];
150
186
  context.report({
@@ -155,15 +191,30 @@ exports.sortProperties = {
155
191
  property: keyNameOf(prop),
156
192
  },
157
193
  fix(fixer) {
158
- const newText = sorted
159
- .map((p) => {
160
- return `${indent}${sourceCode.getText(p)}`;
161
- })
162
- .join(`,${lineEnding}`);
163
- return fixer.replaceTextRange([
164
- node.range[0] + 1,
165
- node.range[1] - 1,
166
- ], `${lineEnding}${newText}${lineEnding}${closingIndent}`);
194
+ return slots.map((slot, j) => {
195
+ const unit = slotOf.get(sorted[j]);
196
+ const body = sourceCode.getText(unit.prop);
197
+ const lineBefore = unit.beforeComma.filter((c) => c.type === 'Line');
198
+ const trailing = slot.hasComma
199
+ ? [...lineBefore, ...unit.afterComma]
200
+ : [...unit.beforeComma, ...unit.afterComma];
201
+ let replacement = slot.hasComma
202
+ ? `${unit.lead}${body}${textOf(unit.beforeComma.filter((c) => c.type === 'Block'))},${textOf(trailing)}`
203
+ : `${unit.lead}${body}${textOf(trailing)}`;
204
+ let end = slot.last.range[1];
205
+ if (trailing[trailing.length - 1]?.type === 'Line') {
206
+ const next = sourceCode.getTokenAfter(slot.last, {
207
+ includeComments: true,
208
+ });
209
+ if (next.loc.start.line === slot.last.loc.end.line) {
210
+ end = next.range[0];
211
+ replacement += `\n${next === sourceCode.getLastToken(node)
212
+ ? indentOf(node.loc.start.line)
213
+ : indentOf(slot.prop.loc.start.line)}`;
214
+ }
215
+ }
216
+ return fixer.replaceTextRange([slot.start, end], replacement);
217
+ });
167
218
  },
168
219
  });
169
220
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/eslint-plugin",
3
- "version": "21.1.4",
3
+ "version": "21.1.5",
4
4
  "description": "Plumeria ESLint plugin",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",
@@ -59,7 +59,7 @@
59
59
  "dependencies": {
60
60
  "oxlint": "1.87.0",
61
61
  "zss-engine": "3.0.1",
62
- "@plumeria/compiler": "21.1.4"
62
+ "@plumeria/compiler": "21.1.5"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "rimraf dist && pnpm cjs",