diff --git a/scripts/perf-result-post.js b/scripts/perf-result-post.js index 79d90d40c5a..337729128d2 100644 --- a/scripts/perf-result-post.js +++ b/scripts/perf-result-post.js @@ -3,45 +3,86 @@ // Must reference esnext.asynciterable lib, since octokit uses AsyncIterable internally const { Octokit } = require("@octokit/rest"); const fs = require("fs"); +const ado = require("azure-devops-node-api"); +const { default: fetch } = require("node-fetch"); -const requester = process.env.requesting_user; -const source = process.env.source_issue; -const postedComment = process.env.status_comment; -console.log(`Loading fragment from ${process.argv[3]}...`); -const outputTableText = fs.readFileSync(process.argv[3], { encoding: "utf8" }); -console.log(`Fragment contents: -${outputTableText}`); -const gh = new Octokit({ - auth: process.argv[2] -}); -gh.issues.createComment({ - issue_number: +source, - owner: "Microsoft", - repo: "TypeScript", - body: `@${requester} -The results of the perf run you requested are in! -
Here they are:

-${outputTableText} -

` -}).then(async data => { - console.log(`Results posted!`); - const newCommentUrl = data.data.html_url; - const comment = await gh.issues.getComment({ - owner: "Microsoft", - repo: "TypeScript", - comment_id: +postedComment - }); - const newBody = `${comment.data.body} +async function main() { + const source = process.env.SOURCE_ISSUE; + if (!source) throw new Error("SOURCE_ISSUE environment variable not set."); -Update: [The results are in!](${newCommentUrl})`; - return await gh.issues.updateComment({ - owner: "Microsoft", - repo: "TypeScript", - comment_id: +postedComment, - body: newBody - }); -}).catch(e => { + const requester = process.env.REQUESTING_USER; + if (!requester) throw new Error("REQUESTING_USER environment variable not set."); + + const buildId = process.env.BUILD_BUILDID; + if (!requester) throw new Error("BUILD_BUILDID environment variable not set."); + + const postedComment = process.env.STATUS_COMMENT; + if (!postedComment) throw new Error("STATUS_COMMENT environment variable not set."); + + const [auth, fragment, includeArtifact] = process.argv.slice(2); + if (!auth) throw new Error("First argument must be a GitHub auth token."); + if (!fragment) throw new Error("Second argument must be a path to an HTML fragment."); + + const gh = new Octokit({ auth }); + try { + console.log(`Loading fragment from ${fragment}...`); + const outputTableText = fs.readFileSync(fragment, { encoding: "utf8" }); + console.log(`Fragment contents:\n${outputTableText}`); + + let benchmarkText = ""; + if (includeArtifact === "--include-artifact") { + // post a link to the benchmark file + const cli = new ado.WebApi("https://typescript.visualstudio.com/defaultcollection", ado.getHandlerFromToken("")); // Empty token, anon auth + const build = await cli.getBuildApi(); + const artifact = await build.getArtifact("typescript", +buildId, "benchmark"); + const updatedUrl = new URL(artifact.resource.url); + updatedUrl.search = `artifactName=benchmark&fileId=${artifact.resource.data}&fileName=manifest`; + const resp = await (await fetch(`${updatedUrl}`)).json(); + for (const file of resp.items) { + if (/[\\/]linux\.benchmark$/.test(file.path)) { + const benchmarkUrl = new URL(artifact.resource.url); + benchmarkUrl.search = `artifactName=benchmark&fileId=${file.blob.id}&fileName=linux.benchmark`; + benchmarkText = `\n
Developer Information:

Download Benchmark

\n`; + break; + } + } + } + + const data = await gh.issues.createComment({ + issue_number: +source, + owner: "Microsoft", + repo: "TypeScript", + body: `@${requester}\nThe results of the perf run you requested are in!\n
Here they are:

\n${outputTableText}\n

${benchmarkText}
` + }); + + console.log(`Results posted!`); + const newCommentUrl = data.data.html_url; + const comment = await gh.issues.getComment({ + owner: "Microsoft", + repo: "TypeScript", + comment_id: +postedComment + }); + const newBody = `${comment.data.body}\n\nUpdate: [The results are in!](${newCommentUrl})`; + await gh.issues.updateComment({ + owner: "Microsoft", + repo: "TypeScript", + comment_id: +postedComment, + body: newBody + }); + } + catch (e) { + const gh = new Octokit({ auth }); + await gh.issues.createComment({ + issue_number: +source, + owner: "Microsoft", + repo: "TypeScript", + body: `Hey @${requester}, something went wrong when publishing results. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${buildId}&_a=summary)).` + }); + } +} + +main().catch(e => { console.error(e); process.exit(1); }); diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 946a567467d..cae8da10305 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -227,6 +227,7 @@ namespace ts { const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; + const bindBinaryExpressionFlow = createBindBinaryExpressionFlow(); /** * Inside the binder, we may create a diagnostic for an as-yet unbound node (with potentially no parent pointers, implying no accessible source file) @@ -1497,132 +1498,110 @@ namespace ts { bindAssignmentTargetFlow(node.left); } - const enum BindBinaryExpressionFlowState { - BindThenBindChildren, - MaybeBindLeft, - BindToken, - BindRight, - FinishBind - } - - function bindBinaryExpressionFlow(node: BinaryExpression) { - const workStacks: { - expr: BinaryExpression[], - state: BindBinaryExpressionFlowState[], - inStrictMode: (boolean | undefined)[], - parent: (Node | undefined)[], - } = { - expr: [node], - state: [BindBinaryExpressionFlowState.MaybeBindLeft], - inStrictMode: [undefined], - parent: [undefined], - }; - let stackIndex = 0; - while (stackIndex >= 0) { - node = workStacks.expr[stackIndex]; - switch (workStacks.state[stackIndex]) { - case BindBinaryExpressionFlowState.BindThenBindChildren: { - // This state is used only when recuring, to emulate the work that `bind` does before - // reaching `bindChildren`. A normal call to `bindBinaryExpressionFlow` will already have done this work. - setParent(node, parent); - const saveInStrictMode = inStrictMode; - bindWorker(node); - const saveParent = parent; - parent = node; - - advanceState(BindBinaryExpressionFlowState.MaybeBindLeft, saveInStrictMode, saveParent); - break; - } - case BindBinaryExpressionFlowState.MaybeBindLeft: { - const operator = node.operatorToken.kind; - // TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions - // we'll need to handle the `bindLogicalExpression` scenarios in this state machine, too - // For now, though, since the common cases are chained `+`, leaving it recursive is fine - if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken || - isLogicalOrCoalescingAssignmentOperator(operator)) { - if (isTopLevelLogicalExpression(node)) { - const postExpressionLabel = createBranchLabel(); - bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel); - currentFlow = finishFlowLabel(postExpressionLabel); - } - else { - bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!); - } - completeNode(); - } - else { - advanceState(BindBinaryExpressionFlowState.BindToken); - maybeBind(node.left); - } - break; - } - case BindBinaryExpressionFlowState.BindToken: { - if (node.operatorToken.kind === SyntaxKind.CommaToken) { - maybeBindExpressionFlowIfCall(node.left); - } - advanceState(BindBinaryExpressionFlowState.BindRight); - maybeBind(node.operatorToken); - break; - } - case BindBinaryExpressionFlowState.BindRight: { - advanceState(BindBinaryExpressionFlowState.FinishBind); - maybeBind(node.right); - break; - } - case BindBinaryExpressionFlowState.FinishBind: { - const operator = node.operatorToken.kind; - if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) { - bindAssignmentTargetFlow(node.left); - if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) { - const elementAccess = node.left; - if (isNarrowableOperand(elementAccess.expression)) { - currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node); - } - } - } - completeNode(); - break; - } - default: return Debug.fail(`Invalid state ${workStacks.state[stackIndex]} for bindBinaryExpressionFlow`); - } + function createBindBinaryExpressionFlow() { + interface WorkArea { + stackIndex: number; + skip: boolean; + inStrictModeStack: (boolean | undefined)[]; + parentStack: (Node | undefined)[]; } - /** - * Note that `advanceState` sets the _current_ head state, and that `maybeBind` potentially pushes on a new - * head state; so `advanceState` must be called before any `maybeBind` during a state's execution. - */ - function advanceState(state: BindBinaryExpressionFlowState, isInStrictMode?: boolean, parent?: Node) { - workStacks.state[stackIndex] = state; - if (isInStrictMode !== undefined) { - workStacks.inStrictMode[stackIndex] = isInStrictMode; - } - if (parent !== undefined) { - workStacks.parent[stackIndex] = parent; - } - } + return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, /*foldState*/ undefined); - function completeNode() { - if (workStacks.inStrictMode[stackIndex] !== undefined) { - inStrictMode = workStacks.inStrictMode[stackIndex]!; - parent = workStacks.parent[stackIndex]!; - } - stackIndex--; - } - - /** - * If `node` is a BinaryExpression, adds it to the local work stack, otherwise recursively binds it - */ - function maybeBind(node: Node) { - if (node && isBinaryExpression(node) && !isDestructuringAssignment(node)) { - stackIndex++; - workStacks.expr[stackIndex] = node; - workStacks.state[stackIndex] = BindBinaryExpressionFlowState.BindThenBindChildren; - workStacks.inStrictMode[stackIndex] = undefined; - workStacks.parent[stackIndex] = undefined; + function onEnter(node: BinaryExpression, state: WorkArea | undefined) { + if (state) { + state.stackIndex++; + // Emulate the work that `bind` does before reaching `bindChildren`. A normal call to + // `bindBinaryExpressionFlow` will already have done this work. + setParent(node, parent); + const saveInStrictMode = inStrictMode; + bindWorker(node); + const saveParent = parent; + parent = node; + state.skip = false; + state.inStrictModeStack[state.stackIndex] = saveInStrictMode; + state.parentStack[state.stackIndex] = saveParent; } else { - bind(node); + state = { + stackIndex: 0, + skip: false, + inStrictModeStack: [undefined], + parentStack: [undefined] + }; } + // TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions + // we'll need to handle the `bindLogicalExpression` scenarios in this state machine, too + // For now, though, since the common cases are chained `+`, leaving it recursive is fine + const operator = node.operatorToken.kind; + if (operator === SyntaxKind.AmpersandAmpersandToken || + operator === SyntaxKind.BarBarToken || + operator === SyntaxKind.QuestionQuestionToken || + isLogicalOrCoalescingAssignmentOperator(operator)) { + if (isTopLevelLogicalExpression(node)) { + const postExpressionLabel = createBranchLabel(); + bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel); + currentFlow = finishFlowLabel(postExpressionLabel); + } + else { + bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!); + } + state.skip = true; + } + return state; + } + + function onLeft(left: Expression, state: WorkArea, _node: BinaryExpression) { + if (!state.skip) { + return maybeBind(left); + } + } + + function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, node: BinaryExpression) { + if (!state.skip) { + if (operatorToken.kind === SyntaxKind.CommaToken) { + maybeBindExpressionFlowIfCall(node.left); + } + bind(operatorToken); + } + } + + function onRight(right: Expression, state: WorkArea, _node: BinaryExpression) { + if (!state.skip) { + return maybeBind(right); + } + } + + function onExit(node: BinaryExpression, state: WorkArea) { + if (!state.skip) { + const operator = node.operatorToken.kind; + if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) { + bindAssignmentTargetFlow(node.left); + if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) { + const elementAccess = node.left; + if (isNarrowableOperand(elementAccess.expression)) { + currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node); + } + } + } + } + const savedInStrictMode = state.inStrictModeStack[state.stackIndex]; + const savedParent = state.parentStack[state.stackIndex]; + if (savedInStrictMode !== undefined) { + inStrictMode = savedInStrictMode; + } + if (savedParent !== undefined) { + parent = savedParent; + } + state.skip = false; + state.stackIndex--; + } + + function maybeBind(node: Node) { + if (node && isBinaryExpression(node) && !isDestructuringAssignment(node)) { + return node; + } + bind(node); } } diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index 8d14c9c1ee5..adf968fe2c7 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -275,6 +275,14 @@ namespace ts { } } + /** + * Asserts a value has the specified type in typespace only (does not perform a runtime assertion). + * This is useful in cases where we switch on `node.kind` and can be reasonably sure the type is accurate, and + * as a result can reduce the number of unnecessary casts. + */ + export function type(value: unknown): asserts value is T; + export function type(_value: unknown) { } + export function getFunctionName(func: AnyFunction) { if (typeof func !== "function") { return ""; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a2bba125ca8..0a20985e6cc 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1,6 +1,5 @@ namespace ts { const brackets = createBracketsMap(); - const syntheticParent: TextRange = { pos: -1, end: -1 }; /*@internal*/ export function isBuildInfoFile(file: string) { @@ -861,20 +860,11 @@ namespace ts { return outputFiles; } - const enum PipelinePhase { - Notification, - Substitution, - Comments, - SourceMaps, - Emit - } - export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer { const { hasGlobalName, - onEmitNode = noEmitNotification, - isEmitNotificationEnabled, - substituteNode = noEmitSubstitution, + onBeforeEmitNode, + onAfterEmitNode, onBeforeEmitNodeArray, onAfterEmitNodeArray, onBeforeEmitToken, @@ -923,9 +913,9 @@ namespace ts { let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[] | undefined; let hasWrittenComment = false; let commentsDisabled = !!printerOptions.removeComments; - let lastNode: Node | undefined; - let lastSubstitution: Node | undefined; const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment"); + const preprint = createPreprinter(handlers); + const emitBinaryExpression = createEmitBinaryExpression(); reset(); return { @@ -1003,7 +993,7 @@ namespace ts { if (sourceFile) { setSourceFile(sourceFile); } - emitList(syntheticParent, nodes, format); + emitList(/*parentNode*/ undefined, nodes, format); reset(); writer = previousWriter; } @@ -1147,7 +1137,7 @@ namespace ts { setSourceFile(sourceFile); } - pipelineEmit(hint, node); + emit(preprint(hint, node)); } function setSourceFile(sourceFile: SourceFile | undefined) { @@ -1179,8 +1169,6 @@ namespace ts { currentSourceFile = undefined!; currentLineMap = undefined!; detachedCommentsInfo = undefined; - lastNode = undefined; - lastSubstitution = undefined; setWriter(/*output*/ undefined, /*_sourceMapGenerator*/ undefined); } @@ -1188,539 +1176,545 @@ namespace ts { return currentLineMap || (currentLineMap = getLineStarts(currentSourceFile!)); } - function emit(node: Node): Node; - function emit(node: Node | undefined): Node | undefined; + function emit(node: Node): void; + function emit(node: Node | undefined): void; function emit(node: Node | undefined) { if (node === undefined) return; - const prevSourceFileTextKind = recordBundleFileInternalSectionStart(node); - const substitute = pipelineEmit(EmitHint.Unspecified, node); + + emitWithContext(node, emitWorker); + recordBundleFileInternalSectionEnd(prevSourceFileTextKind); - return substitute; } - function emitIdentifierName(node: Identifier): Node; - function emitIdentifierName(node: Identifier | undefined): Node | undefined; - function emitIdentifierName(node: Identifier | undefined): Node | undefined { - if (node === undefined) return; - return pipelineEmit(EmitHint.IdentifierName, node); + function shouldEmitComments(node: Node) { + return !commentsDisabled && !isSourceFile(node); } - function emitExpression(node: Expression): Node; - function emitExpression(node: Expression | undefined): Node | undefined; - function emitExpression(node: Expression | undefined): Node | undefined { - if (node === undefined) return; - return pipelineEmit(EmitHint.Expression, node); + function shouldEmitSourceMaps(node: Node) { + return !sourceMapsDisabled && + !isSourceFile(node) && + !isInJsonFile(node) && + !isUnparsedSource(node) && + !isUnparsedPrepend(node); } - function emitJsxAttributeValue(node: StringLiteral | JsxExpression): Node { - return pipelineEmit(isStringLiteral(node) ? EmitHint.JsxAttributeValue : EmitHint.Unspecified, node); - } + function beforeEmitWithContext(node: Node, shouldEmitComments: boolean, shouldEmitSourceMaps: boolean) { + onBeforeEmitNode?.(node); - function pipelineEmit(emitHint: EmitHint, node: Node) { - const savedLastNode = lastNode; - const savedLastSubstitution = lastSubstitution; - const savedPreserveSourceNewlines = preserveSourceNewlines; - lastNode = node; - lastSubstitution = undefined; - if (preserveSourceNewlines && !!(getEmitFlags(node) & EmitFlags.IgnoreSourceNewlines)) { + const emitFlags = getEmitFlags(node); + const commentRange = shouldEmitComments ? getCommentRange(node) : undefined; + const sourceMapRange = shouldEmitSourceMaps ? getSourceMapRange(node) : undefined; + + if (preserveSourceNewlines && (emitFlags & EmitFlags.IgnoreSourceNewlines)) { preserveSourceNewlines = false; } - const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, emitHint, node); - pipelinePhase(emitHint, node); + // Emit leading comments + if (commentRange) { + emitLeadingCommentsOfNode(node, emitFlags, commentRange.pos, commentRange.end); + if (emitFlags & EmitFlags.NoNestedComments) { + commentsDisabled = true; + } + } - Debug.assert(lastNode === node); + // Emit leading sourcemap + if (sourceMapRange) { + if (isUnparsedNode(node)) { + Debug.assertIsDefined(node.parent, "UnparsedNodes must have parent pointers"); + const parsed = getParsedSourceMap(node.parent); + if (parsed && sourceMapGenerator) { + sourceMapGenerator.appendSourceMap( + writer.getLine(), + writer.getColumn(), + parsed, + node.parent.sourceMapPath!, + node.parent.getLineAndCharacterOfPosition(node.pos), + node.parent.getLineAndCharacterOfPosition(node.end) + ); + } + } + else { + const source = sourceMapRange.source || sourceMapSource; + if (node.kind !== SyntaxKind.NotEmittedStatement + && (emitFlags & EmitFlags.NoLeadingSourceMap) === 0 + && sourceMapRange.pos >= 0) { + emitSourcePos(sourceMapRange.source || sourceMapSource, skipSourceTrivia(source, sourceMapRange.pos)); + } + if (emitFlags & EmitFlags.NoNestedSourceMaps) { + sourceMapsDisabled = true; + } + } + } + } + + function afterEmitWithContext(node: Node, shouldEmitComments: boolean, shouldEmitSourceMaps: boolean, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number, savedPreserveSourceNewlines: boolean | undefined) { + const emitFlags = getEmitFlags(node); + const commentRange = shouldEmitComments ? getCommentRange(node) : undefined; + const sourceMapRange = shouldEmitSourceMaps ? getSourceMapRange(node) : undefined; + + // Emit trailing sourcemap + if (sourceMapRange) { + if (!isUnparsedNode(node)) { + if (emitFlags & EmitFlags.NoNestedSourceMaps) { + sourceMapsDisabled = false; + } + if (node.kind !== SyntaxKind.NotEmittedStatement + && (emitFlags & EmitFlags.NoTrailingSourceMap) === 0 + && sourceMapRange.end >= 0) { + emitSourcePos(sourceMapRange.source || sourceMapSource, sourceMapRange.end); + } + } + } + + // Emit trailing comments + if (commentRange) { + if (emitFlags & EmitFlags.NoNestedComments) { + commentsDisabled = false; + } + emitTrailingCommentsOfNode(node, emitFlags, commentRange.pos, commentRange.end, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + } - const substitute = lastSubstitution; - lastNode = savedLastNode; - lastSubstitution = savedLastSubstitution; preserveSourceNewlines = savedPreserveSourceNewlines; - - return substitute || node; + onAfterEmitNode?.(node); } - function getPipelinePhase(phase: PipelinePhase, emitHint: EmitHint, node: Node) { - switch (phase) { - case PipelinePhase.Notification: - if (onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node))) { - return pipelineEmitWithNotification; - } - // falls through - - case PipelinePhase.Substitution: - if (substituteNode !== noEmitSubstitution && (lastSubstitution = substituteNode(emitHint, node)) !== node) { - return pipelineEmitWithSubstitution; - } - // falls through - - case PipelinePhase.Comments: - if (!commentsDisabled && node.kind !== SyntaxKind.SourceFile) { - return pipelineEmitWithComments; - } - // falls through - - case PipelinePhase.SourceMaps: - if (!sourceMapsDisabled && node.kind !== SyntaxKind.SourceFile && !isInJsonFile(node)) { - return pipelineEmitWithSourceMap; - } - // falls through - - case PipelinePhase.Emit: - return pipelineEmitWithHint; - - default: - return Debug.assertNever(phase); - } + function emitWithContext(node: T, emitCallback: (node: T) => void) { + const savedPreserveSourceNewlines = preserveSourceNewlines; + const savedContainerPos = containerPos; + const savedContainerEnd = containerEnd; + const savedDeclarationListContainerEnd = declarationListContainerEnd; + const emitComments = shouldEmitComments(node); + const emitSourceMaps = shouldEmitSourceMaps(node); + beforeEmitWithContext(node, emitComments, emitSourceMaps); + emitCallback(node); + afterEmitWithContext(node, emitComments, emitSourceMaps, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd, savedPreserveSourceNewlines); } - function getNextPipelinePhase(currentPhase: PipelinePhase, emitHint: EmitHint, node: Node) { - return getPipelinePhase(currentPhase + 1, emitHint, node); - } + function emitWorker(node: Node): void { + switch (node.kind) { + // Literals + case SyntaxKind.NumericLiteral: + case SyntaxKind.BigIntLiteral: + return emitNumericOrBigIntLiteral(node); - function pipelineEmitWithNotification(hint: EmitHint, node: Node) { - Debug.assert(lastNode === node); - const pipelinePhase = getNextPipelinePhase(PipelinePhase.Notification, hint, node); - onEmitNode(hint, node, pipelinePhase); - Debug.assert(lastNode === node); - } + case SyntaxKind.StringLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return emitLiteral(node, /*jsxAttributeEscape*/ false); - function pipelineEmitWithHint(hint: EmitHint, node: Node): void { - Debug.assert(lastNode === node || lastSubstitution === node); - if (hint === EmitHint.SourceFile) return emitSourceFile(cast(node, isSourceFile)); - if (hint === EmitHint.IdentifierName) return emitIdentifier(cast(node, isIdentifier)); - if (hint === EmitHint.JsxAttributeValue) return emitLiteral(cast(node, isStringLiteral), /*jsxAttributeEscape*/ true); - if (hint === EmitHint.MappedTypeParameter) return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); - if (hint === EmitHint.EmbeddedStatement) { - Debug.assertNode(node, isEmptyStatement); - return emitEmptyStatement(/*isEmbeddedStatement*/ true); - } - if (hint === EmitHint.Unspecified) { - if (isKeyword(node.kind)) return writeTokenNode(node, writeKeyword); - - switch (node.kind) { - // Pseudo-literals - case SyntaxKind.TemplateHead: - case SyntaxKind.TemplateMiddle: - case SyntaxKind.TemplateTail: - return emitLiteral(node, /*jsxAttributeEscape*/ false); - - case SyntaxKind.UnparsedSource: - case SyntaxKind.UnparsedPrepend: - return emitUnparsedSourceOrPrepend(node); - - case SyntaxKind.UnparsedPrologue: - return writeUnparsedNode(node); - - case SyntaxKind.UnparsedText: - case SyntaxKind.UnparsedInternalText: - return emitUnparsedTextLike(node); - - case SyntaxKind.UnparsedSyntheticReference: - return emitUnparsedSyntheticReference(node); - - - // Identifiers - case SyntaxKind.Identifier: - return emitIdentifier(node); - - // PrivateIdentifiers - case SyntaxKind.PrivateIdentifier: - return emitPrivateIdentifier(node as PrivateIdentifier); - - // Parse tree nodes - // Names - case SyntaxKind.QualifiedName: - return emitQualifiedName(node); - case SyntaxKind.ComputedPropertyName: - return emitComputedPropertyName(node); - - // Signature elements - case SyntaxKind.TypeParameter: - return emitTypeParameter(node); - case SyntaxKind.Parameter: - return emitParameter(node); - case SyntaxKind.Decorator: - return emitDecorator(node); - - // Type members - case SyntaxKind.PropertySignature: - return emitPropertySignature(node); - case SyntaxKind.PropertyDeclaration: - return emitPropertyDeclaration(node); - case SyntaxKind.MethodSignature: - return emitMethodSignature(node); - case SyntaxKind.MethodDeclaration: - return emitMethodDeclaration(node); - case SyntaxKind.Constructor: - return emitConstructor(node); - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - return emitAccessorDeclaration(node); - case SyntaxKind.CallSignature: - return emitCallSignature(node); - case SyntaxKind.ConstructSignature: - return emitConstructSignature(node); - case SyntaxKind.IndexSignature: - return emitIndexSignature(node); - case SyntaxKind.TemplateLiteralTypeSpan: - return emitTemplateTypeSpan(node); - - // Types - case SyntaxKind.TypePredicate: - return emitTypePredicate(node); - case SyntaxKind.TypeReference: - return emitTypeReference(node); - case SyntaxKind.FunctionType: - return emitFunctionType(node); - case SyntaxKind.JSDocFunctionType: - return emitJSDocFunctionType(node as JSDocFunctionType); - case SyntaxKind.ConstructorType: - return emitConstructorType(node); - case SyntaxKind.TypeQuery: - return emitTypeQuery(node); - case SyntaxKind.TypeLiteral: - return emitTypeLiteral(node); - case SyntaxKind.ArrayType: - return emitArrayType(node); - case SyntaxKind.TupleType: - return emitTupleType(node); - case SyntaxKind.OptionalType: - return emitOptionalType(node); - case SyntaxKind.UnionType: - return emitUnionType(node); - case SyntaxKind.IntersectionType: - return emitIntersectionType(node); - case SyntaxKind.ConditionalType: - return emitConditionalType(node); - case SyntaxKind.InferType: - return emitInferType(node); - case SyntaxKind.ParenthesizedType: - return emitParenthesizedType(node); - case SyntaxKind.ExpressionWithTypeArguments: - return emitExpressionWithTypeArguments(node); - case SyntaxKind.ThisType: - return emitThisType(); - case SyntaxKind.TypeOperator: - return emitTypeOperator(node); - case SyntaxKind.IndexedAccessType: - return emitIndexedAccessType(node); - case SyntaxKind.MappedType: - return emitMappedType(node); - case SyntaxKind.LiteralType: - return emitLiteralType(node); - case SyntaxKind.TemplateLiteralType: - return emitTemplateType(node); - case SyntaxKind.ImportType: - return emitImportTypeNode(node); - case SyntaxKind.JSDocAllType: - writePunctuation("*"); - return; - case SyntaxKind.JSDocUnknownType: - writePunctuation("?"); - return; - case SyntaxKind.JSDocNullableType: - return emitJSDocNullableType(node as JSDocNullableType); - case SyntaxKind.JSDocNonNullableType: - return emitJSDocNonNullableType(node as JSDocNonNullableType); - case SyntaxKind.JSDocOptionalType: - return emitJSDocOptionalType(node as JSDocOptionalType); - case SyntaxKind.RestType: - case SyntaxKind.JSDocVariadicType: - return emitRestOrJSDocVariadicType(node as RestTypeNode | JSDocVariadicType); - case SyntaxKind.NamedTupleMember: - return emitNamedTupleMember(node as NamedTupleMember); - - // Binding patterns - case SyntaxKind.ObjectBindingPattern: - return emitObjectBindingPattern(node); - case SyntaxKind.ArrayBindingPattern: - return emitArrayBindingPattern(node); - case SyntaxKind.BindingElement: - return emitBindingElement(node); - - // Misc - case SyntaxKind.TemplateSpan: - return emitTemplateSpan(node); - case SyntaxKind.SemicolonClassElement: - return emitSemicolonClassElement(); - - // Statements - case SyntaxKind.Block: - return emitBlock(node); - case SyntaxKind.VariableStatement: - return emitVariableStatement(node); - case SyntaxKind.EmptyStatement: - return emitEmptyStatement(/*isEmbeddedStatement*/ false); - case SyntaxKind.ExpressionStatement: - return emitExpressionStatement(node); - case SyntaxKind.IfStatement: - return emitIfStatement(node); - case SyntaxKind.DoStatement: - return emitDoStatement(node); - case SyntaxKind.WhileStatement: - return emitWhileStatement(node); - case SyntaxKind.ForStatement: - return emitForStatement(node); - case SyntaxKind.ForInStatement: - return emitForInStatement(node); - case SyntaxKind.ForOfStatement: - return emitForOfStatement(node); - case SyntaxKind.ContinueStatement: - return emitContinueStatement(node); - case SyntaxKind.BreakStatement: - return emitBreakStatement(node); - case SyntaxKind.ReturnStatement: - return emitReturnStatement(node); - case SyntaxKind.WithStatement: - return emitWithStatement(node); - case SyntaxKind.SwitchStatement: - return emitSwitchStatement(node); - case SyntaxKind.LabeledStatement: - return emitLabeledStatement(node); - case SyntaxKind.ThrowStatement: - return emitThrowStatement(node); - case SyntaxKind.TryStatement: - return emitTryStatement(node); - case SyntaxKind.DebuggerStatement: - return emitDebuggerStatement(node); - - // Declarations - case SyntaxKind.VariableDeclaration: - return emitVariableDeclaration(node); - case SyntaxKind.VariableDeclarationList: - return emitVariableDeclarationList(node); - case SyntaxKind.FunctionDeclaration: - return emitFunctionDeclaration(node); - case SyntaxKind.ClassDeclaration: - return emitClassDeclaration(node); - case SyntaxKind.InterfaceDeclaration: - return emitInterfaceDeclaration(node); - case SyntaxKind.TypeAliasDeclaration: - return emitTypeAliasDeclaration(node); - case SyntaxKind.EnumDeclaration: - return emitEnumDeclaration(node); - case SyntaxKind.ModuleDeclaration: - return emitModuleDeclaration(node); - case SyntaxKind.ModuleBlock: - return emitModuleBlock(node); - case SyntaxKind.CaseBlock: - return emitCaseBlock(node); - case SyntaxKind.NamespaceExportDeclaration: - return emitNamespaceExportDeclaration(node); - case SyntaxKind.ImportEqualsDeclaration: - return emitImportEqualsDeclaration(node); - case SyntaxKind.ImportDeclaration: - return emitImportDeclaration(node); - case SyntaxKind.ImportClause: - return emitImportClause(node); - case SyntaxKind.NamespaceImport: - return emitNamespaceImport(node); - case SyntaxKind.NamespaceExport: - return emitNamespaceExport(node); - case SyntaxKind.NamedImports: - return emitNamedImports(node); - case SyntaxKind.ImportSpecifier: - return emitImportSpecifier(node); - case SyntaxKind.ExportAssignment: - return emitExportAssignment(node); - case SyntaxKind.ExportDeclaration: - return emitExportDeclaration(node); - case SyntaxKind.NamedExports: - return emitNamedExports(node); - case SyntaxKind.ExportSpecifier: - return emitExportSpecifier(node); - case SyntaxKind.MissingDeclaration: - return; - - // Module references - case SyntaxKind.ExternalModuleReference: - return emitExternalModuleReference(node); - - // JSX (non-expression) - case SyntaxKind.JsxText: - return emitJsxText(node); - case SyntaxKind.JsxOpeningElement: - case SyntaxKind.JsxOpeningFragment: - return emitJsxOpeningElementOrFragment(node); - case SyntaxKind.JsxClosingElement: - case SyntaxKind.JsxClosingFragment: - return emitJsxClosingElementOrFragment(node); - case SyntaxKind.JsxAttribute: - return emitJsxAttribute(node); - case SyntaxKind.JsxAttributes: - return emitJsxAttributes(node); - case SyntaxKind.JsxSpreadAttribute: - return emitJsxSpreadAttribute(node); - case SyntaxKind.JsxExpression: - return emitJsxExpression(node); - - // Clauses - case SyntaxKind.CaseClause: - return emitCaseClause(node); - case SyntaxKind.DefaultClause: - return emitDefaultClause(node); - case SyntaxKind.HeritageClause: - return emitHeritageClause(node); - case SyntaxKind.CatchClause: - return emitCatchClause(node); - - // Property assignments - case SyntaxKind.PropertyAssignment: - return emitPropertyAssignment(node); - case SyntaxKind.ShorthandPropertyAssignment: - return emitShorthandPropertyAssignment(node); - case SyntaxKind.SpreadAssignment: - return emitSpreadAssignment(node as SpreadAssignment); - - // Enum - case SyntaxKind.EnumMember: - return emitEnumMember(node); - - // JSDoc nodes (only used in codefixes currently) - case SyntaxKind.JSDocParameterTag: - case SyntaxKind.JSDocPropertyTag: - return emitJSDocPropertyLikeTag(node as JSDocPropertyLikeTag); - case SyntaxKind.JSDocReturnTag: - case SyntaxKind.JSDocTypeTag: - case SyntaxKind.JSDocThisTag: - case SyntaxKind.JSDocEnumTag: - return emitJSDocSimpleTypedTag(node as JSDocTypeTag); - case SyntaxKind.JSDocImplementsTag: - case SyntaxKind.JSDocAugmentsTag: - return emitJSDocHeritageTag(node as JSDocImplementsTag | JSDocAugmentsTag); - case SyntaxKind.JSDocTemplateTag: - return emitJSDocTemplateTag(node as JSDocTemplateTag); - case SyntaxKind.JSDocTypedefTag: - return emitJSDocTypedefTag(node as JSDocTypedefTag); - case SyntaxKind.JSDocCallbackTag: - return emitJSDocCallbackTag(node as JSDocCallbackTag); - case SyntaxKind.JSDocSignature: - return emitJSDocSignature(node as JSDocSignature); - case SyntaxKind.JSDocTypeLiteral: - return emitJSDocTypeLiteral(node as JSDocTypeLiteral); - case SyntaxKind.JSDocClassTag: - case SyntaxKind.JSDocTag: - return emitJSDocSimpleTag(node as JSDocTag); - case SyntaxKind.JSDocSeeTag: - return emitJSDocSeeTag(node as JSDocSeeTag); - case SyntaxKind.JSDocNameReference: - return emitJSDocNameReference(node as JSDocNameReference); - - case SyntaxKind.JSDocComment: - return emitJSDoc(node as JSDoc); - - // Transformation nodes (ignored) - } - - if (isExpression(node)) { - hint = EmitHint.Expression; - if (substituteNode !== noEmitSubstitution) { - lastSubstitution = node = substituteNode(hint, node); - } - } - else if (isToken(node)) { - return writeTokenNode(node, writePunctuation); - } - } - if (hint === EmitHint.Expression) { - switch (node.kind) { - // Literals - case SyntaxKind.NumericLiteral: - case SyntaxKind.BigIntLiteral: - return emitNumericOrBigIntLiteral(node); - - case SyntaxKind.StringLiteral: - case SyntaxKind.RegularExpressionLiteral: - case SyntaxKind.NoSubstitutionTemplateLiteral: - return emitLiteral(node, /*jsxAttributeEscape*/ false); - - // Identifiers - case SyntaxKind.Identifier: - return emitIdentifier(node); - - // Reserved words - case SyntaxKind.FalseKeyword: - case SyntaxKind.NullKeyword: - case SyntaxKind.SuperKeyword: - case SyntaxKind.TrueKeyword: - case SyntaxKind.ThisKeyword: - case SyntaxKind.ImportKeyword: - writeTokenNode(node, writeKeyword); - return; - - // Expressions - case SyntaxKind.ArrayLiteralExpression: - return emitArrayLiteralExpression(node); - case SyntaxKind.ObjectLiteralExpression: - return emitObjectLiteralExpression(node); - case SyntaxKind.PropertyAccessExpression: - return emitPropertyAccessExpression(node); - case SyntaxKind.ElementAccessExpression: - return emitElementAccessExpression(node); - case SyntaxKind.CallExpression: - return emitCallExpression(node); - case SyntaxKind.NewExpression: - return emitNewExpression(node); - case SyntaxKind.TaggedTemplateExpression: - return emitTaggedTemplateExpression(node); - case SyntaxKind.TypeAssertionExpression: - return emitTypeAssertionExpression(node); - case SyntaxKind.ParenthesizedExpression: - return emitParenthesizedExpression(node); - case SyntaxKind.FunctionExpression: - return emitFunctionExpression(node); - case SyntaxKind.ArrowFunction: - return emitArrowFunction(node); - case SyntaxKind.DeleteExpression: - return emitDeleteExpression(node); - case SyntaxKind.TypeOfExpression: - return emitTypeOfExpression(node); - case SyntaxKind.VoidExpression: - return emitVoidExpression(node); - case SyntaxKind.AwaitExpression: - return emitAwaitExpression(node); - case SyntaxKind.PrefixUnaryExpression: - return emitPrefixUnaryExpression(node); - case SyntaxKind.PostfixUnaryExpression: - return emitPostfixUnaryExpression(node); - case SyntaxKind.BinaryExpression: - return emitBinaryExpression(node); - case SyntaxKind.ConditionalExpression: - return emitConditionalExpression(node); - case SyntaxKind.TemplateExpression: - return emitTemplateExpression(node); - case SyntaxKind.YieldExpression: - return emitYieldExpression(node); - case SyntaxKind.SpreadElement: - return emitSpreadExpression(node); - case SyntaxKind.ClassExpression: - return emitClassExpression(node); - case SyntaxKind.OmittedExpression: - return; - case SyntaxKind.AsExpression: - return emitAsExpression(node); - case SyntaxKind.NonNullExpression: - return emitNonNullExpression(node); - case SyntaxKind.MetaProperty: - return emitMetaProperty(node); - - // JSX - case SyntaxKind.JsxElement: - return emitJsxElement(node); - case SyntaxKind.JsxSelfClosingElement: - return emitJsxSelfClosingElement(node); - case SyntaxKind.JsxFragment: - return emitJsxFragment(node); - - // Transformation nodes - case SyntaxKind.PartiallyEmittedExpression: - return emitPartiallyEmittedExpression(node); - - case SyntaxKind.CommaListExpression: - return emitCommaList(node); - } + case SyntaxKind.JsxText: + return emitJsxText(node); + + // Pseudo-literals + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + return emitLiteral(node, /*jsxAttributeEscape*/ false); + + // Identifiers and PrivateIdentifiers + case SyntaxKind.Identifier: + return emitIdentifier(node); + case SyntaxKind.PrivateIdentifier: + return emitPrivateIdentifier(node as PrivateIdentifier); + + // Names + case SyntaxKind.QualifiedName: + return emitQualifiedName(node); + case SyntaxKind.ComputedPropertyName: + return emitComputedPropertyName(node); + + // Signature elements + case SyntaxKind.TypeParameter: + return emitTypeParameter(node); + case SyntaxKind.Parameter: + return emitParameter(node); + case SyntaxKind.Decorator: + return emitDecorator(node); + + // Type members + case SyntaxKind.PropertySignature: + return emitPropertySignature(node); + case SyntaxKind.PropertyDeclaration: + return emitPropertyDeclaration(node); + case SyntaxKind.MethodSignature: + return emitMethodSignature(node); + case SyntaxKind.MethodDeclaration: + return emitMethodDeclaration(node); + case SyntaxKind.Constructor: + return emitConstructor(node); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return emitAccessorDeclaration(node); + case SyntaxKind.CallSignature: + return emitCallSignature(node); + case SyntaxKind.ConstructSignature: + return emitConstructSignature(node); + case SyntaxKind.IndexSignature: + return emitIndexSignature(node); + + // Types + case SyntaxKind.TypePredicate: + return emitTypePredicate(node); + case SyntaxKind.TypeReference: + return emitTypeReference(node); + case SyntaxKind.FunctionType: + return emitFunctionType(node); + case SyntaxKind.ConstructorType: + return emitConstructorType(node); + case SyntaxKind.TypeQuery: + return emitTypeQuery(node); + case SyntaxKind.TypeLiteral: + return emitTypeLiteral(node); + case SyntaxKind.ArrayType: + return emitArrayType(node); + case SyntaxKind.TupleType: + return emitTupleType(node); + case SyntaxKind.OptionalType: + return emitOptionalType(node); + // SyntaxKind.RestType is handled below + case SyntaxKind.UnionType: + return emitUnionType(node); + case SyntaxKind.IntersectionType: + return emitIntersectionType(node); + case SyntaxKind.ConditionalType: + return emitConditionalType(node); + case SyntaxKind.InferType: + return emitInferType(node); + case SyntaxKind.ParenthesizedType: + return emitParenthesizedType(node); + case SyntaxKind.ThisType: + return emitThisType(); + case SyntaxKind.TypeOperator: + return emitTypeOperator(node); + case SyntaxKind.IndexedAccessType: + return emitIndexedAccessType(node); + case SyntaxKind.MappedType: + return emitMappedType(node); + case SyntaxKind.LiteralType: + return emitLiteralType(node); + case SyntaxKind.NamedTupleMember: + return emitNamedTupleMember(node as NamedTupleMember); + case SyntaxKind.TemplateLiteralType: + return emitTemplateType(node); + case SyntaxKind.TemplateLiteralTypeSpan: + return emitTemplateTypeSpan(node); + case SyntaxKind.ImportType: + return emitImportTypeNode(node); + + // Binding patterns + case SyntaxKind.ObjectBindingPattern: + return emitObjectBindingPattern(node); + case SyntaxKind.ArrayBindingPattern: + return emitArrayBindingPattern(node); + case SyntaxKind.BindingElement: + return emitBindingElement(node); + + // Expressions + case SyntaxKind.ArrayLiteralExpression: + return emitArrayLiteralExpression(node); + case SyntaxKind.ObjectLiteralExpression: + return emitObjectLiteralExpression(node); + case SyntaxKind.PropertyAccessExpression: + return emitPropertyAccessExpression(node); + case SyntaxKind.ElementAccessExpression: + return emitElementAccessExpression(node); + case SyntaxKind.CallExpression: + return emitCallExpression(node); + case SyntaxKind.NewExpression: + return emitNewExpression(node); + case SyntaxKind.TaggedTemplateExpression: + return emitTaggedTemplateExpression(node); + case SyntaxKind.TypeAssertionExpression: + return emitTypeAssertionExpression(node); + case SyntaxKind.ParenthesizedExpression: + return emitParenthesizedExpression(node); + case SyntaxKind.FunctionExpression: + return emitFunctionExpression(node); + case SyntaxKind.ArrowFunction: + return emitArrowFunction(node); + case SyntaxKind.DeleteExpression: + return emitDeleteExpression(node); + case SyntaxKind.TypeOfExpression: + return emitTypeOfExpression(node); + case SyntaxKind.VoidExpression: + return emitVoidExpression(node); + case SyntaxKind.AwaitExpression: + return emitAwaitExpression(node); + case SyntaxKind.PrefixUnaryExpression: + return emitPrefixUnaryExpression(node); + case SyntaxKind.PostfixUnaryExpression: + return emitPostfixUnaryExpression(node); + case SyntaxKind.BinaryExpression: + return emitBinaryExpression(node); + case SyntaxKind.ConditionalExpression: + return emitConditionalExpression(node); + case SyntaxKind.TemplateExpression: + return emitTemplateExpression(node); + case SyntaxKind.YieldExpression: + return emitYieldExpression(node); + case SyntaxKind.SpreadElement: + return emitSpreadExpression(node); + case SyntaxKind.ClassExpression: + return emitClassExpression(node); + case SyntaxKind.OmittedExpression: + return; + case SyntaxKind.ExpressionWithTypeArguments: + return emitExpressionWithTypeArguments(node); + case SyntaxKind.AsExpression: + return emitAsExpression(node); + case SyntaxKind.NonNullExpression: + return emitNonNullExpression(node); + case SyntaxKind.MetaProperty: + return emitMetaProperty(node); + case SyntaxKind.SyntheticExpression: + Debug.fail("SyntheticExpression should never be printed."); + break; + + // Misc + case SyntaxKind.TemplateSpan: + return emitTemplateSpan(node); + case SyntaxKind.SemicolonClassElement: + return emitSemicolonClassElement(); + + // Element + case SyntaxKind.Block: + return emitBlock(node); + case SyntaxKind.EmptyStatement: + return emitEmptyStatement(/*isEmbeddedStatement*/ false); + case SyntaxKind.VariableStatement: + return emitVariableStatement(node); + case SyntaxKind.ExpressionStatement: + return emitExpressionStatement(node); + case SyntaxKind.IfStatement: + return emitIfStatement(node); + case SyntaxKind.DoStatement: + return emitDoStatement(node); + case SyntaxKind.WhileStatement: + return emitWhileStatement(node); + case SyntaxKind.ForStatement: + return emitForStatement(node); + case SyntaxKind.ForInStatement: + return emitForInStatement(node); + case SyntaxKind.ForOfStatement: + return emitForOfStatement(node); + case SyntaxKind.ContinueStatement: + return emitContinueStatement(node); + case SyntaxKind.BreakStatement: + return emitBreakStatement(node); + case SyntaxKind.ReturnStatement: + return emitReturnStatement(node); + case SyntaxKind.WithStatement: + return emitWithStatement(node); + case SyntaxKind.SwitchStatement: + return emitSwitchStatement(node); + case SyntaxKind.LabeledStatement: + return emitLabeledStatement(node); + case SyntaxKind.ThrowStatement: + return emitThrowStatement(node); + case SyntaxKind.TryStatement: + return emitTryStatement(node); + case SyntaxKind.DebuggerStatement: + return emitDebuggerStatement(node); + + // Declarations + case SyntaxKind.VariableDeclaration: + return emitVariableDeclaration(node); + case SyntaxKind.VariableDeclarationList: + return emitVariableDeclarationList(node); + case SyntaxKind.FunctionDeclaration: + return emitFunctionDeclaration(node); + case SyntaxKind.ClassDeclaration: + return emitClassDeclaration(node); + case SyntaxKind.InterfaceDeclaration: + return emitInterfaceDeclaration(node); + case SyntaxKind.TypeAliasDeclaration: + return emitTypeAliasDeclaration(node); + case SyntaxKind.EnumDeclaration: + return emitEnumDeclaration(node); + case SyntaxKind.ModuleDeclaration: + return emitModuleDeclaration(node); + case SyntaxKind.ModuleBlock: + return emitModuleBlock(node); + case SyntaxKind.CaseBlock: + return emitCaseBlock(node); + case SyntaxKind.NamespaceExportDeclaration: + return emitNamespaceExportDeclaration(node); + case SyntaxKind.ImportEqualsDeclaration: + return emitImportEqualsDeclaration(node); + case SyntaxKind.ImportDeclaration: + return emitImportDeclaration(node); + case SyntaxKind.ImportClause: + return emitImportClause(node); + case SyntaxKind.NamespaceImport: + return emitNamespaceImport(node); + case SyntaxKind.NamedImports: + return emitNamedImports(node); + case SyntaxKind.ImportSpecifier: + return emitImportSpecifier(node); + case SyntaxKind.ExportAssignment: + return emitExportAssignment(node); + case SyntaxKind.ExportDeclaration: + return emitExportDeclaration(node); + case SyntaxKind.NamedExports: + return emitNamedExports(node); + case SyntaxKind.NamespaceExport: + return emitNamespaceExport(node); + case SyntaxKind.ExportSpecifier: + return emitExportSpecifier(node); + case SyntaxKind.MissingDeclaration: + return; + + // Module references + case SyntaxKind.ExternalModuleReference: + return emitExternalModuleReference(node); + + // JSX + case SyntaxKind.JsxElement: + return emitJsxElement(node); + case SyntaxKind.JsxSelfClosingElement: + return emitJsxSelfClosingElement(node); + case SyntaxKind.JsxFragment: + return emitJsxFragment(node); + case SyntaxKind.JsxOpeningElement: + case SyntaxKind.JsxOpeningFragment: + return emitJsxOpeningElementOrFragment(node); + case SyntaxKind.JsxClosingElement: + case SyntaxKind.JsxClosingFragment: + return emitJsxClosingElementOrFragment(node); + case SyntaxKind.JsxAttribute: + return emitJsxAttribute(node); + case SyntaxKind.JsxAttributes: + return emitJsxAttributes(node); + case SyntaxKind.JsxSpreadAttribute: + return emitJsxSpreadAttribute(node); + case SyntaxKind.JsxExpression: + return emitJsxExpression(node); + + // Clauses + case SyntaxKind.CaseClause: + return emitCaseClause(node); + case SyntaxKind.DefaultClause: + return emitDefaultClause(node); + case SyntaxKind.HeritageClause: + return emitHeritageClause(node); + case SyntaxKind.CatchClause: + return emitCatchClause(node); + + // Property assignments + case SyntaxKind.PropertyAssignment: + return emitPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); + case SyntaxKind.SpreadAssignment: + return emitSpreadAssignment(node as SpreadAssignment); + + // Enum + case SyntaxKind.EnumMember: + return emitEnumMember(node); + + // Unparsed + case SyntaxKind.UnparsedPrologue: + return writeUnparsedNode(node); + case SyntaxKind.UnparsedSource: + case SyntaxKind.UnparsedPrepend: + return emitUnparsedSourceOrPrepend(node); + case SyntaxKind.UnparsedText: + case SyntaxKind.UnparsedInternalText: + return emitUnparsedTextLike(node); + case SyntaxKind.UnparsedSyntheticReference: + return emitUnparsedSyntheticReference(node); + + // Top-level nodes + case SyntaxKind.SourceFile: + return emitSourceFile(node); + case SyntaxKind.Bundle: + Debug.fail("Bundles should be printed using printBundle"); + break; + // SyntaxKind.UnparsedSource (handled above) + case SyntaxKind.InputFiles: + Debug.fail("InputFiles should not be printed"); + break; + + // JSDoc nodes (only used in codefixes currently) + case SyntaxKind.JSDocTypeExpression: + return emitJSDocTypeExpression(node as JSDocTypeExpression); + case SyntaxKind.JSDocNameReference: + return emitJSDocNameReference(node as JSDocNameReference); + case SyntaxKind.JSDocAllType: + return writePunctuation("*"); + case SyntaxKind.JSDocUnknownType: + return writePunctuation("?"); + case SyntaxKind.JSDocNullableType: + return emitJSDocNullableType(node as JSDocNullableType); + case SyntaxKind.JSDocNonNullableType: + return emitJSDocNonNullableType(node as JSDocNonNullableType); + case SyntaxKind.JSDocOptionalType: + return emitJSDocOptionalType(node as JSDocOptionalType); + case SyntaxKind.JSDocFunctionType: + return emitJSDocFunctionType(node as JSDocFunctionType); + case SyntaxKind.RestType: + case SyntaxKind.JSDocVariadicType: + return emitRestOrJSDocVariadicType(node as RestTypeNode | JSDocVariadicType); + // SyntaxKind.JSDocNamepathType (missing) + case SyntaxKind.JSDocComment: + return emitJSDoc(node as JSDoc); + case SyntaxKind.JSDocTypeLiteral: + return emitJSDocTypeLiteral(node as JSDocTypeLiteral); + case SyntaxKind.JSDocSignature: + return emitJSDocSignature(node as JSDocSignature); + case SyntaxKind.JSDocTag: + case SyntaxKind.JSDocClassTag: + return emitJSDocSimpleTag(node as JSDocTag); + case SyntaxKind.JSDocAugmentsTag: + case SyntaxKind.JSDocImplementsTag: + return emitJSDocHeritageTag(node as JSDocImplementsTag | JSDocAugmentsTag); + // SyntaxKind.JSDocAuthorTag (missing) + // SyntaxKind.JSDocDeprecatedTag (missing) + // SyntaxKind.JSDocClassTag (see JSDocTag, above) + // SyntaxKind.JSDocPublicTag (missing) + // SyntaxKind.JSDocPrivateTag (missing) + // SyntaxKind.JSDocProtectedTag (missing) + // SyntaxKind.JSDocReadonlyTag (missing) + case SyntaxKind.JSDocCallbackTag: + return emitJSDocCallbackTag(node as JSDocCallbackTag); + // SyntaxKind.JSDocEnumTag (see below) + case SyntaxKind.JSDocParameterTag: + case SyntaxKind.JSDocPropertyTag: + return emitJSDocPropertyLikeTag(node as JSDocPropertyLikeTag); + case SyntaxKind.JSDocEnumTag: + case SyntaxKind.JSDocReturnTag: + case SyntaxKind.JSDocThisTag: + case SyntaxKind.JSDocTypeTag: + return emitJSDocSimpleTypedTag(node as JSDocTypeTag); + case SyntaxKind.JSDocTemplateTag: + return emitJSDocTemplateTag(node as JSDocTemplateTag); + case SyntaxKind.JSDocTypedefTag: + return emitJSDocTypedefTag(node as JSDocTypedefTag); + case SyntaxKind.JSDocSeeTag: + return emitJSDocSeeTag(node as JSDocSeeTag); + // SyntaxKind.JSDocPropertyTag (see JSDocParameterTag, above) + + // Synthesized list + case SyntaxKind.SyntaxList: + Debug.fail("SyntaxList should not be printed"); + break; + + // Transformation nodes + case SyntaxKind.NotEmittedStatement: + break; + case SyntaxKind.PartiallyEmittedExpression: + return emitPartiallyEmittedExpression(node); + case SyntaxKind.CommaListExpression: + return emitCommaList(node); + case SyntaxKind.MergeDeclarationMarker: + case SyntaxKind.EndOfDeclarationMarker: + break; + case SyntaxKind.SyntheticReferenceExpression: + Debug.fail("SyntheticReferenceExpression should not be printed"); } + if (isKeyword(node.kind)) return writeTokenNode(node, writeKeyword); + if (isTokenKind(node.kind)) return writeTokenNode(node, writePunctuation); } function emitMappedTypeParameter(node: TypeParameterDeclaration): void { @@ -1731,13 +1725,6 @@ namespace ts { emit(node.constraint); } - function pipelineEmitWithSubstitution(hint: EmitHint, node: Node) { - Debug.assert(lastNode === node || lastSubstitution === node); - const pipelinePhase = getNextPipelinePhase(PipelinePhase.Substitution, hint, node); - pipelinePhase(hint, lastSubstitution!); - Debug.assert(lastNode === node || lastSubstitution === node); - } - function getHelpersFromBundledSourceFiles(bundle: Bundle): string[] | undefined { let result: string[] | undefined; if (moduleKind === ModuleKind.None || printerOptions.noEmitHelpers) { @@ -1844,6 +1831,10 @@ namespace ts { } } + function emitStringLiteralWithJsxAttributeEscape(node: StringLiteral) { + emitLiteral(node, /*jsxAttributeEscape*/ true); + } + // SyntaxKind.UnparsedSource // SyntaxKind.UnparsedPrepend function emitUnparsedSourceOrPrepend(unparsed: UnparsedSource | UnparsedPrepend) { @@ -1917,7 +1908,7 @@ namespace ts { function emitEntityName(node: EntityName) { if (node.kind === SyntaxKind.Identifier) { - emitExpression(node); + emit(node); } else { emit(node); @@ -1926,7 +1917,7 @@ namespace ts { function emitComputedPropertyName(node: ComputedPropertyName) { writePunctuation("["); - emitExpression(node.expression); + emit(node.expression); writePunctuation("]"); } @@ -1968,7 +1959,7 @@ namespace ts { function emitDecorator(decorator: Decorator) { writePunctuation("@"); - emitExpression(decorator.expression); + emit(decorator.expression); } // @@ -2261,7 +2252,7 @@ namespace ts { } writePunctuation("["); - pipelineEmit(EmitHint.MappedTypeParameter, node.typeParameter); + emitWithContext(node.typeParameter, emitMappedTypeParameter); if (node.nameType) { writeSpace(); writeKeyword("as"); @@ -2291,7 +2282,7 @@ namespace ts { } function emitLiteralType(node: LiteralTypeNode) { - emitExpression(node.literal); + emit(node.literal); } function emitTemplateType(node: TemplateLiteralTypeNode) { @@ -2349,7 +2340,7 @@ namespace ts { function emitArrayLiteralExpression(node: ArrayLiteralExpression) { const elements = node.elements; const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; - emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); + emitList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); } function emitObjectLiteralExpression(node: ObjectLiteralExpression) { @@ -2370,7 +2361,7 @@ namespace ts { } function emitPropertyAccessExpression(node: PropertyAccessExpression) { - const expression = cast(emitExpression(node.expression), isExpression); + emit(node.expression); const token = node.questionDotToken || setTextRangePosEnd(factory.createToken(SyntaxKind.DotToken) as DotToken, node.expression.end, node.name.pos); const linesBeforeDot = getLinesBetweenNodes(node, node.expression, token); const linesAfterDot = getLinesBetweenNodes(node, token, node.name); @@ -2379,7 +2370,7 @@ namespace ts { const shouldEmitDotDot = token.kind !== SyntaxKind.QuestionDotToken && - mayNeedDotDotForPropertyAccess(expression) && + mayNeedDotDotForPropertyAccess(node.expression) && !writer.hasTrailingComment() && !writer.hasTrailingWhitespace(); @@ -2419,46 +2410,46 @@ namespace ts { } function emitElementAccessExpression(node: ElementAccessExpression) { - emitExpression(node.expression); + emit(node.expression); emit(node.questionDotToken); emitTokenWithComment(SyntaxKind.OpenBracketToken, node.expression.end, writePunctuation, node); - emitExpression(node.argumentExpression); + emit(node.argumentExpression); emitTokenWithComment(SyntaxKind.CloseBracketToken, node.argumentExpression.end, writePunctuation, node); } function emitCallExpression(node: CallExpression) { - emitExpression(node.expression); + emit(node.expression); emit(node.questionDotToken); emitTypeArguments(node, node.typeArguments); - emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments); + emitList(node, node.arguments, ListFormat.CallExpressionArguments); } function emitNewExpression(node: NewExpression) { emitTokenWithComment(SyntaxKind.NewKeyword, node.pos, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); emitTypeArguments(node, node.typeArguments); - emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments); + emitList(node, node.arguments, ListFormat.NewExpressionArguments); } function emitTaggedTemplateExpression(node: TaggedTemplateExpression) { - emitExpression(node.tag); + emit(node.tag); emitTypeArguments(node, node.typeArguments); writeSpace(); - emitExpression(node.template); + emit(node.template); } function emitTypeAssertionExpression(node: TypeAssertion) { writePunctuation("<"); emit(node.type); writePunctuation(">"); - emitExpression(node.expression); + emit(node.expression); } function emitParenthesizedExpression(node: ParenthesizedExpression) { const openParenPos = emitTokenWithComment(SyntaxKind.OpenParenToken, node.pos, writePunctuation, node); const indented = writeLineSeparatorsAndIndentBefore(node.expression, node); - emitExpression(node.expression); + emit(node.expression); writeLineSeparatorsAfter(node.expression, node); decreaseIndentIf(indented); emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression ? node.expression.end : openParenPos, writePunctuation, node); @@ -2486,25 +2477,25 @@ namespace ts { function emitDeleteExpression(node: DeleteExpression) { emitTokenWithComment(SyntaxKind.DeleteKeyword, node.pos, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); } function emitTypeOfExpression(node: TypeOfExpression) { emitTokenWithComment(SyntaxKind.TypeOfKeyword, node.pos, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); } function emitVoidExpression(node: VoidExpression) { emitTokenWithComment(SyntaxKind.VoidKeyword, node.pos, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); } function emitAwaitExpression(node: AwaitExpression) { emitTokenWithComment(SyntaxKind.AwaitKeyword, node.pos, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); } function emitPrefixUnaryExpression(node: PrefixUnaryExpression) { @@ -2512,7 +2503,7 @@ namespace ts { if (shouldEmitWhitespaceBeforeOperand(node)) { writeSpace(); } - emitExpression(node.operand); + emit(node.operand); } function shouldEmitWhitespaceBeforeOperand(node: PrefixUnaryExpression) { @@ -2535,87 +2526,82 @@ namespace ts { } function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { - emitExpression(node.operand); + emit(node.operand); writeTokenText(node.operator, writeOperator); } - const enum EmitBinaryExpressionState { - EmitLeft, - EmitRight, - FinishEmit - } + function createEmitBinaryExpression() { + interface WorkArea { + stackIndex: number; + preserveSourceNewlinesStack: (boolean | undefined)[]; + containerPosStack: number[]; + containerEndStack: number[]; + declarationListContainerEndStack: number[]; + shouldEmitCommentsStack: boolean[]; + shouldEmitSourceMapsStack: boolean[]; + } - /** - * emitBinaryExpression includes an embedded work stack to attempt to handle as many nested binary expressions - * as possible without creating any additional stack frames. This can only be done when the emit pipeline does - * not require notification/substitution/comment/sourcemap decorations. - */ - function emitBinaryExpression(node: BinaryExpression) { - const nodeStack = [node]; - const stateStack = [EmitBinaryExpressionState.EmitLeft]; - let stackIndex = 0; - while (stackIndex >= 0) { - node = nodeStack[stackIndex]; - switch (stateStack[stackIndex]) { - case EmitBinaryExpressionState.EmitLeft: { - maybePipelineEmitExpression(node.left); - break; - } - case EmitBinaryExpressionState.EmitRight: { - const isCommaOperator = node.operatorToken.kind !== SyntaxKind.CommaToken; - const linesBeforeOperator = getLinesBetweenNodes(node, node.left, node.operatorToken); - const linesAfterOperator = getLinesBetweenNodes(node, node.operatorToken, node.right); - writeLinesAndIndent(linesBeforeOperator, isCommaOperator); - emitLeadingCommentsOfPosition(node.operatorToken.pos); - writeTokenNode(node.operatorToken, node.operatorToken.kind === SyntaxKind.InKeyword ? writeKeyword : writeOperator); - emitTrailingCommentsOfPosition(node.operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts - writeLinesAndIndent(linesAfterOperator, /*writeSpaceIfNotIndenting*/ true); - maybePipelineEmitExpression(node.right); - break; - } - case EmitBinaryExpressionState.FinishEmit: { - const linesBeforeOperator = getLinesBetweenNodes(node, node.left, node.operatorToken); - const linesAfterOperator = getLinesBetweenNodes(node, node.operatorToken, node.right); - decreaseIndentIf(linesBeforeOperator, linesAfterOperator); - stackIndex--; - break; - } - default: return Debug.fail(`Invalid state ${stateStack[stackIndex]} for emitBinaryExpressionWorker`); + return createBinaryExpressionTrampoline(onEnter, maybeEmitExpression, onOperator, maybeEmitExpression, onExit, /*foldState*/ undefined); + + function onEnter(node: BinaryExpression, state: WorkArea | undefined) { + if (state) { + state.stackIndex++; + state.preserveSourceNewlinesStack[state.stackIndex] = preserveSourceNewlines; + state.containerPosStack[state.stackIndex] = containerPos; + state.containerEndStack[state.stackIndex] = containerEnd; + state.declarationListContainerEndStack[state.stackIndex] = declarationListContainerEnd; + const emitComments = state.shouldEmitCommentsStack[state.stackIndex] = shouldEmitComments(node); + const emitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex] = shouldEmitSourceMaps(node); + beforeEmitWithContext(node, emitComments, emitSourceMaps); + } + else { + state = { + stackIndex: 0, + preserveSourceNewlinesStack: [undefined], + containerPosStack: [-1], + containerEndStack: [-1], + declarationListContainerEndStack: [-1], + shouldEmitCommentsStack: [false], + shouldEmitSourceMapsStack: [false], + }; + } + return state; + } + + function onOperator(operatorToken: BinaryOperatorToken, _state: WorkArea, node: BinaryExpression) { + const isCommaOperator = operatorToken.kind !== SyntaxKind.CommaToken; + const linesBeforeOperator = getLinesBetweenNodes(node, node.left, operatorToken); + const linesAfterOperator = getLinesBetweenNodes(node, operatorToken, node.right); + writeLinesAndIndent(linesBeforeOperator, isCommaOperator); + emitLeadingCommentsOfPosition(operatorToken.pos); + writeTokenNode(operatorToken, operatorToken.kind === SyntaxKind.InKeyword ? writeKeyword : writeOperator); + emitTrailingCommentsOfPosition(operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts + writeLinesAndIndent(linesAfterOperator, /*writeSpaceIfNotIndenting*/ true); + } + + function onExit(node: BinaryExpression, state: WorkArea) { + const linesBeforeOperator = getLinesBetweenNodes(node, node.left, node.operatorToken); + const linesAfterOperator = getLinesBetweenNodes(node, node.operatorToken, node.right); + decreaseIndentIf(linesBeforeOperator, linesAfterOperator); + if (state.stackIndex > 0) { + const savedPreserveSourceNewlines = state.preserveSourceNewlinesStack[state.stackIndex]; + const savedContainerPos = state.containerPosStack[state.stackIndex]; + const savedContainerEnd = state.containerEndStack[state.stackIndex]; + const savedDeclarationListContainerEnd = state.declarationListContainerEndStack[state.stackIndex]; + const shouldEmitComments = state.shouldEmitCommentsStack[state.stackIndex]; + const shouldEmitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex]; + afterEmitWithContext(node, shouldEmitComments, shouldEmitSourceMaps, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd, savedPreserveSourceNewlines); + state.stackIndex--; } } - function maybePipelineEmitExpression(next: Expression) { - // Advance the state of this unit of work, - stateStack[stackIndex]++; - - // Then actually do the work of emitting the node `next` returned by the prior state - - // The following section should be identical to `pipelineEmit` save it assumes EmitHint.Expression and offloads - // binary expression handling, where possible, to the contained work queue - - // #region trampolinePipelineEmit - const savedLastNode = lastNode; - const savedLastSubstitution = lastSubstitution; - lastNode = next; - lastSubstitution = undefined; - - const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.Expression, next); - if (pipelinePhase === pipelineEmitWithHint && isBinaryExpression(next)) { - // If the target pipeline phase is emit directly, and the next node's also a binary expression, - // skip all the intermediate indirection and push the expression directly onto the work stack - stackIndex++; - stateStack[stackIndex] = EmitBinaryExpressionState.EmitLeft; - nodeStack[stackIndex] = next; - } - else { - pipelinePhase(EmitHint.Expression, next); + function maybeEmitExpression(next: Expression) { + // Push a new frame for binary expressions, otherwise emit all other expressions. + if (isBinaryExpression(next)) { + return next; } - Debug.assert(lastNode === next); - - lastNode = savedLastNode; - lastSubstitution = savedLastSubstitution; - // #endregion trampolinePipelineEmit + emit(next); } } @@ -2625,17 +2611,17 @@ namespace ts { const linesBeforeColon = getLinesBetweenNodes(node, node.whenTrue, node.colonToken); const linesAfterColon = getLinesBetweenNodes(node, node.colonToken, node.whenFalse); - emitExpression(node.condition); + emit(node.condition); writeLinesAndIndent(linesBeforeQuestion, /*writeSpaceIfNotIndenting*/ true); emit(node.questionToken); writeLinesAndIndent(linesAfterQuestion, /*writeSpaceIfNotIndenting*/ true); - emitExpression(node.whenTrue); + emit(node.whenTrue); decreaseIndentIf(linesBeforeQuestion, linesAfterQuestion); writeLinesAndIndent(linesBeforeColon, /*writeSpaceIfNotIndenting*/ true); emit(node.colonToken); writeLinesAndIndent(linesAfterColon, /*writeSpaceIfNotIndenting*/ true); - emitExpression(node.whenFalse); + emit(node.whenFalse); decreaseIndentIf(linesBeforeColon, linesAfterColon); } @@ -2652,7 +2638,7 @@ namespace ts { function emitSpreadExpression(node: SpreadElement) { emitTokenWithComment(SyntaxKind.DotDotDotToken, node.pos, writePunctuation, node); - emitExpression(node.expression); + emit(node.expression); } function emitClassExpression(node: ClassExpression) { @@ -2661,12 +2647,12 @@ namespace ts { } function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { - emitExpression(node.expression); + emit(node.expression); emitTypeArguments(node, node.typeArguments); } function emitAsExpression(node: AsExpression) { - emitExpression(node.expression); + emit(node.expression); if (node.type) { writeSpace(); writeKeyword("as"); @@ -2676,7 +2662,7 @@ namespace ts { } function emitNonNullExpression(node: NonNullExpression) { - emitExpression(node.expression); + emit(node.expression); writeOperator("!"); } @@ -2691,7 +2677,7 @@ namespace ts { // function emitTemplateSpan(node: TemplateSpan) { - emitExpression(node.expression); + emit(node.expression); emit(node.literal); } @@ -2727,9 +2713,12 @@ namespace ts { } } + function emitEmbeddedEmptyStatement(_node: EmptyStatement) { + emitEmptyStatement(/*isEmbeddedStatement*/ true); + } function emitExpressionStatement(node: ExpressionStatement) { - emitExpression(node.expression); + emit(node.expression); // Emit semicolon in non json files // or if json file that created synthesized expression(eg.define expression statement when --out and amd code generation) if (!isJsonSourceFile(currentSourceFile!) || nodeIsSynthesized(node.expression)) { @@ -2741,7 +2730,7 @@ namespace ts { const openParenPos = emitTokenWithComment(SyntaxKind.IfKeyword, node.pos, writeKeyword, node); writeSpace(); emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node); - emitExpression(node.expression); + emit(node.expression); emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node); emitEmbeddedStatement(node, node.thenStatement); if (node.elseStatement) { @@ -2761,7 +2750,7 @@ namespace ts { const openParenPos = emitTokenWithComment(SyntaxKind.WhileKeyword, startPos, writeKeyword, node); writeSpace(); emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node); - emitExpression(node.expression); + emit(node.expression); emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node); } @@ -2805,7 +2794,7 @@ namespace ts { writeSpace(); emitTokenWithComment(SyntaxKind.InKeyword, node.initializer.end, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node); emitEmbeddedStatement(node, node.statement); } @@ -2819,7 +2808,7 @@ namespace ts { writeSpace(); emitTokenWithComment(SyntaxKind.OfKeyword, node.initializer.end, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node); emitEmbeddedStatement(node, node.statement); } @@ -2830,7 +2819,7 @@ namespace ts { emit(node); } else { - emitExpression(node); + emit(node); } } } @@ -2882,7 +2871,7 @@ namespace ts { const openParenPos = emitTokenWithComment(SyntaxKind.WithKeyword, node.pos, writeKeyword, node); writeSpace(); emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node); - emitExpression(node.expression); + emit(node.expression); emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node); emitEmbeddedStatement(node, node.statement); } @@ -2891,7 +2880,7 @@ namespace ts { const openParenPos = emitTokenWithComment(SyntaxKind.SwitchKeyword, node.pos, writeKeyword, node); writeSpace(); emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node); - emitExpression(node.expression); + emit(node.expression); emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node); writeSpace(); emit(node.caseBlock); @@ -2958,14 +2947,10 @@ namespace ts { writeKeyword("function"); emit(node.asteriskToken); writeSpace(); - emitIdentifierName(node.name); + emit(node.name); emitSignatureAndBody(node, emitSignatureHead); } - function emitBlockCallback(_hint: EmitHint, body: Node): void { - emitBlockFunctionBody(body); - } - function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) { const body = node.body; if (body) { @@ -2980,12 +2965,7 @@ namespace ts { generateNames(node.body); emitSignatureHead(node); - if (onEmitNode) { - onEmitNode(EmitHint.Unspecified, body, emitBlockCallback); - } - else { - emitBlockFunctionBody(body); - } + emitBlockFunctionBody(body); popNameGenerationScope(node); if (indentedFlag) { @@ -2995,7 +2975,7 @@ namespace ts { else { emitSignatureHead(node); writeSpace(); - emitExpression(body); + emit(body); } } else { @@ -3050,6 +3030,7 @@ namespace ts { } function emitBlockFunctionBody(body: Block) { + onBeforeEmitNode?.(body); writeSpace(); writePunctuation("{"); increaseIndent(); @@ -3067,6 +3048,7 @@ namespace ts { decreaseIndent(); writeToken(SyntaxKind.CloseBraceToken, body.statements.end, writePunctuation, body); + onAfterEmitNode?.(body); } function emitBlockFunctionBodyOnSingleLine(body: Block) { @@ -3100,7 +3082,7 @@ namespace ts { writeKeyword("class"); if (node.name) { writeSpace(); - emitIdentifierName(node.name); + emit(node.name); } const indentedFlag = getEmitFlags(node) & EmitFlags.Indented; @@ -3212,7 +3194,7 @@ namespace ts { function emitModuleReference(node: ModuleReference) { if (node.kind === SyntaxKind.Identifier) { - emitExpression(node); + emit(node); } else { emit(node); @@ -3229,7 +3211,7 @@ namespace ts { emitTokenWithComment(SyntaxKind.FromKeyword, node.importClause.end, writeKeyword, node); writeSpace(); } - emitExpression(node.moduleSpecifier); + emit(node.moduleSpecifier); writeTrailingSemicolon(); } @@ -3272,7 +3254,7 @@ namespace ts { emitTokenWithComment(SyntaxKind.DefaultKeyword, nextPos, writeKeyword, node); } writeSpace(); - emitExpression(node.expression); + emit(node.expression); writeTrailingSemicolon(); } @@ -3294,7 +3276,7 @@ namespace ts { const fromPos = node.exportClause ? node.exportClause.end : nextPos; emitTokenWithComment(SyntaxKind.FromKeyword, fromPos, writeKeyword, node); writeSpace(); - emitExpression(node.moduleSpecifier); + emit(node.moduleSpecifier); } writeTrailingSemicolon(); } @@ -3350,7 +3332,7 @@ namespace ts { function emitExternalModuleReference(node: ExternalModuleReference) { writeKeyword("require"); writePunctuation("("); - emitExpression(node.expression); + emit(node.expression); writePunctuation(")"); } @@ -3413,6 +3395,11 @@ namespace ts { emitList(node, node.properties, ListFormat.JsxElementAttributes); } + function emitJsxAttributeValue(node: StringLiteral | JsxExpression): void { + const emitCallback = isStringLiteral(node) ? emitStringLiteralWithJsxAttributeEscape : emitWorker; + emitWithContext(node, emitCallback); + } + function emitJsxAttribute(node: JsxAttribute) { emit(node.name); emitNodeWithPrefix("=", writePunctuation, node.initializer, emitJsxAttributeValue); @@ -3420,7 +3407,7 @@ namespace ts { function emitJsxSpreadAttribute(node: JsxSpreadAttribute) { writePunctuation("{..."); - emitExpression(node.expression); + emit(node.expression); writePunctuation("}"); } @@ -3448,7 +3435,7 @@ namespace ts { } const end = emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, node); emit(node.dotDotDotToken); - emitExpression(node.expression); + emit(node.expression); emitTokenWithComment(SyntaxKind.CloseBraceToken, node.expression?.end || end, writePunctuation, node); if (isMultiline) { writer.decreaseIndent(); @@ -3458,7 +3445,7 @@ namespace ts { function emitJsxTagName(node: JsxTagNameExpression) { if (node.kind === SyntaxKind.Identifier) { - emitExpression(node); + emit(node); } else { emit(node); @@ -3472,7 +3459,7 @@ namespace ts { function emitCaseClause(node: CaseClause) { emitTokenWithComment(SyntaxKind.CaseKeyword, node.pos, writeKeyword, node); writeSpace(); - emitExpression(node.expression); + emit(node.expression); emitCaseOrDefaultClauseRest(node, node.statements, node.expression.end); } @@ -3543,7 +3530,7 @@ namespace ts { const commentRange = getCommentRange(initializer); emitTrailingCommentsOfPosition(commentRange.pos); } - emitExpression(initializer); + emit(initializer); } function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { @@ -3552,14 +3539,14 @@ namespace ts { writeSpace(); writePunctuation("="); writeSpace(); - emitExpression(node.objectAssignmentInitializer); + emit(node.objectAssignmentInitializer); } } function emitSpreadAssignment(node: SpreadAssignment) { if (node.expression) { emitTokenWithComment(SyntaxKind.DotDotDotToken, node.pos, writePunctuation, node); - emitExpression(node.expression); + emit(node.expression); } } @@ -3826,11 +3813,11 @@ namespace ts { // Transformation nodes function emitPartiallyEmittedExpression(node: PartiallyEmittedExpression) { - emitExpression(node.expression); + emit(node.expression); } function emitCommaList(node: CommaListExpression) { - emitExpressionList(node, node.elements, ListFormat.CommaListElements); + emitList(node, node.elements, ListFormat.CommaListElements); } /** @@ -3980,7 +3967,7 @@ namespace ts { writeSpace(); emitTokenWithComment(SyntaxKind.EqualsToken, equalCommentStartPos, writeOperator, container); writeSpace(); - emitExpression(node); + emit(node); } } @@ -4001,7 +3988,7 @@ namespace ts { function emitExpressionWithLeadingSpace(node: Expression | undefined) { if (node) { writeSpace(); - emitExpression(node); + emit(node); } } @@ -4021,7 +4008,7 @@ namespace ts { writeLine(); increaseIndent(); if (isEmptyStatement(node)) { - pipelineEmit(EmitHint.EmbeddedStatement, node); + emitWithContext(node, emitEmbeddedEmptyStatement); } else { emit(node); @@ -4080,14 +4067,6 @@ namespace ts { emitList(parentNode, parameters, ListFormat.IndexSignatureParameters); } - function emitList(parentNode: TextRange, children: NodeArray | undefined, format: ListFormat, start?: number, count?: number) { - emitNodeList(emit, parentNode, children, format, start, count); - } - - function emitExpressionList(parentNode: TextRange, children: NodeArray | undefined, format: ListFormat, start?: number, count?: number) { - emitNodeList(emitExpression as (node: Node) => void, parentNode, children, format, start, count); // TODO: GH#18217 - } - function writeDelimiter(format: ListFormat) { switch (format & ListFormat.DelimitersMask) { case ListFormat.None: @@ -4111,7 +4090,7 @@ namespace ts { } } - function emitNodeList(emit: (node: Node) => void, parentNode: TextRange, children: NodeArray | undefined, format: ListFormat, start = 0, count = children ? children.length - start : 0) { + function emitList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, start = 0, count = children ? children.length - start : 0) { const isUndefined = children === undefined; if (isUndefined && format & ListFormat.OptionalIfUndefined) { return; @@ -4130,9 +4109,8 @@ namespace ts { if (format & ListFormat.BracketsMask) { writePunctuation(getOpeningBracket(format)); - if (isEmpty && !isUndefined) { - // TODO: GH#18217 - emitTrailingCommentsOfPosition(children!.pos, /*prefixSpace*/ true); // Emit comments within empty bracketed lists + if (isEmpty && children) { + emitTrailingCommentsOfPosition(children.pos, /*prefixSpace*/ true); // Emit comments within empty bracketed lists } } @@ -4142,7 +4120,7 @@ namespace ts { if (isEmpty) { // Write a line terminator if the parent node was multi-line - if (format & ListFormat.MultiLine && !(preserveSourceNewlines && rangeIsOnSingleLine(parentNode, currentSourceFile!))) { + if (format & ListFormat.MultiLine && !(preserveSourceNewlines && (!parentNode || rangeIsOnSingleLine(parentNode, currentSourceFile!)))) { writeLine(); } else if (format & ListFormat.SpaceBetweenBraces && !(format & ListFormat.NoSpaceIfEmpty)) { @@ -4150,10 +4128,11 @@ namespace ts { } } else { + Debug.type>(children); // Write the opening line terminator or leading whitespace. const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0; let shouldEmitInterveningComments = mayEmitInterveningComments; - const leadingLineTerminatorCount = getLeadingLineTerminatorCount(parentNode, children!, format); // TODO: GH#18217 + const leadingLineTerminatorCount = getLeadingLineTerminatorCount(parentNode, children, format); // TODO: GH#18217 if (leadingLineTerminatorCount) { writeLine(leadingLineTerminatorCount); shouldEmitInterveningComments = false; @@ -4172,7 +4151,7 @@ namespace ts { let previousSourceFileTextKind: ReturnType; let shouldDecreaseIndentAfterEmit = false; for (let i = 0; i < count; i++) { - const child = children![start + i]; + const child = children[start + i]; // Write the delimiter if this is not the first node. if (format & ListFormat.AsteriskDelimited) { @@ -4187,7 +4166,7 @@ namespace ts { // a // /* End of parameter a */ -> this comment isn't considered to be trailing comment of parameter "a" due to newline // , - if (format & ListFormat.DelimitersMask && previousSibling.end !== parentNode.end) { + if (format & ListFormat.DelimitersMask && previousSibling.end !== (parentNode ? parentNode.end : -1)) { emitLeadingCommentsOfPosition(previousSibling.end); } writeDelimiter(format); @@ -4253,7 +4232,7 @@ namespace ts { // 2 // /* end of element 2 */ // ]; - if (previousSibling && parentNode.end !== previousSibling.end && (format & ListFormat.DelimitersMask) && !skipTrailingComments) { + if (previousSibling && (parentNode ? parentNode.end : -1) !== previousSibling.end && (format & ListFormat.DelimitersMask) && !skipTrailingComments) { emitLeadingCommentsOfPosition(hasTrailingComma && children?.end ? children.end : previousSibling.end); } @@ -4265,7 +4244,7 @@ namespace ts { recordBundleFileInternalSectionEnd(previousSourceFileTextKind); // Write the closing line terminator or closing whitespace. - const closingLineTerminatorCount = getClosingLineTerminatorCount(parentNode, children!, format); + const closingLineTerminatorCount = getClosingLineTerminatorCount(parentNode, children, format); if (closingLineTerminatorCount) { writeLine(closingLineTerminatorCount); } @@ -4279,9 +4258,8 @@ namespace ts { } if (format & ListFormat.BracketsMask) { - if (isEmpty && !isUndefined) { - // TODO: GH#18217 - emitLeadingCommentsOfPosition(children!.end); // Emit leading comments within empty lists + if (isEmpty && children) { + emitLeadingCommentsOfPosition(children.end); // Emit leading comments within empty lists } writePunctuation(getClosingBracket(format)); } @@ -4428,7 +4406,7 @@ namespace ts { } } - function getLeadingLineTerminatorCount(parentNode: TextRange, children: readonly Node[], format: ListFormat): number { + function getLeadingLineTerminatorCount(parentNode: Node | undefined, children: readonly Node[], format: ListFormat): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (format & ListFormat.PreferNewLine) { return 1; @@ -4436,7 +4414,7 @@ namespace ts { const firstChild = children[0]; if (firstChild === undefined) { - return rangeIsOnSingleLine(parentNode, currentSourceFile!) ? 0 : 1; + return !parentNode || rangeIsOnSingleLine(parentNode, currentSourceFile!) ? 0 : 1; } if (firstChild.pos === nextListElementPos) { // If this child starts at the beginning of a list item in a parent list, its leading @@ -4460,9 +4438,10 @@ namespace ts { // JsxText will be written with its leading whitespace, so don't add more manually. return 0; } - if (!positionIsSynthesized(parentNode.pos) && + if (parentNode && + !positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(firstChild) && - (!firstChild.parent || getOriginalNode(firstChild.parent) === getOriginalNode(parentNode as Node)) + (!firstChild.parent || getOriginalNode(firstChild.parent) === getOriginalNode(parentNode)) ) { if (preserveSourceNewlines) { return getEffectiveLines( @@ -4490,8 +4469,8 @@ namespace ts { // JsxText will be written with its leading whitespace, so don't add more manually. return 0; } - else if (!nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode) && previousNode.parent === nextNode.parent) { - if (preserveSourceNewlines) { + else if (!nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode) && (!previousNode.parent || !nextNode.parent || previousNode.parent === nextNode.parent)) { + if (preserveSourceNewlines && previousNode.parent && nextNode.parent) { return getEffectiveLines( includeComments => getLinesBetweenRangeEndAndRangeStart( previousNode, @@ -4511,7 +4490,7 @@ namespace ts { return format & ListFormat.MultiLine ? 1 : 0; } - function getClosingLineTerminatorCount(parentNode: TextRange, children: readonly Node[], format: ListFormat): number { + function getClosingLineTerminatorCount(parentNode: Node | undefined, children: readonly Node[], format: ListFormat): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (format & ListFormat.PreferNewLine) { return 1; @@ -4519,9 +4498,9 @@ namespace ts { const lastChild = lastOrUndefined(children); if (lastChild === undefined) { - return rangeIsOnSingleLine(parentNode, currentSourceFile!) ? 0 : 1; + return !parentNode || rangeIsOnSingleLine(parentNode, currentSourceFile!) ? 0 : 1; } - if (!positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(lastChild) && (!lastChild.parent || lastChild.parent === parentNode)) { + if (parentNode && !positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(lastChild) && (!lastChild.parent || lastChild.parent === parentNode)) { if (preserveSourceNewlines) { const end = isNodeArray(children) && !positionIsSynthesized(children.end) ? children.end : lastChild.end; return getEffectiveLines( @@ -5072,13 +5051,9 @@ namespace ts { // Comments - function pipelineEmitWithComments(hint: EmitHint, node: Node) { - Debug.assert(lastNode === node || lastSubstitution === node); + function emitLeadingCommentsOfNode(node: Node, emitFlags: EmitFlags, pos: number, end: number) { enterComment(); hasWrittenComment = false; - const emitFlags = getEmitFlags(node); - const { pos, end } = getCommentRange(node); - const isEmittedNode = node.kind !== SyntaxKind.NotEmittedStatement; // We have to explicitly check that the node is JsxText because if the compilerOptions.jsx is "preserve" we will not do any transformation. // It is expensive to walk entire tree just to set one kind of node to have no comments. @@ -5086,14 +5061,11 @@ namespace ts { const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText; // Save current container state on the stack. - const savedContainerPos = containerPos; - const savedContainerEnd = containerEnd; - const savedDeclarationListContainerEnd = declarationListContainerEnd; if ((pos > 0 || end > 0) && pos !== end) { // Emit leading comments if the position is not synthesized and the node // has not opted out from emitting leading comments. if (!skipLeadingComments) { - emitLeadingComments(pos, isEmittedNode); + emitLeadingComments(pos, /*isEmittedNode*/ node.kind !== SyntaxKind.NotEmittedStatement); } if (!skipLeadingComments || (pos >= 0 && (emitFlags & EmitFlags.NoLeadingComments) !== 0)) { @@ -5114,18 +5086,11 @@ namespace ts { } forEach(getSyntheticLeadingComments(node), emitLeadingSynthesizedComment); exitComment(); + } - const pipelinePhase = getNextPipelinePhase(PipelinePhase.Comments, hint, node); - if (emitFlags & EmitFlags.NoNestedComments) { - commentsDisabled = true; - pipelinePhase(hint, node); - commentsDisabled = false; - } - else { - pipelinePhase(hint, node); - } - + function emitTrailingCommentsOfNode(node: Node, emitFlags: EmitFlags, pos: number, end: number, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number) { enterComment(); + const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText; forEach(getSyntheticTrailingComments(node), emitTrailingSynthesizedComment); if ((pos > 0 || end > 0) && pos !== end) { // Restore previous container state. @@ -5135,12 +5100,11 @@ namespace ts { // Emit trailing comments if the position is not synthesized and the node // has not opted out from emitting leading comments and is an emitted node. - if (!skipTrailingComments && isEmittedNode) { + if (!skipTrailingComments && node.kind !== SyntaxKind.NotEmittedStatement) { emitTrailingComments(end); } } exitComment(); - Debug.assert(lastNode === node || lastSubstitution === node); } function emitLeadingSynthesizedComment(comment: SynthesizedComment) { @@ -5409,53 +5373,6 @@ namespace ts { return node.parsedSourceMap || undefined; } - function pipelineEmitWithSourceMap(hint: EmitHint, node: Node) { - Debug.assert(lastNode === node || lastSubstitution === node); - const pipelinePhase = getNextPipelinePhase(PipelinePhase.SourceMaps, hint, node); - if (isUnparsedSource(node) || isUnparsedPrepend(node)) { - pipelinePhase(hint, node); - } - else if (isUnparsedNode(node)) { - const parsed = getParsedSourceMap(node.parent); - if (parsed && sourceMapGenerator) { - sourceMapGenerator.appendSourceMap( - writer.getLine(), - writer.getColumn(), - parsed, - node.parent.sourceMapPath!, - node.parent.getLineAndCharacterOfPosition(node.pos), - node.parent.getLineAndCharacterOfPosition(node.end) - ); - } - pipelinePhase(hint, node); - } - else { - const { pos, end, source = sourceMapSource } = getSourceMapRange(node); - const emitFlags = getEmitFlags(node); - if (node.kind !== SyntaxKind.NotEmittedStatement - && (emitFlags & EmitFlags.NoLeadingSourceMap) === 0 - && pos >= 0) { - emitSourcePos(source, skipSourceTrivia(source, pos)); - } - - if (emitFlags & EmitFlags.NoNestedSourceMaps) { - sourceMapsDisabled = true; - pipelinePhase(hint, node); - sourceMapsDisabled = false; - } - else { - pipelinePhase(hint, node); - } - - if (node.kind !== SyntaxKind.NotEmittedStatement - && (emitFlags & EmitFlags.NoTrailingSourceMap) === 0 - && end >= 0) { - emitSourcePos(source, end); - } - } - Debug.assert(lastNode === node || lastSubstitution === node); - } - /** * Skips trivia such as comments and white-space that can be optionally overridden by the source-map source */ @@ -5569,6 +5486,1249 @@ namespace ts { } } + const enum PreprintPipelinePhase { + Notification, + Substitution, + Visit + } + + function createPreprinter(handlers: PrintHandlers) { + const { + substituteNode = noEmitSubstitution, + onEmitNode = noEmitNotification, + isEmitNotificationEnabled + } = handlers; + + let pipelineResult: Node | undefined; + + // Outer visitors + // + // These visitors are invoked by inner visitors to re-enter the pipeline + // for notification and substitution. + + const visit = makeVisitor(pipelineVisitorForUnspecified); + const visitSourceFile = makeVisitor(pipelineVisitorForSourceFile, isSourceFile); + const visitIdentifierName = makeVisitor(pipelineVisitorForIdentifierName, isIdentifier); + const visitModuleName = makeVisitor(pipelineVisitorForIdentifierNameOrUnspecified, isModuleName); + const visitPropertyName = makeVisitor(pipelineVisitorForIdentifierNameOrUnspecified, isPropertyName); + const visitMemberName = makeVisitor(pipelineVisitorForIdentifierNameOrUnspecified, isMemberName); + const visitBindingName = makeVisitor(pipelineVisitorForIdentifierNameOrUnspecified, isBindingName); + const visitEntityName = makeVisitor(pipelineVisitorForIdentifierReferenceOrUnspecified, isEntityName); + const visitExpression = makeVisitor(pipelineVisitorForExpression, isExpression); + const visitForInitializer = makeVisitor(pipelineVisitorForForInitializer, isForInitializer); + const visitTypeNode = makeVisitor(pipelineVisitorForUnspecified, isTypeNode); + const visitEmbeddedStatement = makeVisitor(pipelineVisitorForEmbeddedStatement, isStatement, factory.liftToBlock); + const visitJsxAttributeValue = makeVisitor(pipelineVisitorForJsxAttributeValue, isStringLiteralOrJsxExpression); + const visitMappedTypeParameter = makeVisitor(pipelineVisitorForMappedTypeParameter, isTypeParameterDeclaration); + const visitConciseBody = makeVisitor(pipelineVisitorForConciseBody, isConciseBody); + const visitFunctionBody = makeVisitor(pipelineVisitorForUnspecified, isFunctionBody); + const visitList = makeListVisitor(pipelineVisitorForUnspecified); + const visitTypeNodeList = makeListVisitor(pipelineVisitorForUnspecified, isTypeNode); + const visitExpressionList = makeListVisitor(pipelineVisitorForExpression, isExpression); + const visitParameterList = makeListVisitor(pipelineVisitorForUnspecified, isParameter); + + function makeVisitor(outerVisitor: (node: Node) => Node | undefined, defaultTest?: (node: Node) => node is T, lift?: (nodes: readonly Node[]) => Node) { + function visit(node: T, test: (node: Node) => node is U): U; + function visit(node: T | undefined, test: (node: Node) => node is U): U | undefined; + function visit(node: T, test?: (node: Node) => node is T): T; + function visit(node: T | undefined, test?: (node: Node) => node is T): T | undefined; + function visit(node: Node | undefined, test?: (node: Node) => node is T): Node | undefined { + return visitNode(node, outerVisitor, test || defaultTest, lift); + } + return visit; + } + + function makeListVisitor(outerVisitor: (node: Node) => Node | undefined, defaultTest?: (node: Node) => node is T) { + function visitList(nodes: NodeArray, test: (node: Node) => node is U): NodeArray; + function visitList(nodes: NodeArray | undefined, test: (node: Node) => node is U): NodeArray | undefined; + function visitList(nodes: NodeArray, test?: (node: Node) => boolean): NodeArray; + function visitList(nodes: NodeArray | undefined, test?: (node: Node) => boolean): NodeArray | undefined; + function visitList(nodes: NodeArray | undefined, test: (node: Node) => boolean = defaultTest || returnTrue): NodeArray | undefined { + return visitNodes(nodes, outerVisitor, test); + } + return visitList; + } + + // Pipeline Visitors + // + // These visitors execute our existing pipeline logic for notification and substitution, + // but adapted to our visitor pattern. In some cases, we refine the `EmitHint` we pass + // to the `onEmitNode` and `substituteNode` APIs to ensure they receive the appropriate + // context. + // + // For example, the ConciseBody of an arrow function could be an Identifier, in which + // case we would want to use `EmitHint.Expression` to ensure we treat the identifier + // as an expression during substitution. + + function pipelineVisitorForSourceFile(node: SourceFile) { return pipelineVisitorWorker(EmitHint.SourceFile, node); } + function pipelineVisitorForExpression(node: Expression) { return pipelineVisitorWorker(EmitHint.Expression, node); } + function pipelineVisitorForIdentifierName(node: Identifier) { return pipelineVisitorWorker(EmitHint.IdentifierName, node); } + function pipelineVisitorForIdentifierNameOrUnspecified(node: Node) { return pipelineVisitorWorker(isIdentifier(node) ? EmitHint.IdentifierName : EmitHint.Unspecified, node); } + function pipelineVisitorForIdentifierReferenceOrUnspecified(node: Node) { return pipelineVisitorWorker(isIdentifier(node) ? EmitHint.Expression : EmitHint.Unspecified, node); } + function pipelineVisitorForForInitializer(node: ForInitializer) { return pipelineVisitorWorker(isVariableDeclarationList(node) ? EmitHint.Unspecified : EmitHint.Expression, node); } + function pipelineVisitorForMappedTypeParameter(node: TypeParameterDeclaration) { return pipelineVisitorWorker(EmitHint.MappedTypeParameter, node); } + function pipelineVisitorForEmbeddedStatement(node: Statement) { return pipelineVisitorWorker(isEmptyStatement(node) ? EmitHint.EmbeddedStatement : EmitHint.Unspecified, node); } + function pipelineVisitorForJsxAttributeValue(node: StringLiteral | JsxExpression) { return pipelineVisitorWorker(isStringLiteral(node) ? EmitHint.JsxAttributeValue : EmitHint.Unspecified, node); } + function pipelineVisitorForConciseBody(node: ConciseBody) { return pipelineVisitorWorker(isBlock(node) ? EmitHint.Unspecified : EmitHint.Expression, node); } + function pipelineVisitorForUnspecified(node: Node) { return pipelineVisitorWorker(EmitHint.Unspecified, node); } + + /** + * Adapts the emit pipeline API to work with the visitor API + */ + function pipelineVisitorWorker(hint: EmitHint, node: Node) { + resetPipelineResult(); + // Get the first supported pipeline phase for this node and evaluate it. We can skip several stack + // frames if we aren't doing emit notification, so we check for substitution and direct callbacks + // and execute those immediately. + const pipelinePhase = getPipelinePhase(PreprintPipelinePhase.Notification, node); + if (pipelinePhase === pipelineVisitDirect) { + return visitor(hint, node); + } + + if (pipelinePhase === pipelineVisitWithSubstitution) { + // The next phase after substitution is always direct visitation, so we can reduce the call stack + // depth by calling the visitor directly. + return visitor(hint, substituteNode(hint, node)); + } + + pipelinePhase(hint, node); + Debug.assertIsDefined(pipelineResult); + const result = pipelineResult; + resetPipelineResult(); + return result; + } + + function resetPipelineResult() { + pipelineResult = undefined; + } + + /** + * Gets the pipeline callback to pass to the relevant API (i.e., `substituteNode` or `onEmitNode`) + */ + function getPipelinePhase(phase: PreprintPipelinePhase, node: Node) { + switch (phase) { + case PreprintPipelinePhase.Notification: + if (onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node))) { + return pipelineVisitWithNotification; + } + // falls through + case PreprintPipelinePhase.Substitution: + if (substituteNode !== noEmitSubstitution) { + return pipelineVisitWithSubstitution; + } + // falls through + default: + return pipelineVisitDirect; + } + } + + /** + * A callback that can be evaluated to trigger emit notification as part of the emit pipeline. + */ + function pipelineVisitWithNotification(hint: EmitHint, node: Node) { + onEmitNode(hint, node, getPipelinePhase(PreprintPipelinePhase.Substitution, node)); + } + + /** + * A callback that can be evaluated to trigger JIT substitution as part of the emit pipeline. + */ + function pipelineVisitWithSubstitution(hint: EmitHint, node: Node) { + // Next phase is always direct visitation, so we can reduce the call stack + // depth by calling the visitor directly. + pipelineResult = visitor(hint, substituteNode(hint, node)); + } + + /** + * A callback that can be evaluated to visit the subtree of a node. + */ + function pipelineVisitDirect(hint: EmitHint, node: Node) { + pipelineResult = visitor(hint, node); + } + + /** + * Re-enters the visitor pattern from the pipeline pattern to perform + * tree updates and trigger parenthesization rules. + */ + function visitor(hint: EmitHint, node: Node): Node { + // This should align with the assertions in `pipelineEmitWithHint`. + if (hint === EmitHint.SourceFile) return preprintSourceFile(cast(node, isSourceFile)); + if (hint === EmitHint.IdentifierName) return preprintIdentifier(cast(node, isIdentifier)); + if (hint === EmitHint.JsxAttributeValue) return cast(node, isStringLiteral); + if (hint === EmitHint.MappedTypeParameter) return preprintTypeParameterDeclaration(cast(node, isTypeParameterDeclaration)); + if (hint === EmitHint.EmbeddedStatement) return cast(node, isEmptyStatement); + + const kind = node.kind; + // No need to visit nodes without children. + if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken) || kind === SyntaxKind.ThisType) { + return node; + } + + if (hint === EmitHint.Unspecified) { + if (isKeyword(node.kind)) return node; + + switch (node.kind) { + // Identifiers + case SyntaxKind.Identifier: + return preprintIdentifier(node as Identifier); + + // Names + case SyntaxKind.QualifiedName: + Debug.type(node); + return factory.updateQualifiedName(node, + visitEntityName(node.left), + visitIdentifierName(node.right)); + + case SyntaxKind.ComputedPropertyName: + Debug.type(node); + return factory.updateComputedPropertyName(node, + visitExpression(node.expression)); + + // Signature elements + case SyntaxKind.TypeParameter: + return preprintTypeParameterDeclaration(node as TypeParameterDeclaration); + + case SyntaxKind.Parameter: + Debug.type(node); + return factory.updateParameterDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visit(node.dotDotDotToken, isDotDotDotToken), + visitBindingName(node.name), + visit(node.questionToken, isQuestionToken), + visitTypeNode(node.type), + visitExpression(node.initializer)); + + case SyntaxKind.Decorator: + Debug.type(node); + return factory.updateDecorator(node, + visitExpression(node.expression)); + + // Type members + case SyntaxKind.PropertySignature: + Debug.type(node); + return factory.updatePropertySignature(node, + visitList(node.modifiers, isModifier), + visitPropertyName(node.name), + visit(node.questionToken, isQuestionToken), + visitTypeNode(node.type)); + + case SyntaxKind.PropertyDeclaration: + Debug.type(node); + return factory.updatePropertyDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitPropertyName(node.name), + visit(node.questionToken || node.exclamationToken, isQuestionOrExclamationToken), + visitTypeNode(node.type), + visitExpression(node.initializer)); + + case SyntaxKind.MethodSignature: + Debug.type(node); + return factory.updateMethodSignature(node, + visitList(node.modifiers, isModifier), + visitPropertyName(node.name), + visit(node.questionToken, isQuestionToken), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type)); + + case SyntaxKind.MethodDeclaration: + Debug.type(node); + return factory.updateMethodDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visit(node.asteriskToken, isAsteriskToken), + visitPropertyName(node.name), + visit(node.questionToken, isQuestionToken), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type), + visitFunctionBody(node.body)); + + case SyntaxKind.Constructor: + Debug.type(node); + return factory.updateConstructorDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitParameterList(node.parameters), + visitFunctionBody(node.body)); + + case SyntaxKind.GetAccessor: + Debug.type(node); + return factory.updateGetAccessorDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitPropertyName(node.name), + visitParameterList(node.parameters), + visitTypeNode(node.type), + visitFunctionBody(node.body)); + + case SyntaxKind.SetAccessor: + Debug.type(node); + return factory.updateSetAccessorDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitPropertyName(node.name), + visitParameterList(node.parameters), + visitFunctionBody(node.body)); + + case SyntaxKind.CallSignature: + Debug.type(node); + return factory.updateCallSignature(node, + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type)); + + case SyntaxKind.ConstructSignature: + Debug.type(node); + return factory.updateConstructSignature(node, + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type)); + + case SyntaxKind.IndexSignature: + Debug.type(node); + return factory.updateIndexSignature(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitParameterList(node.parameters), + visitTypeNode(node.type)); + + // Types + case SyntaxKind.TypePredicate: + Debug.type(node); + return factory.updateTypePredicateNode(node, + visit(node.assertsModifier, isAssertsKeyword), + visit(node.parameterName, isIdentifierOrThisTypeNode), + visitTypeNode(node.type)); + + case SyntaxKind.TypeReference: + Debug.type(node); + return factory.updateTypeReferenceNode(node, + visitEntityName(node.typeName), + visitTypeNodeList(node.typeArguments)); + + case SyntaxKind.FunctionType: + Debug.type(node); + return factory.updateFunctionTypeNode(node, + visitList(node.typeParameters, isTypeParameterDeclaration), + visitNodes(node.parameters, pipelineVisitorForUnspecified, isParameterDeclaration), + visitTypeNode(node.type)); + + case SyntaxKind.ConstructorType: + Debug.type(node); + return factory.updateConstructorTypeNode(node, + visitNodes(node.modifiers, pipelineVisitorForUnspecified, isModifier), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type)); + + case SyntaxKind.TypeQuery: + Debug.type(node); + return factory.updateTypeQueryNode(node, + visitEntityName(node.exprName)); + + case SyntaxKind.TypeLiteral: + Debug.type(node); + return factory.updateTypeLiteralNode(node, + visitList(node.members, isTypeElement)); + + case SyntaxKind.ArrayType: + Debug.type(node); + return factory.updateArrayTypeNode(node, + visitTypeNode(node.elementType)); + + case SyntaxKind.TupleType: + Debug.type(node); + return factory.updateTupleTypeNode(node, + visitTypeNodeList(node.elements)); + + case SyntaxKind.OptionalType: + Debug.type(node); + return factory.updateOptionalTypeNode(node, + visitTypeNode(node.type)); + + case SyntaxKind.RestType: + Debug.type(node); + return factory.updateRestTypeNode(node, + visitTypeNode(node.type)); + + case SyntaxKind.UnionType: + Debug.type(node); + return factory.updateUnionTypeNode(node, + visitTypeNodeList(node.types)); + + case SyntaxKind.IntersectionType: + Debug.type(node); + return factory.updateIntersectionTypeNode(node, + visitTypeNodeList(node.types)); + + case SyntaxKind.ConditionalType: + Debug.type(node); + return factory.updateConditionalTypeNode(node, + visitTypeNode(node.checkType), + visitTypeNode(node.extendsType), + visitTypeNode(node.trueType), + visitTypeNode(node.falseType)); + + case SyntaxKind.InferType: + Debug.type(node); + return factory.updateInferTypeNode(node, + visit(node.typeParameter, isTypeParameterDeclaration)); + + case SyntaxKind.ImportType: + Debug.type(node); + return factory.updateImportTypeNode(node, + visitTypeNode(node.argument), + visitEntityName(node.qualifier), + visitTypeNodeList(node.typeArguments), + node.isTypeOf + ); + + case SyntaxKind.NamedTupleMember: + Debug.type(node); + return factory.updateNamedTupleMember(node, + visit(node.dotDotDotToken, isDotDotDotToken), + visitIdentifierName(node.name), + visit(node.questionToken, isQuestionToken), + visitTypeNode(node.type), + ); + + case SyntaxKind.ParenthesizedType: + Debug.type(node); + return factory.updateParenthesizedType(node, + visitTypeNode(node.type)); + + case SyntaxKind.ExpressionWithTypeArguments: + Debug.type(node); + return factory.updateExpressionWithTypeArguments(node, + visitExpression(node.expression), + visitTypeNodeList(node.typeArguments)); + + case SyntaxKind.TypeOperator: + Debug.type(node); + return factory.updateTypeOperatorNode(node, + visitTypeNode(node.type)); + + case SyntaxKind.IndexedAccessType: + Debug.type(node); + return factory.updateIndexedAccessTypeNode(node, + visitTypeNode(node.objectType), + visitTypeNode(node.indexType)); + + case SyntaxKind.MappedType: + Debug.type(node); + return factory.updateMappedTypeNode(node, + visit(node.readonlyToken, isReadonlyKeywordOrPlusOrMinusToken), + visitMappedTypeParameter(node.typeParameter), + visitTypeNode(node.nameType), + visit(node.questionToken, isQuestionOrPlusOrMinusToken), + visitTypeNode(node.type)); + + case SyntaxKind.LiteralType: + Debug.type(node); + return factory.updateLiteralTypeNode(node, + visitExpression(node.literal, isLiteralTypeLikeExpression)); + + case SyntaxKind.TemplateLiteralType: + Debug.type(node); + return factory.updateTemplateLiteralType(node, + visit(node.head, isTemplateHead), + visitList(node.templateSpans, isTemplateLiteralTypeSpan)); + + case SyntaxKind.TemplateLiteralTypeSpan: + Debug.type(node); + return factory.updateTemplateLiteralTypeSpan(node, + visitTypeNode(node.type), + visit(node.literal, isTemplateMiddleOrTemplateTail)); + + // Binding patterns + case SyntaxKind.ObjectBindingPattern: + Debug.type(node); + return factory.updateObjectBindingPattern(node, + visitList(node.elements, isBindingElement)); + + case SyntaxKind.ArrayBindingPattern: + Debug.type(node); + return factory.updateArrayBindingPattern(node, + visitList(node.elements, isArrayBindingElement)); + + case SyntaxKind.BindingElement: + Debug.type(node); + return factory.updateBindingElement(node, + visit(node.dotDotDotToken, isDotDotDotToken), + visitPropertyName(node.propertyName), + visitBindingName(node.name), + visitExpression(node.initializer)); + + // Misc + case SyntaxKind.TemplateSpan: + Debug.type(node); + return factory.updateTemplateSpan(node, + visitExpression(node.expression), + visit(node.literal, isTemplateMiddleOrTemplateTail)); + + // Element + case SyntaxKind.Block: + Debug.type(node); + return factory.updateBlock(node, + visitList(node.statements, isStatement)); + + case SyntaxKind.VariableStatement: + Debug.type(node); + return factory.updateVariableStatement(node, + visitList(node.modifiers, isModifier), + visit(node.declarationList, isVariableDeclarationList)); + + case SyntaxKind.ExpressionStatement: + Debug.type(node); + return factory.updateExpressionStatement(node, + visitExpression(node.expression)); + + case SyntaxKind.IfStatement: + Debug.type(node); + return factory.updateIfStatement(node, + visitExpression(node.expression), + visitEmbeddedStatement(node.thenStatement), + visitEmbeddedStatement(node.elseStatement)); + + case SyntaxKind.DoStatement: + Debug.type(node); + return factory.updateDoStatement(node, + visitEmbeddedStatement(node.statement), + visitExpression(node.expression)); + + case SyntaxKind.WhileStatement: + Debug.type(node); + return factory.updateWhileStatement(node, + visitExpression(node.expression), + visitEmbeddedStatement(node.statement)); + + case SyntaxKind.ForStatement: + Debug.type(node); + return factory.updateForStatement(node, + visitForInitializer(node.initializer), + visitExpression(node.condition), + visitExpression(node.incrementor), + visitEmbeddedStatement(node.statement)); + + case SyntaxKind.ForInStatement: + Debug.type(node); + return factory.updateForInStatement(node, + visitForInitializer(node.initializer), + visitExpression(node.expression), + visitEmbeddedStatement(node.statement)); + + case SyntaxKind.ForOfStatement: + Debug.type(node); + return factory.updateForOfStatement(node, + visit(node.awaitModifier, isAwaitKeyword), + visitForInitializer(node.initializer), + visitExpression(node.expression), + visitEmbeddedStatement(node.statement)); + + case SyntaxKind.ContinueStatement: + Debug.type(node); + return factory.updateContinueStatement(node, + visitIdentifierName(node.label)); + + case SyntaxKind.BreakStatement: + Debug.type(node); + return factory.updateBreakStatement(node, + visitIdentifierName(node.label)); + + case SyntaxKind.ReturnStatement: + Debug.type(node); + return factory.updateReturnStatement(node, + visitExpression(node.expression)); + + case SyntaxKind.WithStatement: + Debug.type(node); + return factory.updateWithStatement(node, + visitExpression(node.expression), + visitEmbeddedStatement(node.statement)); + + case SyntaxKind.SwitchStatement: + Debug.type(node); + return factory.updateSwitchStatement(node, + visitExpression(node.expression), + visit(node.caseBlock, isCaseBlock)); + + case SyntaxKind.LabeledStatement: + Debug.type(node); + return factory.updateLabeledStatement(node, + visitIdentifierName(node.label), + visitEmbeddedStatement(node.statement)); + + case SyntaxKind.ThrowStatement: + Debug.type(node); + return factory.updateThrowStatement(node, + visitExpression(node.expression)); + + case SyntaxKind.TryStatement: + Debug.type(node); + return factory.updateTryStatement(node, + visit(node.tryBlock, isBlock), + visit(node.catchClause, isCatchClause), + visit(node.finallyBlock, isBlock)); + + // Declarations + case SyntaxKind.VariableDeclaration: + Debug.type(node); + return factory.updateVariableDeclaration(node, + visitBindingName(node.name), + visit(node.exclamationToken, isExclamationToken), + visitTypeNode(node.type), + visitExpression(node.initializer)); + + case SyntaxKind.VariableDeclarationList: + Debug.type(node); + return factory.updateVariableDeclarationList(node, + visitList(node.declarations, isVariableDeclaration)); + + case SyntaxKind.FunctionDeclaration: + Debug.type(node); + return factory.updateFunctionDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visit(node.asteriskToken, isAsteriskToken), + visitIdentifierName(node.name), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type), + visitFunctionBody(node.body)); + + case SyntaxKind.ClassDeclaration: + Debug.type(node); + return factory.updateClassDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitIdentifierName(node.name), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitList(node.heritageClauses, isHeritageClause), + visitList(node.members, isClassElement)); + + case SyntaxKind.InterfaceDeclaration: + Debug.type(node); + return factory.updateInterfaceDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitIdentifierName(node.name), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitList(node.heritageClauses, isHeritageClause), + visitList(node.members, isTypeElement)); + + case SyntaxKind.TypeAliasDeclaration: + Debug.type(node); + return factory.updateTypeAliasDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitIdentifierName(node.name), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitTypeNode(node.type)); + + case SyntaxKind.EnumDeclaration: + Debug.type(node); + return factory.updateEnumDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitIdentifierName(node.name), + visitList(node.members, isEnumMember)); + + case SyntaxKind.ModuleDeclaration: + Debug.type(node); + return factory.updateModuleDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitModuleName(node.name), + visit(node.body, isModuleBody)); + + case SyntaxKind.ModuleBlock: + Debug.type(node); + return factory.updateModuleBlock(node, + visitList(node.statements, isStatement)); + + case SyntaxKind.CaseBlock: + Debug.type(node); + return factory.updateCaseBlock(node, + visitList(node.clauses, isCaseOrDefaultClause)); + + case SyntaxKind.NamespaceExportDeclaration: + Debug.type(node); + return factory.updateNamespaceExportDeclaration(node, + visitIdentifierName(node.name)); + + case SyntaxKind.ImportEqualsDeclaration: + Debug.type(node); + return factory.updateImportEqualsDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + node.isTypeOnly, + visitIdentifierName(node.name), + visit(node.moduleReference, isModuleReference)); + + case SyntaxKind.ImportDeclaration: + Debug.type(node); + return factory.updateImportDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visit(node.importClause, isImportClause), + visitExpression(node.moduleSpecifier)); + + case SyntaxKind.ImportClause: + Debug.type(node); + return factory.updateImportClause(node, + node.isTypeOnly, + visitIdentifierName(node.name), + visit(node.namedBindings, isNamedImportBindings)); + + case SyntaxKind.NamespaceImport: + Debug.type(node); + return factory.updateNamespaceImport(node, + visitIdentifierName(node.name)); + + case SyntaxKind.NamespaceExport: + Debug.type(node); + return factory.updateNamespaceExport(node, + visitIdentifierName(node.name)); + + case SyntaxKind.NamedImports: + Debug.type(node); + return factory.updateNamedImports(node, + visitList(node.elements, isImportSpecifier)); + + case SyntaxKind.ImportSpecifier: + Debug.type(node); + return factory.updateImportSpecifier(node, + visitIdentifierName(node.propertyName), + visitIdentifierName(node.name)); + + case SyntaxKind.ExportAssignment: + Debug.type(node); + return factory.updateExportAssignment(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitExpression(node.expression)); + + case SyntaxKind.ExportDeclaration: + Debug.type(node); + return factory.updateExportDeclaration(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + node.isTypeOnly, + visit(node.exportClause, isNamedExportBindings), + visitExpression(node.moduleSpecifier)); + + case SyntaxKind.NamedExports: + Debug.type(node); + return factory.updateNamedExports(node, + visitList(node.elements, isExportSpecifier)); + + case SyntaxKind.ExportSpecifier: + Debug.type(node); + return factory.updateExportSpecifier(node, + visitIdentifierName(node.propertyName), + visitIdentifierName(node.name)); + + case SyntaxKind.MissingDeclaration: + return node; + + // Module references + case SyntaxKind.ExternalModuleReference: + Debug.type(node); + return factory.updateExternalModuleReference(node, + visitExpression(node.expression)); + + // JSX (non-expression) + case SyntaxKind.JsxOpeningElement: + Debug.type(node); + return factory.updateJsxOpeningElement(node, + visitExpression(node.tagName, isJsxTagNameExpression), + visitList(node.typeArguments, isTypeNode), + visit(node.attributes, isJsxAttributes)); + + case SyntaxKind.JsxClosingElement: + Debug.type(node); + return factory.updateJsxClosingElement(node, + visitExpression(node.tagName, isJsxTagNameExpression)); + + case SyntaxKind.JsxAttribute: + Debug.type(node); + return factory.updateJsxAttribute(node, + visitIdentifierName(node.name), + visitJsxAttributeValue(node.initializer)); + + case SyntaxKind.JsxAttributes: + Debug.type(node); + return factory.updateJsxAttributes(node, + visitList(node.properties, isJsxAttributeLike)); + + case SyntaxKind.JsxSpreadAttribute: + Debug.type(node); + return factory.updateJsxSpreadAttribute(node, + visitExpression(node.expression)); + + case SyntaxKind.JsxExpression: + Debug.type(node); + return factory.updateJsxExpression(node, + visitExpression(node.expression)); + + // Clauses + case SyntaxKind.CaseClause: + Debug.type(node); + return factory.updateCaseClause(node, + visitExpression(node.expression), + visitList(node.statements, isStatement)); + + case SyntaxKind.DefaultClause: + Debug.type(node); + return factory.updateDefaultClause(node, + visitList(node.statements, isStatement)); + + case SyntaxKind.HeritageClause: + Debug.type(node); + return factory.updateHeritageClause(node, + visitList(node.types, isExpressionWithTypeArguments)); + + case SyntaxKind.CatchClause: + Debug.type(node); + return factory.updateCatchClause(node, + visit(node.variableDeclaration, isVariableDeclaration), + visit(node.block, isBlock)); + + // Property assignments + case SyntaxKind.PropertyAssignment: + Debug.type(node); + return factory.updatePropertyAssignment(node, + visitPropertyName(node.name), + visitExpression(node.initializer)); + + case SyntaxKind.ShorthandPropertyAssignment: + Debug.type(node); + return factory.updateShorthandPropertyAssignment(node, + visitIdentifierName(node.name, isIdentifier), + visitExpression(node.objectAssignmentInitializer)); + + case SyntaxKind.SpreadAssignment: + Debug.type(node); + return factory.updateSpreadAssignment(node, + visitExpression(node.expression)); + + // Enum + case SyntaxKind.EnumMember: + Debug.type(node); + return factory.updateEnumMember(node, + visitPropertyName(node.name), + visitExpression(node.initializer)); + + // JSDoc nodes (only used in codefixes currently) + case SyntaxKind.JSDocTypeExpression: + case SyntaxKind.JSDocNameReference: + case SyntaxKind.JSDocAllType: + case SyntaxKind.JSDocUnknownType: + case SyntaxKind.JSDocNullableType: + case SyntaxKind.JSDocNonNullableType: + case SyntaxKind.JSDocOptionalType: + case SyntaxKind.JSDocFunctionType: + case SyntaxKind.JSDocVariadicType: + case SyntaxKind.JSDocNamepathType: + case SyntaxKind.JSDocComment: + case SyntaxKind.JSDocTypeLiteral: + case SyntaxKind.JSDocSignature: + case SyntaxKind.JSDocTag: + case SyntaxKind.JSDocAugmentsTag: + case SyntaxKind.JSDocImplementsTag: + case SyntaxKind.JSDocAuthorTag: + case SyntaxKind.JSDocDeprecatedTag: + case SyntaxKind.JSDocClassTag: + case SyntaxKind.JSDocPublicTag: + case SyntaxKind.JSDocPrivateTag: + case SyntaxKind.JSDocProtectedTag: + case SyntaxKind.JSDocReadonlyTag: + case SyntaxKind.JSDocCallbackTag: + case SyntaxKind.JSDocEnumTag: + case SyntaxKind.JSDocParameterTag: + case SyntaxKind.JSDocPropertyTag: + case SyntaxKind.JSDocReturnTag: + case SyntaxKind.JSDocThisTag: + case SyntaxKind.JSDocTypeTag: + case SyntaxKind.JSDocTemplateTag: + case SyntaxKind.JSDocTypedefTag: + case SyntaxKind.JSDocSeeTag: + return node; + + // Transformation nodes (ignored) + } + + if (isExpression(node)) { + // If this was an expression that was originally in an `Unspecified` hint, + // re-trigger substitution using the correct hint. + hint = EmitHint.Expression; + if (substituteNode !== noEmitSubstitution) { + node = substituteNode(hint, node); + } + } + else if (isSourceFile(node)) { + return preprintSourceFile(node); + } + } + + if (hint === EmitHint.Expression) { + switch (node.kind) { + // Identifiers + case SyntaxKind.Identifier: + return preprintIdentifier(node as Identifier); + + // Expression + case SyntaxKind.ArrayLiteralExpression: + Debug.type(node); + return factory.updateArrayLiteralExpression(node, + visitExpressionList(node.elements)); + + case SyntaxKind.ObjectLiteralExpression: + Debug.type(node); + return factory.updateObjectLiteralExpression(node, + visitList(node.properties, isObjectLiteralElementLike)); + + case SyntaxKind.PropertyAccessExpression: + if (node.flags & NodeFlags.OptionalChain) { + Debug.type(node); + return factory.updatePropertyAccessChain(node, + visitExpression(node.expression), + visit(node.questionDotToken, isQuestionDotToken), + visitMemberName(node.name)); + } + Debug.type(node); + return factory.updatePropertyAccessExpression(node, + visitExpression(node.expression), + visitMemberName(node.name)); + + case SyntaxKind.ElementAccessExpression: + if (node.flags & NodeFlags.OptionalChain) { + Debug.type(node); + return factory.updateElementAccessChain(node, + visitExpression(node.expression), + visit(node.questionDotToken, isQuestionDotToken), + visitExpression(node.argumentExpression)); + } + Debug.type(node); + return factory.updateElementAccessExpression(node, + visitExpression(node.expression), + visitExpression(node.argumentExpression)); + + case SyntaxKind.CallExpression: + if (node.flags & NodeFlags.OptionalChain) { + Debug.type(node); + return factory.updateCallChain(node, + visitExpression(node.expression), + visit(node.questionDotToken, isQuestionDotToken), + visitTypeNodeList(node.typeArguments), + visitExpressionList(node.arguments)); + } + Debug.type(node); + return factory.updateCallExpression(node, + visitExpression(node.expression), + visitTypeNodeList(node.typeArguments), + visitExpressionList(node.arguments)); + + case SyntaxKind.NewExpression: + Debug.type(node); + return factory.updateNewExpression(node, + visitExpression(node.expression), + visitTypeNodeList(node.typeArguments), + visitExpressionList(node.arguments)); + + case SyntaxKind.TaggedTemplateExpression: + Debug.type(node); + return factory.updateTaggedTemplateExpression(node, + visitExpression(node.tag), + visitTypeNodeList(node.typeArguments), + visitExpression(node.template, isTemplateLiteral)); + + case SyntaxKind.TypeAssertionExpression: + Debug.type(node); + return factory.updateTypeAssertion(node, + visitTypeNode(node.type), + visitExpression(node.expression)); + + case SyntaxKind.ParenthesizedExpression: + Debug.type(node); + return factory.updateParenthesizedExpression(node, + visitExpression(node.expression)); + + case SyntaxKind.FunctionExpression: + Debug.type(node); + return factory.updateFunctionExpression(node, + visitList(node.modifiers, isModifier), + visit(node.asteriskToken, isAsteriskToken), + visitIdentifierName(node.name), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type), + visitFunctionBody(node.body)); + + case SyntaxKind.ArrowFunction: + Debug.type(node); + return factory.updateArrowFunction(node, + visitList(node.modifiers, isModifier), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitParameterList(node.parameters), + visitTypeNode(node.type), + visit(node.equalsGreaterThanToken, isEqualsGreaterThanToken), + visitConciseBody(node.body)); + + case SyntaxKind.DeleteExpression: + Debug.type(node); + return factory.updateDeleteExpression(node, + visitExpression(node.expression)); + + case SyntaxKind.TypeOfExpression: + Debug.type(node); + return factory.updateTypeOfExpression(node, + visitExpression(node.expression)); + + case SyntaxKind.VoidExpression: + Debug.type(node); + return factory.updateVoidExpression(node, + visitExpression(node.expression)); + + case SyntaxKind.AwaitExpression: + Debug.type(node); + return factory.updateAwaitExpression(node, + visitExpression(node.expression)); + + case SyntaxKind.PrefixUnaryExpression: + Debug.type(node); + return factory.updatePrefixUnaryExpression(node, + visitExpression(node.operand)); + + case SyntaxKind.PostfixUnaryExpression: + Debug.type(node); + return factory.updatePostfixUnaryExpression(node, + visitExpression(node.operand)); + + case SyntaxKind.BinaryExpression: + return preprintBinaryExpression(node as BinaryExpression); + + case SyntaxKind.ConditionalExpression: + Debug.type(node); + return factory.updateConditionalExpression(node, + visitExpression(node.condition), + visit(node.questionToken, isQuestionToken), + visitExpression(node.whenTrue), + visit(node.colonToken, isColonToken), + visitExpression(node.whenFalse)); + + case SyntaxKind.TemplateExpression: + Debug.type(node); + return factory.updateTemplateExpression(node, + visit(node.head, isTemplateHead), + visitList(node.templateSpans, isTemplateSpan)); + + case SyntaxKind.YieldExpression: + Debug.type(node); + return factory.updateYieldExpression(node, + visit(node.asteriskToken, isAsteriskToken), + visitExpression(node.expression)); + + case SyntaxKind.SpreadElement: + Debug.type(node); + return factory.updateSpreadElement(node, + visitExpression(node.expression)); + + case SyntaxKind.ClassExpression: + Debug.type(node); + return factory.updateClassExpression(node, + visitList(node.decorators, isDecorator), + visitList(node.modifiers, isModifier), + visitIdentifierName(node.name), + visitList(node.typeParameters, isTypeParameterDeclaration), + visitList(node.heritageClauses, isHeritageClause), + visitList(node.members, isClassElement)); + + case SyntaxKind.AsExpression: + Debug.type(node); + return factory.updateAsExpression(node, + visitExpression(node.expression), + visitTypeNode(node.type)); + + case SyntaxKind.NonNullExpression: + if (node.flags & NodeFlags.OptionalChain) { + Debug.type(node); + return factory.updateNonNullChain(node, + visitExpression(node.expression)); + } + Debug.type(node); + return factory.updateNonNullExpression(node, + visitExpression(node.expression)); + + case SyntaxKind.MetaProperty: + Debug.type(node); + return factory.updateMetaProperty(node, + visitIdentifierName(node.name)); + + + // JSX (expression only) + case SyntaxKind.JsxElement: + Debug.type(node); + return factory.updateJsxElement(node, + visit(node.openingElement, isJsxOpeningElement), + visitList(node.children, isJsxChild), + visit(node.closingElement, isJsxClosingElement)); + + case SyntaxKind.JsxSelfClosingElement: + Debug.type(node); + return factory.updateJsxSelfClosingElement(node, + visitExpression(node.tagName, isJsxTagNameExpression), + visitList(node.typeArguments, isTypeNode), + visit(node.attributes, isJsxAttributes)); + + case SyntaxKind.JsxFragment: + Debug.type(node); + return factory.updateJsxFragment(node, + visit(node.openingFragment, isJsxOpeningFragment), + visitList(node.children, isJsxChild), + visit(node.closingFragment, isJsxClosingFragment)); + + // Transformation nodes + case SyntaxKind.PartiallyEmittedExpression: + Debug.type(node); + return factory.updatePartiallyEmittedExpression(node, + visitExpression(node.expression)); + + case SyntaxKind.CommaListExpression: + Debug.type(node); + return factory.updateCommaListExpression(node, + visitExpressionList(node.elements, isExpression)); + } + } + + if (Debug.shouldAssert(AssertionLevel.Normal)) { + // Any other node should not have children or this list isn't up to date. + Debug.assertMissingNode(forEachChild(node, identity), `Expected ${Debug.formatSyntaxKind(node.kind)} to contain no children.`); + } + + // No need to visit nodes with no children. + return node; + } + + function preprintSourceFile(node: SourceFile) { + return factory.updateSourceFile(node, + visitList(node.statements, isStatement)); + } + + function preprintIdentifier(node: Identifier) { + return factory.updateIdentifier(node, + visitList(node.typeArguments, isTypeNodeOrTypeParameterDeclaration)); + } + + function preprintTypeParameterDeclaration(node: TypeParameterDeclaration) { + return factory.updateTypeParameterDeclaration(node, + visitIdentifierName(node.name), + visitTypeNode(node.constraint), + visitTypeNode(node.default)); + } + + function createPreprintBinaryExpression() { + interface WorkArea { + stackIndex: number; + leftStack: Expression[]; + operatorStack: BinaryOperatorToken[]; + rightStack: Expression[]; + } + + return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, foldState); + + function onEnter(node: BinaryExpression, state: WorkArea | undefined) { + if (state) { + state.stackIndex++; + state.leftStack[state.stackIndex] = node.left; + state.operatorStack[state.stackIndex] = node.operatorToken; + state.rightStack[state.stackIndex] = node.right; + } + else { + state = { + stackIndex: 0, + leftStack: [node.left], + operatorStack: [node.operatorToken], + rightStack: [node.right], + }; + } + return state; + } + + function onLeft(left: Expression, state: WorkArea, _node: BinaryExpression) { + return maybeVisitExpression(left, state, "left"); + } + + function onOperator(operator: BinaryOperatorToken, state: WorkArea, _node: BinaryExpression) { + state.operatorStack[state.stackIndex] = visit(operator, isBinaryOperatorToken); + } + + function onRight(right: Expression, state: WorkArea, _node: BinaryExpression) { + return maybeVisitExpression(right, state, "right"); + } + + function onExit(node: BinaryExpression, state: WorkArea) { + const left = state.leftStack[state.stackIndex]; + const operator = state.operatorStack[state.stackIndex]; + const right = state.rightStack[state.stackIndex]; + if (state.stackIndex > 0) { + state.stackIndex--; + } + return factory.updateBinaryExpression(node, left, operator, right); + } + + function foldState(state: WorkArea, result: BinaryExpression, side: "left" | "right") { + (side === "left" ? state.leftStack : state.rightStack)[state.stackIndex] = result; + return state; + } + + function maybeVisitExpression(node: Expression, state: WorkArea, side: "left" | "right") { + // Get the first supported pipeline phase for this node. We can skip several stack + // frames if we aren't doing emit notification, so we check for substitution and + // direct callbacks and execute those immediately. + let pipelinePhase = getPipelinePhase(PreprintPipelinePhase.Notification, node); + if (pipelinePhase === pipelineVisitWithSubstitution) { + // The next phase after substitution is always direct visitation, so we can reduce the call stack + // depth by proceding to the direct visitor. + node = cast(substituteNode(EmitHint.Expression, node), isExpression); + pipelinePhase = pipelineVisitDirect; + } + if (pipelinePhase === pipelineVisitDirect && isBinaryExpression(node)) { + // If we are visiting directly and the next node is a BinaryExpression, we can + // add it to the stack and continue the trampoline. + return node; + } + else { + // Visit the expression and store the result on whichever side we are currently visiting. + (side === "left" ? state.leftStack : state.rightStack)[state.stackIndex] = visitExpression(node, isExpression); + } + } + } + + const preprintBinaryExpression = createPreprintBinaryExpression(); + + function preprint(hint: EmitHint, node: Node) { + // If we're not performing substitution or notification, we have no work to do here. + if (substituteNode === noEmitSubstitution && + onEmitNode === noEmitNotification) { + return node; + } + switch (hint) { + case EmitHint.SourceFile: return visitSourceFile(cast(node, isSourceFile)); + case EmitHint.Expression: return visitExpression(cast(node, isExpression)); + case EmitHint.IdentifierName: return visitIdentifierName(cast(node, isIdentifier)); + case EmitHint.MappedTypeParameter: return visitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); + case EmitHint.EmbeddedStatement: return visitEmbeddedStatement(cast(node, isStatement)); + case EmitHint.JsxAttributeValue: return visitJsxAttributeValue(cast(node, isStringLiteralOrJsxExpression)); + default: return visit(node); + } + } + + return preprint; + } + function createBracketsMap() { const brackets: string[][] = []; brackets[ListFormat.Braces] = ["{", "}"]; diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index 71b329e46d6..0fbb50d9d11 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -39,12 +39,106 @@ namespace ts { return node.kind === SyntaxKind.TemplateTail; } + // Punctuation + + export function isDotDotDotToken(node: Node): node is DotDotDotToken { + return node.kind === SyntaxKind.DotDotDotToken; + } + + /*@internal*/ + export function isCommaToken(node: Node): node is Token { + return node.kind === SyntaxKind.CommaToken; + } + + export function isPlusToken(node: Node): node is PlusToken { + return node.kind === SyntaxKind.PlusToken; + } + + export function isMinusToken(node: Node): node is MinusToken { + return node.kind === SyntaxKind.MinusToken; + } + + export function isAsteriskToken(node: Node): node is AsteriskToken { + return node.kind === SyntaxKind.AsteriskToken; + } + + /*@internal*/ + export function isExclamationToken(node: Node): node is ExclamationToken { + return node.kind === SyntaxKind.ExclamationToken; + } + + /*@internal*/ + export function isQuestionToken(node: Node): node is QuestionToken { + return node.kind === SyntaxKind.QuestionToken; + } + + /*@internal*/ + export function isColonToken(node: Node): node is ColonToken { + return node.kind === SyntaxKind.ColonToken; + } + + /*@internal*/ + export function isQuestionDotToken(node: Node): node is QuestionDotToken { + return node.kind === SyntaxKind.QuestionDotToken; + } + + /*@internal*/ + export function isEqualsGreaterThanToken(node: Node): node is EqualsGreaterThanToken { + return node.kind === SyntaxKind.EqualsGreaterThanToken; + } + // Identifiers export function isIdentifier(node: Node): node is Identifier { return node.kind === SyntaxKind.Identifier; } + export function isPrivateIdentifier(node: Node): node is PrivateIdentifier { + return node.kind === SyntaxKind.PrivateIdentifier; + } + + // Reserved Words + + /* @internal */ + export function isExportModifier(node: Node): node is ExportKeyword { + return node.kind === SyntaxKind.ExportKeyword; + } + + /* @internal */ + export function isAsyncModifier(node: Node): node is AsyncKeyword { + return node.kind === SyntaxKind.AsyncKeyword; + } + + /* @internal */ + export function isAssertsKeyword(node: Node): node is AssertsKeyword { + return node.kind === SyntaxKind.AssertsKeyword; + } + + /* @internal */ + export function isAwaitKeyword(node: Node): node is AwaitKeyword { + return node.kind === SyntaxKind.AwaitKeyword; + } + + /* @internal */ + export function isReadonlyKeyword(node: Node): node is ReadonlyKeyword { + return node.kind === SyntaxKind.ReadonlyKeyword; + } + + /* @internal */ + export function isStaticModifier(node: Node): node is StaticKeyword { + return node.kind === SyntaxKind.StaticKeyword; + } + + /*@internal*/ + export function isSuperKeyword(node: Node): node is SuperExpression { + return node.kind === SyntaxKind.SuperKeyword; + } + + /*@internal*/ + export function isImportKeyword(node: Node): node is ImportExpression { + return node.kind === SyntaxKind.ImportKeyword; + } + // Names export function isQualifiedName(node: Node): node is QualifiedName { @@ -55,37 +149,6 @@ namespace ts { return node.kind === SyntaxKind.ComputedPropertyName; } - export function isPrivateIdentifier(node: Node): node is PrivateIdentifier { - return node.kind === SyntaxKind.PrivateIdentifier; - } - - // Tokens - - /*@internal*/ - export function isSuperKeyword(node: Node): node is Token { - return node.kind === SyntaxKind.SuperKeyword; - } - - /*@internal*/ - export function isImportKeyword(node: Node): node is Token { - return node.kind === SyntaxKind.ImportKeyword; - } - - /*@internal*/ - export function isCommaToken(node: Node): node is Token { - return node.kind === SyntaxKind.CommaToken; - } - - /*@internal*/ - export function isQuestionToken(node: Node): node is Token { - return node.kind === SyntaxKind.QuestionToken; - } - - /*@internal*/ - export function isExclamationToken(node: Node): node is Token { - return node.kind === SyntaxKind.ExclamationToken; - } - // Signature elements export function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration { diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 8b18c3152e3..357e50d7fa5 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -13,7 +13,7 @@ namespace ts { } else { const expression = setTextRange( - isIdentifierOrPrivateIdentifier(memberName) + isMemberName(memberName) ? factory.createPropertyAccessExpression(target, memberName) : factory.createElementAccessExpression(target, memberName), memberName @@ -412,7 +412,7 @@ namespace ts { const helperNames: string[] = []; for (const helper of helpers) { if (!helper.scoped) { - const importName = (helper as UnscopedEmitHelper).importName; + const importName = helper.importName; if (importName) { pushIfUnique(helperNames, importName); } @@ -815,18 +815,300 @@ namespace ts { || kind === SyntaxKind.ExportDeclaration; } - /* @internal */ - export function isExportModifier(node: Modifier): node is ExportKeyword { - return node.kind === SyntaxKind.ExportKeyword; + export const isTypeNodeOrTypeParameterDeclaration = or(isTypeNode, isTypeParameterDeclaration) as (node: Node) => node is TypeNode | TypeParameterDeclaration; + export const isQuestionOrExclamationToken = or(isQuestionToken, isExclamationToken) as (node: Node) => node is QuestionToken | ExclamationToken; + export const isIdentifierOrThisTypeNode = or(isIdentifier, isThisTypeNode) as (node: Node) => node is Identifier | ThisTypeNode; + export const isReadonlyKeywordOrPlusOrMinusToken = or(isReadonlyKeyword, isPlusToken, isMinusToken) as (node: Node) => node is ReadonlyKeyword | PlusToken | MinusToken; + export const isQuestionOrPlusOrMinusToken = or(isQuestionToken, isPlusToken, isMinusToken) as (node: Node) => node is QuestionToken | PlusToken | MinusToken; + export const isModuleName = or(isIdentifier, isStringLiteral) as (node: Node) => node is ModuleName; + + export function isLiteralTypeLikeExpression(node: Node): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { + const kind = node.kind; + return kind === SyntaxKind.NullKeyword + || kind === SyntaxKind.TrueKeyword + || kind === SyntaxKind.FalseKeyword + || isLiteralExpression(node) + || isPrefixUnaryExpression(node); } - /* @internal */ - export function isAsyncModifier(node: Modifier): node is AsyncKeyword { - return node.kind === SyntaxKind.AsyncKeyword; + function isExponentiationOperator(kind: SyntaxKind): kind is ExponentiationOperator { + return kind === SyntaxKind.AsteriskAsteriskToken; } - /* @internal */ - export function isStaticModifier(node: Modifier): node is StaticKeyword { - return node.kind === SyntaxKind.StaticKeyword; + function isMultiplicativeOperator(kind: SyntaxKind): kind is MultiplicativeOperator { + return kind === SyntaxKind.AsteriskToken + || kind === SyntaxKind.SlashToken + || kind === SyntaxKind.PercentToken; + } + + function isMultiplicativeOperatorOrHigher(kind: SyntaxKind): kind is MultiplicativeOperatorOrHigher { + return isExponentiationOperator(kind) + || isMultiplicativeOperator(kind); + } + + function isAdditiveOperator(kind: SyntaxKind): kind is AdditiveOperator { + return kind === SyntaxKind.PlusToken + || kind === SyntaxKind.MinusToken; + } + + function isAdditiveOperatorOrHigher(kind: SyntaxKind): kind is AdditiveOperatorOrHigher { + return isAdditiveOperator(kind) + || isMultiplicativeOperatorOrHigher(kind); + } + + function isShiftOperator(kind: SyntaxKind): kind is ShiftOperator { + return kind === SyntaxKind.LessThanLessThanToken + || kind === SyntaxKind.GreaterThanGreaterThanToken + || kind === SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + } + + function isShiftOperatorOrHigher(kind: SyntaxKind): kind is ShiftOperatorOrHigher { + return isShiftOperator(kind) + || isAdditiveOperatorOrHigher(kind); + } + + function isRelationalOperator(kind: SyntaxKind): kind is RelationalOperator { + return kind === SyntaxKind.LessThanToken + || kind === SyntaxKind.LessThanEqualsToken + || kind === SyntaxKind.GreaterThanToken + || kind === SyntaxKind.GreaterThanEqualsToken + || kind === SyntaxKind.InstanceOfKeyword + || kind === SyntaxKind.InKeyword; + } + + function isRelationalOperatorOrHigher(kind: SyntaxKind): kind is RelationalOperatorOrHigher { + return isRelationalOperator(kind) + || isShiftOperatorOrHigher(kind); + } + + function isEqualityOperator(kind: SyntaxKind): kind is EqualityOperator { + return kind === SyntaxKind.EqualsEqualsToken + || kind === SyntaxKind.EqualsEqualsEqualsToken + || kind === SyntaxKind.ExclamationEqualsToken + || kind === SyntaxKind.ExclamationEqualsEqualsToken; + } + + function isEqualityOperatorOrHigher(kind: SyntaxKind): kind is EqualityOperatorOrHigher { + return isEqualityOperator(kind) + || isRelationalOperatorOrHigher(kind); + } + + function isBitwiseOperator(kind: SyntaxKind): kind is BitwiseOperator { + return kind === SyntaxKind.AmpersandToken + || kind === SyntaxKind.BarToken + || kind === SyntaxKind.CaretToken; + } + + function isBitwiseOperatorOrHigher(kind: SyntaxKind): kind is BitwiseOperatorOrHigher { + return isBitwiseOperator(kind) + || isEqualityOperatorOrHigher(kind); + } + + // NOTE: The version in utilities includes ExclamationToken, which is not a binary operator. + function isLogicalOperator(kind: SyntaxKind): kind is LogicalOperator { + return kind === SyntaxKind.AmpersandAmpersandToken + || kind === SyntaxKind.BarBarToken; + } + + function isLogicalOperatorOrHigher(kind: SyntaxKind): kind is LogicalOperatorOrHigher { + return isLogicalOperator(kind) + || isBitwiseOperatorOrHigher(kind); + } + + function isAssignmentOperatorOrHigher(kind: SyntaxKind): kind is AssignmentOperatorOrHigher { + return kind === SyntaxKind.QuestionQuestionToken + || isLogicalOperatorOrHigher(kind) + || isAssignmentOperator(kind); + } + + function isBinaryOperator(kind: SyntaxKind): kind is BinaryOperator { + return isAssignmentOperatorOrHigher(kind) + || kind === SyntaxKind.CommaToken; + } + + export function isBinaryOperatorToken(node: Node): node is BinaryOperatorToken { + return isBinaryOperator(node.kind); + } + + type BinaryExpressionState = (machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult }) => number; + + namespace BinaryExpressionState { + /** + * Handles walking into a `BinaryExpression`. + * @param machine State machine handler functions + * @param frame The current frame + * @returns The new frame + */ + export function enter(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number { + const prevUserState = stackIndex > 0 ? userStateStack[stackIndex - 1] : undefined; + Debug.assertEqual(stateStack[stackIndex], enter); + userStateStack[stackIndex] = machine.onEnter(nodeStack[stackIndex], prevUserState); + stateStack[stackIndex] = nextState(machine, enter); + return stackIndex; + } + + /** + * Handles walking the `left` side of a `BinaryExpression`. + * @param machine State machine handler functions + * @param frame The current frame + * @returns The new frame + */ + export function left(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number { + Debug.assertEqual(stateStack[stackIndex], left); + Debug.assertIsDefined(machine.onLeft); + stateStack[stackIndex] = nextState(machine, left); + const nextNode = machine.onLeft(nodeStack[stackIndex].left, userStateStack[stackIndex], nodeStack[stackIndex]); + if (nextNode) { + checkCircularity(stackIndex, nodeStack, nextNode); + return pushStack(stackIndex, stateStack, nodeStack, userStateStack, nextNode); + } + return stackIndex; + } + + /** + * Handles walking the `operatorToken` of a `BinaryExpression`. + * @param machine State machine handler functions + * @param frame The current frame + * @returns The new frame + */ + export function operator(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number { + Debug.assertEqual(stateStack[stackIndex], operator); + Debug.assertIsDefined(machine.onOperator); + stateStack[stackIndex] = nextState(machine, operator); + machine.onOperator(nodeStack[stackIndex].operatorToken, userStateStack[stackIndex], nodeStack[stackIndex]); + return stackIndex; + } + + /** + * Handles walking the `right` side of a `BinaryExpression`. + * @param machine State machine handler functions + * @param frame The current frame + * @returns The new frame + */ + export function right(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number { + Debug.assertEqual(stateStack[stackIndex], right); + Debug.assertIsDefined(machine.onRight); + stateStack[stackIndex] = nextState(machine, right); + const nextNode = machine.onRight(nodeStack[stackIndex].right, userStateStack[stackIndex], nodeStack[stackIndex]); + if (nextNode) { + checkCircularity(stackIndex, nodeStack, nextNode); + return pushStack(stackIndex, stateStack, nodeStack, userStateStack, nextNode); + } + return stackIndex; + } + + /** + * Handles walking out of a `BinaryExpression`. + * @param machine State machine handler functions + * @param frame The current frame + * @returns The new frame + */ + export function exit(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult }): number { + Debug.assertEqual(stateStack[stackIndex], exit); + stateStack[stackIndex] = nextState(machine, exit); + const result = machine.onExit(nodeStack[stackIndex], userStateStack[stackIndex]); + if (stackIndex > 0) { + stackIndex--; + if (machine.foldState) { + const side = stateStack[stackIndex] === exit ? "right" : "left"; + userStateStack[stackIndex] = machine.foldState(userStateStack[stackIndex], result, side); + } + } + else { + resultHolder.value = result; + } + return stackIndex; + } + + /** + * Handles a frame that is already done. + * @returns The `done` state. + */ + export function done(_machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], _nodeStack: BinaryExpression[], _userStateStack: TState[], _resultHolder: { value: TResult }): number { + Debug.assertEqual(stateStack[stackIndex], done); + return stackIndex; + } + + export function nextState(machine: BinaryExpressionStateMachine, currentState: BinaryExpressionState) { + switch (currentState) { + case enter: + if (machine.onLeft) return left; + // falls through + case left: + if (machine.onOperator) return operator; + // falls through + case operator: + if (machine.onRight) return right; + // falls through + case right: return exit; + case exit: return done; + case done: return done; + default: Debug.fail("Invalid state"); + } + } + + function pushStack(stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], node: BinaryExpression) { + stackIndex++; + stateStack[stackIndex] = enter; + nodeStack[stackIndex] = node; + userStateStack[stackIndex] = undefined!; + return stackIndex; + } + + function checkCircularity(stackIndex: number, nodeStack: BinaryExpression[], node: BinaryExpression) { + if (Debug.shouldAssert(AssertionLevel.Aggressive)) { + while (stackIndex >= 0) { + Debug.assert(nodeStack[stackIndex] !== node, "Circular traversal detected."); + stackIndex--; + } + } + } + } + + /** + * Holds state machine handler functions + */ + class BinaryExpressionStateMachine { + constructor( + readonly onEnter: (node: BinaryExpression, prev: TState | undefined) => TState, + readonly onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + readonly onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, + readonly onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + readonly onExit: (node: BinaryExpression, userState: TState) => TResult, + readonly foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined, + ) { + } + } + + /** + * Creates a state machine that walks a `BinaryExpression` using the heap to reduce call-stack depth on a large tree. + * @param onEnter Callback evaluated when entering a `BinaryExpression`. Returns new user-defined state to associate with the node while walking. + * @param onLeft Callback evaluated when walking the left side of a `BinaryExpression`. Return a `BinaryExpression` to continue walking, or `void` to advance to the right side. + * @param onRight Callback evaluated when walking the right side of a `BinaryExpression`. Return a `BinaryExpression` to continue walking, or `void` to advance to the end of the node. + * @param onExit Callback evaluated when exiting a `BinaryExpression`. The result returned will either be folded into the parent's state, or returned from the walker if at the top frame. + * @param foldState Callback evaluated when the result from a nested `onExit` should be folded into the state of that node's parent. + * @returns A function that walks a `BinaryExpression` node using the above callbacks, returning the result of the call to `onExit` from the outermost `BinaryExpression` node. + */ + export function createBinaryExpressionTrampoline( + onEnter: (node: BinaryExpression, prev: TState | undefined) => TState, + onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, + onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + onExit: (node: BinaryExpression, userState: TState) => TResult, + foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined, + ) { + const machine = new BinaryExpressionStateMachine(onEnter, onLeft, onOperator, onRight, onExit, foldState); + return (node: BinaryExpression) => { + const resultHolder: { value: TResult } = { value: undefined! }; + const stateStack: BinaryExpressionState[] = [BinaryExpressionState.enter]; + const nodeStack: BinaryExpression[] = [node]; + const userStateStack: TState[] = [undefined!]; + let stackIndex = 0; + while (stateStack[stackIndex] !== BinaryExpressionState.done) { + stackIndex = stateStack[stackIndex](machine, stackIndex, stateStack, nodeStack, userStateStack, resultHolder); + } + Debug.assertEqual(stackIndex, 0); + return resultHolder.value; + }; } } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 24d962c6e2f..a2bee2104b9 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -1864,17 +1864,22 @@ namespace ts { if (exportedNames) { let expression: Expression = node.kind === SyntaxKind.PostfixUnaryExpression ? setTextRange( - factory.createBinaryExpression( - node.operand, - factory.createToken(node.operator === SyntaxKind.PlusPlusToken ? SyntaxKind.PlusEqualsToken : SyntaxKind.MinusEqualsToken), - factory.createNumericLiteral(1) + factory.createPrefixUnaryExpression( + node.operator, + node.operand ), /*location*/ node) : node; for (const exportName of exportedNames) { // Mark the node to prevent triggering this rule again. noSubstitution[getNodeId(expression)] = true; - expression = factory.createParenthesizedExpression(createExportExpression(exportName, expression)); + expression = createExportExpression(exportName, expression); + } + if (node.kind === SyntaxKind.PostfixUnaryExpression) { + noSubstitution[getNodeId(expression)] = true; + expression = node.operator === SyntaxKind.PlusPlusToken + ? factory.createSubtract(expression, factory.createNumericLiteral(1)) + : factory.createAdd(expression, factory.createNumericLiteral(1)); } return expression; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1e43dc112be..76eb00b741f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -361,17 +361,14 @@ namespace ts { // JSDoc nodes JSDocTypeExpression, JSDocNameReference, - // The * type - JSDocAllType, - // The ? type - JSDocUnknownType, + JSDocAllType, // The * type + JSDocUnknownType, // The ? type JSDocNullableType, JSDocNonNullableType, JSDocOptionalType, JSDocFunctionType, JSDocVariadicType, - // https://jsdoc.app/about-namepaths.html - JSDocNamepathType, + JSDocNamepathType, // https://jsdoc.app/about-namepaths.html JSDocComment, JSDocTypeLiteral, JSDocSignature, @@ -1118,6 +1115,8 @@ namespace ts { export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier; + export type MemberName = Identifier | PrivateIdentifier; + export type DeclarationName = | Identifier | PrivateIdentifier @@ -2224,7 +2223,7 @@ namespace ts { readonly kind: SyntaxKind.PropertyAccessExpression; readonly expression: LeftHandSideExpression; readonly questionDotToken?: QuestionDotToken; - readonly name: Identifier | PrivateIdentifier; + readonly name: MemberName; } /*@internal*/ @@ -2234,7 +2233,7 @@ namespace ts { export interface PropertyAccessChain extends PropertyAccessExpression { _optionalChainBrand: any; - readonly name: Identifier | PrivateIdentifier; + readonly name: MemberName; } /* @internal */ @@ -4124,9 +4123,9 @@ namespace ts { */ /* @internal */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined; getApparentType(type: Type): Type; - /* @internal */ getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined; + /* @internal */ getSuggestedSymbolForNonexistentProperty(name: MemberName | string, containingType: Type): Symbol | undefined; /* @internal */ getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | string, containingType: Type): Symbol | undefined; - /* @internal */ getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined; + /* @internal */ getSuggestionForNonexistentProperty(name: MemberName | string, containingType: Type): string | undefined; /* @internal */ getSuggestedSymbolForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined; /* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; /* @internal */ getSuggestedSymbolForNonexistentModule(node: Identifier, target: Symbol): Symbol | undefined; @@ -6570,7 +6569,7 @@ namespace ts { /*@internal*/ IgnoreSourceNewlines = 1 << 27, // Overrides `printerOptions.preserveSourceNewlines` to print this node (and all descendants) with default whitespace. } - export interface EmitHelper { + export interface EmitHelperBase { readonly name: string; // A unique name for this helper. readonly scoped: boolean; // Indicates whether the helper MUST be emitted in the current scope. readonly text: string | ((node: EmitHelperUniqueNameCallback) => string); // ES3-compatible raw script text, or a function yielding such a string @@ -6578,13 +6577,19 @@ namespace ts { readonly dependencies?: EmitHelper[] } - export interface UnscopedEmitHelper extends EmitHelper { + export interface ScopedEmitHelper extends EmitHelperBase { + readonly scoped: true; + } + + export interface UnscopedEmitHelper extends EmitHelperBase { readonly scoped: false; // Indicates whether the helper MUST be emitted in the current scope. /* @internal */ readonly importName?: string; // The name of the helper to use when importing via `--importHelpers`. readonly text: string; // ES3-compatible raw script text, or a function yielding such a string } + export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper; + /* @internal */ export type UniqueNameHandler = (baseName: string, checkFn?: (name: string) => boolean, optimistic?: boolean) => string; @@ -6943,10 +6948,10 @@ namespace ts { updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression; createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression; updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression; - createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier): PropertyAccessExpression; - updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier): PropertyAccessExpression; - createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier): PropertyAccessChain; - updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier): PropertyAccessChain; + createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression; + updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression; + createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain; + updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain; createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression; updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression; createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain; @@ -7782,13 +7787,13 @@ namespace ts { * }); * ``` */ - onEmitNode?(hint: EmitHint, node: Node | undefined, emitCallback: (hint: EmitHint, node: Node | undefined) => void): void; + onEmitNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void; /** * A hook used to check if an emit notification is required for a node. * @param node The node to emit. */ - isEmitNotificationEnabled?(node: Node | undefined): boolean; + isEmitNotificationEnabled?(node: Node): boolean; /** * A hook used by the Printer to perform just-in-time substitution of a node. This is * primarily used by node transformations that need to substitute one node for another, @@ -7810,6 +7815,8 @@ namespace ts { /*@internal*/ onEmitSourceMapOfToken?: (node: Node | undefined, token: SyntaxKind, writer: (s: string) => void, pos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, pos: number) => number) => number; /*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void; /*@internal*/ onSetSourceFile?: (node: SourceFile) => void; + /*@internal*/ onBeforeEmitNode?: (node: Node | undefined) => void; + /*@internal*/ onAfterEmitNode?: (node: Node | undefined) => void; /*@internal*/ onBeforeEmitNodeArray?: (nodes: NodeArray | undefined) => void; /*@internal*/ onAfterEmitNodeArray?: (nodes: NodeArray | undefined) => void; /*@internal*/ onBeforeEmitToken?: (node: Node) => void; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 3fb9d039bf0..6ed8c04803a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3186,11 +3186,11 @@ namespace ts { } } export function getTextOfIdentifierOrLiteral(node: PropertyNameLiteral): string { - return isIdentifierOrPrivateIdentifier(node) ? idText(node) : node.text; + return isMemberName(node) ? idText(node) : node.text; } export function getEscapedTextOfIdentifierOrLiteral(node: PropertyNameLiteral): __String { - return isIdentifierOrPrivateIdentifier(node) ? node.escapedText : escapeLeadingUnderscores(node.text); + return isMemberName(node) ? node.escapedText : escapeLeadingUnderscores(node.text); } export function getPropertyNameForUniqueESSymbol(symbol: Symbol): __String { @@ -3574,6 +3574,7 @@ namespace ts { case SyntaxKind.TaggedTemplateExpression: case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: + case SyntaxKind.MetaProperty: return OperatorPrecedence.Member; case SyntaxKind.AsExpression: diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index d45eb73478d..e6a27fb6492 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -930,7 +930,7 @@ namespace ts { // #region - export function isIdentifierOrPrivateIdentifier(node: Node): node is Identifier | PrivateIdentifier { + export function isMemberName(node: Node): node is MemberName { return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier; } @@ -1055,13 +1055,22 @@ namespace ts { return kind >= SyntaxKind.FirstNode; } + /** + * True if kind is of some token syntax kind. + * For example, this is true for an IfKeyword but not for an IfStatement. + * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail. + */ + export function isTokenKind(kind: SyntaxKind): boolean { + return kind >= SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken; + } + /** * True if node is of some token syntax kind. * For example, this is true for an IfKeyword but not for an IfStatement. * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail. */ export function isToken(n: Node): boolean { - return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken; + return isTokenKind(n.kind); } // Node Arrays diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 958b7b1bdd5..d673014b990 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -1,6 +1,4 @@ namespace ts { - const isTypeNodeOrTypeParameterDeclaration = or(isTypeNode, isTypeParameterDeclaration); - /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * @@ -350,755 +348,889 @@ namespace ts { // Names case SyntaxKind.Identifier: - return factory.updateIdentifier(node, - nodesVisitor((node).typeArguments, visitor, isTypeNodeOrTypeParameterDeclaration)); + Debug.type(node); + return factory.updateIdentifier(node, + nodesVisitor(node.typeArguments, visitor, isTypeNodeOrTypeParameterDeclaration)); case SyntaxKind.QualifiedName: - return factory.updateQualifiedName(node, - nodeVisitor((node).left, visitor, isEntityName), - nodeVisitor((node).right, visitor, isIdentifier)); + Debug.type(node); + return factory.updateQualifiedName(node, + nodeVisitor(node.left, visitor, isEntityName), + nodeVisitor(node.right, visitor, isIdentifier)); case SyntaxKind.ComputedPropertyName: - return factory.updateComputedPropertyName(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateComputedPropertyName(node, + nodeVisitor(node.expression, visitor, isExpression)); // Signature elements case SyntaxKind.TypeParameter: - return factory.updateTypeParameterDeclaration(node, - nodeVisitor((node).name, visitor, isIdentifier), - nodeVisitor((node).constraint, visitor, isTypeNode), - nodeVisitor((node).default, visitor, isTypeNode)); + Debug.type(node); + return factory.updateTypeParameterDeclaration(node, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.constraint, visitor, isTypeNode), + nodeVisitor(node.default, visitor, isTypeNode)); case SyntaxKind.Parameter: - return factory.updateParameterDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).dotDotDotToken, tokenVisitor, isToken), - nodeVisitor((node).name, visitor, isBindingName), - nodeVisitor((node).questionToken, tokenVisitor, isToken), - nodeVisitor((node).type, visitor, isTypeNode), - nodeVisitor((node).initializer, visitor, isExpression)); + Debug.type(node); + return factory.updateParameterDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), + nodeVisitor(node.name, visitor, isBindingName), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.initializer, visitor, isExpression)); case SyntaxKind.Decorator: - return factory.updateDecorator(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateDecorator(node, + nodeVisitor(node.expression, visitor, isExpression)); // Type elements case SyntaxKind.PropertySignature: - return factory.updatePropertySignature((node), - nodesVisitor((node).modifiers, visitor, isToken), - nodeVisitor((node).name, visitor, isPropertyName), - nodeVisitor((node).questionToken, tokenVisitor, isToken), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updatePropertySignature(node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.questionToken, tokenVisitor, isToken), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.PropertyDeclaration: - return factory.updatePropertyDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isPropertyName), + Debug.type(node); + return factory.updatePropertyDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isPropertyName), // QuestionToken and ExclamationToken is uniqued in Property Declaration and the signature of 'updateProperty' is that too - nodeVisitor((node).questionToken || (node).exclamationToken, tokenVisitor, isToken), - nodeVisitor((node).type, visitor, isTypeNode), - nodeVisitor((node).initializer, visitor, isExpression)); + nodeVisitor(node.questionToken || node.exclamationToken, tokenVisitor, isQuestionOrExclamationToken), + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.initializer, visitor, isExpression)); case SyntaxKind.MethodSignature: - return factory.updateMethodSignature(node, - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isPropertyName), - nodeVisitor((node).questionToken, tokenVisitor, isToken), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).parameters, visitor, isParameterDeclaration), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateMethodSignature(node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.MethodDeclaration: - return factory.updateMethodDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).asteriskToken, tokenVisitor, isToken), - nodeVisitor((node).name, visitor, isPropertyName), - nodeVisitor((node).questionToken, tokenVisitor, isToken), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - nodeVisitor((node).type, visitor, isTypeNode), - visitFunctionBody((node).body!, visitor, context, nodeVisitor)); + Debug.type(node); + return factory.updateMethodDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body!, visitor, context, nodeVisitor)); case SyntaxKind.Constructor: - return factory.updateConstructorDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - visitFunctionBody((node).body!, visitor, context, nodeVisitor)); + Debug.type(node); + return factory.updateConstructorDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + visitFunctionBody(node.body!, visitor, context, nodeVisitor)); case SyntaxKind.GetAccessor: - return factory.updateGetAccessorDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isPropertyName), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - nodeVisitor((node).type, visitor, isTypeNode), - visitFunctionBody((node).body!, visitor, context, nodeVisitor)); + Debug.type(node); + return factory.updateGetAccessorDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isPropertyName), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body!, visitor, context, nodeVisitor)); case SyntaxKind.SetAccessor: - return factory.updateSetAccessorDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isPropertyName), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - visitFunctionBody((node).body!, visitor, context, nodeVisitor)); + Debug.type(node); + return factory.updateSetAccessorDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isPropertyName), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + visitFunctionBody(node.body!, visitor, context, nodeVisitor)); case SyntaxKind.CallSignature: - return factory.updateCallSignature(node, - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).parameters, visitor, isParameterDeclaration), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateCallSignature(node, + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.ConstructSignature: - return factory.updateConstructSignature(node, - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).parameters, visitor, isParameterDeclaration), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateConstructSignature(node, + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.IndexSignature: - return factory.updateIndexSignature(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodesVisitor((node).parameters, visitor, isParameterDeclaration), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateIndexSignature(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode)); // Types case SyntaxKind.TypePredicate: - return factory.updateTypePredicateNode(node, - nodeVisitor((node).assertsModifier, visitor), - nodeVisitor((node).parameterName, visitor), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateTypePredicateNode(node, + nodeVisitor(node.assertsModifier, visitor, isAssertsKeyword), + nodeVisitor(node.parameterName, visitor, isIdentifierOrThisTypeNode), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.TypeReference: - return factory.updateTypeReferenceNode(node, - nodeVisitor((node).typeName, visitor, isEntityName), - nodesVisitor((node).typeArguments, visitor, isTypeNode)); + Debug.type(node); + return factory.updateTypeReferenceNode(node, + nodeVisitor(node.typeName, visitor, isEntityName), + nodesVisitor(node.typeArguments, visitor, isTypeNode)); case SyntaxKind.FunctionType: - return factory.updateFunctionTypeNode(node, - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).parameters, visitor, isParameterDeclaration), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateFunctionTypeNode(node, + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.ConstructorType: - return factory.updateConstructorTypeNode(node, - nodesVisitor((node).modifiers, visitor, isModifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).parameters, visitor, isParameterDeclaration), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateConstructorTypeNode(node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.TypeQuery: - return factory.updateTypeQueryNode((node), - nodeVisitor((node).exprName, visitor, isEntityName)); + Debug.type(node); + return factory.updateTypeQueryNode(node, + nodeVisitor(node.exprName, visitor, isEntityName)); case SyntaxKind.TypeLiteral: - return factory.updateTypeLiteralNode((node), - nodesVisitor((node).members, visitor, isTypeElement)); + Debug.type(node); + return factory.updateTypeLiteralNode(node, + nodesVisitor(node.members, visitor, isTypeElement)); case SyntaxKind.ArrayType: - return factory.updateArrayTypeNode(node, - nodeVisitor((node).elementType, visitor, isTypeNode)); + Debug.type(node); + return factory.updateArrayTypeNode(node, + nodeVisitor(node.elementType, visitor, isTypeNode)); case SyntaxKind.TupleType: - return factory.updateTupleTypeNode((node), - nodesVisitor((node).elements, visitor, isTypeNode)); + Debug.type(node); + return factory.updateTupleTypeNode(node, + nodesVisitor(node.elements, visitor, isTypeNode)); case SyntaxKind.OptionalType: - return factory.updateOptionalTypeNode((node), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateOptionalTypeNode(node, + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.RestType: - return factory.updateRestTypeNode((node), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateRestTypeNode(node, + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.UnionType: - return factory.updateUnionTypeNode(node, - nodesVisitor((node).types, visitor, isTypeNode)); + Debug.type(node); + return factory.updateUnionTypeNode(node, + nodesVisitor(node.types, visitor, isTypeNode)); case SyntaxKind.IntersectionType: - return factory.updateIntersectionTypeNode(node, - nodesVisitor((node).types, visitor, isTypeNode)); + Debug.type(node); + return factory.updateIntersectionTypeNode(node, + nodesVisitor(node.types, visitor, isTypeNode)); case SyntaxKind.ConditionalType: - return factory.updateConditionalTypeNode(node, - nodeVisitor((node).checkType, visitor, isTypeNode), - nodeVisitor((node).extendsType, visitor, isTypeNode), - nodeVisitor((node).trueType, visitor, isTypeNode), - nodeVisitor((node).falseType, visitor, isTypeNode)); + Debug.type(node); + return factory.updateConditionalTypeNode(node, + nodeVisitor(node.checkType, visitor, isTypeNode), + nodeVisitor(node.extendsType, visitor, isTypeNode), + nodeVisitor(node.trueType, visitor, isTypeNode), + nodeVisitor(node.falseType, visitor, isTypeNode)); case SyntaxKind.InferType: - return factory.updateInferTypeNode(node, - nodeVisitor((node).typeParameter, visitor, isTypeParameterDeclaration)); + Debug.type(node); + return factory.updateInferTypeNode(node, + nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration)); case SyntaxKind.ImportType: - return factory.updateImportTypeNode(node, - nodeVisitor((node).argument, visitor, isTypeNode), - nodeVisitor((node).qualifier, visitor, isEntityName), - visitNodes((node).typeArguments, visitor, isTypeNode), - (node).isTypeOf + Debug.type(node); + return factory.updateImportTypeNode(node, + nodeVisitor(node.argument, visitor, isTypeNode), + nodeVisitor(node.qualifier, visitor, isEntityName), + visitNodes(node.typeArguments, visitor, isTypeNode), + node.isTypeOf ); case SyntaxKind.NamedTupleMember: - return factory.updateNamedTupleMember(node, - visitNode((node).dotDotDotToken, visitor, isToken), - visitNode((node).name, visitor, isIdentifier), - visitNode((node).questionToken, visitor, isToken), - visitNode((node).type, visitor, isTypeNode), + Debug.type(node); + return factory.updateNamedTupleMember(node, + visitNode(node.dotDotDotToken, visitor, isDotDotDotToken), + visitNode(node.name, visitor, isIdentifier), + visitNode(node.questionToken, visitor, isQuestionToken), + visitNode(node.type, visitor, isTypeNode), ); case SyntaxKind.ParenthesizedType: - return factory.updateParenthesizedType(node, - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateParenthesizedType(node, + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.TypeOperator: - return factory.updateTypeOperatorNode(node, - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateTypeOperatorNode(node, + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.IndexedAccessType: - return factory.updateIndexedAccessTypeNode((node), - nodeVisitor((node).objectType, visitor, isTypeNode), - nodeVisitor((node).indexType, visitor, isTypeNode)); + Debug.type(node); + return factory.updateIndexedAccessTypeNode(node, + nodeVisitor(node.objectType, visitor, isTypeNode), + nodeVisitor(node.indexType, visitor, isTypeNode)); case SyntaxKind.MappedType: - return factory.updateMappedTypeNode((node), - nodeVisitor((node).readonlyToken, tokenVisitor, isToken), - nodeVisitor((node).typeParameter, visitor, isTypeParameterDeclaration), - nodeVisitor((node).nameType, visitor, isTypeNode), - nodeVisitor((node).questionToken, tokenVisitor, isToken), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateMappedTypeNode(node, + nodeVisitor(node.readonlyToken, tokenVisitor, isReadonlyKeywordOrPlusOrMinusToken), + nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration), + nodeVisitor(node.nameType, visitor, isTypeNode), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionOrPlusOrMinusToken), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.LiteralType: - return factory.updateLiteralTypeNode(node, - nodeVisitor((node).literal, visitor, isExpression)); + Debug.type(node); + return factory.updateLiteralTypeNode(node, + nodeVisitor(node.literal, visitor, isExpression)); case SyntaxKind.TemplateLiteralType: - return factory.updateTemplateLiteralType(node, - nodeVisitor((node).head, visitor, isTemplateHead), - nodesVisitor((node).templateSpans, visitor, isTemplateLiteralTypeSpan)); + Debug.type(node); + return factory.updateTemplateLiteralType(node, + nodeVisitor(node.head, visitor, isTemplateHead), + nodesVisitor(node.templateSpans, visitor, isTemplateLiteralTypeSpan)); case SyntaxKind.TemplateLiteralTypeSpan: - return factory.updateTemplateLiteralTypeSpan(node, - nodeVisitor((node).type, visitor, isTypeNode), - nodeVisitor((node).literal, visitor, isTemplateMiddleOrTemplateTail)); + Debug.type(node); + return factory.updateTemplateLiteralTypeSpan(node, + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)); // Binding patterns case SyntaxKind.ObjectBindingPattern: - return factory.updateObjectBindingPattern(node, - nodesVisitor((node).elements, visitor, isBindingElement)); + Debug.type(node); + return factory.updateObjectBindingPattern(node, + nodesVisitor(node.elements, visitor, isBindingElement)); case SyntaxKind.ArrayBindingPattern: - return factory.updateArrayBindingPattern(node, - nodesVisitor((node).elements, visitor, isArrayBindingElement)); + Debug.type(node); + return factory.updateArrayBindingPattern(node, + nodesVisitor(node.elements, visitor, isArrayBindingElement)); case SyntaxKind.BindingElement: - return factory.updateBindingElement(node, - nodeVisitor((node).dotDotDotToken, tokenVisitor, isToken), - nodeVisitor((node).propertyName, visitor, isPropertyName), - nodeVisitor((node).name, visitor, isBindingName), - nodeVisitor((node).initializer, visitor, isExpression)); + Debug.type(node); + return factory.updateBindingElement(node, + nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), + nodeVisitor(node.propertyName, visitor, isPropertyName), + nodeVisitor(node.name, visitor, isBindingName), + nodeVisitor(node.initializer, visitor, isExpression)); // Expression case SyntaxKind.ArrayLiteralExpression: - return factory.updateArrayLiteralExpression(node, - nodesVisitor((node).elements, visitor, isExpression)); + Debug.type(node); + return factory.updateArrayLiteralExpression(node, + nodesVisitor(node.elements, visitor, isExpression)); case SyntaxKind.ObjectLiteralExpression: - return factory.updateObjectLiteralExpression(node, - nodesVisitor((node).properties, visitor, isObjectLiteralElementLike)); + Debug.type(node); + return factory.updateObjectLiteralExpression(node, + nodesVisitor(node.properties, visitor, isObjectLiteralElementLike)); case SyntaxKind.PropertyAccessExpression: if (node.flags & NodeFlags.OptionalChain) { - return factory.updatePropertyAccessChain(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).questionDotToken, tokenVisitor, isToken), - nodeVisitor((node).name, visitor, isIdentifier)); + Debug.type(node); + return factory.updatePropertyAccessChain(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), + nodeVisitor(node.name, visitor, isMemberName)); } - return factory.updatePropertyAccessExpression(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).name, visitor, isIdentifierOrPrivateIdentifier)); + Debug.type(node); + return factory.updatePropertyAccessExpression(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.name, visitor, isMemberName)); case SyntaxKind.ElementAccessExpression: if (node.flags & NodeFlags.OptionalChain) { - return factory.updateElementAccessChain(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).questionDotToken, tokenVisitor, isToken), - nodeVisitor((node).argumentExpression, visitor, isExpression)); + Debug.type(node); + return factory.updateElementAccessChain(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), + nodeVisitor(node.argumentExpression, visitor, isExpression)); } - return factory.updateElementAccessExpression(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).argumentExpression, visitor, isExpression)); + Debug.type(node); + return factory.updateElementAccessExpression(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.argumentExpression, visitor, isExpression)); case SyntaxKind.CallExpression: if (node.flags & NodeFlags.OptionalChain) { - return factory.updateCallChain(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).questionDotToken, tokenVisitor, isToken), - nodesVisitor((node).typeArguments, visitor, isTypeNode), - nodesVisitor((node).arguments, visitor, isExpression)); + Debug.type(node); + return factory.updateCallChain(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodesVisitor(node.arguments, visitor, isExpression)); } - return factory.updateCallExpression(node, - nodeVisitor((node).expression, visitor, isExpression), - nodesVisitor((node).typeArguments, visitor, isTypeNode), - nodesVisitor((node).arguments, visitor, isExpression)); + Debug.type(node); + return factory.updateCallExpression(node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodesVisitor(node.arguments, visitor, isExpression)); case SyntaxKind.NewExpression: - return factory.updateNewExpression(node, - nodeVisitor((node).expression, visitor, isExpression), - nodesVisitor((node).typeArguments, visitor, isTypeNode), - nodesVisitor((node).arguments, visitor, isExpression)); + Debug.type(node); + return factory.updateNewExpression(node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodesVisitor(node.arguments, visitor, isExpression)); case SyntaxKind.TaggedTemplateExpression: - return factory.updateTaggedTemplateExpression(node, - nodeVisitor((node).tag, visitor, isExpression), - visitNodes((node).typeArguments, visitor, isExpression), - nodeVisitor((node).template, visitor, isTemplateLiteral)); + Debug.type(node); + return factory.updateTaggedTemplateExpression(node, + nodeVisitor(node.tag, visitor, isExpression), + visitNodes(node.typeArguments, visitor, isTypeNode), + nodeVisitor(node.template, visitor, isTemplateLiteral)); case SyntaxKind.TypeAssertionExpression: - return factory.updateTypeAssertion(node, - nodeVisitor((node).type, visitor, isTypeNode), - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateTypeAssertion(node, + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.ParenthesizedExpression: - return factory.updateParenthesizedExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateParenthesizedExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.FunctionExpression: - return factory.updateFunctionExpression(node, - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).asteriskToken, tokenVisitor, isToken), - nodeVisitor((node).name, visitor, isIdentifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - nodeVisitor((node).type, visitor, isTypeNode), - visitFunctionBody((node).body, visitor, context, nodeVisitor)); + Debug.type(node); + return factory.updateFunctionExpression(node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body, visitor, context, nodeVisitor)); case SyntaxKind.ArrowFunction: - return factory.updateArrowFunction(node, - nodesVisitor((node).modifiers, visitor, isModifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - nodeVisitor((node).type, visitor, isTypeNode), - nodeVisitor((node).equalsGreaterThanToken, tokenVisitor, isToken), - visitFunctionBody((node).body, visitor, context, nodeVisitor)); + Debug.type(node); + return factory.updateArrowFunction(node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.equalsGreaterThanToken, tokenVisitor, isEqualsGreaterThanToken), + visitFunctionBody(node.body, visitor, context, nodeVisitor)); case SyntaxKind.DeleteExpression: - return factory.updateDeleteExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateDeleteExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.TypeOfExpression: - return factory.updateTypeOfExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateTypeOfExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.VoidExpression: - return factory.updateVoidExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateVoidExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.AwaitExpression: - return factory.updateAwaitExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateAwaitExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.PrefixUnaryExpression: - return factory.updatePrefixUnaryExpression(node, - nodeVisitor((node).operand, visitor, isExpression)); + Debug.type(node); + return factory.updatePrefixUnaryExpression(node, + nodeVisitor(node.operand, visitor, isExpression)); case SyntaxKind.PostfixUnaryExpression: - return factory.updatePostfixUnaryExpression(node, - nodeVisitor((node).operand, visitor, isExpression)); + Debug.type(node); + return factory.updatePostfixUnaryExpression(node, + nodeVisitor(node.operand, visitor, isExpression)); case SyntaxKind.BinaryExpression: - return factory.updateBinaryExpression(node, - nodeVisitor((node).left, visitor, isExpression), - nodeVisitor((node).operatorToken, tokenVisitor, isToken), - nodeVisitor((node).right, visitor, isExpression)); + Debug.type(node); + return factory.updateBinaryExpression(node, + nodeVisitor(node.left, visitor, isExpression), + nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken), + nodeVisitor(node.right, visitor, isExpression)); case SyntaxKind.ConditionalExpression: - return factory.updateConditionalExpression(node, - nodeVisitor((node).condition, visitor, isExpression), - nodeVisitor((node).questionToken, tokenVisitor, isToken), - nodeVisitor((node).whenTrue, visitor, isExpression), - nodeVisitor((node).colonToken, tokenVisitor, isToken), - nodeVisitor((node).whenFalse, visitor, isExpression)); + Debug.type(node); + return factory.updateConditionalExpression(node, + nodeVisitor(node.condition, visitor, isExpression), + nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + nodeVisitor(node.whenTrue, visitor, isExpression), + nodeVisitor(node.colonToken, tokenVisitor, isColonToken), + nodeVisitor(node.whenFalse, visitor, isExpression)); case SyntaxKind.TemplateExpression: - return factory.updateTemplateExpression(node, - nodeVisitor((node).head, visitor, isTemplateHead), - nodesVisitor((node).templateSpans, visitor, isTemplateSpan)); + Debug.type(node); + return factory.updateTemplateExpression(node, + nodeVisitor(node.head, visitor, isTemplateHead), + nodesVisitor(node.templateSpans, visitor, isTemplateSpan)); case SyntaxKind.YieldExpression: - return factory.updateYieldExpression(node, - nodeVisitor((node).asteriskToken, tokenVisitor, isToken), - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateYieldExpression(node, + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.SpreadElement: - return factory.updateSpreadElement(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateSpreadElement(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.ClassExpression: - return factory.updateClassExpression(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isIdentifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).heritageClauses, visitor, isHeritageClause), - nodesVisitor((node).members, visitor, isClassElement)); + Debug.type(node); + return factory.updateClassExpression(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.heritageClauses, visitor, isHeritageClause), + nodesVisitor(node.members, visitor, isClassElement)); case SyntaxKind.ExpressionWithTypeArguments: - return factory.updateExpressionWithTypeArguments(node, - nodeVisitor((node).expression, visitor, isExpression), - nodesVisitor((node).typeArguments, visitor, isTypeNode)); + Debug.type(node); + return factory.updateExpressionWithTypeArguments(node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode)); case SyntaxKind.AsExpression: - return factory.updateAsExpression(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateAsExpression(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.NonNullExpression: if (node.flags & NodeFlags.OptionalChain) { - return factory.updateNonNullChain(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateNonNullChain(node, + nodeVisitor(node.expression, visitor, isExpression)); } - return factory.updateNonNullExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateNonNullExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.MetaProperty: - return factory.updateMetaProperty(node, - nodeVisitor((node).name, visitor, isIdentifier)); + Debug.type(node); + return factory.updateMetaProperty(node, + nodeVisitor(node.name, visitor, isIdentifier)); // Misc case SyntaxKind.TemplateSpan: - return factory.updateTemplateSpan(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).literal, visitor, isTemplateMiddleOrTemplateTail)); + Debug.type(node); + return factory.updateTemplateSpan(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)); // Element case SyntaxKind.Block: - return factory.updateBlock(node, - nodesVisitor((node).statements, visitor, isStatement)); + Debug.type(node); + return factory.updateBlock(node, + nodesVisitor(node.statements, visitor, isStatement)); case SyntaxKind.VariableStatement: - return factory.updateVariableStatement(node, - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).declarationList, visitor, isVariableDeclarationList)); + Debug.type(node); + return factory.updateVariableStatement(node, + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.declarationList, visitor, isVariableDeclarationList)); case SyntaxKind.ExpressionStatement: - return factory.updateExpressionStatement(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateExpressionStatement(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.IfStatement: - return factory.updateIfStatement(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).thenStatement, visitor, isStatement, factory.liftToBlock), - nodeVisitor((node).elseStatement, visitor, isStatement, factory.liftToBlock)); + Debug.type(node); + return factory.updateIfStatement(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.thenStatement, visitor, isStatement, factory.liftToBlock), + nodeVisitor(node.elseStatement, visitor, isStatement, factory.liftToBlock)); case SyntaxKind.DoStatement: - return factory.updateDoStatement(node, - nodeVisitor((node).statement, visitor, isStatement, factory.liftToBlock), - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateDoStatement(node, + nodeVisitor(node.statement, visitor, isStatement, factory.liftToBlock), + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.WhileStatement: - return factory.updateWhileStatement(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).statement, visitor, isStatement, factory.liftToBlock)); + Debug.type(node); + return factory.updateWhileStatement(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.statement, visitor, isStatement, factory.liftToBlock)); case SyntaxKind.ForStatement: - return factory.updateForStatement(node, - nodeVisitor((node).initializer, visitor, isForInitializer), - nodeVisitor((node).condition, visitor, isExpression), - nodeVisitor((node).incrementor, visitor, isExpression), - nodeVisitor((node).statement, visitor, isStatement, factory.liftToBlock)); + Debug.type(node); + return factory.updateForStatement(node, + nodeVisitor(node.initializer, visitor, isForInitializer), + nodeVisitor(node.condition, visitor, isExpression), + nodeVisitor(node.incrementor, visitor, isExpression), + nodeVisitor(node.statement, visitor, isStatement, factory.liftToBlock)); case SyntaxKind.ForInStatement: - return factory.updateForInStatement(node, - nodeVisitor((node).initializer, visitor, isForInitializer), - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).statement, visitor, isStatement, factory.liftToBlock)); + Debug.type(node); + return factory.updateForInStatement(node, + nodeVisitor(node.initializer, visitor, isForInitializer), + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.statement, visitor, isStatement, factory.liftToBlock)); case SyntaxKind.ForOfStatement: - return factory.updateForOfStatement(node, - nodeVisitor((node).awaitModifier, tokenVisitor, isToken), - nodeVisitor((node).initializer, visitor, isForInitializer), - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).statement, visitor, isStatement, factory.liftToBlock)); + Debug.type(node); + return factory.updateForOfStatement(node, + nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword), + nodeVisitor(node.initializer, visitor, isForInitializer), + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.statement, visitor, isStatement, factory.liftToBlock)); case SyntaxKind.ContinueStatement: - return factory.updateContinueStatement(node, - nodeVisitor((node).label, visitor, isIdentifier)); + Debug.type(node); + return factory.updateContinueStatement(node, + nodeVisitor(node.label, visitor, isIdentifier)); case SyntaxKind.BreakStatement: - return factory.updateBreakStatement(node, - nodeVisitor((node).label, visitor, isIdentifier)); + Debug.type(node); + return factory.updateBreakStatement(node, + nodeVisitor(node.label, visitor, isIdentifier)); case SyntaxKind.ReturnStatement: - return factory.updateReturnStatement(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateReturnStatement(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.WithStatement: - return factory.updateWithStatement(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).statement, visitor, isStatement, factory.liftToBlock)); + Debug.type(node); + return factory.updateWithStatement(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.statement, visitor, isStatement, factory.liftToBlock)); case SyntaxKind.SwitchStatement: - return factory.updateSwitchStatement(node, - nodeVisitor((node).expression, visitor, isExpression), - nodeVisitor((node).caseBlock, visitor, isCaseBlock)); + Debug.type(node); + return factory.updateSwitchStatement(node, + nodeVisitor(node.expression, visitor, isExpression), + nodeVisitor(node.caseBlock, visitor, isCaseBlock)); case SyntaxKind.LabeledStatement: - return factory.updateLabeledStatement(node, - nodeVisitor((node).label, visitor, isIdentifier), - nodeVisitor((node).statement, visitor, isStatement, factory.liftToBlock)); + Debug.type(node); + return factory.updateLabeledStatement(node, + nodeVisitor(node.label, visitor, isIdentifier), + nodeVisitor(node.statement, visitor, isStatement, factory.liftToBlock)); case SyntaxKind.ThrowStatement: - return factory.updateThrowStatement(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateThrowStatement(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.TryStatement: - return factory.updateTryStatement(node, - nodeVisitor((node).tryBlock, visitor, isBlock), - nodeVisitor((node).catchClause, visitor, isCatchClause), - nodeVisitor((node).finallyBlock, visitor, isBlock)); + Debug.type(node); + return factory.updateTryStatement(node, + nodeVisitor(node.tryBlock, visitor, isBlock), + nodeVisitor(node.catchClause, visitor, isCatchClause), + nodeVisitor(node.finallyBlock, visitor, isBlock)); case SyntaxKind.VariableDeclaration: - return factory.updateVariableDeclaration(node, - nodeVisitor((node).name, visitor, isBindingName), - nodeVisitor((node).exclamationToken, tokenVisitor, isToken), - nodeVisitor((node).type, visitor, isTypeNode), - nodeVisitor((node).initializer, visitor, isExpression)); + Debug.type(node); + return factory.updateVariableDeclaration(node, + nodeVisitor(node.name, visitor, isBindingName), + nodeVisitor(node.exclamationToken, tokenVisitor, isExclamationToken), + nodeVisitor(node.type, visitor, isTypeNode), + nodeVisitor(node.initializer, visitor, isExpression)); case SyntaxKind.VariableDeclarationList: - return factory.updateVariableDeclarationList(node, - nodesVisitor((node).declarations, visitor, isVariableDeclaration)); + Debug.type(node); + return factory.updateVariableDeclarationList(node, + nodesVisitor(node.declarations, visitor, isVariableDeclaration)); case SyntaxKind.FunctionDeclaration: - return factory.updateFunctionDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).asteriskToken, tokenVisitor, isToken), - nodeVisitor((node).name, visitor, isIdentifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - nodeVisitor((node).type, visitor, isTypeNode), - visitFunctionBody((node).body, visitor, context, nodeVisitor)); + Debug.type(node); + return factory.updateFunctionDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + visitParameterList(node.parameters, visitor, context, nodesVisitor), + nodeVisitor(node.type, visitor, isTypeNode), + visitFunctionBody(node.body, visitor, context, nodeVisitor)); case SyntaxKind.ClassDeclaration: - return factory.updateClassDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isIdentifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).heritageClauses, visitor, isHeritageClause), - nodesVisitor((node).members, visitor, isClassElement)); + Debug.type(node); + return factory.updateClassDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.heritageClauses, visitor, isHeritageClause), + nodesVisitor(node.members, visitor, isClassElement)); case SyntaxKind.InterfaceDeclaration: - return factory.updateInterfaceDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isIdentifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor((node).heritageClauses, visitor, isHeritageClause), - nodesVisitor((node).members, visitor, isTypeElement)); + Debug.type(node); + return factory.updateInterfaceDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodesVisitor(node.heritageClauses, visitor, isHeritageClause), + nodesVisitor(node.members, visitor, isTypeElement)); case SyntaxKind.TypeAliasDeclaration: - return factory.updateTypeAliasDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isIdentifier), - nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), - nodeVisitor((node).type, visitor, isTypeNode)); + Debug.type(node); + return factory.updateTypeAliasDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), + nodeVisitor(node.type, visitor, isTypeNode)); case SyntaxKind.EnumDeclaration: - return factory.updateEnumDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isIdentifier), - nodesVisitor((node).members, visitor, isEnumMember)); + Debug.type(node); + return factory.updateEnumDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isIdentifier), + nodesVisitor(node.members, visitor, isEnumMember)); case SyntaxKind.ModuleDeclaration: - return factory.updateModuleDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).name, visitor, isIdentifier), - nodeVisitor((node).body, visitor, isModuleBody)); + Debug.type(node); + return factory.updateModuleDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.name, visitor, isModuleName), + nodeVisitor(node.body, visitor, isModuleBody)); case SyntaxKind.ModuleBlock: - return factory.updateModuleBlock(node, - nodesVisitor((node).statements, visitor, isStatement)); + Debug.type(node); + return factory.updateModuleBlock(node, + nodesVisitor(node.statements, visitor, isStatement)); case SyntaxKind.CaseBlock: - return factory.updateCaseBlock(node, - nodesVisitor((node).clauses, visitor, isCaseOrDefaultClause)); + Debug.type(node); + return factory.updateCaseBlock(node, + nodesVisitor(node.clauses, visitor, isCaseOrDefaultClause)); case SyntaxKind.NamespaceExportDeclaration: - return factory.updateNamespaceExportDeclaration(node, - nodeVisitor((node).name, visitor, isIdentifier)); + Debug.type(node); + return factory.updateNamespaceExportDeclaration(node, + nodeVisitor(node.name, visitor, isIdentifier)); case SyntaxKind.ImportEqualsDeclaration: - return factory.updateImportEqualsDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - (node).isTypeOnly, - nodeVisitor((node).name, visitor, isIdentifier), - nodeVisitor((node).moduleReference, visitor, isModuleReference)); + Debug.type(node); + return factory.updateImportEqualsDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + node.isTypeOnly, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.moduleReference, visitor, isModuleReference)); case SyntaxKind.ImportDeclaration: - return factory.updateImportDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).importClause, visitor, isImportClause), - nodeVisitor((node).moduleSpecifier, visitor, isExpression)); + Debug.type(node); + return factory.updateImportDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.importClause, visitor, isImportClause), + nodeVisitor(node.moduleSpecifier, visitor, isExpression)); case SyntaxKind.ImportClause: - return factory.updateImportClause(node, - (node).isTypeOnly, - nodeVisitor((node).name, visitor, isIdentifier), - nodeVisitor((node).namedBindings, visitor, isNamedImportBindings)); + Debug.type(node); + return factory.updateImportClause(node, + node.isTypeOnly, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.namedBindings, visitor, isNamedImportBindings)); case SyntaxKind.NamespaceImport: - return factory.updateNamespaceImport(node, - nodeVisitor((node).name, visitor, isIdentifier)); + Debug.type(node); + return factory.updateNamespaceImport(node, + nodeVisitor(node.name, visitor, isIdentifier)); case SyntaxKind.NamespaceExport: - return factory.updateNamespaceExport(node, - nodeVisitor((node).name, visitor, isIdentifier)); + Debug.type(node); + return factory.updateNamespaceExport(node, + nodeVisitor(node.name, visitor, isIdentifier)); case SyntaxKind.NamedImports: - return factory.updateNamedImports(node, - nodesVisitor((node).elements, visitor, isImportSpecifier)); + Debug.type(node); + return factory.updateNamedImports(node, + nodesVisitor(node.elements, visitor, isImportSpecifier)); case SyntaxKind.ImportSpecifier: - return factory.updateImportSpecifier(node, - nodeVisitor((node).propertyName, visitor, isIdentifier), - nodeVisitor((node).name, visitor, isIdentifier)); + Debug.type(node); + return factory.updateImportSpecifier(node, + nodeVisitor(node.propertyName, visitor, isIdentifier), + nodeVisitor(node.name, visitor, isIdentifier)); case SyntaxKind.ExportAssignment: - return factory.updateExportAssignment(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateExportAssignment(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.ExportDeclaration: - return factory.updateExportDeclaration(node, - nodesVisitor((node).decorators, visitor, isDecorator), - nodesVisitor((node).modifiers, visitor, isModifier), - (node).isTypeOnly, - nodeVisitor((node).exportClause, visitor, isNamedExportBindings), - nodeVisitor((node).moduleSpecifier, visitor, isExpression)); + Debug.type(node); + return factory.updateExportDeclaration(node, + nodesVisitor(node.decorators, visitor, isDecorator), + nodesVisitor(node.modifiers, visitor, isModifier), + node.isTypeOnly, + nodeVisitor(node.exportClause, visitor, isNamedExportBindings), + nodeVisitor(node.moduleSpecifier, visitor, isExpression)); case SyntaxKind.NamedExports: - return factory.updateNamedExports(node, - nodesVisitor((node).elements, visitor, isExportSpecifier)); + Debug.type(node); + return factory.updateNamedExports(node, + nodesVisitor(node.elements, visitor, isExportSpecifier)); case SyntaxKind.ExportSpecifier: - return factory.updateExportSpecifier(node, - nodeVisitor((node).propertyName, visitor, isIdentifier), - nodeVisitor((node).name, visitor, isIdentifier)); + Debug.type(node); + return factory.updateExportSpecifier(node, + nodeVisitor(node.propertyName, visitor, isIdentifier), + nodeVisitor(node.name, visitor, isIdentifier)); // Module references case SyntaxKind.ExternalModuleReference: - return factory.updateExternalModuleReference(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateExternalModuleReference(node, + nodeVisitor(node.expression, visitor, isExpression)); // JSX case SyntaxKind.JsxElement: - return factory.updateJsxElement(node, - nodeVisitor((node).openingElement, visitor, isJsxOpeningElement), - nodesVisitor((node).children, visitor, isJsxChild), - nodeVisitor((node).closingElement, visitor, isJsxClosingElement)); + Debug.type(node); + return factory.updateJsxElement(node, + nodeVisitor(node.openingElement, visitor, isJsxOpeningElement), + nodesVisitor(node.children, visitor, isJsxChild), + nodeVisitor(node.closingElement, visitor, isJsxClosingElement)); case SyntaxKind.JsxSelfClosingElement: - return factory.updateJsxSelfClosingElement(node, - nodeVisitor((node).tagName, visitor, isJsxTagNameExpression), - nodesVisitor((node).typeArguments, visitor, isTypeNode), - nodeVisitor((node).attributes, visitor, isJsxAttributes)); + Debug.type(node); + return factory.updateJsxSelfClosingElement(node, + nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodeVisitor(node.attributes, visitor, isJsxAttributes)); case SyntaxKind.JsxOpeningElement: - return factory.updateJsxOpeningElement(node, - nodeVisitor((node).tagName, visitor, isJsxTagNameExpression), - nodesVisitor((node).typeArguments, visitor, isTypeNode), - nodeVisitor((node).attributes, visitor, isJsxAttributes)); + Debug.type(node); + return factory.updateJsxOpeningElement(node, + nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), + nodesVisitor(node.typeArguments, visitor, isTypeNode), + nodeVisitor(node.attributes, visitor, isJsxAttributes)); case SyntaxKind.JsxClosingElement: - return factory.updateJsxClosingElement(node, - nodeVisitor((node).tagName, visitor, isJsxTagNameExpression)); + Debug.type(node); + return factory.updateJsxClosingElement(node, + nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)); case SyntaxKind.JsxFragment: - return factory.updateJsxFragment(node, - nodeVisitor((node).openingFragment, visitor, isJsxOpeningFragment), - nodesVisitor((node).children, visitor, isJsxChild), - nodeVisitor((node).closingFragment, visitor, isJsxClosingFragment)); + Debug.type(node); + return factory.updateJsxFragment(node, + nodeVisitor(node.openingFragment, visitor, isJsxOpeningFragment), + nodesVisitor(node.children, visitor, isJsxChild), + nodeVisitor(node.closingFragment, visitor, isJsxClosingFragment)); case SyntaxKind.JsxAttribute: - return factory.updateJsxAttribute(node, - nodeVisitor((node).name, visitor, isIdentifier), - nodeVisitor((node).initializer, visitor, isStringLiteralOrJsxExpression)); + Debug.type(node); + return factory.updateJsxAttribute(node, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.initializer, visitor, isStringLiteralOrJsxExpression)); case SyntaxKind.JsxAttributes: - return factory.updateJsxAttributes(node, - nodesVisitor((node).properties, visitor, isJsxAttributeLike)); + Debug.type(node); + return factory.updateJsxAttributes(node, + nodesVisitor(node.properties, visitor, isJsxAttributeLike)); case SyntaxKind.JsxSpreadAttribute: - return factory.updateJsxSpreadAttribute(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateJsxSpreadAttribute(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.JsxExpression: - return factory.updateJsxExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateJsxExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); // Clauses case SyntaxKind.CaseClause: - return factory.updateCaseClause(node, - nodeVisitor((node).expression, visitor, isExpression), - nodesVisitor((node).statements, visitor, isStatement)); + Debug.type(node); + return factory.updateCaseClause(node, + nodeVisitor(node.expression, visitor, isExpression), + nodesVisitor(node.statements, visitor, isStatement)); case SyntaxKind.DefaultClause: - return factory.updateDefaultClause(node, - nodesVisitor((node).statements, visitor, isStatement)); + Debug.type(node); + return factory.updateDefaultClause(node, + nodesVisitor(node.statements, visitor, isStatement)); case SyntaxKind.HeritageClause: - return factory.updateHeritageClause(node, - nodesVisitor((node).types, visitor, isExpressionWithTypeArguments)); + Debug.type(node); + return factory.updateHeritageClause(node, + nodesVisitor(node.types, visitor, isExpressionWithTypeArguments)); case SyntaxKind.CatchClause: - return factory.updateCatchClause(node, - nodeVisitor((node).variableDeclaration, visitor, isVariableDeclaration), - nodeVisitor((node).block, visitor, isBlock)); + Debug.type(node); + return factory.updateCatchClause(node, + nodeVisitor(node.variableDeclaration, visitor, isVariableDeclaration), + nodeVisitor(node.block, visitor, isBlock)); // Property assignments case SyntaxKind.PropertyAssignment: - return factory.updatePropertyAssignment(node, - nodeVisitor((node).name, visitor, isPropertyName), - nodeVisitor((node).initializer, visitor, isExpression)); + Debug.type(node); + return factory.updatePropertyAssignment(node, + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.initializer, visitor, isExpression)); case SyntaxKind.ShorthandPropertyAssignment: - return factory.updateShorthandPropertyAssignment(node, - nodeVisitor((node).name, visitor, isIdentifier), - nodeVisitor((node).objectAssignmentInitializer, visitor, isExpression)); + Debug.type(node); + return factory.updateShorthandPropertyAssignment(node, + nodeVisitor(node.name, visitor, isIdentifier), + nodeVisitor(node.objectAssignmentInitializer, visitor, isExpression)); case SyntaxKind.SpreadAssignment: - return factory.updateSpreadAssignment(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updateSpreadAssignment(node, + nodeVisitor(node.expression, visitor, isExpression)); // Enum case SyntaxKind.EnumMember: - return factory.updateEnumMember(node, - nodeVisitor((node).name, visitor, isPropertyName), - nodeVisitor((node).initializer, visitor, isExpression)); + Debug.type(node); + return factory.updateEnumMember(node, + nodeVisitor(node.name, visitor, isPropertyName), + nodeVisitor(node.initializer, visitor, isExpression)); // Top-level nodes case SyntaxKind.SourceFile: - return factory.updateSourceFile(node, - visitLexicalEnvironment((node).statements, visitor, context)); + Debug.type(node); + return factory.updateSourceFile(node, + visitLexicalEnvironment(node.statements, visitor, context)); // Transformation nodes case SyntaxKind.PartiallyEmittedExpression: - return factory.updatePartiallyEmittedExpression(node, - nodeVisitor((node).expression, visitor, isExpression)); + Debug.type(node); + return factory.updatePartiallyEmittedExpression(node, + nodeVisitor(node.expression, visitor, isExpression)); case SyntaxKind.CommaListExpression: - return factory.updateCommaListExpression(node, - nodesVisitor((node).elements, visitor, isExpression)); + Debug.type(node); + return factory.updateCommaListExpression(node, + nodesVisitor(node.elements, visitor, isExpression)); default: // No need to visit nodes with no children. diff --git a/src/deprecatedCompat/deprecations.ts b/src/deprecatedCompat/deprecations.ts index b0573ad4ab7..c04e34e8b16 100644 --- a/src/deprecatedCompat/deprecations.ts +++ b/src/deprecatedCompat/deprecations.ts @@ -1354,4 +1354,24 @@ namespace ts { export interface Map extends ESMap { } // #endregion + + // DEPRECATION: Renamed node tests + // DEPRECATION PLAN: + // - soft: 4.2 + // - warn: 4.3 + // - error: TBD + // #region Renamed node Tests + + /** + * @deprecated Use `isMemberName` instead. + */ + export const isIdentifierOrPrivateIdentifier = Debug.deprecate(function isIdentifierOrPrivateIdentifier(node: Node): node is MemberName { + return isMemberName(node); + }, { + since: "4.2", + warnAfter: "4.3", + message: "Use `isMemberName` instead." + }); + + // #endregion Renamed node Tests } \ No newline at end of file diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index 78d748589e8..ed748ad29c8 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -46,7 +46,7 @@ namespace ts.codefix { let suggestedSymbol: Symbol | undefined; if (isPropertyAccessExpression(parent) && parent.name === node) { - Debug.assert(isIdentifierOrPrivateIdentifier(node), "Expected an identifier for spelling (property access)"); + Debug.assert(isMemberName(node), "Expected an identifier for spelling (property access)"); let containingType = checker.getTypeAtLocation(parent.expression); if (parent.flags & NodeFlags.OptionalChain) { containingType = checker.getNonNullableType(containingType); diff --git a/src/services/completions.ts b/src/services/completions.ts index f5f7176237b..ad135959391 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -977,7 +977,7 @@ namespace ts.Completions { // Check if the caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS| // Skip this partial identifier and adjust the contextToken to the token that precedes it. - if (contextToken && position <= contextToken.end && (isIdentifierOrPrivateIdentifier(contextToken) || isKeyword(contextToken.kind))) { + if (contextToken && position <= contextToken.end && (isMemberName(contextToken) || isKeyword(contextToken.kind))) { const start = timestamp(); contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile, /*startNode*/ undefined)!; // TODO: GH#18217 log("getCompletionData: Get previous token 2: " + (timestamp() - start)); diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index adbcfe68bef..829ebdbf2b6 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -1037,11 +1037,12 @@ namespace ts.textChanges { let lastNonTriviaPosition = 0; const writer = createTextWriter(newLine); - const onEmitNode: PrintHandlers["onEmitNode"] = (hint, node, printCallback) => { + const onBeforeEmitNode: PrintHandlers["onBeforeEmitNode"] = node => { if (node) { setPos(node, lastNonTriviaPosition); } - printCallback(hint, node); + }; + const onAfterEmitNode: PrintHandlers["onAfterEmitNode"] = node => { if (node) { setEnd(node, lastNonTriviaPosition); } @@ -1163,7 +1164,8 @@ namespace ts.textChanges { } return { - onEmitNode, + onBeforeEmitNode, + onAfterEmitNode, onBeforeEmitNodeArray, onAfterEmitNodeArray, onBeforeEmitToken, diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 32e43fc0c4c..e02e91bf766 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -638,6 +638,7 @@ declare namespace ts { } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier; + export type MemberName = Identifier | PrivateIdentifier; export type DeclarationName = Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | EntityNameExpression; export interface Declaration extends Node { _declarationBrand: any; @@ -1216,11 +1217,11 @@ declare namespace ts { readonly kind: SyntaxKind.PropertyAccessExpression; readonly expression: LeftHandSideExpression; readonly questionDotToken?: QuestionDotToken; - readonly name: Identifier | PrivateIdentifier; + readonly name: MemberName; } export interface PropertyAccessChain extends PropertyAccessExpression { _optionalChainBrand: any; - readonly name: Identifier | PrivateIdentifier; + readonly name: MemberName; } export interface SuperPropertyAccessExpression extends PropertyAccessExpression { readonly expression: SuperExpression; @@ -3130,17 +3131,21 @@ declare namespace ts { Iterator = 8388608, NoAsciiEscaping = 16777216, } - export interface EmitHelper { + export interface EmitHelperBase { readonly name: string; readonly scoped: boolean; readonly text: string | ((node: EmitHelperUniqueNameCallback) => string); readonly priority?: number; readonly dependencies?: EmitHelper[]; } - export interface UnscopedEmitHelper extends EmitHelper { + export interface ScopedEmitHelper extends EmitHelperBase { + readonly scoped: true; + } + export interface UnscopedEmitHelper extends EmitHelperBase { readonly scoped: false; readonly text: string; } + export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper; export type EmitHelperUniqueNameCallback = (name: string) => string; export enum EmitHint { SourceFile = 0, @@ -3286,10 +3291,10 @@ declare namespace ts { updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression; createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression; updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression; - createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier): PropertyAccessExpression; - updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier): PropertyAccessExpression; - createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier): PropertyAccessChain; - updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier): PropertyAccessChain; + createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression; + updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression; + createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain; + updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain; createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression; updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression; createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain; @@ -3750,12 +3755,12 @@ declare namespace ts { * }); * ``` */ - onEmitNode?(hint: EmitHint, node: Node | undefined, emitCallback: (hint: EmitHint, node: Node | undefined) => void): void; + onEmitNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void; /** * A hook used to check if an emit notification is required for a node. * @param node The node to emit. */ - isEmitNotificationEnabled?(node: Node | undefined): boolean; + isEmitNotificationEnabled?(node: Node): boolean; /** * A hook used by the Printer to perform just-in-time substitution of a node. This is * primarily used by node transformations that need to substitute one node for another, @@ -4191,7 +4196,7 @@ declare namespace ts { */ function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[]; function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined; - function isIdentifierOrPrivateIdentifier(node: Node): node is Identifier | PrivateIdentifier; + function isMemberName(node: Node): node is MemberName; function isPropertyAccessChain(node: Node): node is PropertyAccessChain; function isElementAccessChain(node: Node): node is ElementAccessChain; function isCallChain(node: Node): node is CallChain; @@ -4206,6 +4211,12 @@ declare namespace ts { function isUnparsedTextLike(node: Node): node is UnparsedTextLike; function isUnparsedNode(node: Node): node is UnparsedNode; function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag; + /** + * True if kind is of some token syntax kind. + * For example, this is true for an IfKeyword but not for an IfStatement. + * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail. + */ + function isTokenKind(kind: SyntaxKind): boolean; /** * True if node is of some token syntax kind. * For example, this is true for an IfKeyword but not for an IfStatement. @@ -4348,10 +4359,14 @@ declare namespace ts { function isTemplateHead(node: Node): node is TemplateHead; function isTemplateMiddle(node: Node): node is TemplateMiddle; function isTemplateTail(node: Node): node is TemplateTail; + function isDotDotDotToken(node: Node): node is DotDotDotToken; + function isPlusToken(node: Node): node is PlusToken; + function isMinusToken(node: Node): node is MinusToken; + function isAsteriskToken(node: Node): node is AsteriskToken; function isIdentifier(node: Node): node is Identifier; + function isPrivateIdentifier(node: Node): node is PrivateIdentifier; function isQualifiedName(node: Node): node is QualifiedName; function isComputedPropertyName(node: Node): node is ComputedPropertyName; - function isPrivateIdentifier(node: Node): node is PrivateIdentifier; function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration; function isParameter(node: Node): node is ParameterDeclaration; function isDecorator(node: Node): node is Decorator; @@ -10370,13 +10385,13 @@ declare namespace ts { /** @deprecated Use `factory.updateObjectLiteralExpression` or the factory supplied by your transformation context instead. */ const updateObjectLiteral: (node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) => ObjectLiteralExpression; /** @deprecated Use `factory.createPropertyAccessExpression` or the factory supplied by your transformation context instead. */ - const createPropertyAccess: (expression: Expression, name: string | Identifier | PrivateIdentifier) => PropertyAccessExpression; + const createPropertyAccess: (expression: Expression, name: string | MemberName) => PropertyAccessExpression; /** @deprecated Use `factory.updatePropertyAccessExpression` or the factory supplied by your transformation context instead. */ - const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) => PropertyAccessExpression; + const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: MemberName) => PropertyAccessExpression; /** @deprecated Use `factory.createPropertyAccessChain` or the factory supplied by your transformation context instead. */ - const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) => PropertyAccessChain; + const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName) => PropertyAccessChain; /** @deprecated Use `factory.updatePropertyAccessChain` or the factory supplied by your transformation context instead. */ - const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) => PropertyAccessChain; + const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName) => PropertyAccessChain; /** @deprecated Use `factory.createElementAccessExpression` or the factory supplied by your transformation context instead. */ const createElementAccess: (expression: Expression, index: number | Expression) => ElementAccessExpression; /** @deprecated Use `factory.updateElementAccessExpression` or the factory supplied by your transformation context instead. */ @@ -10946,6 +10961,10 @@ declare namespace ts { */ interface Map extends ESMap { } + /** + * @deprecated Use `isMemberName` instead. + */ + const isIdentifierOrPrivateIdentifier: (node: Node) => node is MemberName; } export = ts; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 87bb3c3e61e..7b086a2531e 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -638,6 +638,7 @@ declare namespace ts { } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier; + export type MemberName = Identifier | PrivateIdentifier; export type DeclarationName = Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | EntityNameExpression; export interface Declaration extends Node { _declarationBrand: any; @@ -1216,11 +1217,11 @@ declare namespace ts { readonly kind: SyntaxKind.PropertyAccessExpression; readonly expression: LeftHandSideExpression; readonly questionDotToken?: QuestionDotToken; - readonly name: Identifier | PrivateIdentifier; + readonly name: MemberName; } export interface PropertyAccessChain extends PropertyAccessExpression { _optionalChainBrand: any; - readonly name: Identifier | PrivateIdentifier; + readonly name: MemberName; } export interface SuperPropertyAccessExpression extends PropertyAccessExpression { readonly expression: SuperExpression; @@ -3130,17 +3131,21 @@ declare namespace ts { Iterator = 8388608, NoAsciiEscaping = 16777216, } - export interface EmitHelper { + export interface EmitHelperBase { readonly name: string; readonly scoped: boolean; readonly text: string | ((node: EmitHelperUniqueNameCallback) => string); readonly priority?: number; readonly dependencies?: EmitHelper[]; } - export interface UnscopedEmitHelper extends EmitHelper { + export interface ScopedEmitHelper extends EmitHelperBase { + readonly scoped: true; + } + export interface UnscopedEmitHelper extends EmitHelperBase { readonly scoped: false; readonly text: string; } + export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper; export type EmitHelperUniqueNameCallback = (name: string) => string; export enum EmitHint { SourceFile = 0, @@ -3286,10 +3291,10 @@ declare namespace ts { updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression; createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression; updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression; - createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier): PropertyAccessExpression; - updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier): PropertyAccessExpression; - createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier): PropertyAccessChain; - updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier): PropertyAccessChain; + createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression; + updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression; + createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain; + updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain; createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression; updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression; createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain; @@ -3750,12 +3755,12 @@ declare namespace ts { * }); * ``` */ - onEmitNode?(hint: EmitHint, node: Node | undefined, emitCallback: (hint: EmitHint, node: Node | undefined) => void): void; + onEmitNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void; /** * A hook used to check if an emit notification is required for a node. * @param node The node to emit. */ - isEmitNotificationEnabled?(node: Node | undefined): boolean; + isEmitNotificationEnabled?(node: Node): boolean; /** * A hook used by the Printer to perform just-in-time substitution of a node. This is * primarily used by node transformations that need to substitute one node for another, @@ -4191,7 +4196,7 @@ declare namespace ts { */ function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[]; function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined; - function isIdentifierOrPrivateIdentifier(node: Node): node is Identifier | PrivateIdentifier; + function isMemberName(node: Node): node is MemberName; function isPropertyAccessChain(node: Node): node is PropertyAccessChain; function isElementAccessChain(node: Node): node is ElementAccessChain; function isCallChain(node: Node): node is CallChain; @@ -4206,6 +4211,12 @@ declare namespace ts { function isUnparsedTextLike(node: Node): node is UnparsedTextLike; function isUnparsedNode(node: Node): node is UnparsedNode; function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag; + /** + * True if kind is of some token syntax kind. + * For example, this is true for an IfKeyword but not for an IfStatement. + * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail. + */ + function isTokenKind(kind: SyntaxKind): boolean; /** * True if node is of some token syntax kind. * For example, this is true for an IfKeyword but not for an IfStatement. @@ -4348,10 +4359,14 @@ declare namespace ts { function isTemplateHead(node: Node): node is TemplateHead; function isTemplateMiddle(node: Node): node is TemplateMiddle; function isTemplateTail(node: Node): node is TemplateTail; + function isDotDotDotToken(node: Node): node is DotDotDotToken; + function isPlusToken(node: Node): node is PlusToken; + function isMinusToken(node: Node): node is MinusToken; + function isAsteriskToken(node: Node): node is AsteriskToken; function isIdentifier(node: Node): node is Identifier; + function isPrivateIdentifier(node: Node): node is PrivateIdentifier; function isQualifiedName(node: Node): node is QualifiedName; function isComputedPropertyName(node: Node): node is ComputedPropertyName; - function isPrivateIdentifier(node: Node): node is PrivateIdentifier; function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration; function isParameter(node: Node): node is ParameterDeclaration; function isDecorator(node: Node): node is Decorator; @@ -6643,13 +6658,13 @@ declare namespace ts { /** @deprecated Use `factory.updateObjectLiteralExpression` or the factory supplied by your transformation context instead. */ const updateObjectLiteral: (node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) => ObjectLiteralExpression; /** @deprecated Use `factory.createPropertyAccessExpression` or the factory supplied by your transformation context instead. */ - const createPropertyAccess: (expression: Expression, name: string | Identifier | PrivateIdentifier) => PropertyAccessExpression; + const createPropertyAccess: (expression: Expression, name: string | MemberName) => PropertyAccessExpression; /** @deprecated Use `factory.updatePropertyAccessExpression` or the factory supplied by your transformation context instead. */ - const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) => PropertyAccessExpression; + const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: MemberName) => PropertyAccessExpression; /** @deprecated Use `factory.createPropertyAccessChain` or the factory supplied by your transformation context instead. */ - const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) => PropertyAccessChain; + const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName) => PropertyAccessChain; /** @deprecated Use `factory.updatePropertyAccessChain` or the factory supplied by your transformation context instead. */ - const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) => PropertyAccessChain; + const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName) => PropertyAccessChain; /** @deprecated Use `factory.createElementAccessExpression` or the factory supplied by your transformation context instead. */ const createElementAccess: (expression: Expression, index: number | Expression) => ElementAccessExpression; /** @deprecated Use `factory.updateElementAccessExpression` or the factory supplied by your transformation context instead. */ @@ -7219,6 +7234,10 @@ declare namespace ts { */ interface Map extends ESMap { } + /** + * @deprecated Use `isMemberName` instead. + */ + const isIdentifierOrPrivateIdentifier: (node: Node) => node is MemberName; } export = ts; \ No newline at end of file diff --git a/tests/baselines/reference/es6ExportClauseWithAssignmentInEs5.js b/tests/baselines/reference/es6ExportClauseWithAssignmentInEs5.js index 18433ac6885..b57fce233b6 100644 --- a/tests/baselines/reference/es6ExportClauseWithAssignmentInEs5.js +++ b/tests/baselines/reference/es6ExportClauseWithAssignmentInEs5.js @@ -32,6 +32,6 @@ exports.buzz = buzz; exports.buzz = buzz += 3; var bizz = 8; exports.bizz = bizz; -(exports.bizz = bizz += 1); // compiles to exports.bizz = bizz += 1 -(exports.bizz = bizz -= 1); // similarly -(exports.bizz = ++bizz); // compiles to exports.bizz = ++bizz +(exports.bizz = ++bizz) - 1; // compiles to exports.bizz = bizz += 1 +(exports.bizz = --bizz) + 1; // similarly +exports.bizz = ++bizz; // compiles to exports.bizz = ++bizz diff --git a/tests/baselines/reference/importMeta(module=commonjs,target=es5).js b/tests/baselines/reference/importMeta(module=commonjs,target=es5).js index c9ddd9d96e6..c6bc5cf86f3 100644 --- a/tests/baselines/reference/importMeta(module=commonjs,target=es5).js +++ b/tests/baselines/reference/importMeta(module=commonjs,target=es5).js @@ -101,8 +101,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.z = exports.y = exports.x = void 0; -exports.x = (import.meta); -exports.y = (import.metal); +exports.x = import.meta; +exports.y = import.metal; exports.z = import.import.import.malkovich; //// [scriptLookingFile01.js] "use strict"; diff --git a/tests/baselines/reference/importMeta(module=commonjs,target=esnext).js b/tests/baselines/reference/importMeta(module=commonjs,target=esnext).js index f918b0480e2..507aff838e9 100644 --- a/tests/baselines/reference/importMeta(module=commonjs,target=esnext).js +++ b/tests/baselines/reference/importMeta(module=commonjs,target=esnext).js @@ -55,8 +55,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.z = exports.y = exports.x = void 0; -exports.x = (import.meta); -exports.y = (import.metal); +exports.x = import.meta; +exports.y = import.metal; exports.z = import.import.import.malkovich; //// [scriptLookingFile01.js] "use strict"; diff --git a/tests/baselines/reference/importMeta(module=system,target=es5).js b/tests/baselines/reference/importMeta(module=system,target=es5).js index 3eda4156d8b..e68407acd99 100644 --- a/tests/baselines/reference/importMeta(module=system,target=es5).js +++ b/tests/baselines/reference/importMeta(module=system,target=es5).js @@ -112,8 +112,8 @@ System.register([], function (exports_1, context_1) { return { setters: [], execute: function () { - exports_1("x", x = (context_1.meta)); - exports_1("y", y = (import.metal)); + exports_1("x", x = context_1.meta); + exports_1("y", y = import.metal); exports_1("z", z = import.import.import.malkovich); } }; @@ -126,8 +126,8 @@ System.register([], function (exports_1, context_1) { return { setters: [], execute: function () { - globalA = (context_1.meta); - globalB = (import.metal); + globalA = context_1.meta; + globalB = import.metal; globalC = import.import.import.malkovich; } }; diff --git a/tests/baselines/reference/importMeta(module=system,target=esnext).js b/tests/baselines/reference/importMeta(module=system,target=esnext).js index b3639b579a8..1510c190b29 100644 --- a/tests/baselines/reference/importMeta(module=system,target=esnext).js +++ b/tests/baselines/reference/importMeta(module=system,target=esnext).js @@ -66,8 +66,8 @@ System.register([], function (exports_1, context_1) { return { setters: [], execute: function () { - exports_1("x", x = (context_1.meta)); - exports_1("y", y = (import.metal)); + exports_1("x", x = context_1.meta); + exports_1("y", y = import.metal); exports_1("z", z = import.import.import.malkovich); } }; @@ -80,8 +80,8 @@ System.register([], function (exports_1, context_1) { return { setters: [], execute: function () { - globalA = (context_1.meta); - globalB = (import.metal); + globalA = context_1.meta; + globalB = import.metal; globalC = import.import.import.malkovich; } }; diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js index 7b29740e7f9..6621386076f 100644 --- a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js +++ b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js @@ -161,6 +161,4 @@ var _brokenTree = renderer_1.dom(component_1.MySFC, { x: 1, y: 2 }, renderer_1.dom(component_1.MyClass, { x: 3, y: 4 }), renderer_1.dom(component_1.MyClass, { x: 5, y: 6 })); // Should fail, nondom isn't allowed as children of dom -var _brokenTree2 = renderer_1.dom(DOMSFC, { x: 1, y: 2 }, - component_1.tree, - component_1.tree); +var _brokenTree2 = renderer_1.dom(DOMSFC, { x: 1, y: 2 }, component_1.tree, component_1.tree); diff --git a/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js index a1a7692ca76..8eb7b03f2b7 100644 --- a/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js +++ b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js @@ -23,5 +23,5 @@ let x = a={10} b="hi" />; // error, no type arguments in js exports.__esModule = true; var component_1 = require("./component"); var React = require("react"); -var x = , a={10} b="hi" />; // error, no type arguments in js -; +var x = (, a={10} b="hi" />; // error, no type arguments in js +); diff --git a/tests/baselines/reference/moduleExportsUnaryExpression.js b/tests/baselines/reference/moduleExportsUnaryExpression.js index b3956233ed4..cb11efbd375 100644 --- a/tests/baselines/reference/moduleExportsUnaryExpression.js +++ b/tests/baselines/reference/moduleExportsUnaryExpression.js @@ -23,17 +23,17 @@ exports.x = exports.foo = void 0; var x = 1; exports.x = x; function foo(y) { - if (y <= (exports.x = x += 1)) - return y <= (exports.x = x += 1); - if (y <= (exports.x = x -= 1)) - return y <= (exports.x = x -= 1); + if (y <= (exports.x = ++x) - 1) + return y <= (exports.x = ++x) - 1; + if (y <= (exports.x = --x) + 1) + return y <= (exports.x = --x) + 1; if (y <= (exports.x = ++x)) return y <= (exports.x = ++x); if (y <= (exports.x = --x)) return y <= (exports.x = --x); - (exports.x = x += 1); - (exports.x = x -= 1); - (exports.x = ++x); - (exports.x = --x); + (exports.x = ++x) - 1; + (exports.x = --x) + 1; + exports.x = ++x; + exports.x = --x; } exports.foo = foo; diff --git a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.js b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.js index 33ae1f6c8f0..e0aecb5f188 100644 --- a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.js +++ b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.js @@ -35,8 +35,7 @@ var y = { "typeof": }; var x = (_a = { - a: a, - : .b, + a: a, : .b, a: a }, _a["ss"] = , diff --git a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorWithModule.js b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorWithModule.js index f48a6c3a4e5..ee46d4741dd 100644 --- a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorWithModule.js +++ b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorWithModule.js @@ -25,8 +25,7 @@ var n; (function (n) { var z = 10000; n.y = { - m: m, - : .x // error + m: m, : .x // error }; })(n || (n = {})); m.y.x; diff --git a/tests/baselines/reference/objectTypesWithOptionalProperties2.js b/tests/baselines/reference/objectTypesWithOptionalProperties2.js index 284ecdea92c..03d2b162847 100644 --- a/tests/baselines/reference/objectTypesWithOptionalProperties2.js +++ b/tests/baselines/reference/objectTypesWithOptionalProperties2.js @@ -42,6 +42,5 @@ var C2 = /** @class */ (function () { return C2; }()); var b = { - x: function () { }, - 1: // error + x: function () { }, 1: // error }; diff --git a/tests/baselines/reference/parserErrorRecovery_ObjectLiteral2.js b/tests/baselines/reference/parserErrorRecovery_ObjectLiteral2.js index 6d723a00d4a..1cdf73ddadc 100644 --- a/tests/baselines/reference/parserErrorRecovery_ObjectLiteral2.js +++ b/tests/baselines/reference/parserErrorRecovery_ObjectLiteral2.js @@ -3,4 +3,5 @@ var v = { a return; //// [parserErrorRecovery_ObjectLiteral2.js] -var v = { a: a, "return": }; +var v = { a: a, + "return": };