emit top level classes as class expressions when target=ES6 and module=System

This commit is contained in:
Vladimir Matveev
2016-03-16 21:56:53 -07:00
parent b5f418ffcc
commit 57d9a5ada5
9 changed files with 142 additions and 15 deletions

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -15,8 +15,8 @@ System.register([], function(exports_1, context_1) {
return {
setters:[],
execute: function() {
class Foo {
}
Foo = class Foo {
};
exports_1("default", Foo);
}
}

View File

@@ -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();
}

View File

@@ -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);
}
}
});

View File

@@ -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))
}

View File

@@ -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
}

View File

@@ -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();
}