PR Feedback

This commit is contained in:
Ron Buckton 2016-02-29 17:35:50 -08:00
parent fe7ad5fde3
commit a0dbe7601c
6 changed files with 269 additions and 212 deletions

View file

@ -4846,7 +4846,7 @@ namespace ts {
const parent = container && container.parent;
if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) {
if (!(container.flags & NodeFlags.Static) &&
(container.kind !== SyntaxKind.Constructor || isNodeDescendentOf(node, (<ConstructorDeclaration>container).body))) {
(container.kind !== SyntaxKind.Constructor || isNodeDescendantOf(node, (<ConstructorDeclaration>container).body))) {
return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent)).thisType;
}
}
@ -7206,8 +7206,8 @@ namespace ts {
let container = getContainingClass(node);
while (container !== undefined) {
if (container === localOrExportSymbol.valueDeclaration && container.name !== node) {
getNodeLinks(container).flags |= NodeCheckFlags.ClassWithBodyScopedClassBinding;
getNodeLinks(node).flags |= NodeCheckFlags.BodyScopedClassBinding;
getNodeLinks(container).flags |= NodeCheckFlags.DecoratedClassWithSelfReference;
getNodeLinks(node).flags |= NodeCheckFlags.SelfReferenceInDecoratedClass;
break;
}

View file

@ -346,7 +346,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
};
function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) {
if (node.locals && hasProperty(node.locals, name)) {
// We conservatively include alias symbols to cover cases where they're emitted as locals
if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
@ -1529,7 +1529,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return;
}
}
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.BodyScopedClassBinding) {
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.SelfReferenceInDecoratedClass) {
// 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
// behavior of class names in ES6.
@ -5203,7 +5203,7 @@ const _super = (function (geti, seti) {
// [Example 4]
//
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.DecoratedClassWithSelfReference) {
decoratedClassAlias = unescapeIdentifier(makeUniqueName(node.name ? node.name.text : "default"));
decoratedClassAliases[getNodeId(node)] = decoratedClassAlias;
write(`let ${decoratedClassAlias};`);

View file

@ -2368,7 +2368,7 @@ const _super = (function (geti, seti) {
}
function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) {
if (node.locals && hasProperty(node.locals, name)) {
// We conservatively include alias symbols to cover cases where they're emitted as locals
if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {

View file

@ -6,6 +6,15 @@
namespace ts {
type SuperContainer = ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration;
const enum TypeScriptSubstitutionFlags {
/** Enables substitutions for decorated classes. */
DecoratedClasses = 1 << 0,
/** Enables substitutions for namespace exports. */
NamespaceExports = 1 << 1,
/** Enables substitutions for async methods with `super` calls. */
AsyncMethodsWithSuper = 1 << 2,
}
export function transformTypeScript(context: TransformationContext) {
const {
setNodeEmitFlags,
@ -19,14 +28,14 @@ namespace ts {
const languageVersion = getEmitScriptTarget(compilerOptions);
// Save the previous transformation hooks.
const previousExpressionSubstitution = context.expressionSubstitution;
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
const previousOnAfterEmitNode = context.onAfterEmitNode;
const previousExpressionSubstitution = context.expressionSubstitution;
// Set new transformation hooks.
context.expressionSubstitution = substituteExpression;
context.onBeforeEmitNode = onBeforeEmitNode;
context.onAfterEmitNode = onAfterEmitNode;
context.expressionSubstitution = substituteExpression;
// These variables contain state that changes as we descend into the tree.
let currentSourceFile: SourceFile;
@ -36,31 +45,46 @@ namespace ts {
let currentParent: 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;
/**
* Keeps 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 enabledSubstitutions: TypeScriptSubstitutionFlags;
// This map keeps track of aliases created for classes with decorators to avoid issues
// with the double-binding behavior of classes.
/**
* A map that 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.
/**
* A map that 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.
/**
* Keeps track of how deeply nested we are within any containing namespaces
* when performing just-in-time substitution while printing an expression identifier.
* If the nest level is greater than zero, then we are performing a substitution
* inside of a namespace and we should perform the more costly checks to determine
* whether the identifier points to an exported declaration.
*/
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.
/**
* 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[];
return transformSourceFile;
/**
* Transform TypeScript-specific syntax in a SourceFile.
*
* @param node A SourceFile node.
*/
function transformSourceFile(node: SourceFile) {
currentSourceFile = node;
node = visitEachChild(node, visitor, context);
@ -136,8 +160,7 @@ namespace ts {
* @param node The node to visit.
*/
function namespaceElementVisitorWorker(node: Node): Node {
if (node.transformFlags & TransformFlags.TypeScript
|| node.flags & NodeFlags.Export) {
if (node.transformFlags & TransformFlags.TypeScript || isExported(node)) {
// This node is explicitly marked as TypeScript, or is exported at the namespace
// level, so we should transform the node.
node = visitTypeScript(node);
@ -165,12 +188,25 @@ namespace ts {
* @param node The node to visit.
*/
function classElementVisitorWorker(node: Node) {
if (node.kind === SyntaxKind.Constructor) {
// TypeScript constructors are elided.
return undefined;
}
switch (node.kind) {
case SyntaxKind.Constructor:
// TypeScript constructors are transformed in `transformClassDeclaration`.
// We elide them here as `visitorWorker` checks transform flags, which could
// erronously include an ES6 constructor without TypeScript syntax.
return undefined;
return visitorWorker(node);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.IndexSignature:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.MethodDeclaration:
// Fallback to the default visit behavior.
return visitorWorker(node);
default:
Debug.fail("Unexpected node.");
break;
}
}
/**
@ -179,9 +215,9 @@ namespace ts {
* @param node The node to visit.
*/
function visitTypeScript(node: Node): Node {
// TypeScript ambient declarations are elided.
if (node.flags & NodeFlags.Ambient) {
return;
// TypeScript ambient declarations are elided.
return undefined;
}
switch (node.kind) {
@ -233,8 +269,7 @@ namespace ts {
// TypeScript property declarations are elided.
case SyntaxKind.Constructor:
// TypeScript constructors are elided. The constructor of a class will be
// transformed as part of `transformClassDeclaration`.
// TypeScript constructors are transformed in `transformClassDeclaration`.
return undefined;
case SyntaxKind.ClassDeclaration:
@ -376,11 +411,7 @@ namespace ts {
*/
function visitClassDeclaration(node: ClassDeclaration): NodeArrayNode<Statement> {
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
const statements: Statement[] = [];
const modifiers = visitNodes(node.modifiers, visitor, isModifier);
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
const members = transformClassMembers(node, heritageClauses !== undefined);
let decoratedClassAlias: Identifier;
const hasExtendsClause = getClassExtendsHeritageClauseElement(node) !== undefined;
// emit name if
// - node has a name
@ -391,166 +422,28 @@ namespace ts {
name = getGeneratedNameForNode(node);
}
if (node.decorators) {
// When we emit an ES6 class that has a class decorator, we must tailor the
// emit to certain specific cases.
//
// In the simplest case, we emit the class declaration as a let declaration, and
// evaluate decorators after the close of the class body:
//
// [Example 1]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let C = class C {
// class C { | }
// } | C = __decorate([dec], C);
// ---------------------------------------------------------------------
// @dec | let C = class C {
// export class C { | }
// } | C = __decorate([dec], C);
// | export { C };
// ---------------------------------------------------------------------
//
// If a class declaration contains a reference to itself *inside* of the class body,
// this introduces two bindings to the class: One outside of the class body, and one
// inside of the class body. If we apply decorators as in [Example 1] above, there
// is the possibility that the decorator `dec` will return a new value for the
// constructor, which would result in the binding inside of the class no longer
// pointing to the same reference as the binding outside of the class.
//
// As a result, we must instead rewrite all references to the class *inside* of the
// class body to instead point to a local temporary alias for the class:
//
// [Example 2]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let C_1;
// class C { | let C = C_1 = class C {
// static x() { return C.y; } | static x() { return C_1.y; }
// static y = 1; | }
// } | C.y = 1;
// | C = C_1 = __decorate([dec], C);
// ---------------------------------------------------------------------
// @dec | let C_1;
// export class C { | let C = C_1 = class C {
// static x() { return C.y; } | static x() { return C_1.y; }
// static y = 1; | }
// } | C.y = 1;
// | C = C_1 = __decorate([dec], C);
// | export { C };
// ---------------------------------------------------------------------
//
// If a class declaration is the default export of a module, we instead emit
// the export after the decorated declaration:
//
// [Example 3]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let default_1 = class {
// export default class { | }
// } | default_1 = __decorate([dec], default_1);
// | export default default_1;
// ---------------------------------------------------------------------
// @dec | let C = class C {
// export default class C { | }
// } | C = __decorate([dec], C);
// | export default C;
// ---------------------------------------------------------------------
//
// If the class declaration is the default export and a reference to itself
// inside of the class body, we must emit both an alias for the class *and*
// move the export after the declaration:
//
// [Example 4]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let C_1;
// export default class C { | let C = C_1 = class C {
// static x() { return C.y; } | static x() { return C_1.y; }
// static y = 1; | }
// } | C.y = 1;
// | C = C_1 = __decorate([dec], C);
// | export default C;
// ---------------------------------------------------------------------
//
// class ${name} ${heritageClauses} {
// ${members}
// }
let classExpression: Expression = setOriginalNode(
createClassExpression(
name,
heritageClauses,
members,
/*location*/ node
),
node
);
// Record an alias to avoid class double-binding.
if (resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
enableExpressionSubstitutionForDecoratedClasses();
decoratedClassAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default");
decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias;
// We emit the class alias as a `let` declaration here so that it has the same
// TDZ as the class.
// let ${decoratedClassAlias};
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(decoratedClassAlias)
],
/*location*/ undefined,
NodeFlags.Let)
)
);
// ${decoratedClassAlias} = ${classExpression}
classExpression = createAssignment(
cloneNode(decoratedClassAlias),
classExpression,
/*location*/ node);
}
// let ${name} = ${classExpression};
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
name,
classExpression
)
],
/*location*/ undefined,
NodeFlags.Let)
)
);
}
else {
let decoratedClassAlias: Identifier;
const statements: Statement[] = [];
if (!node.decorators) {
// ${modifiers} class ${name} ${heritageClauses} {
// ${members}
// }
addNode(statements,
setOriginalNode(
createClassDeclaration(
modifiers,
visitNodes(node.modifiers, visitor, isModifier),
name,
heritageClauses,
members,
visitNodes(node.heritageClauses, visitor, isHeritageClause),
transformClassMembers(node, hasExtendsClause),
/*location*/ node
),
node
)
);
}
else {
decoratedClassAlias = addClassDeclarationHeadWithDecorators(statements, node, name, hasExtendsClause);
}
// Emit static property assignment. Because classDeclaration is lexically evaluated,
// it is safe to emit static property assignment after classDeclaration
@ -575,13 +468,168 @@ namespace ts {
addNode(statements, createExportDefault(name));
}
else if (isNamedExternalModuleExport(node)) {
addNode(statements, createModuleExport(name));
addNode(statements, createExternalModuleExport(name));
}
}
return createNodeArrayNode(statements);
}
/**
* Transforms a decorated class declaration and appends the resulting statements. If
* the class requires an alias to avoid issues with double-binding, the alias is returned.
*
* @param node A ClassDeclaration node.
* @param name The name of the class.
* @param hasExtendsClause A value indicating whether
*/
function addClassDeclarationHeadWithDecorators(statements: Statement[], node: ClassDeclaration, name: Identifier, hasExtendsClause: boolean) {
// When we emit an ES6 class that has a class decorator, we must tailor the
// emit to certain specific cases.
//
// In the simplest case, we emit the class declaration as a let declaration, and
// evaluate decorators after the close of the class body:
//
// [Example 1]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let C = class C {
// class C { | }
// } | C = __decorate([dec], C);
// ---------------------------------------------------------------------
// @dec | let C = class C {
// export class C { | }
// } | C = __decorate([dec], C);
// | export { C };
// ---------------------------------------------------------------------
//
// If a class declaration contains a reference to itself *inside* of the class body,
// this introduces two bindings to the class: One outside of the class body, and one
// inside of the class body. If we apply decorators as in [Example 1] above, there
// is the possibility that the decorator `dec` will return a new value for the
// constructor, which would result in the binding inside of the class no longer
// pointing to the same reference as the binding outside of the class.
//
// As a result, we must instead rewrite all references to the class *inside* of the
// class body to instead point to a local temporary alias for the class:
//
// [Example 2]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let C_1;
// class C { | let C = C_1 = class C {
// static x() { return C.y; } | static x() { return C_1.y; }
// static y = 1; | }
// } | C.y = 1;
// | C = C_1 = __decorate([dec], C);
// ---------------------------------------------------------------------
// @dec | let C_1;
// export class C { | let C = C_1 = class C {
// static x() { return C.y; } | static x() { return C_1.y; }
// static y = 1; | }
// } | C.y = 1;
// | C = C_1 = __decorate([dec], C);
// | export { C };
// ---------------------------------------------------------------------
//
// If a class declaration is the default export of a module, we instead emit
// the export after the decorated declaration:
//
// [Example 3]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let default_1 = class {
// export default class { | }
// } | default_1 = __decorate([dec], default_1);
// | export default default_1;
// ---------------------------------------------------------------------
// @dec | let C = class C {
// export default class C { | }
// } | C = __decorate([dec], C);
// | export default C;
// ---------------------------------------------------------------------
//
// If the class declaration is the default export and a reference to itself
// inside of the class body, we must emit both an alias for the class *and*
// move the export after the declaration:
//
// [Example 4]
// ---------------------------------------------------------------------
// TypeScript | Javascript
// ---------------------------------------------------------------------
// @dec | let C_1;
// export default class C { | let C = C_1 = class C {
// static x() { return C.y; } | static x() { return C_1.y; }
// static y = 1; | }
// } | C.y = 1;
// | C = C_1 = __decorate([dec], C);
// | export default C;
// ---------------------------------------------------------------------
//
// ... = class ${name} ${heritageClauses} {
// ${members}
// }
let classExpression: Expression = setOriginalNode(
createClassExpression(
name,
visitNodes(node.heritageClauses, visitor, isHeritageClause),
transformClassMembers(node, hasExtendsClause),
/*location*/ node
),
node
);
// Record an alias to avoid class double-binding.
let decoratedClassAlias: Identifier;
if (resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.DecoratedClassWithSelfReference) {
enableExpressionSubstitutionForDecoratedClasses();
decoratedClassAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default");
decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias;
// We emit the class alias as a `let` declaration here so that it has the same
// TDZ as the class.
// let ${decoratedClassAlias};
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(decoratedClassAlias)
],
/*location*/ undefined,
NodeFlags.Let)
)
);
// ${decoratedClassAlias} = ${classExpression}
classExpression = createAssignment(
decoratedClassAlias,
classExpression,
/*location*/ node);
}
// let ${name} = ${classExpression};
addNode(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
name,
classExpression
)
],
/*location*/ undefined,
NodeFlags.Let)
)
);
return decoratedClassAlias;
}
/**
* Transforms a class expression with TypeScript syntax into compatible ES6.
*
@ -638,7 +686,7 @@ namespace ts {
const members: ClassElement[] = [];
addNode(members, transformConstructor(node, hasExtendsClause));
addNodes(members, visitNodes(node.members, classElementVisitor, isClassElement));
return members;
return createNodeArray(members, /*location*/ node.members);
}
/**
@ -2489,9 +2537,15 @@ namespace ts {
&& (node.flags & NodeFlags.Default) !== 0;
}
/**
* 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 !forEach(original.symbol && original.symbol.declarations, declaration => declaration.kind === kind && declaration.pos < original.pos);
return original.symbol && getDeclarationOfKind(original.symbol, kind) === original;
}
/**
@ -2511,7 +2565,7 @@ namespace ts {
);
}
function createModuleExport(exportName: Identifier) {
function createExternalModuleExport(exportName: Identifier) {
return createExportDeclaration(
createNamedExports([
createExportSpecifier(exportName)
@ -2544,12 +2598,13 @@ namespace ts {
previousOnBeforeEmitNode(node);
const kind = node.kind;
if (hasEnabledExpressionSubstitutionForDecoratedClasses
&& kind === SyntaxKind.ClassDeclaration && node.decorators) {
if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses
&& kind === SyntaxKind.ClassDeclaration
&& node.decorators) {
currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)];
}
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports
&& (kind === SyntaxKind.ClassDeclaration
|| kind === SyntaxKind.Constructor
|| kind === SyntaxKind.MethodDeclaration
@ -2563,7 +2618,7 @@ namespace ts {
superContainerStack.push(<SuperContainer>node);
}
if (hasEnabledExpressionSubstitutionForNamespaceExports
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports
&& kind === SyntaxKind.ModuleDeclaration) {
namespaceNestLevel++;
}
@ -2573,12 +2628,13 @@ namespace ts {
previousOnAfterEmitNode(node);
const kind = node.kind;
if (hasEnabledExpressionSubstitutionForDecoratedClasses
&& kind === SyntaxKind.ClassDeclaration && node.decorators) {
if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses
&& kind === SyntaxKind.ClassDeclaration
&& node.decorators) {
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
}
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports
&& (kind === SyntaxKind.ClassDeclaration
|| kind === SyntaxKind.Constructor
|| kind === SyntaxKind.MethodDeclaration
@ -2590,7 +2646,7 @@ namespace ts {
}
}
if (hasEnabledExpressionSubstitutionForNamespaceExports
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports
&& kind === SyntaxKind.ModuleDeclaration) {
namespaceNestLevel--;
}
@ -2604,7 +2660,7 @@ namespace ts {
return substituteExpressionIdentifier(<Identifier>node);
}
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper) {
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports) {
switch (node.kind) {
case SyntaxKind.CallExpression:
return substituteCallExpression(<CallExpression>node);
@ -2619,9 +2675,9 @@ namespace ts {
}
function substituteExpressionIdentifier(node: Identifier): Expression {
if (hasEnabledExpressionSubstitutionForDecoratedClasses
if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses
&& !nodeIsSynthesized(node)
&& resolver.getNodeCheckFlags(node) & NodeCheckFlags.BodyScopedClassBinding) {
&& resolver.getNodeCheckFlags(node) & NodeCheckFlags.SelfReferenceInDecoratedClass) {
// 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
// behavior of class names in ES6.
@ -2635,7 +2691,7 @@ namespace ts {
}
}
if (hasEnabledExpressionSubstitutionForNamespaceExports
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports
&& namespaceNestLevel > 0) {
// If we are nested within a namespace declaration, we may need to qualifiy
// an identifier that is exported from a merged namespace.
@ -2702,8 +2758,8 @@ namespace ts {
}
function enableExpressionSubstitutionForAsyncMethodsWithSuper() {
if (!hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper) {
hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = true;
if ((enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports) === 0) {
enabledSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
// We need to enable substitutions for call, property access, and element access
// if we need to rewrite super calls.
@ -2721,8 +2777,8 @@ namespace ts {
}
function enableExpressionSubstitutionForDecoratedClasses() {
if (!hasEnabledExpressionSubstitutionForDecoratedClasses) {
hasEnabledExpressionSubstitutionForDecoratedClasses = true;
if ((enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses) === 0) {
enabledSubstitutions |= TypeScriptSubstitutionFlags.DecoratedClasses;
// We need to enable substitutions for identifiers. This allows us to
// substitute class names inside of a class declaration.
@ -2735,8 +2791,8 @@ namespace ts {
}
function enableExpressionSubstitutionForNamespaceExports() {
if (!hasEnabledExpressionSubstitutionForNamespaceExports) {
hasEnabledExpressionSubstitutionForNamespaceExports = true;
if ((enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports) === 0) {
enabledSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
// We need to enable substitutions for identifiers. This allows us to
// substitute the names of exported members of a namespace.

View file

@ -2091,8 +2091,8 @@ namespace ts {
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
HasSeenSuperCall = 0x00080000, // Set during the binding when encounter 'super'
ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body.
DecoratedClassWithSelfReference = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
SelfReferenceInDecoratedClass = 0x00200000, // Binding to a decorated class inside of the class's body.
}
/* @internal */

View file

@ -1352,7 +1352,7 @@ namespace ts {
export function isNodeDescendentOf(node: Node, ancestor: Node): boolean {
export function isNodeDescendantOf(node: Node, ancestor: Node): boolean {
while (node) {
if (node === ancestor) return true;
node = node.parent;
@ -2866,7 +2866,8 @@ namespace ts {
}
export function isGeneratedIdentifier(node: Node): node is Identifier {
return isIdentifier(node) && node.autoGenerateKind > GeneratedIdentifierKind.Node;
// Using `>` here catches both `GeneratedIdentifierKind.None` and `undefined`.
return isIdentifier(node) && node.autoGenerateKind > GeneratedIdentifierKind.None;
}
// Keywords