@1adybug/prettier-plugin-sort-imports 0.0.5 → 0.0.7
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 +176 -37
- package/README.zh-CN.md +137 -29
- package/dist/index.d.ts +3 -3
- package/dist/index.js +107 -88
- package/dist/parser.d.ts +2 -1
- package/dist/sorter.d.ts +2 -2
- package/dist/types.d.ts +5 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -13,13 +13,14 @@ A powerful Prettier plugin for intelligently grouping and sorting import stateme
|
|
|
13
13
|
- ✅ **Side Effect Handling**: Configurable sorting behavior for side effect imports
|
|
14
14
|
- ✅ **Unused Import Removal**: Optional automatic removal of unused imports
|
|
15
15
|
- ✅ **Factory Function Pattern**: Support for custom functions in configuration files
|
|
16
|
+
- ✅ **Tailwind CSS Integration**: Compatible with `prettier-plugin-tailwindcss`
|
|
16
17
|
|
|
17
18
|
## Quick Start
|
|
18
19
|
|
|
19
20
|
### Installation
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
|
-
npm install prettier-plugin-
|
|
23
|
+
npm install @1adybug/prettier-plugin-sort-imports --save-dev
|
|
23
24
|
```
|
|
24
25
|
|
|
25
26
|
### Basic Configuration
|
|
@@ -28,7 +29,7 @@ Add the plugin to your `prettier.config.mjs`:
|
|
|
28
29
|
|
|
29
30
|
```javascript
|
|
30
31
|
export default {
|
|
31
|
-
plugins: ["prettier-plugin-
|
|
32
|
+
plugins: ["@1adybug/prettier-plugin-sort-imports"],
|
|
32
33
|
}
|
|
33
34
|
```
|
|
34
35
|
|
|
@@ -50,7 +51,7 @@ npx prettier --write "src/**/*.{js,ts,jsx,tsx}"
|
|
|
50
51
|
|
|
51
52
|
```javascript
|
|
52
53
|
// prettier.config.mjs
|
|
53
|
-
import { createPlugin } from "prettier-plugin-
|
|
54
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
54
55
|
|
|
55
56
|
export default {
|
|
56
57
|
plugins: [
|
|
@@ -157,40 +158,46 @@ interface PluginConfig {
|
|
|
157
158
|
|
|
158
159
|
### Method 1: Simple Configuration
|
|
159
160
|
|
|
160
|
-
|
|
161
|
+
Use the default plugin with basic options:
|
|
161
162
|
|
|
162
163
|
```javascript
|
|
163
164
|
export default {
|
|
164
|
-
plugins: ["prettier-plugin-
|
|
165
|
+
plugins: ["@1adybug/prettier-plugin-sort-imports"],
|
|
165
166
|
importSortSideEffect: false, // Whether to sort side effect imports
|
|
166
167
|
importSortSeparator: "", // Group separator
|
|
167
168
|
importSortRemoveUnused: false, // Whether to remove unused imports
|
|
168
169
|
}
|
|
169
170
|
```
|
|
170
171
|
|
|
171
|
-
### Method 2: Advanced Configuration
|
|
172
|
+
### Method 2: Advanced Configuration
|
|
172
173
|
|
|
173
|
-
Use `createPlugin` function
|
|
174
|
+
Use `createPlugin` function for full control and plugin compatibility:
|
|
174
175
|
|
|
175
176
|
```javascript
|
|
176
|
-
import { createPlugin } from "prettier-plugin-
|
|
177
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
177
178
|
|
|
178
179
|
export default {
|
|
179
180
|
plugins: [
|
|
180
181
|
createPlugin({
|
|
182
|
+
// Custom sorting functions
|
|
181
183
|
getGroup: statement => {
|
|
182
|
-
|
|
184
|
+
if (statement.path.startsWith("react")) return "react"
|
|
185
|
+
if (!statement.path.startsWith(".")) return "external"
|
|
186
|
+
return "local"
|
|
183
187
|
},
|
|
184
188
|
sortGroup: (a, b) => {
|
|
185
|
-
|
|
189
|
+
const order = ["react", "external", "local"]
|
|
190
|
+
return order.indexOf(a.name) - order.indexOf(b.name)
|
|
186
191
|
},
|
|
187
192
|
sortImportStatement: (a, b) => {
|
|
188
|
-
|
|
193
|
+
return a.path.localeCompare(b.path)
|
|
189
194
|
},
|
|
190
195
|
sortImportContent: (a, b) => {
|
|
191
|
-
|
|
196
|
+
return a.name.localeCompare(b.name)
|
|
192
197
|
},
|
|
193
|
-
|
|
198
|
+
|
|
199
|
+
// Configuration
|
|
200
|
+
separator: "\n",
|
|
194
201
|
sortSideEffect: true,
|
|
195
202
|
removeUnusedImports: false,
|
|
196
203
|
}),
|
|
@@ -198,42 +205,150 @@ export default {
|
|
|
198
205
|
}
|
|
199
206
|
```
|
|
200
207
|
|
|
201
|
-
### Method 3:
|
|
208
|
+
### Method 3: Custom Plugin Module
|
|
202
209
|
|
|
203
|
-
|
|
210
|
+
Create a custom plugin module for better organization and reusability:
|
|
204
211
|
|
|
205
|
-
|
|
206
|
-
// prettier.config.mjs
|
|
207
|
-
export default {
|
|
208
|
-
plugins: ["prettier-plugin-import-sorts"],
|
|
209
|
-
sortImportsConfigPath: "./import-sort.config.js",
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
+
**Step 1**: Create a custom plugin file `prettier-plugin-sort-imports.mjs`:
|
|
212
213
|
|
|
213
214
|
```javascript
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
215
|
+
// prettier-plugin-sort-imports.mjs
|
|
216
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
217
|
+
|
|
218
|
+
export default createPlugin({
|
|
219
|
+
// Custom grouping logic
|
|
220
|
+
getGroup: statement => {
|
|
221
|
+
const path = statement.path
|
|
222
|
+
|
|
223
|
+
// React and related libraries
|
|
224
|
+
if (path.startsWith("react") || path.startsWith("@react")) {
|
|
225
|
+
return "react"
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// UI libraries
|
|
229
|
+
if (path.includes("antd") || path.includes("@mui") || path.includes("chakra")) {
|
|
230
|
+
return "ui"
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Utility libraries
|
|
234
|
+
if (path.includes("lodash") || path.includes("ramda") || path.includes("date-fns")) {
|
|
235
|
+
return "utils"
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// External packages (node_modules)
|
|
239
|
+
if (!path.startsWith(".") && !path.startsWith("@/")) {
|
|
240
|
+
return "external"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Internal aliases (@/)
|
|
244
|
+
if (path.startsWith("@/")) {
|
|
245
|
+
return "internal"
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Relative imports
|
|
249
|
+
return "relative"
|
|
222
250
|
},
|
|
251
|
+
|
|
252
|
+
// Define group order
|
|
223
253
|
sortGroup: (a, b) => {
|
|
224
|
-
const order = ["react", "external", "internal", "relative"]
|
|
254
|
+
const order = ["react", "external", "ui", "utils", "internal", "relative"]
|
|
225
255
|
return order.indexOf(a.name) - order.indexOf(b.name)
|
|
226
256
|
},
|
|
257
|
+
|
|
258
|
+
// Custom import content sorting
|
|
259
|
+
sortImportContent: (a, b) => {
|
|
260
|
+
// Types first, then variables
|
|
261
|
+
if (a.type !== b.type) {
|
|
262
|
+
return a.type === "type" ? -1 : 1
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Alphabetical order within same type
|
|
266
|
+
const aName = a.alias ?? a.name
|
|
267
|
+
const bName = b.alias ?? b.name
|
|
268
|
+
return aName.localeCompare(bName)
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// Add blank lines between groups
|
|
227
272
|
separator: "\n",
|
|
273
|
+
|
|
274
|
+
// Sort side effects
|
|
275
|
+
sortSideEffect: true,
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Step 2**: Use the custom plugin in your `prettier.config.mjs`:
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
// prettier.config.mjs
|
|
283
|
+
export default {
|
|
284
|
+
plugins: ["./prettier-plugin-sort-imports.mjs"],
|
|
285
|
+
// Other prettier options...
|
|
286
|
+
semi: false,
|
|
287
|
+
tabWidth: 4,
|
|
228
288
|
}
|
|
229
289
|
```
|
|
230
290
|
|
|
231
|
-
**
|
|
291
|
+
**Benefits of this approach**:
|
|
292
|
+
|
|
293
|
+
- ✅ **Reusable**: Share the same configuration across multiple projects
|
|
294
|
+
- ✅ **Version Control**: Track your import sorting rules in git
|
|
295
|
+
- ✅ **Maintainable**: Keep complex logic separate from prettier config
|
|
296
|
+
- ✅ **Team Collaboration**: Consistent import sorting rules across team members
|
|
232
297
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
298
|
+
### Method 4: Plugin Compatibility
|
|
299
|
+
|
|
300
|
+
Use `createPlugin` with `otherPlugins` to merge with other Prettier plugins and avoid conflicts:
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
304
|
+
import * as tailwindPlugin from "prettier-plugin-tailwindcss"
|
|
305
|
+
|
|
306
|
+
export default {
|
|
307
|
+
plugins: [
|
|
308
|
+
createPlugin({
|
|
309
|
+
// Your import sorting configuration
|
|
310
|
+
getGroup: statement => {
|
|
311
|
+
if (statement.path.startsWith("react")) return "react"
|
|
312
|
+
if (!statement.path.startsWith(".")) return "external"
|
|
313
|
+
return "local"
|
|
314
|
+
},
|
|
315
|
+
separator: "\n",
|
|
316
|
+
|
|
317
|
+
// Other Prettier plugins to combine with (Plugin objects only)
|
|
318
|
+
otherPlugins: [
|
|
319
|
+
tailwindPlugin, // Import the plugin directly
|
|
320
|
+
// Add more plugins as needed...
|
|
321
|
+
],
|
|
322
|
+
|
|
323
|
+
// Configuration options for other plugins
|
|
324
|
+
prettierOptions: {
|
|
325
|
+
// TailwindCSS plugin options
|
|
326
|
+
tailwindConfig: "./tailwind.config.js",
|
|
327
|
+
tailwindFunctions: ["clsx", "cn", "cva"],
|
|
328
|
+
tailwindAttributes: ["class", "className", "ngClass", ":class"],
|
|
329
|
+
|
|
330
|
+
// Other plugin options can go here...
|
|
331
|
+
},
|
|
332
|
+
}),
|
|
333
|
+
],
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Important Notes:**
|
|
338
|
+
|
|
339
|
+
- `otherPlugins` only accepts imported Plugin objects, not string plugin names
|
|
340
|
+
- You must import the plugins yourself to ensure proper module resolution
|
|
341
|
+
- This approach avoids complex module loading issues and gives you full control
|
|
342
|
+
|
|
343
|
+
**Plugin Execution Order:**
|
|
344
|
+
|
|
345
|
+
- Other plugins are executed in the order they appear in the `otherPlugins` array
|
|
346
|
+
- Import sorting is always executed last to ensure compatibility
|
|
347
|
+
|
|
348
|
+
**Configuration Passing:**
|
|
349
|
+
|
|
350
|
+
- Options in `prettierOptions` are passed to all other plugins
|
|
351
|
+
- This allows other plugins to receive their configuration even when merged
|
|
237
352
|
|
|
238
353
|
### importSortRemoveUnused
|
|
239
354
|
|
|
@@ -427,7 +542,7 @@ Prettier natively cannot accept functions as configuration parameters (because c
|
|
|
427
542
|
|
|
428
543
|
```javascript
|
|
429
544
|
// Factory function is called in config file, returning a plugin instance
|
|
430
|
-
import { createPlugin } from "prettier-plugin-
|
|
545
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
431
546
|
|
|
432
547
|
export default {
|
|
433
548
|
plugins: [
|
|
@@ -443,6 +558,30 @@ export default {
|
|
|
443
558
|
|
|
444
559
|
This maintains configuration flexibility while not violating Prettier's configuration system limitations.
|
|
445
560
|
|
|
561
|
+
## Integration with Other Plugins
|
|
562
|
+
|
|
563
|
+
### Tailwind CSS
|
|
564
|
+
|
|
565
|
+
This plugin works seamlessly with `prettier-plugin-tailwindcss`. For detailed setup instructions, see [TAILWINDCSS_INTEGRATION.md](./TAILWINDCSS_INTEGRATION.md).
|
|
566
|
+
|
|
567
|
+
**Quick Setup:**
|
|
568
|
+
|
|
569
|
+
```javascript
|
|
570
|
+
// prettier.config.mjs
|
|
571
|
+
export default {
|
|
572
|
+
plugins: [
|
|
573
|
+
"@1adybug/prettier-plugin-sort-imports",
|
|
574
|
+
"prettier-plugin-tailwindcss", // Must come last
|
|
575
|
+
],
|
|
576
|
+
tailwindFunctions: ["clsx", "cn", "cva", "tw"],
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
This will:
|
|
581
|
+
|
|
582
|
+
- ✅ Sort and merge your imports
|
|
583
|
+
- ✅ Sort your Tailwind CSS classes according to the recommended order
|
|
584
|
+
|
|
446
585
|
## Notes
|
|
447
586
|
|
|
448
587
|
1. **Only processes consecutive import/export statement blocks at the beginning of files**
|
package/README.zh-CN.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
### 安装
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
npm install prettier-plugin-
|
|
22
|
+
npm install @1adybug/prettier-plugin-sort-imports --save-dev
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
### 基础配置
|
|
@@ -28,7 +28,7 @@ npm install prettier-plugin-import-sorts --save-dev
|
|
|
28
28
|
|
|
29
29
|
```javascript
|
|
30
30
|
export default {
|
|
31
|
-
plugins: ["prettier-plugin-
|
|
31
|
+
plugins: ["@1adybug/prettier-plugin-sort-imports"],
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -50,7 +50,7 @@ npx prettier --write "src/**/*.{js,ts,jsx,tsx}"
|
|
|
50
50
|
|
|
51
51
|
```javascript
|
|
52
52
|
// prettier.config.mjs
|
|
53
|
-
import { createPlugin } from "prettier-plugin-
|
|
53
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
54
54
|
|
|
55
55
|
export default {
|
|
56
56
|
plugins: [
|
|
@@ -161,7 +161,7 @@ interface PluginConfig {
|
|
|
161
161
|
|
|
162
162
|
```javascript
|
|
163
163
|
export default {
|
|
164
|
-
plugins: ["prettier-plugin-
|
|
164
|
+
plugins: ["@1adybug/prettier-plugin-sort-imports"],
|
|
165
165
|
importSortSideEffect: false, // 是否对副作用导入排序
|
|
166
166
|
importSortSeparator: "", // 分组分隔符
|
|
167
167
|
importSortRemoveUnused: false, // 是否删除未使用的导入
|
|
@@ -173,7 +173,7 @@ export default {
|
|
|
173
173
|
使用 `createPlugin` 函数可以传递自定义函数:
|
|
174
174
|
|
|
175
175
|
```javascript
|
|
176
|
-
import { createPlugin } from "prettier-plugin-
|
|
176
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
177
177
|
|
|
178
178
|
export default {
|
|
179
179
|
plugins: [
|
|
@@ -198,42 +198,150 @@ export default {
|
|
|
198
198
|
}
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
-
### 方式 3
|
|
201
|
+
### 方式 3:自定义插件模块
|
|
202
202
|
|
|
203
|
-
|
|
203
|
+
创建自定义插件模块以获得更好的组织性和可复用性:
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
// prettier.config.mjs
|
|
207
|
-
export default {
|
|
208
|
-
plugins: ["prettier-plugin-import-sorts"],
|
|
209
|
-
sortImportsConfigPath: "./import-sort.config.js",
|
|
210
|
-
}
|
|
211
|
-
```
|
|
205
|
+
**步骤 1**:创建自定义插件文件 `prettier-plugin-sort-imports.mjs`:
|
|
212
206
|
|
|
213
207
|
```javascript
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
208
|
+
// prettier-plugin-sort-imports.mjs
|
|
209
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
210
|
+
|
|
211
|
+
export default createPlugin({
|
|
212
|
+
// 自定义分组逻辑
|
|
213
|
+
getGroup: statement => {
|
|
214
|
+
const path = statement.path
|
|
215
|
+
|
|
216
|
+
// React 及相关库
|
|
217
|
+
if (path.startsWith("react") || path.startsWith("@react")) {
|
|
218
|
+
return "react"
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// UI 库
|
|
222
|
+
if (path.includes("antd") || path.includes("@mui") || path.includes("chakra")) {
|
|
223
|
+
return "ui"
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 工具库
|
|
227
|
+
if (path.includes("lodash") || path.includes("ramda") || path.includes("date-fns")) {
|
|
228
|
+
return "utils"
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// 外部包 (node_modules)
|
|
232
|
+
if (!path.startsWith(".") && !path.startsWith("@/")) {
|
|
233
|
+
return "external"
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 内部别名 (@/)
|
|
237
|
+
if (path.startsWith("@/")) {
|
|
238
|
+
return "internal"
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 相对导入
|
|
242
|
+
return "relative"
|
|
222
243
|
},
|
|
244
|
+
|
|
245
|
+
// 定义分组顺序
|
|
223
246
|
sortGroup: (a, b) => {
|
|
224
|
-
const order = ["react", "external", "internal", "relative"]
|
|
247
|
+
const order = ["react", "external", "ui", "utils", "internal", "relative"]
|
|
225
248
|
return order.indexOf(a.name) - order.indexOf(b.name)
|
|
226
249
|
},
|
|
250
|
+
|
|
251
|
+
// 自定义导入内容排序
|
|
252
|
+
sortImportContent: (a, b) => {
|
|
253
|
+
// 类型在前,变量在后
|
|
254
|
+
if (a.type !== b.type) {
|
|
255
|
+
return a.type === "type" ? -1 : 1
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// 同类型内按字母顺序
|
|
259
|
+
const aName = a.alias ?? a.name
|
|
260
|
+
const bName = b.alias ?? b.name
|
|
261
|
+
return aName.localeCompare(bName)
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
// 在分组间添加空行
|
|
227
265
|
separator: "\n",
|
|
266
|
+
|
|
267
|
+
// 排序副作用导入
|
|
268
|
+
sortSideEffect: true,
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**步骤 2**:在 `prettier.config.mjs` 中使用自定义插件:
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
// prettier.config.mjs
|
|
276
|
+
export default {
|
|
277
|
+
plugins: ["./prettier-plugin-sort-imports.mjs"],
|
|
278
|
+
// 其他 prettier 选项...
|
|
279
|
+
semi: false,
|
|
280
|
+
tabWidth: 4,
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**此方法的优点**:
|
|
285
|
+
|
|
286
|
+
- ✅ **可复用**:在多个项目间共享相同配置
|
|
287
|
+
- ✅ **版本控制**:在 git 中跟踪你的导入排序规则
|
|
288
|
+
- ✅ **易维护**:将复杂逻辑从 prettier 配置中分离
|
|
289
|
+
- ✅ **团队协作**:团队成员间保持一致的导入排序规则
|
|
290
|
+
|
|
291
|
+
### 方式 4:插件兼容性
|
|
292
|
+
|
|
293
|
+
使用 `createPlugin` 的 `otherPlugins` 参数与其他 Prettier 插件合并,避免冲突:
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
297
|
+
import * as tailwindPlugin from "prettier-plugin-tailwindcss"
|
|
298
|
+
|
|
299
|
+
export default {
|
|
300
|
+
plugins: [
|
|
301
|
+
createPlugin({
|
|
302
|
+
// 你的导入排序配置
|
|
303
|
+
getGroup: statement => {
|
|
304
|
+
if (statement.path.startsWith("react")) return "react"
|
|
305
|
+
if (!statement.path.startsWith(".")) return "external"
|
|
306
|
+
return "local"
|
|
307
|
+
},
|
|
308
|
+
separator: "\n",
|
|
309
|
+
|
|
310
|
+
// 要合并的其他 Prettier 插件(仅支持 Plugin 对象)
|
|
311
|
+
otherPlugins: [
|
|
312
|
+
tailwindPlugin, // 直接导入插件
|
|
313
|
+
// 根据需要添加更多插件...
|
|
314
|
+
],
|
|
315
|
+
|
|
316
|
+
// 其他插件的配置选项
|
|
317
|
+
prettierOptions: {
|
|
318
|
+
// TailwindCSS 插件选项
|
|
319
|
+
tailwindConfig: "./tailwind.config.js",
|
|
320
|
+
tailwindFunctions: ["clsx", "cn", "cva"],
|
|
321
|
+
tailwindAttributes: ["class", "className", "ngClass", ":class"],
|
|
322
|
+
|
|
323
|
+
// 其他插件选项可以在这里配置...
|
|
324
|
+
},
|
|
325
|
+
}),
|
|
326
|
+
],
|
|
228
327
|
}
|
|
229
328
|
```
|
|
230
329
|
|
|
231
|
-
|
|
330
|
+
**重要说明**:
|
|
331
|
+
|
|
332
|
+
- `otherPlugins` 只接受导入的 Plugin 对象,不支持字符串插件名称
|
|
333
|
+
- 你必须自己导入插件以确保正确的模块解析
|
|
334
|
+
- 这种方法避免了复杂的模块加载问题,给你完全的控制权
|
|
335
|
+
|
|
336
|
+
**插件执行顺序**:
|
|
337
|
+
|
|
338
|
+
- 其他插件按照在 `otherPlugins` 数组中出现的顺序执行
|
|
339
|
+
- 导入排序始终最后执行以确保兼容性
|
|
340
|
+
|
|
341
|
+
**配置传递**:
|
|
232
342
|
|
|
233
|
-
-
|
|
234
|
-
-
|
|
235
|
-
- 配置文件路径相对于项目根目录(`process.cwd()`)解析
|
|
236
|
-
- 配置优先级:`createPlugin` 参数 > `sortImportsConfigPath` 加载的配置 > Prettier 配置选项
|
|
343
|
+
- `prettierOptions` 中的选项会传递给所有其他插件
|
|
344
|
+
- 这允许其他插件即使在合并时也能接收到它们的配置
|
|
237
345
|
|
|
238
346
|
### importSortRemoveUnused
|
|
239
347
|
|
|
@@ -427,7 +535,7 @@ Prettier 原生无法接受函数作为配置参数(因为配置需要序列
|
|
|
427
535
|
|
|
428
536
|
```javascript
|
|
429
537
|
// 工厂函数在配置文件中被调用,返回一个插件实例
|
|
430
|
-
import { createPlugin } from "prettier-plugin-
|
|
538
|
+
import { createPlugin } from "@1adybug/prettier-plugin-sort-imports"
|
|
431
539
|
|
|
432
540
|
export default {
|
|
433
541
|
plugins: [
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Plugin } from "prettier";
|
|
2
|
-
import { PluginConfig } from "./types";
|
|
2
|
+
import type { PluginConfig } from "./types";
|
|
3
3
|
export * from "./types";
|
|
4
|
-
/** 默认插件实例(用于简单使用) */
|
|
5
|
-
declare const plugin: Plugin;
|
|
6
4
|
/** 创建自定义配置的插件(工厂函数) */
|
|
7
5
|
export declare function createPlugin(config?: PluginConfig): Plugin;
|
|
6
|
+
/** 默认插件实例(用于简单使用) */
|
|
7
|
+
declare const plugin: Plugin;
|
|
8
8
|
export default plugin;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createRequire } from "module";
|
|
2
|
-
import { resolve } from "path";
|
|
3
2
|
import { parse } from "@babel/parser";
|
|
4
3
|
import traverse from "@babel/traverse";
|
|
5
4
|
function analyzeUsedIdentifiers(code) {
|
|
@@ -236,7 +235,8 @@ function parseImportNode(node, comments, usedComments) {
|
|
|
236
235
|
start,
|
|
237
236
|
end
|
|
238
237
|
};
|
|
239
|
-
const
|
|
238
|
+
const isTypeOnlyExport = "type" === node.exportKind;
|
|
239
|
+
const importContents = parseExportSpecifiers(node, isTypeOnlyExport);
|
|
240
240
|
return {
|
|
241
241
|
path: source,
|
|
242
242
|
isExport: true,
|
|
@@ -290,7 +290,7 @@ function parseImportSpecifiers(node, isTypeOnlyImport = false) {
|
|
|
290
290
|
}
|
|
291
291
|
return contents;
|
|
292
292
|
}
|
|
293
|
-
function parseExportSpecifiers(node) {
|
|
293
|
+
function parseExportSpecifiers(node, isTypeOnlyExport = false) {
|
|
294
294
|
const contents = [];
|
|
295
295
|
if (!node.specifiers) return contents;
|
|
296
296
|
for (const specifier of node.specifiers)if ("ExportSpecifier" === specifier.type) {
|
|
@@ -306,7 +306,7 @@ function parseExportSpecifiers(node) {
|
|
|
306
306
|
}
|
|
307
307
|
const localName = "Identifier" === specifier.local.type ? specifier.local.name : specifier.local.value;
|
|
308
308
|
const exportedName = "Identifier" === specifier.exported.type ? specifier.exported.name : specifier.exported.value;
|
|
309
|
-
const isTypeExport = "type" === specifier.exportKind;
|
|
309
|
+
const isTypeExport = isTypeOnlyExport || "type" === specifier.exportKind;
|
|
310
310
|
contents.push({
|
|
311
311
|
name: localName,
|
|
312
312
|
alias: localName !== exportedName ? exportedName : void 0,
|
|
@@ -526,58 +526,33 @@ function mergeImports(imports) {
|
|
|
526
526
|
return Array.from(mergedMap.values());
|
|
527
527
|
}
|
|
528
528
|
const src_require = createRequire(import.meta.url);
|
|
529
|
-
|
|
530
|
-
const configCache = new Map();
|
|
531
|
-
function loadConfigFromPath(configPath) {
|
|
532
|
-
if (configCache.has(configPath)) return configCache.get(configPath);
|
|
533
|
-
try {
|
|
534
|
-
const absolutePath = resolve(process.cwd(), configPath);
|
|
535
|
-
let config = {};
|
|
536
|
-
try {
|
|
537
|
-
delete src_require.cache[absolutePath];
|
|
538
|
-
const module = src_require(absolutePath);
|
|
539
|
-
config = module.default || module || {};
|
|
540
|
-
} catch (requireError) {
|
|
541
|
-
throw new Error(`Failed to load config file: ${configPath}. Please ensure the config file uses CommonJS format (module.exports) or has a .cjs extension. ESM format (.mjs or "type": "module") is not supported in synchronous loading context.\nOriginal error: ${requireError}`);
|
|
542
|
-
}
|
|
543
|
-
configCache.set(configPath, config);
|
|
544
|
-
return config;
|
|
545
|
-
} catch (error) {
|
|
546
|
-
console.error(`Failed to load config from ${configPath}:`, error);
|
|
547
|
-
const emptyConfig = {};
|
|
548
|
-
configCache.set(configPath, emptyConfig);
|
|
549
|
-
return emptyConfig;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
function preprocessImports(text, options) {
|
|
529
|
+
function preprocessImports(text, options, config = {}) {
|
|
553
530
|
try {
|
|
554
531
|
const imports = parseImports(text);
|
|
555
532
|
if (0 === imports.length) return text;
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
sortSideEffect: src_userConfig.sortSideEffect ?? fileConfig.sortSideEffect ?? options.importSortSideEffect ?? false,
|
|
566
|
-
removeUnusedImports: src_userConfig.removeUnusedImports ?? fileConfig.removeUnusedImports ?? options.importSortRemoveUnused ?? false
|
|
533
|
+
const optionsConfig = options;
|
|
534
|
+
const finalConfig = {
|
|
535
|
+
getGroup: config.getGroup ?? optionsConfig.getGroup,
|
|
536
|
+
sortGroup: config.sortGroup ?? optionsConfig.sortGroup,
|
|
537
|
+
sortImportStatement: config.sortImportStatement ?? optionsConfig.sortImportStatement,
|
|
538
|
+
sortImportContent: config.sortImportContent ?? optionsConfig.sortImportContent,
|
|
539
|
+
separator: config.separator ?? optionsConfig.importSortSeparator ?? optionsConfig.separator,
|
|
540
|
+
sortSideEffect: config.sortSideEffect ?? optionsConfig.importSortSideEffect ?? false,
|
|
541
|
+
removeUnusedImports: config.removeUnusedImports ?? optionsConfig.importSortRemoveUnused ?? false
|
|
567
542
|
};
|
|
568
543
|
let processedImports = imports;
|
|
569
|
-
if (
|
|
544
|
+
if (finalConfig.removeUnusedImports) {
|
|
570
545
|
const lastImport = imports[imports.length - 1];
|
|
571
546
|
const codeAfterImports = text.slice(lastImport.end ?? 0);
|
|
572
547
|
processedImports = removeUnusedImportsFromStatements(imports, codeAfterImports);
|
|
573
548
|
}
|
|
574
|
-
const sortedImports = sortImports(processedImports,
|
|
549
|
+
const sortedImports = sortImports(processedImports, finalConfig);
|
|
575
550
|
const mergedImports = mergeImports(sortedImports);
|
|
576
551
|
let formattedImports;
|
|
577
|
-
if (
|
|
578
|
-
const groups = groupImports(mergedImports,
|
|
579
|
-
const sortedGroups = sortGroups(groups,
|
|
580
|
-
formattedImports = formatGroups(sortedGroups,
|
|
552
|
+
if (finalConfig.getGroup) {
|
|
553
|
+
const groups = groupImports(mergedImports, finalConfig);
|
|
554
|
+
const sortedGroups = sortGroups(groups, finalConfig);
|
|
555
|
+
formattedImports = formatGroups(sortedGroups, finalConfig);
|
|
581
556
|
} else formattedImports = formatImportStatements(mergedImports);
|
|
582
557
|
const firstImport = imports[0];
|
|
583
558
|
const lastImport = imports[imports.length - 1];
|
|
@@ -593,55 +568,99 @@ function preprocessImports(text, options) {
|
|
|
593
568
|
return text;
|
|
594
569
|
}
|
|
595
570
|
}
|
|
596
|
-
const
|
|
597
|
-
const
|
|
598
|
-
const
|
|
599
|
-
function
|
|
600
|
-
return {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
571
|
+
const { parsers: { babel } } = src_require("prettier/parser-babel");
|
|
572
|
+
const { parsers: { typescript } } = src_require("prettier/parser-typescript");
|
|
573
|
+
const { parsers: { "babel-ts": babelTs } } = src_require("prettier/parser-babel");
|
|
574
|
+
function createCombinedPreprocess(parserName, config) {
|
|
575
|
+
return function(text, options) {
|
|
576
|
+
const otherPlugins = config.otherPlugins || [];
|
|
577
|
+
if (0 === otherPlugins.length) return preprocessImports(text, options, config);
|
|
578
|
+
const prettierOptions = config.prettierOptions || {};
|
|
579
|
+
const mergedOptions = {
|
|
580
|
+
...options,
|
|
581
|
+
...prettierOptions
|
|
582
|
+
};
|
|
583
|
+
const preprocessFunctions = [];
|
|
584
|
+
preprocessFunctions.push((text, options)=>preprocessImports(text, options, config));
|
|
585
|
+
for (const plugin of otherPlugins){
|
|
586
|
+
const parser = plugin?.parsers?.[parserName];
|
|
587
|
+
if (parser?.preprocess && "function" == typeof parser.preprocess) preprocessFunctions.push(parser.preprocess);
|
|
588
|
+
}
|
|
589
|
+
let processedText = text;
|
|
590
|
+
for (const preprocess of preprocessFunctions)try {
|
|
591
|
+
processedText = preprocess(processedText, mergedOptions);
|
|
592
|
+
} catch (error) {
|
|
593
|
+
console.warn("Plugin preprocess failed:", error instanceof Error ? error.message : String(error));
|
|
594
|
+
}
|
|
595
|
+
return processedText;
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function createPluginInstance(config = {}) {
|
|
599
|
+
const baseOptions = {
|
|
600
|
+
importSortSeparator: {
|
|
601
|
+
type: "string",
|
|
602
|
+
category: "Import Sort",
|
|
603
|
+
description: "分组之间的分隔符"
|
|
614
604
|
},
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
605
|
+
importSortSideEffect: {
|
|
606
|
+
type: "boolean",
|
|
607
|
+
category: "Import Sort",
|
|
608
|
+
description: "是否对副作用导入进行排序",
|
|
609
|
+
default: false
|
|
610
|
+
},
|
|
611
|
+
importSortRemoveUnused: {
|
|
612
|
+
type: "boolean",
|
|
613
|
+
category: "Import Sort",
|
|
614
|
+
description: "是否删除未使用的导入",
|
|
615
|
+
default: false
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
const otherPlugins = config.otherPlugins || [];
|
|
619
|
+
const mergedOptions = {
|
|
620
|
+
...baseOptions
|
|
621
|
+
};
|
|
622
|
+
for (const plugin of otherPlugins)if (plugin?.options) Object.assign(mergedOptions, plugin.options);
|
|
623
|
+
const mergedPrinters = {};
|
|
624
|
+
for (const plugin of otherPlugins)if (plugin?.printers) Object.assign(mergedPrinters, plugin.printers);
|
|
625
|
+
const mergedParsers = {};
|
|
626
|
+
const parserNames = [
|
|
627
|
+
"babel",
|
|
628
|
+
"typescript",
|
|
629
|
+
"babel-ts"
|
|
630
|
+
];
|
|
631
|
+
const baseParsers = {
|
|
632
|
+
babel,
|
|
633
|
+
typescript,
|
|
634
|
+
"babel-ts": babelTs
|
|
635
|
+
};
|
|
636
|
+
for (const parserName of parserNames){
|
|
637
|
+
const baseParser = baseParsers[parserName];
|
|
638
|
+
let merged = {
|
|
639
|
+
...baseParser
|
|
640
|
+
};
|
|
641
|
+
for (const plugin of otherPlugins){
|
|
642
|
+
const otherParser = plugin?.parsers?.[parserName];
|
|
643
|
+
if (otherParser) {
|
|
644
|
+
const { preprocess, ...otherAttrs } = otherParser;
|
|
645
|
+
merged = {
|
|
646
|
+
...merged,
|
|
647
|
+
...otherAttrs
|
|
648
|
+
};
|
|
637
649
|
}
|
|
638
650
|
}
|
|
651
|
+
merged.preprocess = createCombinedPreprocess(parserName, config);
|
|
652
|
+
mergedParsers[parserName] = merged;
|
|
653
|
+
}
|
|
654
|
+
const result = {
|
|
655
|
+
parsers: mergedParsers,
|
|
656
|
+
options: mergedOptions
|
|
639
657
|
};
|
|
658
|
+
if (Object.keys(mergedPrinters).length > 0) result.printers = mergedPrinters;
|
|
659
|
+
return result;
|
|
640
660
|
}
|
|
641
|
-
const src_plugin = createPluginInstance();
|
|
642
661
|
function createPlugin(config = {}) {
|
|
643
|
-
|
|
644
|
-
return createPluginInstance();
|
|
662
|
+
return createPluginInstance(config);
|
|
645
663
|
}
|
|
664
|
+
const src_plugin = createPluginInstance();
|
|
646
665
|
const src = src_plugin;
|
|
647
666
|
export { createPlugin, src as default };
|
package/dist/parser.d.ts
CHANGED
package/dist/sorter.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Group, ImportContent, ImportStatement, PluginConfig } from "./types";
|
|
1
|
+
import { Group, ImportContent, ImportStatement, PluginConfig } from "./types";
|
|
2
2
|
/** 合并后的配置 */
|
|
3
|
-
export interface MergedConfig extends Omit<Required<PluginConfig>, "separator" | "removeUnusedImports"> {
|
|
3
|
+
export interface MergedConfig extends Omit<Required<PluginConfig>, "separator" | "removeUnusedImports" | "otherPlugins" | "prettierOptions"> {
|
|
4
4
|
separator: PluginConfig["separator"];
|
|
5
5
|
removeUnusedImports: boolean;
|
|
6
6
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Plugin } from "prettier";
|
|
1
2
|
/** 导入内容 */
|
|
2
3
|
export interface ImportContent {
|
|
3
4
|
/** 导入的内容的名称 */
|
|
@@ -67,4 +68,8 @@ export interface PluginConfig {
|
|
|
67
68
|
sortSideEffect?: boolean;
|
|
68
69
|
/** 是否删除未使用的导入,默认为 false */
|
|
69
70
|
removeUnusedImports?: boolean;
|
|
71
|
+
/** 要合并的其他 Prettier 插件,按传入顺序执行 */
|
|
72
|
+
otherPlugins?: Plugin[];
|
|
73
|
+
/** 传递给其他插件的 Prettier 配置选项 */
|
|
74
|
+
prettierOptions?: Record<string, any>;
|
|
70
75
|
}
|
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.
|
|
4
|
+
"version": "0.0.7",
|
|
5
5
|
"description": "一个 Prettier 插件,用于对 JavaScript/TypeScript 文件的导入语句进行分组和排序",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"prettier",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"@types/bun": "latest",
|
|
55
55
|
"@types/node": "^22.18.6",
|
|
56
56
|
"prettier": "^3.6.2",
|
|
57
|
+
"prettier-plugin-tailwindcss": "^0.7.0",
|
|
57
58
|
"supports-color": "^10.2.2",
|
|
58
59
|
"typescript": "^5.9.2"
|
|
59
60
|
},
|