Fixed linter warnings, added comments and minor cleanup.
This commit is contained in:
parent
951ce55ded
commit
08036b7ef6
2 changed files with 186 additions and 100 deletions
|
@ -197,7 +197,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBinaryExpression(root)) {
|
if (isBinaryExpression(root)) {
|
||||||
emitDestructuringAssignment(root.left, value, location)
|
emitDestructuringAssignment(root.left, value, location);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emitBindingElement(root, value);
|
emitBindingElement(root, value);
|
||||||
|
|
|
@ -8,7 +8,6 @@ namespace ts {
|
||||||
|
|
||||||
export function transformTypeScript(context: TransformationContext) {
|
export function transformTypeScript(context: TransformationContext) {
|
||||||
const {
|
const {
|
||||||
nodeHasGeneratedName,
|
|
||||||
getGeneratedNameForNode,
|
getGeneratedNameForNode,
|
||||||
makeUniqueName,
|
makeUniqueName,
|
||||||
setNodeEmitFlags,
|
setNodeEmitFlags,
|
||||||
|
@ -20,23 +19,46 @@ namespace ts {
|
||||||
const resolver = context.getEmitResolver();
|
const resolver = context.getEmitResolver();
|
||||||
const compilerOptions = context.getCompilerOptions();
|
const compilerOptions = context.getCompilerOptions();
|
||||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||||
const decoratedClassAliases: Map<Identifier> = {};
|
|
||||||
const currentDecoratedClassAliases: Map<Identifier> = {};
|
// Save the previous transformation hooks.
|
||||||
const previousExpressionSubstitution = context.expressionSubstitution;
|
const previousExpressionSubstitution = context.expressionSubstitution;
|
||||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||||
context.enableExpressionSubstitution(SyntaxKind.Identifier);
|
|
||||||
|
// Set new transformation hooks.
|
||||||
context.expressionSubstitution = substituteExpression;
|
context.expressionSubstitution = substituteExpression;
|
||||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||||
context.onAfterEmitNode = onAfterEmitNode;
|
context.onAfterEmitNode = onAfterEmitNode;
|
||||||
|
|
||||||
let hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = false;
|
// These variables contain state that changes as we descend into the tree.
|
||||||
let currentSourceFile: SourceFile;
|
let currentSourceFile: SourceFile;
|
||||||
let currentNamespace: ModuleDeclaration;
|
let currentNamespace: ModuleDeclaration;
|
||||||
let currentNamespaceLocalName: Identifier;
|
let currentNamespaceLocalName: Identifier;
|
||||||
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
|
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
|
||||||
let currentParent: Node;
|
let currentParent: Node;
|
||||||
let currentNode: Node;
|
let currentNode: Node;
|
||||||
|
|
||||||
|
// These variables keep track of whether expression substitution has been enabled for
|
||||||
|
// specific edge cases. They are persisted between each SourceFile transformation and
|
||||||
|
// should not be reset.
|
||||||
|
let hasEnabledExpressionSubstitutionForDecoratedClasses = false;
|
||||||
|
let hasEnabledExpressionSubstitutionForNamespaceExports = false;
|
||||||
|
let hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = false;
|
||||||
|
|
||||||
|
// This map keeps track of aliases created for classes with decorators to avoid issues
|
||||||
|
// with the double-binding behavior of classes.
|
||||||
|
let decoratedClassAliases: Map<Identifier>;
|
||||||
|
|
||||||
|
// This map keeps track of currently active aliases defined in `decoratedClassAliases`
|
||||||
|
// when just-in-time substitution occurs while printing an expression identifier.
|
||||||
|
let currentDecoratedClassAliases: Map<Identifier>;
|
||||||
|
|
||||||
|
// This value keeps track of how deeply nested we are within any containing namespaces
|
||||||
|
// when performing just-in-time substitution while printing an expression identifier.
|
||||||
|
let namespaceNestLevel: number;
|
||||||
|
|
||||||
|
// This array keeps track of containers where `super` is valid, for use with
|
||||||
|
// just-in-time substitution for `super` expressions inside of async methods.
|
||||||
let superContainerStack: SuperContainer[];
|
let superContainerStack: SuperContainer[];
|
||||||
|
|
||||||
return transformSourceFile;
|
return transformSourceFile;
|
||||||
|
@ -54,16 +76,23 @@ namespace ts {
|
||||||
* @param node The node to visit.
|
* @param node The node to visit.
|
||||||
*/
|
*/
|
||||||
function visitWithStack(node: Node, visitor: (node: Node) => Node): Node {
|
function visitWithStack(node: Node, visitor: (node: Node) => Node): Node {
|
||||||
|
// Save state
|
||||||
const savedCurrentNamespace = currentNamespace;
|
const savedCurrentNamespace = currentNamespace;
|
||||||
const savedCurrentScope = currentScope;
|
const savedCurrentScope = currentScope;
|
||||||
const savedCurrentParent = currentParent;
|
const savedCurrentParent = currentParent;
|
||||||
const savedCurrentNode = currentNode;
|
const savedCurrentNode = currentNode;
|
||||||
|
|
||||||
|
// Handle state changes before visiting a node.
|
||||||
onBeforeVisitNode(node);
|
onBeforeVisitNode(node);
|
||||||
|
|
||||||
node = visitor(node);
|
node = visitor(node);
|
||||||
|
|
||||||
|
// Restore state
|
||||||
currentNamespace = savedCurrentNamespace;
|
currentNamespace = savedCurrentNamespace;
|
||||||
currentScope = savedCurrentScope;
|
currentScope = savedCurrentScope;
|
||||||
currentParent = savedCurrentParent;
|
currentParent = savedCurrentParent;
|
||||||
currentNode = savedCurrentNode;
|
currentNode = savedCurrentNode;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +175,11 @@ namespace ts {
|
||||||
return visitorWorker(node);
|
return visitorWorker(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Branching visitor, visits a TypeScript syntax node.
|
||||||
|
*
|
||||||
|
* @param node The node to visit.
|
||||||
|
*/
|
||||||
function visitTypeScript(node: Node): Node {
|
function visitTypeScript(node: Node): Node {
|
||||||
// TypeScript ambient declarations are elided.
|
// TypeScript ambient declarations are elided.
|
||||||
if (node.flags & NodeFlags.Ambient) {
|
if (node.flags & NodeFlags.Ambient) {
|
||||||
|
@ -461,11 +495,13 @@ namespace ts {
|
||||||
|
|
||||||
// Record an alias to avoid class double-binding.
|
// Record an alias to avoid class double-binding.
|
||||||
if (resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
|
if (resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
|
||||||
|
enableExpressionSubstitutionForDecoratedClasses();
|
||||||
decoratedClassAlias = makeUniqueName(node.name ? node.name.text : "default");
|
decoratedClassAlias = makeUniqueName(node.name ? node.name.text : "default");
|
||||||
decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias;
|
decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias;
|
||||||
|
|
||||||
// We emit the class alias as a `let` declaration here so that it has the same
|
// We emit the class alias as a `let` declaration here so that it has the same
|
||||||
// TDZ as the class.
|
// TDZ as the class.
|
||||||
|
|
||||||
// let ${decoratedClassAlias};
|
// let ${decoratedClassAlias};
|
||||||
addNode(statements,
|
addNode(statements,
|
||||||
createVariableStatement(
|
createVariableStatement(
|
||||||
|
@ -528,7 +564,7 @@ namespace ts {
|
||||||
// Write any decorators of the node.
|
// Write any decorators of the node.
|
||||||
addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ false));
|
addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ false));
|
||||||
addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ true));
|
addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ true));
|
||||||
addNode(statements, generateConstructorDecorationStatement(node, decoratedClassAlias))
|
addNode(statements, generateConstructorDecorationStatement(node, decoratedClassAlias));
|
||||||
|
|
||||||
// If the class is exported as part of a TypeScript namespace, emit the namespace export.
|
// If the class is exported as part of a TypeScript namespace, emit the namespace export.
|
||||||
// Otherwise, if the class was exported at the top level and was decorated, emit an export
|
// Otherwise, if the class was exported at the top level and was decorated, emit an export
|
||||||
|
@ -1060,7 +1096,7 @@ namespace ts {
|
||||||
* Transforms all of the decorators for a declaration into an array of expressions.
|
* Transforms all of the decorators for a declaration into an array of expressions.
|
||||||
*
|
*
|
||||||
* @param node The declaration node.
|
* @param node The declaration node.
|
||||||
* @param allDecorators The AllDecorators object for the node.
|
* @param allDecorators An object containing all of the decorators for the declaration.
|
||||||
*/
|
*/
|
||||||
function transformAllDecoratorsOfDeclaration(node: Declaration, allDecorators: AllDecorators) {
|
function transformAllDecoratorsOfDeclaration(node: Declaration, allDecorators: AllDecorators) {
|
||||||
if (!allDecorators) {
|
if (!allDecorators) {
|
||||||
|
@ -1257,13 +1293,13 @@ namespace ts {
|
||||||
*/
|
*/
|
||||||
function addTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
|
function addTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
|
||||||
if (compilerOptions.emitDecoratorMetadata) {
|
if (compilerOptions.emitDecoratorMetadata) {
|
||||||
if (shouldAppendTypeMetadata(node)) {
|
if (shouldAddTypeMetadata(node)) {
|
||||||
decoratorExpressions.push(createMetadataHelper("design:type", serializeTypeOfNode(node), /*defer*/ true));
|
decoratorExpressions.push(createMetadataHelper("design:type", serializeTypeOfNode(node), /*defer*/ true));
|
||||||
}
|
}
|
||||||
if (shouldAppendParamTypesMetadata(node)) {
|
if (shouldAddParamTypesMetadata(node)) {
|
||||||
decoratorExpressions.push(createMetadataHelper("design:paramtypes", serializeParameterTypesOfNode(node), /*defer*/ true));
|
decoratorExpressions.push(createMetadataHelper("design:paramtypes", serializeParameterTypesOfNode(node), /*defer*/ true));
|
||||||
}
|
}
|
||||||
if (shouldAppendReturnTypeMetadata(node)) {
|
if (shouldAddReturnTypeMetadata(node)) {
|
||||||
decoratorExpressions.push(createMetadataHelper("design:returntype", serializeReturnTypeOfNode(node), /*defer*/ true));
|
decoratorExpressions.push(createMetadataHelper("design:returntype", serializeReturnTypeOfNode(node), /*defer*/ true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1271,12 +1307,12 @@ namespace ts {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether to emit the "design:type" metadata based on the node's kind.
|
* Determines whether to emit the "design:type" metadata based on the node's kind.
|
||||||
* The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
* The caller should have already tested whether the node has decorators and whether the
|
||||||
* compiler option is set.
|
* emitDecoratorMetadata compiler option is set.
|
||||||
*
|
*
|
||||||
* @param node The node to test.
|
* @param node The node to test.
|
||||||
*/
|
*/
|
||||||
function shouldAppendTypeMetadata(node: Declaration): boolean {
|
function shouldAddTypeMetadata(node: Declaration): boolean {
|
||||||
const kind = node.kind;
|
const kind = node.kind;
|
||||||
return kind === SyntaxKind.MethodDeclaration
|
return kind === SyntaxKind.MethodDeclaration
|
||||||
|| kind === SyntaxKind.GetAccessor
|
|| kind === SyntaxKind.GetAccessor
|
||||||
|
@ -1286,23 +1322,23 @@ namespace ts {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether to emit the "design:returntype" metadata based on the node's kind.
|
* Determines whether to emit the "design:returntype" metadata based on the node's kind.
|
||||||
* The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
* The caller should have already tested whether the node has decorators and whether the
|
||||||
* compiler option is set.
|
* emitDecoratorMetadata compiler option is set.
|
||||||
*
|
*
|
||||||
* @param node The node to test.
|
* @param node The node to test.
|
||||||
*/
|
*/
|
||||||
function shouldAppendReturnTypeMetadata(node: Declaration): boolean {
|
function shouldAddReturnTypeMetadata(node: Declaration): boolean {
|
||||||
return node.kind === SyntaxKind.MethodDeclaration;
|
return node.kind === SyntaxKind.MethodDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether to emit the "design:paramtypes" metadata based on the node's kind.
|
* Determines whether to emit the "design:paramtypes" metadata based on the node's kind.
|
||||||
* The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
* The caller should have already tested whether the node has decorators and whether the
|
||||||
* compiler option is set.
|
* emitDecoratorMetadata compiler option is set.
|
||||||
*
|
*
|
||||||
* @param node The node to test.
|
* @param node The node to test.
|
||||||
*/
|
*/
|
||||||
function shouldAppendParamTypesMetadata(node: Declaration): boolean {
|
function shouldAddParamTypesMetadata(node: Declaration): boolean {
|
||||||
const kind = node.kind;
|
const kind = node.kind;
|
||||||
return kind === SyntaxKind.ClassDeclaration
|
return kind === SyntaxKind.ClassDeclaration
|
||||||
|| kind === SyntaxKind.ClassExpression
|
|| kind === SyntaxKind.ClassExpression
|
||||||
|
@ -1432,7 +1468,7 @@ namespace ts {
|
||||||
|
|
||||||
case SyntaxKind.TypePredicate:
|
case SyntaxKind.TypePredicate:
|
||||||
case SyntaxKind.BooleanKeyword:
|
case SyntaxKind.BooleanKeyword:
|
||||||
return createIdentifier("Boolean")
|
return createIdentifier("Boolean");
|
||||||
|
|
||||||
case SyntaxKind.StringKeyword:
|
case SyntaxKind.StringKeyword:
|
||||||
case SyntaxKind.StringLiteral:
|
case SyntaxKind.StringLiteral:
|
||||||
|
@ -1558,7 +1594,7 @@ namespace ts {
|
||||||
* qualified name at runtime.
|
* qualified name at runtime.
|
||||||
*/
|
*/
|
||||||
function serializeQualifiedNameAsExpression(node: QualifiedName, useFallback: boolean): Expression {
|
function serializeQualifiedNameAsExpression(node: QualifiedName, useFallback: boolean): Expression {
|
||||||
let left: Expression
|
let left: Expression;
|
||||||
if (node.left.kind === SyntaxKind.Identifier) {
|
if (node.left.kind === SyntaxKind.Identifier) {
|
||||||
left = serializeEntityNameAsExpression(node.left, useFallback);
|
left = serializeEntityNameAsExpression(node.left, useFallback);
|
||||||
}
|
}
|
||||||
|
@ -1990,25 +2026,6 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableExpressionSubstitutionForAsyncMethodsWithSuper() {
|
|
||||||
if (!hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper) {
|
|
||||||
hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = true;
|
|
||||||
|
|
||||||
// We need to enable substitutions for call, property access, and element access
|
|
||||||
// if we need to rewrite super calls.
|
|
||||||
context.enableExpressionSubstitution(SyntaxKind.CallExpression);
|
|
||||||
context.enableExpressionSubstitution(SyntaxKind.PropertyAccessExpression);
|
|
||||||
context.enableExpressionSubstitution(SyntaxKind.ElementAccessExpression);
|
|
||||||
|
|
||||||
// We need to be notified when entering and exiting declarations that bind super.
|
|
||||||
context.enableEmitNotification(SyntaxKind.ClassDeclaration);
|
|
||||||
context.enableEmitNotification(SyntaxKind.MethodDeclaration);
|
|
||||||
context.enableEmitNotification(SyntaxKind.GetAccessor);
|
|
||||||
context.enableEmitNotification(SyntaxKind.SetAccessor);
|
|
||||||
context.enableEmitNotification(SyntaxKind.Constructor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visits a parameter declaration node.
|
* Visits a parameter declaration node.
|
||||||
*
|
*
|
||||||
|
@ -2188,7 +2205,7 @@ namespace ts {
|
||||||
* @param member The enum member node.
|
* @param member The enum member node.
|
||||||
*/
|
*/
|
||||||
function transformEnumMemberDeclarationValue(member: EnumMember): Expression {
|
function transformEnumMemberDeclarationValue(member: EnumMember): Expression {
|
||||||
let value = resolver.getConstantValue(member);
|
const value = resolver.getConstantValue(member);
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
return createLiteral(value);
|
return createLiteral(value);
|
||||||
}
|
}
|
||||||
|
@ -2274,6 +2291,8 @@ namespace ts {
|
||||||
|
|
||||||
Debug.assert(isIdentifier(node.name));
|
Debug.assert(isIdentifier(node.name));
|
||||||
|
|
||||||
|
enableExpressionSubstitutionForNamespaceExports();
|
||||||
|
|
||||||
const savedCurrentNamespaceLocalName = currentNamespaceLocalName;
|
const savedCurrentNamespaceLocalName = currentNamespaceLocalName;
|
||||||
const modifiers = visitNodes(node.modifiers, visitor, isModifier);
|
const modifiers = visitNodes(node.modifiers, visitor, isModifier);
|
||||||
const statements: Statement[] = [];
|
const statements: Statement[] = [];
|
||||||
|
@ -2471,19 +2490,6 @@ namespace ts {
|
||||||
return createStatement(expression, /*location*/ undefined);
|
return createStatement(expression, /*location*/ undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createExportStatement(node: ClassExpression | ClassDeclaration | FunctionDeclaration): Statement {
|
|
||||||
const name = getDeclarationName(node);
|
|
||||||
if (currentNamespace) {
|
|
||||||
return createNamespaceExport(name, name);
|
|
||||||
}
|
|
||||||
else if (node.flags & NodeFlags.Default) {
|
|
||||||
return createExportDefault(name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return createModuleExport(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) {
|
function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) {
|
||||||
return createStatement(
|
return createStatement(
|
||||||
createAssignment(
|
createAssignment(
|
||||||
|
@ -2506,7 +2512,7 @@ namespace ts {
|
||||||
name = getSynthesizedNode(name);
|
name = getSynthesizedNode(name);
|
||||||
return currentNamespaceLocalName
|
return currentNamespaceLocalName
|
||||||
? createPropertyAccess(currentNamespaceLocalName, name)
|
? createPropertyAccess(currentNamespaceLocalName, name)
|
||||||
: name
|
: name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeclarationName(node: ClassExpression | ClassDeclaration | FunctionDeclaration) {
|
function getDeclarationName(node: ClassExpression | ClassDeclaration | FunctionDeclaration) {
|
||||||
|
@ -2523,8 +2529,65 @@ namespace ts {
|
||||||
: getClassPrototype(node);
|
: getClassPrototype(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onBeforeEmitNode(node: Node): void {
|
||||||
|
previousOnBeforeEmitNode(node);
|
||||||
|
|
||||||
|
const kind = node.kind;
|
||||||
|
if (hasEnabledExpressionSubstitutionForDecoratedClasses
|
||||||
|
&& kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
||||||
|
currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
||||||
|
&& (kind === SyntaxKind.ClassDeclaration
|
||||||
|
|| kind === SyntaxKind.Constructor
|
||||||
|
|| kind === SyntaxKind.MethodDeclaration
|
||||||
|
|| kind === SyntaxKind.GetAccessor
|
||||||
|
|| kind === SyntaxKind.SetAccessor)) {
|
||||||
|
|
||||||
|
if (!superContainerStack) {
|
||||||
|
superContainerStack = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
superContainerStack.push(<SuperContainer>node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasEnabledExpressionSubstitutionForNamespaceExports
|
||||||
|
&& kind === SyntaxKind.ModuleDeclaration) {
|
||||||
|
namespaceNestLevel++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAfterEmitNode(node: Node): void {
|
||||||
|
previousOnAfterEmitNode(node);
|
||||||
|
|
||||||
|
const kind = node.kind;
|
||||||
|
if (hasEnabledExpressionSubstitutionForDecoratedClasses
|
||||||
|
&& kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
||||||
|
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
||||||
|
&& (kind === SyntaxKind.ClassDeclaration
|
||||||
|
|| kind === SyntaxKind.Constructor
|
||||||
|
|| kind === SyntaxKind.MethodDeclaration
|
||||||
|
|| kind === SyntaxKind.GetAccessor
|
||||||
|
|| kind === SyntaxKind.SetAccessor)) {
|
||||||
|
|
||||||
|
if (superContainerStack) {
|
||||||
|
superContainerStack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasEnabledExpressionSubstitutionForNamespaceExports
|
||||||
|
&& kind === SyntaxKind.ModuleDeclaration) {
|
||||||
|
namespaceNestLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function substituteExpression(node: Expression): Expression {
|
function substituteExpression(node: Expression): Expression {
|
||||||
node = previousExpressionSubstitution ? previousExpressionSubstitution(node) : node;
|
node = previousExpressionSubstitution(node);
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
case SyntaxKind.Identifier:
|
case SyntaxKind.Identifier:
|
||||||
return substituteExpressionIdentifier(<Identifier>node);
|
return substituteExpressionIdentifier(<Identifier>node);
|
||||||
|
@ -2544,8 +2607,10 @@ namespace ts {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
function substituteExpressionIdentifier(node: Identifier) {
|
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||||
if (!nodeIsSynthesized(node) && resolver.getNodeCheckFlags(node) & NodeCheckFlags.BodyScopedClassBinding) {
|
if (hasEnabledExpressionSubstitutionForDecoratedClasses
|
||||||
|
&& !nodeIsSynthesized(node)
|
||||||
|
&& resolver.getNodeCheckFlags(node) & NodeCheckFlags.BodyScopedClassBinding) {
|
||||||
// Due to the emit for class decorators, any reference to the class from inside of the class body
|
// Due to the emit for class decorators, any reference to the class from inside of the class body
|
||||||
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
|
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
|
||||||
// behavior of class names in ES6.
|
// behavior of class names in ES6.
|
||||||
|
@ -2559,10 +2624,23 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasEnabledExpressionSubstitutionForNamespaceExports
|
||||||
|
&& namespaceNestLevel > 0) {
|
||||||
|
// If we are nested within a namespace declaration, we may need to qualifiy
|
||||||
|
// an identifier that is exported from a merged namespace.
|
||||||
|
const original = getOriginalNode(node);
|
||||||
|
if (isIdentifier(original) && original.parent) {
|
||||||
|
const container = resolver.getReferencedExportContainer(original);
|
||||||
|
if (container && container.kind === SyntaxKind.ModuleDeclaration) {
|
||||||
|
return createPropertyAccess(getGeneratedNameForNode(container), node, /*location*/ node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
function substituteCallExpression(node: CallExpression) {
|
function substituteCallExpression(node: CallExpression): Expression {
|
||||||
const expression = node.expression;
|
const expression = node.expression;
|
||||||
if (isSuperPropertyOrElementAccess(expression)) {
|
if (isSuperPropertyOrElementAccess(expression)) {
|
||||||
const flags = getSuperContainerAsyncMethodFlags();
|
const flags = getSuperContainerAsyncMethodFlags();
|
||||||
|
@ -2612,6 +2690,54 @@ namespace ts {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enableExpressionSubstitutionForAsyncMethodsWithSuper() {
|
||||||
|
if (!hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper) {
|
||||||
|
hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = true;
|
||||||
|
|
||||||
|
// We need to enable substitutions for call, property access, and element access
|
||||||
|
// if we need to rewrite super calls.
|
||||||
|
context.enableExpressionSubstitution(SyntaxKind.CallExpression);
|
||||||
|
context.enableExpressionSubstitution(SyntaxKind.PropertyAccessExpression);
|
||||||
|
context.enableExpressionSubstitution(SyntaxKind.ElementAccessExpression);
|
||||||
|
|
||||||
|
// We need to be notified when entering and exiting declarations that bind super.
|
||||||
|
context.enableEmitNotification(SyntaxKind.ClassDeclaration);
|
||||||
|
context.enableEmitNotification(SyntaxKind.MethodDeclaration);
|
||||||
|
context.enableEmitNotification(SyntaxKind.GetAccessor);
|
||||||
|
context.enableEmitNotification(SyntaxKind.SetAccessor);
|
||||||
|
context.enableEmitNotification(SyntaxKind.Constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableExpressionSubstitutionForDecoratedClasses() {
|
||||||
|
if (!hasEnabledExpressionSubstitutionForDecoratedClasses) {
|
||||||
|
hasEnabledExpressionSubstitutionForDecoratedClasses = true;
|
||||||
|
|
||||||
|
// We need to enable substitutions for identifiers. This allows us to
|
||||||
|
// substitute class names inside of a class declaration.
|
||||||
|
context.enableExpressionSubstitution(SyntaxKind.Identifier);
|
||||||
|
|
||||||
|
// Keep track of class aliases.
|
||||||
|
decoratedClassAliases = {};
|
||||||
|
currentDecoratedClassAliases = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableExpressionSubstitutionForNamespaceExports() {
|
||||||
|
if (!hasEnabledExpressionSubstitutionForNamespaceExports) {
|
||||||
|
hasEnabledExpressionSubstitutionForNamespaceExports = true;
|
||||||
|
|
||||||
|
// We need to enable substitutions for identifiers. This allows us to
|
||||||
|
// substitute the names of exported members of a namespace.
|
||||||
|
context.enableExpressionSubstitution(SyntaxKind.Identifier);
|
||||||
|
|
||||||
|
// We need to be notified when entering and exiting namespaces.
|
||||||
|
context.enableEmitNotification(SyntaxKind.ModuleDeclaration);
|
||||||
|
|
||||||
|
// Keep track of namespace nesting depth
|
||||||
|
namespaceNestLevel = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createSuperAccessInAsyncMethod(argumentExpression: Expression, flags: NodeCheckFlags, location: TextRange): LeftHandSideExpression {
|
function createSuperAccessInAsyncMethod(argumentExpression: Expression, flags: NodeCheckFlags, location: TextRange): LeftHandSideExpression {
|
||||||
if (flags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
|
if (flags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
|
||||||
|
@ -2638,45 +2764,5 @@ namespace ts {
|
||||||
return container !== undefined
|
return container !== undefined
|
||||||
&& resolver.getNodeCheckFlags(getOriginalNode(container)) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
|
&& resolver.getNodeCheckFlags(getOriginalNode(container)) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBeforeEmitNode(node: Node): void {
|
|
||||||
const kind = node.kind;
|
|
||||||
if (kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
|
||||||
currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
|
||||||
&& (kind === SyntaxKind.ClassDeclaration
|
|
||||||
|| kind === SyntaxKind.Constructor
|
|
||||||
|| kind === SyntaxKind.MethodDeclaration
|
|
||||||
|| kind === SyntaxKind.GetAccessor
|
|
||||||
|| kind === SyntaxKind.SetAccessor)) {
|
|
||||||
|
|
||||||
if (!superContainerStack) {
|
|
||||||
superContainerStack = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
superContainerStack.push(<SuperContainer>node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAfterEmitNode(node: Node): void {
|
|
||||||
const kind = node.kind;
|
|
||||||
if (kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
|
||||||
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
|
||||||
&& (kind === SyntaxKind.ClassDeclaration
|
|
||||||
|| kind === SyntaxKind.Constructor
|
|
||||||
|| kind === SyntaxKind.MethodDeclaration
|
|
||||||
|| kind === SyntaxKind.GetAccessor
|
|
||||||
|| kind === SyntaxKind.SetAccessor)) {
|
|
||||||
|
|
||||||
if (superContainerStack) {
|
|
||||||
superContainerStack.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue