prettier-plugin-sort 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -10
- package/README.zh.md +16 -10
- package/dist/cursor.d.ts +4 -0
- package/dist/index.js +329 -64
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ import App from './App';
|
|
|
30
30
|
|
|
31
31
|
## Install
|
|
32
32
|
|
|
33
|
-
Requires Prettier 3.9 or
|
|
33
|
+
Requires Prettier 3.x, version 3.9 or later.
|
|
34
34
|
|
|
35
35
|
```shell
|
|
36
36
|
npm i -D prettier prettier-plugin-sort
|
|
@@ -56,20 +56,20 @@ Dynamic `import()` calls and import-like text in strings or comments are left un
|
|
|
56
56
|
|
|
57
57
|
`esmImportGroups` accepts these values:
|
|
58
58
|
|
|
59
|
-
| Group | Matches
|
|
60
|
-
| ---------- |
|
|
61
|
-
| `builtin` | Modules beginning with `node:` or `bun:`, plus `bun`
|
|
62
|
-
| `external` | Packages and module paths not matched by any other group
|
|
63
|
-
| `internal` | Path aliases
|
|
64
|
-
| `parent` | Parent-relative paths such as `../utils`
|
|
65
|
-
| `sibling` | Sibling paths such as `./Button`
|
|
66
|
-
| `index` | `.`, `./`, `./index`, and `./index` with an optional extension
|
|
59
|
+
| Group | Matches |
|
|
60
|
+
| ---------- | ----------------------------------------------------------------------------------------------- |
|
|
61
|
+
| `builtin` | Modules beginning with `node:` or `bun:`, plus `bun` |
|
|
62
|
+
| `external` | Packages and module paths not matched by any other group |
|
|
63
|
+
| `internal` | Path aliases from `compilerOptions.paths` in the TypeScript project containing the current file |
|
|
64
|
+
| `parent` | Parent-relative paths such as `../utils` |
|
|
65
|
+
| `sibling` | Sibling paths such as `./Button` |
|
|
66
|
+
| `index` | `.`, `./`, `./index`, and `./index` with an optional extension |
|
|
67
67
|
|
|
68
68
|
Modern Node.js code should reference built-ins explicitly with [`node:` URLs](https://nodejs.org/api/esm.html#node-imports). The plugin also classifies only `node:`-prefixed modules as `builtin`. Module specifiers without the prefix, such as `fs` and `path`, belong to `external`.
|
|
69
69
|
|
|
70
70
|
The table also shows the default order. Duplicate entries are removed automatically, and omitted default groups are appended in their default order.
|
|
71
71
|
|
|
72
|
-
The plugin searches upward from the current file for the nearest `tsconfig.json` and
|
|
72
|
+
The plugin searches upward from the current file for the nearest `tsconfig.json`, then uses `files`, `include`, and `exclude` to select the TypeScript project containing the file, following `references` when necessary. Each project is resolved through `extends` before matching the file and reading `compilerOptions.paths`. Only `paths` from the selected project are used to classify `internal`; `paths` from other referenced projects are not merged. Non-relative paths not declared there remain `external`. The catch-all pattern `*` is ignored because it cannot distinguish project modules from third-party packages.
|
|
73
73
|
|
|
74
74
|
With `esmImportSeparation` set to `false`, blank lines are removed both between groups and around side-effect imports.
|
|
75
75
|
|
|
@@ -94,6 +94,8 @@ With `esmImportMerge` enabled, imports from the same module are merged when safe
|
|
|
94
94
|
|
|
95
95
|
Imports are not merged when their import attributes differ, comments cannot move safely, or default and namespace bindings conflict. Side-effect imports always remain separate.
|
|
96
96
|
|
|
97
|
+
An import with an attached comment keeps its position relative to surrounding declarations from the same module, preserving the merge boundary after sorting.
|
|
98
|
+
|
|
97
99
|
## Export sorting
|
|
98
100
|
|
|
99
101
|
`esmExportSpecifierSort` sorts top-level `export { ... }` and `export type { ... }` entries by name. Aliased entries use their exported names.
|
|
@@ -262,6 +264,10 @@ The plugin only handles ES module syntax. It does not modify CommonJS `require()
|
|
|
262
264
|
|
|
263
265
|
`tsconfig.json` sorting supports the `json` parser. The file must be named `tsconfig.json` or `tsconfig.*.json`.
|
|
264
266
|
|
|
267
|
+
Range formatting in JavaScript, TypeScript, Flow, or JSON files applies Prettier's layout rules and preserves the original order. For embedded code, the host parser determines the range. For example, Vue may expand a selection to the entire `<script>` block, which still participates in sorting.
|
|
268
|
+
|
|
269
|
+
With `formatWithCursor()`, the cursor follows the corresponding source content. If its position after sorting cannot be determined reliably, the plugin preserves the original order and continues with Prettier's formatting.
|
|
270
|
+
|
|
265
271
|
## TypeScript configuration
|
|
266
272
|
|
|
267
273
|
The plugin also exports the `SortOptions`, `ImportGroup`, and `TypeImportStyle` types for use in TypeScript configuration files:
|
package/README.zh.md
CHANGED
|
@@ -30,7 +30,7 @@ import App from './App';
|
|
|
30
30
|
|
|
31
31
|
## 安装
|
|
32
32
|
|
|
33
|
-
要求 Prettier 3.9
|
|
33
|
+
要求 Prettier 3.9 及以上的 3.x 版本。
|
|
34
34
|
|
|
35
35
|
```shell
|
|
36
36
|
npm i -D prettier prettier-plugin-sort
|
|
@@ -56,20 +56,20 @@ npm i -D prettier prettier-plugin-sort
|
|
|
56
56
|
|
|
57
57
|
`esmImportGroups` 支持以下分组:
|
|
58
58
|
|
|
59
|
-
| 分组 | 匹配范围
|
|
60
|
-
| ---------- |
|
|
61
|
-
| `builtin` | 以 `node:`、`bun:` 开头的模块,以及 `bun`
|
|
62
|
-
| `external` | 第三方包,以及没有匹配其他分组的模块路径
|
|
63
|
-
| `internal` |
|
|
64
|
-
| `parent` | `../utils` 这类指向上级目录的相对路径
|
|
65
|
-
| `sibling` | `./Button` 这类指向同级目录的相对路径
|
|
66
|
-
| `index` | `.`、`./`、`./index` 及带扩展名的 `./index`
|
|
59
|
+
| 分组 | 匹配范围 |
|
|
60
|
+
| ---------- | --------------------------------------------------------------------------- |
|
|
61
|
+
| `builtin` | 以 `node:`、`bun:` 开头的模块,以及 `bun` |
|
|
62
|
+
| `external` | 第三方包,以及没有匹配其他分组的模块路径 |
|
|
63
|
+
| `internal` | 当前文件所属 TypeScript project 的 `compilerOptions.paths` 中定义的路径别名 |
|
|
64
|
+
| `parent` | `../utils` 这类指向上级目录的相对路径 |
|
|
65
|
+
| `sibling` | `./Button` 这类指向同级目录的相对路径 |
|
|
66
|
+
| `index` | `.`、`./`、`./index` 及带扩展名的 `./index` |
|
|
67
67
|
|
|
68
68
|
现代 Node.js 代码应使用 [`node:` URL](https://nodejs.org/api/esm.html#node-imports) 显式引用内置模块。本插件也只把带 `node:` 前缀的内置模块归入 `builtin`。`fs`、`path` 等未带前缀的模块归入 `external`。
|
|
69
69
|
|
|
70
70
|
默认顺序就是表中的顺序。配置数组会自动去重,遗漏的默认分组则按默认顺序补到末尾。
|
|
71
71
|
|
|
72
|
-
插件会从当前文件所在目录向上查找最近的 `tsconfig.json
|
|
72
|
+
插件会从当前文件所在目录向上查找最近的 `tsconfig.json`,根据 `files`、`include` 和 `exclude` 选择包含当前文件的 TypeScript project,并在需要时沿 `references` 查找。每个 project 都会先解析 `extends`,再匹配文件并读取 `compilerOptions.paths`。识别 `internal` 时只使用当前文件所属 project 的 `paths`,不会合并其他 referenced project 的 `paths`。没有在该 `paths` 中声明的非相对路径仍归入 `external`。`*` 无法区分项目代码和第三方包,因此不会用于判断 `internal`。
|
|
73
73
|
|
|
74
74
|
将 `esmImportSeparation` 设为 `false` 后,分组之间和副作用 `import` 上下两侧都不再留空行。
|
|
75
75
|
|
|
@@ -94,6 +94,8 @@ npm i -D prettier prettier-plugin-sort
|
|
|
94
94
|
|
|
95
95
|
`import` 属性不同、注释无法安全移动,或默认导入与命名空间导入发生冲突时,都不会合并。副作用 `import` 始终保持独立。
|
|
96
96
|
|
|
97
|
+
带注释的 `import` 会保留与两侧同源声明的相对顺序,避免排序后改变合并边界。
|
|
98
|
+
|
|
97
99
|
## `export` 排序
|
|
98
100
|
|
|
99
101
|
`esmExportSpecifierSort` 按名称排列顶层 `export { ... }` 和 `export type { ... }`。使用 `as` 时,以导出后的名称为准。
|
|
@@ -262,6 +264,10 @@ Vue、Markdown 等文件中的 JavaScript 和 TypeScript 的**嵌入式代码**
|
|
|
262
264
|
|
|
263
265
|
`tsconfig.json` 排序支持 `json` 解析器,文件名必须是 `tsconfig.json` 或 `tsconfig.*.json`。
|
|
264
266
|
|
|
267
|
+
直接格式化 JavaScript、TypeScript、Flow 或 JSON 文件的局部选区时,插件只执行 Prettier 排版,保留内容原有顺序。嵌入式代码的范围由宿主解析器决定。例如 Vue 可能将选区扩展为整个 `<script>` 块,该代码块仍会参与排序。
|
|
268
|
+
|
|
269
|
+
使用 `formatWithCursor()` 时,光标会跟随对应的源码内容。无法明确定位排序后的光标位置时,插件保留原有顺序,继续执行 Prettier 排版。
|
|
270
|
+
|
|
265
271
|
## TypeScript 配置
|
|
266
272
|
|
|
267
273
|
插件还导出 `SortOptions`、`ImportGroup` 和 `TypeImportStyle` 类型,可直接用于 TypeScript 配置文件:
|
package/dist/cursor.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ParserOptions } from 'prettier';
|
|
2
|
+
import { type ParserAstNode } from '#/parser-ast';
|
|
3
|
+
/** 在 Prettier 根据新 AST 定位光标之前,先跟随源码未变的唯一节点移动。 */
|
|
4
|
+
export declare function updateCursorOffset(sourceText: string, sortedText: string, originalAst: ParserAstNode, sortedAst: ParserAstNode, prettierOptions: ParserOptions): boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined")
|
|
5
|
-
return require.apply(this, arguments);
|
|
6
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
-
});
|
|
8
|
-
|
|
9
1
|
// src/index.ts
|
|
10
2
|
import acornPlugin from "prettier/plugins/acorn";
|
|
11
3
|
import babelPlugin from "prettier/plugins/babel";
|
|
@@ -32,14 +24,7 @@ var DEFAULT_SORT_OPTIONS = {
|
|
|
32
24
|
tsconfigSort: true,
|
|
33
25
|
tsconfigSeparation: true
|
|
34
26
|
};
|
|
35
|
-
var VALID_IMPORT_GROUPS = new Set(
|
|
36
|
-
"builtin",
|
|
37
|
-
"external",
|
|
38
|
-
"internal",
|
|
39
|
-
"parent",
|
|
40
|
-
"sibling",
|
|
41
|
-
"index"
|
|
42
|
-
]);
|
|
27
|
+
var VALID_IMPORT_GROUPS = new Set(DEFAULT_SORT_OPTIONS.esmImportGroups);
|
|
43
28
|
var VALID_TYPE_IMPORT_STYLES = new Set([
|
|
44
29
|
"separate",
|
|
45
30
|
"inline-first",
|
|
@@ -58,7 +43,10 @@ function resolveBooleanSortOption(prettierOptions, optionName) {
|
|
|
58
43
|
function resolveEsmOptions(prettierOptions) {
|
|
59
44
|
const configuredImportGroups = Array.isArray(prettierOptions.esmImportGroups) ? [...new Set(prettierOptions.esmImportGroups.filter(isValidImportGroup))] : [];
|
|
60
45
|
const remainingDefaultImportGroups = DEFAULT_SORT_OPTIONS.esmImportGroups.filter((importGroup) => !configuredImportGroups.includes(importGroup));
|
|
61
|
-
const resolvedImportGroups =
|
|
46
|
+
const resolvedImportGroups = [
|
|
47
|
+
...configuredImportGroups,
|
|
48
|
+
...remainingDefaultImportGroups
|
|
49
|
+
];
|
|
62
50
|
const resolvedTypeImportStyle = isValidTypeImportStyle(prettierOptions.esmImportTypeStyle) ? prettierOptions.esmImportTypeStyle : DEFAULT_SORT_OPTIONS.esmImportTypeStyle;
|
|
63
51
|
return {
|
|
64
52
|
esmImportSort: resolveBooleanSortOption(prettierOptions, "esmImportSort"),
|
|
@@ -306,6 +294,123 @@ function isPrettierIgnored(sourceText, statementRange, sortedComments) {
|
|
|
306
294
|
return false;
|
|
307
295
|
}
|
|
308
296
|
|
|
297
|
+
// src/cursor.ts
|
|
298
|
+
function collectCursorAnchors(parserAst, sourceText) {
|
|
299
|
+
const anchors = [];
|
|
300
|
+
function addAnchor(path, node) {
|
|
301
|
+
const range = getAstNodeTextRange(node);
|
|
302
|
+
if (!range || range.end > sourceText.length) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
anchors.push({
|
|
306
|
+
...range,
|
|
307
|
+
key: JSON.stringify([...path, node?.type ?? "comment"])
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function collectJsonAnchors(node, path) {
|
|
311
|
+
addAnchor(path, node);
|
|
312
|
+
if (node.type === "ObjectExpression") {
|
|
313
|
+
for (const property of node.properties ?? []) {
|
|
314
|
+
const name = getAstNodeName(property.key);
|
|
315
|
+
if (name === null || !isParserAstNode(property.value)) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
const propertyPath = [...path, "property", name];
|
|
319
|
+
addAnchor(propertyPath, property);
|
|
320
|
+
addAnchor([...propertyPath, "key"], property.key);
|
|
321
|
+
collectJsonAnchors(property.value, [...propertyPath, "value"]);
|
|
322
|
+
}
|
|
323
|
+
} else if (node.type === "ArrayExpression") {
|
|
324
|
+
for (const [index, element] of (node.elements ?? []).entries()) {
|
|
325
|
+
if (!element) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const elementPath = typeof element.value === "string" ? [...path, "string", element.value] : [...path, "index", index];
|
|
329
|
+
collectJsonAnchors(element, elementPath);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
const jsonRoot = parserAst.type === "JsonRoot" ? parserAst.node : undefined;
|
|
334
|
+
if (jsonRoot) {
|
|
335
|
+
collectJsonAnchors(jsonRoot, ["json"]);
|
|
336
|
+
} else {
|
|
337
|
+
let statementIndex = 0;
|
|
338
|
+
for (const statement of getProgramStatements(parserAst)) {
|
|
339
|
+
if (statement.type === "ImportDeclaration") {
|
|
340
|
+
const sourceName = getAstNodeName(statement.source);
|
|
341
|
+
if (sourceName === null) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
const importPath = [
|
|
345
|
+
"import",
|
|
346
|
+
sourceName,
|
|
347
|
+
typeof statement.phase === "string" ? statement.phase : ""
|
|
348
|
+
];
|
|
349
|
+
addAnchor([...importPath, "declaration"], statement);
|
|
350
|
+
addAnchor([...importPath, "source"], statement.source);
|
|
351
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
352
|
+
const localName = getAstNodeName(specifier.local);
|
|
353
|
+
if (localName === null) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
const specifierPath = [...importPath, "binding", localName];
|
|
357
|
+
addAnchor(specifierPath, specifier);
|
|
358
|
+
addAnchor([...specifierPath, "local"], specifier.local);
|
|
359
|
+
addAnchor([...specifierPath, "imported"], specifier.imported);
|
|
360
|
+
}
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
const statementPath = ["statement", statementIndex++];
|
|
364
|
+
addAnchor(statementPath, statement);
|
|
365
|
+
if (statement.type === "ExportNamedDeclaration") {
|
|
366
|
+
addAnchor([...statementPath, "source"], statement.source);
|
|
367
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
368
|
+
const exportedName = getAstNodeName(specifier.exported);
|
|
369
|
+
if (exportedName === null) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const specifierPath = [...statementPath, "specifier", exportedName];
|
|
373
|
+
addAnchor(specifierPath, specifier);
|
|
374
|
+
addAnchor([...specifierPath, "local"], specifier.local);
|
|
375
|
+
addAnchor([...specifierPath, "exported"], specifier.exported);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
for (const comment of getProgramComments(parserAst)) {
|
|
381
|
+
const range = getAstNodeTextRange(comment);
|
|
382
|
+
if (range) {
|
|
383
|
+
addAnchor(["comment", sourceText.slice(range.start, range.end)], comment);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return anchors;
|
|
387
|
+
}
|
|
388
|
+
function updateCursorOffset(sourceText, sortedText, originalAst, sortedAst, prettierOptions) {
|
|
389
|
+
const cursorOffset = prettierOptions.cursorOffset;
|
|
390
|
+
if (typeof cursorOffset !== "number" || cursorOffset < 0 || sourceText === sortedText) {
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
if (!Number.isSafeInteger(cursorOffset) || cursorOffset > sourceText.length) {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
if (cursorOffset === 0 || cursorOffset === sourceText.length) {
|
|
397
|
+
prettierOptions.cursorOffset = cursorOffset === 0 ? 0 : sortedText.length;
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
const originalAnchors = collectCursorAnchors(originalAst, sourceText).filter((anchor) => anchor.start <= cursorOffset && cursorOffset <= anchor.end).sort((left, right) => left.end - left.start - (right.end - right.start) || right.start - left.start);
|
|
401
|
+
const sortedAnchors = collectCursorAnchors(sortedAst, sortedText);
|
|
402
|
+
for (const originalAnchor of originalAnchors) {
|
|
403
|
+
const originalNodeText = sourceText.slice(originalAnchor.start, originalAnchor.end);
|
|
404
|
+
const matches = sortedAnchors.filter((anchor) => anchor.key === originalAnchor.key && sortedText.slice(anchor.start, anchor.end) === originalNodeText);
|
|
405
|
+
const [matchingAnchor] = matches;
|
|
406
|
+
if (matches.length === 1 && matchingAnchor) {
|
|
407
|
+
prettierOptions.cursorOffset = matchingAnchor.start + cursorOffset - originalAnchor.start;
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
|
|
309
414
|
// src/utils/package-rules.ts
|
|
310
415
|
var PACKAGE_JSON_FIELD_ORDER = [
|
|
311
416
|
"$schema",
|
|
@@ -518,6 +623,7 @@ class JsonSourceLiteral {
|
|
|
518
623
|
this.sourceText = sourceText;
|
|
519
624
|
}
|
|
520
625
|
}
|
|
626
|
+
var JSON_KEY_ORDER = Symbol("jsonKeyOrder");
|
|
521
627
|
var SEQUENTIAL_SCRIPT_PATTERN = /(?<=^|[\s&;<>|(])(?:run-s|npm-run-all2? .*(?:--sequential|--serial|-s))(?=$|[\s&;<>|)])/;
|
|
522
628
|
var PACKAGE_JSON_FIELD_INDEXES = new Map(PACKAGE_JSON_FIELD_ORDER.map((fieldName, index) => [fieldName, index]));
|
|
523
629
|
function compareStringsCaseSensitive(leftText, rightText) {
|
|
@@ -529,6 +635,19 @@ function compareStringsCaseSensitive(leftText, rightText) {
|
|
|
529
635
|
function isJsonObject(value) {
|
|
530
636
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof JsonSourceLiteral);
|
|
531
637
|
}
|
|
638
|
+
function createJsonObject(entries) {
|
|
639
|
+
const fields = new Map(entries);
|
|
640
|
+
return {
|
|
641
|
+
...Object.fromEntries(fields),
|
|
642
|
+
[JSON_KEY_ORDER]: [...fields.keys()]
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function getJsonKeys(jsonObject) {
|
|
646
|
+
return jsonObject[JSON_KEY_ORDER] ?? Object.keys(jsonObject);
|
|
647
|
+
}
|
|
648
|
+
function getJsonEntries(jsonObject) {
|
|
649
|
+
return getJsonKeys(jsonObject).map((key) => [key, jsonObject[key]]);
|
|
650
|
+
}
|
|
532
651
|
function getJsonPathKey(jsonPath) {
|
|
533
652
|
return JSON.stringify(jsonPath);
|
|
534
653
|
}
|
|
@@ -585,6 +704,7 @@ function preserveJsonSourceLiterals(jsonValue, parserJsonNode, sourceText, field
|
|
|
585
704
|
fieldNameSourceTexts.set(getJsonPathKey(propertyPath), sourceText.slice(propertyNameRange.start, propertyNameRange.end));
|
|
586
705
|
jsonObject[propertyName] = propertyValue;
|
|
587
706
|
}
|
|
707
|
+
jsonObject[JSON_KEY_ORDER] = [...propertyNames];
|
|
588
708
|
return jsonObject;
|
|
589
709
|
}
|
|
590
710
|
if (parserJsonNode.type === "ArrayExpression") {
|
|
@@ -629,7 +749,7 @@ function serializeJsonValue(jsonValue, fieldNameSourceTexts, jsonPath = []) {
|
|
|
629
749
|
}
|
|
630
750
|
if (isJsonObject(jsonValue)) {
|
|
631
751
|
const serializedFields = [];
|
|
632
|
-
for (const [fieldName, fieldValue] of
|
|
752
|
+
for (const [fieldName, fieldValue] of getJsonEntries(jsonValue)) {
|
|
633
753
|
const fieldPath = [...jsonPath, fieldName];
|
|
634
754
|
const fieldNameSourceText = fieldNameSourceTexts.get(getJsonPathKey(fieldPath));
|
|
635
755
|
const serializedValue = serializeJsonValue(fieldValue, fieldNameSourceTexts, fieldPath);
|
|
@@ -656,7 +776,7 @@ function deduplicateStringValues(stringValues) {
|
|
|
656
776
|
return [...uniqueStringValues.values()];
|
|
657
777
|
}
|
|
658
778
|
function sortJsonObject(jsonObject, compareKeys = compareStringsCaseSensitive) {
|
|
659
|
-
return
|
|
779
|
+
return createJsonObject(getJsonEntries(jsonObject).sort(([leftKey], [rightKey]) => compareKeys(leftKey, rightKey)));
|
|
660
780
|
}
|
|
661
781
|
function sortJsonObjectByKeyOrder(jsonObject, keyOrder) {
|
|
662
782
|
const keyOrderIndexes = new Map(keyOrder.map((key, index) => [key, index]));
|
|
@@ -678,7 +798,7 @@ function sortJsonObjectByKeyOrder(jsonObject, keyOrder) {
|
|
|
678
798
|
});
|
|
679
799
|
}
|
|
680
800
|
function sortJsonObjectRecursively(jsonObject, sortObject = sortJsonObject) {
|
|
681
|
-
const sortedNestedValues =
|
|
801
|
+
const sortedNestedValues = createJsonObject(getJsonEntries(jsonObject).map(([key, value]) => [
|
|
682
802
|
key,
|
|
683
803
|
isJsonObject(value) ? sortJsonObjectRecursively(value, sortObject) : value
|
|
684
804
|
]));
|
|
@@ -786,11 +906,7 @@ function sortEslintConfigValue(fieldValue) {
|
|
|
786
906
|
return sortJsonObjectValue(fieldValue, sortEslintConfigObject);
|
|
787
907
|
}
|
|
788
908
|
function sortPrettierConfigObject(prettierConfig) {
|
|
789
|
-
const
|
|
790
|
-
if (Object.hasOwn(prettierConfig, "overrides")) {
|
|
791
|
-
keyOrder.push("overrides");
|
|
792
|
-
}
|
|
793
|
-
const sortedConfig = sortJsonObjectByKeyOrder(prettierConfig, keyOrder);
|
|
909
|
+
const sortedConfig = sortJsonObject(prettierConfig, (leftKey, rightKey) => Number(leftKey === "overrides") - Number(rightKey === "overrides") || compareStringsCaseSensitive(leftKey, rightKey));
|
|
794
910
|
if (Array.isArray(sortedConfig.overrides)) {
|
|
795
911
|
sortedConfig.overrides = sortedConfig.overrides.map((override) => {
|
|
796
912
|
if (!isJsonObject(override)) {
|
|
@@ -814,7 +930,7 @@ function sortWireitScriptObject(scriptConfig) {
|
|
|
814
930
|
sortedConfig.dependencies = sortedConfig.dependencies.map((dependency) => sortJsonObjectValueByKeyOrder(dependency, ["script", "cascade"]));
|
|
815
931
|
}
|
|
816
932
|
if (isJsonObject(sortedConfig.env)) {
|
|
817
|
-
sortedConfig.env = sortJsonObject(
|
|
933
|
+
sortedConfig.env = sortJsonObject(createJsonObject(getJsonEntries(sortedConfig.env).map(([name, value]) => [
|
|
818
934
|
name,
|
|
819
935
|
sortJsonObjectValueByKeyOrder(value, ["external", "default"])
|
|
820
936
|
])));
|
|
@@ -833,7 +949,7 @@ function sortWireitValue(fieldValue) {
|
|
|
833
949
|
if (!isJsonObject(fieldValue)) {
|
|
834
950
|
return fieldValue;
|
|
835
951
|
}
|
|
836
|
-
return sortJsonObject(
|
|
952
|
+
return sortJsonObject(createJsonObject(getJsonEntries(fieldValue).map(([scriptName, scriptConfig]) => [
|
|
837
953
|
scriptName,
|
|
838
954
|
sortJsonObjectValue(scriptConfig, sortWireitScriptObject)
|
|
839
955
|
])));
|
|
@@ -883,7 +999,7 @@ function sortScriptsValue(fieldValue, packageJson) {
|
|
|
883
999
|
if (!isJsonObject(fieldValue)) {
|
|
884
1000
|
return fieldValue;
|
|
885
1001
|
}
|
|
886
|
-
const scriptNames =
|
|
1002
|
+
const scriptNames = getJsonKeys(fieldValue);
|
|
887
1003
|
const baseScriptNames = new Set;
|
|
888
1004
|
const normalizedScriptNames = scriptNames.map((scriptName) => {
|
|
889
1005
|
const baseScriptName = scriptName.replace(/^(?:pre|post)/, "");
|
|
@@ -895,21 +1011,22 @@ function sortScriptsValue(fieldValue, packageJson) {
|
|
|
895
1011
|
}
|
|
896
1012
|
return scriptName;
|
|
897
1013
|
});
|
|
898
|
-
const
|
|
1014
|
+
const uniqueScriptNames = [...new Set(normalizedScriptNames)];
|
|
1015
|
+
const orderedBaseScriptNames = hasSequentialScript(packageJson) ? uniqueScriptNames : sortScriptNames(uniqueScriptNames);
|
|
899
1016
|
const orderedScriptNames = orderedBaseScriptNames.flatMap((baseScriptName) => baseScriptNames.has(baseScriptName) ? [`pre${baseScriptName}`, baseScriptName, `post${baseScriptName}`] : [baseScriptName]);
|
|
900
|
-
return
|
|
1017
|
+
return createJsonObject(orderedScriptNames.filter((scriptName) => Object.hasOwn(fieldValue, scriptName)).map((scriptName) => [scriptName, fieldValue[scriptName]]));
|
|
901
1018
|
}
|
|
902
1019
|
function sortExportsValue(fieldValue) {
|
|
903
1020
|
if (!isJsonObject(fieldValue)) {
|
|
904
1021
|
return fieldValue;
|
|
905
1022
|
}
|
|
906
|
-
const exportKeys =
|
|
1023
|
+
const exportKeys = getJsonKeys(fieldValue);
|
|
907
1024
|
const exportPathKeys = exportKeys.filter((key) => key.startsWith("."));
|
|
908
1025
|
const exportConditionKeys = exportKeys.filter((key) => !key.startsWith(".") && key !== "default");
|
|
909
1026
|
if (Object.hasOwn(fieldValue, "default")) {
|
|
910
1027
|
exportConditionKeys.push("default");
|
|
911
1028
|
}
|
|
912
|
-
return
|
|
1029
|
+
return createJsonObject([...exportPathKeys, ...exportConditionKeys].map((exportKey) => [exportKey, sortExportsValue(fieldValue[exportKey])]));
|
|
913
1030
|
}
|
|
914
1031
|
function sortDevEnginesValue(fieldValue) {
|
|
915
1032
|
if (!isJsonObject(fieldValue) || !isJsonObject(fieldValue.packageManager)) {
|
|
@@ -1107,7 +1224,7 @@ var PACKAGE_JSON_FIELD_SORTERS = {
|
|
|
1107
1224
|
};
|
|
1108
1225
|
function sortPackageJsonObject(packageJson) {
|
|
1109
1226
|
const sortedPackageJsonFields = sortPackageJsonFields(packageJson);
|
|
1110
|
-
return
|
|
1227
|
+
return createJsonObject(getJsonEntries(sortedPackageJsonFields).map(([fieldName, fieldValue]) => {
|
|
1111
1228
|
const fieldSorter = Object.hasOwn(PACKAGE_JSON_FIELD_SORTERS, fieldName) ? PACKAGE_JSON_FIELD_SORTERS[fieldName] : undefined;
|
|
1112
1229
|
return [
|
|
1113
1230
|
fieldName,
|
|
@@ -1136,7 +1253,17 @@ async function preprocessPackageJson(sourceText, prettierOptions, parser) {
|
|
|
1136
1253
|
if (!isJsonObject(packageJsonWithSourceLiterals)) {
|
|
1137
1254
|
return sourceText;
|
|
1138
1255
|
}
|
|
1139
|
-
|
|
1256
|
+
const sortedText = serializeJsonValue(sortPackageJsonObject(packageJsonWithSourceLiterals), fieldNameSourceTexts);
|
|
1257
|
+
if (sortedText === null || sortedText === sourceText) {
|
|
1258
|
+
return sourceText;
|
|
1259
|
+
}
|
|
1260
|
+
if (typeof prettierOptions.cursorOffset === "number" && prettierOptions.cursorOffset >= 0) {
|
|
1261
|
+
const sortedAst = await parser.parse(sortedText, prettierOptions);
|
|
1262
|
+
if (!isParserAstNode(sortedAst) || !updateCursorOffset(sourceText, sortedText, parserJsonAst, sortedAst, prettierOptions)) {
|
|
1263
|
+
return sourceText;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return sortedText;
|
|
1140
1267
|
} catch {
|
|
1141
1268
|
return sourceText;
|
|
1142
1269
|
}
|
|
@@ -1463,7 +1590,7 @@ async function preprocessTsconfig(sourceText, prettierOptions, parser) {
|
|
|
1463
1590
|
if (compilerOptions) {
|
|
1464
1591
|
const propertyRange = getAstNodeTextRange(compilerOptions.property);
|
|
1465
1592
|
const valueRange = getAstNodeTextRange(compilerOptions.value);
|
|
1466
|
-
if (propertyRange && valueRange && !isPrettierIgnored(sourceText, propertyRange, sortedComments)) {
|
|
1593
|
+
if (propertyRange && valueRange && !isPrettierIgnored(sourceText, propertyRange, sortedComments) && !isPrettierIgnored(sourceText, valueRange, sortedComments)) {
|
|
1467
1594
|
const renderedCompilerOptions = renderObject(sourceText, compilerOptions.value, sortedComments, COMPILER_OPTION_FIELD_INDEXES, tsconfigSeparation);
|
|
1468
1595
|
const renderedProperty = renderedCompilerOptions ? replacePropertyValue(sourceText, compilerOptions.property, compilerOptions.value, renderedCompilerOptions.sourceText) : null;
|
|
1469
1596
|
if (renderedCompilerOptions && renderedProperty) {
|
|
@@ -1496,7 +1623,10 @@ async function preprocessTsconfig(sourceText, prettierOptions, parser) {
|
|
|
1496
1623
|
if (editedSourceText === null) {
|
|
1497
1624
|
return sourceText;
|
|
1498
1625
|
}
|
|
1499
|
-
await parser.parse(editedSourceText, prettierOptions);
|
|
1626
|
+
const sortedAst = await parser.parse(editedSourceText, prettierOptions);
|
|
1627
|
+
if (!updateCursorOffset(sourceText, editedSourceText, parserAst, sortedAst, prettierOptions)) {
|
|
1628
|
+
return sourceText;
|
|
1629
|
+
}
|
|
1500
1630
|
return editedSourceText;
|
|
1501
1631
|
} catch {
|
|
1502
1632
|
return sourceText;
|
|
@@ -1692,7 +1822,11 @@ function findLeadingCommentsStart(sourceText, statementStart, sortedComments, pr
|
|
|
1692
1822
|
}
|
|
1693
1823
|
const textBetweenCommentAndImport = sourceText.slice(textRange.end, attachedTextStart);
|
|
1694
1824
|
const lineBreakCount = textBetweenCommentAndImport.match(/\n/g)?.length ?? 0;
|
|
1695
|
-
const
|
|
1825
|
+
const isEslintNextLine = isEslintNextLineComment(comment);
|
|
1826
|
+
if (isEslintNextLine && lineBreakCount === 0) {
|
|
1827
|
+
return null;
|
|
1828
|
+
}
|
|
1829
|
+
const isEslintNextLineCommentAttached = attachedTextStart === statementStart && isEslintNextLine && textBetweenCommentAndImport.trim() === "" && lineBreakCount === 1;
|
|
1696
1830
|
if (isEslintNextLineCommentAttached) {
|
|
1697
1831
|
attachedTextStart = textRange.start;
|
|
1698
1832
|
continue;
|
|
@@ -1761,19 +1895,47 @@ function getTrailingComments(sourceText, statementEnd, sortedComments) {
|
|
|
1761
1895
|
isImportSortingBoundary
|
|
1762
1896
|
};
|
|
1763
1897
|
}
|
|
1898
|
+
function getImportAttributesKey(importDeclarationNode, syntax) {
|
|
1899
|
+
const attributeNodes = importDeclarationNode.attributes;
|
|
1900
|
+
if (!Array.isArray(attributeNodes)) {
|
|
1901
|
+
return null;
|
|
1902
|
+
}
|
|
1903
|
+
const attributes = [];
|
|
1904
|
+
const attributeNames = new Set;
|
|
1905
|
+
for (const attributeNode of attributeNodes) {
|
|
1906
|
+
if (!isParserAstNode(attributeNode) || attributeNode.type !== "ImportAttribute" || !isParserAstNode(attributeNode.value)) {
|
|
1907
|
+
return null;
|
|
1908
|
+
}
|
|
1909
|
+
const keyNode = attributeNode.key;
|
|
1910
|
+
const valueNode = attributeNode.value;
|
|
1911
|
+
if (!keyNode || !["Identifier", "Literal", "StringLiteral"].includes(keyNode.type) || valueNode.type !== "Literal" && valueNode.type !== "StringLiteral" || typeof valueNode.value !== "string") {
|
|
1912
|
+
return null;
|
|
1913
|
+
}
|
|
1914
|
+
const attributeName = getAstNodeName(keyNode);
|
|
1915
|
+
if (attributeName === null || attributeNames.has(attributeName)) {
|
|
1916
|
+
return null;
|
|
1917
|
+
}
|
|
1918
|
+
attributeNames.add(attributeName);
|
|
1919
|
+
attributes.push([attributeName, valueNode.value]);
|
|
1920
|
+
}
|
|
1921
|
+
return JSON.stringify([syntax, attributes]);
|
|
1922
|
+
}
|
|
1764
1923
|
function parseImportAttributes(sourceText, importDeclarationNode) {
|
|
1765
1924
|
const declarationRange = getAstNodeTextRange(importDeclarationNode);
|
|
1766
1925
|
const moduleSpecifierRange = getAstNodeTextRange(importDeclarationNode.source);
|
|
1767
1926
|
if (!declarationRange || !moduleSpecifierRange) {
|
|
1768
|
-
return { attributesText: null, isValid: false };
|
|
1927
|
+
return { attributesText: null, attributesKey: null, isValid: false };
|
|
1769
1928
|
}
|
|
1770
1929
|
const importAttributesText = sourceText.slice(moduleSpecifierRange.end, declarationRange.end).replace(/;\s*$/, "").trim();
|
|
1771
1930
|
if (importAttributesText === "") {
|
|
1772
|
-
return { attributesText: null, isValid: true };
|
|
1931
|
+
return { attributesText: null, attributesKey: null, isValid: true };
|
|
1773
1932
|
}
|
|
1933
|
+
const attributeSyntax = /^(with|assert)\s*\{[\s\S]*\}$/.exec(importAttributesText)?.[1];
|
|
1934
|
+
const attributesKey = attributeSyntax ? getImportAttributesKey(importDeclarationNode, attributeSyntax) : null;
|
|
1774
1935
|
return {
|
|
1775
1936
|
attributesText: importAttributesText,
|
|
1776
|
-
|
|
1937
|
+
attributesKey,
|
|
1938
|
+
isValid: attributesKey !== null
|
|
1777
1939
|
};
|
|
1778
1940
|
}
|
|
1779
1941
|
function parseImportDeclaration(importDeclarationMetadata, sourceText) {
|
|
@@ -1863,6 +2025,7 @@ function parseImportDeclaration(importDeclarationMetadata, sourceText) {
|
|
|
1863
2025
|
namespaceBinding,
|
|
1864
2026
|
namedSpecifiers: parsedNamedSpecifiers,
|
|
1865
2027
|
importAttributes: parsedImportAttributes.attributesText,
|
|
2028
|
+
importAttributesKey: parsedImportAttributes.attributesKey,
|
|
1866
2029
|
verbatimDeclaration,
|
|
1867
2030
|
leadingCommentsText,
|
|
1868
2031
|
trailingCommentsText,
|
|
@@ -1928,10 +2091,10 @@ function getLocalBindingNames(importDeclaration) {
|
|
|
1928
2091
|
return localBindingNames;
|
|
1929
2092
|
}
|
|
1930
2093
|
function getImportRequestKey(importDeclaration) {
|
|
1931
|
-
return `${importDeclaration.moduleSpecifier}\x00${importDeclaration.importAttributes ?? ""}`;
|
|
2094
|
+
return `${importDeclaration.moduleSpecifier}\x00${importDeclaration.importAttributesKey ?? importDeclaration.importAttributes ?? ""}`;
|
|
1932
2095
|
}
|
|
1933
2096
|
function isImportDeclarationMergeSafe(targetImportDeclaration, candidateImportDeclaration, bindingCounts) {
|
|
1934
|
-
if (targetImportDeclaration.verbatimDeclaration !== null || candidateImportDeclaration.verbatimDeclaration !== null || targetImportDeclaration.
|
|
2097
|
+
if (targetImportDeclaration.verbatimDeclaration !== null || candidateImportDeclaration.verbatimDeclaration !== null || targetImportDeclaration.moduleSpecifier !== candidateImportDeclaration.moduleSpecifier || targetImportDeclaration.importAttributesKey !== candidateImportDeclaration.importAttributesKey || targetImportDeclaration.isMergeBoundary || candidateImportDeclaration.isMergeBoundary) {
|
|
1935
2098
|
return false;
|
|
1936
2099
|
}
|
|
1937
2100
|
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) {
|
|
@@ -1963,6 +2126,7 @@ function mergeImportDeclarations(targetImportDeclaration, candidateImportDeclara
|
|
|
1963
2126
|
namespaceBinding: targetImportDeclaration.namespaceBinding ?? candidateImportDeclaration.namespaceBinding,
|
|
1964
2127
|
namedSpecifiers,
|
|
1965
2128
|
importAttributes: targetImportDeclaration.importAttributes,
|
|
2129
|
+
importAttributesKey: targetImportDeclaration.importAttributesKey,
|
|
1966
2130
|
verbatimDeclaration: null,
|
|
1967
2131
|
leadingCommentsText: targetImportDeclaration.leadingCommentsText,
|
|
1968
2132
|
trailingCommentsText: "",
|
|
@@ -1985,7 +2149,7 @@ function mergeCompatibleImports(importDeclarations) {
|
|
|
1985
2149
|
currentBindingCountsByRequest.delete(importRequestKey);
|
|
1986
2150
|
continue;
|
|
1987
2151
|
}
|
|
1988
|
-
if (importDeclaration.verbatimDeclaration !== null
|
|
2152
|
+
if (importDeclaration.verbatimDeclaration !== null) {
|
|
1989
2153
|
continue;
|
|
1990
2154
|
}
|
|
1991
2155
|
const bindingCounts = currentBindingCountsByRequest.get(importRequestKey) ?? {
|
|
@@ -2035,10 +2199,10 @@ function applyTypeImportStyle(importDeclaration, typeImportStyle) {
|
|
|
2035
2199
|
];
|
|
2036
2200
|
}
|
|
2037
2201
|
if (typeImportStyle === "separate") {
|
|
2038
|
-
const
|
|
2039
|
-
const
|
|
2040
|
-
const hasValueBinding =
|
|
2041
|
-
if (
|
|
2202
|
+
const typeSpecifiers = namedSpecifiers.filter((importSpecifier) => importSpecifier.isTypeOnly);
|
|
2203
|
+
const valueSpecifiers = namedSpecifiers.filter((importSpecifier) => !importSpecifier.isTypeOnly);
|
|
2204
|
+
const hasValueBinding = valueSpecifiers.length > 0 || importDeclaration.defaultBinding !== null || importDeclaration.namespaceBinding !== null;
|
|
2205
|
+
if (typeSpecifiers.length > 0 && (!hasValueBinding || importDeclaration.importAttributes !== null || importDeclaration.leadingCommentsText.trim() !== "" || importDeclaration.trailingCommentsText !== "")) {
|
|
2042
2206
|
return [
|
|
2043
2207
|
{
|
|
2044
2208
|
...importDeclaration,
|
|
@@ -2047,25 +2211,25 @@ function applyTypeImportStyle(importDeclaration, typeImportStyle) {
|
|
|
2047
2211
|
];
|
|
2048
2212
|
}
|
|
2049
2213
|
const styledImportDeclarations = [];
|
|
2050
|
-
if (
|
|
2214
|
+
if (typeSpecifiers.length > 0) {
|
|
2051
2215
|
styledImportDeclarations.push({
|
|
2052
2216
|
...importDeclaration,
|
|
2053
2217
|
isTypeOnly: true,
|
|
2054
2218
|
defaultBinding: null,
|
|
2055
2219
|
namespaceBinding: null,
|
|
2056
|
-
namedSpecifiers: sortNamedImportSpecifiers(
|
|
2220
|
+
namedSpecifiers: sortNamedImportSpecifiers(typeSpecifiers.map((importSpecifier) => ({
|
|
2057
2221
|
...importSpecifier,
|
|
2058
2222
|
isTypeOnly: false
|
|
2059
2223
|
})))
|
|
2060
2224
|
});
|
|
2061
2225
|
}
|
|
2062
|
-
if (
|
|
2226
|
+
if (hasValueBinding) {
|
|
2063
2227
|
let namedValueSpecifiers = null;
|
|
2064
|
-
if (
|
|
2065
|
-
namedValueSpecifiers = sortNamedImportSpecifiers(
|
|
2228
|
+
if (valueSpecifiers.length > 0) {
|
|
2229
|
+
namedValueSpecifiers = sortNamedImportSpecifiers(valueSpecifiers);
|
|
2066
2230
|
}
|
|
2067
2231
|
let leadingCommentsText = importDeclaration.leadingCommentsText;
|
|
2068
|
-
if (
|
|
2232
|
+
if (typeSpecifiers.length > 0) {
|
|
2069
2233
|
leadingCommentsText = "";
|
|
2070
2234
|
}
|
|
2071
2235
|
styledImportDeclarations.push({
|
|
@@ -2108,11 +2272,19 @@ function renderSortedImportSegment(importDeclarations, sortOptions, pathPatterns
|
|
|
2108
2272
|
}
|
|
2109
2273
|
const styledImportDeclarations = mergedImportDeclarations.flatMap((importDeclaration) => applyTypeImportStyle(importDeclaration, sortOptions.esmImportTypeStyle));
|
|
2110
2274
|
const unlistedGroupRank = sortOptions.esmImportGroups.length;
|
|
2111
|
-
const
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2275
|
+
const sortRegionByRequest = new Map;
|
|
2276
|
+
const rankedImportDeclarations = styledImportDeclarations.map((importDeclaration, originalIndex) => {
|
|
2277
|
+
const importRequestKey = getImportRequestKey(importDeclaration);
|
|
2278
|
+
const regionOffset = importDeclaration.isMergeBoundary ? 1 : 0;
|
|
2279
|
+
const sortRegion = (sortRegionByRequest.get(importRequestKey) ?? 0) + regionOffset;
|
|
2280
|
+
sortRegionByRequest.set(importRequestKey, sortRegion + regionOffset);
|
|
2281
|
+
return {
|
|
2282
|
+
importDeclaration,
|
|
2283
|
+
importGroup: classifyImportGroup(importDeclaration.moduleSpecifier, pathPatterns),
|
|
2284
|
+
sortRegion,
|
|
2285
|
+
originalIndex
|
|
2286
|
+
};
|
|
2287
|
+
});
|
|
2116
2288
|
rankedImportDeclarations.sort((left, right) => {
|
|
2117
2289
|
const groupRankDifference = (importGroupOrder.get(left.importGroup) ?? unlistedGroupRank) - (importGroupOrder.get(right.importGroup) ?? unlistedGroupRank);
|
|
2118
2290
|
if (groupRankDifference !== 0) {
|
|
@@ -2122,6 +2294,10 @@ function renderSortedImportSegment(importDeclarations, sortOptions, pathPatterns
|
|
|
2122
2294
|
if (moduleSpecifierDifference !== 0) {
|
|
2123
2295
|
return moduleSpecifierDifference;
|
|
2124
2296
|
}
|
|
2297
|
+
const sortRegionDifference = left.sortRegion - right.sortRegion;
|
|
2298
|
+
if (sortRegionDifference !== 0) {
|
|
2299
|
+
return sortRegionDifference;
|
|
2300
|
+
}
|
|
2125
2301
|
if (left.importDeclaration.isTypeOnly !== right.importDeclaration.isTypeOnly) {
|
|
2126
2302
|
if (left.importDeclaration.isTypeOnly) {
|
|
2127
2303
|
return -1;
|
|
@@ -2252,6 +2428,9 @@ function buildImportSortingEdits(sourceText, programStatements, sortedComments,
|
|
|
2252
2428
|
}
|
|
2253
2429
|
const isImportIgnoredByPrettier = isPrettierIgnored(sourceText, declarationRange, sortedComments);
|
|
2254
2430
|
const leadingCommentsStart = findLeadingCommentsStart(sourceText, declarationRange.start, sortedComments, prettierFilePragmaComment);
|
|
2431
|
+
if (leadingCommentsStart === null) {
|
|
2432
|
+
return [];
|
|
2433
|
+
}
|
|
2255
2434
|
const trailingComments = getTrailingComments(sourceText, declarationRange.end, sortedComments);
|
|
2256
2435
|
if (isImportIgnoredByPrettier || trailingComments.isImportSortingBoundary) {
|
|
2257
2436
|
if (currentSortableSegment.length > 0) {
|
|
@@ -2307,14 +2486,92 @@ function buildImportSortingEdits(sourceText, programStatements, sortedComments,
|
|
|
2307
2486
|
}
|
|
2308
2487
|
|
|
2309
2488
|
// src/sort-typescript.ts
|
|
2489
|
+
var SCRIPT_FILE_EXTENSION_PATTERN = /\.[cm]?[jt]sx?$/i;
|
|
2310
2490
|
async function getTsconfigPathPatterns(filePath) {
|
|
2311
2491
|
if (!filePath) {
|
|
2312
2492
|
return [];
|
|
2313
2493
|
}
|
|
2314
2494
|
try {
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2495
|
+
let isFileIncluded = function(project) {
|
|
2496
|
+
try {
|
|
2497
|
+
if (createFilesMatcher(project, isFileSystemCaseSensitive)(absoluteFilePath)) {
|
|
2498
|
+
return true;
|
|
2499
|
+
}
|
|
2500
|
+
const fileExtension = extname(absoluteFilePath);
|
|
2501
|
+
if (!fileExtension || SCRIPT_FILE_EXTENSION_PATTERN.test(fileExtension)) {
|
|
2502
|
+
return false;
|
|
2503
|
+
}
|
|
2504
|
+
const virtualExtension = ".ts";
|
|
2505
|
+
const normalizedFileExtension = isFileSystemCaseSensitive ? fileExtension : fileExtension.toLowerCase();
|
|
2506
|
+
const addVirtualExtension = (patterns) => patterns?.map((pattern) => {
|
|
2507
|
+
const normalizedPattern = isFileSystemCaseSensitive ? pattern : pattern.toLowerCase();
|
|
2508
|
+
return normalizedPattern.endsWith(normalizedFileExtension) ? `${pattern}${virtualExtension}` : pattern;
|
|
2509
|
+
});
|
|
2510
|
+
const virtualConfig = {
|
|
2511
|
+
...project.config,
|
|
2512
|
+
files: addVirtualExtension(project.config.files),
|
|
2513
|
+
include: addVirtualExtension(project.config.include),
|
|
2514
|
+
exclude: addVirtualExtension(project.config.exclude)
|
|
2515
|
+
};
|
|
2516
|
+
return Boolean(createFilesMatcher({ path: project.path, config: virtualConfig }, isFileSystemCaseSensitive)(`${absoluteFilePath}${virtualExtension}`));
|
|
2517
|
+
} catch {
|
|
2518
|
+
return false;
|
|
2519
|
+
}
|
|
2520
|
+
}, findProjectForFile = function(project) {
|
|
2521
|
+
if (visitedConfigPaths.has(project.path)) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
visitedConfigPaths.add(project.path);
|
|
2525
|
+
if (isFileIncluded(project)) {
|
|
2526
|
+
return project;
|
|
2527
|
+
}
|
|
2528
|
+
for (const reference of project.config.references ?? []) {
|
|
2529
|
+
if (typeof reference.path !== "string") {
|
|
2530
|
+
continue;
|
|
2531
|
+
}
|
|
2532
|
+
let referencedProject;
|
|
2533
|
+
try {
|
|
2534
|
+
const referencePath = resolve(dirname(project.path), reference.path);
|
|
2535
|
+
const configPath = extname(referencePath).toLowerCase() === ".json" ? referencePath : join(referencePath, "tsconfig.json");
|
|
2536
|
+
referencedProject = {
|
|
2537
|
+
path: configPath,
|
|
2538
|
+
config: parseTsconfig(configPath, cache)
|
|
2539
|
+
};
|
|
2540
|
+
} catch {
|
|
2541
|
+
continue;
|
|
2542
|
+
}
|
|
2543
|
+
const selectedProject = findProjectForFile(referencedProject);
|
|
2544
|
+
if (selectedProject) {
|
|
2545
|
+
return selectedProject;
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
return;
|
|
2549
|
+
};
|
|
2550
|
+
const { createFilesMatcher, getTsconfig, parseTsconfig } = await import("get-tsconfig");
|
|
2551
|
+
const { dirname, extname, join, resolve } = await import("node:path");
|
|
2552
|
+
const cache = new Map;
|
|
2553
|
+
const absoluteFilePath = resolve(filePath);
|
|
2554
|
+
const isFileSystemCaseSensitive = !["darwin", "win32"].includes(process.platform);
|
|
2555
|
+
const nearestProject = getTsconfig(absoluteFilePath, "tsconfig.json", cache);
|
|
2556
|
+
if (!nearestProject) {
|
|
2557
|
+
return [];
|
|
2558
|
+
}
|
|
2559
|
+
const visitedConfigPaths = new Set;
|
|
2560
|
+
let currentProject = nearestProject;
|
|
2561
|
+
while (currentProject) {
|
|
2562
|
+
const selectedProject = findProjectForFile(currentProject);
|
|
2563
|
+
if (selectedProject) {
|
|
2564
|
+
const paths = selectedProject.config.compilerOptions?.paths;
|
|
2565
|
+
return paths ? Object.keys(paths) : [];
|
|
2566
|
+
}
|
|
2567
|
+
const configDirectory = dirname(currentProject.path);
|
|
2568
|
+
const parentDirectory = dirname(configDirectory);
|
|
2569
|
+
if (parentDirectory === configDirectory) {
|
|
2570
|
+
break;
|
|
2571
|
+
}
|
|
2572
|
+
currentProject = getTsconfig(parentDirectory, "tsconfig.json", cache);
|
|
2573
|
+
}
|
|
2574
|
+
return [];
|
|
2318
2575
|
} catch {
|
|
2319
2576
|
return [];
|
|
2320
2577
|
}
|
|
@@ -2346,7 +2603,10 @@ async function sortTypeScript(sourceText, prettierOptions, parser) {
|
|
|
2346
2603
|
return sourceText;
|
|
2347
2604
|
}
|
|
2348
2605
|
try {
|
|
2349
|
-
await parser.parse(sortedText, prettierOptions);
|
|
2606
|
+
const sortedAst = await parser.parse(sortedText, prettierOptions);
|
|
2607
|
+
if (!updateCursorOffset(sourceText, sortedText, parserAst, sortedAst, prettierOptions)) {
|
|
2608
|
+
return sourceText;
|
|
2609
|
+
}
|
|
2350
2610
|
return sortedText;
|
|
2351
2611
|
} catch {
|
|
2352
2612
|
return sourceText;
|
|
@@ -2354,6 +2614,7 @@ async function sortTypeScript(sourceText, prettierOptions, parser) {
|
|
|
2354
2614
|
}
|
|
2355
2615
|
|
|
2356
2616
|
// src/index.ts
|
|
2617
|
+
var IS_RANGE_FORMATTING = Symbol("isRangeFormatting");
|
|
2357
2618
|
function wrapParserPreprocess(parser, preprocessTransform) {
|
|
2358
2619
|
return {
|
|
2359
2620
|
...parser,
|
|
@@ -2362,6 +2623,10 @@ function wrapParserPreprocess(parser, preprocessTransform) {
|
|
|
2362
2623
|
if (parser.preprocess) {
|
|
2363
2624
|
transformedText = await parser.preprocess(sourceText, prettierOptions);
|
|
2364
2625
|
}
|
|
2626
|
+
if (prettierOptions[IS_RANGE_FORMATTING] || prettierOptions.rangeStart > 0 || prettierOptions.rangeEnd < sourceText.length) {
|
|
2627
|
+
prettierOptions[IS_RANGE_FORMATTING] = true;
|
|
2628
|
+
return transformedText;
|
|
2629
|
+
}
|
|
2365
2630
|
return preprocessTransform(transformedText, prettierOptions, parser);
|
|
2366
2631
|
}
|
|
2367
2632
|
};
|
|
@@ -2387,6 +2652,6 @@ var sortPlugin = {
|
|
|
2387
2652
|
};
|
|
2388
2653
|
var src_default = sortPlugin;
|
|
2389
2654
|
export {
|
|
2390
|
-
|
|
2391
|
-
|
|
2655
|
+
src_default as default,
|
|
2656
|
+
options
|
|
2392
2657
|
};
|
package/package.json
CHANGED