diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6d5146a6801..44feeed0fa9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2639,7 +2639,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { writeLine(); emitStart(node); - if (compilerOptions.module === ModuleKind.System) { + // emit call to exported only for top level nodes + if (compilerOptions.module === ModuleKind.System && node.parent === currentSourceFile) { // emit export default as // export("default", ) write(`${exportFunctionForFile}("`); @@ -4403,7 +4404,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { emitModuleMemberName(node); write(" = {}));"); emitEnd(node); - if (!isES6ExportedDeclaration(node) && node.flags & NodeFlags.Export) { + if (!isES6ExportedDeclaration(node) && node.flags & NodeFlags.Export && !shouldHoistDeclarationInSystemJsModule(node)) { + // do not emit var if variable was already hoisted writeLine(); emitStart(node); write("var "); @@ -4414,6 +4416,15 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { write(";"); } if (languageVersion < ScriptTarget.ES6 && node.parent === currentSourceFile) { + if (compilerOptions.module === ModuleKind.System && (node.flags & NodeFlags.Export)) { + // write the call to exported for enum + writeLine(); + write(`${exportFunctionForFile}("`); + emitDeclarationName(node); + write(`", `); + emitDeclarationName(node); + write(")"); + } emitExportMemberAssignments(node.name); } } @@ -5094,7 +5105,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { // in theory we should hoist only exported functions and its dependencies // in practice to simplify things we'll hoist all source level functions and variable declaration // including variables declarations for module and class declarations - let hoistedVars: (Identifier | ClassDeclaration | ModuleDeclaration)[]; + let hoistedVars: (Identifier | ClassDeclaration | ModuleDeclaration | EnumDeclaration)[]; let hoistedFunctionDeclarations: FunctionDeclaration[]; let exportedDeclarations: (Identifier | Declaration)[]; @@ -5103,13 +5114,30 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { if (hoistedVars) { writeLine(); write("var "); + let seen: Map = {}; for (let i = 0; i < hoistedVars.length; ++i) { let local = hoistedVars[i]; + let name = local.kind === SyntaxKind.Identifier + ? local + : (local).name; + + if (name) { + // do not emit duplicate entries (in case of declaration merging) in the list of hoisted variables + let text = unescapeIdentifier(name.text); + if (hasProperty(seen, text)) { + continue; + } + else { + seen[text] = text; + } + } + if (i !== 0) { write(", "); } - if (local.kind === SyntaxKind.ClassDeclaration || local.kind === SyntaxKind.ModuleDeclaration) { - emitDeclarationName(local); + + if (local.kind === SyntaxKind.ClassDeclaration || local.kind === SyntaxKind.ModuleDeclaration || local.kind === SyntaxKind.EnumDeclaration) { + emitDeclarationName(local); } else { emit(local); @@ -5153,7 +5181,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { } if (node.kind === SyntaxKind.ClassDeclaration) { - // TODO: rename block scoped classes if (!hoistedVars) { hoistedVars = []; } @@ -5162,12 +5189,26 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { return; } - if (node.kind === SyntaxKind.ModuleDeclaration && shouldEmitModuleDeclaration(node)) { - if (!hoistedVars) { - hoistedVars = []; + if (node.kind === SyntaxKind.EnumDeclaration) { + if (shouldEmitEnumDeclaration(node)) { + if (!hoistedVars) { + hoistedVars = []; + } + + hoistedVars.push(node); } - hoistedVars.push(node); + return; + } + + if (node.kind === SyntaxKind.ModuleDeclaration) { + if (shouldEmitModuleDeclaration(node)) { + if (!hoistedVars) { + hoistedVars = []; + } + + hoistedVars.push(node); + } return; } diff --git a/tests/baselines/reference/systemModuleDeclarationMerging.js b/tests/baselines/reference/systemModuleDeclarationMerging.js new file mode 100644 index 00000000000..b745ed04891 --- /dev/null +++ b/tests/baselines/reference/systemModuleDeclarationMerging.js @@ -0,0 +1,43 @@ +//// [systemModuleDeclarationMerging.ts] + +export function F() {} +export module F { var x; } + +export class C {} +export module C { var x; } + +export enum E {} +export module E { var x; } + +//// [systemModuleDeclarationMerging.js] +System.register([], function(exports_1) { + var F, C, E; + function F() { } + exports_1("F", F); + return { + setters:[], + execute: function() { + (function (F) { + var x; + })(F = F || (F = {})); + exports_1("F", F) + C = (function () { + function C() { + } + return C; + })(); + exports_1("C", C); + (function (C) { + var x; + })(C = C || (C = {})); + exports_1("C", C) + (function (E) { + })(E || (E = {})); + exports_1("E", E) + (function (E) { + var x; + })(E = E || (E = {})); + exports_1("E", E) + } + } +}); diff --git a/tests/baselines/reference/systemModuleDeclarationMerging.symbols b/tests/baselines/reference/systemModuleDeclarationMerging.symbols new file mode 100644 index 00000000000..8efce4022ba --- /dev/null +++ b/tests/baselines/reference/systemModuleDeclarationMerging.symbols @@ -0,0 +1,23 @@ +=== tests/cases/compiler/systemModuleDeclarationMerging.ts === + +export function F() {} +>F : Symbol(F, Decl(systemModuleDeclarationMerging.ts, 0, 0), Decl(systemModuleDeclarationMerging.ts, 1, 22)) + +export module F { var x; } +>F : Symbol(F, Decl(systemModuleDeclarationMerging.ts, 0, 0), Decl(systemModuleDeclarationMerging.ts, 1, 22)) +>x : Symbol(x, Decl(systemModuleDeclarationMerging.ts, 2, 21)) + +export class C {} +>C : Symbol(C, Decl(systemModuleDeclarationMerging.ts, 2, 26), Decl(systemModuleDeclarationMerging.ts, 4, 17)) + +export module C { var x; } +>C : Symbol(C, Decl(systemModuleDeclarationMerging.ts, 2, 26), Decl(systemModuleDeclarationMerging.ts, 4, 17)) +>x : Symbol(x, Decl(systemModuleDeclarationMerging.ts, 5, 21)) + +export enum E {} +>E : Symbol(E, Decl(systemModuleDeclarationMerging.ts, 5, 26), Decl(systemModuleDeclarationMerging.ts, 7, 16)) + +export module E { var x; } +>E : Symbol(E, Decl(systemModuleDeclarationMerging.ts, 5, 26), Decl(systemModuleDeclarationMerging.ts, 7, 16)) +>x : Symbol(x, Decl(systemModuleDeclarationMerging.ts, 8, 21)) + diff --git a/tests/baselines/reference/systemModuleDeclarationMerging.types b/tests/baselines/reference/systemModuleDeclarationMerging.types new file mode 100644 index 00000000000..20bf1e67f51 --- /dev/null +++ b/tests/baselines/reference/systemModuleDeclarationMerging.types @@ -0,0 +1,23 @@ +=== tests/cases/compiler/systemModuleDeclarationMerging.ts === + +export function F() {} +>F : typeof F + +export module F { var x; } +>F : typeof F +>x : any + +export class C {} +>C : C + +export module C { var x; } +>C : typeof C +>x : any + +export enum E {} +>E : E + +export module E { var x; } +>E : typeof E +>x : any + diff --git a/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.js b/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.js new file mode 100644 index 00000000000..87e96259bf1 --- /dev/null +++ b/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.js @@ -0,0 +1,58 @@ +//// [systemModuleNonTopLevelModuleMembers.ts] + +export class TopLevelClass {} +export module TopLevelModule {var v;} +export function TopLevelFunction(): void {} +export enum TopLevelEnum {E} + +export module TopLevelModule2 { + export class NonTopLevelClass {} + export module NonTopLevelModule {var v;} + export function NonTopLevelFunction(): void {} + export enum NonTopLevelEnum {E} +} + +//// [systemModuleNonTopLevelModuleMembers.js] +System.register([], function(exports_1) { + var TopLevelClass, TopLevelModule, TopLevelEnum, TopLevelModule2; + function TopLevelFunction() { } + exports_1("TopLevelFunction", TopLevelFunction); + return { + setters:[], + execute: function() { + TopLevelClass = (function () { + function TopLevelClass() { + } + return TopLevelClass; + })(); + exports_1("TopLevelClass", TopLevelClass); + (function (TopLevelModule) { + var v; + })(TopLevelModule = TopLevelModule || (TopLevelModule = {})); + exports_1("TopLevelModule", TopLevelModule) + (function (TopLevelEnum) { + TopLevelEnum[TopLevelEnum["E"] = 0] = "E"; + })(TopLevelEnum || (TopLevelEnum = {})); + exports_1("TopLevelEnum", TopLevelEnum) + (function (TopLevelModule2) { + var NonTopLevelClass = (function () { + function NonTopLevelClass() { + } + return NonTopLevelClass; + })(); + TopLevelModule2.NonTopLevelClass = NonTopLevelClass; + var NonTopLevelModule; + (function (NonTopLevelModule) { + var v; + })(NonTopLevelModule = TopLevelModule2.NonTopLevelModule || (TopLevelModule2.NonTopLevelModule = {})); + function NonTopLevelFunction() { } + TopLevelModule2.NonTopLevelFunction = NonTopLevelFunction; + (function (NonTopLevelEnum) { + NonTopLevelEnum[NonTopLevelEnum["E"] = 0] = "E"; + })(TopLevelModule2.NonTopLevelEnum || (TopLevelModule2.NonTopLevelEnum = {})); + var NonTopLevelEnum = TopLevelModule2.NonTopLevelEnum; + })(TopLevelModule2 = TopLevelModule2 || (TopLevelModule2 = {})); + exports_1("TopLevelModule2", TopLevelModule2) + } + } +}); diff --git a/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.symbols b/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.symbols new file mode 100644 index 00000000000..e0b69c71a2f --- /dev/null +++ b/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/systemModuleNonTopLevelModuleMembers.ts === + +export class TopLevelClass {} +>TopLevelClass : Symbol(TopLevelClass, Decl(systemModuleNonTopLevelModuleMembers.ts, 0, 0)) + +export module TopLevelModule {var v;} +>TopLevelModule : Symbol(TopLevelModule, Decl(systemModuleNonTopLevelModuleMembers.ts, 1, 29)) +>v : Symbol(v, Decl(systemModuleNonTopLevelModuleMembers.ts, 2, 33)) + +export function TopLevelFunction(): void {} +>TopLevelFunction : Symbol(TopLevelFunction, Decl(systemModuleNonTopLevelModuleMembers.ts, 2, 37)) + +export enum TopLevelEnum {E} +>TopLevelEnum : Symbol(TopLevelEnum, Decl(systemModuleNonTopLevelModuleMembers.ts, 3, 43)) +>E : Symbol(TopLevelEnum.E, Decl(systemModuleNonTopLevelModuleMembers.ts, 4, 26)) + +export module TopLevelModule2 { +>TopLevelModule2 : Symbol(TopLevelModule2, Decl(systemModuleNonTopLevelModuleMembers.ts, 4, 28)) + + export class NonTopLevelClass {} +>NonTopLevelClass : Symbol(NonTopLevelClass, Decl(systemModuleNonTopLevelModuleMembers.ts, 6, 31)) + + export module NonTopLevelModule {var v;} +>NonTopLevelModule : Symbol(NonTopLevelModule, Decl(systemModuleNonTopLevelModuleMembers.ts, 7, 36)) +>v : Symbol(v, Decl(systemModuleNonTopLevelModuleMembers.ts, 8, 40)) + + export function NonTopLevelFunction(): void {} +>NonTopLevelFunction : Symbol(NonTopLevelFunction, Decl(systemModuleNonTopLevelModuleMembers.ts, 8, 44)) + + export enum NonTopLevelEnum {E} +>NonTopLevelEnum : Symbol(NonTopLevelEnum, Decl(systemModuleNonTopLevelModuleMembers.ts, 9, 50)) +>E : Symbol(NonTopLevelEnum.E, Decl(systemModuleNonTopLevelModuleMembers.ts, 10, 33)) +} diff --git a/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.types b/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.types new file mode 100644 index 00000000000..ffe3d23f7a6 --- /dev/null +++ b/tests/baselines/reference/systemModuleNonTopLevelModuleMembers.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/systemModuleNonTopLevelModuleMembers.ts === + +export class TopLevelClass {} +>TopLevelClass : TopLevelClass + +export module TopLevelModule {var v;} +>TopLevelModule : typeof TopLevelModule +>v : any + +export function TopLevelFunction(): void {} +>TopLevelFunction : () => void + +export enum TopLevelEnum {E} +>TopLevelEnum : TopLevelEnum +>E : TopLevelEnum + +export module TopLevelModule2 { +>TopLevelModule2 : typeof TopLevelModule2 + + export class NonTopLevelClass {} +>NonTopLevelClass : NonTopLevelClass + + export module NonTopLevelModule {var v;} +>NonTopLevelModule : typeof NonTopLevelModule +>v : any + + export function NonTopLevelFunction(): void {} +>NonTopLevelFunction : () => void + + export enum NonTopLevelEnum {E} +>NonTopLevelEnum : NonTopLevelEnum +>E : NonTopLevelEnum +} diff --git a/tests/cases/compiler/systemModuleDeclarationMerging.ts b/tests/cases/compiler/systemModuleDeclarationMerging.ts new file mode 100644 index 00000000000..45c59c5b5dc --- /dev/null +++ b/tests/cases/compiler/systemModuleDeclarationMerging.ts @@ -0,0 +1,11 @@ +// @module: system +// @separateCompilation: true + +export function F() {} +export module F { var x; } + +export class C {} +export module C { var x; } + +export enum E {} +export module E { var x; } \ No newline at end of file diff --git a/tests/cases/compiler/systemModuleNonTopLevelModuleMembers.ts b/tests/cases/compiler/systemModuleNonTopLevelModuleMembers.ts new file mode 100644 index 00000000000..756d430a2de --- /dev/null +++ b/tests/cases/compiler/systemModuleNonTopLevelModuleMembers.ts @@ -0,0 +1,14 @@ +// @module: system +// @separateCompilation: true + +export class TopLevelClass {} +export module TopLevelModule {var v;} +export function TopLevelFunction(): void {} +export enum TopLevelEnum {E} + +export module TopLevelModule2 { + export class NonTopLevelClass {} + export module NonTopLevelModule {var v;} + export function NonTopLevelFunction(): void {} + export enum NonTopLevelEnum {E} +} \ No newline at end of file