diff --git a/src/compat/factory.ts b/src/compat/deprecations.ts similarity index 95% rename from src/compat/factory.ts rename to src/compat/deprecations.ts index e8984bade03..16cf1fe41e6 100644 --- a/src/compat/factory.ts +++ b/src/compat/deprecations.ts @@ -1,5 +1,20 @@ namespace ts { - // #region Node Factory compat (deprecated since 3.8) + // The following are deprecations for the public API. Deprecated exports are removed from the compiler itself + // and compatible implementations are added here, along with an appropriate deprecation warning using + // the `@deprecated` JSDoc tag as well as the `Debug.deprecateExport` API. + // + // Deprecations fall into one of three categories: + // + // * "soft" - Soft deprecations are indicated with the `@deprecated` JSDoc Tag. + // * "warn" - Warning deprecations are indicated with the `@deprecated` JSDoc Tag and a diagnostic message (assuming a compatible host) + // * "error" - Error deprecations are indicated with the `@deprecated` JSDoc tag and will throw a `TypeError` when invoked. + + // DEPRECATION: Node factory top-level exports + // DEPRECATION PLAN: + // - soft: 3.8 + // - warn: 3.9 + // - error: TBD + // #region Node factory top-level exports // #region export const { ... } = factory; // NOTE: These exports are deprecated in favor of using a `NodeFactory` instance and exist here purely for backwards compatibility reasons. @@ -1380,7 +1395,7 @@ namespace ts { initializer?: Expression ): PropertySignature { const node = factory.createPropertySignature(modifiers, name, questionToken, type); - node.initializer = initializer; + factory.trackExtraneousChildNode(node, node.initializer = initializer); return node; } @@ -1395,13 +1410,14 @@ namespace ts { type: TypeNode | undefined, initializer: Expression | undefined ) { - return node.modifiers !== modifiers - || node.name !== name - || node.questionToken !== questionToken - || node.type !== type - || node.initializer !== initializer - ? updateNode(createPropertySignature(modifiers, name, questionToken, type, initializer), node) - : node; + let updated = factory.updatePropertySignature(node, modifiers, name, questionToken, type); + if (node.initializer !== initializer) { + if (updated === node) { + updated = factory.cloneNode(node); + } + factory.trackExtraneousChildNode(updated, updated.initializer = initializer); + } + return updated; } /** @@ -1905,9 +1921,38 @@ namespace ts { warnAfter: "3.9" }); - // #endregion NodeFactory compat (deprecated in 3.8) + Debug.deprecateExport(ts, "createNode", { + message: "Use an appropriate `factory` method instead.", + since: "3.8", + warnAfter: "3.9" + }); - // #region Node Test compat (deprecated since 3.8) + /** + * Creates a shallow, memberwise clone of a node for mutation. + * @deprecated Use `factory.cloneNode` instead and set `pos`, `end`, and `parent` as needed. + */ + export function getMutableClone(node: T): T { + const clone = factory.cloneNode(node); + clone.pos = node.pos; + clone.end = node.end; + clone.parent = node.parent; + return clone; + } + + Debug.deprecateExport(ts, "getMutableClone", { + message: "Use `factory.cloneNode` instead and set `pos`, `end`, and `parent` as needed.", + since: "3.8", + warnAfter: "3.9" + }); + + // #endregion Node Factory top-level exports + + // DEPRECATION: Renamed node tests + // DEPRECATION PLAN: + // - soft: 3.8 + // - warn: 3.9 + // - error: TBD + // #region Renamed node Tests /** * @deprecated Use `isTypeAssertionExpression` instead. */ @@ -1921,5 +1966,5 @@ namespace ts { warnAfter: "3.9" }); - // #endregion NodeTest compat (deprecated since 3.8) + // #endregion Renamed node Tests } \ No newline at end of file diff --git a/src/compat/tsconfig.json b/src/compat/tsconfig.json index 6a4a20f900f..c9559ebc865 100644 --- a/src/compat/tsconfig.json +++ b/src/compat/tsconfig.json @@ -7,6 +7,6 @@ { "path": "../compiler" } ], "files": [ - "factory.ts" + "deprecations.ts" ] } \ No newline at end of file diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5723a32351c..4bb181f506e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4450,12 +4450,12 @@ namespace ts { } const parameterTypeNode = typeToTypeNodeHelper(parameterType, context); - const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && parameterDeclaration.modifiers ? parameterDeclaration.modifiers.map(getSynthesizedClone) : undefined; + const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && parameterDeclaration.modifiers ? parameterDeclaration.modifiers.map(factory.cloneNode) : undefined; const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; const dotDotDotToken = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined; const name = parameterDeclaration ? parameterDeclaration.name ? - parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(getSynthesizedClone(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : - parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(getSynthesizedClone(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) : + parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : + parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) : cloneBindingName(parameterDeclaration.name) : symbolName(parameterSymbol) : symbolName(parameterSymbol); @@ -4479,7 +4479,7 @@ namespace ts { trackComputedName(node.expression, context.enclosingDeclaration, context); } const visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags)!; - const clone = nodeIsSynthesized(visited) ? visited : getSynthesizedClone(visited); + const clone = nodeIsSynthesized(visited) ? visited : factory.cloneNode(visited); if (clone.kind === SyntaxKind.BindingElement) { (clone).initializer = undefined; } @@ -5935,7 +5935,7 @@ namespace ts { // try to reuse the existing annotation const existing = getEffectiveTypeAnnotationNode(declWithExistingAnnotation)!; const transformed = visitNode(existing, visitExistingNodeTreeSymbols); - return transformed === existing ? getMutableClone(existing) : transformed; + return transformed === existing ? setTextRange(factory.cloneNode(existing), existing) : transformed; } const oldFlags = context.flags; if (type.flags & TypeFlags.UniqueESSymbol && @@ -6689,13 +6689,10 @@ namespace ts { if (parentAccess && parentAccess.flowNode) { const propName = getDestructuringPropertyName(node); if (propName) { - const result = createNode(SyntaxKind.ElementAccessExpression, node.pos, node.end); - result.parent = node; - result.expression = parentAccess; - const literal = createNode(SyntaxKind.StringLiteral, node.pos, node.end); + const literal = setTextRange(parseNodeFactory.createStringLiteral(propName), node); + const result = setTextRange(parseNodeFactory.createElementAccess(parentAccess, literal), node); literal.parent = result; - literal.text = propName; - result.argumentExpression = literal; + result.parent = node; result.flowNode = parentAccess.flowNode; return result; } @@ -20231,7 +20228,8 @@ namespace ts { if (returnType && returnType.flags & TypeFlags.Union) { const unionTypes = (funcTypeNode.type).types; if (unionTypes && unionTypes[unionTypes.length - 1].kind === SyntaxKind.UndefinedKeyword) { - const parenedFuncType = getMutableClone(funcTypeNode); + // TODO(rbuckton): Does this need to be parented? + const parenedFuncType = setParent(setTextRange(factory.cloneNode(funcTypeNode), funcTypeNode), funcTypeNode.parent); // Highlight to the end of the second to last constituent of the union parenedFuncType.end = unionTypes[unionTypes.length - 2].end; addRelatedInfo(diag, createDiagnosticForNode(parenedFuncType, Diagnostics.Did_you_mean_to_parenthesize_this_function_type)); @@ -23901,10 +23899,9 @@ namespace ts { } function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean) { - const result = createNode(SyntaxKind.SyntheticExpression, parent.pos, parent.end); + const result = parseNodeFactory.createSyntheticExpression(type, isSpread); + setTextRange(result, parent); result.parent = parent; - result.type = type; - result.isSpread = isSpread || false; return result; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 7bdac0a2021..ce7a7c9488d 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -674,30 +674,34 @@ namespace ts { } function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo, buildInfoDirectory: string, host: EmitUsingBuildInfoHost): readonly SourceFile[] { - const sourceFiles = bundle.sourceFiles.map(fileName => { - const sourceFile = createNode(SyntaxKind.SourceFile, 0, 0) as SourceFile; + const jsBundle = Debug.assertDefined(bundle.js); + const prologueMap = jsBundle.sources?.prologues && arrayToMap(jsBundle.sources.prologues, prologueInfo => "" + prologueInfo.file); + return bundle.sourceFiles.map((fileName, index) => { + const prologueInfo = prologueMap?.get("" + index); + const statements = prologueInfo?.directives.map(directive => { + const literal = setTextRange(factory.createStringLiteral(directive.expression.text), directive.expression); + const statement = setTextRange(factory.createExpressionStatement(literal), directive); + literal.parent = statement; + return statement; + }); + const eofToken = factory.createToken(SyntaxKind.EndOfFileToken); + const sourceFile = factory.createSourceFile(statements ?? [], eofToken); sourceFile.fileName = getRelativePathFromDirectory( host.getCurrentDirectory(), getNormalizedAbsolutePath(fileName, buildInfoDirectory), !host.useCaseSensitiveFileNames() ); - sourceFile.text = ""; - sourceFile.statements = factory.createNodeArray(); + sourceFile.text = prologueInfo?.text ?? ""; + sourceFile.pos = 0; + sourceFile.end = prologueInfo?.text.length ?? 0; + for (const statement of sourceFile.statements) { + statement.parent = sourceFile; + } + eofToken.pos = sourceFile.end; + eofToken.end = sourceFile.end; + eofToken.parent = sourceFile; return sourceFile; }); - const jsBundle = Debug.assertDefined(bundle.js); - forEach(jsBundle.sources && jsBundle.sources.prologues, prologueInfo => { - const sourceFile = sourceFiles[prologueInfo.file]; - sourceFile.text = prologueInfo.text; - sourceFile.end = prologueInfo.text.length; - sourceFile.statements = factory.createNodeArray(prologueInfo.directives.map(directive => { - const statement = createNode(SyntaxKind.ExpressionStatement, directive.pos, directive.end) as PrologueDirective; - statement.expression = createNode(SyntaxKind.StringLiteral, directive.expression.pos, directive.expression.end) as StringLiteral; - statement.expression.text = directive.expression.text; - return statement; - })); - }); - return sourceFiles; } /*@internal*/ diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index e03006c2767..39dee3a7cea 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -24,6 +24,7 @@ namespace ts { * - This is raised *after* the child has been attached to the parent. * - This is raised *before* the transform flags of the child have been aggregated into the parent. * - The `parent` pointer for the child will likely be `undefined`. + * - NOTE: This may be raised *after* `onFinishNode` if the child is an *extraneous child* attached to a node purely for the purposes of reporting diagnostics. */ onSetChild?(parent: Node, child: Node): void; /** @@ -32,8 +33,9 @@ namespace ts { * - This is raised *after* the array of children has been attached to the parent. * - This is raised *before* the transform flags of the child have been aggregated into the parent. * - The `parent` pointer for each child in the array will likely be `undefined`. + * - NOTE: This may be raised *after* `onFinishNode` if the child is an *extraneous child* attached to a node purely for the purposes of reporting diagnostics. */ - onSetChildren?(parent: Node, children: NodeArray): void; + onSetChildren?(parent: Node, children: readonly Node[]): void; /** * Observes when a `Node` is "finished" (i.e. its child nodes have been attached). * - This is raised *after* transform flags for the node have been aggregated. @@ -76,10 +78,11 @@ namespace ts { const createSourceFileNode = observeResult(baseFactory.createBaseSourceFileNode, treeStateObserver && treeStateObserver.onCreateNode); const setChild = observeArguments(setChildWorker, treeStateObserver && treeStateObserver.onSetChild); const setChildren = observeArguments(setChildrenWorker, treeStateObserver && treeStateObserver.onSetChildren); + const setChildrenArray = observeArguments(setChildrenArrayWorker, treeStateObserver && treeStateObserver.onSetChildren); const finish = observeResult(finishWorker, treeStateObserver && treeStateObserver.onFinishNode); const finishJSDoc = observeResult(identity, treeStateObserver && treeStateObserver.onFinishNode); - const update = observeArguments(updateWorker, treeStateObserver && treeStateObserver.onUpdateNode); - const reuse = observeResult(reuseWorker, treeStateObserver && treeStateObserver.onReuseNode); + const update = observeArguments(updateNodeWorker, treeStateObserver && treeStateObserver.onUpdateNode); + const reuse = observeResult(identity, treeStateObserver && treeStateObserver.onReuseNode); const factory: NodeFactory = { get parenthesizer() { return parenthesizerRules(); }, @@ -421,6 +424,14 @@ namespace ts { updateSourceFile, createBundle, updateBundle, + createUnparsedSource, + createUnparsedPrologue, + createUnparsedPrepend, + createUnparsedTextLike, + createUnparsedSyntheticReference, + createInputFiles, + createSyntheticExpression, + createSyntaxList, createNotEmittedStatement, createPartiallyEmittedExpression, updatePartiallyEmittedExpression, @@ -430,6 +441,7 @@ namespace ts { createMergeDeclarationMarker, createSyntheticReferenceExpression, updateSyntheticReferenceExpression, + cloneNode, // Lazily load factory methods for common operator factories and utilities get createSignatureDeclaration() { return lazyFactory().createSignatureDeclaration; }, @@ -1209,7 +1221,7 @@ namespace ts { markTypeScriptClassSyntax(node); } markClassFields(node); - if (questionOrExclamationToken) { + if (questionOrExclamationToken || hasModifier(node, ModifierFlags.Ambient)) { markTypeScript(node); } } @@ -4523,6 +4535,94 @@ namespace ts { : reuse(node); } + // @api + function createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]) { + const node = createBaseNode(SyntaxKind.UnparsedSource); + setChildrenArray(node, node.prologues = prologues); + setChildrenArray(node, node.syntheticReferences = syntheticReferences); + setChildrenArray(node, node.texts = texts); + node.fileName = ""; + node.text = ""; + node.helpers = undefined; + node.referencedFiles = emptyArray; + node.typeReferenceDirectives = undefined; + node.libReferenceDirectives = emptyArray; + node.hasNoDefaultLib = undefined; + node.sourceMapPath = undefined; + node.sourceMapText = undefined; + node.oldFileOfCurrentEmit = undefined; + node.parsedSourceMap = undefined; + node.getLineAndCharacterOfPosition = pos => getLineAndCharacterOfPosition(node, pos); + return node; + } + + function createBaseUnparsedNode(kind: T["kind"], data?: string): T { + const node = createBaseNode(kind); + node.data = data; + return node; + } + + // @api + function createUnparsedPrologue(data?: string): UnparsedPrologue { + return createBaseUnparsedNode(SyntaxKind.UnparsedPrologue, data); + } + + // @api + function createUnparsedPrepend(data: string | undefined, texts: readonly UnparsedTextLike[]): UnparsedPrepend { + const node = createBaseUnparsedNode(SyntaxKind.UnparsedPrepend, data); + setChildrenArray(node, node.texts = texts); + return node; + } + + // @api + function createUnparsedTextLike(data: string | undefined, internal: boolean): UnparsedTextLike { + return createBaseUnparsedNode(internal ? SyntaxKind.UnparsedInternalText : SyntaxKind.UnparsedText, data); + } + + // @api + function createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference): UnparsedSyntheticReference { + const node = createBaseNode(SyntaxKind.UnparsedSyntheticReference); + node.data = section.data; + node.section = section; + return node; + } + + // @api + function createInputFiles(): InputFiles { + const node = createBaseNode(SyntaxKind.InputFiles); + node.javascriptPath = undefined; + node.javascriptText = ""; + node.javascriptMapPath = undefined; + node.javascriptMapText = undefined; + node.declarationPath = undefined; + node.declarationText = ""; + node.declarationMapPath = undefined; + node.declarationMapText = undefined; + node.buildInfoPath = undefined; + node.buildInfo = undefined; + node.oldFileOfCurrentEmit = undefined; + return node; + } + + // + // Synthetic Nodes (used by checker) + // + + // @api + function createSyntheticExpression(type: Type, isSpread = false) { + const node = createBaseNode(SyntaxKind.SyntheticExpression); + node.type = type; + node.isSpread = isSpread; + return node; + } + + // @api + function createSyntaxList(children: Node[]) { + const node = createBaseNode(SyntaxKind.SyntaxList); + node._children = children; + return node; + } + // // Transformation nodes // @@ -4629,10 +4729,39 @@ namespace ts { function updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression) { return node.expression !== expression || node.thisArg !== thisArg - ? updateNode(createSyntheticReferenceExpression(expression, thisArg), node) + ? update(createSyntheticReferenceExpression(expression, thisArg), node) : node; } + // @api + function cloneNode(node: T): T; + function cloneNode(node: T) { + // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of + // the original node. We also need to exclude specific properties and only include own- + // properties (to skip members already defined on the shared prototype). + if (node === undefined) { + return node; + } + + const clone = node.kind === SyntaxKind.SourceFile ? createSourceFileNode(node.kind) as T: + node.kind === SyntaxKind.Identifier ? createIdentifierNode(node.kind) as T: + !isNodeKind(node.kind) ? createTokenNode(node.kind) as T: + createBaseNode(node.kind) as T; + + clone.flags |= node.flags; + setOriginalNode(clone, node); + + for (const key in node) { + if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { + continue; + } + + clone[key] = node[key]; + } + + return clone; + } + function asNodeArray(array: readonly T[]): NodeArray; function asNodeArray(array: readonly T[] | undefined): NodeArray | undefined; function asNodeArray(array: readonly T[] | undefined): NodeArray | undefined { @@ -4662,18 +4791,14 @@ namespace ts { } function setChildWorker(parent: Node, child: Node | undefined): void { - if (!skipTransformationFlags) { - if (child) { - parent.transformFlags |= propagateChildFlags(child); - } + if (!skipTransformationFlags && child) { + parent.transformFlags |= propagateChildFlags(child); } } function setChildrenWorker(parent: Node, children: NodeArray | undefined): void { - if (!skipTransformationFlags) { - if (children) { - parent.transformFlags |= propagateChildrenFlags(children); - } + if (!skipTransformationFlags && children) { + parent.transformFlags |= propagateChildrenFlags(children); } } @@ -4683,14 +4808,18 @@ namespace ts { } return node; } + } - function updateWorker(updated: T, original: T) { - return updateNode(updated, original); - } + function setChildrenArrayWorker(_parent: Node, _children: readonly Node[] | undefined): void { + // does nothing + } - function reuseWorker(node: T) { - return node; + function updateNodeWorker(updated: T, original: T): T { + if (updated !== original) { + setOriginalNode(updated, original); + setTextRange(updated, original); } + return updated; } function createLazyFactoryMembers( @@ -5117,7 +5246,8 @@ namespace ts { function getName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) { const nodeName = getNameOfDeclaration(node); if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) { - const name = getMutableClone(nodeName); + // TODO(rbuckton): Does this need to be parented? + const name = setParent(setTextRange(factory.cloneNode(nodeName), nodeName), nodeName.parent); emitFlags |= getEmitFlags(nodeName); if (!allowSourceMaps) emitFlags |= EmitFlags.NoSourceMap; if (!allowComments) emitFlags |= EmitFlags.NoComments; @@ -5190,7 +5320,7 @@ namespace ts { * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ function getNamespaceMemberName(ns: Identifier, name: Identifier, allowComments?: boolean, allowSourceMaps?: boolean): PropertyAccessExpression { - const qualifiedName = factory.createPropertyAccess(ns, nodeIsSynthesized(name) ? name : getSynthesizedClone(name)); + const qualifiedName = factory.createPropertyAccess(ns, nodeIsSynthesized(name) ? name : factory.cloneNode(name)); setTextRange(qualifiedName, name); let emitFlags: EmitFlags = 0; if (!allowSourceMaps) emitFlags |= EmitFlags.NoSourceMap; @@ -5516,152 +5646,106 @@ namespace ts { } } - export const factory = createNodeFactory(NodeFactoryFlags.NoIndentationOnFreshPropertyAccess, createBaseNodeFactory(), { + const baseFactory = createBaseNodeFactory(); + + export const factory = createNodeFactory(NodeFactoryFlags.NoIndentationOnFreshPropertyAccess, baseFactory, { onCreateNode: node => node.flags |= NodeFlags.Synthesized }); - /* @internal */ - export function createSynthesizedNode(kind: SyntaxKind): Node { - const node = createNode(kind, -1, -1); - node.flags |= NodeFlags.Synthesized; - return node; - } - - /** - * Creates a shallow, memberwise clone of a node with no source map location. - */ - /* @internal */ - export function getSynthesizedClone(node: T): T { - // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of - // the original node. We also need to exclude specific properties and only include own- - // properties (to skip members already defined on the shared prototype). - - if (node === undefined) { - return node; - } - - const clone = createSynthesizedNode(node.kind); - clone.flags |= node.flags; - setOriginalNode(clone, node); - - for (const key in node) { - if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { - continue; - } - - (clone)[key] = (node)[key]; - } - - return clone; - } - - /** - * Creates a shallow, memberwise clone of a node for mutation. - */ - export function getMutableClone(node: T): T { - const clone = getSynthesizedClone(node); - clone.pos = node.pos; - clone.end = node.end; - clone.parent = node.parent; - return clone; - } - - /* @internal */ - export function updateNode(updated: T, original: T): T { - if (updated !== original) { - setOriginalNode(updated, original); - setTextRange(updated, original); - } - return updated; - } - - // TODO(rbuckton): Move this to factory - function createUnparsedSource() { - const node = createNode(SyntaxKind.UnparsedSource); - node.prologues = emptyArray; - node.referencedFiles = emptyArray; - node.libReferenceDirectives = emptyArray; - node.getLineAndCharacterOfPosition = pos => getLineAndCharacterOfPosition(node, pos); - return node; - } - export function createUnparsedSourceFile(text: string): UnparsedSource; export function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts", stripInternal?: boolean): UnparsedSource; export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource; export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, mapPathOrType?: string, mapTextOrStripInternal?: string | boolean): UnparsedSource { - const node = createUnparsedSource(); let stripInternal: boolean | undefined; let bundleFileInfo: BundleFileInfo | undefined; + let fileName: string; + let text: string | undefined; + let length: number | (() => number); + let sourceMapPath: string | undefined; + let sourceMapText: string | undefined; + let getText: (() => string) | undefined; + let getSourceMapText: (() => string | undefined) | undefined; + let oldFileOfCurrentEmit: boolean | undefined; + if (!isString(textOrInputFiles)) { Debug.assert(mapPathOrType === "js" || mapPathOrType === "dts"); - node.fileName = (mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath) || ""; - node.sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath : textOrInputFiles.declarationMapPath; - Object.defineProperties(node, { - text: { get() { return mapPathOrType === "js" ? textOrInputFiles.javascriptText : textOrInputFiles.declarationText; } }, - sourceMapText: { get() { return mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; } }, - }); - - + fileName = (mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath) || ""; + sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath : textOrInputFiles.declarationMapPath; + getText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptText : textOrInputFiles.declarationText; + getSourceMapText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; + length = () => getText!().length; if (textOrInputFiles.buildInfo && textOrInputFiles.buildInfo.bundle) { - node.oldFileOfCurrentEmit = textOrInputFiles.oldFileOfCurrentEmit; Debug.assert(mapTextOrStripInternal === undefined || typeof mapTextOrStripInternal === "boolean"); stripInternal = mapTextOrStripInternal as boolean | undefined; bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js : textOrInputFiles.buildInfo.bundle.dts; - if (node.oldFileOfCurrentEmit) { - parseOldFileOfCurrentEmit(node, Debug.assertDefined(bundleFileInfo)); - return node; - } + oldFileOfCurrentEmit = textOrInputFiles.oldFileOfCurrentEmit; } } else { - node.fileName = ""; - node.text = textOrInputFiles; - node.sourceMapPath = mapPathOrType; - node.sourceMapText = mapTextOrStripInternal as string; + fileName = ""; + text = textOrInputFiles; + length = textOrInputFiles.length; + sourceMapPath = mapPathOrType; + sourceMapText = mapTextOrStripInternal as string; } - Debug.assert(!node.oldFileOfCurrentEmit); - parseUnparsedSourceFile(node, bundleFileInfo, stripInternal); + const node = oldFileOfCurrentEmit ? + parseOldFileOfCurrentEmit(Debug.assertDefined(bundleFileInfo)) : + parseUnparsedSourceFile(bundleFileInfo, stripInternal, length); + node.fileName = fileName; + node.sourceMapPath = sourceMapPath; + node.oldFileOfCurrentEmit = oldFileOfCurrentEmit; + if (getText && getSourceMapText) { + Object.defineProperty(node, "text", { get: getText }); + Object.defineProperty(node, "sourceMapText", { get: getSourceMapText }); + } + else { + Debug.assert(!oldFileOfCurrentEmit); + node.text = text ?? ""; + node.sourceMapText = sourceMapText; + } + return node; } - function parseUnparsedSourceFile(node: UnparsedSource, bundleFileInfo: BundleFileInfo | undefined, stripInternal: boolean | undefined) { + function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, stripInternal: boolean | undefined, length: number | (() => number)) { let prologues: UnparsedPrologue[] | undefined; let helpers: UnscopedEmitHelper[] | undefined; let referencedFiles: FileReference[] | undefined; let typeReferenceDirectives: string[] | undefined; let libReferenceDirectives: FileReference[] | undefined; + let prependChildren: UnparsedTextLike[] | undefined; let texts: UnparsedSourceText[] | undefined; + let hasNoDefaultLib: boolean | undefined; for (const section of bundleFileInfo ? bundleFileInfo.sections : emptyArray) { switch (section.kind) { case BundleFileSectionKind.Prologue: - (prologues || (prologues = [])).push(createUnparsedNode(section, node) as UnparsedPrologue); + prologues = append(prologues, setTextRange(factory.createUnparsedPrologue(section.data), section)); break; case BundleFileSectionKind.EmitHelpers: - (helpers || (helpers = [])).push(getAllUnscopedEmitHelpers().get(section.data)!); + helpers = append(helpers, getAllUnscopedEmitHelpers().get(section.data)!); break; case BundleFileSectionKind.NoDefaultLib: - node.hasNoDefaultLib = true; + hasNoDefaultLib = true; break; case BundleFileSectionKind.Reference: - (referencedFiles || (referencedFiles = [])).push({ pos: -1, end: -1, fileName: section.data }); + referencedFiles = append(referencedFiles, { pos: -1, end: -1, fileName: section.data }); break; case BundleFileSectionKind.Type: - (typeReferenceDirectives || (typeReferenceDirectives = [])).push(section.data); + typeReferenceDirectives = append(typeReferenceDirectives, section.data); break; case BundleFileSectionKind.Lib: - (libReferenceDirectives || (libReferenceDirectives = [])).push({ pos: -1, end: -1, fileName: section.data }); + libReferenceDirectives = append(libReferenceDirectives, { pos: -1, end: -1, fileName: section.data }); break; case BundleFileSectionKind.Prepend: - const prependNode = createUnparsedNode(section, node) as UnparsedPrepend; let prependTexts: UnparsedTextLike[] | undefined; for (const text of section.texts) { if (!stripInternal || text.kind !== BundleFileSectionKind.Internal) { - (prependTexts || (prependTexts = [])).push(createUnparsedNode(text, node) as UnparsedTextLike); + prependTexts = append(prependTexts, setTextRange(factory.createUnparsedTextLike(text.data, text.kind === BundleFileSectionKind.Internal), text)); } } - prependNode.texts = prependTexts || emptyArray; - (texts || (texts = [])).push(prependNode); + prependChildren = addRange(prependChildren, prependTexts); + texts = append(texts, factory.createUnparsedPrepend(section.data, prependTexts ?? emptyArray)); break; case BundleFileSectionKind.Internal: if (stripInternal) { @@ -5671,37 +5755,47 @@ namespace ts { // falls through case BundleFileSectionKind.Text: - (texts || (texts = [])).push(createUnparsedNode(section, node) as UnparsedTextLike); + texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section)); break; default: Debug.assertNever(section); } } - node.prologues = prologues || emptyArray; + if (!texts) { + const textNode = factory.createUnparsedTextLike(/*data*/ undefined, /*internal*/ false); + textNode.pos = 0; + textNode.end = typeof length === "function" ? length() : length; + texts = [textNode]; + } + + const node = parseNodeFactory.createUnparsedSource(prologues ?? emptyArray, /*syntheticReferences*/ undefined, texts); + setEachParent(prologues, node); + setEachParent(texts, node); + setEachParent(prependChildren, node); + node.hasNoDefaultLib = hasNoDefaultLib; node.helpers = helpers; node.referencedFiles = referencedFiles || emptyArray; node.typeReferenceDirectives = typeReferenceDirectives; node.libReferenceDirectives = libReferenceDirectives || emptyArray; - node.texts = texts || [createUnparsedNode({ kind: BundleFileSectionKind.Text, pos: 0, end: node.text.length }, node)]; + return node; } - function parseOldFileOfCurrentEmit(node: UnparsedSource, bundleFileInfo: BundleFileInfo) { - Debug.assert(!!node.oldFileOfCurrentEmit); + function parseOldFileOfCurrentEmit(bundleFileInfo: BundleFileInfo) { let texts: UnparsedTextLike[] | undefined; let syntheticReferences: UnparsedSyntheticReference[] | undefined; for (const section of bundleFileInfo.sections) { switch (section.kind) { case BundleFileSectionKind.Internal: case BundleFileSectionKind.Text: - (texts || (texts = [])).push(createUnparsedNode(section, node) as UnparsedTextLike); + texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section)); break; case BundleFileSectionKind.NoDefaultLib: case BundleFileSectionKind.Reference: case BundleFileSectionKind.Type: case BundleFileSectionKind.Lib: - (syntheticReferences || (syntheticReferences = [])).push(createUnparsedSyntheticReference(section, node)); + syntheticReferences = append(syntheticReferences, setTextRange(factory.createUnparsedSyntheticReference(section), section)); break; // Ignore @@ -5714,45 +5808,11 @@ namespace ts { Debug.assertNever(section); } } - node.texts = texts || emptyArray; + + const node = factory.createUnparsedSource(emptyArray, syntheticReferences, texts ?? emptyArray); + setEachParent(syntheticReferences, node); + setEachParent(texts, node); node.helpers = map(bundleFileInfo.sources && bundleFileInfo.sources.helpers, name => getAllUnscopedEmitHelpers().get(name)!); - node.syntheticReferences = syntheticReferences; - return node; - } - - function mapBundleFileSectionKindToSyntaxKind(kind: BundleFileSectionKind): SyntaxKind { - switch (kind) { - case BundleFileSectionKind.Prologue: return SyntaxKind.UnparsedPrologue; - case BundleFileSectionKind.Prepend: return SyntaxKind.UnparsedPrepend; - case BundleFileSectionKind.Internal: return SyntaxKind.UnparsedInternalText; - case BundleFileSectionKind.Text: return SyntaxKind.UnparsedText; - - case BundleFileSectionKind.EmitHelpers: - case BundleFileSectionKind.NoDefaultLib: - case BundleFileSectionKind.Reference: - case BundleFileSectionKind.Type: - case BundleFileSectionKind.Lib: - return Debug.fail(`BundleFileSectionKind: ${kind} not yet mapped to SyntaxKind`); - - default: - return Debug.assertNever(kind); - } - } - - // TODO(rbuckton): Move this to factory - function createUnparsedNode(section: BundleFileSection, parent: UnparsedSource): UnparsedNode { - const node = createNode(mapBundleFileSectionKindToSyntaxKind(section.kind), section.pos, section.end) as UnparsedNode; - node.parent = parent; - node.data = section.data; - return node; - } - - // TODO(rbuckton): Move this to factory - function createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference, parent: UnparsedSource) { - const node = createNode(SyntaxKind.UnparsedSyntheticReference, section.pos, section.end) as UnparsedSyntheticReference; - node.parent = parent; - node.data = section.data; - node.section = section; return node; } @@ -5804,7 +5864,7 @@ namespace ts { buildInfo?: BuildInfo, oldFileOfCurrentEmit?: boolean ): InputFiles { - const node = createNode(SyntaxKind.InputFiles); + const node = parseNodeFactory.createInputFiles(); if (!isString(javascriptTextOrReadFileText)) { const cache = createMap(); const textGetter = (path: string | undefined) => { diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 98c6d395c7a..154ed896d5c 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -156,11 +156,13 @@ namespace ts { export function createExpressionFromEntityName(factory: NodeFactory, node: EntityName | Expression): Expression { if (isQualifiedName(node)) { const left = createExpressionFromEntityName(factory, node.left); - const right = getMutableClone(node.right); + // TODO(rbuckton): Does this need to be parented? + const right = setParent(setTextRange(factory.cloneNode(node.right), node.right), node.right.parent); return setTextRange(factory.createPropertyAccess(left, right), node); } else { - return getMutableClone(node); + // TODO(rbuckton): Does this need to be parented? + return setParent(setTextRange(factory.cloneNode(node), node), node.parent); } } @@ -169,10 +171,12 @@ namespace ts { return factory.createStringLiteralFromNode(memberName); } else if (isComputedPropertyName(memberName)) { - return getMutableClone(memberName.expression); + // TODO(rbuckton): Does this need to be parented? + return setParent(setTextRange(factory.cloneNode(memberName.expression), memberName.expression), memberName.expression.parent); } else { - return getMutableClone(memberName); + // TODO(rbuckton): Does this need to be parented? + return setParent(setTextRange(factory.cloneNode(memberName), memberName), memberName.parent); } } @@ -243,7 +247,7 @@ namespace ts { setTextRange( factory.createAssignment( createMemberAccessForPropertyName(factory, receiver, property.name, /*location*/ property.name), - getSynthesizedClone(property.name) + factory.cloneNode(property.name) ), /*location*/ property ), @@ -525,7 +529,7 @@ namespace ts { if (moduleName.kind === SyntaxKind.StringLiteral) { return tryGetModuleNameFromDeclaration(importNode, host, factory, resolver, compilerOptions) || tryRenameExternalModule(factory, moduleName, sourceFile) - || getSynthesizedClone(moduleName); + || factory.cloneNode(moduleName); } return undefined; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2c1948d3e2b..136dd8c0773 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -13,28 +13,27 @@ namespace ts { let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; - export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { - if (kind === SyntaxKind.SourceFile) { - return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end); - } - else if (kind === SyntaxKind.Identifier) { - return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, pos, end); - } - else if (!isNodeKind(kind)) { - return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, pos, end); - } - else { - return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end); - } - } + const parseBaseNodeFactory: BaseNodeFactory = { + createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1), + createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1), + createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), + createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), + }; /* @internal */ - export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.None, { - createBaseSourceFileNode: createNode, - createBaseIdentifierNode: createNode, - createBaseTokenNode: createNode, - createBaseNode: createNode - }); + export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory); + + /** @deprecated Use an appropriate `factory` method instead. */ + export function createNode(kind: SyntaxKind, pos = 0, end = 0): Node { + return setTextRangePosEnd( + kind === SyntaxKind.SourceFile ? parseBaseNodeFactory.createBaseSourceFileNode(kind) : + kind === SyntaxKind.Identifier ? parseBaseNodeFactory.createBaseIdentifierNode(kind) : + !isNodeKind(kind) ? parseBaseNodeFactory.createBaseTokenNode(kind) : + parseBaseNodeFactory.createBaseNode(kind), + pos, + end + ); + } function visitNode(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { return node && cbNode(node); @@ -618,19 +617,25 @@ namespace ts { createBaseNode: kind => new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0) }; - const factoryWithParentPointers = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters, baseNodeFactory, { + const factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters, baseNodeFactory, { onSetChild(parent, child) { - child.parent = parent; - }, - onSetChildren(parent, children) { - for (const child of children) { + if (setParentNodes) { child.parent = parent; } }, + onSetChildren(parent, children) { + if (setParentNodes) { + for (const child of children) { + child.parent = parent; + } + } + }, onFinishNode(node) { - if (hasJSDocNodes(node)) { - for (const jsDoc of node.jsDoc!) { - jsDoc.parent = node; + if (setParentNodes) { + if (hasJSDocNodes(node)) { + for (const jsDoc of node.jsDoc!) { + jsDoc.parent = node; + } } } }, @@ -639,13 +644,6 @@ namespace ts { } }); - const factoryWithoutParentPointers = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters, baseNodeFactory, { - onCreateNode(_) { - nodeCount++; - } - }); - - let factory = factoryWithoutParentPointers; let sourceFlags: NodeFlags; let sourceText: string; let languageVersion: ScriptTarget; @@ -659,6 +657,7 @@ namespace ts { let nodeCount: number; let identifiers: Map; let identifierCount: number; + let setParentNodes: boolean; let parsingContext: ParsingContext; @@ -818,7 +817,6 @@ namespace ts { break; } - // TODO(rbuckton): this does not create the tree correctly and transform flags won't be properly set const statement = factory.createExpressionStatement(expression) as JsonObjectExpressionStatement; finishNode(statement, pos); statements = createNodeArray([statement], pos); @@ -846,13 +844,13 @@ namespace ts { return result; } - function initializeState(_sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind, setParentNodes: boolean) { + function initializeState(_sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind, _setParentNodes: boolean) { NodeConstructor = objectAllocator.getNodeConstructor(); TokenConstructor = objectAllocator.getTokenConstructor(); IdentifierConstructor = objectAllocator.getIdentifierConstructor(); SourceFileConstructor = objectAllocator.getSourceFileConstructor(); - factory = setParentNodes ? factoryWithParentPointers : factoryWithoutParentPointers; + setParentNodes = _setParentNodes; sourceText = _sourceText; languageVersion = _languageVersion; @@ -894,7 +892,7 @@ namespace ts { scanner.setOnError(undefined); // Clear any data. We don't want to accidentally hold onto it for too long. - factory = factoryWithoutParentPointers; + setParentNodes = false; sourceText = undefined!; languageVersion = undefined!; syntaxCursor = undefined; @@ -2537,7 +2535,8 @@ namespace ts { const hasJSDoc = hasPrecedingJSDocComment(); if (lookAhead(nextTokenIsOpenParen)) { nextToken(); - const { parameters, type } = parseSignature(SyntaxKind.ColonToken, SignatureFlags.Type | SignatureFlags.JSDoc); + const parameters = parseParameters(SignatureFlags.Type | SignatureFlags.JSDoc); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); return withJSDoc(finishNode(factory.createJSDocFunctionType(parameters, type), pos), hasJSDoc); } return finishNode(factory.createTypeReferenceNode(parseIdentifierName(), /*typeArguments*/ undefined), pos); @@ -2705,44 +2704,10 @@ namespace ts { ); } - interface SignatureInfo { - typeParameters?: NodeArray; - parameters: NodeArray; - parametersParsedSuccessfully?: boolean; - type?: TypeNode; - } - - function parseSignature( - returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, - flags: SignatureFlags - ) { - const signature: SignatureInfo = { - typeParameters: undefined, - parameters: undefined!, - parametersParsedSuccessfully: undefined, - type: undefined - }; - signature.parametersParsedSuccessfully = fillSignature(returnToken, flags, signature); - return signature; - } - - /** - * Note: If returnToken is EqualsGreaterThanToken, `signature.type` will always be defined. - * @returns If return type parsing succeeds - */ - function fillSignature( - returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, - flags: SignatureFlags, - signature: SignatureInfo): boolean { - if (!(flags & SignatureFlags.JSDoc)) { - signature.typeParameters = parseTypeParameters(); + function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) { + if (shouldParseReturnType(returnToken, isType)) { + return parseTypeOrTypePredicate(); } - const parametersParsedSuccessfully = parseParameterList(signature, flags); - if (shouldParseReturnType(returnToken, !!(flags & SignatureFlags.Type))) { - signature.type = parseTypeOrTypePredicate(); - if (typeHasArrowFunctionBlockingParseError(signature.type)) return false; - } - return parametersParsedSuccessfully; } function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { @@ -2762,8 +2727,37 @@ namespace ts { return false; } - // Returns true on success. - function parseParameterList(signature: SignatureInfo, flags: SignatureFlags): boolean { + function parseParametersWorker(flags: SignatureFlags) { + // FormalParameters [Yield,Await]: (modified) + // [empty] + // FormalParameterList[?Yield,Await] + // + // FormalParameter[Yield,Await]: (modified) + // BindingElement[?Yield,Await] + // + // BindingElement [Yield,Await]: (modified) + // SingleNameBinding[?Yield,?Await] + // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt + // + // SingleNameBinding [Yield,Await]: + // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt + const savedYieldContext = inYieldContext(); + const savedAwaitContext = inAwaitContext(); + + setYieldContext(!!(flags & SignatureFlags.Yield)); + setAwaitContext(!!(flags & SignatureFlags.Await)); + + const parameters = flags & SignatureFlags.JSDoc ? + parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : + parseDelimitedList(ParsingContext.Parameters, parseParameter); + + setYieldContext(savedYieldContext); + setAwaitContext(savedAwaitContext); + + return parameters; + } + + function parseParameters(flags: SignatureFlags): NodeArray { // FormalParameters [Yield,Await]: (modified) // [empty] // FormalParameterList[?Yield,Await] @@ -2778,24 +2772,12 @@ namespace ts { // SingleNameBinding [Yield,Await]: // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt if (!parseExpected(SyntaxKind.OpenParenToken)) { - signature.parameters = createMissingList(); - return false; + return createMissingList(); } - const savedYieldContext = inYieldContext(); - const savedAwaitContext = inAwaitContext(); - - setYieldContext(!!(flags & SignatureFlags.Yield)); - setAwaitContext(!!(flags & SignatureFlags.Await)); - - signature.parameters = flags & SignatureFlags.JSDoc ? - parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : - parseDelimitedList(ParsingContext.Parameters, parseParameter); - - setYieldContext(savedYieldContext); - setAwaitContext(savedAwaitContext); - - return parseExpected(SyntaxKind.CloseParenToken); + const parameters = parseParametersWorker(flags); + parseExpected(SyntaxKind.CloseParenToken); + return parameters; } function parseTypeMemberSemicolon() { @@ -2815,7 +2797,10 @@ namespace ts { if (kind === SyntaxKind.ConstructSignature) { parseExpected(SyntaxKind.NewKeyword); } - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.ColonToken, SignatureFlags.Type); + + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(SignatureFlags.Type); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); parseTypeMemberSemicolon(); const node = kind === SyntaxKind.CallSignature ? factory.createCallSignature(typeParameters, parameters, type) @@ -2897,7 +2882,9 @@ namespace ts { if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { // Method signatures don't exist in expression contexts. So they have neither // [Yield] nor [Await] - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.ColonToken, SignatureFlags.Type); + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(SignatureFlags.Type); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); node = factory.createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type); } else { @@ -3081,7 +3068,9 @@ namespace ts { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); const isConstructorType = parseOptional(SyntaxKind.NewKeyword); - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type); + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(SignatureFlags.Type); + const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false); const node = isConstructorType ? factory.createConstructorTypeNode(typeParameters, parameters, type) : factory.createFunctionTypeNode(typeParameters, parameters, type); @@ -3720,30 +3709,9 @@ namespace ts { // following => or { token. Otherwise, we *might* have an arrow function. Try to parse // it out, but don't allow any ambiguity, and return 'undefined' if this could be an // expression instead. - const pos = getNodePos(); - const hasJSDoc = hasPrecedingJSDocComment(); - const arrowFunction = triState === Tristate.True - ? parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ true) - : tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead); - - if (!arrowFunction) { - // Didn't appear to actually be a parenthesized arrow function. Just bail out. - return undefined; - } - - const { modifiers, typeParameters, parameters, type } = arrowFunction; - const isAsync = some(modifiers, isAsyncModifier); - - // If we have an arrow, then try to parse the body. Even if not, try to parse if we - // have an opening brace, just in case we're in an error state. - const lastToken = token(); - const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); - const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) - ? parseArrowFunctionExpressionBody(isAsync) - : parseIdentifier(); - - const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); - return withJSDoc(finishNode(node, pos), hasJSDoc); + return triState === Tristate.True ? + parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true) : + tryParse(parsePossibleParenthesizedArrowFunctionExpression); } // True -> We definitely expect a parenthesized arrow function here. @@ -3889,13 +3857,13 @@ namespace ts { } } - function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunctionHead | undefined { + function parsePossibleParenthesizedArrowFunctionExpression(): ArrowFunction | undefined { const tokenPos = scanner.getTokenPos(); if (notParenthesizedArrow && notParenthesizedArrow.has(tokenPos.toString())) { return undefined; } - const result = parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false); + const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false); if (!result) { (notParenthesizedArrow || (notParenthesizedArrow = createMap())).set(tokenPos.toString(), true); } @@ -3937,14 +3905,9 @@ namespace ts { return Tristate.False; } - interface ArrowFunctionHead extends SignatureInfo { - modifiers?: ModifiersArray; - typeParameters?: NodeArray; - parameters: NodeArray; - type?: TypeNode; - } - - function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunctionHead | undefined { + function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean): ArrowFunction | undefined { + const pos = getNodePos(); + const hasJSDoc = hasPrecedingJSDocComment(); const modifiers = parseModifiersForArrowFunction(); const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; // Arrow functions are never generators. @@ -3954,12 +3917,26 @@ namespace ts { // a => (b => c) // And think that "(b =>" was actually a parenthesized arrow function with a missing // close paren. - const signature = parseSignature(SyntaxKind.ColonToken, isAsync); - if (!signature.parametersParsedSuccessfully && !allowAmbiguity) { - return undefined; + const typeParameters = parseTypeParameters(); + + let parameters: NodeArray; + if (!parseExpected(SyntaxKind.OpenParenToken)) { + if (!allowAmbiguity) { + return undefined; + } + parameters = createMissingList(); + } + else { + parameters = parseParametersWorker(isAsync); + if (!parseExpected(SyntaxKind.CloseParenToken) && !allowAmbiguity) { + return undefined; + } } - const { typeParameters, parameters, type } = signature; + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); + if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) { + return undefined; + } // Parsing a signature isn't enough. // Parenthesized arrow signatures often look like other valid expressions. @@ -3976,7 +3953,16 @@ namespace ts { return undefined; } - return { modifiers, typeParameters, parameters, type }; + // If we have an arrow, then try to parse the body. Even if not, try to parse if we + // have an opening brace, just in case we're in an error state. + const lastToken = token(); + const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); + const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) + ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier)) + : parseIdentifier(); + + const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); + return withJSDoc(finishNode(node, pos), hasJSDoc); } function parseArrowFunctionExpressionBody(isAsync: boolean): Block | Expression { @@ -5091,7 +5077,9 @@ namespace ts { isAsync ? doInAwaitContext(parseOptionalIdentifier) : parseOptionalIdentifier(); - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.ColonToken, isGenerator | isAsync); + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(isGenerator | isAsync); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlock(isGenerator | isAsync); if (saveDecoratorContext) { @@ -5902,7 +5890,9 @@ namespace ts { const name = modifierFlags & ModifierFlags.Default ? parseOptionalIdentifier() : parseIdentifier(); const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None; - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.ColonToken, isGenerator | isAsync); + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(isGenerator | isAsync); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); const node = factory.createFunctionDeclaration(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body); return withJSDoc(finishNode(node, pos), hasJSDoc); @@ -5923,7 +5913,9 @@ namespace ts { function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined): ConstructorDeclaration | undefined { return tryParse(() => { if (parseConstructorName()) { - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.ColonToken, SignatureFlags.None); + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(SignatureFlags.None); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); const node = factory.createConstructorDeclaration(decorators, modifiers, parameters, body); // Attach `typeParameters` and `type` if they exist so that we can report them in the grammar checker. @@ -5947,7 +5939,9 @@ namespace ts { ): MethodDeclaration { const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.ColonToken, isGenerator | isAsync); + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(isGenerator | isAsync); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage); const node = factory.createMethodDeclaration( decorators, @@ -6001,7 +5995,9 @@ namespace ts { function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray | undefined, modifiers: NodeArray | undefined, kind: AccessorDeclaration["kind"]): AccessorDeclaration { const name = parsePropertyName(); - const { typeParameters, parameters, type } = parseSignature(SyntaxKind.ColonToken, SignatureFlags.None); + const typeParameters = parseTypeParameters(); + const parameters = parseParameters(SignatureFlags.None); + const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(SignatureFlags.None); const node = kind === SyntaxKind.GetAccessor ? factory.createGetAccessorDeclaration(decorators, modifiers, name, parameters, type, body) diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index b45c4010d48..2378297d71a 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -235,7 +235,7 @@ namespace ts { if (isClassWithConstructorReference) { // record an alias as the class name is not in scope for statics. enableSubstitutionForClassAliases(); - const alias = getSynthesizedClone(temp) as GeneratedIdentifier; + const alias = factory.cloneNode(temp) as GeneratedIdentifier; alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; classAliases[getOriginalNodeId(node)] = alias; } @@ -488,7 +488,7 @@ namespace ts { if (declaration) { const classAlias = classAliases[declaration.id!]; // TODO: GH#18217 if (classAlias) { - const clone = getSynthesizedClone(classAlias); + const clone = factory.cloneNode(classAlias); setSourceMapRange(clone, node); setCommentRange(clone, node); return clone; diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 4036161258f..12e619cf613 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -1055,7 +1055,8 @@ namespace ts { // Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too return statement; } - const clone = getMutableClone(statement); + // TODO(rbuckton): Does this need to be parented? + const clone = setParent(setTextRange(factory.cloneNode(statement), statement), statement.parent); const modifiers = factory.createModifiersFromModifierFlags(getModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export)); clone.modifiers = modifiers.length ? factory.createNodeArray(modifiers) : undefined; return clone; diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 5c18aafa4aa..367dec76629 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -466,7 +466,7 @@ namespace ts { return flattenContext.context.factory.createElementAccess(value, argumentExpression); } else if (isStringOrNumericLiteralLike(propertyName)) { - const argumentExpression = getSynthesizedClone(propertyName); + const argumentExpression = factory.cloneNode(propertyName); argumentExpression.text = argumentExpression.text; return flattenContext.context.factory.createElementAccess(value, argumentExpression); } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 19497ba336f..ca6557c553e 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -1299,7 +1299,7 @@ namespace ts { function insertDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void { initializer = visitNode(initializer, visitor, isExpression); const statement = factory.createIf( - factory.createTypeCheck(getSynthesizedClone(name), "undefined"), + factory.createTypeCheck(factory.cloneNode(name), "undefined"), setEmitFlags( setTextRange( factory.createBlock([ @@ -1307,7 +1307,8 @@ namespace ts { setEmitFlags( setTextRange( factory.createAssignment( - setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap), + // TODO(rbuckton): Does this need to be parented? + setEmitFlags(setParent(setTextRange(factory.cloneNode(name), name), name.parent), EmitFlags.NoSourceMap), setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer) | EmitFlags.NoComments) ), parameter @@ -1357,11 +1358,12 @@ namespace ts { } // `declarationName` is the name of the local declaration for the parameter. - const declarationName = parameter.name.kind === SyntaxKind.Identifier ? getMutableClone(parameter.name) : factory.createTempVariable(/*recordTempVariable*/ undefined); + // TODO(rbuckton): Does this need to be parented? + const declarationName = parameter.name.kind === SyntaxKind.Identifier ? setParent(setTextRange(factory.cloneNode(parameter.name), parameter.name), parameter.name.parent) : factory.createTempVariable(/*recordTempVariable*/ undefined); setEmitFlags(declarationName, EmitFlags.NoSourceMap); // `expressionName` is the name of the parameter used in expressions. - const expressionName = parameter.name.kind === SyntaxKind.Identifier ? getSynthesizedClone(parameter.name) : declarationName; + const expressionName = parameter.name.kind === SyntaxKind.Identifier ? factory.cloneNode(parameter.name) : declarationName; const restIndex = node.parameters.length - 1; const temp = factory.createLoopVariable(); @@ -1666,7 +1668,8 @@ namespace ts { function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations, container: Node, startsOnNewLine: boolean): Expression { // To align with source maps in the old emitter, the receiver and property name // arguments are both mapped contiguously to the accessor name. - const target = getMutableClone(receiver); + // TODO(rbuckton): Does this need to be parented? + const target = setParent(setTextRange(factory.cloneNode(receiver), receiver), receiver.parent); setEmitFlags(target, EmitFlags.NoComments | EmitFlags.NoTrailingSourceMap); setSourceMapRange(target, firstAccessor.name); @@ -2630,7 +2633,8 @@ namespace ts { // We need to clone the temporary identifier so that we can write it on a // new line - expressions.push(node.multiLine ? startOnNewLine(getMutableClone(temp)) : temp); + // TODO(rbuckton): Does this need to be parented? + expressions.push(node.multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp); return factory.inlineExpressions(expressions); } return visitEachChild(node, visitor, context); @@ -3406,7 +3410,7 @@ namespace ts { receiver, visitNode(property.name, visitor, isPropertyName) ), - getSynthesizedClone(property.name) + factory.cloneNode(property.name) ); setTextRange(expression, property); if (startsOnNewLine) { @@ -3526,7 +3530,7 @@ namespace ts { return setTextRange( factory.createPropertyAssignment( node.name, - getSynthesizedClone(node.name) + factory.cloneNode(node.name) ), /*location*/ node ); diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index d831acf256b..dd4fb33db72 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -1063,7 +1063,8 @@ namespace ts { ); const expressions = reduceLeft(properties, reduceProperty, [], numInitialProperties); - expressions.push(multiLine ? startOnNewLine(getMutableClone(temp)) : temp); + // TODO(rbuckton): Does this need to be parented? + expressions.push(multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp); return factory.inlineExpressions(expressions); function reduceProperty(expressions: Expression[], property: ObjectLiteralElementLike) { @@ -1252,7 +1253,7 @@ namespace ts { function transformAndEmitVariableDeclarationList(node: VariableDeclarationList): VariableDeclarationList | undefined { for (const variable of node.declarations) { - const name = getSynthesizedClone(variable.name); + const name = factory.cloneNode(variable.name); setCommentRange(name, variable.name); hoistVariableDeclaration(name); } @@ -1284,7 +1285,7 @@ namespace ts { function transformInitializedVariable(node: VariableDeclaration) { return setSourceMapRange( factory.createAssignment( - setSourceMapRange(getSynthesizedClone(node.name), node.name), + setSourceMapRange(factory.cloneNode(node.name), node.name), visitNode(node.initializer, visitor, isExpression) ), node @@ -1570,7 +1571,7 @@ namespace ts { hoistVariableDeclaration(variable.name); } - variable = getSynthesizedClone(initializer.declarations[0].name); + variable = factory.cloneNode(initializer.declarations[0].name); } else { variable = visitNode(initializer, visitor, isExpression); @@ -1964,7 +1965,8 @@ namespace ts { if (declaration) { const name = renamedCatchVariableDeclarations[getOriginalNodeId(declaration)]; if (name) { - const clone = getMutableClone(name); + // TODO(rbuckton): Does this need to be parented? + const clone = setParent(setTextRange(factory.cloneNode(name), name), name.parent); setSourceMapRange(clone, node); setCommentRange(clone, node); return clone; diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index cee5fe0693c..33fa62ebfcc 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -630,7 +630,7 @@ namespace ts { // }); needUMDDynamicImportHelper = true; if (isSimpleCopiableExpression(arg)) { - const argClone = isGeneratedIdentifier(arg) ? arg : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) : setEmitFlags(setTextRange(getSynthesizedClone(arg), arg), EmitFlags.NoComments); + const argClone = isGeneratedIdentifier(arg) ? arg : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) : setEmitFlags(setTextRange(factory.cloneNode(arg), arg), EmitFlags.NoComments); return factory.createConditional( /*condition*/ factory.createIdentifier("__syncRequire"), /*questionToken*/ undefined, @@ -788,7 +788,7 @@ namespace ts { // import * as n from "mod"; variables.push( factory.createVariableDeclaration( - getSynthesizedClone(namespaceDeclaration.name), + factory.cloneNode(namespaceDeclaration.name), /*exclamationToken*/ undefined, /*type*/ undefined, getHelperExpressionForImport(node, createRequireCall(node)) @@ -812,7 +812,7 @@ namespace ts { if (namespaceDeclaration && isDefaultImport(node)) { variables.push( factory.createVariableDeclaration( - getSynthesizedClone(namespaceDeclaration.name), + factory.cloneNode(namespaceDeclaration.name), /*exclamationToken*/ undefined, /*type*/ undefined, factory.getGeneratedNameForNode(node) @@ -847,7 +847,7 @@ namespace ts { setOriginalNode( setTextRange( factory.createVariableDeclaration( - getSynthesizedClone(namespaceDeclaration.name), + factory.cloneNode(namespaceDeclaration.name), /*exclamationToken*/ undefined, /*type*/ undefined, factory.getGeneratedNameForNode(node) @@ -923,7 +923,7 @@ namespace ts { factory.createVariableDeclarationList( [ factory.createVariableDeclaration( - getSynthesizedClone(node.name), + factory.cloneNode(node.name), /*exclamationToken*/ undefined, /*type*/ undefined, createRequireCall(node) @@ -1520,7 +1520,7 @@ namespace ts { factory.createAssignment( factory.createPropertyAccess( factory.createIdentifier("exports"), - getSynthesizedClone(name) + factory.cloneNode(name) ), value ), @@ -1664,7 +1664,7 @@ namespace ts { return setTextRange( factory.createPropertyAccess( factory.createIdentifier("exports"), - getSynthesizedClone(node) + factory.cloneNode(node) ), /*location*/ node ); @@ -1686,7 +1686,7 @@ namespace ts { return setTextRange( factory.createPropertyAccess( factory.getGeneratedNameForNode(importDeclaration.parent.parent.parent), - getSynthesizedClone(name) + factory.cloneNode(name) ), /*location*/ node ); diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index f2518dbfab1..76ae155eb81 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -794,7 +794,7 @@ namespace ts { } } else { - hoistVariableDeclaration(getSynthesizedClone(node.name)); + hoistVariableDeclaration(factory.cloneNode(node.name)); } } @@ -861,7 +861,7 @@ namespace ts { * @param isExportedDeclaration A value indicating whether the variable is exported. */ function createVariableAssignment(name: Identifier, value: Expression, location: TextRange | undefined, isExportedDeclaration: boolean) { - hoistVariableDeclaration(getSynthesizedClone(name)); + hoistVariableDeclaration(factory.cloneNode(name)); return isExportedDeclaration ? createExportExpression(name, preventSubstitution(setTextRange(factory.createAssignment(name, value), location))) : preventSubstitution(setTextRange(factory.createAssignment(name, value), location)); @@ -1663,7 +1663,7 @@ namespace ts { if (isImportClause(importDeclaration)) { return setTextRange( factory.createPropertyAssignment( - getSynthesizedClone(name), + factory.cloneNode(name), factory.createPropertyAccess( factory.getGeneratedNameForNode(importDeclaration.parent), factory.createIdentifier("default") @@ -1675,10 +1675,10 @@ namespace ts { else if (isImportSpecifier(importDeclaration)) { return setTextRange( factory.createPropertyAssignment( - getSynthesizedClone(name), + factory.cloneNode(name), factory.createPropertyAccess( factory.getGeneratedNameForNode(importDeclaration.parent.parent.parent), - getSynthesizedClone(importDeclaration.propertyName || importDeclaration.name) + factory.cloneNode(importDeclaration.propertyName || importDeclaration.name) ), ), /*location*/ node @@ -1747,7 +1747,7 @@ namespace ts { return setTextRange( factory.createPropertyAccess( factory.getGeneratedNameForNode(importDeclaration.parent.parent.parent), - getSynthesizedClone(importDeclaration.propertyName || importDeclaration.name) + factory.cloneNode(importDeclaration.propertyName || importDeclaration.name) ), /*location*/ node ); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index f81f27a2339..cae2cba07be 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1737,7 +1737,8 @@ namespace ts { case SyntaxKind.Identifier: // Create a clone of the name with a new parent, and treat it as if it were // a source tree node for the purposes of the checker. - const name = getMutableClone(node); + // TODO(rbuckton): Does this need to be parented? + const name = setParent(setTextRange(factory.cloneNode(node), node), node.parent); name.flags &= ~NodeFlags.Synthesized; name.original = undefined; name.parent = getParseTreeNode(currentLexicalScope)!; // ensure the parent is set to a parse tree node. @@ -1807,7 +1808,7 @@ namespace ts { return factory.createStringLiteral(idText(name)); } else { - return getSynthesizedClone(name); + return factory.cloneNode(name); } } @@ -1962,10 +1963,12 @@ namespace ts { return undefined; } - const propertyName = getMutableClone(name); + // TODO(rbuckton): Does this need to be parented? + const propertyName = setParent(setTextRange(factory.cloneNode(name), name), name.parent); setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap); - const localName = getMutableClone(name); + // TODO(rbuckton): Does this need to be parented? + const localName = setParent(setTextRange(factory.cloneNode(name), name), name.parent); setEmitFlags(localName, EmitFlags.NoComments); return startOnNewLine( @@ -3213,7 +3216,7 @@ namespace ts { if (declaration) { const classAlias = classAliases[declaration.id!]; // TODO: GH#18217 if (classAlias) { - const clone = getSynthesizedClone(classAlias); + const clone = factory.cloneNode(classAlias); setSourceMapRange(clone, node); setCommentRange(clone, node); return clone; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 763893a8c77..4facdfa017c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6541,6 +6541,19 @@ namespace ts { createSourceFile(statements: readonly Statement[], endOfFileToken: EndOfFileToken): SourceFile; updateSourceFile(node: SourceFile, statements: readonly Statement[], isDeclarationFile?: boolean, referencedFiles?: readonly FileReference[], typeReferences?: readonly FileReference[], hasNoDefaultLib?: boolean, libReferences?: readonly FileReference[]): SourceFile; + /* @internal */ createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]): UnparsedSource; + /* @internal */ createUnparsedPrologue(data?: string): UnparsedPrologue; + /* @internal */ createUnparsedPrepend(data: string | undefined, texts: readonly UnparsedSourceText[]): UnparsedPrepend; + /* @internal */ createUnparsedTextLike(data: string | undefined, internal: boolean): UnparsedTextLike; + /* @internal */ createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference): UnparsedSyntheticReference; + /* @internal */ createInputFiles(): InputFiles; + + // + // Synthetic Nodes + // + /* @internal */ createSyntheticExpression(type: Type, isSpread?: boolean): SyntheticExpression; + /* @internal */ createSyntaxList(children: Node[]): SyntaxList; + // // Transformation nodes // @@ -6719,6 +6732,12 @@ namespace ts { /* @internal */ copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult): number | undefined; /* @internal */ ensureUseStrict(statements: NodeArray): NodeArray; /* @internal */ liftToBlock(nodes: readonly Node[]): Statement; + /** + * Creates a shallow, memberwise clone of a node. + * - The result will have its `original` pointer set to `node`. + * - The result will have its `pos` and `end` set to `-1`. + */ + /* @internal */ cloneNode(node: T): T; } export interface CoreTransformationContext { @@ -7214,6 +7233,7 @@ namespace ts { // SyntaxKind.SyntaxList export interface SyntaxList extends Node { + kind: SyntaxKind.SyntaxList; _children: Node[]; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6eced2ec774..26bda84dc2c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5097,8 +5097,9 @@ namespace ts { } } - export function getDotOrQuestionDotToken(node: PropertyAccessExpression) { - return node.questionDotToken || createNode(SyntaxKind.DotToken, node.expression.end, node.name.pos) as DotToken; + export function getDotOrQuestionDotToken(node: PropertyAccessExpression): DotToken | QuestionDotToken { + return node.questionDotToken || + setTextRangePosEnd(factory.createToken(SyntaxKind.DotToken), node.expression.end, node.name.pos); } export function getLeftmostExpression(node: Expression, stopAtCallExpressions: boolean) { @@ -5938,13 +5939,34 @@ namespace ts { namespace ts { export function setTextRange(range: T, location: TextRange | undefined): T { - if (location) { - range.pos = location.pos; - range.end = location.end; - } + return location ? setTextRangePosEnd(range, location.pos, location.end) : range; + } + + /* @internal */ + export function setTextRangePosEnd(range: T, pos: number, end: number) { + range.pos = pos; + range.end = end; return range; } + /* @internal */ + export function setParent(child: T, parent: T["parent"]): T { + if (!child.parent) { + child.parent = parent; + } + return child; + } + + /* @internal */ + export function setEachParent(children: T, parent: NonNullable[number]["parent"]): T { + if (children) { + for (const child of children!) { + setParent(child, parent); + } + } + return children; + } + export function isConstTypeReference(node: Node) { return isTypeReferenceNode(node) && isIdentifier(node.typeName) && node.typeName.escapedText === "const" && !node.typeArguments; diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 3392439b4f9..66f123a4b31 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -351,7 +351,7 @@ namespace ts.codefix { if (param.initializer || getJSDocType(param) || !isIdentifier(param.name)) return; const typeNode = inference.type && getTypeNodeIfAccessible(inference.type, param, program, host); - const name = getSynthesizedClone(param.name); + const name = factory.cloneNode(param.name); setEmitFlags(name, EmitFlags.NoComments | EmitFlags.NoNestedComments); return typeNode && factory.createJSDocParameterTag(/*tagName*/ undefined, name, !!inference.isOptional, factory.createJSDocTypeExpression(typeNode), /*isNameFirst*/ undefined, ""); }); diff --git a/src/services/refactors/extractType.ts b/src/services/refactors/extractType.ts index 17196a11849..4da7d6db9ce 100644 --- a/src/services/refactors/extractType.ts +++ b/src/services/refactors/extractType.ts @@ -181,24 +181,21 @@ namespace ts.refactor { function doTypedefChange(changes: textChanges.ChangeTracker, file: SourceFile, name: string, info: Info) { const { firstStatement, selection, typeParameters } = info; - const node = createNode(SyntaxKind.JSDocTypedefTag); - node.tagName = factory.createIdentifier("typedef"); // TODO: jsdoc factory https://github.com/Microsoft/TypeScript/pull/29539 - node.fullName = factory.createIdentifier(name); - node.name = node.fullName; - node.typeExpression = factory.createJSDocTypeExpression(selection); + const node = factory.createJSDocTypedefTag( + factory.createIdentifier("typedef"), + factory.createJSDocTypeExpression(selection), + factory.createIdentifier(name)); + node.name = node.name as Identifier; const templates: JSDocTemplateTag[] = []; forEach(typeParameters, typeParameter => { const constraint = getEffectiveConstraintOfTypeParameter(typeParameter); - - const template = createNode(SyntaxKind.JSDocTemplateTag); - template.tagName = factory.createIdentifier("template"); - template.constraint = constraint && cast(constraint, isJSDocTypeExpression); - - const parameter = createNode(SyntaxKind.TypeParameter); - parameter.name = typeParameter.name; - template.typeParameters = factory.createNodeArray([parameter]); - + const parameter = factory.createTypeParameterDeclaration(typeParameter.name); + const template = factory.createJSDocTemplateTag( + factory.createIdentifier("template"), + constraint && cast(constraint, isJSDocTypeExpression), + [parameter] + ); templates.push(template); }); diff --git a/src/services/smartSelection.ts b/src/services/smartSelection.ts index 984c1de86e7..3d8fd11cbd9 100644 --- a/src/services/smartSelection.ts +++ b/src/services/smartSelection.ts @@ -252,9 +252,7 @@ namespace ts.SmartSelectionRange { function createSyntaxList(children: Node[]): SyntaxList { Debug.assertGreaterThanOrEqual(children.length, 1); - const syntaxList = createNode(SyntaxKind.SyntaxList, children[0].pos, last(children).end) as SyntaxList; - syntaxList._children = children; - return syntaxList; + return setTextRangePosEnd(parseNodeFactory.createSyntaxList(children), children[0].pos, last(children).end); } function isListOpener(token: Node | undefined): token is Node { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index d217e035353..84fdbe766df 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1787,7 +1787,7 @@ namespace ts { if (visited === node) { // This only happens for leaf nodes - internal nodes always see their children change. - const clone = getSynthesizedClone(node); + const clone = factory.cloneNode(node); if (isStringLiteral(clone)) { clone.textSourceNode = node as any; } diff --git a/src/testRunner/unittests/transform.ts b/src/testRunner/unittests/transform.ts index 3059b842052..d1ae3d9b295 100644 --- a/src/testRunner/unittests/transform.ts +++ b/src/testRunner/unittests/transform.ts @@ -174,7 +174,8 @@ namespace ts { function replaceWithClassAndNamespace() { return (sourceFile: SourceFile) => { - const result = getMutableClone(sourceFile); + // TODO(rbuckton): Does this need to be parented? + const result = setParent(setTextRange(factory.cloneNode(sourceFile), sourceFile), sourceFile.parent); result.statements = factory.createNodeArray([ factory.createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined!), // TODO: GH#18217 factory.createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, factory.createIdentifier("Foo"), factory.createModuleBlock([factory.createEmptyStatement()])) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 0a4feee687f..b76d6e9025d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3106,9 +3106,7 @@ declare namespace ts { updateParen(node: ParenthesizedExpression, expression: Expression): ParenthesizedExpression; createFunctionExpression(modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, body: Block): FunctionExpression; updateFunctionExpression(node: FunctionExpression, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block): FunctionExpression; - createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; - updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; createDelete(expression: Expression): DeleteExpression; updateDelete(node: DeleteExpression, expression: Expression): DeleteExpression; @@ -3124,9 +3122,7 @@ declare namespace ts { updatePostfix(node: PostfixUnaryExpression, operand: Expression): PostfixUnaryExpression; createBinary(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression; updateBinary(node: BinaryExpression, left: Expression, right: Expression, operator?: BinaryOperator | BinaryOperatorToken): BinaryExpression; - createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; - createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; - updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; + createConditional(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression): ConditionalExpression; updateConditional(node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; @@ -3513,6 +3509,7 @@ declare namespace ts { newLength: number; } export interface SyntaxList extends Node { + kind: SyntaxKind.SyntaxList; _children: Node[]; } export enum ListFormat { @@ -3946,10 +3943,6 @@ declare namespace ts { } declare namespace ts { const factory: NodeFactory; - /** - * Creates a shallow, memberwise clone of a node for mutation. - */ - function getMutableClone(node: T): T; function createUnparsedSourceFile(text: string): UnparsedSource; function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts", stripInternal?: boolean): UnparsedSource; function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource; @@ -4208,6 +4201,7 @@ declare namespace ts { function isJSDocPropertyTag(node: Node): node is JSDocPropertyTag; } declare namespace ts { + /** @deprecated Use an appropriate `factory` method instead. */ export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node; /** * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes @@ -9832,20 +9826,6 @@ declare namespace ts { * @deprecated Use `factory.updateFunctionExpression` or the factory supplied by your transformation context instead. */ updateFunctionExpression: (node: FunctionExpression, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block) => FunctionExpression, - /** - * @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. - */ - createArrowFunction: { - (modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; - (modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; - }, - /** - * @deprecated Use `factory.updateArrowFunction` or the factory supplied by your transformation context instead. - */ - updateArrowFunction: { - (node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; - (node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; - }, /** * @deprecated Use `factory.createDelete` or the factory supplied by your transformation context instead. */ @@ -9905,10 +9885,7 @@ declare namespace ts { /** * @deprecated Use `factory.updateConditional` or the factory supplied by your transformation context instead. */ - updateConditional: { - (node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; - (node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; - }, + updateConditional: (node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression) => ConditionalExpression, /** * @deprecated Use `factory.createTemplateExpression` or the factory supplied by your transformation context instead. */ @@ -10652,6 +10629,22 @@ declare namespace ts { * @deprecated Use `factory.updateExpressionWithTypeArguments` or the factory supplied by your transformation context instead. */ function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, typeArguments: readonly TypeNode[] | undefined, expression: Expression): ExpressionWithTypeArguments; + /** + * @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. + */ + function createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; + /** + * @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. + */ + function createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; + /** + * @deprecated Use `factory.updateArrowFunction` or the factory supplied by your transformation context instead. + */ + function updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; + /** + * @deprecated Use `factory.updateArrowFunction` or the factory supplied by your transformation context instead. + */ + function updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; /** * @deprecated Use `factory.createVariableDeclaration` or the factory supplied by your transformation context instead. */ @@ -10715,6 +10708,11 @@ declare namespace ts { * @deprecated Use `factory.createLogicalNot` or the factory supplied by your transformation context instead. */ function createLogicalNot(operand: Expression): PrefixUnaryExpression; + /** + * Creates a shallow, memberwise clone of a node for mutation. + * @deprecated Use `factory.cloneNode` instead and set `pos`, `end`, and `parent` as needed. + */ + function getMutableClone(node: T): T; /** * @deprecated Use `isTypeAssertionExpression` instead. */ diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index fab0a9b93c9..b0e8f2bb85c 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3106,9 +3106,7 @@ declare namespace ts { updateParen(node: ParenthesizedExpression, expression: Expression): ParenthesizedExpression; createFunctionExpression(modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, body: Block): FunctionExpression; updateFunctionExpression(node: FunctionExpression, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block): FunctionExpression; - createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; - updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; createDelete(expression: Expression): DeleteExpression; updateDelete(node: DeleteExpression, expression: Expression): DeleteExpression; @@ -3124,9 +3122,7 @@ declare namespace ts { updatePostfix(node: PostfixUnaryExpression, operand: Expression): PostfixUnaryExpression; createBinary(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression; updateBinary(node: BinaryExpression, left: Expression, right: Expression, operator?: BinaryOperator | BinaryOperatorToken): BinaryExpression; - createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; - createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; - updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; + createConditional(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression): ConditionalExpression; updateConditional(node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; @@ -3513,6 +3509,7 @@ declare namespace ts { newLength: number; } export interface SyntaxList extends Node { + kind: SyntaxKind.SyntaxList; _children: Node[]; } export enum ListFormat { @@ -3946,10 +3943,6 @@ declare namespace ts { } declare namespace ts { const factory: NodeFactory; - /** - * Creates a shallow, memberwise clone of a node for mutation. - */ - function getMutableClone(node: T): T; function createUnparsedSourceFile(text: string): UnparsedSource; function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts", stripInternal?: boolean): UnparsedSource; function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource; @@ -4208,6 +4201,7 @@ declare namespace ts { function isJSDocPropertyTag(node: Node): node is JSDocPropertyTag; } declare namespace ts { + /** @deprecated Use an appropriate `factory` method instead. */ export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node; /** * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes @@ -6375,20 +6369,6 @@ declare namespace ts { * @deprecated Use `factory.updateFunctionExpression` or the factory supplied by your transformation context instead. */ updateFunctionExpression: (node: FunctionExpression, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block) => FunctionExpression, - /** - * @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. - */ - createArrowFunction: { - (modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; - (modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; - }, - /** - * @deprecated Use `factory.updateArrowFunction` or the factory supplied by your transformation context instead. - */ - updateArrowFunction: { - (node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; - (node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; - }, /** * @deprecated Use `factory.createDelete` or the factory supplied by your transformation context instead. */ @@ -6448,10 +6428,7 @@ declare namespace ts { /** * @deprecated Use `factory.updateConditional` or the factory supplied by your transformation context instead. */ - updateConditional: { - (node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression; - (node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; - }, + updateConditional: (node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression) => ConditionalExpression, /** * @deprecated Use `factory.createTemplateExpression` or the factory supplied by your transformation context instead. */ @@ -7195,6 +7172,22 @@ declare namespace ts { * @deprecated Use `factory.updateExpressionWithTypeArguments` or the factory supplied by your transformation context instead. */ function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, typeArguments: readonly TypeNode[] | undefined, expression: Expression): ExpressionWithTypeArguments; + /** + * @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. + */ + function createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; + /** + * @deprecated Use `factory.createArrowFunction` or the factory supplied by your transformation context instead. + */ + function createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; + /** + * @deprecated Use `factory.updateArrowFunction` or the factory supplied by your transformation context instead. + */ + function updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; + /** + * @deprecated Use `factory.updateArrowFunction` or the factory supplied by your transformation context instead. + */ + function updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody): ArrowFunction; /** * @deprecated Use `factory.createVariableDeclaration` or the factory supplied by your transformation context instead. */ @@ -7258,6 +7251,11 @@ declare namespace ts { * @deprecated Use `factory.createLogicalNot` or the factory supplied by your transformation context instead. */ function createLogicalNot(operand: Expression): PrefixUnaryExpression; + /** + * Creates a shallow, memberwise clone of a node for mutation. + * @deprecated Use `factory.cloneNode` instead and set `pos`, `end`, and `parent` as needed. + */ + function getMutableClone(node: T): T; /** * @deprecated Use `isTypeAssertionExpression` instead. */