Skip to content

Commit c14c9bd

Browse files
benmunroljharb
authored andcommitted
[Fix] named/ExportMap: Fix ExportMap for a merged typescript namespace
A typescript namespace may be declared multiple times, it is then merged together and considered to be a single declaration from consuming code. In the case where a merged namespace is assigned as the export from a module then the declarations from all the instances of the namespace in the AST need to be considered as exported.
1 parent d030d8e commit c14c9bd

File tree

4 files changed

+68
-22
lines changed

4 files changed

+68
-22
lines changed

CHANGELOG.md

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

1616
### Fixed
1717
- `default`: make error message less confusing ([#1470], thanks [@golopot])
18+
- Support export of a merged typescript namespace declaration ([#1495], thanks [@benmunro])
1819

1920
## [2.18.2] - 2019-07-19
2021
- Skip warning on type interfaces ([#1425], thanks [@lencioni])
@@ -609,6 +610,7 @@ for info on changes for earlier releases.
609610

610611
[`memo-parser`]: ./memo-parser/README.md
611612

613+
[#1495]: https://github.com/benmosher/eslint-plugin-import/pull/1495
612614
[#1472]: https://github.com/benmosher/eslint-plugin-import/pull/1472
613615
[#1470]: https://github.com/benmosher/eslint-plugin-import/pull/1470
614616
[#1436]: https://github.com/benmosher/eslint-plugin-import/pull/1436
@@ -992,3 +994,4 @@ for info on changes for earlier releases.
992994
[@atikenny]: https://github.com/atikenny
993995
[@schmidsi]: https://github.com/schmidsi
994996
[@TrevorBurnham]: https://github.com/TrevorBurnham
997+
[@benmunro]: https://github.com/benmunro

src/ExportMap.js

+23-21
Original file line numberDiff line numberDiff line change
@@ -514,30 +514,32 @@ ExportMap.parse = function (path, content, context) {
514514

515515
// This doesn't declare anything, but changes what's being exported.
516516
if (n.type === 'TSExportAssignment') {
517-
const moduleDecl = ast.body.find((bodyNode) =>
517+
const moduleDecls = ast.body.filter((bodyNode) =>
518518
bodyNode.type === 'TSModuleDeclaration' && bodyNode.id.name === n.expression.name
519519
)
520-
if (moduleDecl && moduleDecl.body && moduleDecl.body.body) {
521-
moduleDecl.body.body.forEach((moduleBlockNode) => {
522-
// Export-assignment exports all members in the namespace, explicitly exported or not.
523-
const exportedDecl = moduleBlockNode.type === 'ExportNamedDeclaration' ?
524-
moduleBlockNode.declaration :
525-
moduleBlockNode
526-
527-
if (exportedDecl.type === 'VariableDeclaration') {
528-
exportedDecl.declarations.forEach((decl) =>
529-
recursivePatternCapture(decl.id,(id) => m.namespace.set(
530-
id.name,
531-
captureDoc(source, docStyleParsers, decl, exportedDecl, moduleBlockNode))
520+
moduleDecls.forEach((moduleDecl) => {
521+
if (moduleDecl && moduleDecl.body && moduleDecl.body.body) {
522+
moduleDecl.body.body.forEach((moduleBlockNode) => {
523+
// Export-assignment exports all members in the namespace, explicitly exported or not.
524+
const exportedDecl = moduleBlockNode.type === 'ExportNamedDeclaration' ?
525+
moduleBlockNode.declaration :
526+
moduleBlockNode
527+
528+
if (exportedDecl.type === 'VariableDeclaration') {
529+
exportedDecl.declarations.forEach((decl) =>
530+
recursivePatternCapture(decl.id,(id) => m.namespace.set(
531+
id.name,
532+
captureDoc(source, docStyleParsers, decl, exportedDecl, moduleBlockNode))
533+
)
532534
)
533-
)
534-
} else {
535-
m.namespace.set(
536-
exportedDecl.id.name,
537-
captureDoc(source, docStyleParsers, moduleBlockNode))
538-
}
539-
})
540-
}
535+
} else {
536+
m.namespace.set(
537+
exportedDecl.id.name,
538+
captureDoc(source, docStyleParsers, moduleBlockNode))
539+
}
540+
})
541+
}
542+
})
541543
}
542544
})
543545

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
export = AssignedNamespace;
2+
3+
declare namespace AssignedNamespace {
4+
type MyType = string
5+
enum MyEnum {
6+
Foo,
7+
Bar,
8+
Baz
9+
}
10+
}
11+
12+
declare namespace AssignedNamespace {
13+
interface Foo {
14+
native: string | number
15+
typedef: MyType
16+
enum: MyEnum
17+
}
18+
19+
abstract class Bar {
20+
abstract foo(): Foo
21+
22+
method();
23+
}
24+
25+
export function getFoo() : MyType;
26+
27+
export module MyModule {
28+
export function ModuleFunction();
29+
}
30+
31+
export namespace MyNamespace {
32+
export function NamespaceFunction();
33+
34+
export module NSModule {
35+
export function NSModuleFunction();
36+
}
37+
}
38+
39+
// Export-assignment exports all members in the namespace, explicitly exported or not.
40+
// interface NotExported {}
41+
}

tests/src/rules/named.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ ruleTester.run('named (export *)', rule, {
284284

285285
context('Typescript', function () {
286286
getTSParsers().forEach((parser) => {
287-
['typescript', 'typescript-declare', 'typescript-export-assign'].forEach((source) => {
287+
['typescript', 'typescript-declare', 'typescript-export-assign', 'typescript-export-assign-merged'].forEach((source) => {
288288
ruleTester.run(`named`, rule, {
289289
valid: [
290290
test({

0 commit comments

Comments
 (0)