prettier-plugin-sort 0.0.0 → 0.0.1

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yuki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,357 @@
1
+ # prettier-plugin-sort
2
+
3
+ A [Prettier](https://prettier.io/) plugin focused on sorting.
4
+
5
+ - Sort `import` declarations in JS / TS files
6
+ - Sort named specifiers inside `export { … }`
7
+ - Sort top-level keys, string arrays, and dependency maps in `package.json`
8
+ - Zero runtime dependencies
9
+
10
+ Read this in other languages: English | [中文](./README.zh.md)
11
+
12
+ ## Install
13
+
14
+ ```shell
15
+ npm i -D prettier prettier-plugin-sort
16
+ ```
17
+
18
+ Enable it in your Prettier config:
19
+
20
+ ```json
21
+ {
22
+ "plugins": ["prettier-plugin-sort"]
23
+ }
24
+ ```
25
+
26
+ Then run Prettier as usual, for example `npx prettier --write .`.
27
+
28
+ ## What gets sorted
29
+
30
+ ### Imports
31
+
32
+ #### Grouping and sorting
33
+
34
+ With the default config, imports are grouped and ordered like this.
35
+
36
+ Before:
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
+ After:
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
+ Each import belongs to a group. For example, `node:fs` is a `builtin` (covers Node.js / Bun / Deno built-ins), while `react` and `lodash` are `external` npm packages. The plugin first classifies each import by group, then sorts alphabetically within each group.
60
+
61
+ Grouping and ordering follow the conventions of [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import)'s [import/order](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md) rule.
62
+
63
+ The default import config is:
64
+
65
+ ```json
66
+ {
67
+ "plugins": ["prettier-plugin-sort"],
68
+ "importOrderGroups": ["builtin", "external", "parent", "sibling", "index"],
69
+ "importOrderSeparation": true,
70
+ "importOrderTypeImports": "separate",
71
+ "importOrderMergeDuplicates": true
72
+ }
73
+ ```
74
+
75
+ Group matchers:
76
+
77
+ | Group | Matches | Examples |
78
+ | ---------- | ----------------------------------------------------------- | ---------------------------------- |
79
+ | `builtin` | `node:*`, `bun:*`, `deno:*`, and unprefixed Node built-ins | `node:fs`, `path` |
80
+ | `external` | npm packages, and anything that doesn't match another group | `react`, `@scope/pkg` |
81
+ | `internal` | Project absolute paths and aliases | `/utils`, `~/app`, `@/shared` |
82
+ | `parent` | Parent-relative paths | `../Button` |
83
+ | `sibling` | Sibling paths (excluding index) | `./Icon` |
84
+ | `index` | Current directory index | `.`, `./`, `./index`, `./index.ts` |
85
+
86
+ > **Note on `internal` detection:** the plugin currently uses hardcoded specifier prefixes (`/`, `~`, `@/`) and does not read `tsconfig paths` or any bundler config. An `importOrderInternalPatterns` option for custom regex matching may be added in a future release.
87
+
88
+ Reorder or drop groups through `importOrderGroups`. For example, adding `internal` explicitly:
89
+
90
+ ```json
91
+ {
92
+ "plugins": ["prettier-plugin-sort"],
93
+ "importOrderGroups": [
94
+ "builtin",
95
+ "external",
96
+ "internal",
97
+ "parent",
98
+ "sibling",
99
+ "index"
100
+ ]
101
+ }
102
+ ```
103
+
104
+ Before:
105
+
106
+ <!-- prettier-ignore -->
107
+ ```typescript
108
+ import App from './App.tsx';
109
+ import react from 'react';
110
+ import shared from '@/shared';
111
+ ```
112
+
113
+ After:
114
+
115
+ <!-- prettier-ignore -->
116
+ ```typescript
117
+ import react from 'react';
118
+
119
+ import shared from '@/shared';
120
+
121
+ import App from './App.tsx';
122
+ ```
123
+
124
+ Set `importOrderSeparation` to `false` if you don't want blank lines between groups.
125
+
126
+ #### Type imports
127
+
128
+ By default the plugin splits `type` imports into their own statement.
129
+
130
+ Before:
131
+
132
+ <!-- prettier-ignore -->
133
+ ```typescript
134
+ import { useState, type FC } from 'react';
135
+ ```
136
+
137
+ After:
138
+
139
+ <!-- prettier-ignore -->
140
+ ```typescript
141
+ import type { FC } from 'react';
142
+ import { useState } from 'react';
143
+ ```
144
+
145
+ The shape of `importOrderTypeImports` mirrors conventions in the ESLint ecosystem, especially the `fixStyle` option of [@typescript-eslint/consistent-type-imports](https://typescript-eslint.io/rules/consistent-type-imports).
146
+
147
+ Using `import { c, type B, a } from 'mod';` as an example:
148
+
149
+ | Mode | Result |
150
+ | -------------- | ------------------------------------------------------------- |
151
+ | `separate` | `import type { B } from 'mod';`<br>`import { a, c } from 'mod';` |
152
+ | `inline-first` | `import { type B, a, c } from 'mod';` |
153
+ | `inline-last` | `import { a, c, type B } from 'mod';` |
154
+ | `mixed` | `import { a, type B, c } from 'mod';` |
155
+
156
+ `separate`, `inline-first`, and `inline-last` sort type and value specifiers independently within their own group. `mixed` sorts all specifiers together alphabetically (case-insensitive), keeping the `type` keyword inline where needed.
157
+
158
+ #### Merging same-source imports
159
+
160
+ By default, multiple `import` statements from the same source are merged into one.
161
+
162
+ Before:
163
+
164
+ <!-- prettier-ignore -->
165
+ ```typescript
166
+ import { useState } from 'react';
167
+ import { useEffect } from 'react';
168
+ ```
169
+
170
+ After:
171
+
172
+ ```typescript
173
+ import { useEffect, useState } from 'react';
174
+ ```
175
+
176
+ `importOrderMergeDuplicates` only handles the merge step itself. The arrangement inside the braces is entirely controlled by `importOrderTypeImports`. For instance, merging `import { useState } from 'react';` and `import { type FC, useEffect } from 'react';` produces:
177
+
178
+ - `separate` (default): the merged statement is split back into two at the type-import stage, so you end up with an independent `import type` statement
179
+ - `inline-first`: `import { type FC, useEffect, useState } from 'react';`
180
+ - `inline-last`: `import { useEffect, useState, type FC } from 'react';`
181
+ - `mixed`: `import { type FC, useEffect, useState } from 'react';`
182
+
183
+ Set `importOrderMergeDuplicates` to `false` if you want to keep the original separate statements. Side-effect imports (`import 'mod';`) are never merged because their order has runtime semantics.
184
+
185
+ Sorting rules:
186
+
187
+ - Imports are classified into groups. Within each group they are sorted alphabetically
188
+ - Default group order: `builtin` → `external` → `parent` → `sibling` → `index`
189
+ - A blank line is inserted between groups by default. Disable with `importOrderSeparation`
190
+ - `type` imports are split into their own statement by default. Use `importOrderTypeImports` to inline them instead
191
+ - Multiple imports from the same source are merged into one by default. Disable with `importOrderMergeDuplicates`
192
+ - Side-effect imports (`import 'mod'`) are never merged or moved across groups
193
+
194
+ ### Exports
195
+
196
+ By default, named specifiers inside `export { … }` are sorted alphabetically.
197
+
198
+ Before:
199
+
200
+ <!-- prettier-ignore -->
201
+ ```typescript
202
+ export { useState, useEffect, type FC } from 'react';
203
+ ```
204
+
205
+ After:
206
+
207
+ ```typescript
208
+ export { type FC, useEffect, useState } from 'react';
209
+ ```
210
+
211
+ The plugin only reorders what's inside the braces. It doesn't move the export statement itself and doesn't merge two same-source exports. Set `exportOrder` to `false` to disable this behavior.
212
+
213
+ Sorting rules:
214
+
215
+ - Named specifiers inside `export { … }` and `export type { … }` are sorted alphabetically
216
+ - The position of the export statement in the file is not changed
217
+ - Multiple export statements from the same source are not merged
218
+
219
+ ### package.json
220
+
221
+ With the default config, the output looks like this.
222
+
223
+ Before:
224
+
225
+ <!-- prettier-ignore -->
226
+ ```json
227
+ {
228
+ "version": "1.0.0",
229
+ "keywords": ["sort", "prettier", "plugin"],
230
+ "name": "demo",
231
+ "dependencies": {
232
+ "typescript": "^6.0.0",
233
+ "prettier": "^3.0.0"
234
+ }
235
+ }
236
+ ```
237
+
238
+ After:
239
+
240
+ ```json
241
+ {
242
+ "name": "demo",
243
+ "version": "1.0.0",
244
+ "keywords": ["plugin", "prettier", "sort"],
245
+ "dependencies": {
246
+ "prettier": "^3.0.0",
247
+ "typescript": "^6.0.0"
248
+ }
249
+ }
250
+ ```
251
+
252
+ Top-level key order follows the field list maintained by [sort-package-json](https://github.com/keithamus/sort-package-json), staying aligned with widely adopted community conventions.
253
+
254
+ Rules the plugin follows:
255
+
256
+ - Top-level keys are reordered to the canonical sequence (`name` → `version` → ... → `dependencies`)
257
+ - Top-level string-only arrays are sorted alphabetically, e.g. `keywords`, `files`
258
+ - `dependencies`, `devDependencies`, `peerDependencies` and other dependency maps are always sorted alphabetically, even if `packageJsonOrder` is set to `false`, because `npm install` rewrites them in alphabetical order every time
259
+ - `scripts`, `exports`, `imports` and other nested objects are not sorted recursively, because their key order carries runtime semantics
260
+ - Use `packageJsonOrderExcludeKeys` to opt specific top-level keys out of sorting entirely
261
+
262
+ ## Options
263
+
264
+ Prettier plugin options are flat, so these options are prefixed with `importOrder`, `exportOrder`, or `packageJsonOrder`.
265
+
266
+ | Option | Description | Default |
267
+ | ----------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------- |
268
+ | `importOrder` | Sort `import` declarations in JS / TS | `true` |
269
+ | `importOrderGroups` | Group order. Valid values: `builtin`, `external`, `internal`, `parent`, `sibling`, `index` | `["builtin", "external", "parent", "sibling", "index"]` |
270
+ | `importOrderSeparation` | Insert a blank line between adjacent groups | `true` |
271
+ | `importOrderTypeImports` | How to place `type` imports: `separate`, `inline-first`, `inline-last`, `mixed` | `"separate"` |
272
+ | `importOrderMergeDuplicates` | Merge multiple `import` statements from the same source (except side-effect imports) | `true` |
273
+ | `exportOrder` | Sort named specifiers inside `export { … }` alphabetically | `true` |
274
+ | `packageJsonOrder` | Sort top-level keys and string arrays in `package.json` | `true` |
275
+ | `packageJsonOrderExcludeKeys` | Top-level `package.json` keys to leave untouched | `[]` |
276
+
277
+ ## Example
278
+
279
+ ```json
280
+ {
281
+ "plugins": ["prettier-plugin-sort"],
282
+ "importOrderGroups": [
283
+ "builtin",
284
+ "external",
285
+ "internal",
286
+ "parent",
287
+ "sibling",
288
+ "index"
289
+ ],
290
+ "importOrderTypeImports": "inline-last",
291
+ "packageJsonOrderExcludeKeys": ["contributes"]
292
+ }
293
+ ```
294
+
295
+ ## Type hints
296
+
297
+ If you write your Prettier config in a `.ts` or `.js` file, you can reuse the `SortOptions` type exported by the plugin to get completion and validation.
298
+
299
+ ### In a `.ts` file
300
+
301
+ ```typescript
302
+ import { type Config } from 'prettier';
303
+ import { type SortOptions } from 'prettier-plugin-sort';
304
+
305
+ export default {
306
+ plugins: ['prettier-plugin-sort'],
307
+ importOrderGroups: [
308
+ 'builtin',
309
+ 'external',
310
+ 'internal',
311
+ 'parent',
312
+ 'sibling',
313
+ 'index',
314
+ ],
315
+ importOrderTypeImports: 'inline-last',
316
+ packageJsonOrderExcludeKeys: ['contributes'],
317
+ } satisfies Config & SortOptions;
318
+ ```
319
+
320
+ ### In a `.js` file
321
+
322
+ ```js
323
+ /** @type {import('prettier').Config & import('prettier-plugin-sort').SortOptions} */
324
+ const config = {
325
+ plugins: ['prettier-plugin-sort'],
326
+ importOrderGroups: [
327
+ 'builtin',
328
+ 'external',
329
+ 'internal',
330
+ 'parent',
331
+ 'sibling',
332
+ 'index',
333
+ ],
334
+ importOrderTypeImports: 'inline-last',
335
+ packageJsonOrderExcludeKeys: ['contributes'],
336
+ };
337
+
338
+ export default config;
339
+ ```
340
+
341
+ The `ImportGroup` and `TypeImportsStyle` literal types are also exported if you only need those.
342
+
343
+ ## Motivation
344
+
345
+ Before adopting Prettier, I relied on IDE-native sorting features to keep my code organized. As I started switching between different IDEs, I wanted a portable, unified configuration, so I brought ESLint and Prettier into my projects.
346
+
347
+ Prettier doesn't provide sorting out of the box. To sort imports I had to install `prettier-plugin-organize-imports`. To sort `package.json` I had to install `prettier-plugin-packagejson`. The fragmented experience bothered me.
348
+
349
+ I ignored this for a long time while focusing on actual development. Recently, though, I needed to control how `import type` was inlined and found that `prettier-plugin-organize-imports` didn't support it. On top of that, `prettier-plugin-packagejson`, built on `sort-package-json`, carries many dependencies that are redundant for a plugin. That's when I decided to build my own.
350
+
351
+ `prettier-plugin-sort` isn't meant to replace anything. It's about giving developers more options. Prettier is used almost entirely for JS/TS code, and every JS project has a `package.json`, so the plugin covers these two fundamental sorting tasks. The goal is to let JS developers work out of the box with minimal mental overhead (support for `tsconfig.json` sorting may be added in a future release). If you have other sorting needs, you can still install something like `prettier-plugin-css-order` alongside it. There's no conflict.
352
+
353
+ ## Credits
354
+
355
+ - `eslint-plugin-import`: https://github.com/import-js/eslint-plugin-import
356
+ - `typescript-eslint`: https://github.com/typescript-eslint/typescript-eslint
357
+ - `sort-package-json`: https://github.com/keithamus/sort-package-json