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 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,3 @@
1
+ import type { Rule } from 'eslint';
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -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":"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"}
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
+ }