mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
generate local storage for all exported names to avoid overwriting them via star exports
This commit is contained in:
parent
2349a27f92
commit
aa1ad5233e
@ -3,12 +3,6 @@
|
||||
|
||||
/* @internal */
|
||||
module ts {
|
||||
// represents one LexicalEnvironment frame to store unique generated names
|
||||
interface ScopeFrame {
|
||||
names: Map<string>;
|
||||
previous: ScopeFrame;
|
||||
}
|
||||
|
||||
export function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) {
|
||||
return isExternalModule(sourceFile) || isDeclarationFile(sourceFile);
|
||||
}
|
||||
@ -18,7 +12,6 @@ module ts {
|
||||
Auto = 0x00000000, // No preferred name
|
||||
CountMask = 0x0FFFFFFF, // Temp variable counter
|
||||
_i = 0x10000000, // Use/preference flag for '_i'
|
||||
_n = 0x20000000, // Use/preference flag for '_n'
|
||||
}
|
||||
|
||||
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
|
||||
@ -2683,15 +2676,17 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
|
||||
for (let specifier of exportSpecifiers[name.text]) {
|
||||
writeLine();
|
||||
emitStart(specifier.name);
|
||||
if (compilerOptions.module === ModuleKind.System) {
|
||||
emitStart(specifier.name);
|
||||
write(`${exportFunctionForFile}("`);
|
||||
emitNodeWithoutSourceMap(specifier.name);
|
||||
write(`", `);
|
||||
emitExpressionIdentifier(name);
|
||||
write(")")
|
||||
emitEnd(specifier.name);
|
||||
}
|
||||
else {
|
||||
emitStart(specifier.name);
|
||||
emitContainingModuleName(specifier);
|
||||
write(".");
|
||||
emitNodeWithoutSourceMap(specifier.name);
|
||||
@ -4968,7 +4963,108 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
}
|
||||
}
|
||||
|
||||
function hoistTopLevelVariableAndFunctionDeclarations(node: SourceFile): void {
|
||||
function emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations: (Identifier | Declaration)[]): string {
|
||||
// when resolving exports local exported entries/indirect exported entries in the module
|
||||
// should always win over entries with similar names that were added via star exports
|
||||
// to support this we store names of local/indirect exported entries in a set.
|
||||
// this set is used to filter names brought by star expors.
|
||||
|
||||
if (!hasExportStars) {
|
||||
// local names set is needed only in presence of star exports
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// local names set should only be added if we have anything exported
|
||||
if (!exportedDeclarations && isEmpty(exportSpecifiers)) {
|
||||
// no exported declarations (export var ...) or export specifiers (export {x})
|
||||
// check if we have any non star export declarations.
|
||||
let hasExportDeclarationWithExportClause = false;
|
||||
for (let externalImport of externalImports) {
|
||||
if (externalImport.kind === SyntaxKind.ExportDeclaration && (<ExportDeclaration>externalImport).exportClause) {
|
||||
hasExportDeclarationWithExportClause = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasExportDeclarationWithExportClause) {
|
||||
// nothing is exported
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const exportedNamesStorageRef = makeUniqueName("exportedNames");
|
||||
|
||||
writeLine();
|
||||
write(`var ${exportedNamesStorageRef} = { `);
|
||||
increaseIndent();
|
||||
|
||||
let started = false;
|
||||
if (exportedDeclarations) {
|
||||
for (let i = 0; i < exportedDeclarations.length; ++i) {
|
||||
// write name of exported declaration, i.e 'export var x...'
|
||||
writeExportedName(exportedDeclarations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (exportSpecifiers) {
|
||||
for (let n in exportSpecifiers) {
|
||||
for (let specifier of exportSpecifiers[n]) {
|
||||
// write name of export specified, i.e. 'export {x}'
|
||||
writeExportedName(specifier.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (externalImports) {
|
||||
for (let externalImport of externalImports) {
|
||||
if (externalImport.kind !== SyntaxKind.ExportDeclaration) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let exportDecl = <ExportDeclaration>externalImport;
|
||||
if (!exportDecl.exportClause) {
|
||||
// export * from ...
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let element of exportDecl.exportClause.elements) {
|
||||
// write name of indirectly exported entry, i.e. 'export {x} from ...'
|
||||
writeExportedName(element.name || element.propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decreaseIndent();
|
||||
writeLine();
|
||||
write("};");
|
||||
|
||||
return exportedNamesStorageRef;
|
||||
|
||||
function writeExportedName(node: Identifier | Declaration): void {
|
||||
if (started) {
|
||||
write(",");
|
||||
}
|
||||
else {
|
||||
started = true;
|
||||
}
|
||||
|
||||
writeLine();
|
||||
write("'");
|
||||
if (node.kind === SyntaxKind.Identifier) {
|
||||
emitNodeWithoutSourceMap(node);
|
||||
}
|
||||
else if (node.flags & NodeFlags.Default) {
|
||||
write("default");
|
||||
}
|
||||
else {
|
||||
emitDeclarationName(<Declaration>node);
|
||||
}
|
||||
|
||||
write("': true");
|
||||
}
|
||||
}
|
||||
|
||||
function processTopLevelVariableAndFunctionDeclarations(node: SourceFile): (Identifier | Declaration)[] {
|
||||
// per ES6 spec:
|
||||
// 15.2.1.16.4 ModuleDeclarationInstantiation() Concrete Method
|
||||
// - var declarations are initialized to undefined - 14.a.ii
|
||||
@ -4980,6 +5076,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
// including variables declarations for module and class declarations
|
||||
let hoistedVars: (Identifier | ClassDeclaration | ModuleDeclaration)[];
|
||||
let hoistedFunctionDeclarations: FunctionDeclaration[];
|
||||
let exportedDeclarations: (Identifier | Declaration)[];
|
||||
|
||||
visit(node);
|
||||
|
||||
@ -4997,6 +5094,14 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
else {
|
||||
emit(local);
|
||||
}
|
||||
|
||||
let flags = getCombinedNodeFlags(local.kind === SyntaxKind.Identifier ? local.parent : local);
|
||||
if (flags & NodeFlags.Export) {
|
||||
if (!exportedDeclarations) {
|
||||
exportedDeclarations = [];
|
||||
}
|
||||
exportedDeclarations.push(local);
|
||||
}
|
||||
}
|
||||
write(";")
|
||||
}
|
||||
@ -5005,9 +5110,18 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
for (let f of hoistedFunctionDeclarations) {
|
||||
writeLine();
|
||||
emit(f);
|
||||
|
||||
if (f.flags & NodeFlags.Export) {
|
||||
if (!exportedDeclarations) {
|
||||
exportedDeclarations = [];
|
||||
}
|
||||
exportedDeclarations.push(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exportedDeclarations;
|
||||
|
||||
function visit(node: Node): void {
|
||||
if (node.kind === SyntaxKind.FunctionDeclaration) {
|
||||
if (!hoistedFunctionDeclarations) {
|
||||
@ -5121,12 +5235,13 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
// }
|
||||
emitVariableDeclarationsForImports();
|
||||
writeLine();
|
||||
hoistTopLevelVariableAndFunctionDeclarations(node);
|
||||
var exportedDeclarations = processTopLevelVariableAndFunctionDeclarations(node);
|
||||
let exportedLocalNames = emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations)
|
||||
writeLine();
|
||||
write("return {");
|
||||
increaseIndent();
|
||||
writeLine();
|
||||
emitSetters();
|
||||
emitSetters(exportedLocalNames);
|
||||
writeLine();
|
||||
emitExecute(node, startIndex);
|
||||
emitTempDeclarations(/*newLine*/ true)
|
||||
@ -5135,7 +5250,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
write("}"); // return
|
||||
}
|
||||
|
||||
function emitSetters() {
|
||||
function emitSetters(exportedLocalNamesRef: string) {
|
||||
write("setters:[");
|
||||
for (let i = 0; i < externalImports.length; ++i) {
|
||||
if (i !== 0) {
|
||||
@ -5163,7 +5278,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
increaseIndent();
|
||||
writeLine();
|
||||
// save import into the local
|
||||
write(`${importVariableName} = ${parameterName}`);
|
||||
write(`${importVariableName} = ${parameterName};`);
|
||||
writeLine();
|
||||
|
||||
let defaultName =
|
||||
@ -5230,7 +5345,14 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) {
|
||||
// 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}) ${exportFunctionForFile}(n, ${parameterName}[n]);`);
|
||||
write(`for (var n in ${parameterName})`);
|
||||
increaseIndent();
|
||||
writeLine();
|
||||
if (exportedLocalNamesRef) {
|
||||
write(`if (!${exportedLocalNamesRef}.hasOwnProperty(n))`);
|
||||
}
|
||||
write(` ${exportFunctionForFile}(n, ${parameterName}[n]);`)
|
||||
decreaseIndent();
|
||||
}
|
||||
|
||||
writeLine();
|
||||
|
||||
@ -15,14 +15,14 @@ System.register(['file1', 'file2'], function(exports_1) {
|
||||
return {
|
||||
setters:[
|
||||
function (_file1_1) {
|
||||
file1_1 = _file1_1
|
||||
file1_1 = _file1_1;
|
||||
exports_1("n", file1_1["default"]);
|
||||
exports_1("n1", file1_1["default"]);
|
||||
exports_1("x", file1_1.x);
|
||||
exports_1("y", file1_1.x);
|
||||
},
|
||||
function (_n2) {
|
||||
n2 = _n2
|
||||
n2 = _n2;
|
||||
exports_1("n2", n2);
|
||||
exports_1("n3", n2);
|
||||
}],
|
||||
|
||||
@ -15,14 +15,14 @@ System.register(['file1', 'file2'], function(exports_1) {
|
||||
return {
|
||||
setters:[
|
||||
function (_file1_1) {
|
||||
file1_1 = _file1_1
|
||||
file1_1 = _file1_1;
|
||||
exports_1("n", file1_1.default);
|
||||
exports_1("n1", file1_1.default);
|
||||
exports_1("x", file1_1.x);
|
||||
exports_1("y", file1_1.x);
|
||||
},
|
||||
function (_n2) {
|
||||
n2 = _n2
|
||||
n2 = _n2;
|
||||
exports_1("n2", n2);
|
||||
exports_1("n3", n2);
|
||||
}],
|
||||
|
||||
@ -1,11 +1,49 @@
|
||||
tests/cases/compiler/systemModule11.ts(3,17): error TS2307: Cannot find external module 'bar'.
|
||||
tests/cases/compiler/file1.ts(7,15): error TS2307: Cannot find external module 'bar'.
|
||||
tests/cases/compiler/file2.ts(7,15): error TS2307: Cannot find external module 'bar'.
|
||||
tests/cases/compiler/file3.ts(2,25): error TS2307: Cannot find external module 'a'.
|
||||
tests/cases/compiler/file3.ts(3,15): error TS2307: Cannot find external module 'bar'.
|
||||
tests/cases/compiler/file4.ts(8,27): error TS2307: Cannot find external module 'a'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/systemModule11.ts (1 errors) ====
|
||||
==== tests/cases/compiler/file1.ts (1 errors) ====
|
||||
|
||||
import 'foo'
|
||||
import {f} from 'bar';
|
||||
~~~~~
|
||||
// set of tests cases that checks generation of local storage for exported names
|
||||
|
||||
|
||||
export var x;
|
||||
export function foo() {}
|
||||
export * from 'bar';
|
||||
~~~~~
|
||||
!!! error TS2307: Cannot find external module 'bar'.
|
||||
|
||||
f();
|
||||
==== tests/cases/compiler/file2.ts (1 errors) ====
|
||||
|
||||
var x;
|
||||
var y;
|
||||
export {x};
|
||||
export {y as y1}
|
||||
|
||||
export * from 'bar';
|
||||
~~~~~
|
||||
!!! error TS2307: Cannot find external module 'bar'.
|
||||
|
||||
==== tests/cases/compiler/file3.ts (2 errors) ====
|
||||
|
||||
export {x, y as z} from 'a';
|
||||
~~~
|
||||
!!! error TS2307: Cannot find external module 'a'.
|
||||
export * from 'bar';
|
||||
~~~~~
|
||||
!!! error TS2307: Cannot find external module 'bar'.
|
||||
|
||||
==== tests/cases/compiler/file4.ts (1 errors) ====
|
||||
|
||||
export var x;
|
||||
export function foo() {}
|
||||
|
||||
var z, z1;
|
||||
export {z, z1 as z2};
|
||||
|
||||
export {s, s1 as s2} from 'a'
|
||||
~~~
|
||||
!!! error TS2307: Cannot find external module 'a'.
|
||||
@ -1,21 +1,113 @@
|
||||
//// [systemModule11.ts]
|
||||
|
||||
import 'foo'
|
||||
import {f} from 'bar';
|
||||
|
||||
f();
|
||||
//// [tests/cases/compiler/systemModule11.ts] ////
|
||||
|
||||
//// [systemModule11.js]
|
||||
System.register(['foo', 'bar'], function(exports_1) {
|
||||
var bar_1;
|
||||
//// [file1.ts]
|
||||
|
||||
// set of tests cases that checks generation of local storage for exported names
|
||||
|
||||
|
||||
export var x;
|
||||
export function foo() {}
|
||||
export * from 'bar';
|
||||
|
||||
//// [file2.ts]
|
||||
|
||||
var x;
|
||||
var y;
|
||||
export {x};
|
||||
export {y as y1}
|
||||
|
||||
export * from 'bar';
|
||||
|
||||
//// [file3.ts]
|
||||
|
||||
export {x, y as z} from 'a';
|
||||
export * from 'bar';
|
||||
|
||||
//// [file4.ts]
|
||||
|
||||
export var x;
|
||||
export function foo() {}
|
||||
|
||||
var z, z1;
|
||||
export {z, z1 as z2};
|
||||
|
||||
export {s, s1 as s2} from 'a'
|
||||
|
||||
//// [file1.js]
|
||||
// set of tests cases that checks generation of local storage for exported names
|
||||
System.register(['bar'], function(exports_1) {
|
||||
var x;
|
||||
function foo() { }
|
||||
exports_1("foo", foo);
|
||||
var exportedNames_1 = {
|
||||
'x': true,
|
||||
'foo': true
|
||||
};
|
||||
return {
|
||||
setters:[
|
||||
function (_) {},
|
||||
function (_bar_1) {
|
||||
bar_1 = _bar_1
|
||||
for (var n in _bar_1)
|
||||
if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]);
|
||||
}],
|
||||
execute: function() {
|
||||
bar_1.f();
|
||||
exports_1("x", x);
|
||||
}
|
||||
}
|
||||
});
|
||||
//// [file2.js]
|
||||
System.register(['bar'], function(exports_1) {
|
||||
var x, y;
|
||||
var exportedNames_1 = {
|
||||
'x': true,
|
||||
'y1': true
|
||||
};
|
||||
return {
|
||||
setters:[
|
||||
function (_bar_1) {
|
||||
for (var n in _bar_1)
|
||||
if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _bar_1[n]);
|
||||
}],
|
||||
execute: function() {
|
||||
exports_1("x", x);
|
||||
exports_1("y1", y);
|
||||
}
|
||||
}
|
||||
});
|
||||
//// [file3.js]
|
||||
System.register(['a', 'bar'], function(exports_1) {
|
||||
var exportedNames_1 = {
|
||||
'x': true,
|
||||
'z': true
|
||||
};
|
||||
return {
|
||||
setters:[
|
||||
function (_a_1) {
|
||||
exports_1("x", _a_1["x"]);
|
||||
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]);
|
||||
}],
|
||||
execute: function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
//// [file4.js]
|
||||
System.register(['a'], function(exports_1) {
|
||||
var x, z, z1;
|
||||
function foo() { }
|
||||
exports_1("foo", foo);
|
||||
return {
|
||||
setters:[
|
||||
function (_a_1) {
|
||||
exports_1("s", _a_1["s"]);
|
||||
exports_1("s2", _a_1["s1"]);
|
||||
}],
|
||||
execute: function() {
|
||||
exports_1("x", x);
|
||||
exports_1("z", z);
|
||||
exports_1("z2", z1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -25,26 +25,31 @@ 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
|
||||
};
|
||||
return {
|
||||
setters:[
|
||||
function (_ns) {
|
||||
ns = _ns
|
||||
ns = _ns;
|
||||
},
|
||||
function (_file2_1) {
|
||||
file2_1 = _file2_1
|
||||
file2_1 = _file2_1;
|
||||
},
|
||||
function (_file3_1) {
|
||||
file3_1 = _file3_1
|
||||
file3_1 = _file3_1;
|
||||
},
|
||||
function (_) {},
|
||||
function (_file5_1) {
|
||||
file5_1 = _file5_1
|
||||
file5_1 = _file5_1;
|
||||
},
|
||||
function (_ns3) {
|
||||
ns3 = _ns3
|
||||
ns3 = _ns3;
|
||||
},
|
||||
function (_file7_1) {
|
||||
for (var n in _file7_1) exports_1(n, _file7_1[n]);
|
||||
for (var n in _file7_1)
|
||||
if (!exportedNames_1.hasOwnProperty(n)) exports_1(n, _file7_1[n]);
|
||||
}],
|
||||
execute: function() {
|
||||
ns.f();
|
||||
|
||||
@ -1,7 +1,34 @@
|
||||
// @module: system
|
||||
// @separateCompilation: true
|
||||
|
||||
import 'foo'
|
||||
import {f} from 'bar';
|
||||
// set of tests cases that checks generation of local storage for exported names
|
||||
|
||||
f();
|
||||
// @filename: file1.ts
|
||||
|
||||
export var x;
|
||||
export function foo() {}
|
||||
export * from 'bar';
|
||||
|
||||
// @filename: file2.ts
|
||||
|
||||
var x;
|
||||
var y;
|
||||
export {x};
|
||||
export {y as y1}
|
||||
|
||||
export * from 'bar';
|
||||
|
||||
// @filename: file3.ts
|
||||
|
||||
export {x, y as z} from 'a';
|
||||
export * from 'bar';
|
||||
|
||||
// @filename: file4.ts
|
||||
|
||||
export var x;
|
||||
export function foo() {}
|
||||
|
||||
var z, z1;
|
||||
export {z, z1 as z2};
|
||||
|
||||
export {s, s1 as s2} from 'a'
|
||||
Loading…
x
Reference in New Issue
Block a user