Fix emit for modules and enums.

This commit is contained in:
Ron Buckton 2016-03-30 11:18:29 -07:00
parent 36257ec478
commit d647f89daa
7 changed files with 429 additions and 305 deletions

View File

@ -16076,7 +16076,7 @@ namespace ts {
// When resolved as an expression identifier, if the given node references an exported entity, return the declaration
// node of the exported entity's container. Otherwise, return undefined.
function getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration {
function getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration {
let symbol = getReferencedValueSymbol(node);
if (symbol) {
if (symbol.flags & SymbolFlags.ExportValue) {
@ -16084,7 +16084,7 @@ namespace ts {
// we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the
// kinds that we do NOT prefix.
const exportSymbol = getMergedSymbol(symbol.exportSymbol);
if (exportSymbol.flags & SymbolFlags.ExportHasLocal) {
if (exportSymbol.flags & SymbolFlags.ExportHasLocal && !prefixLocals) {
return undefined;
}
symbol = exportSymbol;

View File

@ -258,6 +258,9 @@ namespace ts {
case SyntaxKind.ClassDeclaration:
return visitClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.ExpressionStatement:
return visitExpressionStatement(<ExpressionStatement>node);
default:
// This visitor does not descend into the tree, as export/import statements
// are only transformed at the top level of a file.
@ -544,24 +547,33 @@ namespace ts {
}
}
function addExportMemberAssignment(statements: Statement[], node: FunctionDeclaration | ClassDeclaration) {
function addExportMemberAssignment(statements: Statement[], node: DeclarationStatement) {
if (hasModifier(node, ModifierFlags.Default)) {
addExportDefault(statements, node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node), /*location*/ node);
addExportDefault(statements, getDeclarationName(node), /*location*/ node);
}
else {
statements.push(
startOnNewLine(
createStatement(
createExportAssignment(node.name, node.name),
/*location*/ node
)
)
createExportStatement(node.name, node.name, /*location*/ node)
);
}
}
function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
if (hasModifier(node, ModifierFlags.Export)) {
// If the variable is for a declaration that has a local name,
// do not elide the declaration.
const original = getOriginalNode(node);
if (original.kind === SyntaxKind.EnumDeclaration
|| original.kind === SyntaxKind.ModuleDeclaration) {
return setOriginalNode(
createVariableStatement(
/*modifiers*/ undefined,
node.declarationList
),
node
);
}
const variables = getInitializedVariables(node.declarationList);
if (variables.length === 0) {
// elide statement if there are no initialized variables
@ -651,6 +663,87 @@ namespace ts {
return singleOrMany(statements);
}
function visitExpressionStatement(node: ExpressionStatement): VisitResult<Statement> {
const original = getOriginalNode(node);
if (hasModifier(original, ModifierFlags.Export)) {
switch (original.kind) {
case SyntaxKind.EnumDeclaration:
return visitExpressionStatementForEnumDeclaration(node, <EnumDeclaration>original);
case SyntaxKind.ModuleDeclaration:
return visitExpressionStatementForModuleDeclaration(node, <ModuleDeclaration>original);
}
}
return node;
}
function visitExpressionStatementForEnumDeclaration(node: ExpressionStatement, original: EnumDeclaration): VisitResult<Statement> {
if (isFirstDeclarationOfKind(original, SyntaxKind.EnumDeclaration)) {
const statements: Statement[] = [node];
addVarForExportedEnumOrModule(statements, original);
return statements;
}
return node;
}
function isModuleMergedWithES6Class(node: ModuleDeclaration) {
return languageVersion === ScriptTarget.ES6
&& isMergedWithClass(node);
}
function visitExpressionStatementForModuleDeclaration(node: ExpressionStatement, original: ModuleDeclaration): VisitResult<Statement> {
if (isFirstDeclarationOfKind(original, SyntaxKind.ModuleDeclaration)) {
const statements: Statement[] = [node];
if (isModuleMergedWithES6Class(original)) {
addAssignmentForExportedModule(statements, original);
}
else {
addVarForExportedEnumOrModule(statements, original);
}
return statements;
}
return node;
}
/**
* Adds a trailing VariableStatement for an enum or module declaration.
*/
function addVarForExportedEnumOrModule(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
[createVariableDeclaration(
getDeclarationName(node),
createPropertyAccess(createIdentifier("exports"), getDeclarationName(node))
)],
/*location*/ node
)
);
}
/**
* Adds a trailing assignment for a module declaration.
*/
function addAssignmentForExportedModule(statements: Statement[], node: ModuleDeclaration) {
statements.push(
createStatement(
createAssignment(
getDeclarationName(node),
createPropertyAccess(createIdentifier("exports"), getDeclarationName(node))
),
/*location*/ node
)
);
}
function getDeclarationName(node: DeclarationStatement) {
return node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node);
}
function substituteExpression(node: Expression) {
node = previousExpressionSubstitution(node);
if (isIdentifier(node)) {
@ -663,7 +756,7 @@ namespace ts {
function substituteExpressionIdentifier(node: Identifier): Expression {
const original = getOriginalNode(node);
if (isIdentifier(original)) {
const container = resolver.getReferencedExportContainer(original);
const container = resolver.getReferencedExportContainer(original, (getNodeEmitFlags(node) & NodeEmitFlags.PrefixExportedLocal) !== 0);
if (container) {
if (container.kind === SyntaxKind.SourceFile) {
return createPropertyAccess(
@ -760,6 +853,10 @@ namespace ts {
return createCall(createIdentifier("require"), args);
}
function createExportStatement(name: Identifier, value: Expression, location?: TextRange) {
return startOnNewLine(createStatement(createExportAssignment(name, value), location));
}
function createExportAssignment(name: Identifier, value: Expression) {
return createAssignment(
name.originalKeywordKind && languageVersion === ScriptTarget.ES3

View File

@ -94,7 +94,7 @@ namespace ts {
*
* @param node The node to visit.
*/
function visitWithStack(node: Node, visitor: (node: Node) => VisitResult<Node>): VisitResult<Node> {
function saveStateAndInvoke<T>(node: Node, f: (node: Node) => T): T {
// Save state
const savedCurrentScope = currentScope;
const savedCurrentParent = currentParent;
@ -103,7 +103,7 @@ namespace ts {
// Handle state changes before visiting a node.
onBeforeVisitNode(node);
const visited = visitor(node);
const visited = f(node);
// Restore state
currentScope = savedCurrentScope;
@ -119,7 +119,7 @@ namespace ts {
* @param node The node to visit.
*/
function visitor(node: Node): VisitResult<Node> {
return visitWithStack(node, visitorWorker);
return saveStateAndInvoke(node, visitorWorker);
}
/**
@ -146,7 +146,7 @@ namespace ts {
* @param node The node to visit.
*/
function namespaceElementVisitor(node: Node): VisitResult<Node> {
return visitWithStack(node, namespaceElementVisitorWorker);
return saveStateAndInvoke(node, namespaceElementVisitorWorker);
}
/**
@ -155,7 +155,7 @@ namespace ts {
* @param node The node to visit.
*/
function namespaceElementVisitorWorker(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.TypeScript || isExported(node)) {
if (node.transformFlags & TransformFlags.TypeScript || hasModifier(node, ModifierFlags.Export)) {
// This node is explicitly marked as TypeScript, or is exported at the namespace
// level, so we should transform the node.
return visitTypeScript(node);
@ -174,7 +174,7 @@ namespace ts {
* @param node The node to visit.
*/
function classElementVisitor(node: Node): VisitResult<Node> {
return visitWithStack(node, classElementVisitorWorker);
return saveStateAndInvoke(node, classElementVisitorWorker);
}
/**
@ -462,7 +462,7 @@ namespace ts {
// Otherwise, if the class was exported at the top level and was decorated, emit an export
// declaration or export default for the class.
if (isNamespaceExport(node)) {
addNamespaceExport(statements, name, name);
addExportMemberAssignment(statements, node);
}
else if (node.decorators) {
if (isDefaultExternalModuleExport(node)) {
@ -619,16 +619,19 @@ namespace ts {
// let ${name} = ${classExpression};
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
name,
classExpression
)
],
/*location*/ undefined,
NodeFlags.Let)
setOriginalNode(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
name,
classExpression
)
],
/*location*/ undefined,
NodeFlags.Let)
),
/*original*/ node
)
);
@ -1785,6 +1788,17 @@ namespace ts {
);
}
/**
* Determines whether to emit a function-like declaration. We should not emit the
* declaration if it is an overload, is abstract, or is an ambient declaration.
*
* @param node The declaration node.
*/
function shouldEmitFunctionLikeDeclaration(node: FunctionLikeDeclaration) {
return !nodeIsMissing(node.body)
&& !hasModifier(node, ModifierFlags.Abstract | ModifierFlags.Ambient);
}
/**
* Visits a method declaration of a class.
*
@ -1797,7 +1811,7 @@ namespace ts {
* @param node The method node.
*/
function visitMethodDeclaration(node: MethodDeclaration) {
if (shouldElideFunctionLikeDeclaration(node)) {
if (!shouldEmitFunctionLikeDeclaration(node)) {
return undefined;
}
@ -1813,6 +1827,16 @@ namespace ts {
);
}
/**
* Determines whether to emit an accessor declaration. We should not emit the
* declaration if it is abstract or is an ambient declaration.
*
* @param node The declaration node.
*/
function shouldEmitAccessorDeclaration(node: AccessorDeclaration) {
return !hasModifier(node, ModifierFlags.Abstract | ModifierFlags.Ambient);
}
/**
* Visits a get accessor declaration of a class.
*
@ -1823,7 +1847,7 @@ namespace ts {
* @param node The get accessor node.
*/
function visitGetAccessor(node: GetAccessorDeclaration) {
if (shouldElideAccessorDeclaration(node)) {
if (!shouldEmitAccessorDeclaration(node)) {
return undefined;
}
@ -1835,16 +1859,6 @@ namespace ts {
);
}
/**
* Determines whether a function-like declaration should be elided. A declaration should
* be elided if it is an overload, is abstract, or is an ambient declaration.
*
* @param node The declaration node.
*/
function shouldElideAccessorDeclaration(node: AccessorDeclaration) {
return hasModifier(node, ModifierFlags.Abstract | ModifierFlags.Ambient);
}
/**
* Visits a set accessor declaration of a class.
*
@ -1855,7 +1869,7 @@ namespace ts {
* @param node The set accessor node.
*/
function visitSetAccessor(node: SetAccessorDeclaration) {
if (shouldElideAccessorDeclaration(node)) {
if (!shouldEmitAccessorDeclaration(node)) {
return undefined;
}
@ -1879,7 +1893,7 @@ namespace ts {
* @param node The function node.
*/
function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> {
if (shouldElideFunctionLikeDeclaration(node)) {
if (!shouldEmitFunctionLikeDeclaration(node)) {
return undefined;
}
@ -1893,10 +1907,9 @@ namespace ts {
);
if (isNamespaceExport(node)) {
return [
func,
createNamespaceExport(getSynthesizedClone(node.name), getSynthesizedClone(node.name))
];
const statements: Statement[] = [func];
addExportMemberAssignment(statements, node);
return statements;
}
return func;
@ -1924,17 +1937,6 @@ namespace ts {
);
}
/**
* Determines whether a function-like declaration should be elided. A declaration should
* be elided if it is an overload, is abstract, or is an ambient declaration.
*
* @param node The declaration node.
*/
function shouldElideFunctionLikeDeclaration(node: FunctionLikeDeclaration) {
return nodeIsMissing(node.body)
|| hasModifier(node, ModifierFlags.Abstract | ModifierFlags.Ambient);
}
/**
* @remarks
* This function will be called when one of the following conditions are met:
@ -2109,155 +2111,6 @@ namespace ts {
}
}
/**
* Visits an enum declaration.
*
* This function will be called any time a TypeScript enum is encountered.
*
* @param node The enum declaration node.
*/
function visitEnumDeclaration(node: EnumDeclaration): VisitResult<Statement> {
if (shouldElideEnumDeclaration(node)) {
return undefined;
}
const savedCurrentNamespaceLocalName = currentNamespaceLocalName;
const statements: Statement[] = [];
let location: TextRange = node;
if (!isExported(node) || (isExternalModuleExport(node) && isFirstDeclarationOfKind(node, SyntaxKind.EnumDeclaration))) {
// Emit a VariableStatement if the enum is not exported, or is the first enum
// with the same name exported from an external module.
statements.push(
createVariableStatement(
visitNodes(node.modifiers, visitor, isModifier),
createVariableDeclarationList([
createVariableDeclaration(node.name)
]),
location
)
);
location = undefined;
}
const name = isNamespaceExport(node)
? getNamespaceMemberName(node.name)
: getSynthesizedClone(node.name);
currentNamespaceLocalName = getGeneratedNameForNode(node);
// (function (x) {
// x[x["y"] = 0] = "y";
// ...
// })(x || (x = {}));
statements.push(
setOriginalNode(
createStatement(
createCall(
createParen(
createFunctionExpression(
/*asteriskToken*/ undefined,
/*name*/ undefined,
[createParameter(currentNamespaceLocalName)],
transformEnumBody(node)
)
),
[createLogicalOr(
name,
createAssignment(
name,
createObjectLiteral()
)
)]
),
location
), node
)
);
if (isNamespaceExport(node)) {
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(node.name, name)
]),
location
)
);
}
currentNamespaceLocalName = savedCurrentNamespaceLocalName;
return statements;
}
/**
* Transforms the body of an enum declaration.
*
* @param node The enum declaration node.
*/
function transformEnumBody(node: EnumDeclaration): Block {
const statements: Statement[] = [];
startLexicalEnvironment();
addNodes(statements, map(node.members, transformEnumMember));
addNodes(statements, endLexicalEnvironment());
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
}
/**
* Transforms an enum member into a statement.
*
* @param member The enum member node.
*/
function transformEnumMember(member: EnumMember): Statement {
const name = getExpressionForPropertyName(member);
return createStatement(
createAssignment(
createElementAccess(
currentNamespaceLocalName,
createAssignment(
createElementAccess(
currentNamespaceLocalName,
name
),
transformEnumMemberDeclarationValue(member)
)
),
name
),
member
);
}
/**
* Transforms the value of an enum member.
*
* @param member The enum member node.
*/
function transformEnumMemberDeclarationValue(member: EnumMember): Expression {
const value = resolver.getConstantValue(member);
if (value !== undefined) {
return createLiteral(value);
}
else if (member.initializer) {
return visitNode(member.initializer, visitor, isExpression);
}
else {
return createVoidZero();
}
}
/**
* Determines whether to elide an enum declaration.
*
* @param node The enum declaration node.
*/
function shouldElideEnumDeclaration(node: EnumDeclaration) {
return isConst(node)
&& !compilerOptions.preserveConstEnums
&& !compilerOptions.isolatedModules;
}
/**
* Visits an await expression.
*
@ -2328,6 +2181,182 @@ namespace ts {
return child;
}
/**
* Adds a leading VariableStatement for an enum or module declaration.
*/
function addVarForEnumOrModuleDeclaration(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
// Emit a variable statement for the enum.
statements.push(
createVariableStatement(
visitNodes(node.modifiers, visitor, isModifier),
[createVariableDeclaration(
getDeclarationName(node)
)],
/*location*/ node
)
);
}
/**
* Adds a trailing VariableStatement for an enum or module declaration.
*/
function addVarForEnumOrModuleExportedFromNamespace(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
[createVariableDeclaration(
getDeclarationName(node),
getDeclarationNameExpression(node)
)],
/*location*/ node
)
)
}
function addAssignmentForModuleExportedFromNamespace(statements: Statement[], node: ModuleDeclaration) {
statements.push(
createStatement(
createAssignment(
getDeclarationName(node),
setNodeEmitFlags(getDeclarationName(node), NodeEmitFlags.PrefixExportedLocal)
),
/*location*/ node
)
);
}
/**
* Determines whether to emit an enum declaration.
*
* @param node The enum declaration node.
*/
function shouldEmitEnumDeclaration(node: EnumDeclaration) {
return !isConst(node)
|| compilerOptions.preserveConstEnums
|| compilerOptions.isolatedModules;
}
function shouldEmitVarForEnumOrModuleDeclaration(node: EnumDeclaration | ModuleDeclaration) {
return !hasModifier(node, ModifierFlags.Export)
|| (isExternalModuleExport(node) && isFirstDeclarationOfKind(node, node.kind));
}
/**
* Visits an enum declaration.
*
* This function will be called any time a TypeScript enum is encountered.
*
* @param node The enum declaration node.
*/
function visitEnumDeclaration(node: EnumDeclaration): VisitResult<Statement> {
if (!shouldEmitEnumDeclaration(node)) {
return undefined;
}
const statements: Statement[] = [];
if (shouldEmitVarForEnumOrModuleDeclaration(node)) {
addVarForEnumOrModuleDeclaration(statements, node);
}
const localName = getGeneratedNameForNode(node);
const name = getDeclarationNameExpression(node);
// (function (x) {
// x[x["y"] = 0] = "y";
// ...
// })(x || (x = {}));
statements.push(
setOriginalNode(
createStatement(
createCall(
createFunctionExpression(
/*asteriskToken*/ undefined,
/*name*/ undefined,
[createParameter(localName)],
transformEnumBody(node, localName)
),
[createLogicalOr(
name,
createAssignment(
name,
createObjectLiteral()
)
)]
),
/*location*/ node
),
/*original*/ node
)
);
if (isNamespaceExport(node)) {
addVarForEnumOrModuleExportedFromNamespace(statements, node);
}
return statements;
}
/**
* Transforms the body of an enum declaration.
*
* @param node The enum declaration node.
*/
function transformEnumBody(node: EnumDeclaration, localName: Identifier): Block {
const savedCurrentNamespaceLocalName = currentNamespaceLocalName;
currentNamespaceLocalName = localName;
const statements: Statement[] = [];
startLexicalEnvironment();
addNodes(statements, map(node.members, transformEnumMember));
addNodes(statements, endLexicalEnvironment());
currentNamespaceLocalName = savedCurrentNamespaceLocalName;
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
}
/**
* Transforms an enum member into a statement.
*
* @param member The enum member node.
*/
function transformEnumMember(member: EnumMember): Statement {
const name = getExpressionForPropertyName(member);
return createStatement(
createAssignment(
createElementAccess(
currentNamespaceLocalName,
createAssignment(
createElementAccess(
currentNamespaceLocalName,
name
),
transformEnumMemberDeclarationValue(member)
)
),
name
),
member
);
}
/**
* Transforms the value of an enum member.
*
* @param member The enum member node.
*/
function transformEnumMemberDeclarationValue(member: EnumMember): Expression {
const value = resolver.getConstantValue(member);
if (value !== undefined) {
return createLiteral(value);
}
else if (member.initializer) {
return visitNode(member.initializer, visitor, isExpression);
}
else {
return createVoidZero();
}
}
/**
* Determines whether to elide a module declaration.
*
@ -2337,20 +2366,9 @@ namespace ts {
return isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.isolatedModules);
}
/**
* Determines whether a module declaration has a name that merges with a class declaration.
*
* @param node The module declaration node.
*/
function isModuleMergedWithClass(node: ModuleDeclaration) {
function isModuleMergedWithES6Class(node: ModuleDeclaration) {
return languageVersion === ScriptTarget.ES6
&& !!(resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.LexicalModuleMergesWithClass);
}
function shouldEmitVarForModuleDeclaration(node: ModuleDeclaration) {
return !isModuleMergedWithClass(node)
&& (!isExternalModuleExport(node)
|| isFirstDeclarationOfKind(node, SyntaxKind.ModuleDeclaration));
&& isMergedWithClass(node);
}
/**
@ -2365,41 +2383,29 @@ namespace ts {
return undefined;
}
Debug.assert(isIdentifier(node.name));
Debug.assert(isIdentifier(node.name), "TypeScript module should have an Identifier name.");
enableExpressionSubstitutionForNamespaceExports();
const savedCurrentNamespaceLocalName = currentNamespaceLocalName;
const savedCurrentNamespace = currentNamespace;
const statements: Statement[] = [];
if (shouldEmitVarForModuleDeclaration(node)) {
// var x;
statements.push(
createVariableStatement(
visitNodes(node.modifiers, visitor, isModifier),
createVariableDeclarationList([
createVariableDeclaration(<Identifier>node.name)
]),
/*location*/ node
)
);
if (!isModuleMergedWithES6Class(node) && (isNamespaceExport(node) || shouldEmitVarForEnumOrModuleDeclaration(node))) {
addVarForEnumOrModuleDeclaration(statements, node);
}
const name = isNamespaceExport(node)
? getNamespaceMemberName(node.name)
: getSynthesizedClone(node.name);
const localName = getGeneratedNameForNode(node);
const name = getDeclarationNameExpression(node);
currentNamespaceLocalName = getGeneratedNameForNode(node);
currentNamespace = node;
const moduleParam = createLogicalOr(
name,
createAssignment(
let moduleArg =
createLogicalOr(
name,
createObjectLiteral()
)
);
createAssignment(
name,
createObjectLiteral()
)
);
if (isNamespaceExport(node)) {
moduleArg = createAssignment(getDeclarationName(node), moduleArg);
}
// (function (x_1) {
// x_1.y = ...;
@ -2409,30 +2415,22 @@ namespace ts {
setOriginalNode(
createStatement(
createCall(
createParen(
createFunctionExpression(
/*asteriskToken*/ undefined,
/*name*/ undefined,
[createParameter(currentNamespaceLocalName)],
transformModuleBody(node)
)
createFunctionExpression(
/*asteriskToken*/ undefined,
/*name*/ undefined,
[createParameter(localName)],
transformModuleBody(node, localName)
),
[
isNamespaceExport(node)
? createAssignment(getSynthesizedClone(<Identifier>node.name), moduleParam)
: moduleParam
]
[moduleArg]
),
/*location*/ node
),
node
/*original*/ node
),
NodeEmitFlags.AdviseOnEmitNode
)
);
currentNamespaceLocalName = savedCurrentNamespaceLocalName;
currentNamespace = savedCurrentNamespace;
return statements;
}
@ -2441,7 +2439,12 @@ namespace ts {
*
* @param node The module declaration node.
*/
function transformModuleBody(node: ModuleDeclaration): Block {
function transformModuleBody(node: ModuleDeclaration, namespaceLocalName: Identifier): Block {
const savedCurrentNamespaceLocalName = currentNamespaceLocalName;
const savedCurrentNamespace = currentNamespace;
currentNamespaceLocalName = namespaceLocalName;
currentNamespace = node;
const statements: Statement[] = [];
startLexicalEnvironment();
const body = node.body;
@ -2453,9 +2456,26 @@ namespace ts {
}
addNodes(statements, endLexicalEnvironment());
currentNamespaceLocalName = savedCurrentNamespaceLocalName;
currentNamespace = savedCurrentNamespace;
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
}
/**
* Determines whether to emit an import equals declaration.
*
* @param node The import equals declaration node.
*/
function shouldEmitImportEqualsDeclaration(node: ImportEqualsDeclaration) {
// preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
// - current file is not external module
// - import declaration is top level and target is value imported by entity name
return resolver.isReferencedAliasDeclaration(node)
|| (!isExternalModule(currentSourceFile)
&& resolver.isTopLevelValueImportEqualsWithEntityName(node));
}
/**
* Visits an import equals declaration.
*
@ -2466,7 +2486,7 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
if (shouldElideImportEqualsDeclaration(node)) {
if (!shouldEmitImportEqualsDeclaration(node)) {
return undefined;
}
@ -2498,35 +2518,13 @@ namespace ts {
}
}
/**
* Determines whether to elide an import equals declaration.
*
* @param node The import equals declaration node.
*/
function shouldElideImportEqualsDeclaration(node: ImportEqualsDeclaration) {
// preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
// - current file is not external module
// - import declaration is top level and target is value imported by entity name
return !resolver.isReferencedAliasDeclaration(node)
&& (isExternalModule(currentSourceFile) || !resolver.isTopLevelValueImportEqualsWithEntityName(node));
}
/**
* Gets a value indicating whether the node is exported.
*
* @param node The node to test.
*/
function isExported(node: Node) {
return hasModifier(node, ModifierFlags.Export);
}
/**
* Gets a value indicating whether the node is exported from a namespace.
*
* @param node The node to test.
*/
function isNamespaceExport(node: Node) {
return currentNamespace !== undefined && isExported(node);
return currentNamespace !== undefined && hasModifier(node, ModifierFlags.Export);
}
/**
@ -2535,7 +2533,7 @@ namespace ts {
* @param node The node to test.
*/
function isExternalModuleExport(node: Node) {
return currentNamespace === undefined && isExported(node);
return currentNamespace === undefined && hasModifier(node, ModifierFlags.Export);
}
/**
@ -2557,16 +2555,6 @@ namespace ts {
return isExternalModuleExport(node)
&& hasModifier(node, ModifierFlags.Default);
}
/**
* Gets a value indicating whether a node is the first declaration of its kind.
*
* @param node A Declaration node.
* @param kind The SyntaxKind to find among related declarations.
*/
function isFirstDeclarationOfKind(node: Declaration, kind: SyntaxKind) {
const original = getOriginalNode(node);
return original.symbol && getDeclarationOfKind(original.symbol, kind) === original;
}
/**
* Creates a statement for the provided expression. This is used in calls to `map`.
@ -2575,8 +2563,8 @@ namespace ts {
return createStatement(expression, /*location*/ undefined);
}
function addNamespaceExport(statements: Statement[], exportName: Identifier, exportValue: Expression, location?: TextRange) {
statements.push(createNamespaceExport(exportName, exportValue, location));
function addExportMemberAssignment(statements: Statement[], node: DeclarationStatement) {
statements.push(createNamespaceExport(getDeclarationName(node), getDeclarationName(node)));
}
function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) {
@ -2601,10 +2589,23 @@ namespace ts {
return createPropertyAccess(currentNamespaceLocalName, getSynthesizedClone(name));
}
function getDeclarationName(node: ClassExpression | ClassDeclaration | FunctionDeclaration | EnumDeclaration) {
function getDeclarationName(node: DeclarationStatement | ClassExpression) {
return node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node);
}
function getDeclarationNameExpression(node: DeclarationStatement) {
const name = getDeclarationName(node);
if (isNamespaceExport(node)) {
return getNamespaceMemberName(name);
}
else {
// We set the "PrefixExportedLocal" flag to indicate to any module transformer
// downstream that any `exports.` prefix should be added.
setNodeEmitFlags(name, getNodeEmitFlags(name) | NodeEmitFlags.PrefixExportedLocal);
return name;
}
}
function getClassPrototype(node: ClassExpression | ClassDeclaration) {
return createPropertyAccess(getDeclarationName(node), "prototype");
}

View File

@ -1924,7 +1924,7 @@ namespace ts {
/* @internal */
export interface EmitResolver {
hasGlobalName(name: string): boolean;
getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration;
getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration;
getReferencedImportDeclaration(node: Identifier): Declaration;
getReferencedDeclarationWithCollidingName(node: Identifier): Declaration;
isDeclarationWithCollidingName(node: Declaration): boolean;
@ -2856,6 +2856,7 @@ namespace ts {
CapturesThis = 1 << 11, // The function captures a lexical `this`
NoSourceMap = 1 << 12, // Do not emit a source map location for this node.
NoNestedSourceMaps = 1 << 13, // Do not emit source map locations for children of this node.
PrefixExportedLocal = 1 << 14,
}
/** Additional context provided to `visitEachChild` */

View File

@ -3034,6 +3034,31 @@ namespace ts {
return node.initializer !== undefined;
}
/**
* Gets a value indicating whether a node is merged with a class declaration in the same scope.
*/
export function isMergedWithClass(node: Node) {
if (node.symbol) {
for (const declaration of node.symbol.declarations) {
if (declaration.kind === SyntaxKind.ClassDeclaration && declaration !== node) {
return true;
}
}
}
return false;
}
/**
* Gets a value indicating whether a node is the first declaration of its kind.
*
* @param node A Declaration node.
* @param kind The SyntaxKind to find among related declarations.
*/
export function isFirstDeclarationOfKind(node: Node, kind: SyntaxKind) {
return node.symbol && getDeclarationOfKind(node.symbol, kind) === node;
}
// Node tests
//
// All node tests in the following list should *not* reference parent pointers so that

View File

@ -21,7 +21,7 @@ System.register([], function (exports_1, context_1) {
// filename: instantiatedModule.ts
(function (M) {
var x = 1;
})(M = M || (M = {}));
})(M || (M = {}));
exports_1("M", M);
}
};

View File

@ -30,7 +30,7 @@ System.register([], function (exports_1, context_1) {
exports_1("TopLevelClass", TopLevelClass);
(function (TopLevelModule) {
var v;
})(TopLevelModule = TopLevelModule || (TopLevelModule = {}));
})(TopLevelModule || (TopLevelModule = {}));
exports_1("TopLevelModule", TopLevelModule);
(function (TopLevelEnum) {
TopLevelEnum[TopLevelEnum["E"] = 0] = "E";
@ -53,7 +53,7 @@ System.register([], function (exports_1, context_1) {
NonTopLevelEnum[NonTopLevelEnum["E"] = 0] = "E";
})(TopLevelModule2.NonTopLevelEnum || (TopLevelModule2.NonTopLevelEnum = {}));
var NonTopLevelEnum = TopLevelModule2.NonTopLevelEnum;
})(TopLevelModule2 = TopLevelModule2 || (TopLevelModule2 = {}));
})(TopLevelModule2 || (TopLevelModule2 = {}));
exports_1("TopLevelModule2", TopLevelModule2);
}
};