Skip to content

Commit 47ea669

Browse files
remcohaszingljharb
authored andcommitted
[Fix] order: Fix import ordering in TypeScript module declarations
Without this, `import/order` checks if all imports in a file are sorted. The autofix would then move all imports to the type of the file, breaking TypeScript module declarations. Closes #2217
1 parent 4ed7867 commit 47ea669

File tree

3 files changed

+84
-16
lines changed

3 files changed

+84
-16
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
1414

1515
### Fixed
1616
- [`no-unresolved`]: ignore type-only imports ([#2220], thanks [@jablko])
17+
- [`order`]: fix sorting imports inside TypeScript module declarations ([#2226], thanks [@remcohaszing])
1718

1819
### Changed
1920
- [Refactor] switch to an internal replacement for `pkg-up` and `read-pkg-up` ([#2047], thanks [@mgwalker])
@@ -913,6 +914,7 @@ for info on changes for earlier releases.
913914

914915
[`memo-parser`]: ./memo-parser/README.md
915916

917+
[#2226]: https://github.com/import-js/eslint-plugin-import/pull/2226
916918
[#2220]: https://github.com/import-js/eslint-plugin-import/pull/2220
917919
[#2219]: https://github.com/import-js/eslint-plugin-import/pull/2219
918920
[#2212]: https://github.com/import-js/eslint-plugin-import/pull/2212
@@ -1520,6 +1522,7 @@ for info on changes for earlier releases.
15201522
[@ramasilveyra]: https://github.com/ramasilveyra
15211523
[@randallreedjr]: https://github.com/randallreedjr
15221524
[@redbugz]: https://github.com/redbugz
1525+
[@remcohaszing]: https://github.com/remcohaszing
15231526
[@rfermann]: https://github.com/rfermann
15241527
[@rhettlivingston]: https://github.com/rhettlivingston
15251528
[@rhys-vdw]: https://github.com/rhys-vdw

src/rules/order.js

+31-16
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ function registerNode(context, importEntry, ranks, imported, excludedImportTypes
336336
}
337337
}
338338

339-
function isModuleLevelRequire(node) {
339+
function getRequireBlock(node) {
340340
let n = node;
341341
// Handle cases like `const baz = require('foo').bar.baz`
342342
// and `const foo = require('foo')()`
@@ -346,11 +346,13 @@ function isModuleLevelRequire(node) {
346346
) {
347347
n = n.parent;
348348
}
349-
return (
349+
if (
350350
n.parent.type === 'VariableDeclarator' &&
351351
n.parent.parent.type === 'VariableDeclaration' &&
352352
n.parent.parent.parent.type === 'Program'
353-
);
353+
) {
354+
return n.parent.parent.parent;
355+
}
354356
}
355357

356358
const types = ['builtin', 'external', 'internal', 'unknown', 'parent', 'sibling', 'index', 'object', 'type'];
@@ -605,7 +607,14 @@ module.exports = {
605607
},
606608
};
607609
}
608-
let imported = [];
610+
const importMap = new Map();
611+
612+
function getBlockImports(node) {
613+
if (!importMap.has(node)) {
614+
importMap.set(node, []);
615+
}
616+
return importMap.get(node);
617+
}
609618

610619
return {
611620
ImportDeclaration: function handleImports(node) {
@@ -621,7 +630,7 @@ module.exports = {
621630
type: 'import',
622631
},
623632
ranks,
624-
imported,
633+
getBlockImports(node.parent),
625634
pathGroupsExcludedImportTypes
626635
);
627636
}
@@ -652,12 +661,16 @@ module.exports = {
652661
type,
653662
},
654663
ranks,
655-
imported,
664+
getBlockImports(node.parent),
656665
pathGroupsExcludedImportTypes
657666
);
658667
},
659668
CallExpression: function handleRequires(node) {
660-
if (!isStaticRequire(node) || !isModuleLevelRequire(node)) {
669+
if (!isStaticRequire(node)) {
670+
return;
671+
}
672+
const block = getRequireBlock(node);
673+
if (!block) {
661674
return;
662675
}
663676
const name = node.arguments[0].value;
@@ -670,22 +683,24 @@ module.exports = {
670683
type: 'require',
671684
},
672685
ranks,
673-
imported,
686+
getBlockImports(block),
674687
pathGroupsExcludedImportTypes
675688
);
676689
},
677690
'Program:exit': function reportAndReset() {
678-
if (newlinesBetweenImports !== 'ignore') {
679-
makeNewlinesBetweenReport(context, imported, newlinesBetweenImports);
680-
}
691+
importMap.forEach((imported) => {
692+
if (newlinesBetweenImports !== 'ignore') {
693+
makeNewlinesBetweenReport(context, imported, newlinesBetweenImports);
694+
}
681695

682-
if (alphabetize.order !== 'ignore') {
683-
mutateRanksToAlphabetize(imported, alphabetize);
684-
}
696+
if (alphabetize.order !== 'ignore') {
697+
mutateRanksToAlphabetize(imported, alphabetize);
698+
}
685699

686-
makeOutOfOrderReport(context, imported);
700+
makeOutOfOrderReport(context, imported);
701+
});
687702

688-
imported = [];
703+
importMap.clear();
689704
},
690705
};
691706
},

tests/src/rules/order.js

+50
Original file line numberDiff line numberDiff line change
@@ -2462,6 +2462,24 @@ context('TypeScript', function () {
24622462
},
24632463
],
24642464
}),
2465+
// Imports inside module declaration
2466+
test({
2467+
code: `
2468+
import type { CopyOptions } from 'fs';
2469+
import type { ParsedPath } from 'path';
2470+
2471+
declare module 'my-module' {
2472+
import type { CopyOptions } from 'fs';
2473+
import type { ParsedPath } from 'path';
2474+
}
2475+
`,
2476+
...parserConfig,
2477+
options: [
2478+
{
2479+
alphabetize: { order: 'asc' },
2480+
},
2481+
],
2482+
}),
24652483
],
24662484
invalid: [
24672485
// Option alphabetize: {order: 'asc'}
@@ -2655,6 +2673,38 @@ context('TypeScript', function () {
26552673
}],
26562674
options: [{ warnOnUnassignedImports: true }],
26572675
}),
2676+
// Imports inside module declaration
2677+
test({
2678+
code: `
2679+
import type { ParsedPath } from 'path';
2680+
import type { CopyOptions } from 'fs';
2681+
2682+
declare module 'my-module' {
2683+
import type { ParsedPath } from 'path';
2684+
import type { CopyOptions } from 'fs';
2685+
}
2686+
`,
2687+
output: `
2688+
import type { CopyOptions } from 'fs';
2689+
import type { ParsedPath } from 'path';
2690+
2691+
declare module 'my-module' {
2692+
import type { CopyOptions } from 'fs';
2693+
import type { ParsedPath } from 'path';
2694+
}
2695+
`,
2696+
errors: [{
2697+
message: '`fs` import should occur before import of `path`',
2698+
},{
2699+
message: '`fs` import should occur before import of `path`',
2700+
}],
2701+
...parserConfig,
2702+
options: [
2703+
{
2704+
alphabetize: { order: 'asc' },
2705+
},
2706+
],
2707+
}),
26582708
],
26592709
});
26602710
});

0 commit comments

Comments
 (0)