eslint-plugin-logical-imports 0.1.0
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.txt +27 -0
- package/README.md +290 -0
- package/build/src/index.d.ts +18 -0
- package/build/src/index.js +11 -0
- package/build/src/index.js.map +1 -0
- package/build/src/rule.d.ts +3 -0
- package/build/src/rule.js +320 -0
- package/build/src/rule.js.map +1 -0
- package/package.json +56 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright © 2024,2026 Phil Booth
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge,
|
|
4
|
+
to any person obtaining a copy of this software
|
|
5
|
+
and associated documentation files (the “Software”),
|
|
6
|
+
to deal in the Software without restriction,
|
|
7
|
+
including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software,
|
|
10
|
+
and to permit persons to whom the Software is furnished to do so,
|
|
11
|
+
subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice
|
|
14
|
+
shall be included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED “AS IS”,
|
|
17
|
+
WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
EXPRESS OR IMPLIED,
|
|
19
|
+
INCLUDING BUT NOT LIMITED TO
|
|
20
|
+
THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE
|
|
22
|
+
AND NONINFRINGEMENT.
|
|
23
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
24
|
+
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
25
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
26
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
27
|
+
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# eslint-plugin-logical-imports
|
|
2
|
+
|
|
3
|
+
You're sorting imports wrong!
|
|
4
|
+
|
|
5
|
+
* [No I'm not](#no-im-not)
|
|
6
|
+
* [What is this?](#what-is-this)
|
|
7
|
+
* [Options](#options)
|
|
8
|
+
* [Block glossary](#block-glossary)
|
|
9
|
+
* [Behaviour](#behaviour)
|
|
10
|
+
* [How do I install it?](#how-do-i-install-it)
|
|
11
|
+
* [How do I configure it?](#how-do-i-configure-it)
|
|
12
|
+
* [How do I use it?](#how-do-i-use-it)
|
|
13
|
+
* [What about performance?](#what-about-performance)
|
|
14
|
+
* [Can I control how it handles import blocks?](#can-i-control-how-it-handles-import-blocks)
|
|
15
|
+
* [Single imports is crazy, can I opt out of that part?](#single-imports-is-crazy-can-i-opt-out-of-that-part)
|
|
16
|
+
* [What alternatives exist?](#what-alternatives-exist)
|
|
17
|
+
* [Examples](#examples)
|
|
18
|
+
* [Change log](#change-log)
|
|
19
|
+
* [License](#license)
|
|
20
|
+
|
|
21
|
+
## No I'm not
|
|
22
|
+
|
|
23
|
+
I think you are!
|
|
24
|
+
Let me explain why.
|
|
25
|
+
If you disagree with any point,
|
|
26
|
+
that's okay and you can skip the rest of the readme.
|
|
27
|
+
This tool is not meant for you. 👍
|
|
28
|
+
|
|
29
|
+
1. What is the point of sorting anything?
|
|
30
|
+
Firstly, to make things easier to find,
|
|
31
|
+
especially when using human eyeballs.
|
|
32
|
+
Secondly, to make things easier to insert,
|
|
33
|
+
by providing a single objectively correct insertion point
|
|
34
|
+
(which is also easy to find).
|
|
35
|
+
|
|
36
|
+
2. What are you most often trying to find when eyeballing a block of imports?
|
|
37
|
+
A local name,
|
|
38
|
+
which could be an alias.
|
|
39
|
+
Something that is referenced elsewhere in the current file.
|
|
40
|
+
|
|
41
|
+
3. If you're looking for a local name,
|
|
42
|
+
what order should the imports be sorted by?
|
|
43
|
+
The local names should be sorted alphabetically.
|
|
44
|
+
|
|
45
|
+
4. What happens if you sort by module path instead?
|
|
46
|
+
It breaks the sort order of local names.
|
|
47
|
+
They might as well be sorted randomly.
|
|
48
|
+
|
|
49
|
+
5. What happens if you sort by export name instead?
|
|
50
|
+
It breaks the sort order of aliased local names.
|
|
51
|
+
They might as well be sorted randomly.
|
|
52
|
+
|
|
53
|
+
6. What happens if you group imports from the same module into a single declaration?
|
|
54
|
+
It breaks the sort order of local names relative to other modules.
|
|
55
|
+
They might as well be sorted randomly.
|
|
56
|
+
|
|
57
|
+
7. What is the only consistent and logical method for sorting imports?
|
|
58
|
+
By breaking down declarations to a single import each,
|
|
59
|
+
then sorting them alphabetically by the local name.
|
|
60
|
+
|
|
61
|
+
## What is this?
|
|
62
|
+
|
|
63
|
+
An ESLint plugin that enforces
|
|
64
|
+
an unconventional, highly opinionated but also very logical
|
|
65
|
+
import style:
|
|
66
|
+
|
|
67
|
+
1. One import per declaration.
|
|
68
|
+
If you need multiple imports from a module,
|
|
69
|
+
there must be equally many declarations.
|
|
70
|
+
|
|
71
|
+
2. Declarations are sorted alphabetically by the local name.
|
|
72
|
+
The thing that is actually referenced in the rest of the codebase
|
|
73
|
+
is the thing that should drive the ordering of imports.
|
|
74
|
+
|
|
75
|
+
### Options
|
|
76
|
+
|
|
77
|
+
Option|Type|Default|Description
|
|
78
|
+
------|----|-------|-----------
|
|
79
|
+
`allowMultipleSpecifiers`|`boolean`|`false`|When `true`, allows `import { a, b } from 'x'` instead of splitting into one specifier per statement.
|
|
80
|
+
`blocks`|`string[]`|`['builtin', 'external', 'internal']`|Group imports into sorted blocks separated by a blank line. Pass `[]` to group everything as a single block.
|
|
81
|
+
|
|
82
|
+
#### Block glossary
|
|
83
|
+
|
|
84
|
+
Value|Matches
|
|
85
|
+
-----|-------
|
|
86
|
+
`builtin`|Node/Deno/Bun builtins, e.g. `node:fs`, `module`, `bun:test`
|
|
87
|
+
`builtin:types`|Type-only imports of builtins
|
|
88
|
+
`external`|External dependencies (npm packages)
|
|
89
|
+
`external:types`|Type-only imports of external dependencies
|
|
90
|
+
`internal`|Local dependencies, e.g. `./foo/bar`, `../baz`, `/qux`
|
|
91
|
+
`internal:types`|Type-only imports of internal dependencies
|
|
92
|
+
|
|
93
|
+
If a `:types` variant is omitted from `blocks`,
|
|
94
|
+
type imports of that category fall back to the runtime-block peer,
|
|
95
|
+
so the default config merges types into their runtime blocks.
|
|
96
|
+
|
|
97
|
+
### Behaviour
|
|
98
|
+
|
|
99
|
+
* Sort key is the _local_ name:
|
|
100
|
+
|
|
101
|
+
Import|Sort key
|
|
102
|
+
------|--------
|
|
103
|
+
`import Foo from 'x'`|`Foo`
|
|
104
|
+
`import * as ns from 'x'`|`ns`
|
|
105
|
+
`import { foo } from 'x'`|`foo`
|
|
106
|
+
`import { foo as bar } from 'x'`|`bar`
|
|
107
|
+
`import type { Foo } from 'x'`|`Foo`
|
|
108
|
+
`import { type Foo } from 'x'`|`Foo`
|
|
109
|
+
|
|
110
|
+
Comparison is then case-insensitive `localeCompare`,
|
|
111
|
+
with ASCII tie-break for stability.
|
|
112
|
+
|
|
113
|
+
* Side-effect imports (`import 'x'`) act as fences.
|
|
114
|
+
They're never reordered and imports either side are sorted independently.
|
|
115
|
+
|
|
116
|
+
* Comments stay attached to their import.
|
|
117
|
+
Leading line and block comments move with the import below,
|
|
118
|
+
trailing same-line comments stay on the right.
|
|
119
|
+
|
|
120
|
+
* Floating comments (a comment with blank lines on either side)
|
|
121
|
+
attach to the next import,
|
|
122
|
+
per ESLint's `getCommentsBefore` semantics.
|
|
123
|
+
|
|
124
|
+
* Line endings (LF or CRLF)
|
|
125
|
+
are detected per file.
|
|
126
|
+
|
|
127
|
+
## How do I install it?
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
npm install --save-dev eslint-plugin-logical-imports
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Requires Node >= 24 and ESLint >= 10.
|
|
134
|
+
|
|
135
|
+
## How do I configure it?
|
|
136
|
+
|
|
137
|
+
Add the recommended config
|
|
138
|
+
to your `eslint.config.js`:
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
// ...
|
|
142
|
+
import logicalImports from 'eslint-plugin-logical-imports';
|
|
143
|
+
|
|
144
|
+
export default [
|
|
145
|
+
// ...
|
|
146
|
+
logicalImports.configs.recommended,
|
|
147
|
+
];
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Or configure it manually:
|
|
151
|
+
|
|
152
|
+
```js
|
|
153
|
+
// ...
|
|
154
|
+
import logicalImports from 'eslint-plugin-logical-imports';
|
|
155
|
+
|
|
156
|
+
export default [
|
|
157
|
+
// ...
|
|
158
|
+
{
|
|
159
|
+
plugins: { 'logical-imports': logicalImports },
|
|
160
|
+
rules: {
|
|
161
|
+
'logical-imports/order': ['error', {
|
|
162
|
+
allowMultipleSpecifiers: false,
|
|
163
|
+
blocks: ['builtin', 'external', 'internal'],
|
|
164
|
+
}],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## How do I use it?
|
|
171
|
+
|
|
172
|
+
Just run `eslint` as you normally would.
|
|
173
|
+
The plugin implements a single, atomic fix
|
|
174
|
+
so `eslint --fix` converges in one pass
|
|
175
|
+
(i.e. is guaranteed to work).
|
|
176
|
+
|
|
177
|
+
## What about performance?
|
|
178
|
+
|
|
179
|
+
There's no impact from splitting imports across multiple declarations.
|
|
180
|
+
The [spec](https://262.ecma-international.org/16.0/index.html#sec-HostLoadImportedModule) mandates
|
|
181
|
+
that all imports of a module must resolve to the same cached hit.
|
|
182
|
+
This works in all runtimes and bundlers.
|
|
183
|
+
|
|
184
|
+
## Can I control how it handles import blocks?
|
|
185
|
+
|
|
186
|
+
Yes, you can re-order the blocks if you wish:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
// ...
|
|
190
|
+
import logicalImports from 'eslint-plugin-logical-imports';
|
|
191
|
+
|
|
192
|
+
export default [
|
|
193
|
+
// ...
|
|
194
|
+
{
|
|
195
|
+
plugins: { 'logical-imports': logicalImports },
|
|
196
|
+
rules: {
|
|
197
|
+
'logical-imports/order': ['error', {
|
|
198
|
+
blocks: ['internal', 'external', 'builtin'],
|
|
199
|
+
}],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
];
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Or separate types from runtime imports:
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
// ...
|
|
209
|
+
import logicalImports from 'eslint-plugin-logical-imports';
|
|
210
|
+
|
|
211
|
+
export default [
|
|
212
|
+
// ...
|
|
213
|
+
{
|
|
214
|
+
plugins: { 'logical-imports': logicalImports },
|
|
215
|
+
rules: {
|
|
216
|
+
'logical-imports/order': ['error', {
|
|
217
|
+
blocks: ['builtin', 'external', 'internal', 'builtin:types', 'external:types', 'internal:types'],
|
|
218
|
+
}],
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
];
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Single imports is crazy, can I opt out of that part?
|
|
225
|
+
|
|
226
|
+
_Deep sigh, sad face._
|
|
227
|
+
Yes, you can.
|
|
228
|
+
Set `allowMultipleSpecifiers: true` in config:
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
// ...
|
|
232
|
+
import logicalImports from 'eslint-plugin-logical-imports';
|
|
233
|
+
|
|
234
|
+
export default [
|
|
235
|
+
// ...
|
|
236
|
+
{
|
|
237
|
+
plugins: { 'logical-imports': logicalImports },
|
|
238
|
+
rules: {
|
|
239
|
+
'logical-imports/order': ['error', {
|
|
240
|
+
allowMultipleSpecifiers: true,
|
|
241
|
+
}],
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Import declarations will be ordered by their first specifier,
|
|
248
|
+
but individual specifiers within each declaration will not be sorted.
|
|
249
|
+
|
|
250
|
+
## What alternatives exist?
|
|
251
|
+
|
|
252
|
+
* [`eslint-plugin-import`](https://github.com/import-js/eslint-plugin-import):
|
|
253
|
+
Sorts alphabetically by module path,
|
|
254
|
+
which is objectively wrong.
|
|
255
|
+
|
|
256
|
+
* [`eslint-plugin-simple-import-sort`](https://github.com/lydell/eslint-plugin-simple-import-sort):
|
|
257
|
+
Sorts alphabetically by module path,
|
|
258
|
+
wrong.
|
|
259
|
+
|
|
260
|
+
## Examples
|
|
261
|
+
|
|
262
|
+
Before:
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
266
|
+
import path from 'node:path';
|
|
267
|
+
import { foo } from './foo';
|
|
268
|
+
import fs from 'node:fs';
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
After, with recommended config:
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
import fs from 'node:fs';
|
|
275
|
+
import path from 'node:path';
|
|
276
|
+
|
|
277
|
+
import { useEffect } from 'react';
|
|
278
|
+
import { useMemo } from 'react';
|
|
279
|
+
import { useState } from 'react';
|
|
280
|
+
|
|
281
|
+
import { foo } from './foo';
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Change log
|
|
285
|
+
|
|
286
|
+
[CHANGELOG.md](CHANGELOG.md)
|
|
287
|
+
|
|
288
|
+
## License
|
|
289
|
+
|
|
290
|
+
[MIT](LICENSE.txt)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import rule from './rule.ts';
|
|
2
|
+
type Plugin = {
|
|
3
|
+
configs: {
|
|
4
|
+
recommended: {
|
|
5
|
+
plugins: {
|
|
6
|
+
'logical-imports': Plugin;
|
|
7
|
+
};
|
|
8
|
+
rules: {
|
|
9
|
+
'logical-imports/order': 'error';
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
rules: {
|
|
14
|
+
order: typeof rule;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
declare const plugin: Plugin;
|
|
18
|
+
export default plugin;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import rule from "./rule.js";
|
|
2
|
+
const plugin = {
|
|
3
|
+
configs: {},
|
|
4
|
+
rules: { order: rule },
|
|
5
|
+
};
|
|
6
|
+
plugin.configs.recommended = {
|
|
7
|
+
plugins: { 'logical-imports': plugin },
|
|
8
|
+
rules: { 'logical-imports/order': 'error' },
|
|
9
|
+
};
|
|
10
|
+
export default plugin;
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAc7B,MAAM,MAAM,GAAW;IACrB,OAAO,EAAE,EAAuB;IAChC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,CAAC,WAAW,GAAG;IAC3B,OAAO,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE;IACtC,KAAK,EAAE,EAAE,uBAAuB,EAAE,OAAO,EAAE;CAC5C,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { builtinModules } from 'node:module';
|
|
2
|
+
const BlockTypes = {
|
|
3
|
+
builtin: 'builtin',
|
|
4
|
+
builtinTypes: 'builtin:types',
|
|
5
|
+
external: 'external',
|
|
6
|
+
externalTypes: 'external:types',
|
|
7
|
+
internal: 'internal',
|
|
8
|
+
internalTypes: 'internal:types',
|
|
9
|
+
};
|
|
10
|
+
const DEFAULT_BLOCKS = [
|
|
11
|
+
BlockTypes.builtin,
|
|
12
|
+
BlockTypes.external,
|
|
13
|
+
BlockTypes.internal,
|
|
14
|
+
];
|
|
15
|
+
const BUILTIN_MODULES = new Set(builtinModules);
|
|
16
|
+
const Messages = {
|
|
17
|
+
disorderedBlocks: 'disorderedBlocks',
|
|
18
|
+
disorderedDeclarations: 'disorderedDeclarations',
|
|
19
|
+
disorderedSpecifiers: 'disorderedSpecifiers',
|
|
20
|
+
muddledBlocks: 'muddledBlocks',
|
|
21
|
+
multipleSpecifiers: 'multipleSpecifiers',
|
|
22
|
+
};
|
|
23
|
+
const rule = {
|
|
24
|
+
create(context) {
|
|
25
|
+
const { allowMultipleSpecifiers, blocks } = (context.options[0] ?? {});
|
|
26
|
+
const blockOrder = blocks ?? DEFAULT_BLOCKS;
|
|
27
|
+
const { sourceCode } = context;
|
|
28
|
+
const lineEnding = detectLineEnding(sourceCode.text);
|
|
29
|
+
const isFlat = blockOrder.length === 0;
|
|
30
|
+
return {
|
|
31
|
+
'Program:exit'() {
|
|
32
|
+
for (const chunk of getChunks(sourceCode.ast.body)) {
|
|
33
|
+
const multiSpecDecls = allowMultipleSpecifiers
|
|
34
|
+
? []
|
|
35
|
+
: chunk.filter((decl) => decl.specifiers.length > 1);
|
|
36
|
+
const runs = isFlat ? [] : getBlockRuns(chunk, blockOrder);
|
|
37
|
+
const isMuddled = !isFlat && new Set(runs).size !== runs.length;
|
|
38
|
+
const isDisorderedBlocks = !isFlat && !isMuddled && !isSubsequence(runs, blockOrder);
|
|
39
|
+
const isDisorderedDecls = hasDisorderedDecls(chunk, blockOrder);
|
|
40
|
+
if (multiSpecDecls.length === 0
|
|
41
|
+
&& !isMuddled
|
|
42
|
+
&& !isDisorderedBlocks
|
|
43
|
+
&& !isDisorderedDecls) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const extendedRanges = chunk.map((decl, i) => getExtendedRange(decl, i > 0 ? chunk[i - 1] : null, sourceCode));
|
|
47
|
+
const newText = buildChunkText(chunk, extendedRanges, sourceCode, blockOrder, lineEnding, allowMultipleSpecifiers ?? false);
|
|
48
|
+
const fix = (fixer) => fixer.replaceTextRange([extendedRanges[0][0], extendedRanges[extendedRanges.length - 1][1]], newText);
|
|
49
|
+
for (const decl of multiSpecDecls) {
|
|
50
|
+
context.report({ fix, messageId: Messages.multipleSpecifiers, node: decl });
|
|
51
|
+
}
|
|
52
|
+
if (isMuddled) {
|
|
53
|
+
context.report({ fix, messageId: Messages.muddledBlocks, node: chunk[0] });
|
|
54
|
+
}
|
|
55
|
+
if (isDisorderedBlocks) {
|
|
56
|
+
context.report({ fix, messageId: Messages.disorderedBlocks, node: chunk[0] });
|
|
57
|
+
}
|
|
58
|
+
if (isDisorderedDecls) {
|
|
59
|
+
context.report({ fix, messageId: Messages.disorderedDeclarations, node: chunk[0] });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
meta: {
|
|
66
|
+
docs: {
|
|
67
|
+
description: 'Enforce logical, deterministic ordering of import statements',
|
|
68
|
+
url: 'https://gitlab.com/philbooth/eslint-plugin-logical-imports#eslint-plugin-logical-imports',
|
|
69
|
+
},
|
|
70
|
+
fixable: 'code',
|
|
71
|
+
messages: {
|
|
72
|
+
[Messages.disorderedBlocks]: 'Consistently order import blocks to make them easier to work with',
|
|
73
|
+
[Messages.disorderedDeclarations]: 'Consistently order import declarations to make them easier to work with',
|
|
74
|
+
[Messages.disorderedSpecifiers]: 'Consistently order import specifiers to make them easier to work with',
|
|
75
|
+
[Messages.muddledBlocks]: 'Group imports into blocks by type to make them easier to work with',
|
|
76
|
+
[Messages.multipleSpecifiers]: 'Restrict import declarations to one specifier so they can be ordered along a single dimension',
|
|
77
|
+
},
|
|
78
|
+
schema: {
|
|
79
|
+
items: [
|
|
80
|
+
{
|
|
81
|
+
additionalProperties: false,
|
|
82
|
+
properties: {
|
|
83
|
+
allowMultipleSpecifiers: {
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
},
|
|
86
|
+
blocks: {
|
|
87
|
+
items: {
|
|
88
|
+
enum: [
|
|
89
|
+
'builtin',
|
|
90
|
+
'builtin:types',
|
|
91
|
+
'external',
|
|
92
|
+
'external:types',
|
|
93
|
+
'internal',
|
|
94
|
+
'internal:types',
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
maxItems: 6,
|
|
98
|
+
minItems: 0,
|
|
99
|
+
type: 'array',
|
|
100
|
+
uniqueItems: true,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
type: 'object',
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
maxItems: 1,
|
|
107
|
+
minItems: 0,
|
|
108
|
+
type: 'array',
|
|
109
|
+
},
|
|
110
|
+
type: 'suggestion'
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
export default rule;
|
|
114
|
+
function getChunks(body) {
|
|
115
|
+
const chunks = [];
|
|
116
|
+
let chunk = [];
|
|
117
|
+
for (const node of body) {
|
|
118
|
+
const isSortable = node.type === 'ImportDeclaration' && node.specifiers.length > 0;
|
|
119
|
+
if (isSortable) {
|
|
120
|
+
chunk.push(node);
|
|
121
|
+
}
|
|
122
|
+
else if (chunk.length > 0) {
|
|
123
|
+
chunks.push(chunk);
|
|
124
|
+
chunk = [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (chunk.length > 0) {
|
|
128
|
+
chunks.push(chunk);
|
|
129
|
+
}
|
|
130
|
+
return chunks;
|
|
131
|
+
}
|
|
132
|
+
function buildChunkText(chunk, extendedRanges, sourceCode, blockOrder, lineEnding, allowMultipleSpecifiers) {
|
|
133
|
+
const items = getLogicalImports(chunk, extendedRanges, sourceCode, blockOrder, allowMultipleSpecifiers);
|
|
134
|
+
if (blockOrder.length === 0) {
|
|
135
|
+
return items
|
|
136
|
+
.sort((a, b) => compareKeys(a.sortKey, b.sortKey))
|
|
137
|
+
.map((item) => item.text)
|
|
138
|
+
.join(lineEnding);
|
|
139
|
+
}
|
|
140
|
+
const buckets = new Map();
|
|
141
|
+
for (const item of items) {
|
|
142
|
+
const bucket = buckets.get(item.block) ?? [];
|
|
143
|
+
bucket.push(item);
|
|
144
|
+
buckets.set(item.block, bucket);
|
|
145
|
+
}
|
|
146
|
+
return blockOrder
|
|
147
|
+
.map((block) => buckets.get(block))
|
|
148
|
+
.filter((bucket) => bucket !== undefined && bucket.length > 0)
|
|
149
|
+
.map((bucket) => bucket
|
|
150
|
+
.sort((a, b) => compareKeys(a.sortKey, b.sortKey))
|
|
151
|
+
.map((item) => item.text)
|
|
152
|
+
.join(lineEnding))
|
|
153
|
+
.join(lineEnding + lineEnding);
|
|
154
|
+
}
|
|
155
|
+
function getLogicalImports(chunk, extendedRanges, sourceCode, blockOrder, allowMultipleSpecifiers) {
|
|
156
|
+
const items = [];
|
|
157
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
158
|
+
const decl = chunk[i];
|
|
159
|
+
const block = classify(decl, blockOrder);
|
|
160
|
+
if (decl.specifiers.length > 1 && !allowMultipleSpecifiers) {
|
|
161
|
+
for (const specifier of decl.specifiers) {
|
|
162
|
+
items.push({
|
|
163
|
+
block,
|
|
164
|
+
sortKey: specifier.local.name,
|
|
165
|
+
text: formatSpecifier(decl, specifier),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const [start, end] = extendedRanges[i];
|
|
171
|
+
items.push({
|
|
172
|
+
block,
|
|
173
|
+
sortKey: decl.specifiers[0].local.name,
|
|
174
|
+
text: sourceCode.text.slice(start, end),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return items;
|
|
179
|
+
}
|
|
180
|
+
function getExtendedRange(decl, prevDecl, sourceCode) {
|
|
181
|
+
const leading = getLeadingComments(decl, prevDecl, sourceCode);
|
|
182
|
+
const trailing = getTrailingSameLineComments(decl, sourceCode);
|
|
183
|
+
const start = leading.length > 0 ? leading[0].range[0] : decl.range[0];
|
|
184
|
+
const end = trailing.length > 0 ? trailing[trailing.length - 1].range[1] : decl.range[1];
|
|
185
|
+
return [start, end];
|
|
186
|
+
}
|
|
187
|
+
function getLeadingComments(decl, prevDecl, sourceCode) {
|
|
188
|
+
const before = sourceCode.getCommentsBefore(decl);
|
|
189
|
+
if (prevDecl === null) {
|
|
190
|
+
return before;
|
|
191
|
+
}
|
|
192
|
+
const prevEndLine = prevDecl.loc.end.line;
|
|
193
|
+
return before.filter((comment) => comment.loc.start.line !== prevEndLine);
|
|
194
|
+
}
|
|
195
|
+
function getTrailingSameLineComments(decl, sourceCode) {
|
|
196
|
+
const after = sourceCode.getCommentsAfter(decl);
|
|
197
|
+
const declEndLine = decl.loc.end.line;
|
|
198
|
+
return after.filter((comment) => comment.loc.start.line === declEndLine);
|
|
199
|
+
}
|
|
200
|
+
function detectLineEnding(text) {
|
|
201
|
+
const crlf = (text.match(/\r\n/g) ?? []).length;
|
|
202
|
+
const lf = (text.match(/(?<!\r)\n/g) ?? []).length;
|
|
203
|
+
return crlf > lf ? '\r\n' : '\n';
|
|
204
|
+
}
|
|
205
|
+
function classify(decl, blockOrder) {
|
|
206
|
+
const baseBlock = getBaseBlock(decl);
|
|
207
|
+
if (isTypeImport(decl)) {
|
|
208
|
+
const typesBlock = `${baseBlock}:types`;
|
|
209
|
+
if (blockOrder.includes(typesBlock)) {
|
|
210
|
+
return typesBlock;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return baseBlock;
|
|
214
|
+
}
|
|
215
|
+
function getBaseBlock(decl) {
|
|
216
|
+
const source = decl.source.value;
|
|
217
|
+
if (/^(bun|deno|node):/.test(source) || BUILTIN_MODULES.has(source)) {
|
|
218
|
+
return BlockTypes.builtin;
|
|
219
|
+
}
|
|
220
|
+
if (source.startsWith('.') || source.startsWith('/')) {
|
|
221
|
+
return BlockTypes.internal;
|
|
222
|
+
}
|
|
223
|
+
return BlockTypes.external;
|
|
224
|
+
}
|
|
225
|
+
function isTypeImport(decl) {
|
|
226
|
+
if (decl.importKind === 'type') {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
return decl.specifiers.some((specifier) => specifier.importKind === 'type');
|
|
230
|
+
}
|
|
231
|
+
function getBlockRuns(chunk, blockOrder) {
|
|
232
|
+
const runs = [];
|
|
233
|
+
for (const decl of chunk) {
|
|
234
|
+
const block = classify(decl, blockOrder);
|
|
235
|
+
if (runs[runs.length - 1] !== block) {
|
|
236
|
+
runs.push(block);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return runs;
|
|
240
|
+
}
|
|
241
|
+
function isSubsequence(runs, blockOrder) {
|
|
242
|
+
let i = 0;
|
|
243
|
+
for (const run of runs) {
|
|
244
|
+
while (i < blockOrder.length && blockOrder[i] !== run) {
|
|
245
|
+
i++;
|
|
246
|
+
}
|
|
247
|
+
if (i >= blockOrder.length) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
i++;
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
function hasDisorderedDecls(chunk, blockOrder) {
|
|
255
|
+
if (blockOrder.length === 0) {
|
|
256
|
+
if (chunk.length < 2) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
const sorted = [...chunk].sort(compareImports);
|
|
260
|
+
return sorted.some((decl, i) => decl !== chunk[i]);
|
|
261
|
+
}
|
|
262
|
+
const buckets = new Map();
|
|
263
|
+
for (const decl of chunk) {
|
|
264
|
+
const block = classify(decl, blockOrder);
|
|
265
|
+
const bucket = buckets.get(block) ?? [];
|
|
266
|
+
bucket.push(decl);
|
|
267
|
+
buckets.set(block, bucket);
|
|
268
|
+
}
|
|
269
|
+
for (const bucket of buckets.values()) {
|
|
270
|
+
if (bucket.length < 2) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const sorted = [...bucket].sort(compareImports);
|
|
274
|
+
if (sorted.some((decl, i) => decl !== bucket[i])) {
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
function formatSpecifier(decl, specifier) {
|
|
281
|
+
if (isImportDefaultSpecifier(specifier)) {
|
|
282
|
+
return formatImport(specifier.local.name, decl.source.raw);
|
|
283
|
+
}
|
|
284
|
+
if (isImportNamespaceSpecifier(specifier)) {
|
|
285
|
+
return formatImport(`* as ${specifier.local.name}`, decl.source.raw);
|
|
286
|
+
}
|
|
287
|
+
if (isIdentifier(specifier.imported) && specifier.imported.name === specifier.local.name) {
|
|
288
|
+
return formatImport(`{ ${specifier.local.name} }`, decl.source.raw);
|
|
289
|
+
}
|
|
290
|
+
const imported = isIdentifier(specifier.imported)
|
|
291
|
+
? specifier.imported.name
|
|
292
|
+
: specifier.imported.raw;
|
|
293
|
+
return formatImport(`{ ${imported} as ${specifier.local.name} }`, decl.source.raw);
|
|
294
|
+
}
|
|
295
|
+
function compareImports(a, b) {
|
|
296
|
+
return compareKeys(getSortKey(a), getSortKey(b));
|
|
297
|
+
}
|
|
298
|
+
function compareKeys(a, b) {
|
|
299
|
+
const ci = a.localeCompare(b, undefined, { sensitivity: 'base' });
|
|
300
|
+
if (ci !== 0) {
|
|
301
|
+
return ci;
|
|
302
|
+
}
|
|
303
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
304
|
+
}
|
|
305
|
+
function getSortKey(node) {
|
|
306
|
+
return node.specifiers[0].local.name;
|
|
307
|
+
}
|
|
308
|
+
function isIdentifier(node) {
|
|
309
|
+
return node.type === 'Identifier';
|
|
310
|
+
}
|
|
311
|
+
function isImportDefaultSpecifier(node) {
|
|
312
|
+
return node.type === 'ImportDefaultSpecifier';
|
|
313
|
+
}
|
|
314
|
+
function isImportNamespaceSpecifier(node) {
|
|
315
|
+
return node.type === 'ImportNamespaceSpecifier';
|
|
316
|
+
}
|
|
317
|
+
function formatImport(lhs, rhs) {
|
|
318
|
+
return `import ${lhs} from ${rhs};`;
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../src/rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAyB7C,MAAM,UAAU,GAAG;IACjB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,eAAe;IAC7B,QAAQ,EAAE,UAAU;IACpB,aAAa,EAAE,gBAAgB;IAC/B,QAAQ,EAAE,UAAU;IACpB,aAAa,EAAE,gBAAgB;CACvB,CAAC;AAGX,MAAM,cAAc,GAAiB;IACnC,UAAU,CAAC,OAAO;IAClB,UAAU,CAAC,QAAQ;IACnB,UAAU,CAAC,QAAQ;CACpB,CAAC;AAEF,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;AAEhD,MAAM,QAAQ,GAAG;IACf,gBAAgB,EAAE,kBAAkB;IACpC,sBAAsB,EAAE,wBAAwB;IAChD,oBAAoB,EAAE,sBAAsB;IAC5C,aAAa,EAAE,eAAe;IAC9B,kBAAkB,EAAE,oBAAoB;CAChC,CAAC;AAGX,MAAM,IAAI,GAAoB;IAC5B,MAAM,CAAC,OAAyB;QAC9B,MAAM,EAAE,uBAAuB,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAY,CAAC;QAClF,MAAM,UAAU,GAAG,MAAM,IAAI,cAAc,CAAC;QAC5C,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;QAC/B,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAErD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC;QAEvC,OAAO;YACL,cAAc;gBACZ,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACnD,MAAM,cAAc,GAAG,uBAAuB;wBAC5C,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;oBAC3D,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC;oBAChE,MAAM,kBAAkB,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;oBACrF,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;oBAEhE,IACE,cAAc,CAAC,MAAM,KAAK,CAAC;2BACxB,CAAC,SAAS;2BACV,CAAC,kBAAkB;2BACnB,CAAC,iBAAiB,EACrB,CAAC;wBACD,SAAS;oBACX,CAAC;oBAED,MAAM,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAC3C,gBAAgB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAChE,CAAC;oBACF,MAAM,OAAO,GAAG,cAAc,CAC5B,KAAK,EACL,cAAc,EACd,UAAU,EACV,UAAU,EACV,UAAU,EACV,uBAAuB,IAAI,KAAK,CACjC,CAAC;oBACF,MAAM,GAAG,GAAG,CAAC,KAAqB,EAAE,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAC3D,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACpE,OAAO,CACR,CAAC;oBAEF,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;wBAClC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC9E,CAAC;oBAED,IAAI,SAAS,EAAE,CAAC;wBACd,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC7E,CAAC;oBAED,IAAI,kBAAkB,EAAE,CAAC;wBACvB,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,gBAAgB,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAChF,CAAC;oBAED,IAAI,iBAAiB,EAAE,CAAC;wBACtB,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,sBAAsB,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACtF,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IACD,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,8DAA8D;YAC3E,GAAG,EAAE,0FAA0F;SAChG;QACD,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE;YACR,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,mEAAmE;YAChG,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,yEAAyE;YAC5G,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,uEAAuE;YACxG,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,oEAAoE;YAC9F,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,+FAA+F;SAC/H;QACD,MAAM,EAAE;YACN,KAAK,EAAE;gBACL;oBACE,oBAAoB,EAAE,KAAK;oBAC3B,UAAU,EAAE;wBACV,uBAAuB,EAAE;4BACvB,IAAI,EAAE,SAAS;yBAChB;wBACD,MAAM,EAAE;4BACN,KAAK,EAAE;gCACL,IAAI,EAAE;oCACJ,SAAS;oCACT,eAAe;oCACf,UAAU;oCACV,gBAAgB;oCAChB,UAAU;oCACV,gBAAgB;iCACjB;6BACF;4BACD,QAAQ,EAAE,CAAC;4BACX,QAAQ,EAAE,CAAC;4BACX,IAAI,EAAE,OAAO;4BACb,WAAW,EAAE,IAAI;yBAClB;qBACF;oBACD,IAAI,EAAE,QAAQ;iBACf;aACF;YACD,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,CAAC;YACX,IAAI,EAAE,OAAO;SACd;QACD,IAAI,EAAE,YAAY;KACnB;CACF,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,SAAS,SAAS,CAAC,IAAqB;IACtC,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,IAAI,KAAK,GAAwB,EAAE,CAAC;IAEpC,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QAEnF,IAAI,UAAU,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,KAAK,GAAG,EAAE,CAAC;QACb,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CACrB,KAA0B,EAC1B,cAAkC,EAClC,UAAsB,EACtB,UAAwB,EACxB,UAAkB,EAClB,uBAAgC;IAEhC,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC;IAExG,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK;aACT,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;aACjD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACxB,IAAI,CAAC,UAAU,CAAC,CAAC;IACtB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAA+B,CAAC;IAEvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,UAAU;SACd,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;SAClC,MAAM,CAAC,CAAC,MAAM,EAA6B,EAAE,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;SACxF,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;SACpB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;SACjD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACxB,IAAI,CAAC,UAAU,CAAC,CAAC;SACnB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,iBAAiB,CACxB,KAA0B,EAC1B,cAAkC,EAClC,UAAsB,EACtB,UAAwB,EACxB,uBAAgC;IAEhC,MAAM,KAAK,GAAoB,EAAE,CAAC;IAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAEzC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAC3D,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,KAAK,CAAC,IAAI,CAAC;oBACT,KAAK;oBACL,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI;oBAC7B,IAAI,EAAE,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC;iBACvC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC;gBACT,KAAK;gBACL,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;gBACtC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC;aACxC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gBAAgB,CACvB,IAAuB,EACvB,QAAkC,EAClC,UAAsB;IAEtB,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC/D,MAAM,QAAQ,GAAG,2BAA2B,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAM,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAM,CAAC,CAAC,CAAC,CAAC;IAE3F,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,kBAAkB,CACzB,IAAuB,EACvB,QAAkC,EAClC,UAAsB;IAEtB,MAAM,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAElD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IAE3C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAI,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,2BAA2B,CAAC,IAAuB,EAAE,UAAsB;IAClF,MAAM,KAAK,GAAG,UAAU,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IAEvC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAI,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAChD,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAEnD,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC;AAED,SAAS,QAAQ,CAAC,IAAuB,EAAE,UAAwB;IACjE,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAErC,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,GAAG,SAAS,QAAsB,CAAC;QAEtD,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACpC,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,YAAY,CAAC,IAAuB;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAe,CAAC;IAE3C,IAAI,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACpE,OAAO,UAAU,CAAC,OAAO,CAAC;IAC5B,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO,UAAU,CAAC,QAAQ,CAAC;IAC7B,CAAC;IAED,OAAO,UAAU,CAAC,QAAQ,CAAC;AAC7B,CAAC;AAED,SAAS,YAAY,CAAC,IAAuB;IAC3C,IAAK,IAA2C,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CACzB,CAAC,SAAS,EAAE,EAAE,CAAE,SAA+C,CAAC,UAAU,KAAK,MAAM,CACtF,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAA0B,EAAE,UAAwB;IACxE,MAAM,IAAI,GAAiB,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAEzC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,IAAkB,EAAE,UAAwB;IACjE,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACtD,CAAC,EAAE,CAAC;QACN,CAAC;QAED,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,CAAC,EAAE,CAAC;IACN,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,KAA0B,EAAE,UAAwB;IAC9E,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE/C,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;IAE3D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAEhD,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CACtB,IAAuB,EACvB,SAA8E;IAE9E,IAAI,wBAAwB,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,OAAO,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,0BAA0B,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1C,OAAO,YAAY,CAAC,QAAQ,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACzF,OAAO,YAAY,CAAC,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC;QAC/C,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI;QACzB,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAI,CAAC;IAE5B,OAAO,YAAY,CAAC,KAAK,QAAQ,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAI,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,cAAc,CAAC,CAAoB,EAAE,CAAoB;IAChE,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,WAAW,CAAC,CAAS,EAAE,CAAS;IACvC,MAAM,EAAE,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IAElE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,UAAU,CAAC,IAAuB;IACzC,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACvC,CAAC;AAED,SAAS,YAAY,CACnB,IAA0B;IAE1B,OAAO,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC;AACpC,CAAC;AAED,SAAS,wBAAwB,CAC/B,IAAyE;IAEzE,OAAO,IAAI,CAAC,IAAI,KAAK,wBAAwB,CAAC;AAChD,CAAC;AAED,SAAS,0BAA0B,CACjC,IAAyE;IAEzE,OAAO,IAAI,CAAC,IAAI,KAAK,0BAA0B,CAAC;AAClD,CAAC;AAED,SAAS,YAAY,CAAC,GAAW,EAAE,GAAW;IAC5C,OAAO,UAAU,GAAG,SAAS,GAAG,GAAG,CAAC;AACtC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eslint-plugin-logical-imports",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ESLint plugin that enforces one specifier per import statement and alphabetical sort by local symbol name, with configurable block grouping.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Phil Booth (https://philbooth.me/)",
|
|
7
|
+
"homepage": "https://gitlab.com/philbooth/eslint-plugin-logical-imports#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://gitlab.com/philbooth/eslint-plugin-logical-imports.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://gitlab.com/philbooth/eslint-plugin-logical-imports/-/issues"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./build/src/index.d.ts",
|
|
18
|
+
"default": "./build/src/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"build/src"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=24"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"clean": "rm -rf build",
|
|
31
|
+
"lint": "eslint",
|
|
32
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
33
|
+
"test": "tsc --noEmit && node --test test/*.ts",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"eslint",
|
|
38
|
+
"import",
|
|
39
|
+
"plugin",
|
|
40
|
+
"sort"
|
|
41
|
+
],
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"eslint": ">=10"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@eslint/js": "^10.0.1",
|
|
47
|
+
"@types/estree": "^1.0.8",
|
|
48
|
+
"@types/node": "^25.6.0",
|
|
49
|
+
"@typescript-eslint/parser": "^8.59.0",
|
|
50
|
+
"eslint": "^10.2.1",
|
|
51
|
+
"globals": "^17.5.0",
|
|
52
|
+
"please-release-me": "^3.4.1",
|
|
53
|
+
"typescript": "^6.0.3",
|
|
54
|
+
"typescript-eslint": "^8.59.0"
|
|
55
|
+
}
|
|
56
|
+
}
|