Merge pull request #4179 from Microsoft/exportDeclarationsInSystem

emit export declarations for system modules as a part of 'execute' me…
This commit is contained in:
Vladimir Matveev
2015-08-10 13:59:45 -07:00
18 changed files with 605 additions and 176 deletions

View File

@@ -3091,31 +3091,38 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
function emitExportMemberAssignments(name: Identifier) {
if (compilerOptions.module === ModuleKind.System) {
return;
}
if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
for (let specifier of exportSpecifiers[name.text]) {
writeLine();
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);
emitEnd(specifier.name);
write(" = ");
emitExpressionIdentifier(name);
}
emitStart(specifier.name);
emitContainingModuleName(specifier);
write(".");
emitNodeWithoutSourceMap(specifier.name);
emitEnd(specifier.name);
write(" = ");
emitExpressionIdentifier(name);
write(";");
}
}
}
function emitExportSpecifierInSystemModule(specifier: ExportSpecifier): void {
Debug.assert(compilerOptions.module === ModuleKind.System);
writeLine();
emitStart(specifier.name);
write(`${exportFunctionForFile}("`);
emitNodeWithoutSourceMap(specifier.name);
write(`", `);
emitExpressionIdentifier(specifier.propertyName || specifier.name);
write(")");
emitEnd(specifier.name);
write(";");
}
function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, isAssignmentExpressionStatement: boolean, value?: Expression) {
let emitCount = 0;
@@ -6060,7 +6067,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return compilerOptions.module === ModuleKind.System && isExternalModule(currentSourceFile);
}
function emitSystemModuleBody(node: SourceFile, startIndex: number): void {
function emitSystemModuleBody(node: SourceFile, dependencyGroups: DependencyGroup[], startIndex: number): void {
// shape of the body in system modules:
// function (exports) {
// <list of local aliases for imports>
@@ -6105,7 +6112,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write("return {");
increaseIndent();
writeLine();
emitSetters(exportStarFunction);
emitSetters(exportStarFunction, dependencyGroups);
writeLine();
emitExecute(node, startIndex);
decreaseIndent();
@@ -6114,115 +6121,90 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitTempDeclarations(/*newLine*/ true);
}
function emitSetters(exportStarFunction: string) {
function emitSetters(exportStarFunction: string, dependencyGroups: DependencyGroup[]) {
write("setters:[");
for (let i = 0; i < externalImports.length; ++i) {
for (let i = 0; i < dependencyGroups.length; ++i) {
if (i !== 0) {
write(",");
}
writeLine();
increaseIndent();
let importNode = externalImports[i];
let importVariableName = getLocalNameForExternalImport(importNode) || "";
let parameterName = "_" + importVariableName;
let group = dependencyGroups[i];
// derive a unique name for parameter from the first named entry in the group
let parameterName = makeUniqueName(forEach(group, getLocalNameForExternalImport) || "");
write(`function (${parameterName}) {`);
increaseIndent();
for(let entry of group) {
let importVariableName = getLocalNameForExternalImport(entry) || "";
switch (entry.kind) {
case SyntaxKind.ImportDeclaration:
if (!(<ImportDeclaration>entry).importClause) {
// 'import "..."' case
// module is imported only for side-effects, no emit required
break;
}
// fall-through
case SyntaxKind.ImportEqualsDeclaration:
Debug.assert(importVariableName !== "");
switch (importNode.kind) {
case SyntaxKind.ImportDeclaration:
if (!(<ImportDeclaration>importNode).importClause) {
// 'import "..."' case
// module is imported only for side-effects, setter body will be empty
break;
}
// fall-through
case SyntaxKind.ImportEqualsDeclaration:
Debug.assert(importVariableName !== "");
increaseIndent();
writeLine();
// save import into the local
write(`${importVariableName} = ${parameterName};`);
writeLine();
let defaultName =
importNode.kind === SyntaxKind.ImportDeclaration
? (<ImportDeclaration>importNode).importClause.name
: (<ImportEqualsDeclaration>importNode).name;
if (defaultName) {
// emit re-export for imported default name
// import n1 from 'foo1'
// import n2 = require('foo2')
// export {n1}
// export {n2}
emitExportMemberAssignments(defaultName);
writeLine();
}
// save import into the local
write(`${importVariableName} = ${parameterName};`);
writeLine();
break;
case SyntaxKind.ExportDeclaration:
Debug.assert(importVariableName !== "");
if (importNode.kind === SyntaxKind.ImportDeclaration &&
(<ImportDeclaration>importNode).importClause.namedBindings) {
let namedBindings = (<ImportDeclaration>importNode).importClause.namedBindings;
if (namedBindings.kind === SyntaxKind.NamespaceImport) {
// emit re-export for namespace
// import * as n from 'foo'
// export {n}
emitExportMemberAssignments((<NamespaceImport>namedBindings).name);
if ((<ExportDeclaration>entry).exportClause) {
// export {a, b as c} from 'foo'
// emit as:
// exports_({
// "a": _["a"],
// "c": _["b"]
// });
writeLine();
write(`${exportFunctionForFile}({`);
writeLine();
increaseIndent();
for (let i = 0, len = (<ExportDeclaration>entry).exportClause.elements.length; i < len; ++i) {
if (i !== 0) {
write(",");
writeLine();
}
let e = (<ExportDeclaration>entry).exportClause.elements[i];
write(`"`);
emitNodeWithoutSourceMap(e.name);
write(`": ${parameterName}["`);
emitNodeWithoutSourceMap(e.propertyName || e.name);
write(`"]`);
}
decreaseIndent();
writeLine();
write("});")
}
else {
// emit re-exports for named imports
// import {a, b} from 'foo'
// export {a, b as c}
for (let element of (<NamedImports>namedBindings).elements) {
emitExportMemberAssignments(element.name || element.propertyName);
writeLine();
}
}
}
decreaseIndent();
break;
case SyntaxKind.ExportDeclaration:
Debug.assert(importVariableName !== "");
increaseIndent();
if ((<ExportDeclaration>importNode).exportClause) {
// export {a, b as c} from 'foo'
// emit as:
// var reexports = {}
// reexports['a'] = _foo["a"];
// reexports['c'] = _foo["b"];
// exports_(reexports);
let reexportsVariableName = makeUniqueName("reexports");
writeLine();
write(`var ${reexportsVariableName} = {};`);
writeLine();
for (let e of (<ExportDeclaration>importNode).exportClause.elements) {
write(`${reexportsVariableName}["`);
emitNodeWithoutSourceMap(e.name);
write(`"] = ${parameterName}["`);
emitNodeWithoutSourceMap(e.propertyName || e.name);
write(`"];`);
writeLine();
// export * from 'foo'
// emit as:
// exportStar(_foo);
write(`${exportStarFunction}(${parameterName});`);
}
write(`${exportFunctionForFile}(${reexportsVariableName});`);
}
else {
writeLine();
// export * from 'foo'
// emit as:
// exportStar(_foo);
write(`${exportStarFunction}(${parameterName});`);
}
writeLine();
decreaseIndent();
break;
writeLine();
break;
}
}
decreaseIndent();
write("}");
decreaseIndent();
}
@@ -6235,26 +6217,40 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
writeLine();
for (let i = startIndex; i < node.statements.length; ++i) {
let statement = node.statements[i];
// - external module related imports/exports are not emitted for system modules
// - function declarations are not emitted because they were already hoisted
switch (statement.kind) {
case SyntaxKind.ExportDeclaration:
// - function declarations are not emitted because they were already hoisted
// - import declarations are not emitted since they are already handled in setters
// - export declarations with module specifiers are not emitted since they were already written in setters
// - export declarations without module specifiers are emitted preserving the order
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.FunctionDeclaration:
continue;
case SyntaxKind.ExportDeclaration:
if (!(<ExportDeclaration>statement).moduleSpecifier) {
for (let element of (<ExportDeclaration>statement).exportClause.elements) {
// write call to exporter function for every export specifier in exports list
emitExportSpecifierInSystemModule(element);
}
}
continue;
case SyntaxKind.ImportEqualsDeclaration:
if (!isInternalModuleImportEqualsDeclaration(statement)) {
// - import equals declarations that import external modules are not emitted
continue;
}
}
writeLine();
emit(statement);
// fall-though for import declarations that import internal modules
default:
writeLine();
emit(statement);
}
}
decreaseIndent();
writeLine();
write("}"); // execute
}
type DependencyGroup = Array<ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration>;
function emitSystemModule(node: SourceFile, startIndex: number): void {
collectExternalModuleInfo(node);
// System modules has the following shape
@@ -6274,8 +6270,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(`"${node.moduleName}", `);
}
write("[");
let groupIndices: Map<number> = {};
let dependencyGroups: DependencyGroup[] = [];
for (let i = 0; i < externalImports.length; ++i) {
let text = getExternalModuleNameText(externalImports[i]);
if (hasProperty(groupIndices, text)) {
// deduplicate/group entries in dependency list by the dependency name
let groupIndex = groupIndices[text];
dependencyGroups[groupIndex].push(externalImports[i]);
continue;
}
else {
groupIndices[text] = dependencyGroups.length;
dependencyGroups.push([externalImports[i]]);
}
if (i !== 0) {
write(", ");
}
@@ -6286,7 +6297,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
increaseIndent();
emitEmitHelpers(node);
emitCaptureThisForNodeIfNecessary(node);
emitSystemModuleBody(node, startIndex);
emitSystemModuleBody(node, dependencyGroups, startIndex);
decreaseIndent();
writeLine();
write("});");