prettier-plugin-sort 0.0.0 → 0.0.2
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/LICENSE +21 -0
- package/README.md +357 -0
- package/README.zh.md +362 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +736 -0
- package/package.json +58 -12
- package/index.js +0 -1
package/README.zh.md
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# prettier-plugin-sort
|
|
2
|
+
|
|
3
|
+
一个专注于排序的 [Prettier](https://prettier.io/) 插件。
|
|
4
|
+
|
|
5
|
+
- 排序 JS / TS 文件里的 import 语句
|
|
6
|
+
- 排序 `export { … }` 花括号内的命名导出
|
|
7
|
+
- 排序 package.json 的顶层字段、字符串数组和依赖表
|
|
8
|
+
- 零运行时依赖
|
|
9
|
+
|
|
10
|
+
使用其他语言阅读:[English](./README.md) | 中文
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
```shell
|
|
15
|
+
npm i -D prettier prettier-plugin-sort
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
在 Prettier 配置里启用:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"plugins": ["prettier-plugin-sort"]
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
然后按常规方式运行 Prettier 即可,例如 `npx prettier --write .`。
|
|
27
|
+
|
|
28
|
+
## 当前支持的排序
|
|
29
|
+
|
|
30
|
+
### import
|
|
31
|
+
|
|
32
|
+
#### 模块分组与排序
|
|
33
|
+
|
|
34
|
+
默认配置下,效果大致如下。
|
|
35
|
+
|
|
36
|
+
排序前:
|
|
37
|
+
|
|
38
|
+
<!-- prettier-ignore -->
|
|
39
|
+
```typescript
|
|
40
|
+
import App from './App.tsx';
|
|
41
|
+
import fs from 'node:fs';
|
|
42
|
+
import lodash from 'lodash';
|
|
43
|
+
import path from 'node:path';
|
|
44
|
+
import react from 'react';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
排序后:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import fs from 'node:fs';
|
|
51
|
+
import path from 'node:path';
|
|
52
|
+
|
|
53
|
+
import lodash from 'lodash';
|
|
54
|
+
import react from 'react';
|
|
55
|
+
|
|
56
|
+
import App from './App.tsx';
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
import 的模块一般可以按其来源分为不同的类别,例如上面的示例代码,'node:fs' 就属于 builtin 分类,该分类涵盖 Node.js、Bun、Deno 等**运行时**的内置模块。而像 react 和 lodash 这种直接从 npm 下载的依赖模块,属于 external 分类。
|
|
60
|
+
|
|
61
|
+
插件会先根据不同的模块进行分类,然后在模块内部基于字母顺序进行排列。
|
|
62
|
+
|
|
63
|
+
整体分组和排序方式参考了 [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) 的 [import/order](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md) 规则。
|
|
64
|
+
|
|
65
|
+
插件 import 默认的配置是:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"plugins": ["prettier-plugin-sort"],
|
|
70
|
+
"importOrderGroups": ["builtin", "external", "parent", "sibling", "index"],
|
|
71
|
+
"importOrderSeparation": true,
|
|
72
|
+
"importOrderTypeImports": "separate",
|
|
73
|
+
"importOrderMergeDuplicates": true
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
各分组的匹配规则如下:
|
|
78
|
+
|
|
79
|
+
| 分组 | 匹配内容 | 示例 |
|
|
80
|
+
| ---------- | ------------------------------------------------------- | ---------------------------------- |
|
|
81
|
+
| `builtin` | `node:*`、`bun:*`、`deno:*`,以及无前缀的 Node 内置模块 | `node:fs`、`path` |
|
|
82
|
+
| `external` | npm 包,以及不属于其他分组的模块 | `react`、`@scope/pkg` |
|
|
83
|
+
| `internal` | 项目绝对路径与别名 | `/utils`、`~/app`、`@/shared` |
|
|
84
|
+
| `parent` | 向上跳级的相对路径 | `../Button` |
|
|
85
|
+
| `sibling` | 同级相对路径(不包含 index) | `./Icon` |
|
|
86
|
+
| `index` | 当前目录的 index 模块 | `.`、`./`、`./index`、`./index.ts` |
|
|
87
|
+
|
|
88
|
+
> **关于 `internal` 的检测方式:** 插件目前通过说明符的前缀硬编码(`/`、`~`、`@/`)来判断,不会读取 tsconfig `paths` 或任何构建工具的配置。后续版本可能会提供 `importOrderInternalPatterns` 选项,支持自定义正则匹配。
|
|
89
|
+
|
|
90
|
+
你可以通过 `importOrderGroups` 调整分组顺序,或者删掉不需要的分组,比如把 `internal` 显式加入分组:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"plugins": ["prettier-plugin-sort"],
|
|
95
|
+
"importOrderGroups": [
|
|
96
|
+
"builtin",
|
|
97
|
+
"external",
|
|
98
|
+
"internal",
|
|
99
|
+
"parent",
|
|
100
|
+
"sibling",
|
|
101
|
+
"index"
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
排序前:
|
|
107
|
+
|
|
108
|
+
<!-- prettier-ignore -->
|
|
109
|
+
```typescript
|
|
110
|
+
import App from './App.tsx';
|
|
111
|
+
import react from 'react';
|
|
112
|
+
import shared from '@/shared';
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
排序后:
|
|
116
|
+
|
|
117
|
+
<!-- prettier-ignore -->
|
|
118
|
+
```typescript
|
|
119
|
+
import react from 'react';
|
|
120
|
+
|
|
121
|
+
import shared from '@/shared';
|
|
122
|
+
|
|
123
|
+
import App from './App.tsx';
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
如果不想在分组之间插入空行,把 `importOrderSeparation` 设为 `false` 即可。
|
|
127
|
+
|
|
128
|
+
#### 类型导入
|
|
129
|
+
|
|
130
|
+
默认配置下,插件会把 `type` import 拆成独立的语句。
|
|
131
|
+
|
|
132
|
+
排序前:
|
|
133
|
+
|
|
134
|
+
<!-- prettier-ignore -->
|
|
135
|
+
```typescript
|
|
136
|
+
import { useState, type FC } from 'react';
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
排序后:
|
|
140
|
+
|
|
141
|
+
<!-- prettier-ignore -->
|
|
142
|
+
```typescript
|
|
143
|
+
import type { FC } from 'react';
|
|
144
|
+
import { useState } from 'react';
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`importOrderTypeImports` 的几种风格则参考了 ESLint 生态里对 type import 的常见约定,尤其是
|
|
148
|
+
[@typescript-eslint/consistent-type-imports](https://typescript-eslint.io/rules/consistent-type-imports) 的 `fixStyle` 设计。
|
|
149
|
+
|
|
150
|
+
以 `import { c, type B, a } from 'mod';` 为例,各模式的效果:
|
|
151
|
+
|
|
152
|
+
| 模式 | 结果 |
|
|
153
|
+
| -------------- | ---------------------------------------------------------------- |
|
|
154
|
+
| `separate` | `import type { B } from 'mod';`<br>`import { a, c } from 'mod';` |
|
|
155
|
+
| `inline-first` | `import { type B, a, c } from 'mod';` |
|
|
156
|
+
| `inline-last` | `import { a, c, type B } from 'mod';` |
|
|
157
|
+
| `mixed` | `import { a, type B, c } from 'mod';` |
|
|
158
|
+
|
|
159
|
+
`separate`、`inline-first`、`inline-last` 三种模式会先按类型和值分开,然后在各自组内按字母序排列。`mixed` 将统一按字母序排列(不分类型与值),type 关键字始终跟随它所修饰的标识符,保持原有的关系。
|
|
160
|
+
|
|
161
|
+
#### 合并同源导入
|
|
162
|
+
|
|
163
|
+
默认情况下,来自同一来源的多条 import 语句会被合并成一条,便于阅读。
|
|
164
|
+
|
|
165
|
+
排序前:
|
|
166
|
+
|
|
167
|
+
<!-- prettier-ignore -->
|
|
168
|
+
```typescript
|
|
169
|
+
import { useState } from 'react';
|
|
170
|
+
import { useEffect } from 'react';
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
排序后:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { useEffect, useState } from 'react';
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`importOrderMergeDuplicates` 只负责合并这一步,花括号内的排列方式完全由 `importOrderTypeImports` 决定。比如把 `import { useState } from 'react';` 和 `import { type FC, useEffect } from 'react';` 合并后,不同模式的结果:
|
|
180
|
+
|
|
181
|
+
- `separate`(默认):合并后这一阶段又会被拆回两条,最终保持独立的 `import type` 语句
|
|
182
|
+
- `inline-first`:`import { type FC, useEffect, useState } from 'react';`
|
|
183
|
+
- `inline-last`:`import { useEffect, useState, type FC } from 'react';`
|
|
184
|
+
- `mixed`:`import { type FC, useEffect, useState } from 'react';`
|
|
185
|
+
|
|
186
|
+
如果你希望保留原本分离的两条语句,把 `importOrderMergeDuplicates` 设为 `false` 即可。副作用导入(`import 'mod';`)因为顺序有语义,永远不会被合并。
|
|
187
|
+
|
|
188
|
+
排序规则:
|
|
189
|
+
|
|
190
|
+
- import 按分组分类,分组内按字母序排列
|
|
191
|
+
- 默认分组顺序:`builtin` → `external` → `parent` → `sibling` → `index`
|
|
192
|
+
- 分组之间默认插入空行,可通过 `importOrderSeparation` 关闭
|
|
193
|
+
- `type` import 默认拆成独立语句,可通过 `importOrderTypeImports` 调整为内联
|
|
194
|
+
- 同一来源的多条 import 默认合并为一条,可通过 `importOrderMergeDuplicates` 关闭
|
|
195
|
+
- 副作用导入(`import 'mod'`)顺序有语义,永远不参与合并或跨位移动
|
|
196
|
+
|
|
197
|
+
### export
|
|
198
|
+
|
|
199
|
+
默认情况下,`export { … }` 花括号内的命名导出会按字母序排列。
|
|
200
|
+
|
|
201
|
+
排序前:
|
|
202
|
+
|
|
203
|
+
<!-- prettier-ignore -->
|
|
204
|
+
```typescript
|
|
205
|
+
export { useState, useEffect, type FC } from 'react';
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
排序后:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
export { type FC, useEffect, useState } from 'react';
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
插件只整理花括号内的顺序,不会改变整条 export 语句的位置,也不会合并两条同来源的 export。如果不需要这个行为,把 `exportOrder` 设为 `false` 即可。
|
|
215
|
+
|
|
216
|
+
排序规则:
|
|
217
|
+
|
|
218
|
+
- `export { … }` 和 `export type { … }` 花括号内的命名导出按字母序排列
|
|
219
|
+
- 不改变整条 export 语句在文件中的位置
|
|
220
|
+
- 不合并同来源的多条 export 语句
|
|
221
|
+
|
|
222
|
+
### package.json
|
|
223
|
+
|
|
224
|
+
默认配置下,效果大致如下。
|
|
225
|
+
|
|
226
|
+
排序前:
|
|
227
|
+
|
|
228
|
+
<!-- prettier-ignore -->
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"version": "1.0.0",
|
|
232
|
+
"keywords": ["sort", "prettier", "plugin"],
|
|
233
|
+
"name": "demo",
|
|
234
|
+
"dependencies": {
|
|
235
|
+
"typescript": "^6.0.0",
|
|
236
|
+
"prettier": "^3.0.0"
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
排序后:
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"name": "demo",
|
|
246
|
+
"version": "1.0.0",
|
|
247
|
+
"keywords": ["plugin", "prettier", "sort"],
|
|
248
|
+
"dependencies": {
|
|
249
|
+
"prettier": "^3.0.0",
|
|
250
|
+
"typescript": "^6.0.0"
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`package.json` 顶层字段顺序参考了 [sort-package-json](https://github.com/keithamus/sort-package-json) 维护的字段列表,便于和社区里被广泛使用的排序习惯保持一致。
|
|
256
|
+
|
|
257
|
+
排序规则:
|
|
258
|
+
|
|
259
|
+
- 顶层字段按常用顺序排列(`name` → `version` → ... → `dependencies`)
|
|
260
|
+
- 顶层的纯字符串数组按字母序排列,如 `keywords`、`files`
|
|
261
|
+
- `dependencies`、`devDependencies`、`peerDependencies` 等依赖表永远按字母序排列,即使 `packageJsonOrder` 设为 `false` 也不例外。因为 `npm install` 每次都会按照字母序写回
|
|
262
|
+
- `scripts`、`exports`、`imports` 等嵌套对象不会递归排序,它们的键顺序有运行时语义
|
|
263
|
+
- 想让某些顶层字段完全跳过排序,可以在 `packageJsonOrderExcludeKeys` 里列出
|
|
264
|
+
|
|
265
|
+
## 配置项
|
|
266
|
+
|
|
267
|
+
Prettier 的插件选项是扁平的,所以这些配置都以 `importOrder`、`exportOrder` 或 `packageJsonOrder` 开头。
|
|
268
|
+
|
|
269
|
+
| 配置项 | 说明 | 默认值 |
|
|
270
|
+
| ----------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------- |
|
|
271
|
+
| `importOrder` | 是否排序 JS / TS 里的 import | `true` |
|
|
272
|
+
| `importOrderGroups` | 分组顺序,支持 `builtin`、`external`、`internal`、`parent`、`sibling`、`index` | `["builtin", "external", "parent", "sibling", "index"]` |
|
|
273
|
+
| `importOrderSeparation` | 分组之间是否插入空行 | `true` |
|
|
274
|
+
| `importOrderTypeImports` | `type` import 的处理方式:`separate`、`inline-first`、`inline-last`、`mixed` | `"separate"` |
|
|
275
|
+
| `importOrderMergeDuplicates` | 是否合并同来源的多条 import 语句(副作用导入除外) | `true` |
|
|
276
|
+
| `exportOrder` | 是否按字母序排列 `export { … }` 花括号内的命名导出 | `true` |
|
|
277
|
+
| `packageJsonOrder` | 是否排序 package.json 的顶层字段和字符串数组 | `true` |
|
|
278
|
+
| `packageJsonOrderExcludeKeys` | 不参与 package.json 排序的顶层字段 | `[]` |
|
|
279
|
+
|
|
280
|
+
## 示例
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"plugins": ["prettier-plugin-sort"],
|
|
285
|
+
"importOrderGroups": [
|
|
286
|
+
"builtin",
|
|
287
|
+
"external",
|
|
288
|
+
"internal",
|
|
289
|
+
"parent",
|
|
290
|
+
"sibling",
|
|
291
|
+
"index"
|
|
292
|
+
],
|
|
293
|
+
"importOrderTypeImports": "inline-last",
|
|
294
|
+
"packageJsonOrderExcludeKeys": ["contributes"]
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## 类型提示
|
|
299
|
+
|
|
300
|
+
如果你在 `.ts` 或 `.js` 配置文件里写 Prettier 配置,可以直接复用插件导出的
|
|
301
|
+
`SortOptions` 类型,这样写配置时会有补全和校验。
|
|
302
|
+
|
|
303
|
+
### 在 `.ts` 文件里使用
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { type Config } from 'prettier';
|
|
307
|
+
import { type SortOptions } from 'prettier-plugin-sort';
|
|
308
|
+
|
|
309
|
+
export default {
|
|
310
|
+
plugins: ['prettier-plugin-sort'],
|
|
311
|
+
importOrderGroups: [
|
|
312
|
+
'builtin',
|
|
313
|
+
'external',
|
|
314
|
+
'internal',
|
|
315
|
+
'parent',
|
|
316
|
+
'sibling',
|
|
317
|
+
'index',
|
|
318
|
+
],
|
|
319
|
+
importOrderTypeImports: 'inline-last',
|
|
320
|
+
packageJsonOrderExcludeKeys: ['contributes'],
|
|
321
|
+
} satisfies Config & SortOptions;
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### 在 `.js` 文件里使用
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
/** @type {import('prettier').Config & import('prettier-plugin-sort').SortOptions} */
|
|
328
|
+
const config = {
|
|
329
|
+
plugins: ['prettier-plugin-sort'],
|
|
330
|
+
importOrderGroups: [
|
|
331
|
+
'builtin',
|
|
332
|
+
'external',
|
|
333
|
+
'internal',
|
|
334
|
+
'parent',
|
|
335
|
+
'sibling',
|
|
336
|
+
'index',
|
|
337
|
+
],
|
|
338
|
+
importOrderTypeImports: 'inline-last',
|
|
339
|
+
packageJsonOrderExcludeKeys: ['contributes'],
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
export default config;
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
如果你只想单独复用字面量类型,也可以使用插件导出的 `ImportGroup` 和
|
|
346
|
+
`TypeImportsStyle`。
|
|
347
|
+
|
|
348
|
+
## 项目由来
|
|
349
|
+
|
|
350
|
+
在接触 Prettier 之前,我一直都在使用 IDE 的自定义代码排序。因为后面开始尝试各种不同的 IDE,所以便有了统一配置管理的需求,于是将 ESLint + Prettier 引入到了项目中。
|
|
351
|
+
|
|
352
|
+
可是 Prettier 没有提供 sort 配置,我想要格式化 import 排序,就必须安装 `prettier-plugin-organize-imports` 插件,想要格式化 package.json 排序,就必须安装 `prettier-plugin-packagejson` 插件,导致体验十分割裂。
|
|
353
|
+
|
|
354
|
+
我在很长的一段时间里都没有去在意这些细枝末节,主要的精力放在了开发上。但在最近,我有调整 import type 内联排版的需求,发现 `prettier-plugin-organize-imports` 并不支持。再加上基于 `sort-package-json` 开发的 `prettier-plugin-packagejson` 有很多对于插件而言冗余的依赖项,所以便有了自己开发的打算。
|
|
355
|
+
|
|
356
|
+
`prettier-plugin-sort` 的目的不是为了替代谁,而是让开发者有着更多的选择。Prettier 绝大多数的用途都是格式化 JS/TS 代码,而所有的 JS 项目都有着 package.json,所以 `prettier-plugin-sort` 只实现了这两种基础的排序,初衷是让 JS 开发者能够以最小的心智负担做到开箱即用(未来可能还会添加对 tsconfig.json 的排序支持)。如果你有着其它代码的排序要求,那么依然可以选择安装 `prettier-plugin-css-order` 之类的插件,它们之间并不冲突。
|
|
357
|
+
|
|
358
|
+
## 鸣谢
|
|
359
|
+
|
|
360
|
+
- `eslint-plugin-import`: https://github.com/import-js/eslint-plugin-import
|
|
361
|
+
- `typescript-eslint`: https://github.com/typescript-eslint/typescript-eslint
|
|
362
|
+
- `sort-package-json`: https://github.com/keithamus/sort-package-json
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
+
|
|
3
|
+
import { Plugin, SupportOptions } from 'prettier';
|
|
4
|
+
|
|
5
|
+
/** import 分组,参考 eslint-plugin-import 的 import/order 规则。 */
|
|
6
|
+
export type ImportGroup = "builtin" | "external" | "internal" | "parent" | "sibling" | "index";
|
|
7
|
+
/** `import type` 内联风格,参考 @typescript-eslint/consistent-type-imports 的 fixStyle 选项。 */
|
|
8
|
+
export type TypeImportsStyle = "separate" | "inline-first" | "inline-last" | "mixed";
|
|
9
|
+
/** 插件排序配置。 */
|
|
10
|
+
export interface SortOptions {
|
|
11
|
+
importOrder?: boolean;
|
|
12
|
+
importOrderGroups?: ImportGroup[];
|
|
13
|
+
importOrderSeparation?: boolean;
|
|
14
|
+
importOrderTypeImports?: TypeImportsStyle;
|
|
15
|
+
importOrderMergeDuplicates?: boolean;
|
|
16
|
+
exportOrder?: boolean;
|
|
17
|
+
packageJsonOrder?: boolean;
|
|
18
|
+
packageJsonOrderExcludeKeys?: string[];
|
|
19
|
+
}
|
|
20
|
+
/** 向 Prettier 注册的选项。使用功能名词前缀命名,因为 Prettier API 不支持嵌套选项对象。 */
|
|
21
|
+
export declare const options: SupportOptions;
|
|
22
|
+
declare const plugin: Plugin;
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
plugin as default,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export {};
|