mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Adds transform flags aggregation to binder and visitor
This commit is contained in:
+472
-1
@@ -132,11 +132,17 @@ namespace ts {
|
||||
let Symbol: { new (flags: SymbolFlags, name: string): Symbol };
|
||||
let classifiableNames: Map<string>;
|
||||
|
||||
// state used to aggregate transform flags during bind.
|
||||
let subtreeTransformFlags: TransformFlags;
|
||||
let skipTransformFlagAggregation: boolean;
|
||||
|
||||
function bindSourceFile(f: SourceFile, opts: CompilerOptions) {
|
||||
file = f;
|
||||
options = opts;
|
||||
inStrictMode = !!file.externalModuleIndicator;
|
||||
classifiableNames = {};
|
||||
subtreeTransformFlags = undefined;
|
||||
skipTransformFlagAggregation = isDeclarationFile(file);
|
||||
|
||||
Symbol = objectAllocator.getSymbolConstructor();
|
||||
|
||||
@@ -1178,11 +1184,43 @@ namespace ts {
|
||||
// symbols we do specialized work when we recurse. For example, we'll keep track of
|
||||
// the current 'container' node when it changes. This helps us know which symbol table
|
||||
// a local should go into for example.
|
||||
bindChildren(node);
|
||||
aggregateTransformFlagsIfNeededAndBindChildren(node);
|
||||
|
||||
inStrictMode = savedInStrictMode;
|
||||
}
|
||||
|
||||
function aggregateTransformFlagsIfNeededAndBindChildren(node: Node) {
|
||||
if (node.transformFlags !== undefined) {
|
||||
skipTransformFlagAggregationAndBindChildren(node);
|
||||
}
|
||||
else {
|
||||
aggregateTransformFlagsAndBindChildren(node);
|
||||
}
|
||||
}
|
||||
|
||||
function skipTransformFlagAggregationAndBindChildren(node: Node) {
|
||||
if (!skipTransformFlagAggregation) {
|
||||
skipTransformFlagAggregation = true;
|
||||
bindChildren(node);
|
||||
skipTransformFlagAggregation = false;
|
||||
}
|
||||
else {
|
||||
bindChildren(node);
|
||||
}
|
||||
}
|
||||
|
||||
function aggregateTransformFlagsAndBindChildren(node: Node) {
|
||||
if (!skipTransformFlagAggregation) {
|
||||
const savedSubtreeTransformFlags = subtreeTransformFlags;
|
||||
subtreeTransformFlags = 0;
|
||||
bindChildren(node);
|
||||
subtreeTransformFlags = savedSubtreeTransformFlags | computeTransformFlagsForNode(node, subtreeTransformFlags);
|
||||
}
|
||||
else {
|
||||
bindChildren(node);
|
||||
}
|
||||
}
|
||||
|
||||
function updateStrictMode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
@@ -1751,4 +1789,437 @@ namespace ts {
|
||||
implicitLabels = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the transform flags for a node, given the transform flags of its subtree
|
||||
*
|
||||
* @param node The node to analyze
|
||||
* @param subtreeFlags Transform flags computed for this node's subtree
|
||||
*/
|
||||
export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags) {
|
||||
// Ambient nodes are TypeScript syntax and the flags of their subtree are ignored.
|
||||
if (node.flags & NodeFlags.Ambient) {
|
||||
return (node.transformFlags = TransformFlags.AssertTypeScript)
|
||||
& ~(node.excludeTransformFlags = TransformFlags.NodeExcludes);
|
||||
}
|
||||
|
||||
// Mark transformations needed for each node
|
||||
let transformFlags: TransformFlags;
|
||||
let excludeFlags: TransformFlags;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
case SyntaxKind.AsyncKeyword:
|
||||
case SyntaxKind.ConstKeyword:
|
||||
case SyntaxKind.AwaitExpression:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
// These nodes are TypeScript syntax.
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
break;
|
||||
|
||||
case SyntaxKind.JsxElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxText:
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
case SyntaxKind.JsxAttribute:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
case SyntaxKind.JsxExpression:
|
||||
// These nodes are Jsx syntax.
|
||||
transformFlags |= TransformFlags.AssertJsx;
|
||||
break;
|
||||
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateHead:
|
||||
case SyntaxKind.TemplateMiddle:
|
||||
case SyntaxKind.TemplateTail:
|
||||
case SyntaxKind.TemplateExpression:
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
case SyntaxKind.YieldExpression:
|
||||
// These nodes are ES6 syntax.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
break;
|
||||
|
||||
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.VoidKeyword:
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.TypePredicate:
|
||||
case SyntaxKind.TypeReference:
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.TypeQuery:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.ArrayType:
|
||||
case SyntaxKind.TupleType:
|
||||
case SyntaxKind.UnionType:
|
||||
case SyntaxKind.IntersectionType:
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.StringLiteralType:
|
||||
// Types and signatures are TypeScript syntax, and exclude all other facts.
|
||||
excludeFlags = TransformFlags.TypeExcludes;
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
// Even though computed property names are ES6, we don't treat them as such.
|
||||
// This is so that they can flow through PropertyName transforms unaffected.
|
||||
// Instead, we mark the container as ES6, so that it can properly handle the transform.
|
||||
transformFlags |= TransformFlags.ContainsComputedPropertyName;
|
||||
break;
|
||||
|
||||
case SyntaxKind.SpreadElementExpression:
|
||||
// This node is ES6 syntax, but is handled by a containing node.
|
||||
transformFlags |= TransformFlags.ContainsSpreadElementExpression;
|
||||
break;
|
||||
|
||||
case SyntaxKind.SuperKeyword:
|
||||
// This node is ES6 syntax.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ThisKeyword:
|
||||
// Mark this node and its ancestors as containing a lexical `this` keyword.
|
||||
transformFlags |= TransformFlags.ContainsLexicalThis;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
// These nodes are ES6 syntax.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
excludeFlags = TransformFlags.ObjectLiteralExcludes;
|
||||
if (subtreeFlags & TransformFlags.ContainsComputedPropertyName) {
|
||||
// If an ObjectLiteralExpression contains a ComputedPropertyName, then it
|
||||
// is an ES6 node.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
|
||||
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression
|
||||
|| isSuperCall(node)) {
|
||||
// If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6
|
||||
// node.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
|
||||
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) {
|
||||
// If the this node contains a SpreadElementExpression, then it is an ES6
|
||||
// node.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.Decorator:
|
||||
// This node is TypeScript syntax, and marks its container as also being TypeScript syntax.
|
||||
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsDecorators;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
// This node is TypeScript syntax, and excludes markers that should not escape the module scope.
|
||||
excludeFlags = TransformFlags.ModuleExcludes;
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
// If the node is synthesized, it means the emitter put the parentheses there,
|
||||
// not the user. If we didn't want them, the emitter would not have put them
|
||||
// there.
|
||||
if (!nodeIsSynthesized(node)) {
|
||||
if ((<ParenthesizedExpression>node).expression.kind === SyntaxKind.AsExpression
|
||||
|| (<ParenthesizedExpression>node).expression.kind === SyntaxKind.TypeAssertionExpression) {
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
// if (node.flags & NodeFlags.Generated) {
|
||||
// let expression = (<ExpressionStatement>node).expression;
|
||||
// if (expression.kind === SyntaxKind.CallExpression
|
||||
// && (<CallExpression>expression).expression.kind === SyntaxKind.SuperKeyword) {
|
||||
// transformFlags |= TransformFlags.AssertES6;
|
||||
// }
|
||||
// }
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if (isDestructuringAssignment(node)) {
|
||||
// Destructuring assignments are ES6 syntax.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
else if ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.AsteriskAsteriskToken
|
||||
|| (<BinaryExpression>node).operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
|
||||
// Exponentiation is ES7 syntax.
|
||||
transformFlags |= TransformFlags.AssertES7;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.Parameter:
|
||||
// If the parameter has a question token, then it is TypeScript syntax.
|
||||
if ((<ParameterDeclaration>node).questionToken) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
|
||||
if ((<ParameterDeclaration>node).flags & NodeFlags.AccessibilityModifier) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
|
||||
}
|
||||
|
||||
// If a parameter has an initializer, a binding pattern or a dotDotDot token, then
|
||||
// it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel.
|
||||
if ((<ParameterDeclaration>node).initializer
|
||||
|| (<ParameterDeclaration>node).dotDotDotToken
|
||||
|| isBindingPattern((<ParameterDeclaration>node).name)) {
|
||||
transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsDefaultValueAssignments;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.ArrowFunction:
|
||||
// An ArrowFunction is ES6 syntax, and excludes markers that should not escape the scope of an ArrowFunction.
|
||||
excludeFlags = TransformFlags.ArrowFunctionExcludes;
|
||||
transformFlags = TransformFlags.AssertES6;
|
||||
|
||||
// If an ArrowFunction contains a lexical this, its container must capture the lexical this.
|
||||
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
|
||||
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
|
||||
}
|
||||
|
||||
// An async arrow function is TypeScript syntax.
|
||||
if (node.flags & NodeFlags.Async) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionExpression:
|
||||
// A FunctionExpression excludes markers that should not escape the scope of a FunctionExpression.
|
||||
excludeFlags = TransformFlags.FunctionExcludes;
|
||||
|
||||
// If a FunctionExpression contains an asterisk token, or its subtree has marked the container
|
||||
// as needing to capture the lexical this, then this node is ES6 syntax.
|
||||
if ((<FunctionLikeDeclaration>node).asteriskToken
|
||||
|| subtreeFlags & TransformFlags.ContainsCapturedLexicalThis
|
||||
|| subtreeFlags & TransformFlags.ContainsDefaultValueAssignments) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
// An async function expression is TypeScript syntax.
|
||||
if (node.flags & NodeFlags.Async) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
// A FunctionDeclaration excludes markers that should not escape the scope of a FunctionDeclaration.
|
||||
excludeFlags = TransformFlags.FunctionExcludes;
|
||||
|
||||
// A FunctionDeclaration without a body is an overload and is TypeScript syntax.
|
||||
if (!(<FunctionDeclaration>node).body) {
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
break;
|
||||
}
|
||||
|
||||
// If a FunctionDeclaration has an asterisk token, is exported, or its
|
||||
// subtree has marked the container as needing to capture the lexical `this`,
|
||||
// then this node is ES6 syntax.
|
||||
if ((<FunctionDeclaration>node).asteriskToken
|
||||
|| node.flags & NodeFlags.Export
|
||||
|| subtreeFlags & TransformFlags.ContainsCapturedLexicalThis
|
||||
|| subtreeFlags & TransformFlags.ContainsDefaultValueAssignments) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
// An async function declaration is TypeScript syntax.
|
||||
if (node.flags & NodeFlags.Async) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
// A VariableDeclaration with a binding pattern is ES6 syntax.
|
||||
if (isBindingPattern((<VariableDeclaration>node).name)) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
// If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax.
|
||||
if (node.flags & NodeFlags.Let
|
||||
|| node.flags & NodeFlags.Const) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.VariableStatement:
|
||||
// If a VariableStatement is exported, then it is ES6 syntax.
|
||||
if (node.flags & NodeFlags.Export) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
// A ClassDeclarations or ClassExpression is ES6 syntax.
|
||||
excludeFlags = TransformFlags.ClassExcludes;
|
||||
transformFlags = TransformFlags.AssertES6;
|
||||
|
||||
// A class with a parameter property assignment, property initializer, or decorator is
|
||||
// TypeScript syntax.
|
||||
if (subtreeFlags & TransformFlags.ContainsParameterPropertyAssignments
|
||||
|| subtreeFlags & TransformFlags.ContainsPropertyInitializer
|
||||
|| subtreeFlags & TransformFlags.ContainsDecorators) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.HeritageClause:
|
||||
// An `extends` HertiageClause is ES6 syntax.
|
||||
if ((<HeritageClause>node).token === SyntaxKind.ExtendsKeyword) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
// An `implements` HeritageClause is TypeScript syntax.
|
||||
else if ((<HeritageClause>node).token === SyntaxKind.ImplementsKeyword) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
// An ExpressionWithTypeArguments is ES6 syntax, as it is used in the
|
||||
// extends clause of a class.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
|
||||
// If an ExpressionWithTypeArguments contains type arguments, then it
|
||||
// is TypeScript syntax.
|
||||
if ((<ExpressionWithTypeArguments>node).typeArguments) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.Constructor:
|
||||
// A Constructor is ES6 syntax.
|
||||
excludeFlags = TransformFlags.ConstructorExcludes;
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
|
||||
// An overload constructor is TypeScript syntax.
|
||||
if (!(<ConstructorDeclaration>node).body) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
// A PropertyDeclaration is TypeScript syntax.
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
|
||||
// If the PropertyDeclaration has an initializer, we need to inform its ancestor
|
||||
// so that it handle the transformation.
|
||||
if ((<PropertyDeclaration>node).initializer) {
|
||||
transformFlags |= TransformFlags.ContainsPropertyInitializer;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
// A MethodDeclaration is ES6 syntax.
|
||||
excludeFlags = TransformFlags.MethodOrAccessorExcludes;
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
|
||||
// A MethodDeclaration is TypeScript syntax if it is either async, abstract, overloaded,
|
||||
// generic, or has both a computed property name and a decorator.
|
||||
if ((<MethodDeclaration>node).body === undefined
|
||||
|| (<MethodDeclaration>node).typeParameters !== undefined
|
||||
|| node.flags & NodeFlags.Async
|
||||
|| node.flags & NodeFlags.Abstract
|
||||
|| (subtreeFlags & TransformFlags.ContainsDecorators
|
||||
&& subtreeFlags & TransformFlags.ContainsComputedPropertyName)) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
// A GetAccessor or SetAccessor is ES5 syntax.
|
||||
excludeFlags = TransformFlags.MethodOrAccessorExcludes;
|
||||
|
||||
// A GetAccessor or SetAccessor is TypeScript syntax if it is either abstract,
|
||||
// or has both a computed property name and a decorator.
|
||||
if (node.flags & NodeFlags.Abstract ||
|
||||
subtreeFlags & TransformFlags.ContainsDecorators &&
|
||||
subtreeFlags & TransformFlags.ContainsComputedPropertyName) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
// An ImportEqualsDeclaration with a namespace reference is TypeScript.
|
||||
if (!isExternalModuleImportEqualsDeclaration(node)) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
// If a PropertyAccessExpression starts with a super keyword, then it is
|
||||
// ES6 syntax, and requires a lexical `this` binding.
|
||||
if ((<PropertyAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword) {
|
||||
transformFlags |= TransformFlags.ContainsLexicalThis;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.SourceFile:
|
||||
if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return (node.transformFlags = subtreeFlags | transformFlags)
|
||||
& ~(node.excludeTransformFlags = excludeFlags | TransformFlags.NodeExcludes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -865,6 +865,8 @@ namespace ts {
|
||||
this.pos = pos;
|
||||
this.end = end;
|
||||
this.flags = NodeFlags.None;
|
||||
this.transformFlags = undefined;
|
||||
this.excludeTransformFlags = undefined;
|
||||
this.parent = undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -442,6 +442,8 @@ namespace ts {
|
||||
export interface Node extends TextRange {
|
||||
kind: SyntaxKind;
|
||||
flags: NodeFlags;
|
||||
/* @internal */ transformFlags?: TransformFlags;
|
||||
/* @internal */ excludeTransformFlags?: TransformFlags;
|
||||
decorators?: NodeArray<Decorator>; // Array of decorators (in document order)
|
||||
modifiers?: ModifiersArray; // Array of modifiers
|
||||
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
|
||||
@@ -2707,6 +2709,52 @@ namespace ts {
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const enum TransformFlags {
|
||||
// Facts
|
||||
// - Flags used to indicate that a node or subtree contains syntax that requires transformation.
|
||||
TypeScript = 1 << 0,
|
||||
ContainsTypeScript = 1 << 1,
|
||||
Jsx = 1 << 2,
|
||||
ContainsJsx = 1 << 3,
|
||||
ES7 = 1 << 4,
|
||||
ContainsES7 = 1 << 5,
|
||||
ES6 = 1 << 6,
|
||||
ContainsES6 = 1 << 7,
|
||||
|
||||
// Assertions
|
||||
// - Bitmasks that are used to assert facts about the syntax of a node and its subtree.
|
||||
AssertTypeScript = TypeScript | ContainsTypeScript,
|
||||
AssertJsx = Jsx | ContainsJsx,
|
||||
AssertES7 = ES7 | ContainsES7,
|
||||
AssertES6 = ES6 | ContainsES6,
|
||||
|
||||
// Markers
|
||||
// - Flags used to indicate that a subtree contains a specific transformation.
|
||||
ContainsDecorators = 1 << 8,
|
||||
ContainsPropertyInitializer = 1 << 9,
|
||||
ContainsLexicalThis = 1 << 10,
|
||||
ContainsCapturedLexicalThis = 1 << 11,
|
||||
ContainsDefaultValueAssignments = 1 << 12,
|
||||
ContainsParameterPropertyAssignments = 1 << 13,
|
||||
ContainsSpreadElementExpression = 1 << 14,
|
||||
ContainsComputedPropertyName = 1 << 15,
|
||||
|
||||
// Scope Exclusions
|
||||
// - Bitmasks that exclude flags from propagating out of a specific context
|
||||
// into the subtree flags of their container.
|
||||
NodeExcludes = TypeScript | Jsx | ES7 | ES6,
|
||||
ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments,
|
||||
FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments,
|
||||
ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsParameterPropertyAssignments,
|
||||
MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis,
|
||||
ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments,
|
||||
ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis,
|
||||
TypeExcludes = ~ContainsTypeScript,
|
||||
ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName,
|
||||
ArrayLiteralOrCallOrNewExcludes = ContainsSpreadElementExpression,
|
||||
}
|
||||
|
||||
export interface TextSpan {
|
||||
start: number;
|
||||
length: number;
|
||||
|
||||
@@ -872,12 +872,20 @@ namespace ts {
|
||||
/**
|
||||
* Determines whether a node is a property or element access expression for super.
|
||||
*/
|
||||
export function isSuperPropertyOrElementAccess(node: Node) {
|
||||
export function isSuperPropertyOrElementAccess(node: Node): node is (PropertyAccessExpression | ElementAccessExpression) {
|
||||
return (node.kind === SyntaxKind.PropertyAccessExpression
|
||||
|| node.kind === SyntaxKind.ElementAccessExpression)
|
||||
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is a call to either `super`, or a super property or element access.
|
||||
*/
|
||||
export function isSuperCall(node: Node): node is CallExpression {
|
||||
return node.kind === SyntaxKind.CallExpression
|
||||
&& ((<CallExpression>node).expression.kind === SyntaxKind.SuperKeyword
|
||||
|| isSuperPropertyOrElementAccess((<CallExpression>node).expression));
|
||||
}
|
||||
|
||||
export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression {
|
||||
if (node) {
|
||||
@@ -1666,7 +1674,7 @@ namespace ts {
|
||||
: <T>createSynthesizedNode(node.kind);
|
||||
|
||||
for (const key in node) {
|
||||
if (key === "parent" || key === "flags" || clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) {
|
||||
if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2694,6 +2702,18 @@ namespace ts {
|
||||
|| isIdentifierNode(node);
|
||||
}
|
||||
|
||||
export function isDestructuringAssignment(node: Node): node is BinaryExpression {
|
||||
if (isBinaryExpression(node)) {
|
||||
if (node.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const kind = node.left.kind;
|
||||
return kind === SyntaxKind.ObjectLiteralExpression
|
||||
|| kind === SyntaxKind.ArrayLiteralExpression;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns false if this heritage clause element's expression contains something unsupported
|
||||
// (i.e. not a name or dotted name).
|
||||
export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean {
|
||||
|
||||
+59
-1
@@ -505,6 +505,7 @@ namespace ts {
|
||||
Debug.assert(test(visited), "Wrong node type after visit.");
|
||||
}
|
||||
|
||||
aggregateTransformFlags(visited);
|
||||
return <T>visited;
|
||||
}
|
||||
|
||||
@@ -542,6 +543,10 @@ namespace ts {
|
||||
}
|
||||
else if (visited !== undefined) {
|
||||
Debug.assert(test(visited), "Wrong node type after visit.");
|
||||
if (visited !== node) {
|
||||
aggregateTransformFlags(visited);
|
||||
}
|
||||
|
||||
updated.push(<T>visited);
|
||||
}
|
||||
}
|
||||
@@ -606,10 +611,14 @@ namespace ts {
|
||||
if (isNewLexicalEnvironment) {
|
||||
const declarations = environment.endLexicalEnvironment();
|
||||
if (declarations !== undefined && declarations.length > 0) {
|
||||
return <T>mergeLexicalEnvironment(updated, declarations, /*nodeIsMutable*/ updated !== node);
|
||||
updated = <T>mergeLexicalEnvironment(updated, declarations, /*nodeIsMutable*/ updated !== node);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated !== node) {
|
||||
aggregateTransformFlags(updated);
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
@@ -766,4 +775,53 @@ namespace ts {
|
||||
Debug.assert(nodes.length <= 1, "Too many nodes written to output.");
|
||||
return nodes.length > 0 ? nodes[0] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates the TransformFlags for a Node and its subtree.
|
||||
*/
|
||||
export function aggregateTransformFlags(node: Node): void {
|
||||
aggregateTransformFlagsForNode(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates the TransformFlags for a Node and its subtree. The flags for the subtree are
|
||||
* computed first, then the transform flags for the current node are computed from the subtree
|
||||
* flags and the state of the current node. Finally, the transform flags of the node are
|
||||
* returned, excluding any flags that should not be included in its parent node's subtree
|
||||
* flags.
|
||||
*/
|
||||
function aggregateTransformFlagsForNode(node: Node): TransformFlags {
|
||||
if (node === undefined) {
|
||||
return <TransformFlags>0;
|
||||
}
|
||||
|
||||
if (node.transformFlags === undefined) {
|
||||
const subtreeFlags = aggregateTransformFlagsForSubtree(node);
|
||||
return computeTransformFlagsForNode(node, subtreeFlags);
|
||||
}
|
||||
|
||||
return node.transformFlags & ~node.excludeTransformFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates the transform flags for the subtree of a node.
|
||||
*/
|
||||
function aggregateTransformFlagsForSubtree(node: Node): TransformFlags {
|
||||
// We do not transform ambient declarations or types, so there is no need to
|
||||
// recursively aggregate transform flags.
|
||||
if (node.flags & NodeFlags.Ambient || isTypeNodeNode(node)) {
|
||||
return <TransformFlags>0;
|
||||
}
|
||||
|
||||
// Aggregate the transform flags of each child.
|
||||
return reduceEachChild<TransformFlags>(node, aggregateTransformFlagsForChildNode, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates the TransformFlags of a child node with the TransformFlags of its
|
||||
* siblings.
|
||||
*/
|
||||
function aggregateTransformFlagsForChildNode(transformFlags: TransformFlags, child: Node): TransformFlags {
|
||||
return transformFlags | aggregateTransformFlagsForNode(child);
|
||||
}
|
||||
}
|
||||
@@ -186,6 +186,8 @@ namespace ts {
|
||||
public end: number;
|
||||
public flags: NodeFlags;
|
||||
public parent: Node;
|
||||
public transformFlags: TransformFlags;
|
||||
public excludeTransformFlags: TransformFlags;
|
||||
private _children: Node[];
|
||||
|
||||
constructor(kind: SyntaxKind, pos: number, end: number) {
|
||||
@@ -193,6 +195,8 @@ namespace ts {
|
||||
this.pos = pos;
|
||||
this.end = end;
|
||||
this.flags = NodeFlags.None;
|
||||
this.transformFlags = undefined;
|
||||
this.excludeTransformFlags = undefined;
|
||||
this.parent = undefined;
|
||||
}
|
||||
|
||||
@@ -1876,7 +1880,7 @@ namespace ts {
|
||||
|
||||
options.isolatedModules = true;
|
||||
|
||||
// transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths.
|
||||
// transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths.
|
||||
options.suppressOutputPathCheck = true;
|
||||
|
||||
// Filename can be non-ts file.
|
||||
@@ -6102,7 +6106,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// For export specifiers, it can be a local symbol, e.g.
|
||||
// For export specifiers, it can be a local symbol, e.g.
|
||||
// import {a} from "mod";
|
||||
// export {a as somethingElse}
|
||||
// We want the local target of the export (i.e. the import symbol) and not the final target (i.e. "mod".a)
|
||||
|
||||
Reference in New Issue
Block a user