prettier-plugin-sort 0.0.2 → 0.1.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 +30 -1
- package/README.zh.md +30 -1
- package/dist/index.js +161 -147
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -182,6 +182,35 @@ import { useEffect, useState } from 'react';
|
|
|
182
182
|
|
|
183
183
|
Set `importOrderMergeDuplicates` to `false` if you want to keep the original separate statements. Side-effect imports (`import 'mod';`) are never merged because their order has runtime semantics.
|
|
184
184
|
|
|
185
|
+
#### Side-effect imports
|
|
186
|
+
|
|
187
|
+
The order of side-effect imports (`import 'mod'`) often carries runtime meaning, such as CSS cascade order or polyfills that must load before a framework. The plugin never moves other imports across a side-effect import — imports on each side are sorted independently, and the side-effect import itself stays in place.
|
|
188
|
+
|
|
189
|
+
Before:
|
|
190
|
+
|
|
191
|
+
<!-- prettier-ignore -->
|
|
192
|
+
```typescript
|
|
193
|
+
import Button from './Button';
|
|
194
|
+
import App from './App';
|
|
195
|
+
import 'normalize.css';
|
|
196
|
+
import theme from './theme';
|
|
197
|
+
import Icon from './Icon';
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
After:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import App from './App';
|
|
204
|
+
import Button from './Button';
|
|
205
|
+
|
|
206
|
+
import 'normalize.css';
|
|
207
|
+
|
|
208
|
+
import Icon from './Icon';
|
|
209
|
+
import theme from './theme';
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Imports on each side are sorted independently. The side-effect import itself stays in place.
|
|
213
|
+
|
|
185
214
|
Sorting rules:
|
|
186
215
|
|
|
187
216
|
- Imports are classified into groups. Within each group they are sorted alphabetically
|
|
@@ -189,7 +218,7 @@ Sorting rules:
|
|
|
189
218
|
- A blank line is inserted between groups by default. Disable with `importOrderSeparation`
|
|
190
219
|
- `type` imports are split into their own statement by default. Use `importOrderTypeImports` to inline them instead
|
|
191
220
|
- Multiple imports from the same source are merged into one by default. Disable with `importOrderMergeDuplicates`
|
|
192
|
-
- Side-effect imports (`import 'mod'`) are never
|
|
221
|
+
- Side-effect imports (`import 'mod'`) carry semantic order and are never moved. Imports on either side are sorted independently
|
|
193
222
|
|
|
194
223
|
### Exports
|
|
195
224
|
|
package/README.zh.md
CHANGED
|
@@ -185,6 +185,35 @@ import { useEffect, useState } from 'react';
|
|
|
185
185
|
|
|
186
186
|
如果你希望保留原本分离的两条语句,把 `importOrderMergeDuplicates` 设为 `false` 即可。副作用导入(`import 'mod';`)因为顺序有语义,永远不会被合并。
|
|
187
187
|
|
|
188
|
+
#### 副作用导入
|
|
189
|
+
|
|
190
|
+
副作用导入(`import 'mod'`)的顺序通常有运行时语义,例如 CSS 的层叠顺序、polyfill 必须在框架之前加载等。插件不会跨越副作用导入移动其他 import 语句:
|
|
191
|
+
|
|
192
|
+
排序前:
|
|
193
|
+
|
|
194
|
+
<!-- prettier-ignore -->
|
|
195
|
+
```typescript
|
|
196
|
+
import Button from './Button';
|
|
197
|
+
import App from './App';
|
|
198
|
+
import 'normalize.css';
|
|
199
|
+
import theme from './theme';
|
|
200
|
+
import Icon from './Icon';
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
排序后:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import App from './App';
|
|
207
|
+
import Button from './Button';
|
|
208
|
+
|
|
209
|
+
import 'normalize.css';
|
|
210
|
+
|
|
211
|
+
import Icon from './Icon';
|
|
212
|
+
import theme from './theme';
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
副作用导入两侧的 import 各自独立排序,副作用导入本身保持原位不动。
|
|
216
|
+
|
|
188
217
|
排序规则:
|
|
189
218
|
|
|
190
219
|
- import 按分组分类,分组内按字母序排列
|
|
@@ -192,7 +221,7 @@ import { useEffect, useState } from 'react';
|
|
|
192
221
|
- 分组之间默认插入空行,可通过 `importOrderSeparation` 关闭
|
|
193
222
|
- `type` import 默认拆成独立语句,可通过 `importOrderTypeImports` 调整为内联
|
|
194
223
|
- 同一来源的多条 import 默认合并为一条,可通过 `importOrderMergeDuplicates` 关闭
|
|
195
|
-
- 副作用导入(`import 'mod'
|
|
224
|
+
- 副作用导入(`import 'mod'`)其顺序有语义,不会被移动,两侧的 import 各自独立排序
|
|
196
225
|
|
|
197
226
|
### export
|
|
198
227
|
|
package/dist/index.js
CHANGED
|
@@ -27,26 +27,24 @@ var VALID_TYPE_STYLES = new Set([
|
|
|
27
27
|
"inline-last",
|
|
28
28
|
"mixed"
|
|
29
29
|
]);
|
|
30
|
-
var isValidImportGroup = (
|
|
31
|
-
var isValidTypeStyle = (
|
|
30
|
+
var isValidImportGroup = (value) => typeof value === "string" && VALID_IMPORT_GROUPS.has(value);
|
|
31
|
+
var isValidTypeStyle = (value) => typeof value === "string" && VALID_TYPE_STYLES.has(value);
|
|
32
|
+
function resolveBoolean(rawOptions, key) {
|
|
33
|
+
const raw = rawOptions[key];
|
|
34
|
+
return typeof raw === "boolean" ? raw : DEFAULT_SORT_OPTIONS[key];
|
|
35
|
+
}
|
|
32
36
|
function resolveSortOptions(rawOptions) {
|
|
33
37
|
const groups = Array.isArray(rawOptions.importOrderGroups) ? rawOptions.importOrderGroups.filter(isValidImportGroup) : [];
|
|
34
|
-
const excludeKeys = Array.isArray(rawOptions.packageJsonOrderExcludeKeys) ? rawOptions.packageJsonOrderExcludeKeys.filter((
|
|
35
|
-
const importOrder = typeof rawOptions.importOrder === "boolean" ? rawOptions.importOrder : DEFAULT_SORT_OPTIONS.importOrder;
|
|
36
|
-
const importOrderGroups = groups.length > 0 ? groups : [...DEFAULT_SORT_OPTIONS.importOrderGroups];
|
|
37
|
-
const importOrderSeparation = typeof rawOptions.importOrderSeparation === "boolean" ? rawOptions.importOrderSeparation : DEFAULT_SORT_OPTIONS.importOrderSeparation;
|
|
38
|
+
const excludeKeys = Array.isArray(rawOptions.packageJsonOrderExcludeKeys) ? rawOptions.packageJsonOrderExcludeKeys.filter((key) => typeof key === "string") : [];
|
|
38
39
|
const importOrderTypeImports = isValidTypeStyle(rawOptions.importOrderTypeImports) ? rawOptions.importOrderTypeImports : DEFAULT_SORT_OPTIONS.importOrderTypeImports;
|
|
39
|
-
const importOrderMergeDuplicates = typeof rawOptions.importOrderMergeDuplicates === "boolean" ? rawOptions.importOrderMergeDuplicates : DEFAULT_SORT_OPTIONS.importOrderMergeDuplicates;
|
|
40
|
-
const exportOrder = typeof rawOptions.exportOrder === "boolean" ? rawOptions.exportOrder : DEFAULT_SORT_OPTIONS.exportOrder;
|
|
41
|
-
const packageJsonOrder = typeof rawOptions.packageJsonOrder === "boolean" ? rawOptions.packageJsonOrder : DEFAULT_SORT_OPTIONS.packageJsonOrder;
|
|
42
40
|
return {
|
|
43
|
-
importOrder,
|
|
44
|
-
importOrderGroups,
|
|
45
|
-
importOrderSeparation,
|
|
41
|
+
importOrder: resolveBoolean(rawOptions, "importOrder"),
|
|
42
|
+
importOrderGroups: groups.length > 0 ? groups : [...DEFAULT_SORT_OPTIONS.importOrderGroups],
|
|
43
|
+
importOrderSeparation: resolveBoolean(rawOptions, "importOrderSeparation"),
|
|
46
44
|
importOrderTypeImports,
|
|
47
|
-
importOrderMergeDuplicates,
|
|
48
|
-
exportOrder,
|
|
49
|
-
packageJsonOrder,
|
|
45
|
+
importOrderMergeDuplicates: resolveBoolean(rawOptions, "importOrderMergeDuplicates"),
|
|
46
|
+
exportOrder: resolveBoolean(rawOptions, "exportOrder"),
|
|
47
|
+
packageJsonOrder: resolveBoolean(rawOptions, "packageJsonOrder"),
|
|
50
48
|
packageJsonOrderExcludeKeys: excludeKeys
|
|
51
49
|
};
|
|
52
50
|
}
|
|
@@ -121,6 +119,30 @@ var options = {
|
|
|
121
119
|
}
|
|
122
120
|
};
|
|
123
121
|
|
|
122
|
+
// src/utils.ts
|
|
123
|
+
function splitTopLevel(input, separator) {
|
|
124
|
+
const segments = [];
|
|
125
|
+
let current = "";
|
|
126
|
+
let depth = 0;
|
|
127
|
+
for (const char of input) {
|
|
128
|
+
if (char === "{" || char === "(" || char === "[") {
|
|
129
|
+
depth++;
|
|
130
|
+
} else if (char === "}" || char === ")" || char === "]") {
|
|
131
|
+
depth--;
|
|
132
|
+
}
|
|
133
|
+
if (char === separator && depth === 0) {
|
|
134
|
+
segments.push(current);
|
|
135
|
+
current = "";
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
current += char;
|
|
139
|
+
}
|
|
140
|
+
if (current.length > 0) {
|
|
141
|
+
segments.push(current);
|
|
142
|
+
}
|
|
143
|
+
return segments.map((segment) => segment.trim()).filter((segment) => segment.length > 0);
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
// src/sort-exports.ts
|
|
125
147
|
function sortExports(text, rawOptions) {
|
|
126
148
|
const options2 = resolveSortOptions(rawOptions);
|
|
@@ -135,36 +157,14 @@ function sortExports(text, rawOptions) {
|
|
|
135
157
|
const sorted = [...members].sort((a, b) => stripTypePrefix(a).localeCompare(stripTypePrefix(b), "en", {
|
|
136
158
|
sensitivity: "base"
|
|
137
159
|
}));
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
160
|
+
const unchanged = sorted.every((member, index) => member === members[index]);
|
|
161
|
+
if (unchanged) {
|
|
140
162
|
return match;
|
|
141
163
|
}
|
|
142
164
|
const prefix = typeKeyword ? `export${typeKeyword}` : "export";
|
|
143
165
|
return `${prefix} { ${sorted.join(", ")} }`;
|
|
144
166
|
});
|
|
145
167
|
}
|
|
146
|
-
function splitTopLevel(input, separator) {
|
|
147
|
-
const out = [];
|
|
148
|
-
let buf = "";
|
|
149
|
-
let depth = 0;
|
|
150
|
-
for (const ch of input) {
|
|
151
|
-
if (ch === "{" || ch === "(" || ch === "[") {
|
|
152
|
-
depth++;
|
|
153
|
-
} else if (ch === "}" || ch === ")" || ch === "]") {
|
|
154
|
-
depth--;
|
|
155
|
-
}
|
|
156
|
-
if (ch === separator && depth === 0) {
|
|
157
|
-
out.push(buf);
|
|
158
|
-
buf = "";
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
buf += ch;
|
|
162
|
-
}
|
|
163
|
-
if (buf.length > 0) {
|
|
164
|
-
out.push(buf);
|
|
165
|
-
}
|
|
166
|
-
return out.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
167
|
-
}
|
|
168
168
|
function stripTypePrefix(member) {
|
|
169
169
|
return member.replace(/^type\s+/, "");
|
|
170
170
|
}
|
|
@@ -195,62 +195,41 @@ function detectGroup(source) {
|
|
|
195
195
|
}
|
|
196
196
|
return "external";
|
|
197
197
|
}
|
|
198
|
-
|
|
199
|
-
const out = [];
|
|
200
|
-
let buf = "";
|
|
201
|
-
let depth = 0;
|
|
202
|
-
for (const ch of input) {
|
|
203
|
-
if (ch === "{" || ch === "(" || ch === "[") {
|
|
204
|
-
depth++;
|
|
205
|
-
} else if (ch === "}" || ch === ")" || ch === "]") {
|
|
206
|
-
depth--;
|
|
207
|
-
}
|
|
208
|
-
if (ch === separator && depth === 0) {
|
|
209
|
-
out.push(buf);
|
|
210
|
-
buf = "";
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
buf += ch;
|
|
214
|
-
}
|
|
215
|
-
if (buf.length > 0) {
|
|
216
|
-
out.push(buf);
|
|
217
|
-
}
|
|
218
|
-
return out.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
219
|
-
}
|
|
198
|
+
var TYPE_PREFIX = /^type\s+(.+)$/s;
|
|
220
199
|
function splitMembers(inner) {
|
|
221
|
-
return
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
return { name, isType };
|
|
200
|
+
return splitTopLevel(inner, ",").map((part) => {
|
|
201
|
+
const match = TYPE_PREFIX.exec(part);
|
|
202
|
+
return match ? { name: match[1].trim(), isType: true } : { name: part, isType: false };
|
|
225
203
|
});
|
|
226
204
|
}
|
|
227
|
-
function parseImport(
|
|
228
|
-
const trimmed =
|
|
229
|
-
const leadingComments =
|
|
230
|
-
const sideEffect = /^import\s*(['"])([^'"]+)\1\s*;?$/.exec(trimmed);
|
|
205
|
+
function parseImport(statement) {
|
|
206
|
+
const trimmed = statement.raw.trim();
|
|
207
|
+
const leadingComments = statement.leadingComments;
|
|
208
|
+
const sideEffect = /^import\s*(['"])([^'"]+)\1(?:\s+with\s*(\{[^}]*\}))?\s*;?$/.exec(trimmed);
|
|
231
209
|
if (sideEffect) {
|
|
232
210
|
return {
|
|
233
|
-
raw: trimmed,
|
|
234
211
|
source: sideEffect[2] ?? "",
|
|
235
212
|
typeClause: false,
|
|
236
213
|
sideEffect: true,
|
|
237
214
|
defaultSpec: null,
|
|
238
215
|
namespaceSpec: null,
|
|
239
216
|
members: null,
|
|
217
|
+
attributes: sideEffect[3] ?? null,
|
|
240
218
|
leadingComments
|
|
241
219
|
};
|
|
242
220
|
}
|
|
243
|
-
const
|
|
244
|
-
if (!
|
|
221
|
+
const match = /^import\s+(type\s+)?([\s\S]+?)\s*from\s*(['"])([^'"]+)\3(?:\s+with\s*(\{[^}]*\}))?\s*;?$/.exec(trimmed);
|
|
222
|
+
if (!match) {
|
|
245
223
|
return null;
|
|
246
224
|
}
|
|
247
|
-
const typeClause = Boolean(
|
|
248
|
-
const clause = (
|
|
249
|
-
const source =
|
|
225
|
+
const typeClause = Boolean(match[1]);
|
|
226
|
+
const clause = (match[2] ?? "").trim();
|
|
227
|
+
const source = match[4] ?? "";
|
|
228
|
+
const attributes = match[5] ?? null;
|
|
250
229
|
let defaultSpec = null;
|
|
251
230
|
let namespaceSpec = null;
|
|
252
231
|
let members = null;
|
|
253
|
-
for (const part of
|
|
232
|
+
for (const part of splitTopLevel(clause, ",")) {
|
|
254
233
|
if (part.startsWith("{")) {
|
|
255
234
|
const inner = part.slice(1, part.lastIndexOf("}")).trim();
|
|
256
235
|
members = inner ? splitMembers(inner) : [];
|
|
@@ -261,13 +240,13 @@ function parseImport(stmt) {
|
|
|
261
240
|
}
|
|
262
241
|
}
|
|
263
242
|
return {
|
|
264
|
-
raw: trimmed,
|
|
265
243
|
source,
|
|
266
244
|
typeClause,
|
|
267
245
|
sideEffect: false,
|
|
268
246
|
defaultSpec,
|
|
269
247
|
namespaceSpec,
|
|
270
248
|
members,
|
|
249
|
+
attributes,
|
|
271
250
|
leadingComments
|
|
272
251
|
};
|
|
273
252
|
}
|
|
@@ -280,17 +259,21 @@ function extractImportBlock(text) {
|
|
|
280
259
|
const start = first.index + (text[first.index] === `
|
|
281
260
|
` ? 1 : 0);
|
|
282
261
|
const statements = [];
|
|
262
|
+
const skipRe = /(?:[ \t]*(?:\/\/[^\n]*|\/\*[\s\S]*?\*\/)?[ \t]*\n)*/y;
|
|
263
|
+
const importRe = /[ \t]*(import\b[\s\S]*?(?:from\s*(['"])[^'"]+\2|(['"])[^'"]+\3)(?:\s+with\s*\{[^}]*\})?\s*;?)/y;
|
|
283
264
|
let cursor = start;
|
|
284
265
|
while (cursor < text.length) {
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
const
|
|
266
|
+
skipRe.lastIndex = cursor;
|
|
267
|
+
const skipMatch = skipRe.exec(text);
|
|
268
|
+
const skipped = skipMatch ? skipMatch[0] : "";
|
|
269
|
+
const afterSkip = cursor + skipped.length;
|
|
270
|
+
importRe.lastIndex = afterSkip;
|
|
271
|
+
const importMatch = importRe.exec(text);
|
|
289
272
|
if (!importMatch) {
|
|
290
273
|
break;
|
|
291
274
|
}
|
|
292
|
-
const normalised =
|
|
293
|
-
`) ?
|
|
275
|
+
const normalised = skipped.endsWith(`
|
|
276
|
+
`) ? skipped.slice(0, -1) : skipped;
|
|
294
277
|
const commentLines = normalised.length > 0 ? normalised.split(`
|
|
295
278
|
`) : [];
|
|
296
279
|
const leadingLines = [];
|
|
@@ -322,27 +305,23 @@ function extractImportBlock(text) {
|
|
|
322
305
|
function renderMembers(members) {
|
|
323
306
|
return members.map((member) => member.isType ? `type ${member.name}` : member.name).join(", ");
|
|
324
307
|
}
|
|
308
|
+
function renderSpecifiers(importDecl) {
|
|
309
|
+
const parts = [];
|
|
310
|
+
if (importDecl.defaultSpec) {
|
|
311
|
+
parts.push(importDecl.defaultSpec);
|
|
312
|
+
}
|
|
313
|
+
if (importDecl.namespaceSpec) {
|
|
314
|
+
parts.push(importDecl.namespaceSpec);
|
|
315
|
+
}
|
|
316
|
+
if (importDecl.members) {
|
|
317
|
+
parts.push(`{ ${renderMembers(importDecl.members)} }`);
|
|
318
|
+
}
|
|
319
|
+
return parts.join(", ");
|
|
320
|
+
}
|
|
325
321
|
function renderImport(importDecl) {
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
if (importDecl.typeClause) {
|
|
331
|
-
const inner = importDecl.members ? `{ ${renderMembers(importDecl.members)} }` : "";
|
|
332
|
-
return `import type ${inner} from '${importDecl.source}';`;
|
|
333
|
-
}
|
|
334
|
-
const leftParts = [];
|
|
335
|
-
if (importDecl.defaultSpec) {
|
|
336
|
-
leftParts.push(importDecl.defaultSpec);
|
|
337
|
-
}
|
|
338
|
-
if (importDecl.namespaceSpec) {
|
|
339
|
-
leftParts.push(importDecl.namespaceSpec);
|
|
340
|
-
}
|
|
341
|
-
if (importDecl.members) {
|
|
342
|
-
leftParts.push(`{ ${renderMembers(importDecl.members)} }`);
|
|
343
|
-
}
|
|
344
|
-
return `import ${leftParts.join(", ")} from '${importDecl.source}';`;
|
|
345
|
-
})();
|
|
322
|
+
const suffix = importDecl.attributes ? ` with ${importDecl.attributes}` : "";
|
|
323
|
+
const source = `'${importDecl.source}'`;
|
|
324
|
+
const body = importDecl.sideEffect ? `import ${source}${suffix};` : importDecl.typeClause ? `import type ${renderSpecifiers(importDecl)} from ${source}${suffix};` : `import ${renderSpecifiers(importDecl)} from ${source}${suffix};`;
|
|
346
325
|
return importDecl.leadingComments + body;
|
|
347
326
|
}
|
|
348
327
|
function sortMembersAlpha(members) {
|
|
@@ -361,9 +340,9 @@ function normalizeTypeClause(importDecl) {
|
|
|
361
340
|
function mergeImportsFromSameSource(imports) {
|
|
362
341
|
const indexBySource = new Map;
|
|
363
342
|
const result = [];
|
|
364
|
-
for (const
|
|
365
|
-
const importDecl = normalizeTypeClause(
|
|
366
|
-
if (importDecl.sideEffect) {
|
|
343
|
+
for (const rawImport of imports) {
|
|
344
|
+
const importDecl = normalizeTypeClause(rawImport);
|
|
345
|
+
if (importDecl.sideEffect || importDecl.typeClause) {
|
|
367
346
|
result.push(importDecl);
|
|
368
347
|
continue;
|
|
369
348
|
}
|
|
@@ -375,13 +354,13 @@ function mergeImportsFromSameSource(imports) {
|
|
|
375
354
|
}
|
|
376
355
|
const existing = result[existingIndex];
|
|
377
356
|
result[existingIndex] = {
|
|
378
|
-
raw: "",
|
|
379
357
|
source: existing.source,
|
|
380
358
|
typeClause: false,
|
|
381
359
|
sideEffect: false,
|
|
382
360
|
defaultSpec: existing.defaultSpec ?? importDecl.defaultSpec,
|
|
383
361
|
namespaceSpec: existing.namespaceSpec ?? importDecl.namespaceSpec,
|
|
384
362
|
members: existing.members === null && importDecl.members === null ? null : [...existing.members ?? [], ...importDecl.members ?? []],
|
|
363
|
+
attributes: existing.attributes ?? importDecl.attributes,
|
|
385
364
|
leadingComments: existing.leadingComments
|
|
386
365
|
};
|
|
387
366
|
}
|
|
@@ -400,13 +379,13 @@ function applyTypeImports(importDecl, style) {
|
|
|
400
379
|
const out = [];
|
|
401
380
|
if (typeMembers2.length > 0) {
|
|
402
381
|
out.push({
|
|
403
|
-
raw: "",
|
|
404
382
|
source: importDecl.source,
|
|
405
383
|
typeClause: true,
|
|
406
384
|
sideEffect: false,
|
|
407
385
|
defaultSpec: null,
|
|
408
386
|
namespaceSpec: null,
|
|
409
387
|
members: sortMembersAlpha(typeMembers2.map((member) => ({ ...member, isType: false }))),
|
|
388
|
+
attributes: importDecl.attributes,
|
|
410
389
|
leadingComments: importDecl.leadingComments
|
|
411
390
|
});
|
|
412
391
|
}
|
|
@@ -420,7 +399,7 @@ function applyTypeImports(importDecl, style) {
|
|
|
420
399
|
}
|
|
421
400
|
return out.length > 0 ? out : [importDecl];
|
|
422
401
|
}
|
|
423
|
-
const
|
|
402
|
+
const inlineBase = importDecl.typeClause ? {
|
|
424
403
|
...importDecl,
|
|
425
404
|
typeClause: false,
|
|
426
405
|
members: importDecl.members.map((member) => ({
|
|
@@ -429,38 +408,24 @@ function applyTypeImports(importDecl, style) {
|
|
|
429
408
|
}))
|
|
430
409
|
} : { ...importDecl, members: importDecl.members };
|
|
431
410
|
if (style === "mixed") {
|
|
432
|
-
return [{ ...
|
|
411
|
+
return [{ ...inlineBase, members: sortMembersAlpha(inlineBase.members) }];
|
|
433
412
|
}
|
|
434
|
-
const typeMembers =
|
|
435
|
-
const valueMembers =
|
|
413
|
+
const typeMembers = inlineBase.members.filter((member) => member.isType);
|
|
414
|
+
const valueMembers = inlineBase.members.filter((member) => !member.isType);
|
|
436
415
|
const sortedTypes = sortMembersAlpha(typeMembers);
|
|
437
416
|
const sortedValues = sortMembersAlpha(valueMembers);
|
|
438
417
|
const ordered = style === "inline-first" ? [...sortedTypes, ...sortedValues] : [...sortedValues, ...sortedTypes];
|
|
439
|
-
return [{ ...
|
|
418
|
+
return [{ ...inlineBase, members: ordered }];
|
|
440
419
|
}
|
|
441
|
-
function
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
return text;
|
|
445
|
-
}
|
|
446
|
-
const block = extractImportBlock(text);
|
|
447
|
-
if (!block || block.statements.length === 0) {
|
|
448
|
-
return text;
|
|
449
|
-
}
|
|
450
|
-
const parsed = block.statements.map((rawStmt) => parseImport(rawStmt)).filter((decl) => decl !== null);
|
|
451
|
-
if (parsed.length === 0) {
|
|
452
|
-
return text;
|
|
420
|
+
function sortSegment(imports, options2, groupIndex, fallback) {
|
|
421
|
+
if (imports.length === 0) {
|
|
422
|
+
return [];
|
|
453
423
|
}
|
|
454
424
|
const style = options2.importOrderTypeImports;
|
|
455
|
-
const deduped = options2.importOrderMergeDuplicates ? mergeImportsFromSameSource(
|
|
425
|
+
const deduped = options2.importOrderMergeDuplicates ? mergeImportsFromSameSource(imports) : imports;
|
|
456
426
|
const rewritten = deduped.flatMap((importDecl) => applyTypeImports(importDecl, style));
|
|
457
|
-
const groupIndex = new Map(options2.importOrderGroups.map((group, index) => [
|
|
458
|
-
group,
|
|
459
|
-
index
|
|
460
|
-
]));
|
|
461
|
-
const fallback = options2.importOrderGroups.length;
|
|
462
427
|
const decorated = rewritten.map((importDecl, index) => ({
|
|
463
|
-
|
|
428
|
+
importDecl,
|
|
464
429
|
group: detectGroup(importDecl.source),
|
|
465
430
|
originalIndex: index
|
|
466
431
|
}));
|
|
@@ -470,26 +435,75 @@ function sortImports(text, rawOptions) {
|
|
|
470
435
|
if (groupOrderA !== groupOrderB) {
|
|
471
436
|
return groupOrderA - groupOrderB;
|
|
472
437
|
}
|
|
473
|
-
const sourceA = a.
|
|
474
|
-
const sourceB = b.
|
|
438
|
+
const sourceA = a.importDecl.source.toLowerCase();
|
|
439
|
+
const sourceB = b.importDecl.source.toLowerCase();
|
|
475
440
|
if (sourceA !== sourceB) {
|
|
476
441
|
return sourceA < sourceB ? -1 : 1;
|
|
477
442
|
}
|
|
478
|
-
if (a.
|
|
479
|
-
return a.
|
|
443
|
+
if (a.importDecl.typeClause !== b.importDecl.typeClause) {
|
|
444
|
+
return a.importDecl.typeClause ? -1 : 1;
|
|
480
445
|
}
|
|
481
446
|
return a.originalIndex - b.originalIndex;
|
|
482
447
|
});
|
|
483
448
|
const lines = [];
|
|
484
|
-
let
|
|
449
|
+
let previousGroup = null;
|
|
485
450
|
for (const item of decorated) {
|
|
486
|
-
if (options2.importOrderSeparation &&
|
|
451
|
+
if (options2.importOrderSeparation && previousGroup !== null && item.group !== previousGroup) {
|
|
487
452
|
lines.push("");
|
|
488
453
|
}
|
|
489
|
-
lines.push(renderImport(item.
|
|
490
|
-
|
|
454
|
+
lines.push(renderImport(item.importDecl));
|
|
455
|
+
previousGroup = item.group;
|
|
456
|
+
}
|
|
457
|
+
return lines;
|
|
458
|
+
}
|
|
459
|
+
function sortImports(text, rawOptions) {
|
|
460
|
+
const options2 = resolveSortOptions(rawOptions);
|
|
461
|
+
if (!options2.importOrder) {
|
|
462
|
+
return text;
|
|
463
|
+
}
|
|
464
|
+
const block = extractImportBlock(text);
|
|
465
|
+
if (!block || block.statements.length === 0) {
|
|
466
|
+
return text;
|
|
467
|
+
}
|
|
468
|
+
const parsed = block.statements.map((rawStatement) => parseImport(rawStatement)).filter((importDecl) => importDecl !== null);
|
|
469
|
+
if (parsed.length === 0) {
|
|
470
|
+
return text;
|
|
471
|
+
}
|
|
472
|
+
const groupIndex = new Map(options2.importOrderGroups.map((group, index) => [
|
|
473
|
+
group,
|
|
474
|
+
index
|
|
475
|
+
]));
|
|
476
|
+
const fallback = options2.importOrderGroups.length;
|
|
477
|
+
const chunks = [];
|
|
478
|
+
let currentSegment = [];
|
|
479
|
+
for (const importDecl of parsed) {
|
|
480
|
+
if (importDecl.sideEffect) {
|
|
481
|
+
if (currentSegment.length > 0) {
|
|
482
|
+
chunks.push({ kind: "segment", imports: currentSegment });
|
|
483
|
+
currentSegment = [];
|
|
484
|
+
}
|
|
485
|
+
chunks.push({ kind: "side-effect", importDecl });
|
|
486
|
+
} else {
|
|
487
|
+
currentSegment.push(importDecl);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (currentSegment.length > 0) {
|
|
491
|
+
chunks.push({ kind: "segment", imports: currentSegment });
|
|
492
|
+
}
|
|
493
|
+
const allLines = [];
|
|
494
|
+
let previousKind = null;
|
|
495
|
+
for (const chunk of chunks) {
|
|
496
|
+
if (previousKind !== null && previousKind !== chunk.kind && options2.importOrderSeparation) {
|
|
497
|
+
allLines.push("");
|
|
498
|
+
}
|
|
499
|
+
if (chunk.kind === "segment") {
|
|
500
|
+
allLines.push(...sortSegment(chunk.imports, options2, groupIndex, fallback));
|
|
501
|
+
} else {
|
|
502
|
+
allLines.push(renderImport(chunk.importDecl));
|
|
503
|
+
}
|
|
504
|
+
previousKind = chunk.kind;
|
|
491
505
|
}
|
|
492
|
-
const replacement =
|
|
506
|
+
const replacement = allLines.join(`
|
|
493
507
|
`);
|
|
494
508
|
const trailing = text.slice(block.end);
|
|
495
509
|
const suffix = trailing.trim() ? `
|
|
@@ -644,15 +658,15 @@ function sortObjectKeysByOrder(record, order) {
|
|
|
644
658
|
rest.push(entry);
|
|
645
659
|
}
|
|
646
660
|
}
|
|
647
|
-
known.sort(([
|
|
648
|
-
rest.sort(([
|
|
661
|
+
known.sort(([a], [b]) => (orderIndex.get(a) ?? 0) - (orderIndex.get(b) ?? 0));
|
|
662
|
+
rest.sort(([a], [b]) => a.localeCompare(b, "en"));
|
|
649
663
|
return Object.fromEntries([...known, ...rest]);
|
|
650
664
|
}
|
|
651
665
|
function sortObjectKeysAlpha(value) {
|
|
652
666
|
if (!isPlainObject(value)) {
|
|
653
667
|
return value;
|
|
654
668
|
}
|
|
655
|
-
return Object.fromEntries(Object.entries(value).sort(([
|
|
669
|
+
return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b, "en")));
|
|
656
670
|
}
|
|
657
671
|
function sortStringArrayAlpha(value) {
|
|
658
672
|
return [...value].sort((a, b) => a.localeCompare(b, "en"));
|
|
@@ -682,7 +696,7 @@ function sortPackageJson(text, rawOptions) {
|
|
|
682
696
|
if (!isPlainObject(parsed)) {
|
|
683
697
|
return text;
|
|
684
698
|
}
|
|
685
|
-
let result =
|
|
699
|
+
let result = parsed;
|
|
686
700
|
for (const field of DEPENDENCY_FIELDS) {
|
|
687
701
|
const dependencyMap = result[field];
|
|
688
702
|
if (dependencyMap !== undefined && !exclude.has(field)) {
|
|
@@ -713,8 +727,8 @@ function wrap(parser, ...transforms) {
|
|
|
713
727
|
...parser,
|
|
714
728
|
async preprocess(text, parserOptions) {
|
|
715
729
|
let source = parser.preprocess ? await parser.preprocess(text, parserOptions) : text;
|
|
716
|
-
for (const
|
|
717
|
-
source =
|
|
730
|
+
for (const transform of transforms) {
|
|
731
|
+
source = transform(source, parserOptions);
|
|
718
732
|
}
|
|
719
733
|
return source;
|
|
720
734
|
}
|