Skip to content

Commit 176627c

Browse files
author
Andy
authored
Support augmenting module with export as namespace (#27281)
* Support augmenting module with `export as namespace` * Warn on use of merged symbol containing 'export as namespace'
1 parent acc34bd commit 176627c

7 files changed

+256
-8
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ namespace ts {
854854
(source.flags | target.flags) & SymbolFlags.Assignment) {
855855
Debug.assert(source !== target);
856856
if (!(target.flags & SymbolFlags.Transient)) {
857-
target = cloneSymbol(target);
857+
target = cloneSymbol(resolveSymbol(target));
858858
}
859859
// Javascript static-property-assignment declarations always merge, even though they are also values
860860
if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) {
@@ -883,7 +883,7 @@ namespace ts {
883883
else if (target.flags & SymbolFlags.NamespaceModule) {
884884
error(getNameOfDeclaration(source.declarations[0]), Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target));
885885
}
886-
else {
886+
else { // error
887887
const isEitherEnum = !!(target.flags & SymbolFlags.Enum || source.flags & SymbolFlags.Enum);
888888
const isEitherBlockScoped = !!(target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable);
889889
const message = isEitherEnum
@@ -947,7 +947,8 @@ namespace ts {
947947

948948
function mergeSymbolTable(target: SymbolTable, source: SymbolTable) {
949949
source.forEach((sourceSymbol, id) => {
950-
target.set(id, target.has(id) ? mergeSymbol(target.get(id)!, sourceSymbol) : sourceSymbol);
950+
const targetSymbol = target.get(id);
951+
target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol) : sourceSymbol);
951952
});
952953
}
953954

@@ -1549,8 +1550,7 @@ namespace ts {
15491550

15501551
// If we're in an external module, we can't reference value symbols created from UMD export declarations
15511552
if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value && !(originalLocation!.flags & NodeFlags.JSDoc)) {
1552-
const decls = result.declarations;
1553-
if (decls && decls.length === 1 && decls[0].kind === SyntaxKind.NamespaceExportDeclaration) {
1553+
if (some(result.declarations, d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports)) {
15541554
error(errorLocation!, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, unescapeLeadingUnderscores(name)); // TODO: GH#18217
15551555
}
15561556
}

tests/baselines/reference/duplicateVarsAcrossFileBoundaries.symbols

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ var z = 0;
3434

3535
=== tests/cases/compiler/duplicateVarsAcrossFileBoundaries_4.ts ===
3636
module P { }
37-
>P : Symbol(P, Decl(duplicateVarsAcrossFileBoundaries_4.ts, 0, 0))
37+
>P : Symbol(P, Decl(duplicateVarsAcrossFileBoundaries_4.ts, 0, 0), Decl(duplicateVarsAcrossFileBoundaries_5.ts, 2, 3))
3838

3939
import p = P;
40-
>p : Symbol(p, Decl(duplicateVarsAcrossFileBoundaries_4.ts, 0, 12), Decl(duplicateVarsAcrossFileBoundaries_5.ts, 2, 3))
40+
>p : Symbol(p, Decl(duplicateVarsAcrossFileBoundaries_4.ts, 0, 12))
4141
>P : Symbol(P, Decl(duplicateVarsAcrossFileBoundaries_4.ts, 0, 0))
4242

4343
var q;
@@ -52,5 +52,5 @@ import q = Q;
5252
>Q : Symbol(Q, Decl(duplicateVarsAcrossFileBoundaries_5.ts, 0, 0))
5353

5454
var p;
55-
>p : Symbol(p, Decl(duplicateVarsAcrossFileBoundaries_4.ts, 0, 12), Decl(duplicateVarsAcrossFileBoundaries_5.ts, 2, 3))
55+
>p : Symbol(P, Decl(duplicateVarsAcrossFileBoundaries_4.ts, 0, 0), Decl(duplicateVarsAcrossFileBoundaries_5.ts, 2, 3))
5656

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/a.d.ts(3,14): error TS2451: Cannot redeclare block-scoped variable 'conflict'.
2+
/b.ts(6,22): error TS2451: Cannot redeclare block-scoped variable 'conflict'.
3+
/b.ts(12,18): error TS2451: Cannot redeclare block-scoped variable 'conflict'.
4+
/b.ts(15,1): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
5+
/b.ts(15,7): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
6+
/b.ts(15,13): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
7+
/b.ts(15,19): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
8+
9+
10+
==== /a.d.ts (1 errors) ====
11+
export as namespace a;
12+
export const x = 0;
13+
export const conflict = 0;
14+
~~~~~~~~
15+
!!! error TS2451: Cannot redeclare block-scoped variable 'conflict'.
16+
!!! related TS6203 /b.ts:6:22: 'conflict' was also declared here.
17+
!!! related TS6204 /b.ts:6:22: and here.
18+
19+
==== /b.ts (6 errors) ====
20+
import * as a2 from "./a";
21+
22+
declare global {
23+
namespace a {
24+
export const y = 0;
25+
export const conflict = 0;
26+
~~~~~~~~
27+
!!! error TS2451: Cannot redeclare block-scoped variable 'conflict'.
28+
!!! related TS6203 /a.d.ts:3:14: 'conflict' was also declared here.
29+
}
30+
}
31+
32+
declare module "./a" {
33+
export const z = 0;
34+
export const conflict = 0;
35+
~~~~~~~~
36+
!!! error TS2451: Cannot redeclare block-scoped variable 'conflict'.
37+
!!! related TS6203 /a.d.ts:3:14: 'conflict' was also declared here.
38+
}
39+
40+
a.x + a.y + a.z + a.conflict;
41+
~
42+
!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
43+
~
44+
!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
45+
~
46+
!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
47+
~
48+
!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead.
49+
a2.x + a2.y + a2.z + a2.conflict;
50+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//// [tests/cases/compiler/exportAsNamespace_augment.ts] ////
2+
3+
//// [a.d.ts]
4+
export as namespace a;
5+
export const x = 0;
6+
export const conflict = 0;
7+
8+
//// [b.ts]
9+
import * as a2 from "./a";
10+
11+
declare global {
12+
namespace a {
13+
export const y = 0;
14+
export const conflict = 0;
15+
}
16+
}
17+
18+
declare module "./a" {
19+
export const z = 0;
20+
export const conflict = 0;
21+
}
22+
23+
a.x + a.y + a.z + a.conflict;
24+
a2.x + a2.y + a2.z + a2.conflict;
25+
26+
27+
//// [b.js]
28+
"use strict";
29+
exports.__esModule = true;
30+
var a2 = require("./a");
31+
a.x + a.y + a.z + a.conflict;
32+
a2.x + a2.y + a2.z + a2.conflict;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
=== /a.d.ts ===
2+
export as namespace a;
3+
>a : Symbol(a, Decl(a.d.ts, 0, 0))
4+
5+
export const x = 0;
6+
>x : Symbol(x, Decl(a.d.ts, 1, 12))
7+
8+
export const conflict = 0;
9+
>conflict : Symbol(conflict, Decl(a.d.ts, 2, 12))
10+
11+
=== /b.ts ===
12+
import * as a2 from "./a";
13+
>a2 : Symbol(a2, Decl(b.ts, 0, 6))
14+
15+
declare global {
16+
>global : Symbol(global, Decl(b.ts, 0, 26))
17+
18+
namespace a {
19+
>a : Symbol(a2, Decl(a.d.ts, 0, 0), Decl(b.ts, 2, 16), Decl(b.ts, 7, 1))
20+
21+
export const y = 0;
22+
>y : Symbol(y, Decl(b.ts, 4, 20))
23+
24+
export const conflict = 0;
25+
>conflict : Symbol(conflict, Decl(b.ts, 5, 20))
26+
}
27+
}
28+
29+
declare module "./a" {
30+
>"./a" : Symbol(a2, Decl(a.d.ts, 0, 0), Decl(b.ts, 2, 16), Decl(b.ts, 7, 1))
31+
32+
export const z = 0;
33+
>z : Symbol(z, Decl(b.ts, 10, 16))
34+
35+
export const conflict = 0;
36+
>conflict : Symbol(conflict, Decl(b.ts, 11, 16))
37+
}
38+
39+
a.x + a.y + a.z + a.conflict;
40+
>a.x : Symbol(a2.x, Decl(a.d.ts, 1, 12))
41+
>a : Symbol(a2, Decl(a.d.ts, 0, 0), Decl(b.ts, 2, 16), Decl(b.ts, 7, 1))
42+
>x : Symbol(a2.x, Decl(a.d.ts, 1, 12))
43+
>a.y : Symbol(a2.y, Decl(b.ts, 4, 20))
44+
>a : Symbol(a2, Decl(a.d.ts, 0, 0), Decl(b.ts, 2, 16), Decl(b.ts, 7, 1))
45+
>y : Symbol(a2.y, Decl(b.ts, 4, 20))
46+
>a.z : Symbol(a2.z, Decl(b.ts, 10, 16))
47+
>a : Symbol(a2, Decl(a.d.ts, 0, 0), Decl(b.ts, 2, 16), Decl(b.ts, 7, 1))
48+
>z : Symbol(a2.z, Decl(b.ts, 10, 16))
49+
>a.conflict : Symbol(a2.conflict, Decl(a.d.ts, 2, 12))
50+
>a : Symbol(a2, Decl(a.d.ts, 0, 0), Decl(b.ts, 2, 16), Decl(b.ts, 7, 1))
51+
>conflict : Symbol(a2.conflict, Decl(a.d.ts, 2, 12))
52+
53+
a2.x + a2.y + a2.z + a2.conflict;
54+
>a2.x : Symbol(a2.x, Decl(a.d.ts, 1, 12))
55+
>a2 : Symbol(a2, Decl(b.ts, 0, 6))
56+
>x : Symbol(a2.x, Decl(a.d.ts, 1, 12))
57+
>a2.y : Symbol(a2.y, Decl(b.ts, 4, 20))
58+
>a2 : Symbol(a2, Decl(b.ts, 0, 6))
59+
>y : Symbol(a2.y, Decl(b.ts, 4, 20))
60+
>a2.z : Symbol(a2.z, Decl(b.ts, 10, 16))
61+
>a2 : Symbol(a2, Decl(b.ts, 0, 6))
62+
>z : Symbol(a2.z, Decl(b.ts, 10, 16))
63+
>a2.conflict : Symbol(a2.conflict, Decl(a.d.ts, 2, 12))
64+
>a2 : Symbol(a2, Decl(b.ts, 0, 6))
65+
>conflict : Symbol(a2.conflict, Decl(a.d.ts, 2, 12))
66+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
=== /a.d.ts ===
2+
export as namespace a;
3+
>a : typeof import("/a")
4+
5+
export const x = 0;
6+
>x : 0
7+
>0 : 0
8+
9+
export const conflict = 0;
10+
>conflict : 0
11+
>0 : 0
12+
13+
=== /b.ts ===
14+
import * as a2 from "./a";
15+
>a2 : typeof a2
16+
17+
declare global {
18+
>global : typeof global
19+
20+
namespace a {
21+
>a : typeof a2
22+
23+
export const y = 0;
24+
>y : 0
25+
>0 : 0
26+
27+
export const conflict = 0;
28+
>conflict : 0
29+
>0 : 0
30+
}
31+
}
32+
33+
declare module "./a" {
34+
>"./a" : typeof a2
35+
36+
export const z = 0;
37+
>z : 0
38+
>0 : 0
39+
40+
export const conflict = 0;
41+
>conflict : 0
42+
>0 : 0
43+
}
44+
45+
a.x + a.y + a.z + a.conflict;
46+
>a.x + a.y + a.z + a.conflict : number
47+
>a.x + a.y + a.z : number
48+
>a.x + a.y : number
49+
>a.x : 0
50+
>a : typeof a2
51+
>x : 0
52+
>a.y : 0
53+
>a : typeof a2
54+
>y : 0
55+
>a.z : 0
56+
>a : typeof a2
57+
>z : 0
58+
>a.conflict : 0
59+
>a : typeof a2
60+
>conflict : 0
61+
62+
a2.x + a2.y + a2.z + a2.conflict;
63+
>a2.x + a2.y + a2.z + a2.conflict : number
64+
>a2.x + a2.y + a2.z : number
65+
>a2.x + a2.y : number
66+
>a2.x : 0
67+
>a2 : typeof a2
68+
>x : 0
69+
>a2.y : 0
70+
>a2 : typeof a2
71+
>y : 0
72+
>a2.z : 0
73+
>a2 : typeof a2
74+
>z : 0
75+
>a2.conflict : 0
76+
>a2 : typeof a2
77+
>conflict : 0
78+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @Filename: /a.d.ts
2+
export as namespace a;
3+
export const x = 0;
4+
export const conflict = 0;
5+
6+
// @Filename: /b.ts
7+
import * as a2 from "./a";
8+
9+
declare global {
10+
namespace a {
11+
export const y = 0;
12+
export const conflict = 0;
13+
}
14+
}
15+
16+
declare module "./a" {
17+
export const z = 0;
18+
export const conflict = 0;
19+
}
20+
21+
a.x + a.y + a.z + a.conflict;
22+
a2.x + a2.y + a2.z + a2.conflict;

0 commit comments

Comments
 (0)