prettier-plugin-sort 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/README.zh.md +4 -3
- package/dist/index.d.ts +4 -27
- package/dist/index.js +163 -23
- package/dist/options.d.ts +26 -0
- package/dist/order-package.d.ts +10 -0
- package/dist/sort-exports.d.ts +12 -0
- package/dist/sort-imports.d.ts +2 -0
- package/dist/sort-package.d.ts +2 -0
- package/dist/utils.d.ts +8 -0
- package/package.json +13 -12
package/README.md
CHANGED
|
@@ -283,9 +283,10 @@ Top-level key order follows the field list maintained by [sort-package-json](htt
|
|
|
283
283
|
Rules the plugin follows:
|
|
284
284
|
|
|
285
285
|
- Top-level keys are reordered to the canonical sequence (`name` → `version` → ... → `dependencies`)
|
|
286
|
-
-
|
|
286
|
+
- `scripts` and `betterScripts` keys are sorted with pre/post lifecycle grouping and `:` namespace ordering
|
|
287
|
+
- `exports` keys are sorted: path subkeys first, conditions alphabetically with `default` moved to the end; nested export maps are recursively sorted
|
|
287
288
|
- `dependencies`, `devDependencies`, `peerDependencies` and other dependency maps are always sorted alphabetically, even if `packageJsonOrder` is set to `false`, because `npm install` rewrites them in alphabetical order every time
|
|
288
|
-
- `
|
|
289
|
+
- String arrays are handled by field: `keywords`, `files`, `activationEvents` are deduplicated preserving original order; `bundledDependencies`, `bundleDependencies`, `extensionPack`, `extensionDependencies` are deduplicated then sorted; `workspaces` arrays are left untouched; all other string arrays are sorted alphabetically
|
|
289
290
|
- Use `packageJsonOrderExcludeKeys` to opt specific top-level keys out of sorting entirely
|
|
290
291
|
|
|
291
292
|
## Options
|
|
@@ -300,7 +301,7 @@ Prettier plugin options are flat, so these options are prefixed with `importOrde
|
|
|
300
301
|
| `importOrderTypeImports` | How to place `type` imports: `separate`, `inline-first`, `inline-last`, `mixed` | `"separate"` |
|
|
301
302
|
| `importOrderMergeDuplicates` | Merge multiple `import` statements from the same source (except side-effect imports) | `true` |
|
|
302
303
|
| `exportOrder` | Sort named specifiers inside `export { … }` alphabetically | `true` |
|
|
303
|
-
| `packageJsonOrder` | Sort top-level keys and string arrays in `package.json`
|
|
304
|
+
| `packageJsonOrder` | Sort top-level keys, scripts/exports subkeys, and string arrays in `package.json` | `true` |
|
|
304
305
|
| `packageJsonOrderExcludeKeys` | Top-level `package.json` keys to leave untouched | `[]` |
|
|
305
306
|
|
|
306
307
|
## Example
|
package/README.zh.md
CHANGED
|
@@ -286,9 +286,10 @@ export { type FC, useEffect, useState } from 'react';
|
|
|
286
286
|
排序规则:
|
|
287
287
|
|
|
288
288
|
- 顶层字段按常用顺序排列(`name` → `version` → ... → `dependencies`)
|
|
289
|
-
-
|
|
289
|
+
- `scripts` 和 `betterScripts` 的键名按 pre/post 生命周期包围和 `:` 命名空间分组排序
|
|
290
|
+
- `exports` 键按路径优先、条件字母序、`default` 置底排序,嵌套的 export 对象递归处理
|
|
290
291
|
- `dependencies`、`devDependencies`、`peerDependencies` 等依赖表永远按字母序排列,即使 `packageJsonOrder` 设为 `false` 也不例外。因为 `npm install` 每次都会按照字母序写回
|
|
291
|
-
- `
|
|
292
|
+
- 字符串数组按字段分类处理:`keywords`、`files`、`activationEvents` 只去重不排序,保留原始语义顺序;`bundledDependencies`、`bundleDependencies`、`extensionPack`、`extensionDependencies` 去重后按字母序排列;`workspaces` 数组不排序;其余字符串数组按字母序排列
|
|
292
293
|
- 想让某些顶层字段完全跳过排序,可以在 `packageJsonOrderExcludeKeys` 里列出
|
|
293
294
|
|
|
294
295
|
## 配置项
|
|
@@ -303,7 +304,7 @@ Prettier 的插件选项是扁平的,所以这些配置都以 `importOrder`、
|
|
|
303
304
|
| `importOrderTypeImports` | `type` import 的处理方式:`separate`、`inline-first`、`inline-last`、`mixed` | `"separate"` |
|
|
304
305
|
| `importOrderMergeDuplicates` | 是否合并同来源的多条 import 语句(副作用导入除外) | `true` |
|
|
305
306
|
| `exportOrder` | 是否按字母序排列 `export { … }` 花括号内的命名导出 | `true` |
|
|
306
|
-
| `packageJsonOrder` | 是否排序 package.json
|
|
307
|
+
| `packageJsonOrder` | 是否排序 package.json 的顶层字段、scripts/exports 子键和字符串数组 | `true` |
|
|
307
308
|
| `packageJsonOrderExcludeKeys` | 不参与 package.json 排序的顶层字段 | `[]` |
|
|
308
309
|
|
|
309
310
|
## 示例
|
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Plugin, SupportOptions } from 'prettier';
|
|
4
|
-
|
|
5
|
-
/** import 分组,参考 eslint-plugin-import 的 import/order 规则。 */
|
|
6
|
-
export type ImportGroup = "builtin" | "external" | "internal" | "parent" | "sibling" | "index";
|
|
7
|
-
/** `import type` 内联风格,参考 @typescript-eslint/consistent-type-imports 的 fixStyle 选项。 */
|
|
8
|
-
export type TypeImportsStyle = "separate" | "inline-first" | "inline-last" | "mixed";
|
|
9
|
-
/** 插件排序配置。 */
|
|
10
|
-
export interface SortOptions {
|
|
11
|
-
importOrder?: boolean;
|
|
12
|
-
importOrderGroups?: ImportGroup[];
|
|
13
|
-
importOrderSeparation?: boolean;
|
|
14
|
-
importOrderTypeImports?: TypeImportsStyle;
|
|
15
|
-
importOrderMergeDuplicates?: boolean;
|
|
16
|
-
exportOrder?: boolean;
|
|
17
|
-
packageJsonOrder?: boolean;
|
|
18
|
-
packageJsonOrderExcludeKeys?: string[];
|
|
19
|
-
}
|
|
20
|
-
/** 向 Prettier 注册的选项。使用功能名词前缀命名,因为 Prettier API 不支持嵌套选项对象。 */
|
|
21
|
-
export declare const options: SupportOptions;
|
|
1
|
+
import { type Plugin } from 'prettier';
|
|
22
2
|
declare const plugin: Plugin;
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export {};
|
|
3
|
+
export default plugin;
|
|
4
|
+
export { options } from './options';
|
|
5
|
+
export type { ImportGroup, SortOptions, TypeImportsStyle } from './options';
|
package/dist/index.js
CHANGED
|
@@ -172,6 +172,7 @@ function stripTypePrefix(member) {
|
|
|
172
172
|
// src/sort-imports.ts
|
|
173
173
|
import { builtinModules } from "node:module";
|
|
174
174
|
var NODE_BUILTINS = new Set(builtinModules);
|
|
175
|
+
var INDEX_PATTERN = /^\.\/index(\.[a-z]+)?$/;
|
|
175
176
|
function detectGroup(source) {
|
|
176
177
|
if (source === "bun" || source.startsWith("bun:") || source.startsWith("node:")) {
|
|
177
178
|
return "builtin";
|
|
@@ -181,7 +182,7 @@ function detectGroup(source) {
|
|
|
181
182
|
if (head && NODE_BUILTINS.has(head)) {
|
|
182
183
|
return "builtin";
|
|
183
184
|
}
|
|
184
|
-
if (source === "." || source === "./" ||
|
|
185
|
+
if (source === "." || source === "./" || INDEX_PATTERN.test(source)) {
|
|
185
186
|
return "index";
|
|
186
187
|
}
|
|
187
188
|
if (source.startsWith("../") || source === "..") {
|
|
@@ -195,7 +196,7 @@ function detectGroup(source) {
|
|
|
195
196
|
}
|
|
196
197
|
return "external";
|
|
197
198
|
}
|
|
198
|
-
var TYPE_PREFIX = /^type\s+(.+)
|
|
199
|
+
var TYPE_PREFIX = /^type\s+(.+)$/;
|
|
199
200
|
function splitMembers(inner) {
|
|
200
201
|
return splitTopLevel(inner, ",").map((part) => {
|
|
201
202
|
const match = TYPE_PREFIX.exec(part);
|
|
@@ -279,9 +280,6 @@ function extractImportBlock(text) {
|
|
|
279
280
|
const leadingLines = [];
|
|
280
281
|
for (let i = commentLines.length - 1;i >= 0; i--) {
|
|
281
282
|
const line = commentLines[i];
|
|
282
|
-
if (line === undefined) {
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
283
|
if (line.trim() === "") {
|
|
286
284
|
break;
|
|
287
285
|
}
|
|
@@ -377,9 +375,9 @@ function applyTypeImports(importDecl, style) {
|
|
|
377
375
|
}
|
|
378
376
|
const typeMembers2 = importDecl.members.filter((member) => member.isType);
|
|
379
377
|
const valueMembers2 = importDecl.members.filter((member) => !member.isType);
|
|
380
|
-
const
|
|
378
|
+
const output = [];
|
|
381
379
|
if (typeMembers2.length > 0) {
|
|
382
|
-
|
|
380
|
+
output.push({
|
|
383
381
|
source: importDecl.source,
|
|
384
382
|
typeClause: true,
|
|
385
383
|
sideEffect: false,
|
|
@@ -392,13 +390,13 @@ function applyTypeImports(importDecl, style) {
|
|
|
392
390
|
}
|
|
393
391
|
const hasValueBody = valueMembers2.length > 0 || importDecl.defaultSpec !== null || importDecl.namespaceSpec !== null;
|
|
394
392
|
if (hasValueBody) {
|
|
395
|
-
|
|
393
|
+
output.push({
|
|
396
394
|
...importDecl,
|
|
397
395
|
members: valueMembers2.length > 0 ? sortMembersAlpha(valueMembers2) : null,
|
|
398
396
|
leadingComments: typeMembers2.length > 0 ? "" : importDecl.leadingComments
|
|
399
397
|
});
|
|
400
398
|
}
|
|
401
|
-
return
|
|
399
|
+
return output.length > 0 ? output : [importDecl];
|
|
402
400
|
}
|
|
403
401
|
const inlineBase = importDecl.typeClause ? {
|
|
404
402
|
...importDecl,
|
|
@@ -423,8 +421,8 @@ function sortSegment(imports, options2, groupIndex, fallback) {
|
|
|
423
421
|
return [];
|
|
424
422
|
}
|
|
425
423
|
const style = options2.importOrderTypeImports;
|
|
426
|
-
const
|
|
427
|
-
const rewritten =
|
|
424
|
+
const deduplicated = options2.importOrderMergeDuplicates ? mergeImportsFromSameSource(imports) : imports;
|
|
425
|
+
const rewritten = deduplicated.flatMap((importDecl) => applyTypeImports(importDecl, style));
|
|
428
426
|
const decorated = rewritten.map((importDecl, index) => ({
|
|
429
427
|
importDecl,
|
|
430
428
|
group: detectGroup(importDecl.source),
|
|
@@ -507,9 +505,10 @@ function sortImports(text, rawOptions) {
|
|
|
507
505
|
const replacement = allLines.join(`
|
|
508
506
|
`);
|
|
509
507
|
const trailing = text.slice(block.end);
|
|
510
|
-
const
|
|
508
|
+
const nonBlankIndex = trailing.search(/\S/);
|
|
509
|
+
const suffix = nonBlankIndex >= 0 ? `
|
|
511
510
|
|
|
512
|
-
` + trailing.
|
|
511
|
+
` + trailing.slice(nonBlankIndex) : trailing;
|
|
513
512
|
return text.slice(0, block.start) + replacement + suffix;
|
|
514
513
|
}
|
|
515
514
|
|
|
@@ -634,8 +633,6 @@ var DEPENDENCY_FIELDS = [
|
|
|
634
633
|
"devDependencies",
|
|
635
634
|
"peerDependencies",
|
|
636
635
|
"optionalDependencies",
|
|
637
|
-
"bundledDependencies",
|
|
638
|
-
"bundleDependencies",
|
|
639
636
|
"resolutions",
|
|
640
637
|
"overrides"
|
|
641
638
|
];
|
|
@@ -647,8 +644,8 @@ function isPlainObject(value) {
|
|
|
647
644
|
function isStringArray(value) {
|
|
648
645
|
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
649
646
|
}
|
|
650
|
-
|
|
651
|
-
|
|
647
|
+
var TOP_LEVEL_ORDER_INDEX = new Map(PACKAGE_JSON_TOP_LEVEL_ORDER.map((key, index) => [key, index]));
|
|
648
|
+
function sortObjectKeysByOrder(record, orderIndex) {
|
|
652
649
|
const known = [];
|
|
653
650
|
const rest = [];
|
|
654
651
|
for (const entry of Object.entries(record)) {
|
|
@@ -672,6 +669,9 @@ function sortObjectKeysAlpha(value) {
|
|
|
672
669
|
function sortStringArrayAlpha(value) {
|
|
673
670
|
return [...value].sort((a, b) => a.localeCompare(b, "en"));
|
|
674
671
|
}
|
|
672
|
+
function uniqueStringArray(value) {
|
|
673
|
+
return [...new Set(value)];
|
|
674
|
+
}
|
|
675
675
|
function isPackageJson(filepath) {
|
|
676
676
|
if (!filepath) {
|
|
677
677
|
return false;
|
|
@@ -682,6 +682,116 @@ function detectIndent(source) {
|
|
|
682
682
|
const match = /\n([ \t]+)\S/.exec(source);
|
|
683
683
|
return match ? match[1] ?? " " : " ";
|
|
684
684
|
}
|
|
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
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
const scriptCommands = ["scripts", "betterScripts"].flatMap((field) => {
|
|
705
|
+
const scriptsObject = packageObject[field];
|
|
706
|
+
return isPlainObject(scriptsObject) ? Object.values(scriptsObject) : [];
|
|
707
|
+
});
|
|
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);
|
|
721
|
+
}
|
|
722
|
+
group.push(key);
|
|
723
|
+
} else {
|
|
724
|
+
let group = groupMap.get(key);
|
|
725
|
+
if (!group) {
|
|
726
|
+
group = [];
|
|
727
|
+
groupMap.set(key, group);
|
|
728
|
+
}
|
|
729
|
+
group.push(key);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
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)];
|
|
738
|
+
}
|
|
739
|
+
return children.sort((a, b) => a.localeCompare(b, "en"));
|
|
740
|
+
});
|
|
741
|
+
}
|
|
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;
|
|
750
|
+
}
|
|
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];
|
|
774
|
+
return [
|
|
775
|
+
key,
|
|
776
|
+
isPlainObject(value) ? sortExportsField(value) : value
|
|
777
|
+
];
|
|
778
|
+
}));
|
|
779
|
+
}
|
|
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
|
+
`;
|
|
794
|
+
}
|
|
685
795
|
function sortPackageJson(text, rawOptions) {
|
|
686
796
|
if (!isPackageJson(rawOptions.filepath)) {
|
|
687
797
|
return text;
|
|
@@ -705,21 +815,51 @@ function sortPackageJson(text, rawOptions) {
|
|
|
705
815
|
}
|
|
706
816
|
}
|
|
707
817
|
if (options2.packageJsonOrder) {
|
|
708
|
-
result = sortObjectKeysByOrder(result,
|
|
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
|
+
}
|
|
709
829
|
for (const [key, value] of Object.entries(result)) {
|
|
710
830
|
if (exclude.has(key)) {
|
|
711
831
|
continue;
|
|
712
832
|
}
|
|
713
|
-
if (isStringArray(value)) {
|
|
714
|
-
|
|
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;
|
|
715
846
|
}
|
|
847
|
+
result[key] = sortStringArrayAlpha(value);
|
|
716
848
|
}
|
|
717
849
|
}
|
|
718
850
|
const indent = detectIndent(text);
|
|
851
|
+
const newline = detectNewline(text);
|
|
719
852
|
const output = JSON.stringify(result, null, indent);
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
`
|
|
853
|
+
if (text.endsWith(newline)) {
|
|
854
|
+
return newline === `\r
|
|
855
|
+
` ? output.replace(/\n/g, `\r
|
|
856
|
+
`) + `\r
|
|
857
|
+
` : output + `
|
|
858
|
+
`;
|
|
859
|
+
}
|
|
860
|
+
return newline === `\r
|
|
861
|
+
` ? output.replace(/\n/g, `\r
|
|
862
|
+
`) : output;
|
|
723
863
|
}
|
|
724
864
|
|
|
725
865
|
// src/index.ts
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ParserOptions, type SupportOptions } from 'prettier';
|
|
2
|
+
/** import 分组,参考 eslint-plugin-import 的 import/order 规则。 */
|
|
3
|
+
export type ImportGroup = 'builtin' | 'external' | 'internal' | 'parent' | 'sibling' | 'index';
|
|
4
|
+
/** `import type` 内联风格,参考 @typescript-eslint/consistent-type-imports 的 fixStyle 选项。 */
|
|
5
|
+
export type TypeImportsStyle = 'separate' | 'inline-first' | 'inline-last' | 'mixed';
|
|
6
|
+
/** 插件排序配置。 */
|
|
7
|
+
export interface SortOptions {
|
|
8
|
+
importOrder?: boolean;
|
|
9
|
+
importOrderGroups?: ImportGroup[];
|
|
10
|
+
importOrderSeparation?: boolean;
|
|
11
|
+
importOrderTypeImports?: TypeImportsStyle;
|
|
12
|
+
importOrderMergeDuplicates?: boolean;
|
|
13
|
+
exportOrder?: boolean;
|
|
14
|
+
packageJsonOrder?: boolean;
|
|
15
|
+
packageJsonOrderExcludeKeys?: string[];
|
|
16
|
+
}
|
|
17
|
+
/** 默认排序配置。 */
|
|
18
|
+
export declare const DEFAULT_SORT_OPTIONS: Required<SortOptions>;
|
|
19
|
+
type RawSortOptions = ParserOptions & Partial<SortOptions>;
|
|
20
|
+
/**
|
|
21
|
+
* 从 Prettier 选项中提取插件配置,缺失或非法的参数会回退为默认值。
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveSortOptions(rawOptions: RawSortOptions): Required<SortOptions>;
|
|
24
|
+
/** 注册到 Prettier 的选项定义。使用功能名词前缀命名,因为 Prettier API 不支持嵌套的选项对象。 */
|
|
25
|
+
export declare const options: SupportOptions;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `package.json` 顶层字段的排列顺序。
|
|
3
|
+
* 参考社区标准 sort-package-json 的字段列表:https://github.com/keithamus/sort-package-json/blob/main/index.js#L433-L564
|
|
4
|
+
*/
|
|
5
|
+
export declare const PACKAGE_JSON_TOP_LEVEL_ORDER: readonly string[];
|
|
6
|
+
/**
|
|
7
|
+
* 值为 `{ name: range }` 映射的依赖表字段。
|
|
8
|
+
* 始终按字母序排列,不受用户选项影响——npm install 每次都会按字母序重写。
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEPENDENCY_FIELDS: readonly string[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ParserOptions } from 'prettier';
|
|
2
|
+
/**
|
|
3
|
+
* 按字母序排列 `export { … }` 花括号内的命名导出。
|
|
4
|
+
* 不改变语句位置,不跨语句合并,只针对单条 export 语句的花括号内部。
|
|
5
|
+
*
|
|
6
|
+
* 覆盖的语法形式:
|
|
7
|
+
* export { a, b };
|
|
8
|
+
* export { a, b } from 'mod';
|
|
9
|
+
* export type { A, B };
|
|
10
|
+
* export type { A, B } from 'mod';
|
|
11
|
+
*/
|
|
12
|
+
export declare function sortExports(text: string, rawOptions: ParserOptions): string;
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 按 `separator` 分割字符串,忽略嵌套在 `{}` / `()` / `[]` 中的分隔符。
|
|
3
|
+
* 仅在顶层(深度为 0 的位置)分隔。返回结果会 trim 并剔除空段。
|
|
4
|
+
*
|
|
5
|
+
* 不使用 `String.prototype.split` 直接分隔,因为 import / export 的花括号内可能
|
|
6
|
+
* 出现形如 `{ a, b as c }`,其中嵌套结构内的逗号不应被当作分隔符。
|
|
7
|
+
*/
|
|
8
|
+
export declare function splitTopLevel(input: string, separator: string): string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prettier-plugin-sort",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "An all-in-one Prettier plugin to sort imports, package.json keys, and more.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"imports",
|
|
@@ -35,24 +35,25 @@
|
|
|
35
35
|
"dist"
|
|
36
36
|
],
|
|
37
37
|
"scripts": {
|
|
38
|
-
"build": "bun run scripts/build/
|
|
39
|
-
"format": "prettier
|
|
40
|
-
"lint": "eslint
|
|
38
|
+
"build": "bun run scripts/build/",
|
|
39
|
+
"format": "prettier **/*.ts --write",
|
|
40
|
+
"lint": "eslint **/*.ts",
|
|
41
41
|
"prepare": "husky",
|
|
42
|
-
"test": "bun test"
|
|
42
|
+
"test": "bun test scripts/test/",
|
|
43
|
+
"typecheck": "tsc --noEmit"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
|
-
"@commitlint/cli": "^
|
|
46
|
-
"@commitlint/config-conventional": "^
|
|
47
|
-
"@commitlint/types": "^
|
|
46
|
+
"@commitlint/cli": "^21.0.1",
|
|
47
|
+
"@commitlint/config-conventional": "^21.0.1",
|
|
48
|
+
"@commitlint/types": "^21.0.1",
|
|
48
49
|
"@eslint/js": "^10.0.1",
|
|
49
|
-
"@types/bun": "^1.3.
|
|
50
|
-
"
|
|
51
|
-
"eslint": "^10.
|
|
50
|
+
"@types/bun": "^1.3.14",
|
|
51
|
+
"annal": "^0.0.2",
|
|
52
|
+
"eslint": "^10.4.0",
|
|
52
53
|
"husky": "^9.1.7",
|
|
53
54
|
"prettier": "^3.8.3",
|
|
54
55
|
"typescript": "^6.0.3",
|
|
55
|
-
"typescript-eslint": "^8.59.
|
|
56
|
+
"typescript-eslint": "^8.59.3"
|
|
56
57
|
},
|
|
57
58
|
"peerDependencies": {
|
|
58
59
|
"prettier": ">=3.0.0"
|