Skip to content

Commit 3ff4d77

Browse files
committedAug 18, 2021
[Fix] named, namespace: properly set reexports on export * as … from
Fixes #1998. Fixes #2161.
1 parent b2bf591 commit 3ff4d77

File tree

10 files changed

+75
-38
lines changed

10 files changed

+75
-38
lines changed
 

‎CHANGELOG.md

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

99
### Fixed
1010
- `ExportMap`: Add default export when esModuleInterop is true and anything is exported ([#2184], thanks [@Maxim-Mazurok])
11+
- [`named`], [`namespace`]: properly set reexports on `export * as … from` ([#1998], [#2161], thanks [@ljharb])
1112

1213
### Changed
1314
- [Docs] `max-dependencies`: 📖 Document `ignoreTypeImports` option ([#2196], thanks [@himynameisdave])
@@ -1145,10 +1146,12 @@ for info on changes for earlier releases.
11451146
[#211]: https://github.com/import-js/eslint-plugin-import/pull/211
11461147
[#164]: https://github.com/import-js/eslint-plugin-import/pull/164
11471148
[#157]: https://github.com/import-js/eslint-plugin-import/pull/157
1149+
[#2161]: https://github.com/import-js/eslint-plugin-import/issues/2161
11481150
[#2118]: https://github.com/import-js/eslint-plugin-import/issues/2118
11491151
[#2067]: https://github.com/import-js/eslint-plugin-import/issues/2067
11501152
[#2056]: https://github.com/import-js/eslint-plugin-import/issues/2056
11511153
[#2063]: https://github.com/import-js/eslint-plugin-import/issues/2063
1154+
[#1998]: https://github.com/import-js/eslint-plugin-import/issues/1998
11521155
[#1965]: https://github.com/import-js/eslint-plugin-import/issues/1965
11531156
[#1924]: https://github.com/import-js/eslint-plugin-import/issues/1924
11541157
[#1854]: https://github.com/import-js/eslint-plugin-import/issues/1854

‎src/ExportMap.js

+37-29
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,39 @@ ExportMap.parse = function (path, content, context) {
414414
return object;
415415
}
416416

417+
function processSpecifier(s, n, m) {
418+
const nsource = n.source && n.source.value;
419+
const exportMeta = {};
420+
let local;
421+
422+
switch (s.type) {
423+
case 'ExportDefaultSpecifier':
424+
if (!n.source) return;
425+
local = 'default';
426+
break;
427+
case 'ExportNamespaceSpecifier':
428+
m.namespace.set(s.exported.name, Object.defineProperty(exportMeta, 'namespace', {
429+
get() { return resolveImport(nsource); },
430+
}));
431+
return;
432+
case 'ExportAllDeclaration':
433+
local = s.exported ? s.exported.name : s.local.name;
434+
break;
435+
case 'ExportSpecifier':
436+
if (!n.source) {
437+
m.namespace.set(s.exported.name, addNamespace(exportMeta, s.local));
438+
return;
439+
}
440+
// else falls through
441+
default:
442+
local = s.local.name;
443+
break;
444+
}
445+
446+
// todo: JSDoc
447+
m.reexports.set(s.exported.name, { local, getImport: () => resolveImport(nsource) });
448+
}
449+
417450
function captureDependency({ source }, isOnlyImportingTypes, importedSpecifiers = new Set()) {
418451
if (source == null) return null;
419452

@@ -489,6 +522,9 @@ ExportMap.parse = function (path, content, context) {
489522
if (n.type === 'ExportAllDeclaration') {
490523
const getter = captureDependency(n, n.exportKind === 'type');
491524
if (getter) m.dependencies.add(getter);
525+
if (n.exported) {
526+
processSpecifier(n, n.exported, m);
527+
}
492528
return;
493529
}
494530

@@ -546,35 +582,7 @@ ExportMap.parse = function (path, content, context) {
546582
}
547583
}
548584

549-
const nsource = n.source && n.source.value;
550-
n.specifiers.forEach((s) => {
551-
const exportMeta = {};
552-
let local;
553-
554-
switch (s.type) {
555-
case 'ExportDefaultSpecifier':
556-
if (!n.source) return;
557-
local = 'default';
558-
break;
559-
case 'ExportNamespaceSpecifier':
560-
m.namespace.set(s.exported.name, Object.defineProperty(exportMeta, 'namespace', {
561-
get() { return resolveImport(nsource); },
562-
}));
563-
return;
564-
case 'ExportSpecifier':
565-
if (!n.source) {
566-
m.namespace.set(s.exported.name, addNamespace(exportMeta, s.local));
567-
return;
568-
}
569-
// else falls through
570-
default:
571-
local = s.local.name;
572-
break;
573-
}
574-
575-
// todo: JSDoc
576-
m.reexports.set(s.exported.name, { local, getImport: () => resolveImport(nsource) });
577-
});
585+
n.specifiers.forEach((s) => processSpecifier(s, n, m));
578586
}
579587

580588
const exports = ['TSExportAssignment'];

‎src/rules/namespace.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module.exports = {
6060
if (!imports.size) {
6161
context.report(
6262
specifier,
63-
`No exported names found in module '${declaration.source.value}'.`
63+
`No exported names found in module '${declaration.source.value}'.`,
6464
);
6565
}
6666
namespaces.set(specifier.local.name, imports);
@@ -69,7 +69,7 @@ module.exports = {
6969
case 'ImportSpecifier': {
7070
const meta = imports.get(
7171
// default to 'default' for default http://i.imgur.com/nj6qAWy.jpg
72-
specifier.imported ? specifier.imported.name : 'default'
72+
specifier.imported ? specifier.imported.name : 'default',
7373
);
7474
if (!meta || !meta.namespace) { break; }
7575
namespaces.set(specifier.local.name, meta.namespace);
@@ -96,7 +96,7 @@ module.exports = {
9696
if (!imports.size) {
9797
context.report(
9898
namespace,
99-
`No exported names found in module '${declaration.source.value}'.`
99+
`No exported names found in module '${declaration.source.value}'.`,
100100
);
101101
}
102102
},
@@ -111,7 +111,7 @@ module.exports = {
111111
if (dereference.parent.type === 'AssignmentExpression' && dereference.parent.left === dereference) {
112112
context.report(
113113
dereference.parent,
114-
`Assignment to member of namespace '${dereference.object.name}'.`
114+
`Assignment to member of namespace '${dereference.object.name}'.`,
115115
);
116116
}
117117

@@ -125,7 +125,7 @@ module.exports = {
125125
if (!allowComputed) {
126126
context.report(
127127
dereference.property,
128-
`Unable to validate computed reference to imported namespace '${dereference.object.name}'.`
128+
`Unable to validate computed reference to imported namespace '${dereference.object.name}'.`,
129129
);
130130
}
131131
return;
@@ -134,7 +134,7 @@ module.exports = {
134134
if (!namespace.has(dereference.property.name)) {
135135
context.report(
136136
dereference.property,
137-
makeMessage(dereference.property, namepath)
137+
makeMessage(dereference.property, namepath),
138138
);
139139
break;
140140
}

‎tests/files/export-star-2/middle.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * as myName from './upstream';

‎tests/files/export-star-2/upstream.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const a = 1;

‎tests/files/export-star/extfield.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 42;

‎tests/files/export-star/extfield2.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default NaN;

‎tests/files/export-star/models.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * as ExtfieldModel from './extfield';
2+
export * as Extfield2Model from './extfield2';

‎tests/src/rules/named.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test, SYNTAX_CASES, getTSParsers } from '../utils';
1+
import { test, SYNTAX_CASES, getTSParsers, testFilePath, testVersion } from '../utils';
22
import { RuleTester } from 'eslint';
33

44
import { CASE_SENSITIVE_FS } from 'eslint-module-utils/resolve';
@@ -182,10 +182,18 @@ ruleTester.run('named', rule, {
182182
}),
183183

184184
...SYNTAX_CASES,
185+
186+
...[].concat(testVersion('>= 6', () => ({
187+
code: `import { ExtfieldModel, Extfield2Model } from './models';`,
188+
filename: testFilePath('./export-star/downstream.js'),
189+
parserOptions: {
190+
sourceType: 'module',
191+
ecmaVersion: 2020,
192+
},
193+
})) || []),
185194
],
186195

187196
invalid: [
188-
189197
test({ code: 'import { somethingElse } from "./test-module"',
190198
errors: [ error('somethingElse', './test-module') ] }),
191199

‎tests/src/rules/namespace.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test, SYNTAX_CASES, getTSParsers } from '../utils';
1+
import { test, SYNTAX_CASES, getTSParsers, testVersion, testFilePath } from '../utils';
22
import { RuleTester } from 'eslint';
33
import flatMap from 'array.prototype.flatmap';
44

@@ -172,6 +172,18 @@ const valid = [
172172
export const getExampleColor = () => color.example
173173
`,
174174
}),
175+
176+
...[].concat(testVersion('>= 6', () => ({
177+
code: `
178+
import * as middle from './middle';
179+
180+
console.log(middle.myName);
181+
`,
182+
filename: testFilePath('export-star-2/downstream.js'),
183+
parserOptions: {
184+
ecmaVersion: 2020,
185+
},
186+
})) || []),
175187
];
176188

177189
const invalid = [

0 commit comments

Comments
 (0)
Please sign in to comment.