prettier-plugin-sort 0.2.0 → 1.0.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/dist/index.js CHANGED
@@ -1,17 +1,19 @@
1
1
  // src/index.ts
2
- import { parsers as babelParsers } from "prettier/plugins/babel";
3
- import { parsers as typescriptParsers } from "prettier/plugins/typescript";
2
+ import acornPlugin from "prettier/plugins/acorn";
3
+ import babelPlugin from "prettier/plugins/babel";
4
+ import flowPlugin from "prettier/plugins/flow";
5
+ import meriyahPlugin from "prettier/plugins/meriyah";
6
+ import typescriptPlugin from "prettier/plugins/typescript";
4
7
 
5
8
  // src/options.ts
6
9
  var DEFAULT_SORT_OPTIONS = {
7
- importOrder: true,
8
- importOrderGroups: ["builtin", "external", "parent", "sibling", "index"],
9
- importOrderSeparation: true,
10
- importOrderTypeImports: "separate",
11
- importOrderMergeDuplicates: true,
12
- exportOrder: true,
13
- packageJsonOrder: true,
14
- packageJsonOrderExcludeKeys: []
10
+ esmImportSort: true,
11
+ esmImportGroups: ["builtin", "external", "parent", "sibling", "index"],
12
+ esmImportSeparation: true,
13
+ esmImportTypeStyle: "separate",
14
+ esmImportMerge: true,
15
+ esmExportSpecifierSort: true,
16
+ packageSort: true
15
17
  };
16
18
  var VALID_IMPORT_GROUPS = new Set([
17
19
  "builtin",
@@ -21,502 +23,250 @@ var VALID_IMPORT_GROUPS = new Set([
21
23
  "sibling",
22
24
  "index"
23
25
  ]);
24
- var VALID_TYPE_STYLES = new Set([
26
+ var VALID_TYPE_IMPORT_STYLES = new Set([
25
27
  "separate",
26
28
  "inline-first",
27
29
  "inline-last",
28
30
  "mixed"
29
31
  ]);
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
- }
36
- function resolveSortOptions(rawOptions) {
37
- const groups = Array.isArray(rawOptions.importOrderGroups) ? rawOptions.importOrderGroups.filter(isValidImportGroup) : [];
38
- const excludeKeys = Array.isArray(rawOptions.packageJsonOrderExcludeKeys) ? rawOptions.packageJsonOrderExcludeKeys.filter((key) => typeof key === "string") : [];
39
- const importOrderTypeImports = isValidTypeStyle(rawOptions.importOrderTypeImports) ? rawOptions.importOrderTypeImports : DEFAULT_SORT_OPTIONS.importOrderTypeImports;
32
+ var isValidImportGroup = (candidateValue) => typeof candidateValue === "string" && VALID_IMPORT_GROUPS.has(candidateValue);
33
+ var isValidTypeImportStyle = (candidateValue) => typeof candidateValue === "string" && VALID_TYPE_IMPORT_STYLES.has(candidateValue);
34
+ function resolveBooleanSortOption(prettierOptions, optionName) {
35
+ const configuredValue = prettierOptions[optionName];
36
+ if (typeof configuredValue === "boolean") {
37
+ return configuredValue;
38
+ }
39
+ return DEFAULT_SORT_OPTIONS[optionName];
40
+ }
41
+ function resolveSortOptions(prettierOptions) {
42
+ const configuredImportGroups = Array.isArray(prettierOptions.esmImportGroups) ? [...new Set(prettierOptions.esmImportGroups.filter(isValidImportGroup))] : [];
43
+ const remainingDefaultImportGroups = DEFAULT_SORT_OPTIONS.esmImportGroups.filter((importGroup) => !configuredImportGroups.includes(importGroup));
44
+ const resolvedImportGroups = configuredImportGroups.length > 0 ? [...configuredImportGroups, ...remainingDefaultImportGroups] : [...DEFAULT_SORT_OPTIONS.esmImportGroups];
45
+ const resolvedTypeImportStyle = isValidTypeImportStyle(prettierOptions.esmImportTypeStyle) ? prettierOptions.esmImportTypeStyle : DEFAULT_SORT_OPTIONS.esmImportTypeStyle;
40
46
  return {
41
- importOrder: resolveBoolean(rawOptions, "importOrder"),
42
- importOrderGroups: groups.length > 0 ? groups : [...DEFAULT_SORT_OPTIONS.importOrderGroups],
43
- importOrderSeparation: resolveBoolean(rawOptions, "importOrderSeparation"),
44
- importOrderTypeImports,
45
- importOrderMergeDuplicates: resolveBoolean(rawOptions, "importOrderMergeDuplicates"),
46
- exportOrder: resolveBoolean(rawOptions, "exportOrder"),
47
- packageJsonOrder: resolveBoolean(rawOptions, "packageJsonOrder"),
48
- packageJsonOrderExcludeKeys: excludeKeys
47
+ esmImportSort: resolveBooleanSortOption(prettierOptions, "esmImportSort"),
48
+ esmImportGroups: resolvedImportGroups,
49
+ esmImportSeparation: resolveBooleanSortOption(prettierOptions, "esmImportSeparation"),
50
+ esmImportTypeStyle: resolvedTypeImportStyle,
51
+ esmImportMerge: resolveBooleanSortOption(prettierOptions, "esmImportMerge"),
52
+ esmExportSpecifierSort: resolveBooleanSortOption(prettierOptions, "esmExportSpecifierSort"),
53
+ packageSort: resolveBooleanSortOption(prettierOptions, "packageSort")
49
54
  };
50
55
  }
51
56
  var options = {
52
- importOrder: {
57
+ esmImportSort: {
53
58
  type: "boolean",
54
- default: DEFAULT_SORT_OPTIONS.importOrder,
55
- category: "SortImports",
56
- description: "Sort `import` declarations in JS/TS files."
59
+ default: DEFAULT_SORT_OPTIONS.esmImportSort,
60
+ category: "ES Module Imports",
61
+ description: "Sort top-level ES module import declarations and named specifiers."
57
62
  },
58
- importOrderGroups: {
63
+ esmImportGroups: {
59
64
  type: "string",
60
65
  array: true,
61
- default: [{ value: [...DEFAULT_SORT_OPTIONS.importOrderGroups] }],
62
- category: "SortImports",
63
- description: 'Ordered list of import groups. Valid values: "builtin", "external", "internal", "parent", "sibling", "index". Each group is sorted alphabetically; unknown groups are ignored.'
66
+ default: [{ value: [...DEFAULT_SORT_OPTIONS.esmImportGroups] }],
67
+ category: "ES Module Imports",
68
+ description: 'Set import group order. Valid groups: "builtin", "external", "internal", "parent", "sibling", and "index". Unlisted groups sort after listed groups.'
64
69
  },
65
- importOrderSeparation: {
70
+ esmImportSeparation: {
66
71
  type: "boolean",
67
- default: DEFAULT_SORT_OPTIONS.importOrderSeparation,
68
- category: "SortImports",
69
- description: "Insert a blank line between adjacent import groups."
72
+ default: DEFAULT_SORT_OPTIONS.esmImportSeparation,
73
+ category: "ES Module Imports",
74
+ description: "Add blank lines between import groups and around side-effect import boundaries."
70
75
  },
71
- importOrderTypeImports: {
76
+ esmImportTypeStyle: {
72
77
  type: "choice",
73
- default: DEFAULT_SORT_OPTIONS.importOrderTypeImports,
74
- category: "SortImports",
75
- description: "How to place `type` imports relative to value imports.",
78
+ default: DEFAULT_SORT_OPTIONS.esmImportTypeStyle,
79
+ category: "ES Module Imports",
80
+ description: "Format named type imports as separate declarations or inline specifiers.",
76
81
  choices: [
77
82
  {
78
83
  value: "separate",
79
- description: "Keep `import type { … }` as its own statement."
84
+ description: "Use a separate import type declaration."
80
85
  },
81
86
  {
82
87
  value: "inline-first",
83
- description: "Inline inside braces, type specifiers before value specifiers."
88
+ description: "Place inline type specifiers before value specifiers."
84
89
  },
85
90
  {
86
91
  value: "inline-last",
87
- description: "Inline inside braces, type specifiers after value specifiers."
92
+ description: "Place inline type specifiers after value specifiers."
88
93
  },
89
94
  {
90
95
  value: "mixed",
91
- description: "Inline inside braces, alphabetical without distinguishing type from value."
96
+ description: "Use inline type specifiers and sort all specifiers together."
92
97
  }
93
98
  ]
94
99
  },
95
- importOrderMergeDuplicates: {
100
+ esmImportMerge: {
96
101
  type: "boolean",
97
- default: DEFAULT_SORT_OPTIONS.importOrderMergeDuplicates,
98
- category: "SortImports",
99
- description: "Merge multiple `import` statements from the same source into one. Side-effect imports are never merged."
102
+ default: DEFAULT_SORT_OPTIONS.esmImportMerge,
103
+ category: "ES Module Imports",
104
+ description: "Merge compatible import declarations from the same module."
100
105
  },
101
- exportOrder: {
106
+ esmExportSpecifierSort: {
102
107
  type: "boolean",
103
- default: DEFAULT_SORT_OPTIONS.exportOrder,
104
- category: "SortExports",
105
- description: "Sort named specifiers inside `export { }` alphabetically. Does not reorder export statements."
108
+ default: DEFAULT_SORT_OPTIONS.esmExportSpecifierSort,
109
+ category: "ES Module Exports",
110
+ description: "Sort named export specifiers without reordering export declarations."
106
111
  },
107
- packageJsonOrder: {
112
+ packageSort: {
108
113
  type: "boolean",
109
- default: DEFAULT_SORT_OPTIONS.packageJsonOrder,
110
- category: "SortPackageJson",
111
- description: "Sort top-level keys and string-array values inside `package.json`. Dependency maps are always alphabetised regardless of this option."
112
- },
113
- packageJsonOrderExcludeKeys: {
114
- type: "string",
115
- array: true,
116
- default: [{ value: [...DEFAULT_SORT_OPTIONS.packageJsonOrderExcludeKeys] }],
117
- category: "SortPackageJson",
118
- description: "Top-level `package.json` keys to leave untouched (no key reordering or array sorting). Takes priority over `packageJsonOrder`."
114
+ default: DEFAULT_SORT_OPTIONS.packageSort,
115
+ category: "package.json",
116
+ description: "Sort package.json fields using the sort-package-json community convention."
119
117
  }
120
118
  };
121
119
 
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
-
146
- // src/sort-exports.ts
147
- function sortExports(text, rawOptions) {
148
- const options2 = resolveSortOptions(rawOptions);
149
- if (!options2.exportOrder) {
150
- return text;
151
- }
152
- return text.replace(/export(\s+type)?\s*\{([^}]*)\}/g, (match, typeKeyword, inner) => {
153
- const members = splitTopLevel(inner, ",");
154
- if (members.length <= 1) {
155
- return match;
156
- }
157
- const sorted = [...members].sort((a, b) => stripTypePrefix(a).localeCompare(stripTypePrefix(b), "en", {
158
- sensitivity: "base"
159
- }));
160
- const unchanged = sorted.every((member, index) => member === members[index]);
161
- if (unchanged) {
162
- return match;
163
- }
164
- const prefix = typeKeyword ? `export${typeKeyword}` : "export";
165
- return `${prefix} { ${sorted.join(", ")} }`;
166
- });
167
- }
168
- function stripTypePrefix(member) {
169
- return member.replace(/^type\s+/, "");
170
- }
120
+ // src/sort-package.ts
121
+ import findMinimumSemanticVersion from "semver/ranges/min-version.js";
171
122
 
172
- // src/sort-imports.ts
173
- import { builtinModules } from "node:module";
174
- var NODE_BUILTINS = new Set(builtinModules);
175
- var INDEX_PATTERN = /^\.\/index(\.[a-z]+)?$/;
176
- function detectGroup(source) {
177
- if (source === "bun" || source.startsWith("bun:") || source.startsWith("node:")) {
178
- return "builtin";
179
- }
180
- const slashIndex = source.indexOf("/");
181
- const head = slashIndex === -1 ? source : source.slice(0, slashIndex);
182
- if (head && NODE_BUILTINS.has(head)) {
183
- return "builtin";
184
- }
185
- if (source === "." || source === "./" || INDEX_PATTERN.test(source)) {
186
- return "index";
187
- }
188
- if (source.startsWith("../") || source === "..") {
189
- return "parent";
190
- }
191
- if (source.startsWith("./")) {
192
- return "sibling";
123
+ // src/parser-ast.ts
124
+ function getAstNodeTextRange(node) {
125
+ if (!node) {
126
+ return null;
193
127
  }
194
- if (source.startsWith("/") || source.startsWith("~") || source.startsWith("@/")) {
195
- return "internal";
128
+ const [start = NaN, end = NaN] = node.range ?? [node.start, node.end];
129
+ const isOffsetRangeValid = [start, end].every(Number.isSafeInteger) && start >= 0 && end >= start;
130
+ if (!isOffsetRangeValid) {
131
+ return null;
196
132
  }
197
- return "external";
133
+ return { start, end };
198
134
  }
199
- var TYPE_PREFIX = /^type\s+(.+)$/;
200
- function splitMembers(inner) {
201
- return splitTopLevel(inner, ",").map((part) => {
202
- const match = TYPE_PREFIX.exec(part);
203
- return match ? { name: match[1].trim(), isType: true } : { name: part, isType: false };
204
- });
135
+ function getSortedAstCommentsWithTextRanges(comments) {
136
+ return comments.flatMap((comment) => {
137
+ const textRange = getAstNodeTextRange(comment);
138
+ return textRange ? [{ comment, textRange }] : [];
139
+ }).sort((left, right) => left.textRange.start - right.textRange.start || left.textRange.end - right.textRange.end);
205
140
  }
206
- function parseImport(statement) {
207
- const trimmed = statement.raw.trim();
208
- const leadingComments = statement.leadingComments;
209
- const sideEffect = /^import\s*(['"])([^'"]+)\1(?:\s+with\s*(\{[^}]*\}))?\s*;?$/.exec(trimmed);
210
- if (sideEffect) {
211
- return {
212
- source: sideEffect[2] ?? "",
213
- typeClause: false,
214
- sideEffect: true,
215
- defaultSpec: null,
216
- namespaceSpec: null,
217
- members: null,
218
- attributes: sideEffect[3] ?? null,
219
- leadingComments
220
- };
221
- }
222
- const match = /^import\s+(type\s+)?([\s\S]+?)\s*from\s*(['"])([^'"]+)\3(?:\s+with\s*(\{[^}]*\}))?\s*;?$/.exec(trimmed);
223
- if (!match) {
224
- return null;
225
- }
226
- const typeClause = Boolean(match[1]);
227
- const clause = (match[2] ?? "").trim();
228
- const source = match[4] ?? "";
229
- const attributes = match[5] ?? null;
230
- let defaultSpec = null;
231
- let namespaceSpec = null;
232
- let members = null;
233
- for (const part of splitTopLevel(clause, ",")) {
234
- if (part.startsWith("{")) {
235
- const inner = part.slice(1, part.lastIndexOf("}")).trim();
236
- members = inner ? splitMembers(inner) : [];
237
- } else if (part.startsWith("*")) {
238
- namespaceSpec = part;
141
+ function findCommentIndexAtOrAfter(sortedComments, sourceIndex) {
142
+ let searchStartIndex = 0;
143
+ let searchEndIndex = sortedComments.length;
144
+ while (searchStartIndex < searchEndIndex) {
145
+ const middleIndex = Math.floor((searchStartIndex + searchEndIndex) / 2);
146
+ const middleCommentStart = sortedComments[middleIndex].textRange.start;
147
+ if (middleCommentStart < sourceIndex) {
148
+ searchStartIndex = middleIndex + 1;
239
149
  } else {
240
- defaultSpec = part;
150
+ searchEndIndex = middleIndex;
241
151
  }
242
152
  }
243
- return {
244
- source,
245
- typeClause,
246
- sideEffect: false,
247
- defaultSpec,
248
- namespaceSpec,
249
- members,
250
- attributes,
251
- leadingComments
252
- };
153
+ return searchStartIndex;
253
154
  }
254
- function extractImportBlock(text) {
255
- const firstRe = /(?:^|\n)(?:[ \t]*(?:\/\/[^\n]*|\/\*[\s\S]*?\*\/)[ \t]*\n)*[ \t]*import\b(?![.(])/;
256
- const first = firstRe.exec(text);
257
- if (!first) {
155
+ function getAstNodeName(node) {
156
+ if (!node) {
258
157
  return null;
259
158
  }
260
- const start = first.index + (text[first.index] === `
261
- ` ? 1 : 0);
262
- const statements = [];
263
- const skipRe = /(?:[ \t]*(?:\/\/[^\n]*|\/\*[\s\S]*?\*\/)?[ \t]*\n)*/y;
264
- const importRe = /[ \t]*(import\b(?![.(])[\s\S]*?(?:from\s*(['"])[^'"]+\2|(['"])[^'"]+\3)(?:\s+with\s*\{[^}]*\})?\s*;?)/y;
265
- let cursor = start;
266
- while (cursor < text.length) {
267
- skipRe.lastIndex = cursor;
268
- const skipMatch = skipRe.exec(text);
269
- const skipped = skipMatch ? skipMatch[0] : "";
270
- const afterSkip = cursor + skipped.length;
271
- importRe.lastIndex = afterSkip;
272
- const importMatch = importRe.exec(text);
273
- if (!importMatch) {
274
- break;
275
- }
276
- const normalised = skipped.endsWith(`
277
- `) ? skipped.slice(0, -1) : skipped;
278
- const commentLines = normalised.length > 0 ? normalised.split(`
279
- `) : [];
280
- const leadingLines = [];
281
- for (let i = commentLines.length - 1;i >= 0; i--) {
282
- const line = commentLines[i];
283
- if (line.trim() === "") {
284
- break;
285
- }
286
- leadingLines.unshift(line);
287
- }
288
- const leadingComments = leadingLines.length > 0 ? leadingLines.join(`
289
- `) + `
290
- ` : "";
291
- const statement = importMatch[1];
292
- if (!statement) {
293
- break;
294
- }
295
- statements.push({ raw: statement.trim(), leadingComments });
296
- cursor = afterSkip + importMatch[0].length;
159
+ if (typeof node.name === "string") {
160
+ return node.name;
297
161
  }
298
- if (statements.length === 0) {
299
- return null;
162
+ switch (typeof node.value) {
163
+ case "string":
164
+ case "number":
165
+ case "boolean":
166
+ return String(node.value);
167
+ default:
168
+ return null;
300
169
  }
301
- return { start, end: cursor, statements };
302
170
  }
303
- function renderMembers(members) {
304
- return members.map((member) => member.isType ? `type ${member.name}` : member.name).join(", ");
171
+ function getAstCommentText(comment) {
172
+ return typeof comment.value === "string" ? comment.value : null;
305
173
  }
306
- function renderSpecifiers(importDecl) {
307
- const parts = [];
308
- if (importDecl.defaultSpec) {
309
- parts.push(importDecl.defaultSpec);
174
+ function getProgramStatements(parserAst) {
175
+ if (Array.isArray(parserAst.body)) {
176
+ return parserAst.body;
310
177
  }
311
- if (importDecl.namespaceSpec) {
312
- parts.push(importDecl.namespaceSpec);
313
- }
314
- if (importDecl.members) {
315
- parts.push(`{ ${renderMembers(importDecl.members)} }`);
178
+ const programNode = parserAst.program;
179
+ if (!programNode || !Array.isArray(programNode.body)) {
180
+ return [];
316
181
  }
317
- return parts.join(", ");
182
+ return programNode.body;
318
183
  }
319
- function renderImport(importDecl) {
320
- const suffix = importDecl.attributes ? ` with ${importDecl.attributes}` : "";
321
- const source = `'${importDecl.source}'`;
322
- const body = importDecl.sideEffect ? `import ${source}${suffix};` : importDecl.typeClause ? `import type ${renderSpecifiers(importDecl)} from ${source}${suffix};` : `import ${renderSpecifiers(importDecl)} from ${source}${suffix};`;
323
- return importDecl.leadingComments + body;
324
- }
325
- function sortMembersAlpha(members) {
326
- return [...members].sort((a, b) => a.name.localeCompare(b.name, "en", { sensitivity: "base" }));
327
- }
328
- function normalizeTypeClause(importDecl) {
329
- if (!importDecl.typeClause || importDecl.members === null) {
330
- return importDecl;
184
+ function getProgramComments(parserAst) {
185
+ if (Array.isArray(parserAst.comments)) {
186
+ return parserAst.comments;
331
187
  }
332
- return {
333
- ...importDecl,
334
- typeClause: false,
335
- members: importDecl.members.map((member) => ({ ...member, isType: true }))
336
- };
188
+ const programNode = parserAst.program;
189
+ if (!programNode || !Array.isArray(programNode.comments)) {
190
+ return [];
191
+ }
192
+ return programNode.comments;
337
193
  }
338
- function mergeImportsFromSameSource(imports) {
339
- const indexByKey = new Map;
340
- const result = [];
341
- for (const rawImport of imports) {
342
- const importDecl = normalizeTypeClause(rawImport);
343
- if (importDecl.sideEffect || importDecl.typeClause) {
344
- result.push(importDecl);
345
- continue;
194
+ function isSourceRangeWhitespaceOrComments(sourceText, sourceRange, sortedComments) {
195
+ let sourceIndex = sourceRange.start;
196
+ let commentIndex = Math.max(findCommentIndexAtOrAfter(sortedComments, sourceRange.start) - 1, 0);
197
+ for (;commentIndex < sortedComments.length; commentIndex++) {
198
+ const parserComment = sortedComments[commentIndex];
199
+ if (!parserComment || parserComment.textRange.start >= sourceRange.end) {
200
+ break;
346
201
  }
347
- const mergeKey = `${importDecl.source}\x00${importDecl.attributes ?? ""}`;
348
- const existingIndex = indexByKey.get(mergeKey);
349
- if (existingIndex === undefined) {
350
- indexByKey.set(mergeKey, result.length);
351
- result.push(importDecl);
202
+ if (parserComment.textRange.end <= sourceIndex) {
352
203
  continue;
353
204
  }
354
- const existing = result[existingIndex];
355
- result[existingIndex] = {
356
- source: existing.source,
357
- typeClause: false,
358
- sideEffect: false,
359
- defaultSpec: existing.defaultSpec ?? importDecl.defaultSpec,
360
- namespaceSpec: existing.namespaceSpec ?? importDecl.namespaceSpec,
361
- members: existing.members === null && importDecl.members === null ? null : [...existing.members ?? [], ...importDecl.members ?? []],
362
- attributes: existing.attributes,
363
- leadingComments: existing.leadingComments
364
- };
365
- }
366
- return result;
367
- }
368
- function applyTypeImports(importDecl, style) {
369
- if (importDecl.sideEffect || !importDecl.members) {
370
- return [importDecl];
371
- }
372
- if (style === "separate") {
373
- if (importDecl.typeClause) {
374
- return [importDecl];
375
- }
376
- const typeMembers2 = importDecl.members.filter((member) => member.isType);
377
- const valueMembers2 = importDecl.members.filter((member) => !member.isType);
378
- const output = [];
379
- if (typeMembers2.length > 0) {
380
- output.push({
381
- source: importDecl.source,
382
- typeClause: true,
383
- sideEffect: false,
384
- defaultSpec: null,
385
- namespaceSpec: null,
386
- members: sortMembersAlpha(typeMembers2.map((member) => ({ ...member, isType: false }))),
387
- attributes: importDecl.attributes,
388
- leadingComments: importDecl.leadingComments
389
- });
390
- }
391
- const hasValueBody = valueMembers2.length > 0 || importDecl.defaultSpec !== null || importDecl.namespaceSpec !== null;
392
- if (hasValueBody) {
393
- output.push({
394
- ...importDecl,
395
- members: valueMembers2.length > 0 ? sortMembersAlpha(valueMembers2) : null,
396
- leadingComments: typeMembers2.length > 0 ? "" : importDecl.leadingComments
397
- });
205
+ const commentStart = Math.max(parserComment.textRange.start, sourceRange.start);
206
+ if (sourceText.slice(sourceIndex, commentStart).trim() !== "") {
207
+ return false;
398
208
  }
399
- return output.length > 0 ? output : [importDecl];
400
- }
401
- const inlineBase = importDecl.typeClause ? {
402
- ...importDecl,
403
- typeClause: false,
404
- members: importDecl.members.map((member) => ({
405
- ...member,
406
- isType: true
407
- }))
408
- } : { ...importDecl, members: importDecl.members };
409
- if (style === "mixed") {
410
- return [{ ...inlineBase, members: sortMembersAlpha(inlineBase.members) }];
411
- }
412
- const typeMembers = inlineBase.members.filter((member) => member.isType);
413
- const valueMembers = inlineBase.members.filter((member) => !member.isType);
414
- const sortedTypes = sortMembersAlpha(typeMembers);
415
- const sortedValues = sortMembersAlpha(valueMembers);
416
- const ordered = style === "inline-first" ? [...sortedTypes, ...sortedValues] : [...sortedValues, ...sortedTypes];
417
- return [{ ...inlineBase, members: ordered }];
418
- }
419
- function sortSegment(imports, options2, groupIndex, fallback) {
420
- if (imports.length === 0) {
421
- return [];
209
+ sourceIndex = Math.min(parserComment.textRange.end, sourceRange.end);
422
210
  }
423
- const style = options2.importOrderTypeImports;
424
- const deduplicated = options2.importOrderMergeDuplicates ? mergeImportsFromSameSource(imports) : imports;
425
- const rewritten = deduplicated.flatMap((importDecl) => applyTypeImports(importDecl, style));
426
- const decorated = rewritten.map((importDecl, index) => ({
427
- importDecl,
428
- group: detectGroup(importDecl.source),
429
- originalIndex: index
430
- }));
431
- decorated.sort((a, b) => {
432
- const groupOrderA = groupIndex.get(a.group) ?? fallback;
433
- const groupOrderB = groupIndex.get(b.group) ?? fallback;
434
- if (groupOrderA !== groupOrderB) {
435
- return groupOrderA - groupOrderB;
211
+ return sourceText.slice(sourceIndex, sourceRange.end).trim() === "";
212
+ }
213
+ function isPrettierIgnored(sourceText, statementRange, sortedComments) {
214
+ let leadingCommentsStart = statementRange.start;
215
+ for (let commentIndex = findCommentIndexAtOrAfter(sortedComments, statementRange.start) - 1;commentIndex >= 0; commentIndex--) {
216
+ const parserComment = sortedComments[commentIndex];
217
+ if (!parserComment || parserComment.textRange.end > statementRange.start) {
218
+ continue;
436
219
  }
437
- const sourceA = a.importDecl.source.toLowerCase();
438
- const sourceB = b.importDecl.source.toLowerCase();
439
- if (sourceA !== sourceB) {
440
- return sourceA < sourceB ? -1 : 1;
220
+ const { comment, textRange } = parserComment;
221
+ const followingText = sourceText.slice(textRange.end, leadingCommentsStart);
222
+ if (followingText.trim() !== "") {
223
+ break;
441
224
  }
442
- if (a.importDecl.typeClause !== b.importDecl.typeClause) {
443
- return a.importDecl.typeClause ? -1 : 1;
225
+ if (followingText.includes(`
226
+ `)) {
227
+ const commentLineStart = sourceText.lastIndexOf(`
228
+ `, textRange.start - 1) + 1;
229
+ const isCommentLinePrefixEmpty = isSourceRangeWhitespaceOrComments(sourceText, { start: commentLineStart, end: textRange.start }, sortedComments);
230
+ if (!isCommentLinePrefixEmpty) {
231
+ break;
232
+ }
444
233
  }
445
- return a.originalIndex - b.originalIndex;
446
- });
447
- const lines = [];
448
- let previousGroup = null;
449
- for (const item of decorated) {
450
- if (options2.importOrderSeparation && previousGroup !== null && item.group !== previousGroup) {
451
- lines.push("");
234
+ const commentText = getAstCommentText(comment);
235
+ const isPrettierIgnoreComment = commentText?.trim() === "prettier-ignore";
236
+ if (isPrettierIgnoreComment) {
237
+ return true;
452
238
  }
453
- lines.push(renderImport(item.importDecl));
454
- previousGroup = item.group;
455
- }
456
- return lines;
457
- }
458
- function sortImports(text, rawOptions) {
459
- const options2 = resolveSortOptions(rawOptions);
460
- if (!options2.importOrder) {
461
- return text;
462
- }
463
- const block = extractImportBlock(text);
464
- if (!block || block.statements.length === 0) {
465
- return text;
239
+ leadingCommentsStart = textRange.start;
466
240
  }
467
- const parsed = block.statements.map((rawStatement) => parseImport(rawStatement)).filter((importDecl) => importDecl !== null);
468
- if (parsed.length === 0) {
469
- return text;
470
- }
471
- const groupIndex = new Map(options2.importOrderGroups.map((group, index) => [
472
- group,
473
- index
474
- ]));
475
- const fallback = options2.importOrderGroups.length;
476
- const chunks = [];
477
- let currentSegment = [];
478
- for (const importDecl of parsed) {
479
- if (importDecl.sideEffect) {
480
- if (currentSegment.length > 0) {
481
- chunks.push({ kind: "segment", imports: currentSegment });
482
- currentSegment = [];
483
- }
484
- chunks.push({ kind: "side-effect", importDecl });
485
- } else {
486
- currentSegment.push(importDecl);
241
+ let trailingCommentsEnd = statementRange.end;
242
+ for (let commentIndex = findCommentIndexAtOrAfter(sortedComments, statementRange.end);commentIndex < sortedComments.length; commentIndex++) {
243
+ const parserComment = sortedComments[commentIndex];
244
+ if (!parserComment) {
245
+ break;
487
246
  }
488
- }
489
- if (currentSegment.length > 0) {
490
- chunks.push({ kind: "segment", imports: currentSegment });
491
- }
492
- const allLines = [];
493
- let previousKind = null;
494
- for (const chunk of chunks) {
495
- if (previousKind !== null && previousKind !== chunk.kind && options2.importOrderSeparation) {
496
- allLines.push("");
247
+ const { comment, textRange } = parserComment;
248
+ const textBeforeComment = sourceText.slice(trailingCommentsEnd, textRange.start);
249
+ if (textBeforeComment.includes(`
250
+ `) || textBeforeComment.trim() !== "") {
251
+ break;
497
252
  }
498
- if (chunk.kind === "segment") {
499
- allLines.push(...sortSegment(chunk.imports, options2, groupIndex, fallback));
500
- } else {
501
- allLines.push(renderImport(chunk.importDecl));
253
+ const commentLineEnd = sourceText.indexOf(`
254
+ `, textRange.end);
255
+ const isCommentLastOnLine = isSourceRangeWhitespaceOrComments(sourceText, {
256
+ start: textRange.end,
257
+ end: commentLineEnd < 0 ? sourceText.length : commentLineEnd
258
+ }, sortedComments);
259
+ const commentText = getAstCommentText(comment);
260
+ if (isCommentLastOnLine && commentText?.trim() === "prettier-ignore") {
261
+ return true;
502
262
  }
503
- previousKind = chunk.kind;
263
+ trailingCommentsEnd = textRange.end;
504
264
  }
505
- const replacement = allLines.join(`
506
- `);
507
- const trailing = text.slice(block.end);
508
- const nonBlankIndex = trailing.search(/\S/);
509
- const suffix = nonBlankIndex >= 0 ? `
510
-
511
- ` + trailing.slice(nonBlankIndex) : trailing;
512
- return text.slice(0, block.start) + replacement + suffix;
265
+ return false;
513
266
  }
514
267
 
515
- // src/sort-package.ts
516
- import path from "node:path";
517
-
518
- // src/order-package.ts
519
- var PACKAGE_JSON_TOP_LEVEL_ORDER = [
268
+ // src/utils/package-rules.ts
269
+ var PACKAGE_JSON_FIELD_ORDER = [
520
270
  "$schema",
521
271
  "name",
522
272
  "displayName",
@@ -565,6 +315,7 @@ var PACKAGE_JSON_TOP_LEVEL_ORDER = [
565
315
  "binary",
566
316
  "scripts",
567
317
  "betterScripts",
318
+ "wireit",
568
319
  "l10n",
569
320
  "contributes",
570
321
  "activationEvents",
@@ -628,263 +379,1618 @@ var PACKAGE_JSON_TOP_LEVEL_ORDER = [
628
379
  "markdown",
629
380
  "pnpm"
630
381
  ];
631
- var DEPENDENCY_FIELDS = [
382
+ var DIRECTORY_FIELD_ORDER = [
383
+ "lib",
384
+ "bin",
385
+ "man",
386
+ "doc",
387
+ "example",
388
+ "test"
389
+ ];
390
+ var ESLINT_CONFIG_FIELD_ORDER = [
391
+ "files",
392
+ "excludedFiles",
393
+ "env",
394
+ "parser",
395
+ "parserOptions",
396
+ "settings",
397
+ "plugins",
398
+ "extends",
399
+ "rules",
400
+ "overrides",
401
+ "globals",
402
+ "processor",
403
+ "noInlineConfig",
404
+ "reportUnusedDisableDirectives"
405
+ ];
406
+ var GIT_HOOK_ORDER = [
407
+ "applypatch-msg",
408
+ "pre-applypatch",
409
+ "post-applypatch",
410
+ "pre-commit",
411
+ "pre-merge-commit",
412
+ "prepare-commit-msg",
413
+ "commit-msg",
414
+ "post-commit",
415
+ "pre-rebase",
416
+ "post-checkout",
417
+ "post-merge",
418
+ "pre-push",
419
+ "pre-receive",
420
+ "update",
421
+ "proc-receive",
422
+ "post-receive",
423
+ "post-update",
424
+ "reference-transaction",
425
+ "push-to-checkout",
426
+ "pre-auto-gc",
427
+ "post-rewrite",
428
+ "sendemail-validate",
429
+ "fsmonitor-watchman",
430
+ "p4-changelist",
431
+ "p4-prepare-changelist",
432
+ "p4-post-changelist",
433
+ "p4-pre-submit",
434
+ "post-index-change"
435
+ ];
436
+ var NPM_LIFECYCLE_SCRIPT_NAMES = new Set([
437
+ "install",
438
+ "pack",
439
+ "prepare",
440
+ "publish",
441
+ "restart",
442
+ "shrinkwrap",
443
+ "start",
444
+ "stop",
445
+ "test",
446
+ "uninstall",
447
+ "version"
448
+ ]);
449
+ var PNPM_CONFIG_FIELD_ORDER = [
450
+ "peerDependencyRules",
451
+ "neverBuiltDependencies",
452
+ "onlyBuiltDependencies",
453
+ "onlyBuiltDependenciesFile",
454
+ "allowedDeprecatedVersions",
455
+ "allowNonAppliedPatches",
456
+ "updateConfig",
457
+ "auditConfig",
458
+ "requiredScripts",
459
+ "supportedArchitectures",
460
+ "overrides",
461
+ "patchedDependencies",
462
+ "packageExtensions"
463
+ ];
464
+ var WIREIT_SCRIPT_FIELD_ORDER = [
465
+ "command",
632
466
  "dependencies",
633
- "devDependencies",
634
- "peerDependencies",
635
- "optionalDependencies",
636
- "resolutions",
637
- "overrides"
467
+ "files",
468
+ "output"
638
469
  ];
639
470
 
640
471
  // src/sort-package.ts
641
- function isPlainObject(value) {
642
- return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
472
+ class JsonSourceLiteral {
473
+ value;
474
+ sourceText;
475
+ constructor(value, sourceText) {
476
+ this.value = value;
477
+ this.sourceText = sourceText;
478
+ }
479
+ }
480
+ var SEQUENTIAL_SCRIPT_PATTERN = /(?<=^|[\s&;<>|(])(?:run-s|npm-run-all2? .*(?:--sequential|--serial|-s))(?=$|[\s&;<>|)])/;
481
+ function compareText(leftText, rightText) {
482
+ if (leftText === rightText) {
483
+ return 0;
484
+ }
485
+ return leftText < rightText ? -1 : 1;
486
+ }
487
+ function isJsonObject(value) {
488
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof JsonSourceLiteral);
489
+ }
490
+ function getJsonPathKey(jsonPath) {
491
+ return JSON.stringify(jsonPath);
492
+ }
493
+ function getJsonString(jsonValue) {
494
+ if (typeof jsonValue === "string") {
495
+ return jsonValue;
496
+ }
497
+ if (jsonValue instanceof JsonSourceLiteral && typeof jsonValue.value === "string") {
498
+ return jsonValue.value;
499
+ }
500
+ return null;
501
+ }
502
+ function isJsonStringValue(jsonValue) {
503
+ return getJsonString(jsonValue) !== null;
504
+ }
505
+ function isParserJsonAstNode(value) {
506
+ return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
507
+ }
508
+ function preserveJsonSourceLiterals(jsonValue, parserJsonNode, sourceText, fieldNameSourceTexts, jsonPath = []) {
509
+ if (parserJsonNode.type === "JsonRoot") {
510
+ const rootNode = parserJsonNode.node;
511
+ if (!isParserJsonAstNode(rootNode)) {
512
+ return;
513
+ }
514
+ return preserveJsonSourceLiterals(jsonValue, rootNode, sourceText, fieldNameSourceTexts, jsonPath);
515
+ }
516
+ const isStringLiteral = parserJsonNode.type === "StringLiteral";
517
+ const isNumberLiteral = parserJsonNode.type === "NumericLiteral";
518
+ const isNegativeNumberLiteral = parserJsonNode.type === "UnaryExpression" && parserJsonNode.operator === "-" && parserJsonNode.argument?.type === "NumericLiteral";
519
+ if (isStringLiteral || isNumberLiteral || isNegativeNumberLiteral) {
520
+ const literalRange = getAstNodeTextRange(parserJsonNode);
521
+ const isLiteralValueValid = isStringLiteral && typeof jsonValue === "string" || !isStringLiteral && typeof jsonValue === "number";
522
+ if (!literalRange || !isLiteralValueValid) {
523
+ return;
524
+ }
525
+ return new JsonSourceLiteral(jsonValue, sourceText.slice(literalRange.start, literalRange.end));
526
+ }
527
+ if (parserJsonNode.type === "ObjectExpression") {
528
+ if (!isJsonObject(jsonValue) || !Array.isArray(parserJsonNode.properties)) {
529
+ return;
530
+ }
531
+ const jsonObject = { ...jsonValue };
532
+ const propertyNames = new Set;
533
+ for (const propertyNode of parserJsonNode.properties) {
534
+ const propertyName = getAstNodeName(propertyNode.key);
535
+ const propertyNameRange = getAstNodeTextRange(propertyNode.key);
536
+ const propertyValueNode = propertyNode.value;
537
+ if (propertyNode.type !== "ObjectProperty" || propertyName === null || !propertyNameRange || propertyNames.has(propertyName) || !Object.hasOwn(jsonValue, propertyName) || !isParserJsonAstNode(propertyValueNode)) {
538
+ return;
539
+ }
540
+ propertyNames.add(propertyName);
541
+ const propertyPath = [...jsonPath, propertyName];
542
+ const propertyValue = preserveJsonSourceLiterals(jsonValue[propertyName], propertyValueNode, sourceText, fieldNameSourceTexts, propertyPath);
543
+ if (propertyValue === undefined) {
544
+ return;
545
+ }
546
+ fieldNameSourceTexts.set(getJsonPathKey(propertyPath), sourceText.slice(propertyNameRange.start, propertyNameRange.end));
547
+ jsonObject[propertyName] = propertyValue;
548
+ }
549
+ return jsonObject;
550
+ }
551
+ if (parserJsonNode.type === "ArrayExpression") {
552
+ if (!Array.isArray(jsonValue) || !Array.isArray(parserJsonNode.elements) || jsonValue.length !== parserJsonNode.elements.length) {
553
+ return;
554
+ }
555
+ const jsonArray = [];
556
+ for (const [
557
+ elementIndex,
558
+ elementNode
559
+ ] of parserJsonNode.elements.entries()) {
560
+ if (!elementNode) {
561
+ return;
562
+ }
563
+ const elementValue = preserveJsonSourceLiterals(jsonValue[elementIndex], elementNode, sourceText, fieldNameSourceTexts, [...jsonPath, elementIndex]);
564
+ if (elementValue === undefined) {
565
+ return;
566
+ }
567
+ jsonArray.push(elementValue);
568
+ }
569
+ return jsonArray;
570
+ }
571
+ return jsonValue;
572
+ }
573
+ function serializeJsonValue(jsonValue, fieldNameSourceTexts, jsonPath = []) {
574
+ if (jsonValue instanceof JsonSourceLiteral) {
575
+ return jsonValue.sourceText;
576
+ }
577
+ if (typeof jsonValue === "number" || typeof jsonValue === "string") {
578
+ return null;
579
+ }
580
+ if (Array.isArray(jsonValue)) {
581
+ const serializedValues = [];
582
+ for (const [arrayIndex, arrayValue] of jsonValue.entries()) {
583
+ const serializedValue = serializeJsonValue(arrayValue, fieldNameSourceTexts, [...jsonPath, arrayIndex]);
584
+ if (serializedValue === null) {
585
+ return null;
586
+ }
587
+ serializedValues.push(serializedValue);
588
+ }
589
+ return `[${serializedValues.join(",")}]`;
590
+ }
591
+ if (isJsonObject(jsonValue)) {
592
+ const serializedFields = [];
593
+ for (const [fieldName, fieldValue] of Object.entries(jsonValue)) {
594
+ const fieldPath = [...jsonPath, fieldName];
595
+ const fieldNameSourceText = fieldNameSourceTexts.get(getJsonPathKey(fieldPath));
596
+ const serializedValue = serializeJsonValue(fieldValue, fieldNameSourceTexts, fieldPath);
597
+ if (!fieldNameSourceText || serializedValue === null) {
598
+ return null;
599
+ }
600
+ serializedFields.push(`${fieldNameSourceText}:${serializedValue}`);
601
+ }
602
+ return `{${serializedFields.join(",")}}`;
603
+ }
604
+ return JSON.stringify(jsonValue);
643
605
  }
644
606
  function isStringArray(value) {
645
- return Array.isArray(value) && value.every((item) => typeof item === "string");
646
- }
647
- var TOP_LEVEL_ORDER_INDEX = new Map(PACKAGE_JSON_TOP_LEVEL_ORDER.map((key, index) => [key, index]));
648
- function sortObjectKeysByOrder(record, orderIndex) {
649
- const known = [];
650
- const rest = [];
651
- for (const entry of Object.entries(record)) {
652
- const [key] = entry;
653
- if (orderIndex.has(key)) {
654
- known.push(entry);
655
- } else {
656
- rest.push(entry);
607
+ return Array.isArray(value) && value.every(isJsonStringValue);
608
+ }
609
+ function deduplicateStringValues(stringValues) {
610
+ const uniqueStringValues = new Map;
611
+ for (const stringValue of stringValues) {
612
+ const text = getJsonString(stringValue);
613
+ if (!uniqueStringValues.has(text)) {
614
+ uniqueStringValues.set(text, stringValue);
657
615
  }
658
616
  }
659
- known.sort(([a], [b]) => (orderIndex.get(a) ?? 0) - (orderIndex.get(b) ?? 0));
660
- rest.sort(([a], [b]) => a.localeCompare(b, "en"));
661
- return Object.fromEntries([...known, ...rest]);
617
+ return [...uniqueStringValues.values()];
618
+ }
619
+ function sortJsonObject(jsonObject, compareKeys = compareText) {
620
+ return Object.fromEntries(Object.entries(jsonObject).sort(([leftKey], [rightKey]) => compareKeys(leftKey, rightKey)));
621
+ }
622
+ function sortJsonObjectByKeyOrder(jsonObject, keyOrder) {
623
+ const keyOrderIndexes = new Map(keyOrder.map((key, index) => [key, index]));
624
+ return sortJsonObject(jsonObject, (leftKey, rightKey) => {
625
+ const leftIndex = keyOrderIndexes.get(leftKey);
626
+ const rightIndex = keyOrderIndexes.get(rightKey);
627
+ const isLeftKeyKnown = leftIndex !== undefined;
628
+ const isRightKeyKnown = rightIndex !== undefined;
629
+ if (isLeftKeyKnown && isRightKeyKnown) {
630
+ return leftIndex - rightIndex;
631
+ }
632
+ if (isLeftKeyKnown) {
633
+ return -1;
634
+ }
635
+ if (isRightKeyKnown) {
636
+ return 1;
637
+ }
638
+ return compareText(leftKey, rightKey);
639
+ });
640
+ }
641
+ function sortJsonObjectRecursively(jsonObject, sortObject = sortJsonObject) {
642
+ const sortedNestedValues = Object.fromEntries(Object.entries(jsonObject).map(([key, value]) => [
643
+ key,
644
+ isJsonObject(value) ? sortJsonObjectRecursively(value, sortObject) : value
645
+ ]));
646
+ return sortObject(sortedNestedValues);
647
+ }
648
+ function sortJsonObjectValue(fieldValue, sortObject) {
649
+ return isJsonObject(fieldValue) ? sortObject(fieldValue) : fieldValue;
662
650
  }
663
- function sortObjectKeysAlpha(value) {
664
- if (!isPlainObject(value)) {
665
- return value;
651
+ function sortJsonObjectValueAlphabetically(fieldValue) {
652
+ return sortJsonObjectValue(fieldValue, sortJsonObject);
653
+ }
654
+ function sortJsonObjectValueRecursively(fieldValue) {
655
+ return sortJsonObjectValue(fieldValue, sortJsonObjectRecursively);
656
+ }
657
+ function sortJsonObjectValueByKeyOrder(fieldValue, keyOrder) {
658
+ return sortJsonObjectValue(fieldValue, (jsonObject) => sortJsonObjectByKeyOrder(jsonObject, keyOrder));
659
+ }
660
+ function sortUniqueStringArrayValue(fieldValue) {
661
+ if (!isStringArray(fieldValue)) {
662
+ return fieldValue;
666
663
  }
667
- return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b, "en")));
664
+ return deduplicateStringValues(fieldValue).sort((leftValue, rightValue) => compareText(getJsonString(leftValue), getJsonString(rightValue)));
668
665
  }
669
- function sortStringArrayAlpha(value) {
670
- return [...value].sort((a, b) => a.localeCompare(b, "en"));
666
+ function deduplicateStringArrayValue(fieldValue) {
667
+ return isStringArray(fieldValue) ? deduplicateStringValues(fieldValue) : fieldValue;
671
668
  }
672
- function uniqueStringArray(value) {
673
- return [...new Set(value)];
669
+ function sortPersonValue(fieldValue) {
670
+ return sortJsonObjectValueByKeyOrder(fieldValue, ["name", "email", "url"]);
674
671
  }
675
- function isPackageJson(filepath) {
676
- if (!filepath) {
677
- return false;
672
+ function sortPeopleArrayValue(fieldValue) {
673
+ if (!Array.isArray(fieldValue)) {
674
+ return fieldValue;
678
675
  }
679
- return path.basename(filepath) === "package.json";
676
+ return fieldValue.map((person) => sortPersonValue(person));
680
677
  }
681
- function detectIndent(source) {
682
- const match = /\n([ \t]+)\S/.exec(source);
683
- return match ? match[1] ?? " " : " ";
678
+ function sortPackageJsonFields(packageJson) {
679
+ const fieldOrderIndexes = new Map(PACKAGE_JSON_FIELD_ORDER.map((fieldName, index) => [fieldName, index]));
680
+ return sortJsonObject(packageJson, (leftFieldName, rightFieldName) => {
681
+ const leftIndex = fieldOrderIndexes.get(leftFieldName);
682
+ const rightIndex = fieldOrderIndexes.get(rightFieldName);
683
+ const isLeftFieldKnown = leftIndex !== undefined;
684
+ const isRightFieldKnown = rightIndex !== undefined;
685
+ if (isLeftFieldKnown && isRightFieldKnown) {
686
+ return leftIndex - rightIndex;
687
+ }
688
+ if (isLeftFieldKnown) {
689
+ return -1;
690
+ }
691
+ if (isRightFieldKnown) {
692
+ return 1;
693
+ }
694
+ const isLeftFieldPrivate = leftFieldName.startsWith("_");
695
+ const isRightFieldPrivate = rightFieldName.startsWith("_");
696
+ if (isLeftFieldPrivate !== isRightFieldPrivate) {
697
+ return isLeftFieldPrivate ? 1 : -1;
698
+ }
699
+ return compareText(leftFieldName, rightFieldName);
700
+ });
684
701
  }
685
- var DEFAULT_NPM_SCRIPTS = new Set([
686
- "install",
687
- "pack",
688
- "prepare",
689
- "publish",
690
- "restart",
691
- "shrinkwrap",
692
- "start",
693
- "stop",
694
- "test",
695
- "uninstall",
696
- "version"
697
- ]);
698
- var RUN_S_PATTERN = /(?<=^|[\s&;<>|(])(?:run-s|npm-run-all2? .*(?:--sequential|--serial|-s))(?=$|[\s&;<>|)])/;
699
- function hasSequentialScript(packageObject) {
700
- const devDependencies = packageObject["devDependencies"];
701
- if (!isPlainObject(devDependencies) || !Object.hasOwn(devDependencies, "npm-run-all") && !Object.hasOwn(devDependencies, "npm-run-all2")) {
702
+ function isNpmDependencyOrderPreferred(packageJson) {
703
+ const packageManager = getJsonString(packageJson.packageManager);
704
+ if (packageManager !== null) {
705
+ return packageManager.startsWith("npm@");
706
+ }
707
+ const devEngines = packageJson.devEngines;
708
+ if (isJsonObject(devEngines)) {
709
+ const devPackageManager = devEngines.packageManager;
710
+ const devPackageManagerName = isJsonObject(devPackageManager) ? getJsonString(devPackageManager.name) : null;
711
+ if (devPackageManagerName !== null) {
712
+ return devPackageManagerName === "npm";
713
+ }
714
+ }
715
+ if (isJsonObject(packageJson.pnpm)) {
702
716
  return false;
703
717
  }
704
- const scriptCommands = ["scripts", "betterScripts"].flatMap((field) => {
705
- const scriptsObject = packageObject[field];
706
- return isPlainObject(scriptsObject) ? Object.values(scriptsObject) : [];
718
+ return true;
719
+ }
720
+ function sortDependencyObject(dependencyObject, packageJson) {
721
+ if (!isNpmDependencyOrderPreferred(packageJson)) {
722
+ return sortJsonObject(dependencyObject);
723
+ }
724
+ return sortJsonObject(dependencyObject, (leftName, rightName) => leftName.localeCompare(rightName, "en"));
725
+ }
726
+ function sortDependencyValue(fieldValue, packageJson) {
727
+ return sortJsonObjectValue(fieldValue, (dependencyObject) => sortDependencyObject(dependencyObject, packageJson));
728
+ }
729
+ function sortWorkspacesValue(fieldValue, packageJson) {
730
+ if (!isJsonObject(fieldValue)) {
731
+ return fieldValue;
732
+ }
733
+ const sortedWorkspaces = sortJsonObjectByKeyOrder(fieldValue, [
734
+ "packages",
735
+ "catalog"
736
+ ]);
737
+ const workspacePackages = sortedWorkspaces.packages;
738
+ if (workspacePackages !== undefined) {
739
+ sortedWorkspaces.packages = sortUniqueStringArrayValue(workspacePackages);
740
+ }
741
+ if (isJsonObject(sortedWorkspaces.catalog)) {
742
+ sortedWorkspaces.catalog = sortDependencyObject(sortedWorkspaces.catalog, packageJson);
743
+ }
744
+ return sortedWorkspaces;
745
+ }
746
+ function sortEslintRules(rules) {
747
+ return sortJsonObject(rules, (leftRuleName, rightRuleName) => {
748
+ const leftPluginDepth = leftRuleName.split("/").length;
749
+ const rightPluginDepth = rightRuleName.split("/").length;
750
+ return leftPluginDepth - rightPluginDepth || leftRuleName.localeCompare(rightRuleName);
707
751
  });
708
- return scriptCommands.some((script) => typeof script === "string" && script.includes("*") && RUN_S_PATTERN.test(script));
709
- }
710
- function sortScriptNames(keys, prefix = "") {
711
- const groupMap = new Map;
712
- for (const key of keys) {
713
- const rest = prefix ? key.slice(prefix.length + 1) : key;
714
- const colonIndex = rest.indexOf(":");
715
- if (colonIndex > 0) {
716
- const base = key.slice(0, (prefix ? prefix.length + 1 : 0) + colonIndex);
717
- let group = groupMap.get(base);
718
- if (!group) {
719
- group = [];
720
- groupMap.set(base, group);
752
+ }
753
+ function sortEslintConfigObject(eslintConfig) {
754
+ const sortedConfig = sortJsonObjectByKeyOrder(eslintConfig, ESLINT_CONFIG_FIELD_ORDER);
755
+ for (const fieldName of ["env", "globals", "parserOptions", "settings"]) {
756
+ if (isJsonObject(sortedConfig[fieldName])) {
757
+ sortedConfig[fieldName] = sortJsonObject(sortedConfig[fieldName]);
758
+ }
759
+ }
760
+ if (isJsonObject(sortedConfig.rules)) {
761
+ sortedConfig.rules = sortEslintRules(sortedConfig.rules);
762
+ }
763
+ if (Array.isArray(sortedConfig.overrides)) {
764
+ sortedConfig.overrides = sortedConfig.overrides.map((override) => isJsonObject(override) ? sortEslintConfigObject(override) : override);
765
+ }
766
+ return sortedConfig;
767
+ }
768
+ function sortEslintConfigValue(fieldValue) {
769
+ return sortJsonObjectValue(fieldValue, sortEslintConfigObject);
770
+ }
771
+ function sortPrettierConfigObject(prettierConfig) {
772
+ const keyOrder = Object.keys(prettierConfig).filter((key) => key !== "overrides").sort(compareText);
773
+ if (Object.hasOwn(prettierConfig, "overrides")) {
774
+ keyOrder.push("overrides");
775
+ }
776
+ const sortedConfig = sortJsonObjectByKeyOrder(prettierConfig, keyOrder);
777
+ if (Array.isArray(sortedConfig.overrides)) {
778
+ sortedConfig.overrides = sortedConfig.overrides.map((override) => {
779
+ if (!isJsonObject(override)) {
780
+ return override;
721
781
  }
722
- group.push(key);
723
- } else {
724
- let group = groupMap.get(key);
725
- if (!group) {
726
- group = [];
727
- groupMap.set(key, group);
782
+ const sortedOverride = sortJsonObject(override);
783
+ if (isJsonObject(sortedOverride.options)) {
784
+ sortedOverride.options = sortJsonObject(sortedOverride.options);
728
785
  }
729
- group.push(key);
730
- }
786
+ return sortedOverride;
787
+ });
788
+ }
789
+ return sortedConfig;
790
+ }
791
+ function sortPrettierConfigValue(fieldValue) {
792
+ return sortJsonObjectValue(fieldValue, sortPrettierConfigObject);
793
+ }
794
+ function sortWireitScriptObject(scriptConfig) {
795
+ const sortedConfig = sortJsonObjectByKeyOrder(scriptConfig, WIREIT_SCRIPT_FIELD_ORDER);
796
+ if (Array.isArray(sortedConfig.dependencies)) {
797
+ sortedConfig.dependencies = sortedConfig.dependencies.map((dependency) => sortJsonObjectValueByKeyOrder(dependency, ["script", "cascade"]));
798
+ }
799
+ if (isJsonObject(sortedConfig.env)) {
800
+ sortedConfig.env = sortJsonObject(Object.fromEntries(Object.entries(sortedConfig.env).map(([name, value]) => [
801
+ name,
802
+ sortJsonObjectValueByKeyOrder(value, ["external", "default"])
803
+ ])));
731
804
  }
732
- return [...groupMap.keys()].sort((a, b) => a.localeCompare(b, "en")).flatMap((groupKey) => {
733
- const children = groupMap.get(groupKey);
734
- if (children.length > 1 && children.some((key) => key !== groupKey && key.startsWith(groupKey + ":"))) {
735
- const direct = children.filter((key) => key === groupKey || !key.startsWith(groupKey + ":")).sort((a, b) => a.localeCompare(b, "en"));
736
- const nested = children.filter((key) => key.startsWith(groupKey + ":"));
737
- return [...direct, ...sortScriptNames(nested, groupKey)];
805
+ if (isJsonObject(sortedConfig.service)) {
806
+ sortedConfig.service = sortJsonObjectByKeyOrder(sortedConfig.service, [
807
+ "readyWhen"
808
+ ]);
809
+ if (isJsonObject(sortedConfig.service.readyWhen)) {
810
+ sortedConfig.service.readyWhen = sortJsonObject(sortedConfig.service.readyWhen);
738
811
  }
739
- return children.sort((a, b) => a.localeCompare(b, "en"));
812
+ }
813
+ return sortedConfig;
814
+ }
815
+ function sortWireitValue(fieldValue) {
816
+ if (!isJsonObject(fieldValue)) {
817
+ return fieldValue;
818
+ }
819
+ return sortJsonObject(Object.fromEntries(Object.entries(fieldValue).map(([scriptName, scriptConfig]) => [
820
+ scriptName,
821
+ sortJsonObjectValue(scriptConfig, sortWireitScriptObject)
822
+ ])));
823
+ }
824
+ function hasSequentialScript(packageJson) {
825
+ const devDependencies = packageJson.devDependencies;
826
+ if (!isJsonObject(devDependencies)) {
827
+ return false;
828
+ }
829
+ const isSequentialRunnerInstalled = Object.hasOwn(devDependencies, "npm-run-all") || Object.hasOwn(devDependencies, "npm-run-all2");
830
+ if (!isSequentialRunnerInstalled) {
831
+ return false;
832
+ }
833
+ return ["scripts", "betterScripts"].some((fieldName) => {
834
+ const scripts = packageJson[fieldName];
835
+ return isJsonObject(scripts) && Object.values(scripts).some((script) => {
836
+ const scriptText = getJsonString(script);
837
+ return scriptText !== null && scriptText.includes("*") && SEQUENTIAL_SCRIPT_PATTERN.test(scriptText);
838
+ });
740
839
  });
741
840
  }
742
- function sortScripts(scripts, packageObject) {
743
- const names = Object.keys(scripts);
744
- const prefixable = new Set;
745
- const normalized = names.map((name) => {
746
- const base = name.replace(/^(?:pre|post)/, "");
747
- if (DEFAULT_NPM_SCRIPTS.has(base) || names.includes(base)) {
748
- prefixable.add(base);
749
- return base;
841
+ function sortScriptNames(scriptNames, namespacePrefix = "") {
842
+ const scriptGroups = new Map;
843
+ for (const scriptName of scriptNames) {
844
+ const unprefixedScriptName = namespacePrefix ? scriptName.slice(namespacePrefix.length + 1) : scriptName;
845
+ const namespaceSeparatorIndex = unprefixedScriptName.indexOf(":");
846
+ const scriptGroupName = namespaceSeparatorIndex > 0 ? scriptName.slice(0, (namespacePrefix ? namespacePrefix.length + 1 : 0) + namespaceSeparatorIndex) : scriptName;
847
+ const groupedScriptNames = scriptGroups.get(scriptGroupName) ?? [];
848
+ groupedScriptNames.push(scriptName);
849
+ scriptGroups.set(scriptGroupName, groupedScriptNames);
850
+ }
851
+ return [...scriptGroups.keys()].sort(compareText).flatMap((scriptGroupName) => {
852
+ const groupedScriptNames = scriptGroups.get(scriptGroupName);
853
+ const isNestedGroup = groupedScriptNames.length > 1 && groupedScriptNames.some((scriptName) => scriptName !== scriptGroupName && scriptName.startsWith(`${scriptGroupName}:`));
854
+ if (!isNestedGroup) {
855
+ return groupedScriptNames.sort(compareText);
750
856
  }
751
- return name;
752
- });
753
- let sortedNames;
754
- if (hasSequentialScript(packageObject)) {
755
- sortedNames = [...new Set(normalized)];
756
- } else {
757
- sortedNames = sortScriptNames(normalized);
758
- }
759
- const orderedNames = sortedNames.flatMap((key) => prefixable.has(key) ? [`pre${key}`, key, `post${key}`] : [key]);
760
- return Object.fromEntries(orderedNames.filter((name) => Object.hasOwn(scripts, name)).map((name) => [name, scripts[name]]));
761
- }
762
- function sortExportsField(exports) {
763
- const keys = Object.keys(exports);
764
- const paths = keys.filter((key) => key.startsWith(".")).sort();
765
- const conditions = keys.filter((key) => !key.startsWith(".")).sort();
766
- const defaultIndex = conditions.indexOf("default");
767
- if (defaultIndex >= 0) {
768
- conditions.splice(defaultIndex, 1);
769
- conditions.push("default");
770
- }
771
- const orderedKeys = [...paths, ...conditions];
772
- return Object.fromEntries(orderedKeys.map((key) => {
773
- const value = exports[key];
857
+ const directScriptNames = groupedScriptNames.filter((scriptName) => scriptName === scriptGroupName || !scriptName.startsWith(`${scriptGroupName}:`)).sort(compareText);
858
+ const nestedScriptNames = groupedScriptNames.filter((scriptName) => scriptName.startsWith(`${scriptGroupName}:`));
774
859
  return [
775
- key,
776
- isPlainObject(value) ? sortExportsField(value) : value
860
+ ...directScriptNames,
861
+ ...sortScriptNames(nestedScriptNames, scriptGroupName)
777
862
  ];
778
- }));
863
+ });
779
864
  }
780
- var UNIQUE_ONLY_FIELDS = new Set(["keywords", "files", "activationEvents"]);
781
- var UNIQUE_AND_SORT_FIELDS = new Set([
782
- "bundledDependencies",
783
- "bundleDependencies",
784
- "extensionPack",
785
- "extensionDependencies"
786
- ]);
787
- var NO_SORT_ARRAY_FIELDS = new Set(["workspaces"]);
788
- function detectNewline(source) {
789
- const crlfIndex = source.indexOf(`\r
790
- `);
791
- return crlfIndex >= 0 ? `\r
792
- ` : `
793
- `;
865
+ function sortScriptsValue(fieldValue, packageJson) {
866
+ if (!isJsonObject(fieldValue)) {
867
+ return fieldValue;
868
+ }
869
+ const scriptNames = Object.keys(fieldValue);
870
+ const baseScriptNames = new Set;
871
+ const normalizedScriptNames = scriptNames.map((scriptName) => {
872
+ const baseScriptName = scriptName.replace(/^(?:pre|post)/, "");
873
+ const isLifecycleScript = NPM_LIFECYCLE_SCRIPT_NAMES.has(baseScriptName);
874
+ const isBaseScriptPresent = scriptNames.includes(baseScriptName);
875
+ if (isLifecycleScript || isBaseScriptPresent) {
876
+ baseScriptNames.add(baseScriptName);
877
+ return baseScriptName;
878
+ }
879
+ return scriptName;
880
+ });
881
+ const orderedBaseScriptNames = hasSequentialScript(packageJson) ? [...new Set(normalizedScriptNames)] : sortScriptNames(normalizedScriptNames);
882
+ const orderedScriptNames = orderedBaseScriptNames.flatMap((baseScriptName) => baseScriptNames.has(baseScriptName) ? [`pre${baseScriptName}`, baseScriptName, `post${baseScriptName}`] : [baseScriptName]);
883
+ return Object.fromEntries(orderedScriptNames.filter((scriptName) => Object.hasOwn(fieldValue, scriptName)).map((scriptName) => [scriptName, fieldValue[scriptName]]));
884
+ }
885
+ function sortExportsValue(fieldValue) {
886
+ if (!isJsonObject(fieldValue)) {
887
+ return fieldValue;
888
+ }
889
+ const exportKeys = Object.keys(fieldValue);
890
+ const exportPathKeys = exportKeys.filter((key) => key.startsWith("."));
891
+ const exportConditionKeys = exportKeys.filter((key) => !key.startsWith(".") && key !== "default");
892
+ if (Object.hasOwn(fieldValue, "default")) {
893
+ exportConditionKeys.push("default");
894
+ }
895
+ return Object.fromEntries([...exportPathKeys, ...exportConditionKeys].map((exportKey) => [exportKey, sortExportsValue(fieldValue[exportKey])]));
896
+ }
897
+ function sortDevEnginesValue(fieldValue) {
898
+ if (!isJsonObject(fieldValue) || !isJsonObject(fieldValue.packageManager)) {
899
+ return fieldValue;
900
+ }
901
+ return {
902
+ ...fieldValue,
903
+ packageManager: sortJsonObjectByKeyOrder(fieldValue.packageManager, [
904
+ "name",
905
+ "version",
906
+ "onFail"
907
+ ])
908
+ };
909
+ }
910
+ function getDependencyName(dependencyIdentifier) {
911
+ const versionSeparatorIndex = dependencyIdentifier.indexOf("@", dependencyIdentifier.startsWith("@") ? 1 : 0);
912
+ return versionSeparatorIndex < 0 ? dependencyIdentifier : dependencyIdentifier.slice(0, versionSeparatorIndex);
794
913
  }
795
- function sortPackageJson(text, rawOptions) {
796
- if (!isPackageJson(rawOptions.filepath)) {
797
- return text;
914
+ function parsePackageSelector(packageSelector) {
915
+ const [nameAndVersion = packageSelector] = packageSelector.split(">");
916
+ const versionSeparatorIndex = nameAndVersion.lastIndexOf("@");
917
+ if (versionSeparatorIndex <= 0) {
918
+ return { name: packageSelector, versionRange: null };
798
919
  }
799
- const options2 = resolveSortOptions(rawOptions);
800
- const exclude = new Set(options2.packageJsonOrderExcludeKeys);
801
- let parsed;
920
+ return {
921
+ name: nameAndVersion.slice(0, versionSeparatorIndex),
922
+ versionRange: nameAndVersion.slice(versionSeparatorIndex + 1) || null
923
+ };
924
+ }
925
+ function getMinimumSemanticVersion(versionRange) {
802
926
  try {
803
- parsed = JSON.parse(text);
927
+ return findMinimumSemanticVersion(versionRange);
804
928
  } catch {
805
- return text;
929
+ return null;
806
930
  }
807
- if (!isPlainObject(parsed)) {
808
- return text;
931
+ }
932
+ function comparePnpmOverrideSelectors(leftSelector, rightSelector) {
933
+ const leftPackage = parsePackageSelector(leftSelector);
934
+ const rightPackage = parsePackageSelector(rightSelector);
935
+ if (leftPackage.name !== rightPackage.name) {
936
+ return leftPackage.name.localeCompare(rightPackage.name, "en");
809
937
  }
810
- let result = parsed;
811
- for (const field of DEPENDENCY_FIELDS) {
812
- const dependencyMap = result[field];
813
- if (dependencyMap !== undefined && !exclude.has(field)) {
814
- result[field] = sortObjectKeysAlpha(dependencyMap);
815
- }
938
+ if (!leftPackage.versionRange && !rightPackage.versionRange) {
939
+ return 0;
816
940
  }
817
- if (options2.packageJsonOrder) {
818
- result = sortObjectKeysByOrder(result, TOP_LEVEL_ORDER_INDEX);
819
- for (const field of ["scripts", "betterScripts"]) {
820
- const scriptsValue = result[field];
821
- if (scriptsValue !== undefined && isPlainObject(scriptsValue) && !exclude.has(field)) {
822
- result[field] = sortScripts(scriptsValue, result);
823
- }
824
- }
825
- const exportsValue = result["exports"];
826
- if (exportsValue !== undefined && isPlainObject(exportsValue) && !exclude.has("exports")) {
827
- result["exports"] = sortExportsField(exportsValue);
828
- }
829
- for (const [key, value] of Object.entries(result)) {
830
- if (exclude.has(key)) {
831
- continue;
832
- }
833
- if (!isStringArray(value)) {
834
- continue;
835
- }
836
- if (NO_SORT_ARRAY_FIELDS.has(key)) {
837
- continue;
838
- }
839
- if (UNIQUE_ONLY_FIELDS.has(key)) {
840
- result[key] = uniqueStringArray(value);
841
- continue;
842
- }
843
- if (UNIQUE_AND_SORT_FIELDS.has(key)) {
844
- result[key] = sortStringArrayAlpha(uniqueStringArray(value));
845
- continue;
846
- }
847
- result[key] = sortStringArrayAlpha(value);
848
- }
941
+ if (!leftPackage.versionRange) {
942
+ return -1;
849
943
  }
850
- const indent = detectIndent(text);
851
- const newline = detectNewline(text);
852
- const output = JSON.stringify(result, null, indent);
853
- if (text.endsWith(newline)) {
854
- return newline === `\r
855
- ` ? output.replace(/\n/g, `\r
856
- `) + `\r
857
- ` : output + `
858
- `;
944
+ if (!rightPackage.versionRange) {
945
+ return 1;
946
+ }
947
+ const leftVersion = getMinimumSemanticVersion(leftPackage.versionRange);
948
+ const rightVersion = getMinimumSemanticVersion(rightPackage.versionRange);
949
+ if (!leftVersion && !rightVersion) {
950
+ return compareText(leftPackage.versionRange, rightPackage.versionRange);
951
+ }
952
+ if (!leftVersion) {
953
+ return 1;
954
+ }
955
+ if (!rightVersion) {
956
+ return -1;
957
+ }
958
+ return leftVersion.compare(rightVersion);
959
+ }
960
+ function sortDependencyMetadataValue(fieldValue) {
961
+ return sortJsonObjectValue(fieldValue, (dependencyMetadata) => {
962
+ const compareDependencyIdentifiers = (leftIdentifier, rightIdentifier) => compareText(getDependencyName(leftIdentifier), getDependencyName(rightIdentifier));
963
+ return sortJsonObjectRecursively(dependencyMetadata, (jsonObject) => sortJsonObject(jsonObject, compareDependencyIdentifiers));
964
+ });
965
+ }
966
+ function sortPnpmConfigValue(fieldValue) {
967
+ return sortJsonObjectValue(fieldValue, (pnpmConfig) => {
968
+ const sortedPnpmConfig = sortJsonObjectRecursively(pnpmConfig, (jsonObject) => sortJsonObjectByKeyOrder(jsonObject, PNPM_CONFIG_FIELD_ORDER));
969
+ if (!isJsonObject(sortedPnpmConfig.overrides)) {
970
+ return sortedPnpmConfig;
971
+ }
972
+ return {
973
+ ...sortedPnpmConfig,
974
+ overrides: sortJsonObject(sortedPnpmConfig.overrides, comparePnpmOverrideSelectors)
975
+ };
976
+ });
977
+ }
978
+ var PACKAGE_JSON_FIELD_SORTERS = {
979
+ categories: deduplicateStringArrayValue,
980
+ keywords: deduplicateStringArrayValue,
981
+ bugs: (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, ["url", "email"]),
982
+ repository: (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, ["type", "url"]),
983
+ funding: (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, ["type", "url"]),
984
+ license: (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, ["type", "url"]),
985
+ author: sortPersonValue,
986
+ maintainers: sortPeopleArrayValue,
987
+ contributors: sortPeopleArrayValue,
988
+ exports: sortExportsValue,
989
+ bin: sortJsonObjectValueAlphabetically,
990
+ directories: (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, DIRECTORY_FIELD_ORDER),
991
+ files: deduplicateStringArrayValue,
992
+ workspaces: sortWorkspacesValue,
993
+ binary: (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, [
994
+ "module_name",
995
+ "module_path",
996
+ "remote_path",
997
+ "package_name",
998
+ "host"
999
+ ]),
1000
+ scripts: sortScriptsValue,
1001
+ betterScripts: sortScriptsValue,
1002
+ wireit: sortWireitValue,
1003
+ contributes: sortJsonObjectValueAlphabetically,
1004
+ activationEvents: deduplicateStringArrayValue,
1005
+ husky: (fieldValue) => {
1006
+ if (!isJsonObject(fieldValue) || !isJsonObject(fieldValue.hooks)) {
1007
+ return fieldValue;
1008
+ }
1009
+ return {
1010
+ ...fieldValue,
1011
+ hooks: sortJsonObjectByKeyOrder(fieldValue.hooks, GIT_HOOK_ORDER)
1012
+ };
1013
+ },
1014
+ "simple-git-hooks": (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, GIT_HOOK_ORDER),
1015
+ commitlint: sortJsonObjectValueAlphabetically,
1016
+ config: sortJsonObjectValueAlphabetically,
1017
+ nodemonConfig: sortJsonObjectValueAlphabetically,
1018
+ browserify: sortJsonObjectValueAlphabetically,
1019
+ babel: sortJsonObjectValueAlphabetically,
1020
+ xo: sortJsonObjectValueAlphabetically,
1021
+ prettier: sortPrettierConfigValue,
1022
+ eslintConfig: sortEslintConfigValue,
1023
+ npmpkgjsonlint: sortJsonObjectValueAlphabetically,
1024
+ npmPackageJsonLintConfig: sortJsonObjectValueAlphabetically,
1025
+ npmpackagejsonlint: sortJsonObjectValueAlphabetically,
1026
+ release: sortJsonObjectValueAlphabetically,
1027
+ remarkConfig: sortJsonObjectValueAlphabetically,
1028
+ ava: sortJsonObjectValueAlphabetically,
1029
+ jest: sortJsonObjectValueAlphabetically,
1030
+ "jest-junit": sortJsonObjectValueAlphabetically,
1031
+ "jest-stare": sortJsonObjectValueAlphabetically,
1032
+ mocha: sortJsonObjectValueAlphabetically,
1033
+ nyc: sortJsonObjectValueAlphabetically,
1034
+ c8: sortJsonObjectValueAlphabetically,
1035
+ tap: sortJsonObjectValueAlphabetically,
1036
+ oclif: sortJsonObjectValueRecursively,
1037
+ resolutions: sortJsonObjectValueAlphabetically,
1038
+ overrides: sortDependencyValue,
1039
+ dependencies: sortDependencyValue,
1040
+ devDependencies: sortDependencyValue,
1041
+ dependenciesMeta: sortDependencyMetadataValue,
1042
+ peerDependencies: sortDependencyValue,
1043
+ peerDependenciesMeta: sortJsonObjectValueRecursively,
1044
+ optionalDependencies: sortDependencyValue,
1045
+ bundledDependencies: sortUniqueStringArrayValue,
1046
+ bundleDependencies: sortUniqueStringArrayValue,
1047
+ extensionPack: sortUniqueStringArrayValue,
1048
+ extensionDependencies: sortUniqueStringArrayValue,
1049
+ engines: sortJsonObjectValueAlphabetically,
1050
+ engineStrict: sortJsonObjectValueAlphabetically,
1051
+ devEngines: sortDevEnginesValue,
1052
+ volta: (fieldValue) => sortJsonObjectValueByKeyOrder(fieldValue, ["node", "npm", "yarn"]),
1053
+ preferGlobal: sortJsonObjectValueAlphabetically,
1054
+ publishConfig: sortJsonObjectValueAlphabetically,
1055
+ badges: (fieldValue) => {
1056
+ if (!Array.isArray(fieldValue)) {
1057
+ return fieldValue;
1058
+ }
1059
+ return fieldValue.map((badge) => sortJsonObjectValueByKeyOrder(badge, ["description", "url", "href"]));
1060
+ },
1061
+ galleryBanner: sortJsonObjectValueAlphabetically,
1062
+ pnpm: sortPnpmConfigValue
1063
+ };
1064
+ function sortPackageJsonObject(packageJson) {
1065
+ const sortedPackageJsonFields = sortPackageJsonFields(packageJson);
1066
+ return Object.fromEntries(Object.entries(sortedPackageJsonFields).map(([fieldName, fieldValue]) => {
1067
+ const fieldSorter = Object.hasOwn(PACKAGE_JSON_FIELD_SORTERS, fieldName) ? PACKAGE_JSON_FIELD_SORTERS[fieldName] : undefined;
1068
+ return [
1069
+ fieldName,
1070
+ fieldSorter ? fieldSorter(fieldValue, packageJson) : fieldValue
1071
+ ];
1072
+ }));
1073
+ }
1074
+ function isPackageJsonFile(filePath) {
1075
+ return filePath?.split(/[\\/]/).at(-1) === "package.json";
1076
+ }
1077
+ async function preprocessPackageJson(sourceText, prettierOptions, parser) {
1078
+ if (!isPackageJsonFile(prettierOptions.filepath) || !resolveSortOptions(prettierOptions).packageSort) {
1079
+ return sourceText;
1080
+ }
1081
+ try {
1082
+ const parsedPackageJson = JSON.parse(sourceText);
1083
+ if (!isJsonObject(parsedPackageJson)) {
1084
+ return sourceText;
1085
+ }
1086
+ const parserJsonAst = await parser.parse(sourceText, prettierOptions);
1087
+ if (!isParserJsonAstNode(parserJsonAst)) {
1088
+ return sourceText;
1089
+ }
1090
+ const fieldNameSourceTexts = new Map;
1091
+ const packageJsonWithSourceLiterals = preserveJsonSourceLiterals(parsedPackageJson, parserJsonAst, sourceText, fieldNameSourceTexts);
1092
+ if (!isJsonObject(packageJsonWithSourceLiterals)) {
1093
+ return sourceText;
1094
+ }
1095
+ return serializeJsonValue(sortPackageJsonObject(packageJsonWithSourceLiterals), fieldNameSourceTexts) ?? sourceText;
1096
+ } catch {
1097
+ return sourceText;
1098
+ }
1099
+ }
1100
+
1101
+ // src/sort-exports.ts
1102
+ function buildExportSortingEdits(sourceText, programStatements, sortedComments) {
1103
+ const sortingEdits = [];
1104
+ for (const exportDeclarationNode of programStatements) {
1105
+ if (exportDeclarationNode.type !== "ExportNamedDeclaration" || exportDeclarationNode.declaration) {
1106
+ continue;
1107
+ }
1108
+ const declarationRange = getAstNodeTextRange(exportDeclarationNode);
1109
+ const specifierNodes = exportDeclarationNode.specifiers;
1110
+ if (!declarationRange || !specifierNodes || specifierNodes.length <= 1 || isPrettierIgnored(sourceText, declarationRange, sortedComments) || specifierNodes.some((specifierNode) => specifierNode.type !== "ExportSpecifier")) {
1111
+ continue;
1112
+ }
1113
+ const firstSpecifierRange = getAstNodeTextRange(specifierNodes[0]);
1114
+ const lastSpecifierRange = getAstNodeTextRange(specifierNodes.at(-1));
1115
+ if (!firstSpecifierRange || !lastSpecifierRange) {
1116
+ continue;
1117
+ }
1118
+ const openingBraceIndex = sourceText.lastIndexOf("{", firstSpecifierRange.start);
1119
+ const closingBraceIndex = sourceText.indexOf("}", lastSpecifierRange.end);
1120
+ if (openingBraceIndex < declarationRange.start || closingBraceIndex < lastSpecifierRange.end || closingBraceIndex >= declarationRange.end) {
1121
+ continue;
1122
+ }
1123
+ const firstInternalCommentIndex = findCommentIndexAtOrAfter(sortedComments, openingBraceIndex + 1);
1124
+ const firstInternalComment = sortedComments[firstInternalCommentIndex];
1125
+ const isInternalCommentPresent = firstInternalComment !== undefined && firstInternalComment.textRange.start < closingBraceIndex;
1126
+ if (isInternalCommentPresent) {
1127
+ continue;
1128
+ }
1129
+ let isEverySpecifierValid = true;
1130
+ const sortableSpecifiers = [];
1131
+ for (const [originalIndex, specifierNode] of specifierNodes.entries()) {
1132
+ const specifierRange = getAstNodeTextRange(specifierNode);
1133
+ const exportedName = getAstNodeName(specifierNode.exported);
1134
+ const localName = getAstNodeName(specifierNode.local);
1135
+ const sortName = exportedName ?? localName;
1136
+ if (!specifierRange || !sortName) {
1137
+ isEverySpecifierValid = false;
1138
+ break;
1139
+ }
1140
+ sortableSpecifiers.push({
1141
+ originalIndex,
1142
+ sortName,
1143
+ specifierText: sourceText.slice(specifierRange.start, specifierRange.end)
1144
+ });
1145
+ }
1146
+ if (!isEverySpecifierValid) {
1147
+ continue;
1148
+ }
1149
+ const sortedSpecifiers = [...sortableSpecifiers].sort((left, right) => left.sortName.localeCompare(right.sortName, "en", {
1150
+ sensitivity: "base"
1151
+ }) || left.originalIndex - right.originalIndex);
1152
+ const isSpecifierOrderUnchanged = sortedSpecifiers.every((specifier, sortedIndex) => specifier.originalIndex === sortedIndex);
1153
+ if (isSpecifierOrderUnchanged) {
1154
+ continue;
1155
+ }
1156
+ sortingEdits.push({
1157
+ start: openingBraceIndex,
1158
+ end: closingBraceIndex + 1,
1159
+ replacementText: `{ ${sortedSpecifiers.map((specifier) => specifier.specifierText).join(", ")} }`
1160
+ });
1161
+ }
1162
+ return sortingEdits;
1163
+ }
1164
+
1165
+ // src/utils/source-text.ts
1166
+ function applySourceTextEdits(sourceText, sourceTextEdits) {
1167
+ if (sourceTextEdits.length === 0) {
1168
+ return sourceText;
1169
+ }
1170
+ let previousEditEnd = 0;
1171
+ const ascendingEdits = [...sourceTextEdits].sort((left, right) => left.start - right.start || left.end - right.end);
1172
+ for (const sourceTextEdit of ascendingEdits) {
1173
+ const { start, end } = sourceTextEdit;
1174
+ const isSourceTextEditValid = [start, end].every(Number.isSafeInteger) && start >= previousEditEnd && end >= start && end <= sourceText.length;
1175
+ if (!isSourceTextEditValid) {
1176
+ return null;
1177
+ }
1178
+ previousEditEnd = end;
1179
+ }
1180
+ let editedText = sourceText;
1181
+ for (const sourceTextEdit of ascendingEdits.reverse()) {
1182
+ editedText = editedText.slice(0, sourceTextEdit.start) + sourceTextEdit.replacementText + editedText.slice(sourceTextEdit.end);
1183
+ }
1184
+ return editedText;
1185
+ }
1186
+
1187
+ // src/sort-imports.ts
1188
+ var INDEX_MODULE_PATTERN = /^\.\/index(?:\.[^/]+)*$/;
1189
+ var PRETTIER_FILE_PRAGMA_DIRECTIVES = ["@format", "@prettier"];
1190
+ var ESLINT_RANGE_DIRECTIVES = ["eslint-disable", "eslint-enable"];
1191
+ var ESLINT_GLOBAL_DIRECTIVES = ["global", "globals"];
1192
+ function getCommentDirectiveArguments(commentLine, directive) {
1193
+ if (!commentLine.startsWith(directive)) {
1194
+ return null;
1195
+ }
1196
+ const directiveArguments = commentLine.slice(directive.length);
1197
+ if (directiveArguments === "") {
1198
+ return "";
1199
+ }
1200
+ if (directiveArguments[0]?.trim() !== "") {
1201
+ return null;
1202
+ }
1203
+ return directiveArguments.trimStart();
1204
+ }
1205
+ function hasCommentDirective(commentLine, directives) {
1206
+ return directives.some((directive) => getCommentDirectiveArguments(commentLine, directive) !== null);
1207
+ }
1208
+ function isEslintRuleConfiguration(commentLine) {
1209
+ const ruleConfiguration = getCommentDirectiveArguments(commentLine, "eslint");
1210
+ if (!ruleConfiguration) {
1211
+ return false;
1212
+ }
1213
+ const separatorIndex = ruleConfiguration.indexOf(":");
1214
+ if (separatorIndex < 1) {
1215
+ return false;
1216
+ }
1217
+ const ruleName = ruleConfiguration.slice(0, separatorIndex).trimEnd();
1218
+ return ruleName.length > 0 && [...ruleName].every((character) => character.trim() !== "");
1219
+ }
1220
+ function isFixedEslintComment(comment, isBlockComment) {
1221
+ if (!isBlockComment) {
1222
+ return false;
1223
+ }
1224
+ const commentText = getAstCommentText(comment)?.trim();
1225
+ if (!commentText) {
1226
+ return false;
1227
+ }
1228
+ return hasCommentDirective(commentText, ESLINT_RANGE_DIRECTIVES) || isEslintRuleConfiguration(commentText) || hasCommentDirective(commentText, ESLINT_GLOBAL_DIRECTIVES);
1229
+ }
1230
+ function isEslintNextLineComment(comment) {
1231
+ const commentText = getAstCommentText(comment)?.trim();
1232
+ if (!commentText) {
1233
+ return false;
1234
+ }
1235
+ return getCommentDirectiveArguments(commentText, "eslint-disable-next-line") !== null;
1236
+ }
1237
+ function isFixedEslintParserComment(sourceText, parserComment) {
1238
+ const { comment, textRange } = parserComment;
1239
+ const sourceCommentText = sourceText.slice(textRange.start, textRange.end);
1240
+ return isFixedEslintComment(comment, sourceCommentText.startsWith("/*"));
1241
+ }
1242
+ function isPositionSensitiveEslintComment(sourceText, parserComment) {
1243
+ return isEslintNextLineComment(parserComment.comment) || isFixedEslintParserComment(sourceText, parserComment);
1244
+ }
1245
+ function getCommentLines(comment) {
1246
+ const commentText = getAstCommentText(comment);
1247
+ if (commentText === null) {
1248
+ return [];
1249
+ }
1250
+ return commentText.split(/\r?\n/).map((commentLine) => commentLine.replace(/^\s*\*+\s*/, ""));
1251
+ }
1252
+ function isFixedFileComment(sourceText, comment, commentRange, prettierFilePragmaComment) {
1253
+ const sourceCommentText = sourceText.slice(commentRange.start, commentRange.end);
1254
+ if (sourceCommentText.startsWith("#!")) {
1255
+ return true;
1256
+ }
1257
+ if (comment === prettierFilePragmaComment) {
1258
+ return true;
1259
+ }
1260
+ const isBlockComment = sourceCommentText.startsWith("/*");
1261
+ return isFixedEslintComment(comment, isBlockComment);
1262
+ }
1263
+ function getPrettierFilePragmaComment(sortedComments, isPrettierFilePragmaPresent) {
1264
+ if (!isPrettierFilePragmaPresent) {
1265
+ return null;
1266
+ }
1267
+ return sortedComments.find(({ comment }) => getCommentLines(comment).some((commentLine) => hasCommentDirective(commentLine.trim(), PRETTIER_FILE_PRAGMA_DIRECTIVES)))?.comment ?? null;
1268
+ }
1269
+ function classifyImportGroup(moduleSpecifier) {
1270
+ if (moduleSpecifier === "bun" || moduleSpecifier.startsWith("bun:") || moduleSpecifier.startsWith("node:")) {
1271
+ return "builtin";
1272
+ }
1273
+ if (moduleSpecifier === "." || moduleSpecifier === "./" || INDEX_MODULE_PATTERN.test(moduleSpecifier)) {
1274
+ return "index";
1275
+ }
1276
+ if (moduleSpecifier === ".." || moduleSpecifier.startsWith("../")) {
1277
+ return "parent";
1278
+ }
1279
+ if (moduleSpecifier.startsWith("./")) {
1280
+ return "sibling";
1281
+ }
1282
+ if (moduleSpecifier.startsWith("/") || moduleSpecifier.startsWith("~") || moduleSpecifier.startsWith("@/") || moduleSpecifier.startsWith("#")) {
1283
+ return "internal";
1284
+ }
1285
+ return "external";
1286
+ }
1287
+ function findLeadingCommentsStart(sourceText, statementStart, sortedComments, prettierFilePragmaComment) {
1288
+ let attachedTextStart = statementStart;
1289
+ for (let commentIndex = findCommentIndexAtOrAfter(sortedComments, statementStart) - 1;commentIndex >= 0; commentIndex--) {
1290
+ const parserComment = sortedComments[commentIndex];
1291
+ if (!parserComment || parserComment.textRange.end > statementStart) {
1292
+ continue;
1293
+ }
1294
+ const { comment, textRange } = parserComment;
1295
+ if (isFixedFileComment(sourceText, comment, textRange, prettierFilePragmaComment)) {
1296
+ break;
1297
+ }
1298
+ const textBetweenCommentAndImport = sourceText.slice(textRange.end, attachedTextStart);
1299
+ const lineBreakCount = textBetweenCommentAndImport.match(/\n/g)?.length ?? 0;
1300
+ const isEslintNextLineCommentAttached = attachedTextStart === statementStart && isEslintNextLineComment(comment) && textBetweenCommentAndImport.trim() === "" && lineBreakCount === 1;
1301
+ if (isEslintNextLineCommentAttached) {
1302
+ attachedTextStart = textRange.start;
1303
+ continue;
1304
+ }
1305
+ const commentLineStart = sourceText.lastIndexOf(`
1306
+ `, textRange.start - 1) + 1;
1307
+ if (sourceText.slice(commentLineStart, textRange.start).trim() !== "") {
1308
+ break;
1309
+ }
1310
+ if (textBetweenCommentAndImport.trim() !== "" || lineBreakCount >= 2) {
1311
+ break;
1312
+ }
1313
+ attachedTextStart = textRange.start;
1314
+ }
1315
+ while (attachedTextStart > 0 && /[ \t]/.test(sourceText[attachedTextStart - 1])) {
1316
+ attachedTextStart--;
1317
+ }
1318
+ return attachedTextStart;
1319
+ }
1320
+ function getRangeEndIncludingLineBreak(sourceText, sourceIndex) {
1321
+ if (sourceText[sourceIndex] === "\r" && sourceText[sourceIndex + 1] === `
1322
+ `) {
1323
+ return sourceIndex + 2;
1324
+ }
1325
+ if (sourceText[sourceIndex] === `
1326
+ `) {
1327
+ return sourceIndex + 1;
1328
+ }
1329
+ return sourceIndex;
1330
+ }
1331
+ function getTrailingComments(sourceText, statementEnd, sortedComments) {
1332
+ let trailingCommentsEnd = statementEnd;
1333
+ let isImportSortingBoundary = false;
1334
+ const firstTrailingCommentIndex = findCommentIndexAtOrAfter(sortedComments, statementEnd);
1335
+ for (let commentIndex = firstTrailingCommentIndex;commentIndex < sortedComments.length; commentIndex++) {
1336
+ const trailingComment = sortedComments[commentIndex];
1337
+ if (!trailingComment) {
1338
+ break;
1339
+ }
1340
+ const { textRange } = trailingComment;
1341
+ const textBeforeComment = sourceText.slice(trailingCommentsEnd, textRange.start);
1342
+ if (textBeforeComment.includes(`
1343
+ `) || textBeforeComment.trim() !== "") {
1344
+ break;
1345
+ }
1346
+ const commentLineEnd = sourceText.indexOf(`
1347
+ `, textRange.end);
1348
+ if (!isSourceRangeWhitespaceOrComments(sourceText, {
1349
+ start: textRange.end,
1350
+ end: commentLineEnd < 0 ? sourceText.length : commentLineEnd
1351
+ }, sortedComments)) {
1352
+ break;
1353
+ }
1354
+ if (isFixedEslintParserComment(sourceText, trailingComment)) {
1355
+ isImportSortingBoundary = true;
1356
+ break;
1357
+ }
1358
+ if (isEslintNextLineComment(trailingComment.comment)) {
1359
+ break;
1360
+ }
1361
+ trailingCommentsEnd = textRange.end;
1362
+ }
1363
+ return {
1364
+ commentsText: sourceText.slice(statementEnd, trailingCommentsEnd),
1365
+ rangeEnd: trailingCommentsEnd,
1366
+ isImportSortingBoundary
1367
+ };
1368
+ }
1369
+ function parseImportAttributes(sourceText, importDeclarationNode) {
1370
+ const declarationRange = getAstNodeTextRange(importDeclarationNode);
1371
+ const moduleSpecifierRange = getAstNodeTextRange(importDeclarationNode.source);
1372
+ if (!declarationRange || !moduleSpecifierRange) {
1373
+ return { attributesText: null, isValid: false };
1374
+ }
1375
+ const importAttributesText = sourceText.slice(moduleSpecifierRange.end, declarationRange.end).replace(/;\s*$/, "").trim();
1376
+ if (importAttributesText === "") {
1377
+ return { attributesText: null, isValid: true };
1378
+ }
1379
+ return {
1380
+ attributesText: importAttributesText,
1381
+ isValid: /^(?:with|assert)\s*\{[\s\S]*\}$/.test(importAttributesText)
1382
+ };
1383
+ }
1384
+ function parseImportDeclaration(importDeclarationMetadata, sourceText) {
1385
+ const {
1386
+ importDeclarationNode,
1387
+ declarationRange,
1388
+ leadingCommentsText,
1389
+ trailingCommentsText,
1390
+ hasInternalComments
1391
+ } = importDeclarationMetadata;
1392
+ const moduleSpecifierNode = importDeclarationNode.source;
1393
+ const moduleSpecifierRange = getAstNodeTextRange(moduleSpecifierNode);
1394
+ const moduleSpecifier = getAstNodeName(moduleSpecifierNode);
1395
+ if (!moduleSpecifierRange || moduleSpecifier === null) {
1396
+ return null;
1397
+ }
1398
+ let importKind = "value";
1399
+ const declarationText = sourceText.slice(declarationRange.start, declarationRange.end);
1400
+ if (typeof importDeclarationNode.importKind === "string") {
1401
+ importKind = importDeclarationNode.importKind;
1402
+ }
1403
+ let specifierNodes = [];
1404
+ const isTypeOnly = importKind === "type";
1405
+ if (Array.isArray(importDeclarationNode.specifiers)) {
1406
+ specifierNodes = importDeclarationNode.specifiers;
1407
+ }
1408
+ let importPhase = null;
1409
+ const isSideEffectOnly = specifierNodes.length === 0 && importKind === "value";
1410
+ const parsedImportAttributes = parseImportAttributes(sourceText, importDeclarationNode);
1411
+ if (typeof importDeclarationNode.phase === "string") {
1412
+ importPhase = importDeclarationNode.phase;
1413
+ }
1414
+ let defaultBinding = null;
1415
+ let namespaceBinding = null;
1416
+ let isEverySpecifierSupported = true;
1417
+ const namedSpecifiers = [];
1418
+ for (const specifierNode of specifierNodes) {
1419
+ if (specifierNode.type === "ImportDefaultSpecifier") {
1420
+ defaultBinding = getAstNodeName(specifierNode.local);
1421
+ isEverySpecifierSupported &&= defaultBinding !== null;
1422
+ continue;
1423
+ }
1424
+ if (specifierNode.type === "ImportNamespaceSpecifier") {
1425
+ namespaceBinding = getAstNodeName(specifierNode.local);
1426
+ isEverySpecifierSupported &&= namespaceBinding !== null;
1427
+ continue;
1428
+ }
1429
+ if (specifierNode.type !== "ImportSpecifier") {
1430
+ isEverySpecifierSupported = false;
1431
+ continue;
1432
+ }
1433
+ let specifierKind = "value";
1434
+ const importedNode = specifierNode.imported;
1435
+ const importedNameRange = getAstNodeTextRange(importedNode);
1436
+ const importedName = getAstNodeName(importedNode);
1437
+ const localName = getAstNodeName(specifierNode.local);
1438
+ if (typeof specifierNode.importKind === "string") {
1439
+ specifierKind = specifierNode.importKind;
1440
+ }
1441
+ if (!importedNameRange || importedName === null || localName === null || specifierKind !== "value" && specifierKind !== "type") {
1442
+ isEverySpecifierSupported = false;
1443
+ continue;
1444
+ }
1445
+ namedSpecifiers.push({
1446
+ importedName,
1447
+ importedNameText: sourceText.slice(importedNameRange.start, importedNameRange.end),
1448
+ localName,
1449
+ isTypeOnly: specifierKind === "type"
1450
+ });
1451
+ }
1452
+ let parsedNamedSpecifiers = null;
1453
+ const isTypeClauseRewriteUnsupported = isTypeOnly && (defaultBinding !== null || namespaceBinding !== null);
1454
+ const isVerbatimRenderingRequired = specifierNodes.length === 0 || hasInternalComments || importPhase !== null || importKind !== "value" && importKind !== "type" || !isEverySpecifierSupported || !parsedImportAttributes.isValid || isTypeClauseRewriteUnsupported || isTypeOnly && parsedImportAttributes.attributesText !== null;
1455
+ if (namedSpecifiers.length > 0) {
1456
+ parsedNamedSpecifiers = namedSpecifiers;
1457
+ }
1458
+ let verbatimDeclaration = null;
1459
+ if (isVerbatimRenderingRequired) {
1460
+ verbatimDeclaration = declarationText;
1461
+ }
1462
+ return {
1463
+ moduleSpecifier,
1464
+ moduleSpecifierText: sourceText.slice(moduleSpecifierRange.start, moduleSpecifierRange.end),
1465
+ isTypeOnly,
1466
+ isSideEffectOnly,
1467
+ defaultBinding,
1468
+ namespaceBinding,
1469
+ namedSpecifiers: parsedNamedSpecifiers,
1470
+ importAttributes: parsedImportAttributes.attributesText,
1471
+ verbatimDeclaration,
1472
+ leadingCommentsText,
1473
+ trailingCommentsText,
1474
+ isMergeBoundary: leadingCommentsText.trim() !== "" || trailingCommentsText !== "" || hasInternalComments
1475
+ };
1476
+ }
1477
+ function renderNamedImportSpecifiers(namedSpecifiers) {
1478
+ return namedSpecifiers.map((importSpecifier) => {
1479
+ let renderedSpecifier = importSpecifier.importedNameText;
1480
+ const isAliasRequired = importSpecifier.importedNameText !== importSpecifier.importedName || importSpecifier.importedName !== importSpecifier.localName;
1481
+ if (isAliasRequired) {
1482
+ renderedSpecifier = `${importSpecifier.importedNameText} as ${importSpecifier.localName}`;
1483
+ }
1484
+ if (importSpecifier.isTypeOnly) {
1485
+ return `type ${renderedSpecifier}`;
1486
+ }
1487
+ return renderedSpecifier;
1488
+ }).join(", ");
1489
+ }
1490
+ function renderImportBindings(importDeclaration) {
1491
+ const renderedBindings = [];
1492
+ if (importDeclaration.defaultBinding) {
1493
+ renderedBindings.push(importDeclaration.defaultBinding);
1494
+ }
1495
+ if (importDeclaration.namespaceBinding) {
1496
+ renderedBindings.push(`* as ${importDeclaration.namespaceBinding}`);
1497
+ }
1498
+ if (importDeclaration.namedSpecifiers) {
1499
+ renderedBindings.push(`{ ${renderNamedImportSpecifiers(importDeclaration.namedSpecifiers)} }`);
1500
+ }
1501
+ return renderedBindings.join(", ");
1502
+ }
1503
+ function renderImportDeclaration(importDeclaration) {
1504
+ if (importDeclaration.verbatimDeclaration !== null) {
1505
+ return importDeclaration.leadingCommentsText + importDeclaration.verbatimDeclaration + importDeclaration.trailingCommentsText;
1506
+ }
1507
+ let attributesSuffix = "";
1508
+ if (importDeclaration.importAttributes) {
1509
+ attributesSuffix = ` ${importDeclaration.importAttributes}`;
1510
+ }
1511
+ let declarationText = `import ${renderImportBindings(importDeclaration)} from ${importDeclaration.moduleSpecifierText}${attributesSuffix};`;
1512
+ if (importDeclaration.isTypeOnly) {
1513
+ declarationText = `import type ${renderImportBindings(importDeclaration)} from ${importDeclaration.moduleSpecifierText}${attributesSuffix};`;
1514
+ }
1515
+ return importDeclaration.leadingCommentsText + declarationText + importDeclaration.trailingCommentsText;
1516
+ }
1517
+ function sortNamedImportSpecifiers(namedSpecifiers) {
1518
+ return [...namedSpecifiers].sort((left, right) => left.localName.localeCompare(right.localName, "en", {
1519
+ sensitivity: "base"
1520
+ }));
1521
+ }
1522
+ function getLocalBindingNames(importDeclaration) {
1523
+ const localBindingNames = [];
1524
+ if (importDeclaration.defaultBinding) {
1525
+ localBindingNames.push(importDeclaration.defaultBinding);
1526
+ }
1527
+ if (importDeclaration.namespaceBinding) {
1528
+ localBindingNames.push(importDeclaration.namespaceBinding);
1529
+ }
1530
+ if (importDeclaration.namedSpecifiers) {
1531
+ localBindingNames.push(...importDeclaration.namedSpecifiers.map((importSpecifier) => importSpecifier.localName));
1532
+ }
1533
+ return localBindingNames;
1534
+ }
1535
+ function normalizeNamedTypeOnlyImport(importDeclaration) {
1536
+ if (!importDeclaration.isTypeOnly || !importDeclaration.namedSpecifiers || importDeclaration.defaultBinding || importDeclaration.namespaceBinding || importDeclaration.verbatimDeclaration !== null) {
1537
+ return importDeclaration;
1538
+ }
1539
+ return {
1540
+ ...importDeclaration,
1541
+ isTypeOnly: false,
1542
+ namedSpecifiers: importDeclaration.namedSpecifiers.map((importSpecifier) => ({
1543
+ ...importSpecifier,
1544
+ isTypeOnly: true
1545
+ }))
1546
+ };
1547
+ }
1548
+ function getImportRequestKey(importDeclaration) {
1549
+ return `${importDeclaration.moduleSpecifier}\x00${importDeclaration.importAttributes ?? ""}`;
1550
+ }
1551
+ function isImportDeclarationMergeSafe(targetImportDeclaration, candidateImportDeclaration, bindingCounts) {
1552
+ if (targetImportDeclaration.verbatimDeclaration !== null || candidateImportDeclaration.verbatimDeclaration !== null || targetImportDeclaration.isSideEffectOnly || candidateImportDeclaration.isSideEffectOnly || targetImportDeclaration.moduleSpecifier !== candidateImportDeclaration.moduleSpecifier || targetImportDeclaration.importAttributes !== candidateImportDeclaration.importAttributes || targetImportDeclaration.isMergeBoundary || candidateImportDeclaration.isMergeBoundary) {
1553
+ return false;
1554
+ }
1555
+ if (bindingCounts.defaultBindingCount > 1 && (targetImportDeclaration.defaultBinding !== null || candidateImportDeclaration.defaultBinding !== null) || bindingCounts.namespaceBindingCount > 1 && (targetImportDeclaration.namespaceBinding !== null || candidateImportDeclaration.namespaceBinding !== null) || targetImportDeclaration.defaultBinding !== null && candidateImportDeclaration.defaultBinding !== null || targetImportDeclaration.namespaceBinding !== null && candidateImportDeclaration.namespaceBinding !== null) {
1556
+ return false;
1557
+ }
1558
+ const isAnyNamedSpecifierPresent = (targetImportDeclaration.namedSpecifiers?.length ?? 0) > 0 || (candidateImportDeclaration.namedSpecifiers?.length ?? 0) > 0;
1559
+ if (isAnyNamedSpecifierPresent && (targetImportDeclaration.namespaceBinding !== null || candidateImportDeclaration.namespaceBinding !== null)) {
1560
+ return false;
1561
+ }
1562
+ const usedLocalNames = new Set(getLocalBindingNames(targetImportDeclaration));
1563
+ return getLocalBindingNames(candidateImportDeclaration).every((localName) => !usedLocalNames.has(localName));
1564
+ }
1565
+ function mergeImportDeclarations(targetImportDeclaration, candidateImportDeclaration) {
1566
+ let namedSpecifiers = null;
1567
+ const mergedNamedSpecifiers = [
1568
+ ...targetImportDeclaration.namedSpecifiers ?? [],
1569
+ ...candidateImportDeclaration.namedSpecifiers ?? []
1570
+ ];
1571
+ if (mergedNamedSpecifiers.length > 0) {
1572
+ namedSpecifiers = mergedNamedSpecifiers;
1573
+ }
1574
+ return {
1575
+ moduleSpecifier: targetImportDeclaration.moduleSpecifier,
1576
+ moduleSpecifierText: targetImportDeclaration.moduleSpecifierText,
1577
+ isTypeOnly: false,
1578
+ isSideEffectOnly: false,
1579
+ defaultBinding: targetImportDeclaration.defaultBinding ?? candidateImportDeclaration.defaultBinding,
1580
+ namespaceBinding: targetImportDeclaration.namespaceBinding ?? candidateImportDeclaration.namespaceBinding,
1581
+ namedSpecifiers,
1582
+ importAttributes: targetImportDeclaration.importAttributes,
1583
+ verbatimDeclaration: null,
1584
+ leadingCommentsText: targetImportDeclaration.leadingCommentsText,
1585
+ trailingCommentsText: "",
1586
+ isMergeBoundary: false
1587
+ };
1588
+ }
1589
+ function mergeCompatibleImports(importDeclarations) {
1590
+ const bindingCountsByImportDeclaration = new Map;
1591
+ const currentBindingCountsByRequest = new Map;
1592
+ const minimumMergeTargetIndexByRequest = new Map;
1593
+ for (const importDeclaration of importDeclarations) {
1594
+ const importRequestKey = getImportRequestKey(importDeclaration);
1595
+ if (importDeclaration.isMergeBoundary) {
1596
+ currentBindingCountsByRequest.delete(importRequestKey);
1597
+ continue;
1598
+ }
1599
+ if (importDeclaration.verbatimDeclaration !== null || importDeclaration.isSideEffectOnly) {
1600
+ continue;
1601
+ }
1602
+ const bindingCounts = currentBindingCountsByRequest.get(importRequestKey) ?? {
1603
+ defaultBindingCount: 0,
1604
+ namespaceBindingCount: 0
1605
+ };
1606
+ if (importDeclaration.defaultBinding !== null) {
1607
+ bindingCounts.defaultBindingCount++;
1608
+ }
1609
+ if (importDeclaration.namespaceBinding !== null) {
1610
+ bindingCounts.namespaceBindingCount++;
1611
+ }
1612
+ currentBindingCountsByRequest.set(importRequestKey, bindingCounts);
1613
+ bindingCountsByImportDeclaration.set(importDeclaration, bindingCounts);
1614
+ }
1615
+ const mergedImportDeclarations = [];
1616
+ for (const originalImportDeclaration of importDeclarations) {
1617
+ const importDeclaration = normalizeNamedTypeOnlyImport(originalImportDeclaration);
1618
+ const importRequestKey = getImportRequestKey(importDeclaration);
1619
+ const bindingCounts = bindingCountsByImportDeclaration.get(originalImportDeclaration) ?? {
1620
+ defaultBindingCount: 0,
1621
+ namespaceBindingCount: 0
1622
+ };
1623
+ const minimumMergeTargetIndex = minimumMergeTargetIndexByRequest.get(importRequestKey) ?? 0;
1624
+ const mergeTargetIndex = mergedImportDeclarations.findIndex((existingImportDeclaration, existingImportIndex) => existingImportIndex >= minimumMergeTargetIndex && isImportDeclarationMergeSafe(existingImportDeclaration, importDeclaration, bindingCounts));
1625
+ if (mergeTargetIndex < 0) {
1626
+ mergedImportDeclarations.push(importDeclaration);
1627
+ } else {
1628
+ mergedImportDeclarations[mergeTargetIndex] = mergeImportDeclarations(mergedImportDeclarations[mergeTargetIndex], importDeclaration);
1629
+ }
1630
+ if (importDeclaration.isMergeBoundary) {
1631
+ minimumMergeTargetIndexByRequest.set(importRequestKey, mergedImportDeclarations.length);
1632
+ }
1633
+ }
1634
+ return mergedImportDeclarations;
1635
+ }
1636
+ function applyTypeImportStyle(importDeclaration, typeImportStyle) {
1637
+ if (importDeclaration.verbatimDeclaration !== null || !importDeclaration.namedSpecifiers) {
1638
+ return [importDeclaration];
1639
+ }
1640
+ const namedSpecifiers = importDeclaration.namedSpecifiers;
1641
+ if (typeImportStyle === "separate") {
1642
+ if (importDeclaration.isTypeOnly) {
1643
+ return [
1644
+ {
1645
+ ...importDeclaration,
1646
+ namedSpecifiers: sortNamedImportSpecifiers(namedSpecifiers)
1647
+ }
1648
+ ];
1649
+ }
1650
+ const typeSpecifiers2 = namedSpecifiers.filter((importSpecifier) => importSpecifier.isTypeOnly);
1651
+ const valueSpecifiers2 = namedSpecifiers.filter((importSpecifier) => !importSpecifier.isTypeOnly);
1652
+ if (typeSpecifiers2.length > 0 && (importDeclaration.importAttributes !== null || importDeclaration.leadingCommentsText.trim() !== "" || importDeclaration.trailingCommentsText !== "")) {
1653
+ return [
1654
+ {
1655
+ ...importDeclaration,
1656
+ namedSpecifiers: sortNamedImportSpecifiers(namedSpecifiers)
1657
+ }
1658
+ ];
1659
+ }
1660
+ const styledImportDeclarations = [];
1661
+ if (typeSpecifiers2.length > 0) {
1662
+ styledImportDeclarations.push({
1663
+ ...importDeclaration,
1664
+ isTypeOnly: true,
1665
+ defaultBinding: null,
1666
+ namespaceBinding: null,
1667
+ namedSpecifiers: sortNamedImportSpecifiers(typeSpecifiers2.map((importSpecifier) => ({
1668
+ ...importSpecifier,
1669
+ isTypeOnly: false
1670
+ })))
1671
+ });
1672
+ }
1673
+ if (valueSpecifiers2.length > 0 || importDeclaration.defaultBinding !== null || importDeclaration.namespaceBinding !== null) {
1674
+ let namedValueSpecifiers = null;
1675
+ if (valueSpecifiers2.length > 0) {
1676
+ namedValueSpecifiers = sortNamedImportSpecifiers(valueSpecifiers2);
1677
+ }
1678
+ let leadingCommentsText = importDeclaration.leadingCommentsText;
1679
+ if (typeSpecifiers2.length > 0) {
1680
+ leadingCommentsText = "";
1681
+ }
1682
+ styledImportDeclarations.push({
1683
+ ...importDeclaration,
1684
+ namedSpecifiers: namedValueSpecifiers,
1685
+ leadingCommentsText
1686
+ });
1687
+ }
1688
+ return styledImportDeclarations;
1689
+ }
1690
+ let inlineImportDeclaration = { ...importDeclaration, namedSpecifiers };
1691
+ if (importDeclaration.isTypeOnly) {
1692
+ inlineImportDeclaration = {
1693
+ ...importDeclaration,
1694
+ isTypeOnly: false,
1695
+ namedSpecifiers: namedSpecifiers.map((importSpecifier) => ({
1696
+ ...importSpecifier,
1697
+ isTypeOnly: true
1698
+ }))
1699
+ };
1700
+ }
1701
+ if (typeImportStyle === "mixed") {
1702
+ return [
1703
+ {
1704
+ ...inlineImportDeclaration,
1705
+ namedSpecifiers: sortNamedImportSpecifiers(inlineImportDeclaration.namedSpecifiers)
1706
+ }
1707
+ ];
1708
+ }
1709
+ const typeSpecifiers = sortNamedImportSpecifiers(inlineImportDeclaration.namedSpecifiers.filter((importSpecifier) => importSpecifier.isTypeOnly));
1710
+ const valueSpecifiers = sortNamedImportSpecifiers(inlineImportDeclaration.namedSpecifiers.filter((importSpecifier) => !importSpecifier.isTypeOnly));
1711
+ let orderedSpecifiers = [...valueSpecifiers, ...typeSpecifiers];
1712
+ if (typeImportStyle === "inline-first") {
1713
+ orderedSpecifiers = [...typeSpecifiers, ...valueSpecifiers];
1714
+ }
1715
+ return [{ ...inlineImportDeclaration, namedSpecifiers: orderedSpecifiers }];
1716
+ }
1717
+ function getImportBindingShapeRank(importDeclaration) {
1718
+ if (importDeclaration.defaultBinding !== null) {
1719
+ return 0;
1720
+ }
1721
+ if (importDeclaration.namespaceBinding !== null) {
1722
+ return 1;
1723
+ }
1724
+ return 2;
1725
+ }
1726
+ function sortImportSegment(importDeclarations, sortOptions, importGroupOrder) {
1727
+ let mergedImportDeclarations = [...importDeclarations];
1728
+ if (sortOptions.esmImportMerge) {
1729
+ mergedImportDeclarations = mergeCompatibleImports(importDeclarations);
1730
+ }
1731
+ const styledImportDeclarations = mergedImportDeclarations.flatMap((importDeclaration) => applyTypeImportStyle(importDeclaration, sortOptions.esmImportTypeStyle));
1732
+ const unlistedGroupRank = sortOptions.esmImportGroups.length;
1733
+ const rankedImportDeclarations = styledImportDeclarations.map((importDeclaration, originalIndex) => ({
1734
+ importDeclaration,
1735
+ importGroup: classifyImportGroup(importDeclaration.moduleSpecifier),
1736
+ originalIndex
1737
+ }));
1738
+ rankedImportDeclarations.sort((left, right) => {
1739
+ const groupRankDifference = (importGroupOrder.get(left.importGroup) ?? unlistedGroupRank) - (importGroupOrder.get(right.importGroup) ?? unlistedGroupRank);
1740
+ if (groupRankDifference !== 0) {
1741
+ return groupRankDifference;
1742
+ }
1743
+ const moduleSpecifierDifference = left.importDeclaration.moduleSpecifier.localeCompare(right.importDeclaration.moduleSpecifier, "en", { sensitivity: "base" });
1744
+ if (moduleSpecifierDifference !== 0) {
1745
+ return moduleSpecifierDifference;
1746
+ }
1747
+ if (left.importDeclaration.isTypeOnly !== right.importDeclaration.isTypeOnly) {
1748
+ if (left.importDeclaration.isTypeOnly) {
1749
+ return -1;
1750
+ }
1751
+ return 1;
1752
+ }
1753
+ return getImportBindingShapeRank(left.importDeclaration) - getImportBindingShapeRank(right.importDeclaration) || left.originalIndex - right.originalIndex;
1754
+ });
1755
+ let previousImportGroup = null;
1756
+ const renderedImportLines = [];
1757
+ for (const { importDeclaration, importGroup } of rankedImportDeclarations) {
1758
+ if (sortOptions.esmImportSeparation && previousImportGroup !== null && importGroup !== previousImportGroup) {
1759
+ renderedImportLines.push("");
1760
+ }
1761
+ renderedImportLines.push(renderImportDeclaration(importDeclaration));
1762
+ previousImportGroup = importGroup;
1763
+ }
1764
+ return renderedImportLines;
1765
+ }
1766
+ function renderSortedImportLines(importDeclarations, sortOptions) {
1767
+ let currentSortableImportDeclarations = [];
1768
+ const importGroupOrder = new Map(sortOptions.esmImportGroups.map((importGroup, groupIndex) => [
1769
+ importGroup,
1770
+ groupIndex
1771
+ ]));
1772
+ const importDeclarationChunks = [];
1773
+ for (const importDeclaration of importDeclarations) {
1774
+ if (!importDeclaration.isSideEffectOnly) {
1775
+ currentSortableImportDeclarations.push(importDeclaration);
1776
+ continue;
1777
+ }
1778
+ if (currentSortableImportDeclarations.length > 0) {
1779
+ importDeclarationChunks.push({
1780
+ kind: "sortable",
1781
+ importDeclarations: currentSortableImportDeclarations
1782
+ });
1783
+ currentSortableImportDeclarations = [];
1784
+ }
1785
+ importDeclarationChunks.push({ kind: "side-effect", importDeclaration });
1786
+ }
1787
+ if (currentSortableImportDeclarations.length > 0) {
1788
+ importDeclarationChunks.push({
1789
+ kind: "sortable",
1790
+ importDeclarations: currentSortableImportDeclarations
1791
+ });
1792
+ }
1793
+ let previousChunkKind = null;
1794
+ const renderedImportLines = [];
1795
+ for (const importChunk of importDeclarationChunks) {
1796
+ if (sortOptions.esmImportSeparation && previousChunkKind !== null && previousChunkKind !== importChunk.kind) {
1797
+ renderedImportLines.push("");
1798
+ }
1799
+ if (importChunk.kind === "sortable") {
1800
+ renderedImportLines.push(...sortImportSegment(importChunk.importDeclarations, sortOptions, importGroupOrder));
1801
+ } else {
1802
+ renderedImportLines.push(renderImportDeclaration(importChunk.importDeclaration));
1803
+ }
1804
+ previousChunkKind = importChunk.kind;
1805
+ }
1806
+ return renderedImportLines;
1807
+ }
1808
+ function isCommentPresentWithinRange(sortedComments, start, end) {
1809
+ const firstCommentIndex = findCommentIndexAtOrAfter(sortedComments, start);
1810
+ const firstComment = sortedComments[firstCommentIndex];
1811
+ return firstComment !== undefined && firstComment.textRange.end <= end;
1812
+ }
1813
+ function hasPositionSensitiveEslintCommentWithinRange(sourceText, sortedComments, start, end) {
1814
+ for (let commentIndex = findCommentIndexAtOrAfter(sortedComments, start);commentIndex < sortedComments.length; commentIndex++) {
1815
+ const parserComment = sortedComments[commentIndex];
1816
+ if (!parserComment || parserComment.textRange.start >= end) {
1817
+ return false;
1818
+ }
1819
+ if (parserComment.textRange.end <= end && isPositionSensitiveEslintComment(sourceText, parserComment)) {
1820
+ return true;
1821
+ }
1822
+ }
1823
+ return false;
1824
+ }
1825
+ function buildImportSegmentEdits(sourceText, importEntries, sortOptions, lineEnding, isBlankLineRequired) {
1826
+ const [firstImportEntry] = importEntries;
1827
+ if (!firstImportEntry) {
1828
+ return null;
1829
+ }
1830
+ let trailingLineBreaks = lineEnding;
1831
+ const replacementText = renderSortedImportLines(importEntries.map((importEntry) => importEntry.parsedImportDeclaration), sortOptions).join(lineEnding);
1832
+ const removalEdits = importEntries.slice(1).map((importEntry) => ({
1833
+ start: importEntry.start,
1834
+ end: importEntry.end,
1835
+ replacementText: ""
1836
+ }));
1837
+ if (isBlankLineRequired) {
1838
+ const textWithoutLaterImports = applySourceTextEdits(sourceText, removalEdits);
1839
+ if (textWithoutLaterImports === null) {
1840
+ return null;
1841
+ }
1842
+ const isFollowingContentPresent = textWithoutLaterImports.slice(firstImportEntry.end).trim() !== "";
1843
+ if (isFollowingContentPresent) {
1844
+ trailingLineBreaks += lineEnding;
1845
+ }
1846
+ }
1847
+ return [
1848
+ {
1849
+ start: firstImportEntry.start,
1850
+ end: firstImportEntry.end,
1851
+ replacementText: replacementText + trailingLineBreaks
1852
+ },
1853
+ ...removalEdits
1854
+ ];
1855
+ }
1856
+ function buildImportSortingEdits(sourceText, programStatements, sortedComments, sortOptions, isPrettierFilePragmaPresent) {
1857
+ const importDeclarationNodes = programStatements.filter((statement) => statement.type === "ImportDeclaration");
1858
+ if (importDeclarationNodes.length === 0) {
1859
+ return [];
1860
+ }
1861
+ const prettierFilePragmaComment = getPrettierFilePragmaComment(sortedComments, isPrettierFilePragmaPresent);
1862
+ if (isPrettierFilePragmaPresent && !prettierFilePragmaComment) {
1863
+ return [];
1864
+ }
1865
+ let currentSortableSegment = [];
1866
+ const sortableSegments = [];
1867
+ for (const importDeclarationNode of importDeclarationNodes) {
1868
+ const declarationRange = getAstNodeTextRange(importDeclarationNode);
1869
+ if (!declarationRange) {
1870
+ return [];
1871
+ }
1872
+ if (hasPositionSensitiveEslintCommentWithinRange(sourceText, sortedComments, declarationRange.start, declarationRange.end)) {
1873
+ return [];
1874
+ }
1875
+ const isImportIgnoredByPrettier = isPrettierIgnored(sourceText, declarationRange, sortedComments);
1876
+ const leadingCommentsStart = findLeadingCommentsStart(sourceText, declarationRange.start, sortedComments, prettierFilePragmaComment);
1877
+ const trailingComments = getTrailingComments(sourceText, declarationRange.end, sortedComments);
1878
+ if (isImportIgnoredByPrettier || trailingComments.isImportSortingBoundary) {
1879
+ if (currentSortableSegment.length > 0) {
1880
+ sortableSegments.push(currentSortableSegment);
1881
+ currentSortableSegment = [];
1882
+ }
1883
+ continue;
1884
+ }
1885
+ const parsedImportDeclaration = parseImportDeclaration({
1886
+ importDeclarationNode,
1887
+ declarationRange,
1888
+ leadingCommentsText: sourceText.slice(leadingCommentsStart, declarationRange.start),
1889
+ trailingCommentsText: trailingComments.commentsText,
1890
+ hasInternalComments: isCommentPresentWithinRange(sortedComments, declarationRange.start, declarationRange.end)
1891
+ }, sourceText);
1892
+ if (parsedImportDeclaration === null) {
1893
+ return [];
1894
+ }
1895
+ const parsedImportEntry = {
1896
+ importDeclarationNode,
1897
+ start: leadingCommentsStart,
1898
+ end: getRangeEndIncludingLineBreak(sourceText, trailingComments.rangeEnd),
1899
+ parsedImportDeclaration
1900
+ };
1901
+ const previousImportEntry = currentSortableSegment.at(-1);
1902
+ if (previousImportEntry && isCommentPresentWithinRange(sortedComments, previousImportEntry.end, parsedImportEntry.start)) {
1903
+ sortableSegments.push(currentSortableSegment);
1904
+ currentSortableSegment = [];
1905
+ }
1906
+ currentSortableSegment.push(parsedImportEntry);
1907
+ }
1908
+ if (currentSortableSegment.length > 0) {
1909
+ sortableSegments.push(currentSortableSegment);
1910
+ }
1911
+ let lineEnding = `
1912
+ `;
1913
+ if (sourceText.includes(`\r
1914
+ `)) {
1915
+ lineEnding = `\r
1916
+ `;
1917
+ }
1918
+ const sortingEdits = [];
1919
+ const lastImportDeclarationNode = importDeclarationNodes.at(-1);
1920
+ for (const sortableSegment of sortableSegments) {
1921
+ const isLastImportSegment = sortableSegment.at(-1)?.importDeclarationNode === lastImportDeclarationNode;
1922
+ const importSegmentEdits = buildImportSegmentEdits(sourceText, sortableSegment, sortOptions, lineEnding, isLastImportSegment);
1923
+ if (importSegmentEdits === null) {
1924
+ return [];
1925
+ }
1926
+ sortingEdits.push(...importSegmentEdits);
1927
+ }
1928
+ return sortingEdits;
1929
+ }
1930
+
1931
+ // src/sort-typescript.ts
1932
+ async function sortTypeScript(sourceText, prettierOptions, parser) {
1933
+ const sortOptions = resolveSortOptions(prettierOptions);
1934
+ if (!sortOptions.esmImportSort && !sortOptions.esmExportSpecifierSort) {
1935
+ return sourceText;
1936
+ }
1937
+ let parserAst;
1938
+ try {
1939
+ parserAst = await parser.parse(sourceText, prettierOptions);
1940
+ } catch {
1941
+ return sourceText;
1942
+ }
1943
+ const programStatements = getProgramStatements(parserAst);
1944
+ const sortedComments = getSortedAstCommentsWithTextRanges(getProgramComments(parserAst));
1945
+ const sortingEdits = [];
1946
+ if (sortOptions.esmImportSort) {
1947
+ const isPrettierFilePragmaPresent = parser.hasPragma?.(sourceText) ?? false;
1948
+ sortingEdits.push(...buildImportSortingEdits(sourceText, programStatements, sortedComments, sortOptions, isPrettierFilePragmaPresent));
1949
+ }
1950
+ if (sortOptions.esmExportSpecifierSort) {
1951
+ sortingEdits.push(...buildExportSortingEdits(sourceText, programStatements, sortedComments));
1952
+ }
1953
+ const sortedText = applySourceTextEdits(sourceText, sortingEdits);
1954
+ if (sortedText === null || sortedText === sourceText) {
1955
+ return sourceText;
1956
+ }
1957
+ try {
1958
+ await parser.parse(sortedText, prettierOptions);
1959
+ return sortedText;
1960
+ } catch {
1961
+ return sourceText;
859
1962
  }
860
- return newline === `\r
861
- ` ? output.replace(/\n/g, `\r
862
- `) : output;
863
1963
  }
864
1964
 
865
1965
  // src/index.ts
866
- function wrap(parser, ...transforms) {
1966
+ function wrapParserPreprocess(parser, preprocessTransform) {
867
1967
  return {
868
1968
  ...parser,
869
- async preprocess(text, parserOptions) {
870
- let source = parser.preprocess ? await parser.preprocess(text, parserOptions) : text;
871
- for (const transform of transforms) {
872
- source = transform(source, parserOptions);
1969
+ async preprocess(sourceText, prettierOptions) {
1970
+ let transformedText = sourceText;
1971
+ if (parser.preprocess) {
1972
+ transformedText = await parser.preprocess(sourceText, prettierOptions);
873
1973
  }
874
- return source;
1974
+ return preprocessTransform(transformedText, prettierOptions, parser);
875
1975
  }
876
1976
  };
877
1977
  }
878
- var plugin = {
1978
+ var sortPlugin = {
879
1979
  options,
880
1980
  parsers: {
881
- babel: wrap(babelParsers.babel, sortImports, sortExports),
882
- "babel-ts": wrap(babelParsers["babel-ts"], sortImports, sortExports),
883
- typescript: wrap(typescriptParsers.typescript, sortImports, sortExports),
884
- "json-stringify": wrap(babelParsers["json-stringify"], sortPackageJson)
1981
+ acorn: wrapParserPreprocess(acornPlugin.parsers.acorn, sortTypeScript),
1982
+ babel: wrapParserPreprocess(babelPlugin.parsers.babel, sortTypeScript),
1983
+ "babel-flow": wrapParserPreprocess(babelPlugin.parsers["babel-flow"], sortTypeScript),
1984
+ "babel-ts": wrapParserPreprocess(babelPlugin.parsers["babel-ts"], sortTypeScript),
1985
+ espree: wrapParserPreprocess(acornPlugin.parsers.espree, sortTypeScript),
1986
+ flow: wrapParserPreprocess(flowPlugin.parsers.flow, sortTypeScript),
1987
+ json: wrapParserPreprocess(babelPlugin.parsers.json, preprocessPackageJson),
1988
+ "json-stringify": wrapParserPreprocess(babelPlugin.parsers["json-stringify"], preprocessPackageJson),
1989
+ meriyah: wrapParserPreprocess(meriyahPlugin.parsers.meriyah, sortTypeScript),
1990
+ typescript: wrapParserPreprocess(typescriptPlugin.parsers.typescript, sortTypeScript)
885
1991
  }
886
1992
  };
887
- var src_default = plugin;
1993
+ var src_default = sortPlugin;
888
1994
  export {
889
1995
  options,
890
1996
  src_default as default