Skip to content

Commit

Permalink
Merge pull request #7559 from Microsoft/rewrite-class-as-expr
Browse files Browse the repository at this point in the history
emit top level classes as class expressions when target=ES6 and module=System
  • Loading branch information
vladima committed Mar 17, 2016
2 parents b5f418f + 57d9a5a commit 223730d
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 15 deletions.
21 changes: 14 additions & 7 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down Expand Up @@ -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};`);
Expand All @@ -5372,7 +5377,9 @@ const _super = (function (geti, seti) {
write("export ");
}

write("let ");
if (!isHoistedDeclarationInSystemModule) {
write("let ");
}
emitDeclarationName(node);
if (decoratedClassAlias !== undefined) {
write(` = ${decoratedClassAlias}`);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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(";");
}
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/anonymousDefaultExportsSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/defaultExportsGetExportedSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ System.register([], function(exports_1, context_1) {
return {
setters:[],
execute: function() {
class Foo {
}
Foo = class Foo {
};
exports_1("default", Foo);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/outFilerootDirModuleNamesSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
42 changes: 42 additions & 0 deletions tests/baselines/reference/systemModuleTargetES6.js
Original file line number Diff line number Diff line change
@@ -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);
}
}
});
30 changes: 30 additions & 0 deletions tests/baselines/reference/systemModuleTargetES6.symbols
Original file line number Diff line number Diff line change
@@ -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))
}
33 changes: 33 additions & 0 deletions tests/baselines/reference/systemModuleTargetES6.types
Original file line number Diff line number Diff line change
@@ -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
}
15 changes: 15 additions & 0 deletions tests/cases/compiler/systemModuleTargetES6.ts
Original file line number Diff line number Diff line change
@@ -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();
}

0 comments on commit 223730d

Please sign in to comment.