@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 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 separatorIndex = key.lastIndexOf("|||");
470
- const name = key.slice(0, separatorIndex);
471
- const isSideEffect = "true" === key.slice(separatorIndex + 3);
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 imports = parseImports(text);
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
@@ -1,3 +1,3 @@
1
1
  import { ImportStatement } from "./types";
2
2
  /** 解析导入语句 */
3
- export declare function parseImports(code: string): ImportStatement[];
3
+ export declare function parseImports(code: string, filepath?: string): ImportStatement[];
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 和 isSideEffect 区分 */
9
+ /** 对导入语句进行分组,同时根据 name、isSideEffectisExport 区分 */
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1adybug/prettier-plugin-sort-imports",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "一个 Prettier 插件,用于对 JavaScript/TypeScript 文件的导入语句进行分组和排序",
5
5
  "keywords": [
6
6
  "prettier",