@1adybug/prettier-plugin-sort-imports 0.0.1 → 0.0.3

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.
@@ -1,5 +1,4 @@
1
- import { ImportStatement } from "./types";
2
- /** 分析代码中使用的标识符 */
1
+ import { ImportStatement } from "./types"; /** 分析代码中使用的标识符 */
3
2
  export declare function analyzeUsedIdentifiers(code: string): Set<string>;
4
3
  /** 过滤未使用的导入内容 */
5
4
  export declare function filterUnusedImports(importStatement: ImportStatement, usedIdentifiers: Set<string>): ImportStatement;
@@ -1,5 +1,4 @@
1
- import { Group, ImportStatement, PluginConfig } from "./types";
2
- /** 格式化导入语句 */
1
+ import { Group, ImportStatement, PluginConfig } from "./types"; /** 格式化导入语句 */
3
2
  export declare function formatImportStatement(statement: ImportStatement): string;
4
3
  /** 格式化分组 */
5
4
  export declare function formatGroups(groups: Group[], config: PluginConfig): string;
package/dist/index.cjs ADDED
@@ -0,0 +1,666 @@
1
+ "use strict";
2
+ const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
3
+ return 'undefined' == typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
4
+ }();
5
+ var __webpack_require__ = {};
6
+ (()=>{
7
+ __webpack_require__.n = (module)=>{
8
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
9
+ __webpack_require__.d(getter, {
10
+ a: getter
11
+ });
12
+ return getter;
13
+ };
14
+ })();
15
+ (()=>{
16
+ __webpack_require__.d = (exports1, definition)=>{
17
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
18
+ enumerable: true,
19
+ get: definition[key]
20
+ });
21
+ };
22
+ })();
23
+ (()=>{
24
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
25
+ })();
26
+ (()=>{
27
+ __webpack_require__.r = (exports1)=>{
28
+ if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
29
+ value: 'Module'
30
+ });
31
+ Object.defineProperty(exports1, '__esModule', {
32
+ value: true
33
+ });
34
+ };
35
+ })();
36
+ var __webpack_exports__ = {};
37
+ __webpack_require__.r(__webpack_exports__);
38
+ __webpack_require__.d(__webpack_exports__, {
39
+ createPlugin: ()=>createPlugin,
40
+ default: ()=>src
41
+ });
42
+ const external_module_namespaceObject = require("module");
43
+ const parser_namespaceObject = require("@babel/parser");
44
+ const traverse_namespaceObject = require("@babel/traverse");
45
+ var traverse_default = /*#__PURE__*/ __webpack_require__.n(traverse_namespaceObject);
46
+ function analyzeUsedIdentifiers(code) {
47
+ const usedIdentifiers = new Set();
48
+ try {
49
+ const ast = (0, parser_namespaceObject.parse)(code, {
50
+ sourceType: "module",
51
+ plugins: [
52
+ "typescript",
53
+ "jsx"
54
+ ],
55
+ errorRecovery: true
56
+ });
57
+ traverse_default()(ast, {
58
+ Identifier (path) {
59
+ const node = path.node;
60
+ const parent = path.parent;
61
+ if (path.isBindingIdentifier()) return;
62
+ if (parent?.type === "ObjectProperty" && parent.key === node && !parent.computed) return;
63
+ usedIdentifiers.add(node.name);
64
+ },
65
+ JSXIdentifier (path) {
66
+ const node = path.node;
67
+ if (path.parent?.type === "JSXOpeningElement" || path.parent?.type === "JSXClosingElement") usedIdentifiers.add(node.name);
68
+ },
69
+ TSTypeReference (path) {
70
+ const node = path.node;
71
+ if ("Identifier" === node.typeName.type) usedIdentifiers.add(node.typeName.name);
72
+ else if ("TSQualifiedName" === node.typeName.type) {
73
+ let current = node.typeName;
74
+ while("TSQualifiedName" === current.type)current = current.left;
75
+ if ("Identifier" === current.type) usedIdentifiers.add(current.name);
76
+ }
77
+ },
78
+ ExportNamedDeclaration (path) {
79
+ const node = path.node;
80
+ if (!node.source && node.specifiers) {
81
+ for (const specifier of node.specifiers)if ("ExportSpecifier" === specifier.type) {
82
+ if ("Identifier" === specifier.local.type) usedIdentifiers.add(specifier.local.name);
83
+ }
84
+ }
85
+ }
86
+ });
87
+ } catch (error) {
88
+ console.error("Failed to analyze used identifiers:", error);
89
+ }
90
+ return usedIdentifiers;
91
+ }
92
+ function filterUnusedImports(importStatement, usedIdentifiers) {
93
+ if (importStatement.isSideEffect || importStatement.isExport) return importStatement;
94
+ const usedContents = [];
95
+ for (const content of importStatement.importContents){
96
+ const usedName = content.alias ?? content.name;
97
+ if ("default" === content.name || "*" === content.name) {
98
+ if (content.alias && usedIdentifiers.has(content.alias)) usedContents.push(content);
99
+ } else if (usedIdentifiers.has(usedName)) usedContents.push(content);
100
+ }
101
+ return {
102
+ ...importStatement,
103
+ importContents: usedContents,
104
+ isSideEffect: 0 === usedContents.length
105
+ };
106
+ }
107
+ function removeUnusedImportsFromStatements(importStatements, code) {
108
+ const usedIdentifiers = analyzeUsedIdentifiers(code);
109
+ const filteredStatements = [];
110
+ for (const statement of importStatements){
111
+ const filteredStatement = filterUnusedImports(statement, usedIdentifiers);
112
+ if (statement.isSideEffect || !filteredStatement.isSideEffect || 0 !== filteredStatement.importContents.length) filteredStatements.push(filteredStatement);
113
+ }
114
+ return filteredStatements;
115
+ }
116
+ function formatImportStatement(statement) {
117
+ const { path, isExport, isSideEffect, importContents, leadingComments, trailingComments, removedTrailingComments } = statement;
118
+ const lines = [];
119
+ if (leadingComments && leadingComments.length > 0) lines.push(...leadingComments);
120
+ if (isSideEffect) {
121
+ let importLine = "";
122
+ importLine = isExport ? `export * from "${path}"` : `import "${path}"`;
123
+ if (trailingComments && trailingComments.length > 0) importLine += ` ${trailingComments.join(" ")}`;
124
+ lines.push(importLine);
125
+ return lines.join("\n");
126
+ }
127
+ const hasNamedImportComments = importContents.some((content)=>"default" !== content.name && "*" !== content.name && (content.leadingComments && content.leadingComments.length > 0 || content.trailingComments && content.trailingComments.length > 0));
128
+ const parts = [];
129
+ const namedParts = [];
130
+ const namedPartsWithComments = [];
131
+ for (const content of importContents){
132
+ if ("default" === content.name) {
133
+ parts.push(content.alias ?? "default");
134
+ continue;
135
+ }
136
+ if ("*" === content.name) {
137
+ parts.push(`* as ${content.alias ?? "namespace"}`);
138
+ continue;
139
+ }
140
+ const typePrefix = "type" === content.type ? "type " : "";
141
+ let importItem = "";
142
+ importItem = content.alias ? `${typePrefix}${content.name} as ${content.alias}` : `${typePrefix}${content.name}`;
143
+ if (hasNamedImportComments) {
144
+ const itemLines = [];
145
+ if (content.leadingComments && content.leadingComments.length > 0) itemLines.push(...content.leadingComments);
146
+ let itemLine = importItem;
147
+ if (content.trailingComments && content.trailingComments.length > 0) itemLine += ` ${content.trailingComments.join(" ")}`;
148
+ itemLines.push(itemLine);
149
+ namedPartsWithComments.push(itemLines.join("\n "));
150
+ } else namedParts.push(importItem);
151
+ }
152
+ const namedImports = importContents.filter((c)=>"default" !== c.name && "*" !== c.name);
153
+ const allNamedImportsAreTypes = namedImports.every((c)=>"type" === c.type);
154
+ const hasDefaultOrNamespace = importContents.some((c)=>"default" === c.name || "*" === c.name);
155
+ if (hasNamedImportComments && namedPartsWithComments.length > 0) {
156
+ const keyword = isExport ? "export" : "import";
157
+ const typeKeyword = allNamedImportsAreTypes && !hasDefaultOrNamespace ? "type " : "";
158
+ const defaultPart = parts.length > 0 ? parts.join(", ") + ", " : "";
159
+ const importStart = `${keyword} ${typeKeyword}${defaultPart}{`;
160
+ const importEnd = `} from "${path}"`;
161
+ lines.push(importStart);
162
+ lines.push(` ${namedPartsWithComments.join(",\n ")},`);
163
+ lines.push(importEnd);
164
+ } else {
165
+ if (namedParts.length > 0) if (allNamedImportsAreTypes && !hasDefaultOrNamespace) {
166
+ const cleanedParts = namedParts.map((part)=>part.replace(/^type /, ""));
167
+ parts.push(`{ ${cleanedParts.join(", ")} }`);
168
+ } else parts.push(`{ ${namedParts.join(", ")} }`);
169
+ const importClause = parts.join(", ");
170
+ const typeKeyword = allNamedImportsAreTypes && !hasDefaultOrNamespace ? "type " : "";
171
+ let importLine = "";
172
+ importLine = isExport ? `export ${typeKeyword}${importClause} from "${path}"` : `import ${typeKeyword}${importClause} from "${path}"`;
173
+ if (trailingComments && trailingComments.length > 0) importLine += ` ${trailingComments.join(" ")}`;
174
+ lines.push(importLine);
175
+ }
176
+ if (removedTrailingComments && removedTrailingComments.length > 0) {
177
+ lines.push("");
178
+ lines.push(...removedTrailingComments);
179
+ }
180
+ return lines.join("\n");
181
+ }
182
+ function formatGroups(groups, config) {
183
+ const lines = [];
184
+ const separator = config.separator;
185
+ for(let i = 0; i < groups.length; i++){
186
+ const group = groups[i];
187
+ if (void 0 !== separator) {
188
+ let separatorStr;
189
+ separatorStr = "string" == typeof separator ? separator : separator(group, i);
190
+ if (void 0 !== separatorStr) {
191
+ lines.push("");
192
+ if ("" !== separatorStr) lines.push(separatorStr);
193
+ }
194
+ }
195
+ for (const statement of group.importStatements)lines.push(formatImportStatement(statement));
196
+ }
197
+ return lines.join("\n");
198
+ }
199
+ function formatImportStatements(statements) {
200
+ return statements.map(formatImportStatement).join("\n");
201
+ }
202
+ function parseImports(code) {
203
+ const ast = (0, parser_namespaceObject.parse)(code, {
204
+ sourceType: "module",
205
+ plugins: [
206
+ "typescript",
207
+ "jsx"
208
+ ],
209
+ errorRecovery: true,
210
+ attachComment: true
211
+ });
212
+ const importStatements = [];
213
+ const { body } = ast.program;
214
+ const usedComments = new Set();
215
+ for (const node of body)if ("ImportDeclaration" === node.type || "ExportNamedDeclaration" === node.type && node.source || "ExportAllDeclaration" === node.type) {
216
+ const statement = parseImportNode(node, ast.comments ?? [], usedComments);
217
+ importStatements.push(statement);
218
+ } else break;
219
+ return importStatements;
220
+ }
221
+ function parseImportNode(node, comments, usedComments) {
222
+ node.type;
223
+ const source = node.source?.value ?? "";
224
+ node.loc?.start.line;
225
+ node.loc?.end.line;
226
+ const nodeStart = node.start ?? 0;
227
+ let nodeEnd = node.end ?? 0;
228
+ const leadingComments = [];
229
+ const trailingComments = [];
230
+ let start = nodeStart;
231
+ if (node.leadingComments) {
232
+ for (const comment of node.leadingComments)if (!usedComments.has(comment)) {
233
+ if ("CommentLine" === comment.type) leadingComments.push(`//${comment.value}`);
234
+ else if ("CommentBlock" === comment.type) leadingComments.push(`/*${comment.value}*/`);
235
+ const commentStart = comment.start ?? 0;
236
+ if (commentStart < start) start = commentStart;
237
+ usedComments.add(comment);
238
+ }
239
+ }
240
+ if (node.trailingComments) {
241
+ for (const comment of node.trailingComments)if (!usedComments.has(comment)) {
242
+ const commentLoc = comment.loc;
243
+ const nodeLoc = node.loc;
244
+ const isSameLine = commentLoc && nodeLoc && commentLoc.start.line === nodeLoc.end.line;
245
+ if (isSameLine) {
246
+ if ("CommentLine" === comment.type) trailingComments.push(`//${comment.value}`);
247
+ else if ("CommentBlock" === comment.type) trailingComments.push(`/*${comment.value}*/`);
248
+ const commentEnd = comment.end ?? 0;
249
+ if (commentEnd > nodeEnd) nodeEnd = commentEnd;
250
+ usedComments.add(comment);
251
+ }
252
+ }
253
+ }
254
+ const end = nodeEnd;
255
+ if ("ImportDeclaration" === node.type) {
256
+ const isTypeOnlyImport = "type" === node.importKind;
257
+ const importContents = parseImportSpecifiers(node, isTypeOnlyImport);
258
+ const isSideEffect = 0 === importContents.length;
259
+ return {
260
+ path: source,
261
+ isExport: false,
262
+ isSideEffect,
263
+ importContents,
264
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
265
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0,
266
+ start,
267
+ end
268
+ };
269
+ }
270
+ if ("ExportAllDeclaration" === node.type) return {
271
+ path: source,
272
+ isExport: true,
273
+ isSideEffect: false,
274
+ importContents: [],
275
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
276
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0,
277
+ start,
278
+ end
279
+ };
280
+ const importContents = parseExportSpecifiers(node);
281
+ return {
282
+ path: source,
283
+ isExport: true,
284
+ isSideEffect: false,
285
+ importContents,
286
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
287
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0,
288
+ start,
289
+ end
290
+ };
291
+ }
292
+ function parseImportSpecifiers(node, isTypeOnlyImport = false) {
293
+ const contents = [];
294
+ for (const specifier of node.specifiers){
295
+ const leadingComments = [];
296
+ const trailingComments = [];
297
+ if (specifier.leadingComments) {
298
+ for (const comment of specifier.leadingComments)if ("CommentLine" === comment.type) leadingComments.push(`//${comment.value}`);
299
+ else if ("CommentBlock" === comment.type) leadingComments.push(`/*${comment.value}*/`);
300
+ }
301
+ if (specifier.trailingComments) {
302
+ for (const comment of specifier.trailingComments)if ("CommentLine" === comment.type) trailingComments.push(`//${comment.value}`);
303
+ else if ("CommentBlock" === comment.type) trailingComments.push(`/*${comment.value}*/`);
304
+ }
305
+ if ("ImportDefaultSpecifier" === specifier.type) contents.push({
306
+ name: "default",
307
+ alias: specifier.local.name,
308
+ type: isTypeOnlyImport ? "type" : "variable",
309
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
310
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
311
+ });
312
+ else if ("ImportNamespaceSpecifier" === specifier.type) contents.push({
313
+ name: "*",
314
+ alias: specifier.local.name,
315
+ type: isTypeOnlyImport ? "type" : "variable",
316
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
317
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
318
+ });
319
+ else if ("ImportSpecifier" === specifier.type) {
320
+ const importedName = "Identifier" === specifier.imported.type ? specifier.imported.name : specifier.imported.value;
321
+ const localName = specifier.local.name;
322
+ const isTypeImport = isTypeOnlyImport || "type" === specifier.importKind;
323
+ contents.push({
324
+ name: importedName,
325
+ alias: importedName !== localName ? localName : void 0,
326
+ type: isTypeImport ? "type" : "variable",
327
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
328
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
329
+ });
330
+ }
331
+ }
332
+ return contents;
333
+ }
334
+ function parseExportSpecifiers(node) {
335
+ const contents = [];
336
+ if (!node.specifiers) return contents;
337
+ for (const specifier of node.specifiers)if ("ExportSpecifier" === specifier.type) {
338
+ const leadingComments = [];
339
+ const trailingComments = [];
340
+ if (specifier.leadingComments) {
341
+ for (const comment of specifier.leadingComments)if ("CommentLine" === comment.type) leadingComments.push(`//${comment.value}`);
342
+ else if ("CommentBlock" === comment.type) leadingComments.push(`/*${comment.value}*/`);
343
+ }
344
+ if (specifier.trailingComments) {
345
+ for (const comment of specifier.trailingComments)if ("CommentLine" === comment.type) trailingComments.push(`//${comment.value}`);
346
+ else if ("CommentBlock" === comment.type) trailingComments.push(`/*${comment.value}*/`);
347
+ }
348
+ const localName = "Identifier" === specifier.local.type ? specifier.local.name : specifier.local.value;
349
+ const exportedName = "Identifier" === specifier.exported.type ? specifier.exported.name : specifier.exported.value;
350
+ const isTypeExport = "type" === specifier.exportKind;
351
+ contents.push({
352
+ name: localName,
353
+ alias: localName !== exportedName ? exportedName : void 0,
354
+ type: isTypeExport ? "type" : "variable",
355
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
356
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
357
+ });
358
+ }
359
+ return contents;
360
+ }
361
+ function defaultGetGroup() {
362
+ return "default";
363
+ }
364
+ function defaultSortGroup(a, b) {
365
+ return a.name.localeCompare(b.name);
366
+ }
367
+ function getImportType(path) {
368
+ if (path.startsWith("./") || path.startsWith("../")) return "relative";
369
+ if (path.startsWith("@/") || path.startsWith("~/") || path.startsWith("#/")) return "alias";
370
+ if (path.startsWith("/")) return "alias";
371
+ return "module";
372
+ }
373
+ function getImportTypePriority(type) {
374
+ switch(type){
375
+ case "module":
376
+ return 0;
377
+ case "alias":
378
+ return 1;
379
+ case "relative":
380
+ return 2;
381
+ }
382
+ }
383
+ function defaultSortImportStatement(a, b) {
384
+ const aType = getImportType(a.path);
385
+ const bType = getImportType(b.path);
386
+ const aPriority = getImportTypePriority(aType);
387
+ const bPriority = getImportTypePriority(bType);
388
+ if (aPriority !== bPriority) return aPriority - bPriority;
389
+ return a.path.localeCompare(b.path);
390
+ }
391
+ function defaultSortImportContent(a, b) {
392
+ if ("type" === a.type && "type" !== b.type) return -1;
393
+ if ("type" !== a.type && "type" === b.type) return 1;
394
+ const aName = a.alias ?? a.name;
395
+ const bName = b.alias ?? b.name;
396
+ return aName.localeCompare(bName);
397
+ }
398
+ const DEFAULT_CONFIG = {
399
+ getGroup: defaultGetGroup,
400
+ sortGroup: defaultSortGroup,
401
+ sortImportStatement: defaultSortImportStatement,
402
+ sortImportContent: defaultSortImportContent,
403
+ sortSideEffect: false
404
+ };
405
+ function mergeConfig(userConfig) {
406
+ return {
407
+ getGroup: userConfig.getGroup ?? DEFAULT_CONFIG.getGroup,
408
+ sortGroup: userConfig.sortGroup ?? DEFAULT_CONFIG.sortGroup,
409
+ sortImportStatement: userConfig.sortImportStatement ?? DEFAULT_CONFIG.sortImportStatement,
410
+ sortImportContent: userConfig.sortImportContent ?? DEFAULT_CONFIG.sortImportContent,
411
+ separator: userConfig.separator,
412
+ sortSideEffect: userConfig.sortSideEffect ?? DEFAULT_CONFIG.sortSideEffect,
413
+ removeUnusedImports: userConfig.removeUnusedImports ?? false
414
+ };
415
+ }
416
+ function sortImports(imports, userConfig) {
417
+ const config = mergeConfig(userConfig);
418
+ if (!config.sortSideEffect) return sortImportsWithSideEffectSeparators(imports, config);
419
+ const groups = groupImports(imports, config);
420
+ const sortedGroups = sortGroups(groups, config);
421
+ const result = [];
422
+ for (const group of sortedGroups){
423
+ const sortedStatements = sortImportStatements(group.importStatements, config);
424
+ for (const statement of sortedStatements){
425
+ const sortedContents = sortImportContents(statement.importContents, config);
426
+ result.push({
427
+ ...statement,
428
+ importContents: sortedContents
429
+ });
430
+ }
431
+ }
432
+ return result;
433
+ }
434
+ function sortImportsWithSideEffectSeparators(imports, config) {
435
+ const result = [];
436
+ const chunks = [];
437
+ let currentChunk = [];
438
+ for (const statement of imports)if (statement.isSideEffect) {
439
+ if (currentChunk.length > 0) {
440
+ chunks.push(currentChunk);
441
+ currentChunk = [];
442
+ }
443
+ chunks.push([
444
+ statement
445
+ ]);
446
+ } else currentChunk.push(statement);
447
+ if (currentChunk.length > 0) chunks.push(currentChunk);
448
+ for (const chunk of chunks){
449
+ if (1 === chunk.length && chunk[0].isSideEffect) {
450
+ result.push(chunk[0]);
451
+ continue;
452
+ }
453
+ const groups = groupImports(chunk, config);
454
+ const sortedGroups = sortGroups(groups, config);
455
+ for (const group of sortedGroups){
456
+ const sortedStatements = sortImportStatements(group.importStatements, config);
457
+ for (const statement of sortedStatements){
458
+ const sortedContents = sortImportContents(statement.importContents, config);
459
+ result.push({
460
+ ...statement,
461
+ importContents: sortedContents
462
+ });
463
+ }
464
+ }
465
+ }
466
+ return result;
467
+ }
468
+ function groupImports(imports, userConfig) {
469
+ const config = mergeConfig(userConfig);
470
+ const groupMap = new Map();
471
+ for (const statement of imports){
472
+ const groupName = config.getGroup(statement);
473
+ const statements = groupMap.get(groupName) ?? [];
474
+ statements.push(statement);
475
+ groupMap.set(groupName, statements);
476
+ }
477
+ const groups = [];
478
+ for (const [name, statements] of Array.from(groupMap.entries())){
479
+ const isSideEffect = statements.every((s)=>s.isSideEffect);
480
+ groups.push({
481
+ name,
482
+ isSideEffect,
483
+ importStatements: statements
484
+ });
485
+ }
486
+ return groups;
487
+ }
488
+ function sortGroups(groups, userConfig) {
489
+ const config = mergeConfig(userConfig);
490
+ return [
491
+ ...groups
492
+ ].sort(config.sortGroup);
493
+ }
494
+ function sortImportStatements(statements, userConfig) {
495
+ const config = mergeConfig(userConfig);
496
+ return [
497
+ ...statements
498
+ ].sort(config.sortImportStatement);
499
+ }
500
+ function sortImportContents(contents, userConfig) {
501
+ const config = mergeConfig(userConfig);
502
+ if (userConfig.sortImportContent) return [
503
+ ...contents
504
+ ].sort(config.sortImportContent);
505
+ const defaultImport = contents.filter((c)=>"default" === c.name);
506
+ const namespaceImport = contents.filter((c)=>"*" === c.name);
507
+ const namedImports = contents.filter((c)=>"default" !== c.name && "*" !== c.name);
508
+ return [
509
+ ...defaultImport,
510
+ ...namespaceImport,
511
+ ...namedImports.sort(config.sortImportContent)
512
+ ];
513
+ }
514
+ function mergeImports(imports) {
515
+ const mergedMap = new Map();
516
+ for (const statement of imports){
517
+ if (statement.isSideEffect) {
518
+ const key = `${statement.path}|||${statement.isExport}|||sideEffect|||${statement.start}`;
519
+ mergedMap.set(key, statement);
520
+ continue;
521
+ }
522
+ const hasNamespaceImport = statement.importContents.some((c)=>"*" === c.name);
523
+ if (hasNamespaceImport) {
524
+ const key = `${statement.path}|||${statement.isExport}|||namespace|||${statement.start}`;
525
+ mergedMap.set(key, statement);
526
+ continue;
527
+ }
528
+ const key = `${statement.path}|||${statement.isExport}`;
529
+ const existing = mergedMap.get(key);
530
+ if (existing) {
531
+ const mergedContents = [
532
+ ...existing.importContents
533
+ ];
534
+ for (const content of statement.importContents){
535
+ const existingContent = mergedContents.find((c)=>c.name === content.name && c.alias === content.alias);
536
+ if (existingContent) {
537
+ if (content.leadingComments) existingContent.leadingComments = [
538
+ ...existingContent.leadingComments ?? [],
539
+ ...content.leadingComments
540
+ ];
541
+ if (content.trailingComments) existingContent.trailingComments = [
542
+ ...existingContent.trailingComments ?? [],
543
+ ...content.trailingComments
544
+ ];
545
+ } else mergedContents.push(content);
546
+ }
547
+ const mergedLeadingComments = [
548
+ ...existing.leadingComments ?? [],
549
+ ...statement.leadingComments ?? []
550
+ ];
551
+ const mergedTrailingComments = existing.trailingComments ?? [];
552
+ const removedTrailingComments = [
553
+ ...existing.removedTrailingComments ?? [],
554
+ ...statement.trailingComments ?? []
555
+ ];
556
+ mergedMap.set(key, {
557
+ ...existing,
558
+ importContents: mergedContents,
559
+ leadingComments: mergedLeadingComments.length > 0 ? mergedLeadingComments : void 0,
560
+ trailingComments: mergedTrailingComments.length > 0 ? mergedTrailingComments : void 0,
561
+ removedTrailingComments: removedTrailingComments.length > 0 ? removedTrailingComments : void 0
562
+ });
563
+ } else mergedMap.set(key, {
564
+ ...statement
565
+ });
566
+ }
567
+ return Array.from(mergedMap.values());
568
+ }
569
+ const src_require = (0, external_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
570
+ let src_userConfig = {};
571
+ function preprocessImports(text, options) {
572
+ try {
573
+ const imports = parseImports(text);
574
+ if (0 === imports.length) return text;
575
+ const config = {
576
+ getGroup: src_userConfig.getGroup ?? options.getGroup,
577
+ sortGroup: src_userConfig.sortGroup ?? options.sortGroup,
578
+ sortImportStatement: src_userConfig.sortImportStatement ?? options.sortImportStatement,
579
+ sortImportContent: src_userConfig.sortImportContent ?? options.sortImportContent,
580
+ separator: src_userConfig.separator ?? options.importSortSeparator ?? options.separator,
581
+ sortSideEffect: src_userConfig.sortSideEffect ?? options.importSortSideEffect ?? false,
582
+ removeUnusedImports: src_userConfig.removeUnusedImports ?? options.importSortRemoveUnused ?? false
583
+ };
584
+ let processedImports = imports;
585
+ if (config.removeUnusedImports) {
586
+ const lastImport = imports[imports.length - 1];
587
+ const codeAfterImports = text.slice(lastImport.end ?? 0);
588
+ processedImports = removeUnusedImportsFromStatements(imports, codeAfterImports);
589
+ }
590
+ const sortedImports = sortImports(processedImports, config);
591
+ const mergedImports = mergeImports(sortedImports);
592
+ let formattedImports;
593
+ if (config.getGroup) {
594
+ const groups = groupImports(mergedImports, config);
595
+ const sortedGroups = sortGroups(groups, config);
596
+ formattedImports = formatGroups(sortedGroups, config);
597
+ } else formattedImports = formatImportStatements(mergedImports);
598
+ const firstImport = imports[0];
599
+ const lastImport = imports[imports.length - 1];
600
+ const startIndex = firstImport.start ?? 0;
601
+ const endIndex = lastImport.end ?? text.length;
602
+ const beforeImports = text.slice(0, startIndex);
603
+ const afterImports = text.slice(endIndex);
604
+ const needsExtraNewline = afterImports && !afterImports.startsWith("\n");
605
+ const separator = needsExtraNewline ? "\n\n" : "\n";
606
+ return beforeImports + formattedImports + separator + afterImports;
607
+ } catch (error) {
608
+ console.error("Failed to sort imports:", error);
609
+ return text;
610
+ }
611
+ }
612
+ const babelParser = src_require("prettier/parser-babel").parsers.babel;
613
+ const typescriptParser = src_require("prettier/parser-typescript").parsers.typescript;
614
+ const babelTsParser = src_require("prettier/parser-babel").parsers["babel-ts"];
615
+ function createPluginInstance() {
616
+ return {
617
+ parsers: {
618
+ babel: {
619
+ ...babelParser,
620
+ preprocess: preprocessImports
621
+ },
622
+ typescript: {
623
+ ...typescriptParser,
624
+ preprocess: preprocessImports
625
+ },
626
+ "babel-ts": {
627
+ ...babelTsParser,
628
+ preprocess: preprocessImports
629
+ }
630
+ },
631
+ options: {
632
+ importSortSeparator: {
633
+ type: "string",
634
+ category: "Import Sort",
635
+ description: "分组之间的分隔符"
636
+ },
637
+ importSortSideEffect: {
638
+ type: "boolean",
639
+ category: "Import Sort",
640
+ description: "是否对副作用导入进行排序",
641
+ default: false
642
+ },
643
+ importSortRemoveUnused: {
644
+ type: "boolean",
645
+ category: "Import Sort",
646
+ description: "是否删除未使用的导入",
647
+ default: false
648
+ }
649
+ }
650
+ };
651
+ }
652
+ const src_plugin = createPluginInstance();
653
+ function createPlugin(config = {}) {
654
+ src_userConfig = config;
655
+ return createPluginInstance();
656
+ }
657
+ const src = src_plugin;
658
+ exports.createPlugin = __webpack_exports__.createPlugin;
659
+ exports["default"] = __webpack_exports__["default"];
660
+ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
661
+ "createPlugin",
662
+ "default"
663
+ ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
664
+ Object.defineProperty(exports, '__esModule', {
665
+ value: true
666
+ });
package/dist/index.js CHANGED
@@ -72,16 +72,20 @@ function removeUnusedImportsFromStatements(importStatements, code) {
72
72
  return filteredStatements;
73
73
  }
74
74
  function formatImportStatement(statement) {
75
- const { path, isExport, isSideEffect, importContents, leadingComments } = statement;
75
+ const { path, isExport, isSideEffect, importContents, leadingComments, trailingComments, removedTrailingComments } = statement;
76
76
  const lines = [];
77
77
  if (leadingComments && leadingComments.length > 0) lines.push(...leadingComments);
78
78
  if (isSideEffect) {
79
- if (isExport) lines.push(`export * from "${path}"`);
80
- else lines.push(`import "${path}"`);
79
+ let importLine = "";
80
+ importLine = isExport ? `export * from "${path}"` : `import "${path}"`;
81
+ if (trailingComments && trailingComments.length > 0) importLine += ` ${trailingComments.join(" ")}`;
82
+ lines.push(importLine);
81
83
  return lines.join("\n");
82
84
  }
85
+ const hasNamedImportComments = importContents.some((content)=>"default" !== content.name && "*" !== content.name && (content.leadingComments && content.leadingComments.length > 0 || content.trailingComments && content.trailingComments.length > 0));
83
86
  const parts = [];
84
87
  const namedParts = [];
88
+ const namedPartsWithComments = [];
85
89
  for (const content of importContents){
86
90
  if ("default" === content.name) {
87
91
  parts.push(content.alias ?? "default");
@@ -92,13 +96,45 @@ function formatImportStatement(statement) {
92
96
  continue;
93
97
  }
94
98
  const typePrefix = "type" === content.type ? "type " : "";
95
- if (content.alias) namedParts.push(`${typePrefix}${content.name} as ${content.alias}`);
96
- else namedParts.push(`${typePrefix}${content.name}`);
99
+ let importItem = "";
100
+ importItem = content.alias ? `${typePrefix}${content.name} as ${content.alias}` : `${typePrefix}${content.name}`;
101
+ if (hasNamedImportComments) {
102
+ const itemLines = [];
103
+ if (content.leadingComments && content.leadingComments.length > 0) itemLines.push(...content.leadingComments);
104
+ let itemLine = importItem;
105
+ if (content.trailingComments && content.trailingComments.length > 0) itemLine += ` ${content.trailingComments.join(" ")}`;
106
+ itemLines.push(itemLine);
107
+ namedPartsWithComments.push(itemLines.join("\n "));
108
+ } else namedParts.push(importItem);
109
+ }
110
+ const namedImports = importContents.filter((c)=>"default" !== c.name && "*" !== c.name);
111
+ const allNamedImportsAreTypes = namedImports.every((c)=>"type" === c.type);
112
+ const hasDefaultOrNamespace = importContents.some((c)=>"default" === c.name || "*" === c.name);
113
+ if (hasNamedImportComments && namedPartsWithComments.length > 0) {
114
+ const keyword = isExport ? "export" : "import";
115
+ const typeKeyword = allNamedImportsAreTypes && !hasDefaultOrNamespace ? "type " : "";
116
+ const defaultPart = parts.length > 0 ? parts.join(", ") + ", " : "";
117
+ const importStart = `${keyword} ${typeKeyword}${defaultPart}{`;
118
+ const importEnd = `} from "${path}"`;
119
+ lines.push(importStart);
120
+ lines.push(` ${namedPartsWithComments.join(",\n ")},`);
121
+ lines.push(importEnd);
122
+ } else {
123
+ if (namedParts.length > 0) if (allNamedImportsAreTypes && !hasDefaultOrNamespace) {
124
+ const cleanedParts = namedParts.map((part)=>part.replace(/^type /, ""));
125
+ parts.push(`{ ${cleanedParts.join(", ")} }`);
126
+ } else parts.push(`{ ${namedParts.join(", ")} }`);
127
+ const importClause = parts.join(", ");
128
+ const typeKeyword = allNamedImportsAreTypes && !hasDefaultOrNamespace ? "type " : "";
129
+ let importLine = "";
130
+ importLine = isExport ? `export ${typeKeyword}${importClause} from "${path}"` : `import ${typeKeyword}${importClause} from "${path}"`;
131
+ if (trailingComments && trailingComments.length > 0) importLine += ` ${trailingComments.join(" ")}`;
132
+ lines.push(importLine);
133
+ }
134
+ if (removedTrailingComments && removedTrailingComments.length > 0) {
135
+ lines.push("");
136
+ lines.push(...removedTrailingComments);
97
137
  }
98
- if (namedParts.length > 0) parts.push(`{ ${namedParts.join(", ")} }`);
99
- const importClause = parts.join(", ");
100
- if (isExport) lines.push(`export ${importClause} from "${path}"`);
101
- else lines.push(`import ${importClause} from "${path}"`);
102
138
  return lines.join("\n");
103
139
  }
104
140
  function formatGroups(groups, config) {
@@ -128,30 +164,55 @@ function parseImports(code) {
128
164
  "typescript",
129
165
  "jsx"
130
166
  ],
131
- errorRecovery: true
167
+ errorRecovery: true,
168
+ attachComment: true
132
169
  });
133
170
  const importStatements = [];
134
171
  const { body } = ast.program;
172
+ const usedComments = new Set();
135
173
  for (const node of body)if ("ImportDeclaration" === node.type || "ExportNamedDeclaration" === node.type && node.source || "ExportAllDeclaration" === node.type) {
136
- const statement = parseImportNode(node, ast.comments ?? []);
174
+ const statement = parseImportNode(node, ast.comments ?? [], usedComments);
137
175
  importStatements.push(statement);
138
176
  } else break;
139
177
  return importStatements;
140
178
  }
141
- function parseImportNode(node, comments) {
179
+ function parseImportNode(node, comments, usedComments) {
142
180
  node.type;
143
181
  const source = node.source?.value ?? "";
182
+ node.loc?.start.line;
183
+ node.loc?.end.line;
184
+ const nodeStart = node.start ?? 0;
185
+ let nodeEnd = node.end ?? 0;
144
186
  const leadingComments = [];
145
- let start = node.start ?? 0;
187
+ const trailingComments = [];
188
+ let start = nodeStart;
146
189
  if (node.leadingComments) {
147
- const firstComment = node.leadingComments[0];
148
- if (null !== firstComment.start && void 0 !== firstComment.start) start = firstComment.start;
149
- for (const comment of node.leadingComments)if ("CommentLine" === comment.type) leadingComments.push(`//${comment.value}`);
150
- else if ("CommentBlock" === comment.type) leadingComments.push(`/*${comment.value}*/`);
190
+ for (const comment of node.leadingComments)if (!usedComments.has(comment)) {
191
+ if ("CommentLine" === comment.type) leadingComments.push(`//${comment.value}`);
192
+ else if ("CommentBlock" === comment.type) leadingComments.push(`/*${comment.value}*/`);
193
+ const commentStart = comment.start ?? 0;
194
+ if (commentStart < start) start = commentStart;
195
+ usedComments.add(comment);
196
+ }
197
+ }
198
+ if (node.trailingComments) {
199
+ for (const comment of node.trailingComments)if (!usedComments.has(comment)) {
200
+ const commentLoc = comment.loc;
201
+ const nodeLoc = node.loc;
202
+ const isSameLine = commentLoc && nodeLoc && commentLoc.start.line === nodeLoc.end.line;
203
+ if (isSameLine) {
204
+ if ("CommentLine" === comment.type) trailingComments.push(`//${comment.value}`);
205
+ else if ("CommentBlock" === comment.type) trailingComments.push(`/*${comment.value}*/`);
206
+ const commentEnd = comment.end ?? 0;
207
+ if (commentEnd > nodeEnd) nodeEnd = commentEnd;
208
+ usedComments.add(comment);
209
+ }
210
+ }
151
211
  }
152
- const end = node.end ?? 0;
212
+ const end = nodeEnd;
153
213
  if ("ImportDeclaration" === node.type) {
154
- const importContents = parseImportSpecifiers(node);
214
+ const isTypeOnlyImport = "type" === node.importKind;
215
+ const importContents = parseImportSpecifiers(node, isTypeOnlyImport);
155
216
  const isSideEffect = 0 === importContents.length;
156
217
  return {
157
218
  path: source,
@@ -159,6 +220,7 @@ function parseImportNode(node, comments) {
159
220
  isSideEffect,
160
221
  importContents,
161
222
  leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
223
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0,
162
224
  start,
163
225
  end
164
226
  };
@@ -169,6 +231,7 @@ function parseImportNode(node, comments) {
169
231
  isSideEffect: false,
170
232
  importContents: [],
171
233
  leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
234
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0,
172
235
  start,
173
236
  end
174
237
  };
@@ -179,31 +242,50 @@ function parseImportNode(node, comments) {
179
242
  isSideEffect: false,
180
243
  importContents,
181
244
  leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
245
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0,
182
246
  start,
183
247
  end
184
248
  };
185
249
  }
186
- function parseImportSpecifiers(node) {
250
+ function parseImportSpecifiers(node, isTypeOnlyImport = false) {
187
251
  const contents = [];
188
- for (const specifier of node.specifiers)if ("ImportDefaultSpecifier" === specifier.type) contents.push({
189
- name: "default",
190
- alias: specifier.local.name,
191
- type: "variable"
192
- });
193
- else if ("ImportNamespaceSpecifier" === specifier.type) contents.push({
194
- name: "*",
195
- alias: specifier.local.name,
196
- type: "variable"
197
- });
198
- else if ("ImportSpecifier" === specifier.type) {
199
- const importedName = "Identifier" === specifier.imported.type ? specifier.imported.name : specifier.imported.value;
200
- const localName = specifier.local.name;
201
- const isTypeImport = "type" === specifier.importKind;
202
- contents.push({
203
- name: importedName,
204
- alias: importedName !== localName ? localName : void 0,
205
- type: isTypeImport ? "type" : "variable"
252
+ for (const specifier of node.specifiers){
253
+ const leadingComments = [];
254
+ const trailingComments = [];
255
+ if (specifier.leadingComments) {
256
+ for (const comment of specifier.leadingComments)if ("CommentLine" === comment.type) leadingComments.push(`//${comment.value}`);
257
+ else if ("CommentBlock" === comment.type) leadingComments.push(`/*${comment.value}*/`);
258
+ }
259
+ if (specifier.trailingComments) {
260
+ for (const comment of specifier.trailingComments)if ("CommentLine" === comment.type) trailingComments.push(`//${comment.value}`);
261
+ else if ("CommentBlock" === comment.type) trailingComments.push(`/*${comment.value}*/`);
262
+ }
263
+ if ("ImportDefaultSpecifier" === specifier.type) contents.push({
264
+ name: "default",
265
+ alias: specifier.local.name,
266
+ type: isTypeOnlyImport ? "type" : "variable",
267
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
268
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
206
269
  });
270
+ else if ("ImportNamespaceSpecifier" === specifier.type) contents.push({
271
+ name: "*",
272
+ alias: specifier.local.name,
273
+ type: isTypeOnlyImport ? "type" : "variable",
274
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
275
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
276
+ });
277
+ else if ("ImportSpecifier" === specifier.type) {
278
+ const importedName = "Identifier" === specifier.imported.type ? specifier.imported.name : specifier.imported.value;
279
+ const localName = specifier.local.name;
280
+ const isTypeImport = isTypeOnlyImport || "type" === specifier.importKind;
281
+ contents.push({
282
+ name: importedName,
283
+ alias: importedName !== localName ? localName : void 0,
284
+ type: isTypeImport ? "type" : "variable",
285
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
286
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
287
+ });
288
+ }
207
289
  }
208
290
  return contents;
209
291
  }
@@ -211,13 +293,25 @@ function parseExportSpecifiers(node) {
211
293
  const contents = [];
212
294
  if (!node.specifiers) return contents;
213
295
  for (const specifier of node.specifiers)if ("ExportSpecifier" === specifier.type) {
296
+ const leadingComments = [];
297
+ const trailingComments = [];
298
+ if (specifier.leadingComments) {
299
+ for (const comment of specifier.leadingComments)if ("CommentLine" === comment.type) leadingComments.push(`//${comment.value}`);
300
+ else if ("CommentBlock" === comment.type) leadingComments.push(`/*${comment.value}*/`);
301
+ }
302
+ if (specifier.trailingComments) {
303
+ for (const comment of specifier.trailingComments)if ("CommentLine" === comment.type) trailingComments.push(`//${comment.value}`);
304
+ else if ("CommentBlock" === comment.type) trailingComments.push(`/*${comment.value}*/`);
305
+ }
214
306
  const localName = "Identifier" === specifier.local.type ? specifier.local.name : specifier.local.value;
215
307
  const exportedName = "Identifier" === specifier.exported.type ? specifier.exported.name : specifier.exported.value;
216
308
  const isTypeExport = "type" === specifier.exportKind;
217
309
  contents.push({
218
310
  name: localName,
219
311
  alias: localName !== exportedName ? exportedName : void 0,
220
- type: isTypeExport ? "type" : "variable"
312
+ type: isTypeExport ? "type" : "variable",
313
+ leadingComments: leadingComments.length > 0 ? leadingComments : void 0,
314
+ trailingComments: trailingComments.length > 0 ? trailingComments : void 0
221
315
  });
222
316
  }
223
317
  return contents;
@@ -375,6 +469,61 @@ function sortImportContents(contents, userConfig) {
375
469
  ...namedImports.sort(config.sortImportContent)
376
470
  ];
377
471
  }
472
+ function mergeImports(imports) {
473
+ const mergedMap = new Map();
474
+ for (const statement of imports){
475
+ if (statement.isSideEffect) {
476
+ const key = `${statement.path}|||${statement.isExport}|||sideEffect|||${statement.start}`;
477
+ mergedMap.set(key, statement);
478
+ continue;
479
+ }
480
+ const hasNamespaceImport = statement.importContents.some((c)=>"*" === c.name);
481
+ if (hasNamespaceImport) {
482
+ const key = `${statement.path}|||${statement.isExport}|||namespace|||${statement.start}`;
483
+ mergedMap.set(key, statement);
484
+ continue;
485
+ }
486
+ const key = `${statement.path}|||${statement.isExport}`;
487
+ const existing = mergedMap.get(key);
488
+ if (existing) {
489
+ const mergedContents = [
490
+ ...existing.importContents
491
+ ];
492
+ for (const content of statement.importContents){
493
+ const existingContent = mergedContents.find((c)=>c.name === content.name && c.alias === content.alias);
494
+ if (existingContent) {
495
+ if (content.leadingComments) existingContent.leadingComments = [
496
+ ...existingContent.leadingComments ?? [],
497
+ ...content.leadingComments
498
+ ];
499
+ if (content.trailingComments) existingContent.trailingComments = [
500
+ ...existingContent.trailingComments ?? [],
501
+ ...content.trailingComments
502
+ ];
503
+ } else mergedContents.push(content);
504
+ }
505
+ const mergedLeadingComments = [
506
+ ...existing.leadingComments ?? [],
507
+ ...statement.leadingComments ?? []
508
+ ];
509
+ const mergedTrailingComments = existing.trailingComments ?? [];
510
+ const removedTrailingComments = [
511
+ ...existing.removedTrailingComments ?? [],
512
+ ...statement.trailingComments ?? []
513
+ ];
514
+ mergedMap.set(key, {
515
+ ...existing,
516
+ importContents: mergedContents,
517
+ leadingComments: mergedLeadingComments.length > 0 ? mergedLeadingComments : void 0,
518
+ trailingComments: mergedTrailingComments.length > 0 ? mergedTrailingComments : void 0,
519
+ removedTrailingComments: removedTrailingComments.length > 0 ? removedTrailingComments : void 0
520
+ });
521
+ } else mergedMap.set(key, {
522
+ ...statement
523
+ });
524
+ }
525
+ return Array.from(mergedMap.values());
526
+ }
378
527
  const src_require = createRequire(import.meta.url);
379
528
  let src_userConfig = {};
380
529
  function preprocessImports(text, options) {
@@ -397,19 +546,22 @@ function preprocessImports(text, options) {
397
546
  processedImports = removeUnusedImportsFromStatements(imports, codeAfterImports);
398
547
  }
399
548
  const sortedImports = sortImports(processedImports, config);
549
+ const mergedImports = mergeImports(sortedImports);
400
550
  let formattedImports;
401
551
  if (config.getGroup) {
402
- const groups = groupImports(sortedImports, config);
552
+ const groups = groupImports(mergedImports, config);
403
553
  const sortedGroups = sortGroups(groups, config);
404
554
  formattedImports = formatGroups(sortedGroups, config);
405
- } else formattedImports = formatImportStatements(sortedImports);
555
+ } else formattedImports = formatImportStatements(mergedImports);
406
556
  const firstImport = imports[0];
407
557
  const lastImport = imports[imports.length - 1];
408
558
  const startIndex = firstImport.start ?? 0;
409
559
  const endIndex = lastImport.end ?? text.length;
410
560
  const beforeImports = text.slice(0, startIndex);
411
561
  const afterImports = text.slice(endIndex);
412
- return beforeImports + formattedImports + "\n" + afterImports;
562
+ const needsExtraNewline = afterImports && !afterImports.startsWith("\n");
563
+ const separator = needsExtraNewline ? "\n\n" : "\n";
564
+ return beforeImports + formattedImports + separator + afterImports;
413
565
  } catch (error) {
414
566
  console.error("Failed to sort imports:", error);
415
567
  return text;
package/dist/parser.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- import { ImportStatement } from "./types";
2
- /** 解析导入语句 */
1
+ import { ImportStatement } from "./types"; /** 解析导入语句 */
3
2
  export declare function parseImports(code: string): ImportStatement[];
package/dist/sorter.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Group, ImportContent, ImportStatement, PluginConfig } from "./types";
1
+ import { Group, ImportContent, ImportStatement, PluginConfig } from "./types"; /** 导入类型 */
2
2
  /** 合并后的配置 */
3
3
  export interface MergedConfig extends Omit<Required<PluginConfig>, "separator" | "removeUnusedImports"> {
4
4
  separator: PluginConfig["separator"];
@@ -14,3 +14,5 @@ export declare function sortGroups(groups: Group[], userConfig: PluginConfig): G
14
14
  export declare function sortImportStatements(statements: ImportStatement[], userConfig: PluginConfig): ImportStatement[];
15
15
  /** 对导入内容进行排序 */
16
16
  export declare function sortImportContents(contents: ImportContent[], userConfig: PluginConfig): ImportContent[];
17
+ /** 合并来自同一模块的导入语句 */
18
+ export declare function mergeImports(imports: ImportStatement[]): ImportStatement[];
package/dist/types.d.ts CHANGED
@@ -6,6 +6,10 @@ export interface ImportContent {
6
6
  alias?: string;
7
7
  /** 导入的内容的类型,只有明确在导入前加入了 type 标记的才属于 type 类型,没有明确的加入 type 标记的都属于 variable 类型 */
8
8
  type: "type" | "variable";
9
+ /** 导入内容上方的注释 */
10
+ leadingComments?: string[];
11
+ /** 导入内容后方的行尾注释 */
12
+ trailingComments?: string[];
9
13
  }
10
14
  /** 导入语句 */
11
15
  export interface ImportStatement {
@@ -19,6 +23,10 @@ export interface ImportStatement {
19
23
  importContents: ImportContent[];
20
24
  /** 导入语句上方的注释 */
21
25
  leadingComments?: string[];
26
+ /** 导入语句后方的行尾注释 */
27
+ trailingComments?: string[];
28
+ /** 被移除的导入语句的行尾注释(合并时使用) */
29
+ removedTrailingComments?: string[];
22
30
  /** 在源代码中的起始位置(包括注释) */
23
31
  start?: number;
24
32
  /** 在源代码中的结束位置 */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@1adybug/prettier-plugin-sort-imports",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "description": "一个 Prettier 插件,用于对 JavaScript/TypeScript 文件的导入语句进行分组和排序",
6
6
  "keywords": [
7
7
  "prettier",
@@ -30,9 +30,12 @@
30
30
  "exports": {
31
31
  ".": {
32
32
  "types": "./dist/index.d.ts",
33
- "import": "./dist/index.js"
33
+ "import": "./dist/index.js",
34
+ "require": "./dist/index.cjs"
34
35
  }
35
36
  },
37
+ "main": "./dist/index.cjs",
38
+ "module": "./dist/index.js",
36
39
  "types": "./dist/index.d.ts",
37
40
  "files": [
38
41
  "dist"
@@ -41,11 +44,14 @@
41
44
  "build": "rslib build",
42
45
  "dev": "rslib build --watch",
43
46
  "prepublishOnly": "npm run build",
44
- "format": "prettier --config prettier.config.mjs --write ."
47
+ "format": "prettier --config prettier.config.mjs --write .",
48
+ "test": "bun test",
49
+ "test:watch": "bun test --watch"
45
50
  },
46
51
  "devDependencies": {
47
52
  "@rslib/core": "^0.15.0",
48
53
  "@types/babel__core": "^7.20.5",
54
+ "@types/bun": "latest",
49
55
  "@types/node": "^22.18.6",
50
56
  "prettier": "^3.6.2",
51
57
  "supports-color": "^10.2.2",