diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 235e28b8203..aa65406b426 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4992,10 +4992,18 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } } + // storage has the following structure + // { + // : void 0, + // : 'm' + // } + // this allows to: + // - prevent star exports to overwrite locally exported names + // - bind star exported names to particular module so they won't be overwritten by other star exports const exportedNamesStorageRef = makeUniqueName("exportedNames"); writeLine(); - write(`var ${exportedNamesStorageRef} = { `); + write(`var ${exportedNamesStorageRef} = {`); increaseIndent(); let started = false; @@ -5036,7 +5044,26 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLine(); write("};"); - return exportedNamesStorageRef; + writeLine(); + + const exportStarFunction = makeUniqueName("exportStar"); + + // define an export star helper function + write(`function ${exportStarFunction}(m, name) {`); + writeLine(); + write(` for(var n in m) {`); + writeLine(); + // if name is not yet taken by either local names or names in other modules - reserve it + write(` if (!${exportedNamesStorageRef}.hasOwnProperty(n)) ${exportedNamesStorageRef}[n] = name;`); + writeLine(); + // only export value if it was exported from the module with name 'name'; + write(` if (${exportedNamesStorageRef}[n] === name) ${exportFunctionForFile}(n, m[n]);`); + writeLine(); + write(" }"); + writeLine(); + write("}") + + return exportStarFunction; function writeExportedName(node: Identifier | Declaration): void { if (started) { @@ -5058,7 +5085,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { emitDeclarationName(node); } - write("': true"); + write("': void 0"); } } @@ -5234,12 +5261,12 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { emitVariableDeclarationsForImports(); writeLine(); var exportedDeclarations = processTopLevelVariableAndFunctionDeclarations(node); - let exportedLocalNames = emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations) + let exportStarFunction = emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations) writeLine(); write("return {"); increaseIndent(); writeLine(); - emitSetters(exportedLocalNames); + emitSetters(exportStarFunction); writeLine(); emitExecute(node, startIndex); emitTempDeclarations(/*newLine*/ true) @@ -5248,7 +5275,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { write("}"); // return } - function emitSetters(exportedLocalNamesRef: string) { + function emitSetters(exportStarFunction: string) { write("setters:["); for (let i = 0; i < externalImports.length; ++i) { if (i !== 0) { @@ -5341,16 +5368,8 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLine(); // export * from 'foo' // emit as: - // for (var n in _foo) exports(n, _foo[n]); - // NOTE: it is safe to use name 'n' since parameter name always starts with '_' - write(`for (var n in ${parameterName})`); - increaseIndent(); - writeLine(); - if (exportedLocalNamesRef) { - write(`if (!${exportedLocalNamesRef}.hasOwnProperty(n))`); - } - write(` ${exportFunctionForFile}(n, ${parameterName}[n]);`) - decreaseIndent(); + // exportStar(_foo, 'foo'); + write(`${exportStarFunction}(${parameterName}, ${getExternalModuleNameText(importNode)});`); } writeLine(); diff --git a/tests/baselines/reference/systemModule11.js b/tests/baselines/reference/systemModule11.js index 85e275ebbcf..c42719ac031 100644 --- a/tests/baselines/reference/systemModule11.js +++ b/tests/baselines/reference/systemModule11.js @@ -39,15 +39,20 @@ System.register(['bar'], function(exports_1) { var x; function foo() { } exports_1("foo", foo); - var exportedNames_1 = { - 'x': true, - 'foo': true + var exportedNames_1 = { + 'x': void 0, + 'foo': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_bar_1) { - for (var n in _bar_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + exportStar_1(_bar_1, 'bar'); }], execute: function() { exports_1("x", x); @@ -57,15 +62,20 @@ System.register(['bar'], function(exports_1) { //// [file2.js] System.register(['bar'], function(exports_1) { var x, y; - var exportedNames_1 = { - 'x': true, - 'y1': true + var exportedNames_1 = { + 'x': void 0, + 'y1': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_bar_1) { - for (var n in _bar_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + exportStar_1(_bar_1, 'bar'); }], execute: function() { exports_1("x", x); @@ -75,10 +85,16 @@ System.register(['bar'], function(exports_1) { }); //// [file3.js] System.register(['a', 'bar'], function(exports_1) { - var exportedNames_1 = { - 'x': true, - 'z': true + var exportedNames_1 = { + 'x': void 0, + 'z': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_a_1) { @@ -86,8 +102,7 @@ System.register(['a', 'bar'], function(exports_1) { exports_1("z", _a_1["y"]); }, function (_bar_1) { - for (var n in _bar_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]); + exportStar_1(_bar_1, 'bar'); }], execute: function() { } diff --git a/tests/baselines/reference/systemModule9.js b/tests/baselines/reference/systemModule9.js index 55f7707ecb1..27b274e8ab6 100644 --- a/tests/baselines/reference/systemModule9.js +++ b/tests/baselines/reference/systemModule9.js @@ -25,10 +25,16 @@ export {y as z}; System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], function(exports_1) { var ns, file2_1, file3_1, file5_1, ns3; var x, y; - var exportedNames_1 = { - 'x': true, - 'z': true + var exportedNames_1 = { + 'x': void 0, + 'z': void 0 }; + function exportStar_1(m, name) { + for(var n in m) { + if (!exportedNames_1.hasOwnProperty(n)) exportedNames_1[n] = name; + if (exportedNames_1[n] === name) exports_1(n, m[n]); + } + } return { setters:[ function (_ns) { @@ -48,8 +54,7 @@ System.register(['file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7'], ns3 = _ns3; }, function (_file7_1) { - for (var n in _file7_1) - if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _file7_1[n]); + exportStar_1(_file7_1, 'file7'); }], execute: function() { ns.f();