diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 7fb4d8f032e07..042f7f877c72e 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1,5 +1,5 @@ -let nextAutoGenerateId = 0; namespace ts { + let nextAutoGenerateId = 0; /* @internal */ export const enum NodeFactoryFlags { @@ -85,6 +85,21 @@ namespace ts { const update = observeArguments(updateNodeWorker, treeStateObserver && treeStateObserver.onUpdateNode); const reuse = observeResult(identity, treeStateObserver && treeStateObserver.onReuseNode); + const onSetChild: (parent: Node, child: Node | undefined) => void = + treeStateObserver?.onSetChild ? + (parent, child) => { if (child) treeStateObserver!.onSetChild!(parent, child) } : + ((_, __) => {}); + + const onSetChildren: (parent: Node, children: readonly Node[] | undefined) => void = + treeStateObserver?.onSetChildren ? + (parent, children) => { if (children) treeStateObserver!.onSetChildren!(parent, children); } : + ((_, __) => {}); + + const onFinishNode: (node: Node) => void = + treeStateObserver?.onFinishNode ? + (node) => { treeStateObserver!.onFinishNode!(node); } : + ((_) => {}); + const factory: NodeFactory = { get parenthesizer() { return parenthesizerRules(); }, get converters() { return converters(); }, @@ -747,28 +762,6 @@ namespace ts { return node; } - function createBaseVariableLikeDeclaration( - kind: T["kind"], - decorators: readonly Decorator[] | undefined, - modifiers: readonly Modifier[] | undefined, - name: string | T["name"] | undefined, - type: TypeNode | undefined, - initializer: Expression | undefined - ) { - const node = createBaseBindingLikeDeclaration( - kind, - decorators, - modifiers, - name, - initializer - ); - setChild(node, node.type = type); - if (!skipTransformationFlags) { - if (type) markTypeScript(node); - } - return node; - } - // // Literals // @@ -788,19 +781,31 @@ namespace ts { function createNumericLiteral(value: string | number, numericLiteralFlags: TokenFlags = TokenFlags.None): NumericLiteral { const node = createBaseLiteral(SyntaxKind.NumericLiteral, typeof value === "number" ? value + "" : value); node.numericLiteralFlags = numericLiteralFlags; + // propagate flags and set markers if (!skipTransformationFlags) { - if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) markES2015(node); - } - return finish(node); + node.transformFlags = + (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier ? + TransformFlags.ContainsES2015 : + TransformFlags.None) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onFinishNode(node); + return node; } // @api function createBigIntLiteral(value: string | PseudoBigInt): BigIntLiteral { const node = createBaseLiteral(SyntaxKind.BigIntLiteral, typeof value === "string" ? value : pseudoBigIntToString(value) + "n"); if (!skipTransformationFlags) { - markESNext(node); + // propagate flags and set markers + node.transformFlags = + TransformFlags.ContainsESNext | + TransformFlags.HasComputedFlags; } - return finish(node); + // trigger observers + onFinishNode(node); + return node; } function createBaseStringLiteral(text: string, isSingleQuote?: boolean) { @@ -813,10 +818,18 @@ namespace ts { function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral { const node = createBaseStringLiteral(text, isSingleQuote); node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape; + node.textSourceNode = undefined; + // propagate flags and markers if (!skipTransformationFlags) { - if (hasExtendedUnicodeEscape) markES2015(node); - } - return finish(node); + node.transformFlags = + (hasExtendedUnicodeEscape ? + TransformFlags.ContainsES2015 : + TransformFlags.None) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onFinishNode(node); + return node; } // @api @@ -859,6 +872,9 @@ namespace ts { const node = createIdentifierNode(SyntaxKind.Identifier) as Mutable; node.originalKeywordKind = originalKeywordKind; node.escapedText = escapeLeadingUnderscores(text); + node.typeArguments = undefined; + node.autoGenerateFlags = 0; + node.autoGenerateId = 0; return node; } @@ -867,20 +883,25 @@ namespace ts { node.autoGenerateFlags = autoGenerateFlags; node.autoGenerateId = nextAutoGenerateId; nextAutoGenerateId++; + // propagate flags and set markers + if (!skipTransformationFlags) { + node.transformFlags = TransformFlags.HasComputedFlags; + } return node; } // @api function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind): Identifier { const node = createBaseIdentifier(text, originalKeywordKind); - if (typeArguments) { - // NOTE: we do not use `setChildren` here because typeArguments in an identifier do not contribute to transformations - node.typeArguments = createNodeArray(typeArguments); - if (treeStateObserver && treeStateObserver.onSetChildren) { - treeStateObserver.onSetChildren(node, node.typeArguments); - } + node.typeArguments = asNodeArray(typeArguments); + // propagate flags and set markers + if (!skipTransformationFlags) { + node.transformFlags |= TransformFlags.HasComputedFlags; } - return finish(node); + // trigger observers + onSetChildren(node, node.typeArguments); + onFinishNode(node); + return node; } // @api @@ -894,7 +915,9 @@ namespace ts { function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean): GeneratedIdentifier { let flags = GeneratedIdentifierFlags.Auto; if (reservedInNestedScopes) flags |= GeneratedIdentifierFlags.ReservedInNestedScopes; - const name = finish(createBaseGeneratedIdentifier("", flags)); + const name = createBaseGeneratedIdentifier("", flags); + // trigger observers + onFinishNode(name); if (recordTempVariable) { recordTempVariable(name); } @@ -904,7 +927,10 @@ namespace ts { /** Create a unique temporary variable for use in a loop. */ // @api function createLoopVariable(): Identifier { - return finish(createBaseGeneratedIdentifier("", GeneratedIdentifierFlags.Loop)); + const node = createBaseGeneratedIdentifier("", GeneratedIdentifierFlags.Loop); + // trigger observers + onFinishNode(node); + return node; } /** Create a unique name based on the supplied text. */ @@ -912,7 +938,10 @@ namespace ts { function createUniqueName(text: string, flags: GeneratedIdentifierFlags = GeneratedIdentifierFlags.None): Identifier { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); Debug.assert((flags & (GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)) !== GeneratedIdentifierFlags.FileLevel, "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic"); - return finish(createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Unique | flags)); + const node = createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Unique | flags); + // trigger observers + onFinishNode(node); + return node; } /** Create a unique name generated for a node. */ @@ -921,7 +950,9 @@ namespace ts { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); const name = createBaseGeneratedIdentifier(node && isIdentifier(node) ? idText(node) : "", GeneratedIdentifierFlags.Node | flags); name.original = node; - return finish(name); + // trigger observers + onFinishNode(name); + return name; } // @api @@ -929,9 +960,14 @@ namespace ts { if (!startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text); const node = createPrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable; node.escapedText = escapeLeadingUnderscores(text); + // propagate flags and set markers if (!skipTransformationFlags) { - markClassFields(node); + node.transformFlags = + TransformFlags.ContainsClassFields | + TransformFlags.HasComputedFlags; } + // trigger observers + onFinishNode(node); return node; } @@ -961,12 +997,15 @@ namespace ts { Debug.assert(token <= SyntaxKind.FirstLiteralToken || token >= SyntaxKind.LastLiteralToken, "Invalid token. Use 'createLiteralLikeNode' to create literals."); Debug.assert(token !== SyntaxKind.Identifier, "Invalid token. Use 'createIdentifier' to create identifiers"); const node = createBaseToken>(token); + // propagate flags and set markers if (!skipTransformationFlags) { switch (token) { case SyntaxKind.AsyncKeyword: // 'async' modifier is ES2017 (async functions) or ES2018 (async generators) - markES2017(node); - markES2018(node); + node.transformFlags = + TransformFlags.ContainsES2017 | + TransformFlags.ContainsES2018 | + TransformFlags.HasComputedFlags; break; case SyntaxKind.PublicKeyword: @@ -987,19 +1026,31 @@ namespace ts { case SyntaxKind.VoidKeyword: case SyntaxKind.UnknownKeyword: case SyntaxKind.UndefinedKeyword: // `undefined` is an Identifier in the expression case. - markTypeScript(node); + node.transformFlags = + TransformFlags.ContainsTypeScript | + TransformFlags.HasComputedFlags; break; case SyntaxKind.StaticKeyword: case SyntaxKind.SuperKeyword: - markES2015(node); + node.transformFlags = + TransformFlags.ContainsES2015 | + TransformFlags.HasComputedFlags; break; case SyntaxKind.ThisKeyword: // 'this' indicates a lexical 'this' - markLexicalThis(node); + node.transformFlags = + TransformFlags.ContainsLexicalThis | + TransformFlags.HasComputedFlags; + break; + default: + node.transformFlags = + TransformFlags.HasComputedFlags; break; } } - return finish(node); + // trigger observers + onFinishNode(node); + return node; } // @@ -1109,6 +1160,8 @@ namespace ts { ); setChild(node, node.constraint = constraint); setChild(node, node.default = defaultType); + // extraneous nodes set by the parser + node.expression = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -1134,27 +1187,53 @@ namespace ts { type?: TypeNode, initializer?: Expression ) { - const node = createBaseVariableLikeDeclaration( - SyntaxKind.Parameter, - decorators, - modifiers, - name, - type, - initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer) - ); - setChild(node, node.dotDotDotToken = dotDotDotToken); - setChild(node, node.questionToken = questionToken); + const node = createBaseNode(SyntaxKind.Parameter); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.dotDotDotToken = dotDotDotToken; + node.name = asName(name); + node.questionToken = questionToken; + node.type = type; + node.initializer = initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); + node.jsDoc = undefined; + // propagate flags and markers if (!skipTransformationFlags) { if (isThisIdentifier(node.name)) { - markTypeScriptOnly(node); + node.transformFlags = + TransformFlags.ContainsTypeScript | + TransformFlags.HasComputedFlags; } else { - if (questionToken) markTypeScript(node); - if (hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier)) markTypeScriptClassSyntax(node); - if (initializer || dotDotDotToken) markES2015(node); + node.transformFlags = + propagateChildrenFlags(node.decorators) | + propagateChildrenFlags(node.modifiers) | + propagateChildFlags(node.dotDotDotToken) | + propagateChildFlags(node.name) | + propagateChildFlags(node.questionToken) | + propagateChildFlags(node.type) | + propagateChildFlags(node.initializer) | + (node.type || node.questionToken ? + TransformFlags.ContainsTypeScript : + TransformFlags.None) | + (modifiersToFlags(node.modifiers) & ModifierFlags.ParameterPropertyModifier ? + TransformFlags.ContainsTypeScriptClassSyntax : + TransformFlags.None) | + (node.initializer || node.dotDotDotToken ? + TransformFlags.ContainsES2015 : + TransformFlags.None) | + TransformFlags.HasComputedFlags; } } - return finish(node); + // trigger observers + onSetChildren(node, node.decorators); + onSetChildren(node, node.modifiers); + onSetChild(node, node.dotDotDotToken); + onSetChild(node, node.name); + onSetChild(node, node.questionToken); + onSetChild(node, node.type); + onSetChild(node, node.initializer); + onFinishNode(node); + return node; } // @api @@ -1216,6 +1295,9 @@ namespace ts { ); setChild(node, node.type = type); setChild(node, node.questionToken = questionToken); + // extraneous nodes set by the parser + node.initializer = undefined; + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -1247,26 +1329,44 @@ namespace ts { type: TypeNode | undefined, initializer: Expression | undefined ) { - const node = createBaseVariableLikeDeclaration( - SyntaxKind.PropertyDeclaration, - decorators, - modifiers, - name, - type, - initializer - ); - setChild(node, node.questionToken = questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.QuestionToken ? questionOrExclamationToken : undefined); - setChild(node, node.exclamationToken = questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.ExclamationToken ? questionOrExclamationToken : undefined); + const node = createBaseNode(SyntaxKind.PropertyDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.name = asName(name); + node.questionToken = questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.QuestionToken ? questionOrExclamationToken : undefined; + node.exclamationToken = questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.ExclamationToken ? questionOrExclamationToken : undefined; + node.type = type; + node.initializer = initializer; + node.jsDoc = undefined; + // propagate flags and set markers if (!skipTransformationFlags) { - if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) { - markTypeScriptClassSyntax(node); - } - markClassFields(node); - if (questionOrExclamationToken || hasSyntacticModifier(node, ModifierFlags.Ambient)) { - markTypeScript(node); - } - } - return finish(node); + node.transformFlags = + propagateChildrenFlags(node.decorators) | + propagateChildrenFlags(node.modifiers) | + propagateChildFlags(node.name) | + propagateChildFlags(node.questionToken) | + propagateChildFlags(node.exclamationToken) | + propagateChildFlags(node.type) | + propagateChildFlags(node.initializer) | + (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer) ? + TransformFlags.ContainsTypeScriptClassSyntax : + TransformFlags.None) | + (node.questionToken || node.exclamationToken || node.type || modifiersToFlags(node.modifiers) & ModifierFlags.Ambient ? + TransformFlags.ContainsTypeScript : + TransformFlags.None) | + TransformFlags.ContainsClassFields | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChildren(node, node.decorators); + onSetChildren(node, node.modifiers); + onSetChild(node, node.name); + onSetChild(node, node.questionToken); + onSetChild(node, node.exclamationToken); + onSetChild(node, node.type); + onSetChild(node, node.initializer); + onFinishNode(node); + return node; } // @api @@ -1309,6 +1409,8 @@ namespace ts { type ); setChild(node, node.questionToken = questionToken); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -1347,36 +1449,55 @@ namespace ts { type: TypeNode | undefined, body: Block | undefined ) { - const node = createBaseFunctionLikeDeclaration( - SyntaxKind.MethodDeclaration, - decorators, - modifiers, - name, - typeParameters, - parameters, - type, - body - ); - setChild(node, node.asteriskToken = asteriskToken); - setChild(node, node.questionToken = questionToken); + const node = createBaseNode(SyntaxKind.MethodDeclaration); + node.decorators = asNodeArray(decorators); + node.modifiers = asNodeArray(modifiers); + node.asteriskToken = asteriskToken; + node.name = asName(name); + node.questionToken = questionToken; + node.exclamationToken = undefined; // extraneous node set by the parser + node.typeParameters = asNodeArray(typeParameters); + node.parameters = createNodeArray(parameters); + node.type = type; + node.body = body; + node.jsDoc = undefined; // extraneous node set by the parser + // propagate flags and set markers if (!skipTransformationFlags) { - if (questionToken) { - markTypeScript(node); - } - if (hasSyntacticModifier(node, ModifierFlags.Async)) { - if (asteriskToken) { - markES2018(node); - } - else { - markES2017(node); - } - } - else if (asteriskToken) { - markGenerator(node); - } - markES2015(node); - } - return finish(node); + node.transformFlags = + propagateChildrenFlags(node.decorators) | + propagateChildrenFlags(node.modifiers) | + propagateChildFlags(node.asteriskToken) | + propagateChildFlags(node.name) | + propagateChildFlags(node.questionToken) | + propagateChildrenFlags(node.typeParameters) | + propagateChildrenFlags(node.parameters) | + propagateChildFlags(node.type) | + propagateChildFlags(node.body) | + (node.questionToken || node.typeParameters || node.type || !node.body ? + TransformFlags.ContainsTypeScript : + TransformFlags.None) | + (modifiersToFlags(node.modifiers) & ModifierFlags.Async ? + asteriskToken ? + TransformFlags.ContainsES2018 : + TransformFlags.ContainsES2017 : + asteriskToken ? + TransformFlags.ContainsGenerator : + TransformFlags.None) | + TransformFlags.ContainsES2015 | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChildren(node, node.decorators); + onSetChildren(node, node.modifiers); + onSetChild(node, node.asteriskToken); + onSetChild(node, node.name); + onSetChild(node, node.questionToken); + onSetChildren(node, node.typeParameters); + onSetChildren(node, node.parameters); + onSetChild(node, node.type); + onSetChild(node, node.body); + onFinishNode(node); + return node; } // @api @@ -1422,6 +1543,8 @@ namespace ts { /*type*/ undefined, body ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markES2015(node); } @@ -1463,6 +1586,8 @@ namespace ts { type, body ); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finish(node); } @@ -1504,6 +1629,8 @@ namespace ts { /*type*/ undefined, body ); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finish(node); } @@ -1540,6 +1667,8 @@ namespace ts { parameters, type ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -1575,6 +1704,8 @@ namespace ts { parameters, type ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -1611,6 +1742,8 @@ namespace ts { parameters, type ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -1666,12 +1799,19 @@ namespace ts { // @api function createTypeReferenceNode(typeName: string | EntityName, typeArguments: readonly TypeNode[] | undefined) { const node = createBaseNode(SyntaxKind.TypeReference); - setChild(node, node.typeName = asName(typeName)); - setChildren(node, node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments))); + node.typeName = asName(typeName); + node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments)); + // propagate flags and set markers if (!skipTransformationFlags) { - markTypeScriptOnly(node); - } - return finish(node); + node.transformFlags = + TransformFlags.ContainsTypeScript | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChild(node, node.typeName); + onSetChildren(node, node.typeArguments); + onFinishNode(node); + return node; } // @api @@ -1697,6 +1837,8 @@ namespace ts { parameters, type ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -1732,6 +1874,8 @@ namespace ts { parameters, type ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -2149,9 +2293,18 @@ namespace ts { // @api function createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean) { const node = createBaseNode(SyntaxKind.ObjectLiteralExpression); - setChildren(node, node.properties = createNodeArray(properties)); - if (multiLine) node.multiLine = true; - return finish(node); + node.properties = createNodeArray(properties); + node.multiLine = multiLine; + // propagate flags and set markers + if (!skipTransformationFlags) { + node.transformFlags = + propagateChildrenFlags(node.properties) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChildren(node, node.properties); + onFinishNode(node); + return node; } // @api @@ -2161,20 +2314,48 @@ namespace ts { : reuse(node); } - // @api - function createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier) { + function createPropertyAccessExpressionBase( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: string | Identifier | PrivateIdentifier, + isOptionalChain: boolean + ) { const node = createBaseNode(SyntaxKind.PropertyAccessExpression); - setChild(node, node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression)); - setChild(node, node.name = asName(name)); + if (isOptionalChain) node.flags |= NodeFlags.OptionalChain; + node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression) + node.questionDotToken = questionDotToken; + node.name = asName(name); + // propagate flags and markers if (!skipTransformationFlags) { - // super method calls require a lexical 'this' - // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators - if (expression.kind === SyntaxKind.SuperKeyword) { - markES2017(node); - markES2018(node); - } - } - return finish(node); + node.transformFlags = + propagateChildFlags(node.expression) | + propagateChildFlags(node.name) | + // super method calls require a lexical 'this' + // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators + (isSuperKeyword(expression) ? + TransformFlags.ContainsES2017 | TransformFlags.ContainsES2018 : + TransformFlags.None) | + (isOptionalChain ? + TransformFlags.ContainsES2020 : + TransformFlags.None) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChild(node, node.expression); + onSetChild(node, node.questionDotToken); + onSetChild(node, node.name); + onFinishNode(node); + return node; + } + + // @api + function createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier) { + return createPropertyAccessExpressionBase( + expression, + /*questionDotToken*/ undefined, + name, + /*isOptionalChain*/ false + ); } // @api @@ -2190,15 +2371,12 @@ namespace ts { // @api function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) { - const node = createBaseNode(SyntaxKind.PropertyAccessExpression); - node.flags |= NodeFlags.OptionalChain; - setChild(node, node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression)); - setChild(node, node.questionDotToken = questionDotToken); - setChild(node, node.name = asName(name)); - if (!skipTransformationFlags) { - markES2020(node); - } - return finish(node); + return createPropertyAccessExpressionBase( + expression, + questionDotToken, + name, + /*isOptionalChain*/ true + ); } // @api @@ -2217,6 +2395,7 @@ namespace ts { function createElementAccessExpression(expression: Expression, index: number | Expression) { const node = createBaseNode(SyntaxKind.ElementAccessExpression); setChild(node, node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression)); + node.questionDotToken = undefined; setChild(node, node.argumentExpression = asExpression(index)); if (!skipTransformationFlags) { // super method calls require a lexical 'this' @@ -2265,24 +2444,58 @@ namespace ts { : node; } - // @api - function createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function createCallExpressionBase( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + isOptionalChain: boolean + ) { const node = createBaseNode(SyntaxKind.CallExpression); - setChild(node, node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression)); - setChildren(node, node.typeArguments = asNodeArray(typeArguments)); - setChildren(node, node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray))); + if (isOptionalChain) node.flags |= NodeFlags.OptionalChain; + node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); + node.questionDotToken = questionDotToken; + node.typeArguments = asNodeArray(typeArguments); + node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray)); if (!skipTransformationFlags) { - if (typeArguments) { - markTypeScript(node); - } - if (expression.kind === SyntaxKind.ImportKeyword) { - markDynamicImport(node); - } - if (isSuperProperty(expression)) { - markLexicalThis(node); - } - } - return finish(node); + // propagate flags and markers + node.transformFlags = + propagateChildFlags(node.expression) | + propagateChildFlags(node.questionDotToken) | + propagateChildrenFlags(node.typeArguments) | + propagateChildrenFlags(node.arguments) | + (node.typeArguments ? + TransformFlags.ContainsTypeScript : + TransformFlags.None) | + (isImportKeyword(node.expression) ? + TransformFlags.ContainsDynamicImport : + TransformFlags.None) | + (isSuperProperty(node.expression) ? + TransformFlags.ContainsLexicalThis : + TransformFlags.None) | + (isOptionalChain ? + TransformFlags.ContainsES2020 : + TransformFlags.None) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChild(node, node.expression); + onSetChild(node, node.questionDotToken); + onSetChildren(node, node.typeArguments); + onSetChildren(node, node.arguments); + onFinishNode(node); + return node; + } + + // @api + function createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + return createCallExpressionBase( + expression, + /*questionDotToken*/ undefined, + typeArguments, + argumentsArray, + /*isOptionalChain*/ false + ); } // @api @@ -2299,22 +2512,13 @@ namespace ts { // @api function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { - const node = createBaseNode(SyntaxKind.CallExpression); - node.flags |= NodeFlags.OptionalChain; - setChild(node, node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression)); - setChild(node, node.questionDotToken = questionDotToken); - setChildren(node, node.typeArguments = asNodeArray(typeArguments)); - setChildren(node, node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray))); - if (!skipTransformationFlags) { - markES2020(node); - if (typeArguments) { - markTypeScript(node); - } - if (isSuperProperty(expression)) { - markLexicalThis(node); - } - } - return finish(node); + return createCallExpressionBase( + expression, + questionDotToken, + typeArguments, + argumentsArray, + /*isOptionalChain*/ true + ) as CallChain; } // @api @@ -2357,6 +2561,8 @@ namespace ts { setChild(node, node.tag = parenthesizerRules().parenthesizeLeftSideOfAccess(tag)); setChildren(node, node.typeArguments = asNodeArray(typeArguments)); setChild(node, node.template = template); + // extraneous nodes set by the parser + node.questionDotToken = undefined; if (!skipTransformationFlags) { markES2015(node); if (typeArguments) { @@ -2401,6 +2607,8 @@ namespace ts { function createParenthesizedExpression(expression: Expression) { const node = createBaseNode(SyntaxKind.ParenthesizedExpression); setChild(node, node.expression = expression); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finish(node); } @@ -2432,6 +2640,8 @@ namespace ts { body ); setChild(node, node.asteriskToken = asteriskToken); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { if (typeParameters) { markTypeScript(node); @@ -2493,6 +2703,8 @@ namespace ts { parenthesizerRules().parenthesizeConciseBodyOfArrowFunction(body) ); setChild(node, node.equalsGreaterThanToken = equalsGreaterThanToken || createToken(SyntaxKind.EqualsGreaterThanToken)); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { if (hasSyntacticModifier(node, ModifierFlags.Async)) markES2017(node); markES2015(node); @@ -2616,29 +2828,39 @@ namespace ts { const node = createBaseNode(SyntaxKind.BinaryExpression); const operatorToken = asToken(operator); const operatorKind = operatorToken.kind; - setChild(node, node.left = parenthesizerRules().parenthesizeLeftSideOfBinary(operatorKind, left)); - setChild(node, node.operatorToken = operatorToken); - setChild(node, node.right = parenthesizerRules().parenthesizeRightSideOfBinary(operatorKind, node.left, right)); + node.left = parenthesizerRules().parenthesizeLeftSideOfBinary(operatorKind, left); + node.operatorToken = operatorToken; + node.right = parenthesizerRules().parenthesizeRightSideOfBinary(operatorKind, node.left, right); + // propagate flags and set markers if (!skipTransformationFlags) { - if (operatorKind === SyntaxKind.QuestionQuestionToken) { - markES2020(node); - } - else if (operatorKind === SyntaxKind.EqualsToken) { - if (node.left.kind === SyntaxKind.ObjectLiteralExpression) { - markES2015(node); - markES2018(node); - markDestructuringAssignment(node); - } - else if (node.left.kind === SyntaxKind.ArrayLiteralExpression) { - markES2015(node); - markDestructuringAssignment(node); - } - } - else if (operatorKind === SyntaxKind.AsteriskAsteriskToken || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken) { - markES2016(node); - } - } - return finish(node); + node.transformFlags = + propagateChildFlags(node.left) | + propagateChildFlags(node.operatorToken) | + propagateChildFlags(node.right) | + (operatorKind === SyntaxKind.QuestionQuestionToken ? + TransformFlags.ContainsES2020 : + TransformFlags.None) | + (operatorKind === SyntaxKind.AsteriskAsteriskToken || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken ? + TransformFlags.ContainsES2016 : + TransformFlags.None) | + (operatorKind === SyntaxKind.EqualsToken ? + isObjectLiteralExpression(node.left) ? + TransformFlags.ContainsDestructuringAssignment | + TransformFlags.ContainsES2015 | + TransformFlags.ContainsES2018 : + isArrayLiteralExpression(node.left) ? + TransformFlags.ContainsDestructuringAssignment | + TransformFlags.ContainsES2015 : + TransformFlags.None : + TransformFlags.None) | + TransformFlags.HasComputedFlags; + } + // trigger observers + setChild(node, node.left); + setChild(node, node.operatorToken); + setChild(node, node.right); + onFinishNode(node); + return node; } // @api @@ -2814,6 +3036,8 @@ namespace ts { heritageClauses, members ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markES2015(node); } @@ -2986,9 +3210,18 @@ namespace ts { // @api function createBlock(statements: readonly Statement[], multiLine?: boolean): Block { const node = createBaseNode(SyntaxKind.Block); - setChildren(node, node.statements = createNodeArray(statements)); - if (multiLine) node.multiLine = multiLine; - return finish(node); + node.statements = createNodeArray(statements); + node.multiLine = multiLine; + // propagate flags and set markers + if (!skipTransformationFlags) { + node.transformFlags = + propagateChildrenFlags(node.statements) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChildren(node, node.statements); + onFinishNode(node); + return node; } // @api @@ -3002,6 +3235,8 @@ namespace ts { function createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]) { const node = createBaseDeclaration(SyntaxKind.VariableStatement, /*decorators*/ undefined, modifiers); setChild(node, node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { if (hasSyntacticModifier(node, ModifierFlags.Ambient)) { markTypeScriptOnly(node); @@ -3026,8 +3261,18 @@ namespace ts { // @api function createExpressionStatement(expression: Expression): ExpressionStatement { const node = createBaseNode(SyntaxKind.ExpressionStatement); - setChild(node, node.expression = parenthesizerRules().parenthesizeExpressionOfExpressionStatement(expression)); - return finish(node); + node.expression = parenthesizerRules().parenthesizeExpressionOfExpressionStatement(expression); + node.jsDoc = undefined; // extraneous node set by the parser + // propagate flags and set markers + if (!skipTransformationFlags) { + node.transformFlags = + propagateChildFlags(node.expression) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChild(node, node.expression); + onFinishNode(node); + return node; } // @api @@ -3239,6 +3484,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.LabeledStatement); setChild(node, node.label = asName(label)); setChild(node, node.statement = asEmbeddedStatement(statement)); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finish(node); } @@ -3288,22 +3535,38 @@ namespace ts { } // @api - function createVariableDeclaration(name: string | BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { - const node = createBaseVariableLikeDeclaration( - SyntaxKind.VariableDeclaration, - /*decorators*/ undefined, - /*modifiers*/ undefined, - name, - type, - initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer) - ); - setChild(node, node.exclamationToken = exclamationToken); + function createVariableDeclaration( + name: string | BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined + ) { + const node = createBaseNode(SyntaxKind.VariableDeclaration); + node.decorators = undefined; + node.modifiers = undefined; + node.name = asName(name); + node.exclamationToken = exclamationToken; + node.type = type; + node.initializer = initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); + // propagate flags and set markers if (!skipTransformationFlags) { - if (exclamationToken) { - markTypeScript(node); - } - } - return finish(node); + node.transformFlags = + propagateChildFlags(node.name) | + propagateChildFlags(node.exclamationToken) | + propagateChildFlags(node.type) | + propagateChildFlags(node.initializer) | + (node.exclamationToken || node.type ? + TransformFlags.ContainsTypeScript : + TransformFlags.None) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChild(node, node.name); + onSetChild(node, node.exclamationToken); + onSetChild(node, node.type); + onSetChild(node, node.initializer); + onFinishNode(node); + return node; } // @api @@ -3360,6 +3623,8 @@ namespace ts { body ); setChild(node, node.asteriskToken = asteriskToken); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { if (!body || hasSyntacticModifier(node, ModifierFlags.Ambient)) { markTypeScriptOnly(node); @@ -3424,6 +3689,8 @@ namespace ts { heritageClauses, members ); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { if (hasSyntacticModifier(node, ModifierFlags.Ambient)) { markTypeScriptOnly(node); @@ -3476,6 +3743,8 @@ namespace ts { heritageClauses ); setChildren(node, node.members = createNodeArray(members)); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -3518,6 +3787,8 @@ namespace ts { typeParameters ); setChild(node, node.type = type); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -3556,6 +3827,8 @@ namespace ts { name ); setChildren(node, node.members = createNodeArray(members)); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScript(node); } @@ -3593,6 +3866,8 @@ namespace ts { node.flags |= flags & (NodeFlags.Namespace | NodeFlags.NestedNamespace | NodeFlags.GlobalAugmentation); setChild(node, node.name = name); setChild(node, node.body = body); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { if (hasSyntacticModifier(node, ModifierFlags.Ambient)) { markTypeScriptOnly(node); @@ -3652,6 +3927,10 @@ namespace ts { function createNamespaceExportDeclaration(name: string | Identifier) { const node = createBaseNode(SyntaxKind.NamespaceExportDeclaration); setChild(node, node.name = asName(name)); + // extraneous nodes set by the parser + node.decorators = undefined; + node.modifiers = undefined; + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScriptOnly(node); } @@ -3679,6 +3958,8 @@ namespace ts { name ); setChild(node, node.moduleReference = moduleReference); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { if (moduleReference.kind !== SyntaxKind.ExternalModuleReference) markTypeScript(node); } @@ -3715,6 +3996,8 @@ namespace ts { ); setChild(node, node.importClause = importClause); setChild(node, node.moduleSpecifier = moduleSpecifier); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finish(node); } @@ -3834,6 +4117,8 @@ namespace ts { setChild(node, node.expression = isExportEquals ? parenthesizerRules().parenthesizeRightSideOfBinary(SyntaxKind.EqualsToken, /*leftSide*/ undefined, expression) : parenthesizerRules().parenthesizeExpressionOfExportDefault(expression)); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finish(node); } @@ -3867,6 +4152,8 @@ namespace ts { node.isTypeOnly = isTypeOnly; setChild(node, node.exportClause = exportClause); setChild(node, node.moduleSpecifier = moduleSpecifier); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finish(node); } @@ -4011,6 +4298,8 @@ namespace ts { parameters, type ); + // extraneous nodes set by the parser + node.jsDoc = undefined; return finishJSDoc(node); } @@ -4632,10 +4921,25 @@ namespace ts { // @api function createPropertyAssignment(name: string | PropertyName, initializer: Expression) { const node = createBaseNode(SyntaxKind.PropertyAssignment); - setChild(node, node.name = asName(name)); - setChild(node, node.questionToken = undefined); - setChild(node, node.initializer = parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer)); - return finish(node); + node.decorators = undefined; // extraneous node set by the parser + node.modifiers = undefined; // extraneous node set by the parser + node.name = asName(name) + node.questionToken = undefined; // extraneous node set by the parser + node.exclamationToken = undefined; // extraneous node set by the parser + node.initializer = parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer) + node.jsDoc = undefined; // extraneous node set by the parser + // propagate flags and markers + if (!skipTransformationFlags) { + node.transformFlags = + propagateChildFlags(node.name) | + propagateChildFlags(node.initializer) | + TransformFlags.HasComputedFlags; + } + // trigger observers + onSetChild(node, node.name); + onSetChild(node, node.initializer); + onFinishNode(node); + return node; } function finishUpdatePropertyAssignment(updated: Mutable, original: PropertyAssignment) { @@ -4666,6 +4970,11 @@ namespace ts { setChild(node, node.objectAssignmentInitializer = objectAssignmentInitializer !== undefined ? parenthesizerRules().parenthesizeExpressionForDisallowedComma(objectAssignmentInitializer) : undefined); + // extraneous nodes set by the parser + node.equalsToken = undefined; + node.questionToken = undefined; + node.exclamationToken = undefined; + node.jsDoc = undefined; if (!skipTransformationFlags) { markES2015(node); } @@ -4694,6 +5003,8 @@ namespace ts { function createSpreadAssignment(expression: Expression) { const node = createBaseNode(SyntaxKind.SpreadAssignment); setChild(node, node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression)); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markES2018(node); markObjectRestOrSpread(node); @@ -4717,6 +5028,8 @@ namespace ts { const node = createBaseNode(SyntaxKind.EnumMember); setChild(node, node.name = asName(name)); setChild(node, node.initializer = initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer)); + // extraneous nodes set by the parser + node.jsDoc = undefined; if (!skipTransformationFlags) { markTypeScript(node); } @@ -5920,16 +6233,11 @@ namespace ts { const markBlockScopedBinding = createFlagMarker(TransformFlags.ContainsBlockScopedBinding); const markRestOrSpread = createFlagMarker(TransformFlags.ContainsRestOrSpread); const markObjectRestOrSpread = createFlagMarker(TransformFlags.ContainsObjectRestOrSpread); - const markDestructuringAssignment = createFlagMarker(TransformFlags.ContainsDestructuringAssignment); const markComputedPropertyName = createFlagMarker(TransformFlags.ContainsComputedPropertyName); - const markLexicalThis = createFlagMarker(TransformFlags.ContainsLexicalThis); - const markDynamicImport = createFlagMarker(TransformFlags.ContainsDynamicImport); const markGenerator = createFlagMarker(TransformFlags.ContainsGenerator); const markYield = createFlagMarker(TransformFlags.ContainsYield); const markHoistedDeclarationOrCompletion = createFlagMarker(TransformFlags.ContainsHoistedDeclarationOrCompletion); - const markClassFields = createFlagMarker(TransformFlags.ContainsClassFields); const markES2015 = createFlagMarker(TransformFlags.ContainsES2015); - const markES2016 = createFlagMarker(TransformFlags.ContainsES2016); const markES2017 = createFlagMarker(TransformFlags.ContainsES2017); const markES2018 = createFlagMarker(TransformFlags.ContainsES2018); const markES2019 = createFlagMarker(TransformFlags.ContainsES2019); @@ -6024,13 +6332,14 @@ namespace ts { return transformFlags | (node.transformFlags & TransformFlags.PropertyNamePropagatingFlags); } - function propagateChildFlags(child: Node): TransformFlags { + function propagateChildFlags(child: Node | undefined): TransformFlags { + if (!child) return TransformFlags.None; const childFlags = child.transformFlags & ~TransformFlags.HasComputedFlags & ~getTransformFlagsSubtreeExclusions(child.kind); return isNamedDeclaration(child) && isPropertyName(child.name) ? propagatePropertyNameFlags(child.name, childFlags) : childFlags; } - function propagateChildrenFlags(children: NodeArray): TransformFlags { - return children.transformFlags & ~TransformFlags.HasComputedFlags; + function propagateChildrenFlags(children: NodeArray | undefined): TransformFlags { + return children ? children.transformFlags & ~TransformFlags.HasComputedFlags : TransformFlags.None; } function aggregateChildrenFlags(children: NodeArray) { diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index f94b223236dec..086bea9bd4879 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -59,6 +59,16 @@ namespace ts { return node.kind === SyntaxKind.PrivateIdentifier; } + // Tokens + + export function isSuperKeyword(node: Node): node is Token { + return node.kind === SyntaxKind.SuperKeyword; + } + + export function isImportKeyword(node: Node): node is Token { + return node.kind === SyntaxKind.ImportKeyword; + } + // Signature elements export function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration { diff --git a/src/compiler/forEachChild.ts b/src/compiler/forEachChild.ts new file mode 100644 index 0000000000000..24e1a55090813 --- /dev/null +++ b/src/compiler/forEachChild.ts @@ -0,0 +1,558 @@ +namespace ts { + function visitNode(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { + return node && cbNode(node); + } + + function visitNodes(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray) => T | undefined) | undefined, nodes: NodeArray | undefined): T | undefined { + if (nodes) { + if (cbNodes) { + return cbNodes(nodes); + } + for (const node of nodes) { + const result = cbNode(node); + if (result) { + return result; + } + } + } + } + + /** + * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes + * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, + * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns + * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. + * + * @param node a given node to visit its children + * @param cbNode a callback to be invoked for all child nodes + * @param cbNodes a callback to be invoked for embedded array + * + * @remarks `forEachChild` must visit the children of a node in the order + * that they appear in the source code. The language service depends on this property to locate nodes by position. + */ + export function forEachChild(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + if (!node || node.kind <= SyntaxKind.LastToken) { + return; + } + switch (node.kind) { + case SyntaxKind.QualifiedName: + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).right); + case SyntaxKind.TypeParameter: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).constraint) || + visitNode(cbNode, (node).default) || + visitNode(cbNode, (node).expression); + case SyntaxKind.ShorthandPropertyAssignment: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).exclamationToken) || + visitNode(cbNode, (node).equalsToken) || + visitNode(cbNode, (node).objectAssignmentInitializer); + case SyntaxKind.SpreadAssignment: + return visitNode(cbNode, (node).expression); + case SyntaxKind.Parameter: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).dotDotDotToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.PropertyDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).exclamationToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.PropertySignature: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.PropertyAssignment: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.VariableDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).exclamationToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.BindingElement: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).dotDotDotToken) || + visitNode(cbNode, (node).propertyName) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).parameters) || + visitNode(cbNode, (node).type); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).exclamationToken) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).parameters) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).equalsGreaterThanToken) || + visitNode(cbNode, (node).body); + case SyntaxKind.TypeReference: + return visitNode(cbNode, (node).typeName) || + visitNodes(cbNode, cbNodes, (node).typeArguments); + case SyntaxKind.TypePredicate: + return visitNode(cbNode, (node).assertsModifier) || + visitNode(cbNode, (node).parameterName) || + visitNode(cbNode, (node).type); + case SyntaxKind.TypeQuery: + return visitNode(cbNode, (node).exprName); + case SyntaxKind.TypeLiteral: + return visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.ArrayType: + return visitNode(cbNode, (node).elementType); + case SyntaxKind.TupleType: + return visitNodes(cbNode, cbNodes, (node).elementTypes); + case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: + return visitNodes(cbNode, cbNodes, (node).types); + case SyntaxKind.ConditionalType: + return visitNode(cbNode, (node).checkType) || + visitNode(cbNode, (node).extendsType) || + visitNode(cbNode, (node).trueType) || + visitNode(cbNode, (node).falseType); + case SyntaxKind.InferType: + return visitNode(cbNode, (node).typeParameter); + case SyntaxKind.ImportType: + return visitNode(cbNode, (node).argument) || + visitNode(cbNode, (node).qualifier) || + visitNodes(cbNode, cbNodes, (node).typeArguments); + case SyntaxKind.ParenthesizedType: + case SyntaxKind.TypeOperator: + return visitNode(cbNode, (node).type); + case SyntaxKind.IndexedAccessType: + return visitNode(cbNode, (node).objectType) || + visitNode(cbNode, (node).indexType); + case SyntaxKind.MappedType: + return visitNode(cbNode, (node).readonlyToken) || + visitNode(cbNode, (node).typeParameter) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type); + case SyntaxKind.LiteralType: + return visitNode(cbNode, (node).literal); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + return visitNodes(cbNode, cbNodes, (node).elements); + case SyntaxKind.ArrayLiteralExpression: + return visitNodes(cbNode, cbNodes, (node).elements); + case SyntaxKind.ObjectLiteralExpression: + return visitNodes(cbNode, cbNodes, (node).properties); + case SyntaxKind.PropertyAccessExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).questionDotToken) || + visitNode(cbNode, (node).name); + case SyntaxKind.ElementAccessExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).questionDotToken) || + visitNode(cbNode, (node).argumentExpression); + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).questionDotToken) || + visitNodes(cbNode, cbNodes, (node).typeArguments) || + visitNodes(cbNode, cbNodes, (node).arguments); + case SyntaxKind.TaggedTemplateExpression: + return visitNode(cbNode, (node).tag) || + visitNode(cbNode, (node).questionDotToken) || + visitNodes(cbNode, cbNodes, (node).typeArguments) || + visitNode(cbNode, (node).template); + case SyntaxKind.TypeAssertionExpression: + return visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).expression); + case SyntaxKind.ParenthesizedExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.DeleteExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.TypeOfExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.VoidExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.PrefixUnaryExpression: + return visitNode(cbNode, (node).operand); + case SyntaxKind.YieldExpression: + return visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).expression); + case SyntaxKind.AwaitExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.PostfixUnaryExpression: + return visitNode(cbNode, (node).operand); + case SyntaxKind.BinaryExpression: + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).operatorToken) || + visitNode(cbNode, (node).right); + case SyntaxKind.AsExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).type); + case SyntaxKind.NonNullExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.MetaProperty: + return visitNode(cbNode, (node).name); + case SyntaxKind.ConditionalExpression: + return visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).whenTrue) || + visitNode(cbNode, (node).colonToken) || + visitNode(cbNode, (node).whenFalse); + case SyntaxKind.SpreadElement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + return visitNodes(cbNode, cbNodes, (node).statements); + case SyntaxKind.SourceFile: + return visitNodes(cbNode, cbNodes, (node).statements) || + visitNode(cbNode, (node).endOfFileToken); + case SyntaxKind.VariableStatement: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).declarationList); + case SyntaxKind.VariableDeclarationList: + return visitNodes(cbNode, cbNodes, (node).declarations); + case SyntaxKind.ExpressionStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.IfStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).thenStatement) || + visitNode(cbNode, (node).elseStatement); + case SyntaxKind.DoStatement: + return visitNode(cbNode, (node).statement) || + visitNode(cbNode, (node).expression); + case SyntaxKind.WhileStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForStatement: + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).incrementor) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForInStatement: + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForOfStatement: + return visitNode(cbNode, (node).awaitModifier) || + visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ContinueStatement: + case SyntaxKind.BreakStatement: + return visitNode(cbNode, (node).label); + case SyntaxKind.ReturnStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.WithStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.SwitchStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).caseBlock); + case SyntaxKind.CaseBlock: + return visitNodes(cbNode, cbNodes, (node).clauses); + case SyntaxKind.CaseClause: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNode, cbNodes, (node).statements); + case SyntaxKind.DefaultClause: + return visitNodes(cbNode, cbNodes, (node).statements); + case SyntaxKind.LabeledStatement: + return visitNode(cbNode, (node).label) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ThrowStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.TryStatement: + return visitNode(cbNode, (node).tryBlock) || + visitNode(cbNode, (node).catchClause) || + visitNode(cbNode, (node).finallyBlock); + case SyntaxKind.CatchClause: + return visitNode(cbNode, (node).variableDeclaration) || + visitNode(cbNode, (node).block); + case SyntaxKind.Decorator: + return visitNode(cbNode, (node).expression); + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).heritageClauses) || + visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.InterfaceDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).heritageClauses) || + visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.TypeAliasDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNode(cbNode, (node).type); + case SyntaxKind.EnumDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.EnumMember: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.ModuleDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).body); + case SyntaxKind.ImportEqualsDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).moduleReference); + case SyntaxKind.ImportDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).importClause) || + visitNode(cbNode, (node).moduleSpecifier); + case SyntaxKind.ImportClause: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).namedBindings); + case SyntaxKind.NamespaceExportDeclaration: + return visitNode(cbNode, (node).name); + + case SyntaxKind.NamespaceImport: + return visitNode(cbNode, (node).name); + case SyntaxKind.NamespaceExport: + return visitNode(cbNode, (node).name); + case SyntaxKind.NamedImports: + case SyntaxKind.NamedExports: + return visitNodes(cbNode, cbNodes, (node).elements); + case SyntaxKind.ExportDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).exportClause) || + visitNode(cbNode, (node).moduleSpecifier); + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + return visitNode(cbNode, (node).propertyName) || + visitNode(cbNode, (node).name); + case SyntaxKind.ExportAssignment: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).expression); + case SyntaxKind.TemplateExpression: + return visitNode(cbNode, (node).head) || visitNodes(cbNode, cbNodes, (node).templateSpans); + case SyntaxKind.TemplateSpan: + return visitNode(cbNode, (node).expression) || visitNode(cbNode, (node).literal); + case SyntaxKind.ComputedPropertyName: + return visitNode(cbNode, (node).expression); + case SyntaxKind.HeritageClause: + return visitNodes(cbNode, cbNodes, (node).types); + case SyntaxKind.ExpressionWithTypeArguments: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNode, cbNodes, (node).typeArguments); + case SyntaxKind.ExternalModuleReference: + return visitNode(cbNode, (node).expression); + case SyntaxKind.MissingDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators); + case SyntaxKind.CommaListExpression: + return visitNodes(cbNode, cbNodes, (node).elements); + + case SyntaxKind.JsxElement: + return visitNode(cbNode, (node).openingElement) || + visitNodes(cbNode, cbNodes, (node).children) || + visitNode(cbNode, (node).closingElement); + case SyntaxKind.JsxFragment: + return visitNode(cbNode, (node).openingFragment) || + visitNodes(cbNode, cbNodes, (node).children) || + visitNode(cbNode, (node).closingFragment); + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxOpeningElement: + return visitNode(cbNode, (node).tagName) || + visitNodes(cbNode, cbNodes, (node).typeArguments) || + visitNode(cbNode, (node).attributes); + case SyntaxKind.JsxAttributes: + return visitNodes(cbNode, cbNodes, (node).properties); + case SyntaxKind.JsxAttribute: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.JsxSpreadAttribute: + return visitNode(cbNode, (node).expression); + case SyntaxKind.JsxExpression: + return visitNode(cbNode, (node as JsxExpression).dotDotDotToken) || + visitNode(cbNode, (node as JsxExpression).expression); + case SyntaxKind.JsxClosingElement: + return visitNode(cbNode, (node).tagName); + + case SyntaxKind.OptionalType: + case SyntaxKind.RestType: + case SyntaxKind.JSDocTypeExpression: + case SyntaxKind.JSDocNonNullableType: + case SyntaxKind.JSDocNullableType: + case SyntaxKind.JSDocOptionalType: + case SyntaxKind.JSDocVariadicType: + return visitNode(cbNode, (node).type); + case SyntaxKind.JSDocFunctionType: + return visitNodes(cbNode, cbNodes, (node).parameters) || + visitNode(cbNode, (node).type); + case SyntaxKind.JSDocComment: + return visitNodes(cbNode, cbNodes, (node).tags); + case SyntaxKind.JSDocParameterTag: + case SyntaxKind.JSDocPropertyTag: + return visitNode(cbNode, (node as JSDocTag).tagName) || + ((node as JSDocPropertyLikeTag).isNameFirst + ? visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).typeExpression) + : visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).name)); + case SyntaxKind.JSDocAuthorTag: + return visitNode(cbNode, (node as JSDocTag).tagName); + case SyntaxKind.JSDocImplementsTag: + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node).class); + case SyntaxKind.JSDocAugmentsTag: + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node).class); + case SyntaxKind.JSDocTemplateTag: + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node).constraint) || + visitNodes(cbNode, cbNodes, (node).typeParameters); + case SyntaxKind.JSDocTypedefTag: + return visitNode(cbNode, (node as JSDocTag).tagName) || + ((node as JSDocTypedefTag).typeExpression && + (node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression + ? visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).fullName) + : visitNode(cbNode, (node).fullName) || + visitNode(cbNode, (node).typeExpression)); + case SyntaxKind.JSDocCallbackTag: + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node as JSDocCallbackTag).fullName) || + visitNode(cbNode, (node as JSDocCallbackTag).typeExpression); + case SyntaxKind.JSDocReturnTag: + case SyntaxKind.JSDocTypeTag: + case SyntaxKind.JSDocThisTag: + case SyntaxKind.JSDocEnumTag: + return visitNode(cbNode, (node as JSDocTag).tagName) || + visitNode(cbNode, (node as JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag).typeExpression); + case SyntaxKind.JSDocSignature: + return forEach((node).typeParameters, cbNode) || + forEach((node).parameters, cbNode) || + visitNode(cbNode, (node).type); + case SyntaxKind.JSDocTypeLiteral: + return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode); + case SyntaxKind.JSDocTag: + case SyntaxKind.JSDocClassTag: + case SyntaxKind.JSDocPublicTag: + case SyntaxKind.JSDocPrivateTag: + case SyntaxKind.JSDocProtectedTag: + case SyntaxKind.JSDocReadonlyTag: + return visitNode(cbNode, (node as JSDocTag).tagName); + case SyntaxKind.PartiallyEmittedExpression: + return visitNode(cbNode, (node).expression); + } + } + + /** @internal */ + /** + * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes + * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally, + * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element. + * If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. + * + * @param node a given node to visit its children + * @param cbNode a callback to be invoked for all child nodes + * @param cbNodes a callback to be invoked for embedded array + * + * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found, + * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure. + */ + export function forEachChildRecursively(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray, parent: Node) => T | "skip" | undefined): T | undefined { + + const stack: Node[] = [rootNode]; + while (stack.length) { + const parent = stack.pop()!; + const res = visitAllPossibleChildren(parent, gatherPossibleChildren(parent)); + if (res) { + return res; + } + } + + return; + + function gatherPossibleChildren(node: Node) { + const children: (Node | NodeArray)[] = []; + forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal + return children; + + function addWorkItem(n: Node | NodeArray) { + children.unshift(n); + } + } + + function visitAllPossibleChildren(parent: Node, children: readonly (Node | NodeArray)[]) { + for (const child of children) { + if (isArray(child)) { + if (cbNodes) { + const res = cbNodes(child, parent); + if (res) { + if (res === "skip") continue; + return res; + } + } + + for (let i = child.length - 1; i >= 0; i--) { + const realChild = child[i]; + const res = cbNode(realChild, parent); + if (res) { + if (res === "skip") continue; + return res; + } + stack.push(realChild); + } + } + else { + stack.push(child); + const res = cbNode(child, parent); + if (res) { + if (res === "skip") continue; + return res; + } + } + } + } + } + +} \ No newline at end of file diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 63e26f2b2747f..78b3f76e742fa 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -29,24 +29,6 @@ namespace ts { /* @internal */ export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory); - function visitNode(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { - return node && cbNode(node); - } - - function visitNodes(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray) => T | undefined) | undefined, nodes: NodeArray | undefined): T | undefined { - if (nodes) { - if (cbNodes) { - return cbNodes(nodes); - } - for (const node of nodes) { - const result = cbNode(node); - if (result) { - return result; - } - } - } - } - /*@internal*/ export function isJSDocLikeText(text: string, start: number) { return text.charCodeAt(start + 1) === CharacterCodes.asterisk && @@ -54,544 +36,6 @@ namespace ts { text.charCodeAt(start + 3) !== CharacterCodes.slash; } - /** - * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes - * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, - * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns - * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. - * - * @param node a given node to visit its children - * @param cbNode a callback to be invoked for all child nodes - * @param cbNodes a callback to be invoked for embedded array - * - * @remarks `forEachChild` must visit the children of a node in the order - * that they appear in the source code. The language service depends on this property to locate nodes by position. - */ - export function forEachChild(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - if (!node || node.kind <= SyntaxKind.LastToken) { - return; - } - switch (node.kind) { - case SyntaxKind.QualifiedName: - return visitNode(cbNode, (node).left) || - visitNode(cbNode, (node).right); - case SyntaxKind.TypeParameter: - return visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).constraint) || - visitNode(cbNode, (node).default) || - visitNode(cbNode, (node).expression); - case SyntaxKind.ShorthandPropertyAssignment: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).exclamationToken) || - visitNode(cbNode, (node).equalsToken) || - visitNode(cbNode, (node).objectAssignmentInitializer); - case SyntaxKind.SpreadAssignment: - return visitNode(cbNode, (node).expression); - case SyntaxKind.Parameter: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).dotDotDotToken) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.PropertyDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).exclamationToken) || - visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.PropertySignature: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.PropertyAssignment: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.VariableDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).exclamationToken) || - visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.BindingElement: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).dotDotDotToken) || - visitNode(cbNode, (node).propertyName) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.FunctionType: - case SyntaxKind.ConstructorType: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.IndexSignature: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, (node).typeParameters) || - visitNodes(cbNode, cbNodes, (node).parameters) || - visitNode(cbNode, (node).type); - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.Constructor: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ArrowFunction: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).asteriskToken) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).exclamationToken) || - visitNodes(cbNode, cbNodes, (node).typeParameters) || - visitNodes(cbNode, cbNodes, (node).parameters) || - visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).equalsGreaterThanToken) || - visitNode(cbNode, (node).body); - case SyntaxKind.TypeReference: - return visitNode(cbNode, (node).typeName) || - visitNodes(cbNode, cbNodes, (node).typeArguments); - case SyntaxKind.TypePredicate: - return visitNode(cbNode, (node).assertsModifier) || - visitNode(cbNode, (node).parameterName) || - visitNode(cbNode, (node).type); - case SyntaxKind.TypeQuery: - return visitNode(cbNode, (node).exprName); - case SyntaxKind.TypeLiteral: - return visitNodes(cbNode, cbNodes, (node).members); - case SyntaxKind.ArrayType: - return visitNode(cbNode, (node).elementType); - case SyntaxKind.TupleType: - return visitNodes(cbNode, cbNodes, (node).elementTypes); - case SyntaxKind.UnionType: - case SyntaxKind.IntersectionType: - return visitNodes(cbNode, cbNodes, (node).types); - case SyntaxKind.ConditionalType: - return visitNode(cbNode, (node).checkType) || - visitNode(cbNode, (node).extendsType) || - visitNode(cbNode, (node).trueType) || - visitNode(cbNode, (node).falseType); - case SyntaxKind.InferType: - return visitNode(cbNode, (node).typeParameter); - case SyntaxKind.ImportType: - return visitNode(cbNode, (node).argument) || - visitNode(cbNode, (node).qualifier) || - visitNodes(cbNode, cbNodes, (node).typeArguments); - case SyntaxKind.ParenthesizedType: - case SyntaxKind.TypeOperator: - return visitNode(cbNode, (node).type); - case SyntaxKind.IndexedAccessType: - return visitNode(cbNode, (node).objectType) || - visitNode(cbNode, (node).indexType); - case SyntaxKind.MappedType: - return visitNode(cbNode, (node).readonlyToken) || - visitNode(cbNode, (node).typeParameter) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).type); - case SyntaxKind.LiteralType: - return visitNode(cbNode, (node).literal); - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - return visitNodes(cbNode, cbNodes, (node).elements); - case SyntaxKind.ArrayLiteralExpression: - return visitNodes(cbNode, cbNodes, (node).elements); - case SyntaxKind.ObjectLiteralExpression: - return visitNodes(cbNode, cbNodes, (node).properties); - case SyntaxKind.PropertyAccessExpression: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).questionDotToken) || - visitNode(cbNode, (node).name); - case SyntaxKind.ElementAccessExpression: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).questionDotToken) || - visitNode(cbNode, (node).argumentExpression); - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).questionDotToken) || - visitNodes(cbNode, cbNodes, (node).typeArguments) || - visitNodes(cbNode, cbNodes, (node).arguments); - case SyntaxKind.TaggedTemplateExpression: - return visitNode(cbNode, (node).tag) || - visitNode(cbNode, (node).questionDotToken) || - visitNodes(cbNode, cbNodes, (node).typeArguments) || - visitNode(cbNode, (node).template); - case SyntaxKind.TypeAssertionExpression: - return visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).expression); - case SyntaxKind.ParenthesizedExpression: - return visitNode(cbNode, (node).expression); - case SyntaxKind.DeleteExpression: - return visitNode(cbNode, (node).expression); - case SyntaxKind.TypeOfExpression: - return visitNode(cbNode, (node).expression); - case SyntaxKind.VoidExpression: - return visitNode(cbNode, (node).expression); - case SyntaxKind.PrefixUnaryExpression: - return visitNode(cbNode, (node).operand); - case SyntaxKind.YieldExpression: - return visitNode(cbNode, (node).asteriskToken) || - visitNode(cbNode, (node).expression); - case SyntaxKind.AwaitExpression: - return visitNode(cbNode, (node).expression); - case SyntaxKind.PostfixUnaryExpression: - return visitNode(cbNode, (node).operand); - case SyntaxKind.BinaryExpression: - return visitNode(cbNode, (node).left) || - visitNode(cbNode, (node).operatorToken) || - visitNode(cbNode, (node).right); - case SyntaxKind.AsExpression: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).type); - case SyntaxKind.NonNullExpression: - return visitNode(cbNode, (node).expression); - case SyntaxKind.MetaProperty: - return visitNode(cbNode, (node).name); - case SyntaxKind.ConditionalExpression: - return visitNode(cbNode, (node).condition) || - visitNode(cbNode, (node).questionToken) || - visitNode(cbNode, (node).whenTrue) || - visitNode(cbNode, (node).colonToken) || - visitNode(cbNode, (node).whenFalse); - case SyntaxKind.SpreadElement: - return visitNode(cbNode, (node).expression); - case SyntaxKind.Block: - case SyntaxKind.ModuleBlock: - return visitNodes(cbNode, cbNodes, (node).statements); - case SyntaxKind.SourceFile: - return visitNodes(cbNode, cbNodes, (node).statements) || - visitNode(cbNode, (node).endOfFileToken); - case SyntaxKind.VariableStatement: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).declarationList); - case SyntaxKind.VariableDeclarationList: - return visitNodes(cbNode, cbNodes, (node).declarations); - case SyntaxKind.ExpressionStatement: - return visitNode(cbNode, (node).expression); - case SyntaxKind.IfStatement: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).thenStatement) || - visitNode(cbNode, (node).elseStatement); - case SyntaxKind.DoStatement: - return visitNode(cbNode, (node).statement) || - visitNode(cbNode, (node).expression); - case SyntaxKind.WhileStatement: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).statement); - case SyntaxKind.ForStatement: - return visitNode(cbNode, (node).initializer) || - visitNode(cbNode, (node).condition) || - visitNode(cbNode, (node).incrementor) || - visitNode(cbNode, (node).statement); - case SyntaxKind.ForInStatement: - return visitNode(cbNode, (node).initializer) || - visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).statement); - case SyntaxKind.ForOfStatement: - return visitNode(cbNode, (node).awaitModifier) || - visitNode(cbNode, (node).initializer) || - visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).statement); - case SyntaxKind.ContinueStatement: - case SyntaxKind.BreakStatement: - return visitNode(cbNode, (node).label); - case SyntaxKind.ReturnStatement: - return visitNode(cbNode, (node).expression); - case SyntaxKind.WithStatement: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).statement); - case SyntaxKind.SwitchStatement: - return visitNode(cbNode, (node).expression) || - visitNode(cbNode, (node).caseBlock); - case SyntaxKind.CaseBlock: - return visitNodes(cbNode, cbNodes, (node).clauses); - case SyntaxKind.CaseClause: - return visitNode(cbNode, (node).expression) || - visitNodes(cbNode, cbNodes, (node).statements); - case SyntaxKind.DefaultClause: - return visitNodes(cbNode, cbNodes, (node).statements); - case SyntaxKind.LabeledStatement: - return visitNode(cbNode, (node).label) || - visitNode(cbNode, (node).statement); - case SyntaxKind.ThrowStatement: - return visitNode(cbNode, (node).expression); - case SyntaxKind.TryStatement: - return visitNode(cbNode, (node).tryBlock) || - visitNode(cbNode, (node).catchClause) || - visitNode(cbNode, (node).finallyBlock); - case SyntaxKind.CatchClause: - return visitNode(cbNode, (node).variableDeclaration) || - visitNode(cbNode, (node).block); - case SyntaxKind.Decorator: - return visitNode(cbNode, (node).expression); - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNodes(cbNode, cbNodes, (node).typeParameters) || - visitNodes(cbNode, cbNodes, (node).heritageClauses) || - visitNodes(cbNode, cbNodes, (node).members); - case SyntaxKind.InterfaceDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNodes(cbNode, cbNodes, (node).typeParameters) || - visitNodes(cbNode, cbNodes, (node).heritageClauses) || - visitNodes(cbNode, cbNodes, (node).members); - case SyntaxKind.TypeAliasDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNodes(cbNode, cbNodes, (node).typeParameters) || - visitNode(cbNode, (node).type); - case SyntaxKind.EnumDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNodes(cbNode, cbNodes, (node).members); - case SyntaxKind.EnumMember: - return visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.ModuleDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).body); - case SyntaxKind.ImportEqualsDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).moduleReference); - case SyntaxKind.ImportDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).importClause) || - visitNode(cbNode, (node).moduleSpecifier); - case SyntaxKind.ImportClause: - return visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).namedBindings); - case SyntaxKind.NamespaceExportDeclaration: - return visitNode(cbNode, (node).name); - - case SyntaxKind.NamespaceImport: - return visitNode(cbNode, (node).name); - case SyntaxKind.NamespaceExport: - return visitNode(cbNode, (node).name); - case SyntaxKind.NamedImports: - case SyntaxKind.NamedExports: - return visitNodes(cbNode, cbNodes, (node).elements); - case SyntaxKind.ExportDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).exportClause) || - visitNode(cbNode, (node).moduleSpecifier); - case SyntaxKind.ImportSpecifier: - case SyntaxKind.ExportSpecifier: - return visitNode(cbNode, (node).propertyName) || - visitNode(cbNode, (node).name); - case SyntaxKind.ExportAssignment: - return visitNodes(cbNode, cbNodes, node.decorators) || - visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, (node).expression); - case SyntaxKind.TemplateExpression: - return visitNode(cbNode, (node).head) || visitNodes(cbNode, cbNodes, (node).templateSpans); - case SyntaxKind.TemplateSpan: - return visitNode(cbNode, (node).expression) || visitNode(cbNode, (node).literal); - case SyntaxKind.ComputedPropertyName: - return visitNode(cbNode, (node).expression); - case SyntaxKind.HeritageClause: - return visitNodes(cbNode, cbNodes, (node).types); - case SyntaxKind.ExpressionWithTypeArguments: - return visitNode(cbNode, (node).expression) || - visitNodes(cbNode, cbNodes, (node).typeArguments); - case SyntaxKind.ExternalModuleReference: - return visitNode(cbNode, (node).expression); - case SyntaxKind.MissingDeclaration: - return visitNodes(cbNode, cbNodes, node.decorators); - case SyntaxKind.CommaListExpression: - return visitNodes(cbNode, cbNodes, (node).elements); - - case SyntaxKind.JsxElement: - return visitNode(cbNode, (node).openingElement) || - visitNodes(cbNode, cbNodes, (node).children) || - visitNode(cbNode, (node).closingElement); - case SyntaxKind.JsxFragment: - return visitNode(cbNode, (node).openingFragment) || - visitNodes(cbNode, cbNodes, (node).children) || - visitNode(cbNode, (node).closingFragment); - case SyntaxKind.JsxSelfClosingElement: - case SyntaxKind.JsxOpeningElement: - return visitNode(cbNode, (node).tagName) || - visitNodes(cbNode, cbNodes, (node).typeArguments) || - visitNode(cbNode, (node).attributes); - case SyntaxKind.JsxAttributes: - return visitNodes(cbNode, cbNodes, (node).properties); - case SyntaxKind.JsxAttribute: - return visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).initializer); - case SyntaxKind.JsxSpreadAttribute: - return visitNode(cbNode, (node).expression); - case SyntaxKind.JsxExpression: - return visitNode(cbNode, (node as JsxExpression).dotDotDotToken) || - visitNode(cbNode, (node as JsxExpression).expression); - case SyntaxKind.JsxClosingElement: - return visitNode(cbNode, (node).tagName); - - case SyntaxKind.OptionalType: - case SyntaxKind.RestType: - case SyntaxKind.JSDocTypeExpression: - case SyntaxKind.JSDocNonNullableType: - case SyntaxKind.JSDocNullableType: - case SyntaxKind.JSDocOptionalType: - case SyntaxKind.JSDocVariadicType: - return visitNode(cbNode, (node).type); - case SyntaxKind.JSDocFunctionType: - return visitNodes(cbNode, cbNodes, (node).parameters) || - visitNode(cbNode, (node).type); - case SyntaxKind.JSDocComment: - return visitNodes(cbNode, cbNodes, (node).tags); - case SyntaxKind.JSDocParameterTag: - case SyntaxKind.JSDocPropertyTag: - return visitNode(cbNode, (node as JSDocTag).tagName) || - ((node as JSDocPropertyLikeTag).isNameFirst - ? visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).typeExpression) - : visitNode(cbNode, (node).typeExpression) || - visitNode(cbNode, (node).name)); - case SyntaxKind.JSDocAuthorTag: - return visitNode(cbNode, (node as JSDocTag).tagName); - case SyntaxKind.JSDocImplementsTag: - return visitNode(cbNode, (node as JSDocTag).tagName) || - visitNode(cbNode, (node).class); - case SyntaxKind.JSDocAugmentsTag: - return visitNode(cbNode, (node as JSDocTag).tagName) || - visitNode(cbNode, (node).class); - case SyntaxKind.JSDocTemplateTag: - return visitNode(cbNode, (node as JSDocTag).tagName) || - visitNode(cbNode, (node).constraint) || - visitNodes(cbNode, cbNodes, (node).typeParameters); - case SyntaxKind.JSDocTypedefTag: - return visitNode(cbNode, (node as JSDocTag).tagName) || - ((node as JSDocTypedefTag).typeExpression && - (node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression - ? visitNode(cbNode, (node).typeExpression) || - visitNode(cbNode, (node).fullName) - : visitNode(cbNode, (node).fullName) || - visitNode(cbNode, (node).typeExpression)); - case SyntaxKind.JSDocCallbackTag: - return visitNode(cbNode, (node as JSDocTag).tagName) || - visitNode(cbNode, (node as JSDocCallbackTag).fullName) || - visitNode(cbNode, (node as JSDocCallbackTag).typeExpression); - case SyntaxKind.JSDocReturnTag: - case SyntaxKind.JSDocTypeTag: - case SyntaxKind.JSDocThisTag: - case SyntaxKind.JSDocEnumTag: - return visitNode(cbNode, (node as JSDocTag).tagName) || - visitNode(cbNode, (node as JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag).typeExpression); - case SyntaxKind.JSDocSignature: - return forEach((node).typeParameters, cbNode) || - forEach((node).parameters, cbNode) || - visitNode(cbNode, (node).type); - case SyntaxKind.JSDocTypeLiteral: - return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode); - case SyntaxKind.JSDocTag: - case SyntaxKind.JSDocClassTag: - case SyntaxKind.JSDocPublicTag: - case SyntaxKind.JSDocPrivateTag: - case SyntaxKind.JSDocProtectedTag: - case SyntaxKind.JSDocReadonlyTag: - return visitNode(cbNode, (node as JSDocTag).tagName); - case SyntaxKind.PartiallyEmittedExpression: - return visitNode(cbNode, (node).expression); - } - } - - /** @internal */ - /** - * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes - * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally, - * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element. - * If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. - * - * @param node a given node to visit its children - * @param cbNode a callback to be invoked for all child nodes - * @param cbNodes a callback to be invoked for embedded array - * - * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found, - * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure. - */ - export function forEachChildRecursively(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray, parent: Node) => T | "skip" | undefined): T | undefined { - - const stack: Node[] = [rootNode]; - while (stack.length) { - const parent = stack.pop()!; - const res = visitAllPossibleChildren(parent, gatherPossibleChildren(parent)); - if (res) { - return res; - } - } - - return; - - function gatherPossibleChildren(node: Node) { - const children: (Node | NodeArray)[] = []; - forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal - return children; - - function addWorkItem(n: Node | NodeArray) { - children.unshift(n); - } - } - - function visitAllPossibleChildren(parent: Node, children: readonly (Node | NodeArray)[]) { - for (const child of children) { - if (isArray(child)) { - if (cbNodes) { - const res = cbNodes(child, parent); - if (res) { - if (res === "skip") continue; - return res; - } - } - - for (let i = child.length - 1; i >= 0; i--) { - const realChild = child[i]; - const res = cbNode(realChild, parent); - if (res) { - if (res === "skip") continue; - return res; - } - stack.push(realChild); - } - } - else { - stack.push(child); - const res = cbNode(child, parent); - if (res) { - if (res === "skip") continue; - return res; - } - } - } - } - } - export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile { performance.mark("beforeParse"); let result: SourceFile; @@ -682,14 +126,19 @@ namespace ts { let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; // tslint:enable variable-name + function countNode(node: Node) { + nodeCount++; + return node; + } + // Rather than using `createBaseNodeFactory` here, we establish a `BaseNodeFactory` that closes over the // constructors above, which are reset each time `initializeState` is called. const baseNodeFactory: BaseNodeFactory = { - createBaseSourceFileNode: kind => new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0), - createBaseIdentifierNode: kind => new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0), - createBasePrivateIdentifierNode: kind => new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0), - createBaseTokenNode: kind => new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0), - createBaseNode: kind => new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0) + createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)), + createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), + createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), + createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)), + createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)) }; const factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters, baseNodeFactory, { @@ -704,14 +153,9 @@ namespace ts { } }, onFinishNode(node) { - if (setParentNodes) { - if (hasJSDocNodes(node)) { - setEachParent(node.jsDoc, node); - } + if (setParentNodes && hasJSDocNodes(node)) { + setEachParent(node.jsDoc, node); } - }, - onCreateNode(_) { - nodeCount++; } }); diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index 6b17c1b21d32b..5fb8e671decca 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -33,6 +33,7 @@ "factory/nodeTests.ts", "factory/utilities.ts", "factory/utilitiesPublic.ts", + "forEachChild.ts", "parser.ts", "commandLineParser.ts", "moduleNameResolver.ts",