From 57d9a5ada54c3eba95c739b9c2c4de0e82973e0a Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 16 Mar 2016 21:56:53 -0700 Subject: [PATCH] emit top level classes as class expressions when target=ES6 and module=System --- src/compiler/emitter.ts | 21 ++++++---- .../anonymousDefaultExportsSystem.js | 4 +- ...ecoratedDefaultExportsGetExportedSystem.js | 4 +- .../defaultExportsGetExportedSystem.js | 4 +- .../outFilerootDirModuleNamesSystem.js | 4 +- .../reference/systemModuleTargetES6.js | 42 +++++++++++++++++++ .../reference/systemModuleTargetES6.symbols | 30 +++++++++++++ .../reference/systemModuleTargetES6.types | 33 +++++++++++++++ tests/cases/compiler/systemModuleTargetES6.ts | 15 +++++++ 9 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 tests/baselines/reference/systemModuleTargetES6.js create mode 100644 tests/baselines/reference/systemModuleTargetES6.symbols create mode 100644 tests/baselines/reference/systemModuleTargetES6.types create mode 100644 tests/cases/compiler/systemModuleTargetES6.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index e5498d24576..7e3ee93f2f6 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5278,9 +5278,11 @@ const _super = (function (geti, seti) { function emitClassLikeDeclarationForES6AndHigher(node: ClassLikeDeclaration) { let decoratedClassAlias: string; - const thisNodeIsDecorated = nodeIsDecorated(node); + const isHoistedDeclarationInSystemModule = shouldHoistDeclarationInSystemJsModule(node); + const isDecorated = nodeIsDecorated(node); + const rewriteAsClassExpression = isDecorated || isHoistedDeclarationInSystemModule; if (node.kind === SyntaxKind.ClassDeclaration) { - if (thisNodeIsDecorated) { + if (rewriteAsClassExpression) { // When we emit an ES6 class that has a class decorator, we must tailor the // emit to certain specific cases. // @@ -5361,7 +5363,10 @@ const _super = (function (geti, seti) { // [Example 4] // - if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithBodyScopedClassBinding) { + // NOTE: we reuse the same rewriting logic for cases when targeting ES6 and module kind is System. + // Because of hoisting top level class declaration need to be emitted as class expressions. + // Double bind case is only required if node is decorated. + if (isDecorated && resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithBodyScopedClassBinding) { decoratedClassAlias = unescapeIdentifier(makeUniqueName(node.name ? node.name.text : "default")); decoratedClassAliases[getNodeId(node)] = decoratedClassAlias; write(`let ${decoratedClassAlias};`); @@ -5372,7 +5377,9 @@ const _super = (function (geti, seti) { write("export "); } - write("let "); + if (!isHoistedDeclarationInSystemModule) { + write("let "); + } emitDeclarationName(node); if (decoratedClassAlias !== undefined) { write(` = ${decoratedClassAlias}`); @@ -5416,7 +5423,7 @@ const _super = (function (geti, seti) { // emit name if // - node has a name // - this is default export with static initializers - if (node.name || (node.flags & NodeFlags.Default && (staticProperties.length > 0 || modulekind !== ModuleKind.ES6) && !thisNodeIsDecorated)) { + if (node.name || (node.flags & NodeFlags.Default && (staticProperties.length > 0 || modulekind !== ModuleKind.ES6) && !rewriteAsClassExpression)) { write(" "); emitDeclarationName(node); } @@ -5436,7 +5443,7 @@ const _super = (function (geti, seti) { writeLine(); emitToken(SyntaxKind.CloseBraceToken, node.members.end); - if (thisNodeIsDecorated) { + if (rewriteAsClassExpression) { decoratedClassAliases[getNodeId(node)] = undefined; write(";"); } @@ -5476,7 +5483,7 @@ const _super = (function (geti, seti) { // module), export it if (node.flags & NodeFlags.Default) { // if this is a top level default export of decorated class, write the export after the declaration. - if (thisNodeIsDecorated) { + if (isDecorated) { writeLine(); write("export default "); emitDeclarationName(node); diff --git a/tests/baselines/reference/anonymousDefaultExportsSystem.js b/tests/baselines/reference/anonymousDefaultExportsSystem.js index f9ff71dec06..f68806eb1af 100644 --- a/tests/baselines/reference/anonymousDefaultExportsSystem.js +++ b/tests/baselines/reference/anonymousDefaultExportsSystem.js @@ -14,8 +14,8 @@ System.register([], function(exports_1, context_1) { return { setters:[], execute: function() { - class default_1 { - } + default_1 = class { + }; exports_1("default", default_1); } } diff --git a/tests/baselines/reference/decoratedDefaultExportsGetExportedSystem.js b/tests/baselines/reference/decoratedDefaultExportsGetExportedSystem.js index e2d9d0f0a6d..d5cd115edc0 100644 --- a/tests/baselines/reference/decoratedDefaultExportsGetExportedSystem.js +++ b/tests/baselines/reference/decoratedDefaultExportsGetExportedSystem.js @@ -26,7 +26,7 @@ System.register([], function(exports_1, context_1) { return { setters:[], execute: function() { - let Foo = class Foo { + Foo = class Foo { }; Foo = __decorate([ decorator @@ -49,7 +49,7 @@ System.register([], function(exports_1, context_1) { return { setters:[], execute: function() { - let default_1 = class { + default_1 = class { }; default_1 = __decorate([ decorator diff --git a/tests/baselines/reference/defaultExportsGetExportedSystem.js b/tests/baselines/reference/defaultExportsGetExportedSystem.js index eac3d3c7c43..eaf6d323f09 100644 --- a/tests/baselines/reference/defaultExportsGetExportedSystem.js +++ b/tests/baselines/reference/defaultExportsGetExportedSystem.js @@ -15,8 +15,8 @@ System.register([], function(exports_1, context_1) { return { setters:[], execute: function() { - class Foo { - } + Foo = class Foo { + }; exports_1("default", Foo); } } diff --git a/tests/baselines/reference/outFilerootDirModuleNamesSystem.js b/tests/baselines/reference/outFilerootDirModuleNamesSystem.js index eb1ef2a4a54..18ec6ecc19b 100644 --- a/tests/baselines/reference/outFilerootDirModuleNamesSystem.js +++ b/tests/baselines/reference/outFilerootDirModuleNamesSystem.js @@ -37,8 +37,8 @@ System.register("a", ["b"], function(exports_2, context_2) { b_1 = b_1_1; }], execute: function() { - class Foo { - } + Foo = class Foo { + }; exports_2("default", Foo); b_1.default(); } diff --git a/tests/baselines/reference/systemModuleTargetES6.js b/tests/baselines/reference/systemModuleTargetES6.js new file mode 100644 index 00000000000..21bbc6a6ad8 --- /dev/null +++ b/tests/baselines/reference/systemModuleTargetES6.js @@ -0,0 +1,42 @@ +//// [systemModuleTargetES6.ts] +export class MyClass { } +export class MyClass2 { + static value = 42; + static getInstance() { return MyClass2.value; } +} + +export function myFunction() { + return new MyClass(); +} + +export function myFunction2() { + return new MyClass2(); +} + +//// [systemModuleTargetES6.js] +System.register([], function(exports_1, context_1) { + "use strict"; + var __moduleName = context_1 && context_1.id; + var MyClass, MyClass2; + function myFunction() { + return new MyClass(); + } + exports_1("myFunction", myFunction); + function myFunction2() { + return new MyClass2(); + } + exports_1("myFunction2", myFunction2); + return { + setters:[], + execute: function() { + MyClass = class MyClass { + }; + exports_1("MyClass", MyClass); + MyClass2 = class MyClass2 { + static getInstance() { return MyClass2.value; } + }; + MyClass2.value = 42; + exports_1("MyClass2", MyClass2); + } + } +}); diff --git a/tests/baselines/reference/systemModuleTargetES6.symbols b/tests/baselines/reference/systemModuleTargetES6.symbols new file mode 100644 index 00000000000..afb217c0c0a --- /dev/null +++ b/tests/baselines/reference/systemModuleTargetES6.symbols @@ -0,0 +1,30 @@ +=== tests/cases/compiler/systemModuleTargetES6.ts === +export class MyClass { } +>MyClass : Symbol(MyClass, Decl(systemModuleTargetES6.ts, 0, 0)) + +export class MyClass2 { +>MyClass2 : Symbol(MyClass2, Decl(systemModuleTargetES6.ts, 0, 24)) + + static value = 42; +>value : Symbol(MyClass2.value, Decl(systemModuleTargetES6.ts, 1, 23)) + + static getInstance() { return MyClass2.value; } +>getInstance : Symbol(MyClass2.getInstance, Decl(systemModuleTargetES6.ts, 2, 22)) +>MyClass2.value : Symbol(MyClass2.value, Decl(systemModuleTargetES6.ts, 1, 23)) +>MyClass2 : Symbol(MyClass2, Decl(systemModuleTargetES6.ts, 0, 24)) +>value : Symbol(MyClass2.value, Decl(systemModuleTargetES6.ts, 1, 23)) +} + +export function myFunction() { +>myFunction : Symbol(myFunction, Decl(systemModuleTargetES6.ts, 4, 1)) + + return new MyClass(); +>MyClass : Symbol(MyClass, Decl(systemModuleTargetES6.ts, 0, 0)) +} + +export function myFunction2() { +>myFunction2 : Symbol(myFunction2, Decl(systemModuleTargetES6.ts, 8, 1)) + + return new MyClass2(); +>MyClass2 : Symbol(MyClass2, Decl(systemModuleTargetES6.ts, 0, 24)) +} diff --git a/tests/baselines/reference/systemModuleTargetES6.types b/tests/baselines/reference/systemModuleTargetES6.types new file mode 100644 index 00000000000..5a9801a5d89 --- /dev/null +++ b/tests/baselines/reference/systemModuleTargetES6.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/systemModuleTargetES6.ts === +export class MyClass { } +>MyClass : MyClass + +export class MyClass2 { +>MyClass2 : MyClass2 + + static value = 42; +>value : number +>42 : number + + static getInstance() { return MyClass2.value; } +>getInstance : () => number +>MyClass2.value : number +>MyClass2 : typeof MyClass2 +>value : number +} + +export function myFunction() { +>myFunction : () => MyClass + + return new MyClass(); +>new MyClass() : MyClass +>MyClass : typeof MyClass +} + +export function myFunction2() { +>myFunction2 : () => MyClass2 + + return new MyClass2(); +>new MyClass2() : MyClass2 +>MyClass2 : typeof MyClass2 +} diff --git a/tests/cases/compiler/systemModuleTargetES6.ts b/tests/cases/compiler/systemModuleTargetES6.ts new file mode 100644 index 00000000000..a41b0a62c86 --- /dev/null +++ b/tests/cases/compiler/systemModuleTargetES6.ts @@ -0,0 +1,15 @@ +// @target: ES6 +// @module: System +export class MyClass { } +export class MyClass2 { + static value = 42; + static getInstance() { return MyClass2.value; } +} + +export function myFunction() { + return new MyClass(); +} + +export function myFunction2() { + return new MyClass2(); +} \ No newline at end of file