Skip to content

Commit 5113249

Browse files
committed
Changed parser.ts to support all forms of export default described in microsoft#3792 (comment).
Added corresponding tests. NB: export defaults are not yet transformed correctly.
1 parent ee87cf4 commit 5113249

File tree

140 files changed

+5461
-16
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+5461
-16
lines changed

src/compiler/binder.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,15 @@ namespace ts {
417417
symbol = createSymbol(SymbolFlags.None, name);
418418
}
419419
}
420+
else if (isDefaultExport && parent && symbol.declarations && symbol.declarations.length) {
421+
// && parent because we only want to check the export default symbol.
422+
// if there is already an export default declaration, make sure that their local names are the same.
423+
if (symbol.declarations[0].localSymbol !== node.localSymbol) {
424+
const message = Diagnostics.Merged_default_exports_must_have_the_same_name;
425+
file.bindDiagnostics.push(createDiagnosticForNode(getNameOfDeclaration(symbol.declarations[0]) || symbol.declarations[0], message));
426+
file.bindDiagnostics.push(createDiagnosticForNode(getNameOfDeclaration(node) || node, message));
427+
}
428+
}
420429
}
421430

422431
addDeclarationToSymbol(symbol, node, includes);
@@ -459,8 +468,8 @@ namespace ts {
459468
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefInJSDocNamespace) {
460469
const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
461470
const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
462-
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
463471
node.localSymbol = local;
472+
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
464473
return local;
465474
}
466475
else {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,6 +2304,10 @@
23042304
"category": "Error",
23052305
"code": 2723
23062306
},
2307+
"Merged default exports must have the same name.": {
2308+
"category": "Error",
2309+
"code": 2724
2310+
},
23072311
"Import declaration '{0}' is using private name '{1}'.": {
23082312
"category": "Error",
23092313
"code": 4000

src/compiler/parser.ts

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,12 +1326,12 @@ namespace ts {
13261326
if (token() === SyntaxKind.ExportKeyword) {
13271327
nextToken();
13281328
if (token() === SyntaxKind.DefaultKeyword) {
1329-
return lookAhead(nextTokenCanFollowDefaultKeyword);
1329+
return lookAhead(nextTokenCanFollowDefaultModifier);
13301330
}
13311331
return token() !== SyntaxKind.AsteriskToken && token() !== SyntaxKind.AsKeyword && token() !== SyntaxKind.OpenBraceToken && canFollowModifier();
13321332
}
13331333
if (token() === SyntaxKind.DefaultKeyword) {
1334-
return nextTokenCanFollowDefaultKeyword();
1334+
return nextTokenCanFollowDefaultModifier();
13351335
}
13361336
if (token() === SyntaxKind.StaticKeyword) {
13371337
nextToken();
@@ -1353,12 +1353,35 @@ namespace ts {
13531353
|| isLiteralPropertyName();
13541354
}
13551355

1356-
function nextTokenCanFollowDefaultKeyword(): boolean {
1356+
/**
1357+
* For export default assignments like
1358+
* "export default foo"
1359+
* "export default async"
1360+
* no modifiers should be parsed.
1361+
*/
1362+
function nextTokenCanFollowDefaultModifier(): boolean {
13571363
nextToken();
1358-
return token() === SyntaxKind.ClassKeyword || token() === SyntaxKind.FunctionKeyword ||
1359-
token() === SyntaxKind.InterfaceKeyword ||
1360-
(token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) ||
1361-
(token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine));
1364+
switch (token()) {
1365+
case SyntaxKind.ClassKeyword:
1366+
case SyntaxKind.FunctionKeyword:
1367+
case SyntaxKind.EnumKeyword:
1368+
case SyntaxKind.NamespaceKeyword:
1369+
case SyntaxKind.ModuleKeyword:
1370+
case SyntaxKind.ConstKeyword:
1371+
return true;
1372+
1373+
// The following keywords aren't reserved keywords and could be identifiers.
1374+
// We need to look at the next token to make sure these should be parsed as a modifier keyword,
1375+
// and not as an identifier. If they are followed by an identifier or a keyword on the same line,
1376+
// the current statement is not an export default assignment.
1377+
// See https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words
1378+
case SyntaxKind.InterfaceKeyword:
1379+
case SyntaxKind.AbstractKeyword:
1380+
case SyntaxKind.DeclareKeyword:
1381+
case SyntaxKind.AsyncKeyword:
1382+
case SyntaxKind.TypeKeyword:
1383+
return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);
1384+
}
13621385
}
13631386

13641387
// True if positioned at the start of a list element
@@ -4907,11 +4930,6 @@ namespace ts {
49074930
return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak();
49084931
}
49094932

4910-
function nextTokenIsClassKeywordOnSameLine() {
4911-
nextToken();
4912-
return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak();
4913-
}
4914-
49154933
function nextTokenIsFunctionKeywordOnSameLine() {
49164934
nextToken();
49174935
return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak();
@@ -5697,8 +5715,8 @@ namespace ts {
56975715

56985716
function tryParseTypeArguments(): NodeArray<TypeNode> | undefined {
56995717
return token() === SyntaxKind.LessThanToken
5700-
? parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken)
5701-
: undefined;
5718+
? parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken)
5719+
: undefined;
57025720
}
57035721

57045722
function isHeritageClause(): boolean {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/compiler/exportDefaultClodule.ts] ////
2+
3+
//// [a.ts]
4+
// https://github.com/Microsoft/TypeScript/issues/3792
5+
export default class A {
6+
A1: string
7+
}
8+
export default namespace A {
9+
export const A2 = 32;
10+
}
11+
12+
//// [b.ts]
13+
import A from "./a";
14+
15+
const a = new A();
16+
const a2 = A.A2;
17+
18+
//// [a.js]
19+
"use strict";
20+
exports.__esModule = true;
21+
// https://github.com/Microsoft/TypeScript/issues/3792
22+
var A = /** @class */ (function () {
23+
function A() {
24+
}
25+
return A;
26+
}());
27+
exports["default"] = A;
28+
(function (A) {
29+
A.A2 = 32;
30+
})(A = exports.A || (exports.A = {}));
31+
//// [b.js]
32+
"use strict";
33+
exports.__esModule = true;
34+
var a_1 = require("./a");
35+
var a = new a_1["default"]();
36+
var a2 = a_1["default"].A2;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/compiler/a.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/3792
3+
export default class A {
4+
>A : Symbol(A, Decl(a.ts, 0, 0), Decl(a.ts, 3, 1))
5+
6+
A1: string
7+
>A1 : Symbol(A.A1, Decl(a.ts, 1, 24))
8+
}
9+
export default namespace A {
10+
>A : Symbol(A, Decl(a.ts, 0, 0), Decl(a.ts, 3, 1))
11+
12+
export const A2 = 32;
13+
>A2 : Symbol(A2, Decl(a.ts, 5, 16))
14+
}
15+
16+
=== tests/cases/compiler/b.ts ===
17+
import A from "./a";
18+
>A : Symbol(A, Decl(b.ts, 0, 6))
19+
20+
const a = new A();
21+
>a : Symbol(a, Decl(b.ts, 2, 5))
22+
>A : Symbol(A, Decl(b.ts, 0, 6))
23+
24+
const a2 = A.A2;
25+
>a2 : Symbol(a2, Decl(b.ts, 3, 5))
26+
>A.A2 : Symbol(A.A2, Decl(a.ts, 5, 16))
27+
>A : Symbol(A, Decl(b.ts, 0, 6))
28+
>A2 : Symbol(A.A2, Decl(a.ts, 5, 16))
29+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/compiler/a.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/3792
3+
export default class A {
4+
>A : A
5+
6+
A1: string
7+
>A1 : string
8+
}
9+
export default namespace A {
10+
>A : typeof A
11+
12+
export const A2 = 32;
13+
>A2 : 32
14+
>32 : 32
15+
}
16+
17+
=== tests/cases/compiler/b.ts ===
18+
import A from "./a";
19+
>A : typeof A
20+
21+
const a = new A();
22+
>a : A
23+
>new A() : A
24+
>A : typeof A
25+
26+
const a2 = A.A2;
27+
>a2 : 32
28+
>A.A2 : 32
29+
>A : typeof A
30+
>A2 : 32
31+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/a.ts(2,22): error TS2724: Merged default exports must have the same name.
2+
tests/cases/compiler/a.ts(5,26): error TS2724: Merged default exports must have the same name.
3+
4+
5+
==== tests/cases/compiler/a.ts (2 errors) ====
6+
// https://github.com/Microsoft/TypeScript/issues/3792
7+
export default class A {
8+
~
9+
!!! error TS2724: Merged default exports must have the same name.
10+
A1: string = "init"
11+
}
12+
export default namespace B {
13+
~
14+
!!! error TS2724: Merged default exports must have the same name.
15+
export const A2 = 32;
16+
}
17+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [a.ts]
2+
// https://github.com/Microsoft/TypeScript/issues/3792
3+
export default class A {
4+
A1: string = "init"
5+
}
6+
export default namespace B {
7+
export const A2 = 32;
8+
}
9+
10+
11+
//// [a.js]
12+
"use strict";
13+
exports.__esModule = true;
14+
// https://github.com/Microsoft/TypeScript/issues/3792
15+
var A = /** @class */ (function () {
16+
function A() {
17+
this.A1 = "init";
18+
}
19+
return A;
20+
}());
21+
exports["default"] = A;
22+
var B;
23+
(function (B) {
24+
B.A2 = 32;
25+
})(B = exports.B || (exports.B = {}));
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/a.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/3792
3+
export default class A {
4+
>A : Symbol(A, Decl(a.ts, 0, 0), Decl(a.ts, 3, 1))
5+
6+
A1: string = "init"
7+
>A1 : Symbol(A.A1, Decl(a.ts, 1, 24))
8+
}
9+
export default namespace B {
10+
>B : Symbol(A, Decl(a.ts, 0, 0), Decl(a.ts, 3, 1))
11+
12+
export const A2 = 32;
13+
>A2 : Symbol(A2, Decl(a.ts, 5, 16))
14+
}
15+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/compiler/a.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/3792
3+
export default class A {
4+
>A : A
5+
6+
A1: string = "init"
7+
>A1 : string
8+
>"init" : "init"
9+
}
10+
export default namespace B {
11+
>B : typeof A
12+
13+
export const A2 = 32;
14+
>A2 : 32
15+
>32 : 32
16+
}
17+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [tests/cases/compiler/exportDefaultConstEnum.ts] ////
2+
3+
//// [a.ts]
4+
// https://github.com/Microsoft/TypeScript/issues/3792
5+
export
6+
default
7+
const
8+
enum
9+
A
10+
{ FOO }
11+
12+
//// [b.ts]
13+
import A from './a';
14+
15+
const x = A.FOO;
16+
17+
//// [a.js]
18+
"use strict";
19+
exports.__esModule = true;
20+
//// [b.js]
21+
"use strict";
22+
exports.__esModule = true;
23+
var x = 0 /* FOO */;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/compiler/a.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/3792
3+
export
4+
default
5+
const
6+
enum
7+
A
8+
>A : Symbol(A, Decl(a.ts, 0, 0))
9+
10+
{ FOO }
11+
>FOO : Symbol(A.FOO, Decl(a.ts, 6, 1))
12+
13+
=== tests/cases/compiler/b.ts ===
14+
import A from './a';
15+
>A : Symbol(A, Decl(b.ts, 0, 6))
16+
17+
const x = A.FOO;
18+
>x : Symbol(x, Decl(b.ts, 2, 5))
19+
>A.FOO : Symbol(A.FOO, Decl(a.ts, 6, 1))
20+
>A : Symbol(A, Decl(b.ts, 0, 6))
21+
>FOO : Symbol(A.FOO, Decl(a.ts, 6, 1))
22+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/compiler/a.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/3792
3+
export
4+
default
5+
const
6+
enum
7+
A
8+
>A : A
9+
10+
{ FOO }
11+
>FOO : A
12+
13+
=== tests/cases/compiler/b.ts ===
14+
import A from './a';
15+
>A : typeof A
16+
17+
const x = A.FOO;
18+
>x : A
19+
>A.FOO : A
20+
>A : typeof A
21+
>FOO : A
22+

0 commit comments

Comments
 (0)