From bbf35659bd6c2cb2dc3198d61f04e9d046bf097d Mon Sep 17 00:00:00 2001 From: Erik McClenney Date: Fri, 7 Apr 2017 11:29:59 -0700 Subject: [PATCH 1/4] Allow export default interface. Related to issue 3792. --- src/compiler/parser.ts | 7 ++++--- .../baselines/reference/exportDefaultInterface.js | 15 +++++++++++++++ .../reference/exportDefaultInterface.symbols | 8 ++++++++ .../reference/exportDefaultInterface.types | 8 ++++++++ tests/cases/compiler/exportDefaultInterface.ts | 5 +++++ 5 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/exportDefaultInterface.js create mode 100644 tests/baselines/reference/exportDefaultInterface.symbols create mode 100644 tests/baselines/reference/exportDefaultInterface.types create mode 100644 tests/cases/compiler/exportDefaultInterface.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a82d5b02b4402..9fe4ea79e7080 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1237,12 +1237,12 @@ namespace ts { if (token() === SyntaxKind.ExportKeyword) { nextToken(); if (token() === SyntaxKind.DefaultKeyword) { - return lookAhead(nextTokenIsClassOrFunctionOrAsync); + return lookAhead(nextTokenCanFollowDefaultKeyword); } return token() !== SyntaxKind.AsteriskToken && token() !== SyntaxKind.AsKeyword && token() !== SyntaxKind.OpenBraceToken && canFollowModifier(); } if (token() === SyntaxKind.DefaultKeyword) { - return nextTokenIsClassOrFunctionOrAsync(); + return nextTokenCanFollowDefaultKeyword(); } if (token() === SyntaxKind.StaticKeyword) { nextToken(); @@ -1264,9 +1264,10 @@ namespace ts { || isLiteralPropertyName(); } - function nextTokenIsClassOrFunctionOrAsync(): boolean { + function nextTokenCanFollowDefaultKeyword(): boolean { nextToken(); return token() === SyntaxKind.ClassKeyword || token() === SyntaxKind.FunctionKeyword || + token() === SyntaxKind.InterfaceKeyword || (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) || (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); } diff --git a/tests/baselines/reference/exportDefaultInterface.js b/tests/baselines/reference/exportDefaultInterface.js new file mode 100644 index 0000000000000..961a6fedc1dd7 --- /dev/null +++ b/tests/baselines/reference/exportDefaultInterface.js @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/exportDefaultInterface.ts] //// + +//// [a.ts] +export default interface A {} + +//// [b.ts] +import A from './a' + + +//// [a.js] +"use strict"; +exports.__esModule = true; +//// [b.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/exportDefaultInterface.symbols b/tests/baselines/reference/exportDefaultInterface.symbols new file mode 100644 index 0000000000000..57b09ec499377 --- /dev/null +++ b/tests/baselines/reference/exportDefaultInterface.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/a.ts === +export default interface A {} +>A : Symbol(A, Decl(a.ts, 0, 0)) + +=== tests/cases/compiler/b.ts === +import A from './a' +>A : Symbol(A, Decl(b.ts, 0, 6)) + diff --git a/tests/baselines/reference/exportDefaultInterface.types b/tests/baselines/reference/exportDefaultInterface.types new file mode 100644 index 0000000000000..2c507ce5df654 --- /dev/null +++ b/tests/baselines/reference/exportDefaultInterface.types @@ -0,0 +1,8 @@ +=== tests/cases/compiler/a.ts === +export default interface A {} +>A : A + +=== tests/cases/compiler/b.ts === +import A from './a' +>A : any + diff --git a/tests/cases/compiler/exportDefaultInterface.ts b/tests/cases/compiler/exportDefaultInterface.ts new file mode 100644 index 0000000000000..e9dda3df53969 --- /dev/null +++ b/tests/cases/compiler/exportDefaultInterface.ts @@ -0,0 +1,5 @@ +// @filename: a.ts +export default interface A {} + +// @filename: b.ts +import A from './a' From 90a3bfdb50357aaccc6c841c865360f07d7bdb81 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 23 May 2017 12:56:34 -0700 Subject: [PATCH 2/4] Update exportDefaultAbstractClass test --- .../reference/exportDefaultAbstractClass.js | 48 +++++++++++++++++-- .../exportDefaultAbstractClass.symbols | 27 ++++++++++- .../exportDefaultAbstractClass.types | 31 +++++++++++- .../compiler/exportDefaultAbstractClass.ts | 16 +++++-- 4 files changed, 110 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/exportDefaultAbstractClass.js b/tests/baselines/reference/exportDefaultAbstractClass.js index c8dba03543dc1..38976311d63be 100644 --- a/tests/baselines/reference/exportDefaultAbstractClass.js +++ b/tests/baselines/reference/exportDefaultAbstractClass.js @@ -1,14 +1,29 @@ //// [tests/cases/compiler/exportDefaultAbstractClass.ts] //// //// [a.ts] -export default abstract class A {} +export default abstract class A { a: number; } + +class B extends A {} +new B().a.toExponential(); //// [b.ts] -import A from './a' - +import A from './a'; + +class C extends A {} +new C().a.toExponential(); //// [a.js] "use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); exports.__esModule = true; var A = (function () { function A() { @@ -16,6 +31,33 @@ var A = (function () { return A; }()); exports["default"] = A; +var B = (function (_super) { + __extends(B, _super); + function B() { + return _super !== null && _super.apply(this, arguments) || this; + } + return B; +}(A)); +new B().a.toExponential(); //// [b.js] "use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); exports.__esModule = true; +var a_1 = require("./a"); +var C = (function (_super) { + __extends(C, _super); + function C() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C; +}(a_1["default"])); +new C().a.toExponential(); diff --git a/tests/baselines/reference/exportDefaultAbstractClass.symbols b/tests/baselines/reference/exportDefaultAbstractClass.symbols index 75c6c068f08e1..27e42487f31dc 100644 --- a/tests/baselines/reference/exportDefaultAbstractClass.symbols +++ b/tests/baselines/reference/exportDefaultAbstractClass.symbols @@ -1,8 +1,31 @@ === tests/cases/compiler/a.ts === -export default abstract class A {} +export default abstract class A { a: number; } >A : Symbol(A, Decl(a.ts, 0, 0)) +>a : Symbol(A.a, Decl(a.ts, 0, 33)) + +class B extends A {} +>B : Symbol(B, Decl(a.ts, 0, 46)) +>A : Symbol(A, Decl(a.ts, 0, 0)) + +new B().a.toExponential(); +>new B().a.toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>new B().a : Symbol(A.a, Decl(a.ts, 0, 33)) +>B : Symbol(B, Decl(a.ts, 0, 46)) +>a : Symbol(A.a, Decl(a.ts, 0, 33)) +>toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) === tests/cases/compiler/b.ts === -import A from './a' +import A from './a'; >A : Symbol(A, Decl(b.ts, 0, 6)) +class C extends A {} +>C : Symbol(C, Decl(b.ts, 0, 20)) +>A : Symbol(A, Decl(b.ts, 0, 6)) + +new C().a.toExponential(); +>new C().a.toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>new C().a : Symbol(A.a, Decl(a.ts, 0, 33)) +>C : Symbol(C, Decl(b.ts, 0, 20)) +>a : Symbol(A.a, Decl(a.ts, 0, 33)) +>toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/exportDefaultAbstractClass.types b/tests/baselines/reference/exportDefaultAbstractClass.types index d400be1af43f3..776ad01420ada 100644 --- a/tests/baselines/reference/exportDefaultAbstractClass.types +++ b/tests/baselines/reference/exportDefaultAbstractClass.types @@ -1,8 +1,35 @@ === tests/cases/compiler/a.ts === -export default abstract class A {} +export default abstract class A { a: number; } >A : A +>a : number + +class B extends A {} +>B : B +>A : A + +new B().a.toExponential(); +>new B().a.toExponential() : string +>new B().a.toExponential : (fractionDigits?: number) => string +>new B().a : number +>new B() : B +>B : typeof B +>a : number +>toExponential : (fractionDigits?: number) => string === tests/cases/compiler/b.ts === -import A from './a' +import A from './a'; >A : typeof A +class C extends A {} +>C : C +>A : A + +new C().a.toExponential(); +>new C().a.toExponential() : string +>new C().a.toExponential : (fractionDigits?: number) => string +>new C().a : number +>new C() : C +>C : typeof C +>a : number +>toExponential : (fractionDigits?: number) => string + diff --git a/tests/cases/compiler/exportDefaultAbstractClass.ts b/tests/cases/compiler/exportDefaultAbstractClass.ts index 584e95b6b03b8..31877911622a5 100644 --- a/tests/cases/compiler/exportDefaultAbstractClass.ts +++ b/tests/cases/compiler/exportDefaultAbstractClass.ts @@ -1,5 +1,11 @@ -// @filename: a.ts -export default abstract class A {} - -// @filename: b.ts -import A from './a' +// @Filename: a.ts +export default abstract class A { a: number; } + +class B extends A {} +new B().a.toExponential(); + +// @Filename: b.ts +import A from './a'; + +class C extends A {} +new C().a.toExponential(); \ No newline at end of file From 2bd4e411dfdbb3d9d8ef7f7b6ff90fda7db639bd Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 23 May 2017 12:57:00 -0700 Subject: [PATCH 3/4] Allow default export to be a non-value for lookup purposes --- src/compiler/utilities.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 3a8b8b59f7d1d..22210419af772 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3168,11 +3168,11 @@ namespace ts { } export function getLocalSymbolForExportDefault(symbol: Symbol) { - return isExportDefaultSymbol(symbol) ? symbol.valueDeclaration.localSymbol : undefined; + return isExportDefaultSymbol(symbol) ? symbol.declarations[0].localSymbol : undefined; } function isExportDefaultSymbol(symbol: Symbol): boolean { - return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default); + return symbol && length(symbol.declarations) > 0 && hasModifier(symbol.declarations[0], ModifierFlags.Default); } /** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */ From 9139af204611c4bd1141a5857cf503ebf1826299 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 23 May 2017 13:05:20 -0700 Subject: [PATCH 4/4] Add local usage to exportDefaultInterface test --- .../reference/exportDefaultInterface.js | 15 ++++++++-- .../reference/exportDefaultInterface.symbols | 27 +++++++++++++++-- .../reference/exportDefaultInterface.types | 29 +++++++++++++++++-- .../cases/compiler/exportDefaultInterface.ts | 16 ++++++---- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/exportDefaultInterface.js b/tests/baselines/reference/exportDefaultInterface.js index 961a6fedc1dd7..e7b5c945e327e 100644 --- a/tests/baselines/reference/exportDefaultInterface.js +++ b/tests/baselines/reference/exportDefaultInterface.js @@ -1,15 +1,24 @@ //// [tests/cases/compiler/exportDefaultInterface.ts] //// //// [a.ts] -export default interface A {} +export default interface A { value: number; } + +var a: A; +a.value.toExponential(); //// [b.ts] -import A from './a' - +import A from './a'; + +var a: A; +a.value.toExponential(); //// [a.js] "use strict"; exports.__esModule = true; +var a; +a.value.toExponential(); //// [b.js] "use strict"; exports.__esModule = true; +var a; +a.value.toExponential(); diff --git a/tests/baselines/reference/exportDefaultInterface.symbols b/tests/baselines/reference/exportDefaultInterface.symbols index 57b09ec499377..1a3b172fe976e 100644 --- a/tests/baselines/reference/exportDefaultInterface.symbols +++ b/tests/baselines/reference/exportDefaultInterface.symbols @@ -1,8 +1,31 @@ === tests/cases/compiler/a.ts === -export default interface A {} +export default interface A { value: number; } >A : Symbol(A, Decl(a.ts, 0, 0)) +>value : Symbol(A.value, Decl(a.ts, 0, 28)) + +var a: A; +>a : Symbol(a, Decl(a.ts, 2, 3)) +>A : Symbol(A, Decl(a.ts, 0, 0)) + +a.value.toExponential(); +>a.value.toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>a.value : Symbol(A.value, Decl(a.ts, 0, 28)) +>a : Symbol(a, Decl(a.ts, 2, 3)) +>value : Symbol(A.value, Decl(a.ts, 0, 28)) +>toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) === tests/cases/compiler/b.ts === -import A from './a' +import A from './a'; >A : Symbol(A, Decl(b.ts, 0, 6)) +var a: A; +>a : Symbol(a, Decl(b.ts, 2, 3)) +>A : Symbol(A, Decl(b.ts, 0, 6)) + +a.value.toExponential(); +>a.value.toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>a.value : Symbol(A.value, Decl(a.ts, 0, 28)) +>a : Symbol(a, Decl(b.ts, 2, 3)) +>value : Symbol(A.value, Decl(a.ts, 0, 28)) +>toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/exportDefaultInterface.types b/tests/baselines/reference/exportDefaultInterface.types index 2c507ce5df654..636197339f40e 100644 --- a/tests/baselines/reference/exportDefaultInterface.types +++ b/tests/baselines/reference/exportDefaultInterface.types @@ -1,8 +1,33 @@ === tests/cases/compiler/a.ts === -export default interface A {} +export default interface A { value: number; } >A : A +>value : number + +var a: A; +>a : A +>A : A + +a.value.toExponential(); +>a.value.toExponential() : string +>a.value.toExponential : (fractionDigits?: number) => string +>a.value : number +>a : A +>value : number +>toExponential : (fractionDigits?: number) => string === tests/cases/compiler/b.ts === -import A from './a' +import A from './a'; >A : any +var a: A; +>a : A +>A : A + +a.value.toExponential(); +>a.value.toExponential() : string +>a.value.toExponential : (fractionDigits?: number) => string +>a.value : number +>a : A +>value : number +>toExponential : (fractionDigits?: number) => string + diff --git a/tests/cases/compiler/exportDefaultInterface.ts b/tests/cases/compiler/exportDefaultInterface.ts index e9dda3df53969..c7bbbe8019e35 100644 --- a/tests/cases/compiler/exportDefaultInterface.ts +++ b/tests/cases/compiler/exportDefaultInterface.ts @@ -1,5 +1,11 @@ -// @filename: a.ts -export default interface A {} - -// @filename: b.ts -import A from './a' +// @Filename: a.ts +export default interface A { value: number; } + +var a: A; +a.value.toExponential(); + +// @Filename: b.ts +import A from './a'; + +var a: A; +a.value.toExponential(); \ No newline at end of file