@1adybug/prettier-plugin-sort-imports 0.0.18 → 0.0.20
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 +13 -22
- package/README.zh-CN.md +13 -22
- package/dist/index.js +18 -10
- package/dist/parser.d.ts +1 -1
- package/dist/sorter.d.ts +1 -1
- package/dist/types.d.ts +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,9 +44,10 @@ npx prettier --write "src/**/*.{js,ts,jsx,tsx}"
|
|
|
44
44
|
### Basic Sorting
|
|
45
45
|
|
|
46
46
|
```typescript
|
|
47
|
-
import { Button } from "antd"
|
|
48
47
|
import React, { useEffect, useState } from "react"
|
|
49
48
|
|
|
49
|
+
import { Button } from "antd"
|
|
50
|
+
|
|
50
51
|
import { sum } from "./utils"
|
|
51
52
|
|
|
52
53
|
import "./styles.css"
|
|
@@ -83,9 +84,10 @@ export default {
|
|
|
83
84
|
Result:
|
|
84
85
|
|
|
85
86
|
```typescript
|
|
87
|
+
import React, { useState } from "react"
|
|
88
|
+
|
|
86
89
|
import { Button } from "antd"
|
|
87
90
|
import { format } from "date-fns"
|
|
88
|
-
import React, { useState } from "react"
|
|
89
91
|
|
|
90
92
|
import { Header } from "./components/Header"
|
|
91
93
|
|
|
@@ -232,29 +234,19 @@ export default createPlugin({
|
|
|
232
234
|
const path = statement.path
|
|
233
235
|
|
|
234
236
|
// React and related libraries
|
|
235
|
-
if (path.startsWith("react") || path.startsWith("@react"))
|
|
236
|
-
return "react"
|
|
237
|
-
}
|
|
237
|
+
if (path.startsWith("react") || path.startsWith("@react")) return "react"
|
|
238
238
|
|
|
239
239
|
// UI libraries
|
|
240
|
-
if (path.includes("antd") || path.includes("@mui") || path.includes("chakra"))
|
|
241
|
-
return "ui"
|
|
242
|
-
}
|
|
240
|
+
if (path.includes("antd") || path.includes("@mui") || path.includes("chakra")) return "ui"
|
|
243
241
|
|
|
244
242
|
// Utility libraries
|
|
245
|
-
if (path.includes("lodash") || path.includes("ramda") || path.includes("date-fns"))
|
|
246
|
-
return "utils"
|
|
247
|
-
}
|
|
243
|
+
if (path.includes("lodash") || path.includes("ramda") || path.includes("date-fns")) return "utils"
|
|
248
244
|
|
|
249
245
|
// External packages (node_modules)
|
|
250
|
-
if (!path.startsWith(".") && !path.startsWith("@/"))
|
|
251
|
-
return "external"
|
|
252
|
-
}
|
|
246
|
+
if (!path.startsWith(".") && !path.startsWith("@/")) return "external"
|
|
253
247
|
|
|
254
248
|
// Internal aliases (@/)
|
|
255
|
-
if (path.startsWith("@/"))
|
|
256
|
-
return "internal"
|
|
257
|
-
}
|
|
249
|
+
if (path.startsWith("@/")) return "internal"
|
|
258
250
|
|
|
259
251
|
// Relative imports
|
|
260
252
|
return "relative"
|
|
@@ -270,9 +262,7 @@ export default createPlugin({
|
|
|
270
262
|
// Custom import content sorting
|
|
271
263
|
sortImportContent: (a, b) => {
|
|
272
264
|
// Types first, then variables
|
|
273
|
-
if (a.type !== b.type)
|
|
274
|
-
return a.type === "type" ? -1 : 1
|
|
275
|
-
}
|
|
265
|
+
if (a.type !== b.type) return a.type === "type" ? -1 : 1
|
|
276
266
|
|
|
277
267
|
// Alphabetical order within same type
|
|
278
268
|
const aName = a.alias ?? a.name
|
|
@@ -485,11 +475,12 @@ import { c } from "c-module"
|
|
|
485
475
|
Comments follow the import statements they are attached to:
|
|
486
476
|
|
|
487
477
|
```typescript
|
|
488
|
-
// UI components
|
|
489
|
-
import { Button } from "antd"
|
|
490
478
|
// React related imports
|
|
491
479
|
import React from "react"
|
|
492
480
|
|
|
481
|
+
// UI components
|
|
482
|
+
import { Button } from "antd"
|
|
483
|
+
|
|
493
484
|
// Utilities
|
|
494
485
|
import { sum } from "./utils"
|
|
495
486
|
```
|
package/README.zh-CN.md
CHANGED
|
@@ -43,9 +43,10 @@ npx prettier --write "src/**/*.{js,ts,jsx,tsx}"
|
|
|
43
43
|
### 基本排序
|
|
44
44
|
|
|
45
45
|
```typescript
|
|
46
|
-
import { Button } from "antd"
|
|
47
46
|
import React, { useEffect, useState } from "react"
|
|
48
47
|
|
|
48
|
+
import { Button } from "antd"
|
|
49
|
+
|
|
49
50
|
import { sum } from "./utils"
|
|
50
51
|
|
|
51
52
|
import "./styles.css"
|
|
@@ -82,9 +83,10 @@ export default {
|
|
|
82
83
|
结果:
|
|
83
84
|
|
|
84
85
|
```typescript
|
|
86
|
+
import React, { useState } from "react"
|
|
87
|
+
|
|
85
88
|
import { Button } from "antd"
|
|
86
89
|
import { format } from "date-fns"
|
|
87
|
-
import React, { useState } from "react"
|
|
88
90
|
|
|
89
91
|
import { Header } from "./components/Header"
|
|
90
92
|
|
|
@@ -228,29 +230,19 @@ export default createPlugin({
|
|
|
228
230
|
const path = statement.path
|
|
229
231
|
|
|
230
232
|
// React 及相关库
|
|
231
|
-
if (path.startsWith("react") || path.startsWith("@react"))
|
|
232
|
-
return "react"
|
|
233
|
-
}
|
|
233
|
+
if (path.startsWith("react") || path.startsWith("@react")) return "react"
|
|
234
234
|
|
|
235
235
|
// UI 库
|
|
236
|
-
if (path.includes("antd") || path.includes("@mui") || path.includes("chakra"))
|
|
237
|
-
return "ui"
|
|
238
|
-
}
|
|
236
|
+
if (path.includes("antd") || path.includes("@mui") || path.includes("chakra")) return "ui"
|
|
239
237
|
|
|
240
238
|
// 工具库
|
|
241
|
-
if (path.includes("lodash") || path.includes("ramda") || path.includes("date-fns"))
|
|
242
|
-
return "utils"
|
|
243
|
-
}
|
|
239
|
+
if (path.includes("lodash") || path.includes("ramda") || path.includes("date-fns")) return "utils"
|
|
244
240
|
|
|
245
241
|
// 外部包 (node_modules)
|
|
246
|
-
if (!path.startsWith(".") && !path.startsWith("@/"))
|
|
247
|
-
return "external"
|
|
248
|
-
}
|
|
242
|
+
if (!path.startsWith(".") && !path.startsWith("@/")) return "external"
|
|
249
243
|
|
|
250
244
|
// 内部别名 (@/)
|
|
251
|
-
if (path.startsWith("@/"))
|
|
252
|
-
return "internal"
|
|
253
|
-
}
|
|
245
|
+
if (path.startsWith("@/")) return "internal"
|
|
254
246
|
|
|
255
247
|
// 相对导入
|
|
256
248
|
return "relative"
|
|
@@ -266,9 +258,7 @@ export default createPlugin({
|
|
|
266
258
|
// 自定义导入内容排序
|
|
267
259
|
sortImportContent: (a, b) => {
|
|
268
260
|
// 类型在前,变量在后
|
|
269
|
-
if (a.type !== b.type)
|
|
270
|
-
return a.type === "type" ? -1 : 1
|
|
271
|
-
}
|
|
261
|
+
if (a.type !== b.type) return a.type === "type" ? -1 : 1
|
|
272
262
|
|
|
273
263
|
// 同类型内按字母顺序
|
|
274
264
|
const aName = a.alias ?? a.name
|
|
@@ -481,11 +471,12 @@ import { c } from "c-module"
|
|
|
481
471
|
注释会跟随它们所附加的导入语句一起移动:
|
|
482
472
|
|
|
483
473
|
```typescript
|
|
484
|
-
// UI 组件
|
|
485
|
-
import { Button } from "antd"
|
|
486
474
|
// React 相关导入
|
|
487
475
|
import React from "react"
|
|
488
476
|
|
|
477
|
+
// UI 组件
|
|
478
|
+
import { Button } from "antd"
|
|
479
|
+
|
|
489
480
|
// 工具函数
|
|
490
481
|
import { sum } from "./utils"
|
|
491
482
|
```
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "module";
|
|
2
|
+
import { relative } from "path";
|
|
2
3
|
import { parse } from "@babel/parser";
|
|
3
4
|
import traverse from "@babel/traverse";
|
|
4
5
|
const analyzer_traverse = "function" == typeof traverse ? traverse : traverse["default"];
|
|
@@ -170,7 +171,7 @@ function formatGroups(groups, config) {
|
|
|
170
171
|
function formatImportStatements(statements) {
|
|
171
172
|
return statements.map(formatImportStatement).join("\n");
|
|
172
173
|
}
|
|
173
|
-
function parseImports(code) {
|
|
174
|
+
function parseImports(code, filepath) {
|
|
174
175
|
const hasImportOrExport = /^\s*(import|export)\s/m.test(code);
|
|
175
176
|
if (!hasImportOrExport) return [];
|
|
176
177
|
const ast = parse(code, {
|
|
@@ -187,17 +188,15 @@ function parseImports(code) {
|
|
|
187
188
|
const usedComments = new Set();
|
|
188
189
|
let isFirstImport = true;
|
|
189
190
|
for (const node of body)if ("ImportDeclaration" === node.type || "ExportNamedDeclaration" === node.type && node.source || "ExportAllDeclaration" === node.type) {
|
|
190
|
-
const statement = parseImportNode(node, ast.comments ?? [], usedComments, code, isFirstImport);
|
|
191
|
+
const statement = parseImportNode(node, ast.comments ?? [], usedComments, code, isFirstImport, filepath);
|
|
191
192
|
importStatements.push(statement);
|
|
192
193
|
isFirstImport = false;
|
|
193
194
|
} else break;
|
|
194
195
|
return importStatements;
|
|
195
196
|
}
|
|
196
|
-
function parseImportNode(node, comments, usedComments, code, isFirstImport) {
|
|
197
|
-
node.type;
|
|
197
|
+
function parseImportNode(node, comments, usedComments, code, isFirstImport, filepath) {
|
|
198
198
|
const source = node.source?.value ?? "";
|
|
199
199
|
const nodeStartLine = node.loc?.start.line ?? 0;
|
|
200
|
-
node.loc?.end.line;
|
|
201
200
|
const nodeStart = node.start ?? 0;
|
|
202
201
|
let nodeEnd = node.end ?? 0;
|
|
203
202
|
const leadingComments = [];
|
|
@@ -242,6 +241,7 @@ function parseImportNode(node, comments, usedComments, code, isFirstImport) {
|
|
|
242
241
|
const importContents = parseImportSpecifiers(node, isTypeOnlyImport);
|
|
243
242
|
const isSideEffect = 0 === importContents.length;
|
|
244
243
|
return {
|
|
244
|
+
filepath,
|
|
245
245
|
path: source,
|
|
246
246
|
isExport: false,
|
|
247
247
|
isSideEffect,
|
|
@@ -254,6 +254,7 @@ function parseImportNode(node, comments, usedComments, code, isFirstImport) {
|
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
256
|
if ("ExportAllDeclaration" === node.type) return {
|
|
257
|
+
filepath,
|
|
257
258
|
path: source,
|
|
258
259
|
isExport: true,
|
|
259
260
|
isSideEffect: true,
|
|
@@ -267,6 +268,7 @@ function parseImportNode(node, comments, usedComments, code, isFirstImport) {
|
|
|
267
268
|
const isTypeOnlyExport = "type" === node.exportKind;
|
|
268
269
|
const importContents = parseExportSpecifiers(node, isTypeOnlyExport);
|
|
269
270
|
return {
|
|
271
|
+
filepath,
|
|
270
272
|
path: source,
|
|
271
273
|
isExport: true,
|
|
272
274
|
isSideEffect: false,
|
|
@@ -459,19 +461,23 @@ function groupImports(imports, userConfig) {
|
|
|
459
461
|
const groupMap = new Map();
|
|
460
462
|
for (const statement of imports){
|
|
461
463
|
const groupName = config.getGroup(statement);
|
|
462
|
-
const key = `${groupName}|||${statement.isSideEffect}`;
|
|
464
|
+
const key = `${groupName}|||${statement.isSideEffect}|||${statement.isExport}`;
|
|
463
465
|
const statements = groupMap.get(key) ?? [];
|
|
464
466
|
statements.push(statement);
|
|
465
467
|
groupMap.set(key, statements);
|
|
466
468
|
}
|
|
467
469
|
const groups = [];
|
|
468
470
|
for (const [key, statements] of Array.from(groupMap.entries())){
|
|
469
|
-
const
|
|
470
|
-
const
|
|
471
|
-
const isSideEffect = "true" ===
|
|
471
|
+
const parts = key.split("|||");
|
|
472
|
+
const isExport = "true" === parts.pop();
|
|
473
|
+
const isSideEffect = "true" === parts.pop();
|
|
474
|
+
const name = parts.join("|||");
|
|
475
|
+
const filepath = statements[0].filepath;
|
|
472
476
|
groups.push({
|
|
477
|
+
filepath,
|
|
473
478
|
name,
|
|
474
479
|
isSideEffect,
|
|
480
|
+
isExport,
|
|
475
481
|
importStatements: statements
|
|
476
482
|
});
|
|
477
483
|
}
|
|
@@ -568,7 +574,9 @@ function preprocessImports(text, options, config = {}) {
|
|
|
568
574
|
"babel-ts"
|
|
569
575
|
];
|
|
570
576
|
if (!parser || !supportedParsers.includes(parser)) return text;
|
|
571
|
-
const
|
|
577
|
+
const absoluteFilepath = options.filepath;
|
|
578
|
+
const relativeFilepath = absoluteFilepath ? `./${relative(process.cwd(), absoluteFilepath).replace(/\\/g, "/")}` : void 0;
|
|
579
|
+
const imports = parseImports(text, relativeFilepath);
|
|
572
580
|
if (0 === imports.length) return text;
|
|
573
581
|
const optionsConfig = options;
|
|
574
582
|
const finalConfig = {
|
package/dist/parser.d.ts
CHANGED
package/dist/sorter.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface MergedConfig extends Omit<Required<PluginConfig>, "separator" |
|
|
|
6
6
|
}
|
|
7
7
|
/** 对导入语句进行排序 */
|
|
8
8
|
export declare function sortImports(imports: ImportStatement[], userConfig: PluginConfig): ImportStatement[];
|
|
9
|
-
/** 对导入语句进行分组,同时根据 name 和
|
|
9
|
+
/** 对导入语句进行分组,同时根据 name、isSideEffect 和 isExport 区分 */
|
|
10
10
|
export declare function groupImports(imports: ImportStatement[], userConfig: PluginConfig): Group[];
|
|
11
11
|
/** 对分组进行排序 */
|
|
12
12
|
export declare function sortGroups(groups: Group[], userConfig: PluginConfig): Group[];
|
package/dist/types.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface ImportContent {
|
|
|
14
14
|
}
|
|
15
15
|
/** 导入语句 */
|
|
16
16
|
export interface ImportStatement {
|
|
17
|
+
/** 当前文件相对于当前路径的位置 */
|
|
18
|
+
filepath?: string;
|
|
17
19
|
/** 导入的模块路径,可以是相对路径或绝对路径,比如 react, react-dom 或者 ./utils/index,@/utils/index 等 */
|
|
18
20
|
path: string;
|
|
19
21
|
/** 是否是导出语句,默认为 false */
|
|
@@ -37,10 +39,14 @@ export interface ImportStatement {
|
|
|
37
39
|
}
|
|
38
40
|
/** 分组 */
|
|
39
41
|
export interface Group {
|
|
42
|
+
/** 当前文件相对于当前路径的位置 */
|
|
43
|
+
filepath?: string;
|
|
40
44
|
/** 分组名称,默认为 default */
|
|
41
45
|
name: string;
|
|
42
46
|
/** 是否是副作用分组,默认为 false */
|
|
43
47
|
isSideEffect: boolean;
|
|
48
|
+
/** 是否是导出分组,默认为 false */
|
|
49
|
+
isExport: boolean;
|
|
44
50
|
/** 分组对应的导入语句列表 */
|
|
45
51
|
importStatements: ImportStatement[];
|
|
46
52
|
}
|