namespace ts { let nextAutoGenerateId = 0; /* @internal */ export const enum NodeFactoryFlags { None = 0, // Disables the parenthesizer rules for the factory. NoParenthesizerRules = 1 << 0, // Disables the node converters for the factory. NoNodeConverters = 1 << 1, // Ensures new `PropertyAccessExpression` nodes are created with the `NoIndentation` emit flag set. NoIndentationOnFreshPropertyAccess = 1 << 2, // Do not set an `original` pointer when updating a node. NoOriginalNode = 1 << 3, } /** * Creates a `NodeFactory` that can be used to create and update a syntax tree. * @param flags Flags that control factory behavior. * @param baseFactory A `BaseNodeFactory` used to create the base `Node` objects. */ /* @internal */ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNodeFactory): NodeFactory { const update = flags & NodeFactoryFlags.NoOriginalNode ? updateWithoutOriginal : updateWithOriginal; // Lazily load the parenthesizer, node converters, and some factory methods until they are used. const parenthesizerRules = memoize(() => flags & NodeFactoryFlags.NoParenthesizerRules ? nullParenthesizerRules : createParenthesizerRules(factory)); const converters = memoize(() => flags & NodeFactoryFlags.NoNodeConverters ? nullNodeConverters : createNodeConverters(factory)); // lazy initializaton of common operator factories const getBinaryCreateFunction = memoizeOne((operator: BinaryOperator) => (left: Expression, right: Expression) => createBinaryExpression(left, operator, right)); const getPrefixUnaryCreateFunction = memoizeOne((operator: PrefixUnaryOperator) => (operand: Expression) => createPrefixUnaryExpression(operator, operand)); const getPostfixUnaryCreateFunction = memoizeOne((operator: PostfixUnaryOperator) => (operand: Expression) => createPostfixUnaryExpression(operand, operator)); const getJSDocPrimaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind)); const getJSDocUnaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => (type: T["type"]) => createJSDocUnaryTypeWorker(kind, type)); const getJSDocUnaryTypeUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker(kind, node, type)); const getJSDocSimpleTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, comment?: string) => createJSDocSimpleTagWorker(kind, tagName, comment)); const getJSDocSimpleTagUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, tagName: Identifier | undefined, comment?: string) => updateJSDocSimpleTagWorker(kind, node, tagName, comment)); const getJSDocTypeLikeTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string) => createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment)); const getJSDocTypeLikeTagUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string) => updateJSDocTypeLikeTagWorker(kind, node, tagName, typeExpression, comment)); const factory: NodeFactory = { get parenthesizer() { return parenthesizerRules(); }, get converters() { return converters(); }, createNodeArray, createNumericLiteral, createBigIntLiteral, createStringLiteral, createStringLiteralFromNode, createRegularExpressionLiteral, createLiteralLikeNode, createIdentifier, updateIdentifier, createTempVariable, createLoopVariable, createUniqueName, getGeneratedNameForNode, createPrivateIdentifier, createToken, createSuper, createThis, createNull, createTrue, createFalse, createModifier, createModifiersFromModifierFlags, createQualifiedName, updateQualifiedName, createComputedPropertyName, updateComputedPropertyName, createTypeParameterDeclaration, updateTypeParameterDeclaration, createParameterDeclaration, updateParameterDeclaration, createDecorator, updateDecorator, createPropertySignature, updatePropertySignature, createPropertyDeclaration, updatePropertyDeclaration, createMethodSignature, updateMethodSignature, createMethodDeclaration, updateMethodDeclaration, createConstructorDeclaration, updateConstructorDeclaration, createGetAccessorDeclaration, updateGetAccessorDeclaration, createSetAccessorDeclaration, updateSetAccessorDeclaration, createCallSignature, updateCallSignature, createConstructSignature, updateConstructSignature, createIndexSignature, updateIndexSignature, createKeywordTypeNode, createTypePredicateNode, updateTypePredicateNode, createTypeReferenceNode, updateTypeReferenceNode, createFunctionTypeNode, updateFunctionTypeNode, createConstructorTypeNode, updateConstructorTypeNode, createTypeQueryNode, updateTypeQueryNode, createTypeLiteralNode, updateTypeLiteralNode, createArrayTypeNode, updateArrayTypeNode, createTupleTypeNode, updateTupleTypeNode, createNamedTupleMember, updateNamedTupleMember, createOptionalTypeNode, updateOptionalTypeNode, createRestTypeNode, updateRestTypeNode, createUnionTypeNode, updateUnionTypeNode, createIntersectionTypeNode, updateIntersectionTypeNode, createConditionalTypeNode, updateConditionalTypeNode, createInferTypeNode, updateInferTypeNode, createImportTypeNode, updateImportTypeNode, createParenthesizedType, updateParenthesizedType, createThisTypeNode, createTypeOperatorNode, updateTypeOperatorNode, createIndexedAccessTypeNode, updateIndexedAccessTypeNode, createMappedTypeNode, updateMappedTypeNode, createLiteralTypeNode, updateLiteralTypeNode, createObjectBindingPattern, updateObjectBindingPattern, createArrayBindingPattern, updateArrayBindingPattern, createBindingElement, updateBindingElement, createArrayLiteralExpression, updateArrayLiteralExpression, createObjectLiteralExpression, updateObjectLiteralExpression, createPropertyAccessExpression: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ? (expression, name) => setEmitFlags(createPropertyAccessExpression(expression, name), EmitFlags.NoIndentation) : createPropertyAccessExpression, updatePropertyAccessExpression, createPropertyAccessChain: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ? (expression, questionDotToken, name) => setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), EmitFlags.NoIndentation) : createPropertyAccessChain, updatePropertyAccessChain, createElementAccessExpression, updateElementAccessExpression, createElementAccessChain, updateElementAccessChain, createCallExpression, updateCallExpression, createCallChain, updateCallChain, createNewExpression, updateNewExpression, createTaggedTemplateExpression, updateTaggedTemplateExpression, createTypeAssertion, updateTypeAssertion, createParenthesizedExpression, updateParenthesizedExpression, createFunctionExpression, updateFunctionExpression, createArrowFunction, updateArrowFunction, createDeleteExpression, updateDeleteExpression, createTypeOfExpression, updateTypeOfExpression, createVoidExpression, updateVoidExpression, createAwaitExpression, updateAwaitExpression, createPrefixUnaryExpression, updatePrefixUnaryExpression, createPostfixUnaryExpression, updatePostfixUnaryExpression, createBinaryExpression, updateBinaryExpression, createConditionalExpression, updateConditionalExpression, createTemplateExpression, updateTemplateExpression, createTemplateHead, createTemplateMiddle, createTemplateTail, createNoSubstitutionTemplateLiteral, createTemplateLiteralLikeNode, createYieldExpression, updateYieldExpression, createSpreadElement, updateSpreadElement, createClassExpression, updateClassExpression, createOmittedExpression, createExpressionWithTypeArguments, updateExpressionWithTypeArguments, createAsExpression, updateAsExpression, createNonNullExpression, updateNonNullExpression, createNonNullChain, updateNonNullChain, createMetaProperty, updateMetaProperty, createTemplateSpan, updateTemplateSpan, createSemicolonClassElement, createBlock, updateBlock, createVariableStatement, updateVariableStatement, createEmptyStatement, createExpressionStatement, updateExpressionStatement, createIfStatement, updateIfStatement, createDoStatement, updateDoStatement, createWhileStatement, updateWhileStatement, createForStatement, updateForStatement, createForInStatement, updateForInStatement, createForOfStatement, updateForOfStatement, createContinueStatement, updateContinueStatement, createBreakStatement, updateBreakStatement, createReturnStatement, updateReturnStatement, createWithStatement, updateWithStatement, createSwitchStatement, updateSwitchStatement, createLabeledStatement, updateLabeledStatement, createThrowStatement, updateThrowStatement, createTryStatement, updateTryStatement, createDebuggerStatement, createVariableDeclaration, updateVariableDeclaration, createVariableDeclarationList, updateVariableDeclarationList, createFunctionDeclaration, updateFunctionDeclaration, createClassDeclaration, updateClassDeclaration, createInterfaceDeclaration, updateInterfaceDeclaration, createTypeAliasDeclaration, updateTypeAliasDeclaration, createEnumDeclaration, updateEnumDeclaration, createModuleDeclaration, updateModuleDeclaration, createModuleBlock, updateModuleBlock, createCaseBlock, updateCaseBlock, createNamespaceExportDeclaration, updateNamespaceExportDeclaration, createImportEqualsDeclaration, updateImportEqualsDeclaration, createImportDeclaration, updateImportDeclaration, createImportClause, updateImportClause, createNamespaceImport, updateNamespaceImport, createNamespaceExport, updateNamespaceExport, createNamedImports, updateNamedImports, createImportSpecifier, updateImportSpecifier, createExportAssignment, updateExportAssignment, createExportDeclaration, updateExportDeclaration, createNamedExports, updateNamedExports, createExportSpecifier, updateExportSpecifier, createMissingDeclaration, createExternalModuleReference, updateExternalModuleReference, // lazily load factory members for JSDoc types with similar structure get createJSDocAllType() { return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocAllType); }, get createJSDocUnknownType() { return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocUnknownType); }, get createJSDocNonNullableType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocNonNullableType); }, get updateJSDocNonNullableType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocNonNullableType); }, get createJSDocNullableType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocNullableType); }, get updateJSDocNullableType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocNullableType); }, get createJSDocOptionalType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocOptionalType); }, get updateJSDocOptionalType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocOptionalType); }, get createJSDocVariadicType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocVariadicType); }, get updateJSDocVariadicType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocVariadicType); }, get createJSDocNamepathType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocNamepathType); }, get updateJSDocNamepathType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocNamepathType); }, createJSDocFunctionType, updateJSDocFunctionType, createJSDocTypeLiteral, updateJSDocTypeLiteral, createJSDocTypeExpression, updateJSDocTypeExpression, createJSDocSignature, updateJSDocSignature, createJSDocTemplateTag, updateJSDocTemplateTag, createJSDocTypedefTag, updateJSDocTypedefTag, createJSDocParameterTag, updateJSDocParameterTag, createJSDocPropertyTag, updateJSDocPropertyTag, createJSDocCallbackTag, updateJSDocCallbackTag, createJSDocAugmentsTag, updateJSDocAugmentsTag, createJSDocImplementsTag, updateJSDocImplementsTag, // lazily load factory members for JSDoc tags with similar structure get createJSDocTypeTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocTypeTag); }, get updateJSDocTypeTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocTypeTag); }, get createJSDocReturnTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocReturnTag); }, get updateJSDocReturnTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocReturnTag); }, get createJSDocThisTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocThisTag); }, get updateJSDocThisTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocThisTag); }, get createJSDocEnumTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocEnumTag); }, get updateJSDocEnumTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocEnumTag); }, get createJSDocAuthorTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocAuthorTag); }, get updateJSDocAuthorTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocAuthorTag); }, get createJSDocClassTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocClassTag); }, get updateJSDocClassTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocClassTag); }, get createJSDocPublicTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocPublicTag); }, get updateJSDocPublicTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocPublicTag); }, get createJSDocPrivateTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocPrivateTag); }, get updateJSDocPrivateTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocPrivateTag); }, get createJSDocProtectedTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocProtectedTag); }, get updateJSDocProtectedTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocProtectedTag); }, get createJSDocReadonlyTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocReadonlyTag); }, get updateJSDocReadonlyTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocReadonlyTag); }, get createJSDocDeprecatedTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocDeprecatedTag); }, get updateJSDocDeprecatedTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocDeprecatedTag); }, createJSDocUnknownTag, updateJSDocUnknownTag, createJSDocComment, updateJSDocComment, createJsxElement, updateJsxElement, createJsxSelfClosingElement, updateJsxSelfClosingElement, createJsxOpeningElement, updateJsxOpeningElement, createJsxClosingElement, updateJsxClosingElement, createJsxFragment, createJsxText, updateJsxText, createJsxOpeningFragment, createJsxJsxClosingFragment, updateJsxFragment, createJsxAttribute, updateJsxAttribute, createJsxAttributes, updateJsxAttributes, createJsxSpreadAttribute, updateJsxSpreadAttribute, createJsxExpression, updateJsxExpression, createCaseClause, updateCaseClause, createDefaultClause, updateDefaultClause, createHeritageClause, updateHeritageClause, createCatchClause, updateCatchClause, createPropertyAssignment, updatePropertyAssignment, createShorthandPropertyAssignment, updateShorthandPropertyAssignment, createSpreadAssignment, updateSpreadAssignment, createEnumMember, updateEnumMember, createSourceFile, updateSourceFile, createBundle, updateBundle, createUnparsedSource, createUnparsedPrologue, createUnparsedPrepend, createUnparsedTextLike, createUnparsedSyntheticReference, createInputFiles, createSyntheticExpression, createSyntaxList, createNotEmittedStatement, createPartiallyEmittedExpression, updatePartiallyEmittedExpression, createCommaListExpression, updateCommaListExpression, createEndOfDeclarationMarker, createMergeDeclarationMarker, createSyntheticReferenceExpression, updateSyntheticReferenceExpression, cloneNode, // Lazily load factory methods for common operator factories and utilities get createComma() { return getBinaryCreateFunction(SyntaxKind.CommaToken); }, get createAssignment() { return getBinaryCreateFunction(SyntaxKind.EqualsToken) as NodeFactory["createAssignment"]; }, get createLogicalOr() { return getBinaryCreateFunction(SyntaxKind.BarBarToken); }, get createLogicalAnd() { return getBinaryCreateFunction(SyntaxKind.AmpersandAmpersandToken); }, get createBitwiseOr() { return getBinaryCreateFunction(SyntaxKind.BarToken); }, get createBitwiseXor() { return getBinaryCreateFunction(SyntaxKind.CaretToken); }, get createBitwiseAnd() { return getBinaryCreateFunction(SyntaxKind.AmpersandToken); }, get createStrictEquality() { return getBinaryCreateFunction(SyntaxKind.EqualsEqualsEqualsToken); }, get createStrictInequality() { return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsEqualsToken); }, get createEquality() { return getBinaryCreateFunction(SyntaxKind.EqualsEqualsToken); }, get createInequality() { return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsToken); }, get createLessThan() { return getBinaryCreateFunction(SyntaxKind.LessThanToken); }, get createLessThanEquals() { return getBinaryCreateFunction(SyntaxKind.LessThanEqualsToken); }, get createGreaterThan() { return getBinaryCreateFunction(SyntaxKind.GreaterThanToken); }, get createGreaterThanEquals() { return getBinaryCreateFunction(SyntaxKind.GreaterThanEqualsToken); }, get createLeftShift() { return getBinaryCreateFunction(SyntaxKind.LessThanLessThanToken); }, get createRightShift() { return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanToken); }, get createUnsignedRightShift() { return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); }, get createAdd() { return getBinaryCreateFunction(SyntaxKind.PlusToken); }, get createSubtract() { return getBinaryCreateFunction(SyntaxKind.MinusToken); }, get createMultiply() { return getBinaryCreateFunction(SyntaxKind.AsteriskToken); }, get createDivide() { return getBinaryCreateFunction(SyntaxKind.SlashToken); }, get createModulo() { return getBinaryCreateFunction(SyntaxKind.PercentToken); }, get createExponent() { return getBinaryCreateFunction(SyntaxKind.AsteriskAsteriskToken); }, get createPrefixPlus() { return getPrefixUnaryCreateFunction(SyntaxKind.PlusToken); }, get createPrefixMinus() { return getPrefixUnaryCreateFunction(SyntaxKind.MinusToken); }, get createPrefixIncrement() { return getPrefixUnaryCreateFunction(SyntaxKind.PlusPlusToken); }, get createPrefixDecrement() { return getPrefixUnaryCreateFunction(SyntaxKind.MinusMinusToken); }, get createBitwiseNot() { return getPrefixUnaryCreateFunction(SyntaxKind.TildeToken); }, get createLogicalNot() { return getPrefixUnaryCreateFunction(SyntaxKind.ExclamationToken); }, get createPostfixIncrement() { return getPostfixUnaryCreateFunction(SyntaxKind.PlusPlusToken); }, get createPostfixDecrement() { return getPostfixUnaryCreateFunction(SyntaxKind.MinusMinusToken); }, // Compound nodes createImmediatelyInvokedFunctionExpression, createImmediatelyInvokedArrowFunction, createVoidZero, createExportDefault, createExternalModuleExport, createTypeCheck, createMethodCall, createGlobalMethodCall, createFunctionBindCall, createFunctionCallCall, createFunctionApplyCall, createArraySliceCall, createArrayConcatCall, createObjectDefinePropertyCall, createPropertyDescriptor, createCallBinding, // Utilities inlineExpressions, getInternalName, getLocalName, getExportName, getDeclarationName, getNamespaceMemberName, getExternalModuleOrNamespaceExportName, restoreOuterExpressions, restoreEnclosingLabel, createUseStrictPrologue, copyPrologue, copyStandardPrologue, copyCustomPrologue, ensureUseStrict, liftToBlock, mergeLexicalEnvironment, updateModifiers, }; return factory; // @api function createNodeArray(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray { if (elements === undefined || elements === emptyArray) { elements = []; } else if (isNodeArray(elements)) { // Ensure the transform flags have been aggregated for this NodeArray if (elements.transformFlags === undefined) { aggregateChildrenFlags(elements as MutableNodeArray); } Debug.attachNodeArrayDebugInfo(elements); return elements; } // Since the element list of a node array is typically created by starting with an empty array and // repeatedly calling push(), the list may not have the optimal memory layout. We invoke slice() for // small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation. const length = elements.length; const array = >(length >= 1 && length <= 4 ? elements.slice() : elements); setTextRangePosEnd(array, -1, -1); array.hasTrailingComma = !!hasTrailingComma; aggregateChildrenFlags(array); Debug.attachNodeArrayDebugInfo(array); return array; } function createBaseNode(kind: T["kind"]) { return baseFactory.createBaseNode(kind) as Mutable; } function createBaseDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined ) { const node = createBaseNode(kind); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); node.transformFlags |= propagateChildrenFlags(node.decorators) | propagateChildrenFlags(node.modifiers); // NOTE: The following properties are commonly set by the binder and are added here to // ensure declarations have a stable shape. node.symbol = undefined!; // initialized by binder node.localSymbol = undefined!; // initialized by binder node.locals = undefined!; // initialized by binder node.nextContainer = undefined!; // initialized by binder return node; } function createBaseNamedDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined ) { const node = createBaseDeclaration( kind, decorators, modifiers ); name = asName(name); node.name = name; // The PropertyName of a member is allowed to be `await`. // We don't need to exclude `await` for type signatures since types // don't propagate child flags. if (name) { switch (node.kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertyAssignment: if (isIdentifier(name)) { node.transformFlags |= propagateIdentifierNameFlags(name); break; } // fall through default: node.transformFlags |= propagateChildFlags(name); break; } } return node; } function createBaseGenericNamedDeclaration }>( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined ) { const node = createBaseNamedDeclaration( kind, decorators, modifiers, name ); node.typeParameters = asNodeArray(typeParameters); node.transformFlags |= propagateChildrenFlags(node.typeParameters); if (typeParameters) node.transformFlags |= TransformFlags.ContainsTypeScript; return node; } function createBaseSignatureDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined ) { const node = createBaseGenericNamedDeclaration( kind, decorators, modifiers, name, typeParameters ); node.parameters = createNodeArray(parameters); node.type = type; node.transformFlags |= propagateChildrenFlags(node.parameters) | propagateChildFlags(node.type); if (type) node.transformFlags |= TransformFlags.ContainsTypeScript; return node; } function updateBaseSignatureDeclaration(updated: Mutable, original: T) { // copy children used only for error reporting if (original.typeArguments) updated.typeArguments = original.typeArguments; return update(updated, original); } function createBaseFunctionLikeDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, body: T["body"] ) { const node = createBaseSignatureDeclaration( kind, decorators, modifiers, name, typeParameters, parameters, type ); node.body = body; node.transformFlags |= propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait; if (!body) node.transformFlags |= TransformFlags.ContainsTypeScript; return node; } function updateBaseFunctionLikeDeclaration(updated: Mutable, original: T) { // copy children used only for error reporting if (original.exclamationToken) updated.exclamationToken = original.exclamationToken; if (original.typeArguments) updated.typeArguments = original.typeArguments; return updateBaseSignatureDeclaration(updated, original); } function createBaseInterfaceOrClassLikeDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined ) { const node = createBaseGenericNamedDeclaration( kind, decorators, modifiers, name, typeParameters ); node.heritageClauses = asNodeArray(heritageClauses); node.transformFlags |= propagateChildrenFlags(node.heritageClauses); return node; } function createBaseClassLikeDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[] ) { const node = createBaseInterfaceOrClassLikeDeclaration( kind, decorators, modifiers, name, typeParameters, heritageClauses ); node.members = createNodeArray(members); node.transformFlags |= propagateChildrenFlags(node.members); return node; } function createBaseBindingLikeDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | T["name"] | undefined, initializer: Expression | undefined ) { const node = createBaseNamedDeclaration( kind, decorators, modifiers, name ); node.initializer = initializer; node.transformFlags |= propagateChildFlags(node.initializer); return node; } function createBaseVariableLikeDeclaration( kind: T["kind"], decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | T["name"] | undefined, type: TypeNode | undefined, initializer: Expression | undefined ) { const node = createBaseBindingLikeDeclaration( kind, decorators, modifiers, name, initializer ); node.type = type; node.transformFlags |= propagateChildFlags(type); if (type) node.transformFlags |= TransformFlags.ContainsTypeScript; return node; } // // Literals // function createBaseLiteral( kind: T["kind"], text: string ) { const node = createBaseToken(kind); node.text = text; return node; } // @api function createNumericLiteral(value: string | number, numericLiteralFlags: TokenFlags = TokenFlags.None): NumericLiteral { const node = createBaseLiteral(SyntaxKind.NumericLiteral, typeof value === "number" ? value + "" : value); node.numericLiteralFlags = numericLiteralFlags; if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) node.transformFlags |= TransformFlags.ContainsES2015; return node; } // @api function createBigIntLiteral(value: string | PseudoBigInt): BigIntLiteral { const node = createBaseLiteral(SyntaxKind.BigIntLiteral, typeof value === "string" ? value : pseudoBigIntToString(value) + "n"); node.transformFlags |= TransformFlags.ContainsESNext; return node; } function createBaseStringLiteral(text: string, isSingleQuote?: boolean) { const node = createBaseLiteral(SyntaxKind.StringLiteral, text); node.singleQuote = isSingleQuote; return node; } // @api function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral { const node = createBaseStringLiteral(text, isSingleQuote); node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape; if (hasExtendedUnicodeEscape) node.transformFlags |= TransformFlags.ContainsES2015; return node; } // @api function createStringLiteralFromNode(sourceNode: PropertyNameLiteral): StringLiteral { const node = createBaseStringLiteral(getTextOfIdentifierOrLiteral(sourceNode), /*isSingleQuote*/ undefined); node.textSourceNode = sourceNode; return node; } // @api function createRegularExpressionLiteral(text: string): RegularExpressionLiteral { const node = createBaseLiteral(SyntaxKind.RegularExpressionLiteral, text); return node; } // @api function createLiteralLikeNode(kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, text: string): LiteralToken { switch (kind) { case SyntaxKind.NumericLiteral: return createNumericLiteral(text, /*numericLiteralFlags*/ 0); case SyntaxKind.BigIntLiteral: return createBigIntLiteral(text); case SyntaxKind.StringLiteral: return createStringLiteral(text, /*isSingleQuote*/ undefined); case SyntaxKind.JsxText: return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ false); case SyntaxKind.JsxTextAllWhiteSpaces: return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ true); case SyntaxKind.RegularExpressionLiteral: return createRegularExpressionLiteral(text); case SyntaxKind.NoSubstitutionTemplateLiteral: return createTemplateLiteralLikeNode(kind, text, /*rawText*/ undefined, /*templateFlags*/ 0) as NoSubstitutionTemplateLiteral; } } // // Identifiers // function createBaseIdentifier(text: string, originalKeywordKind: SyntaxKind | undefined) { if (originalKeywordKind === undefined && text) { originalKeywordKind = stringToToken(text); } if (originalKeywordKind === SyntaxKind.Identifier) { originalKeywordKind = undefined; } const node = baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as Mutable; node.originalKeywordKind = originalKeywordKind; node.escapedText = escapeLeadingUnderscores(text); return node; } function createBaseGeneratedIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags) { const node = createBaseIdentifier(text, /*originalKeywordKind*/ undefined) as Mutable; node.autoGenerateFlags = autoGenerateFlags; node.autoGenerateId = nextAutoGenerateId; nextAutoGenerateId++; return node; } // @api function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind): Identifier { const node = createBaseIdentifier(text, originalKeywordKind); if (typeArguments) { // NOTE: we do not use `setChildren` here because typeArguments in an identifier do not contribute to transformations node.typeArguments = createNodeArray(typeArguments); } if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) { node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait; } return node; } // @api function updateIdentifier(node: Identifier, typeArguments?: NodeArray | undefined): Identifier { return node.typeArguments !== typeArguments ? update(createIdentifier(idText(node), typeArguments), node) : node; } // @api function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean): GeneratedIdentifier { let flags = GeneratedIdentifierFlags.Auto; if (reservedInNestedScopes) flags |= GeneratedIdentifierFlags.ReservedInNestedScopes; const name = createBaseGeneratedIdentifier("", flags); if (recordTempVariable) { recordTempVariable(name); } return name; } /** Create a unique temporary variable for use in a loop. */ // @api function createLoopVariable(): Identifier { return createBaseGeneratedIdentifier("", GeneratedIdentifierFlags.Loop); } /** Create a unique name based on the supplied text. */ // @api function createUniqueName(text: string, flags: GeneratedIdentifierFlags = GeneratedIdentifierFlags.None): Identifier { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); Debug.assert((flags & (GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)) !== GeneratedIdentifierFlags.FileLevel, "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic"); return createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Unique | flags); } /** Create a unique name generated for a node. */ // @api function getGeneratedNameForNode(node: Node | undefined, flags: GeneratedIdentifierFlags = 0): Identifier { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); const name = createBaseGeneratedIdentifier(node && isIdentifier(node) ? idText(node) : "", GeneratedIdentifierFlags.Node | flags); name.original = node; return name; } // @api function createPrivateIdentifier(text: string): PrivateIdentifier { if (!startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text); const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable; node.escapedText = escapeLeadingUnderscores(text); node.transformFlags |= TransformFlags.ContainsClassFields; return node; } // // Punctuation // function createBaseToken(kind: T["kind"]) { return baseFactory.createBaseTokenNode(kind) as Mutable; } // @api function createToken(token: SyntaxKind.SuperKeyword): SuperExpression; function createToken(token: SyntaxKind.ThisKeyword): ThisExpression; function createToken(token: SyntaxKind.NullKeyword): NullLiteral; function createToken(token: SyntaxKind.TrueKeyword): TrueLiteral; function createToken(token: SyntaxKind.FalseKeyword): FalseLiteral; function createToken(token: TKind): PunctuationToken; function createToken(token: TKind): KeywordTypeNode; function createToken(token: TKind): ModifierToken; function createToken(token: TKind): KeywordToken; function createToken(token: TKind): Token; function createToken(token: TKind): Token; function createToken(token: TKind) { Debug.assert(token >= SyntaxKind.FirstToken && token <= SyntaxKind.LastToken, "Invalid token"); Debug.assert(token <= SyntaxKind.FirstTemplateToken || token >= SyntaxKind.LastTemplateToken, "Invalid token. Use 'createTemplateLiteralLikeNode' to create template literals."); Debug.assert(token <= SyntaxKind.FirstLiteralToken || token >= SyntaxKind.LastLiteralToken, "Invalid token. Use 'createLiteralLikeNode' to create literals."); Debug.assert(token !== SyntaxKind.Identifier, "Invalid token. Use 'createIdentifier' to create identifiers"); const node = createBaseToken>(token); let transformFlags = TransformFlags.None; switch (token) { case SyntaxKind.AsyncKeyword: // 'async' modifier is ES2017 (async functions) or ES2018 (async generators) transformFlags = TransformFlags.ContainsES2017 | TransformFlags.ContainsES2018; break; case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.ReadonlyKeyword: case SyntaxKind.AbstractKeyword: case SyntaxKind.DeclareKeyword: case SyntaxKind.ConstKeyword: case SyntaxKind.AnyKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.BigIntKeyword: case SyntaxKind.NeverKeyword: case SyntaxKind.ObjectKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.VoidKeyword: case SyntaxKind.UnknownKeyword: case SyntaxKind.UndefinedKeyword: // `undefined` is an Identifier in the expression case. transformFlags = TransformFlags.ContainsTypeScript; break; case SyntaxKind.StaticKeyword: case SyntaxKind.SuperKeyword: transformFlags = TransformFlags.ContainsES2015; break; case SyntaxKind.ThisKeyword: // 'this' indicates a lexical 'this' transformFlags = TransformFlags.ContainsLexicalThis; break; } if (transformFlags) { node.transformFlags |= transformFlags; } return node; } // // Reserved words // // @api function createSuper() { return createToken(SyntaxKind.SuperKeyword); } // @api function createThis() { return createToken(SyntaxKind.ThisKeyword); } // @api function createNull() { return createToken(SyntaxKind.NullKeyword); } // @api function createTrue() { return createToken(SyntaxKind.TrueKeyword); } // @api function createFalse() { return createToken(SyntaxKind.FalseKeyword); } // // Modifiers // // @api function createModifier(kind: T) { return createToken(kind); } // @api function createModifiersFromModifierFlags(flags: ModifierFlags) { const result: Modifier[] = []; if (flags & ModifierFlags.Export) { result.push(createModifier(SyntaxKind.ExportKeyword)); } if (flags & ModifierFlags.Ambient) { result.push(createModifier(SyntaxKind.DeclareKeyword)); } if (flags & ModifierFlags.Default) { result.push(createModifier(SyntaxKind.DefaultKeyword)); } if (flags & ModifierFlags.Const) { result.push(createModifier(SyntaxKind.ConstKeyword)); } if (flags & ModifierFlags.Public) { result.push(createModifier(SyntaxKind.PublicKeyword)); } if (flags & ModifierFlags.Private) { result.push(createModifier(SyntaxKind.PrivateKeyword)); } if (flags & ModifierFlags.Protected) { result.push(createModifier(SyntaxKind.ProtectedKeyword)); } if (flags & ModifierFlags.Abstract) { result.push(createModifier(SyntaxKind.AbstractKeyword)); } if (flags & ModifierFlags.Static) { result.push(createModifier(SyntaxKind.StaticKeyword)); } if (flags & ModifierFlags.Readonly) { result.push(createModifier(SyntaxKind.ReadonlyKeyword)); } if (flags & ModifierFlags.Async) { result.push(createModifier(SyntaxKind.AsyncKeyword)); } return result; } // // Names // // @api function createQualifiedName(left: EntityName, right: string | Identifier) { const node = createBaseNode(SyntaxKind.QualifiedName); node.left = left; node.right = asName(right); node.transformFlags |= propagateChildFlags(node.left) | propagateIdentifierNameFlags(node.right); return node; } // @api function updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier) { return node.left !== left || node.right !== right ? update(createQualifiedName(left, right), node) : node; } // @api function createComputedPropertyName(expression: Expression) { const node = createBaseNode(SyntaxKind.ComputedPropertyName); node.expression = parenthesizerRules().parenthesizeExpressionOfComputedPropertyName(expression); node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsES2015 | TransformFlags.ContainsComputedPropertyName; return node; } // @api function updateComputedPropertyName(node: ComputedPropertyName, expression: Expression) { return node.expression !== expression ? update(createComputedPropertyName(expression), node) : node; } // // Signature elements // // @api function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) { const node = createBaseNamedDeclaration( SyntaxKind.TypeParameter, /*decorators*/ undefined, /*modifiers*/ undefined, name ); node.constraint = constraint; node.default = defaultType; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) { return node.name !== name || node.constraint !== constraint || node.default !== defaultType ? update(createTypeParameterDeclaration(name, constraint, defaultType), node) : node; } // @api function createParameterDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression ) { const node = createBaseVariableLikeDeclaration( SyntaxKind.Parameter, decorators, modifiers, name, type, initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer) ); node.dotDotDotToken = dotDotDotToken; node.questionToken = questionToken; if (isThisIdentifier(node.name)) { node.transformFlags = TransformFlags.ContainsTypeScript; } else { node.transformFlags |= propagateChildFlags(node.dotDotDotToken) | propagateChildFlags(node.questionToken); if (questionToken) node.transformFlags |= TransformFlags.ContainsTypeScript; if (modifiersToFlags(node.modifiers) & ModifierFlags.ParameterPropertyModifier) node.transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax; if (initializer || dotDotDotToken) node.transformFlags |= TransformFlags.ContainsES2015; } return node; } // @api function updateParameterDeclaration( node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.questionToken !== questionToken || node.type !== type || node.initializer !== initializer ? update(createParameterDeclaration(decorators, modifiers, dotDotDotToken, name, questionToken, type, initializer), node) : node; } // @api function createDecorator(expression: Expression) { const node = createBaseNode(SyntaxKind.Decorator); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsTypeScript | TransformFlags.ContainsTypeScriptClassSyntax; return node; } // @api function updateDecorator(node: Decorator, expression: Expression) { return node.expression !== expression ? update(createDecorator(expression), node) : node; } // // Type Elements // // @api function createPropertySignature( modifiers: readonly Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined ): PropertySignature { const node = createBaseNamedDeclaration( SyntaxKind.PropertySignature, /*decorators*/ undefined, modifiers, name ); node.type = type; node.questionToken = questionToken; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updatePropertySignature( node: PropertySignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined ) { return node.modifiers !== modifiers || node.name !== name || node.questionToken !== questionToken || node.type !== type ? update(createPropertySignature(modifiers, name, questionToken, type), node) : node; } // @api function createPropertyDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined ) { const node = createBaseVariableLikeDeclaration( SyntaxKind.PropertyDeclaration, decorators, modifiers, name, type, initializer ); node.questionToken = questionOrExclamationToken && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined; node.exclamationToken = questionOrExclamationToken && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined; node.transformFlags |= propagateChildFlags(node.questionToken) | propagateChildFlags(node.exclamationToken) | TransformFlags.ContainsClassFields; if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) { node.transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax; } if (questionOrExclamationToken || modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags |= TransformFlags.ContainsTypeScript; } return node; } // @api function updatePropertyDeclaration( node: PropertyDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.questionToken !== (questionOrExclamationToken !== undefined && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined) || node.exclamationToken !== (questionOrExclamationToken !== undefined && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined) || node.type !== type || node.initializer !== initializer ? update(createPropertyDeclaration(decorators, modifiers, name, questionOrExclamationToken, type, initializer), node) : node; } // @api function createMethodSignature( modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined ) { const node = createBaseSignatureDeclaration( SyntaxKind.MethodSignature, /*decorators*/ undefined, modifiers, name, typeParameters, parameters, type ); node.questionToken = questionToken; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateMethodSignature( node: MethodSignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined ) { return node.modifiers !== modifiers || node.name !== name || node.questionToken !== questionToken || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type ? updateBaseSignatureDeclaration(createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type), node) : node; } // @api function createMethodDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined ) { const node = createBaseFunctionLikeDeclaration( SyntaxKind.MethodDeclaration, decorators, modifiers, name, typeParameters, parameters, type, body ); node.asteriskToken = asteriskToken; node.questionToken = questionToken; node.transformFlags |= propagateChildFlags(node.asteriskToken) | propagateChildFlags(node.questionToken) | TransformFlags.ContainsES2015; if (questionToken) { node.transformFlags |= TransformFlags.ContainsTypeScript; } if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) { if (asteriskToken) { node.transformFlags |= TransformFlags.ContainsES2018; } else { node.transformFlags |= TransformFlags.ContainsES2017; } } else if (asteriskToken) { node.transformFlags |= TransformFlags.ContainsGenerator; } return node; } // @api function updateMethodDeclaration( node: MethodDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken || node.name !== name || node.questionToken !== questionToken || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body ? updateBaseFunctionLikeDeclaration(createMethodDeclaration(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node) : node; } // @api function createConstructorDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined ) { const node = createBaseFunctionLikeDeclaration( SyntaxKind.Constructor, decorators, modifiers, /*name*/ undefined, /*typeParameters*/ undefined, parameters, /*type*/ undefined, body ); node.transformFlags |= TransformFlags.ContainsES2015; return node; } // @api function updateConstructorDeclaration( node: ConstructorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.parameters !== parameters || node.body !== body ? updateBaseFunctionLikeDeclaration(createConstructorDeclaration(decorators, modifiers, parameters, body), node) : node; } // @api function createGetAccessorDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined ) { return createBaseFunctionLikeDeclaration( SyntaxKind.GetAccessor, decorators, modifiers, name, /*typeParameters*/ undefined, parameters, type, body ); } // @api function updateGetAccessorDeclaration( node: GetAccessorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.parameters !== parameters || node.type !== type || node.body !== body ? updateBaseFunctionLikeDeclaration(createGetAccessorDeclaration(decorators, modifiers, name, parameters, type, body), node) : node; } // @api function createSetAccessorDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined ) { return createBaseFunctionLikeDeclaration( SyntaxKind.SetAccessor, decorators, modifiers, name, /*typeParameters*/ undefined, parameters, /*type*/ undefined, body ); } // @api function updateSetAccessorDeclaration( node: SetAccessorDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.parameters !== parameters || node.body !== body ? updateBaseFunctionLikeDeclaration(createSetAccessorDeclaration(decorators, modifiers, name, parameters, body), node) : node; } // @api function createCallSignature( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined ): CallSignatureDeclaration { const node = createBaseSignatureDeclaration( SyntaxKind.CallSignature, /*decorators*/ undefined, /*modifiers*/ undefined, /*name*/ undefined, typeParameters, parameters, type ); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateCallSignature( node: CallSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined ) { return node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type ? updateBaseSignatureDeclaration(createCallSignature(typeParameters, parameters, type), node) : node; } // @api function createConstructSignature( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined ): ConstructSignatureDeclaration { const node = createBaseSignatureDeclaration( SyntaxKind.ConstructSignature, /*decorators*/ undefined, /*modifiers*/ undefined, /*name*/ undefined, typeParameters, parameters, type ); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateConstructSignature( node: ConstructSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined ) { return node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type ? updateBaseSignatureDeclaration(createConstructSignature(typeParameters, parameters, type), node) : node; } // @api function createIndexSignature( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined ): IndexSignatureDeclaration { const node = createBaseSignatureDeclaration( SyntaxKind.IndexSignature, decorators, modifiers, /*name*/ undefined, /*typeParameters*/ undefined, parameters, type ); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateIndexSignature( node: IndexSignatureDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode ) { return node.parameters !== parameters || node.type !== type || node.decorators !== decorators || node.modifiers !== modifiers ? updateBaseSignatureDeclaration(createIndexSignature(decorators, modifiers, parameters, type), node) : node; } // // Types // // @api function createKeywordTypeNode(kind: TKind) { return createToken(kind); } // @api function createTypePredicateNode(assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) { const node = createBaseNode(SyntaxKind.TypePredicate); node.assertsModifier = assertsModifier; node.parameterName = asName(parameterName); node.type = type; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) { return node.assertsModifier !== assertsModifier || node.parameterName !== parameterName || node.type !== type ? update(createTypePredicateNode(assertsModifier, parameterName, type), node) : node; } // @api function createTypeReferenceNode(typeName: string | EntityName, typeArguments: readonly TypeNode[] | undefined) { const node = createBaseNode(SyntaxKind.TypeReference); node.typeName = asName(typeName); node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments)); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined) { return node.typeName !== typeName || node.typeArguments !== typeArguments ? update(createTypeReferenceNode(typeName, typeArguments), node) : node; } // @api function createFunctionTypeNode( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined ): FunctionTypeNode { const node = createBaseSignatureDeclaration( SyntaxKind.FunctionType, /*decorators*/ undefined, /*modifiers*/ undefined, /*name*/ undefined, typeParameters, parameters, type ); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateFunctionTypeNode( node: FunctionTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined ) { return node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type ? updateBaseSignatureDeclaration(createFunctionTypeNode(typeParameters, parameters, type), node) : node; } // @api function createConstructorTypeNode( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined ): ConstructorTypeNode { const node = createBaseSignatureDeclaration( SyntaxKind.ConstructorType, /*decorators*/ undefined, /*modifiers*/ undefined, /*name*/ undefined, typeParameters, parameters, type ); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateConstructorTypeNode( node: ConstructorTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined ) { return node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type ? updateBaseSignatureDeclaration(createConstructorTypeNode(typeParameters, parameters, type), node) : node; } // @api function createTypeQueryNode(exprName: EntityName) { const node = createBaseNode(SyntaxKind.TypeQuery); node.exprName = exprName; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName) { return node.exprName !== exprName ? update(createTypeQueryNode(exprName), node) : node; } // @api function createTypeLiteralNode(members: readonly TypeElement[] | undefined) { const node = createBaseNode(SyntaxKind.TypeLiteral); node.members = createNodeArray(members); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray) { return node.members !== members ? update(createTypeLiteralNode(members), node) : node; } // @api function createArrayTypeNode(elementType: TypeNode) { const node = createBaseNode(SyntaxKind.ArrayType); node.elementType = parenthesizerRules().parenthesizeElementTypeOfArrayType(elementType); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode { return node.elementType !== elementType ? update(createArrayTypeNode(elementType), node) : node; } // @api function createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]) { const node = createBaseNode(SyntaxKind.TupleType); node.elements = createNodeArray(elements); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]) { return node.elements !== elements ? update(createTupleTypeNode(elements), node) : node; } // @api function createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { const node = createBaseNode(SyntaxKind.NamedTupleMember); node.dotDotDotToken = dotDotDotToken; node.name = name; node.questionToken = questionToken; node.type = type; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { return node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.questionToken !== questionToken || node.type !== type ? update(createNamedTupleMember(dotDotDotToken, name, questionToken, type), node) : node; } // @api function createOptionalTypeNode(type: TypeNode) { const node = createBaseNode(SyntaxKind.OptionalType); node.type = parenthesizerRules().parenthesizeElementTypeOfArrayType(type); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode { return node.type !== type ? update(createOptionalTypeNode(type), node) : node; } // @api function createRestTypeNode(type: TypeNode) { const node = createBaseNode(SyntaxKind.RestType); node.type = type; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateRestTypeNode(node: RestTypeNode, type: TypeNode): RestTypeNode { return node.type !== type ? update(createRestTypeNode(type), node) : node; } function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[]) { const node = createBaseNode(kind); node.types = parenthesizerRules().parenthesizeConstituentTypesOfUnionOrIntersectionType(types); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } function updateUnionOrIntersectionTypeNode(node: T, types: NodeArray): T { return node.types !== types ? update(createUnionOrIntersectionTypeNode(node.kind, types), node) : node; } // @api function createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode { return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types); } // @api function updateUnionTypeNode(node: UnionTypeNode, types: NodeArray) { return updateUnionOrIntersectionTypeNode(node, types); } // @api function createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode { return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types); } // @api function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray) { return updateUnionOrIntersectionTypeNode(node, types); } // @api function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { const node = createBaseNode(SyntaxKind.ConditionalType); node.checkType = parenthesizerRules().parenthesizeMemberOfConditionalType(checkType); node.extendsType = parenthesizerRules().parenthesizeMemberOfConditionalType(extendsType); node.trueType = trueType; node.falseType = falseType; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { return node.checkType !== checkType || node.extendsType !== extendsType || node.trueType !== trueType || node.falseType !== falseType ? update(createConditionalTypeNode(checkType, extendsType, trueType, falseType), node) : node; } // @api function createInferTypeNode(typeParameter: TypeParameterDeclaration) { const node = createBaseNode(SyntaxKind.InferType); node.typeParameter = typeParameter; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration) { return node.typeParameter !== typeParameter ? update(createInferTypeNode(typeParameter), node) : node; } // @api function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf = false) { const node = createBaseNode(SyntaxKind.ImportType); node.argument = argument; node.qualifier = qualifier; node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments); node.isTypeOf = isTypeOf; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf = node.isTypeOf) { return node.argument !== argument || node.qualifier !== qualifier || node.typeArguments !== typeArguments || node.isTypeOf !== isTypeOf ? update(createImportTypeNode(argument, qualifier, typeArguments, isTypeOf), node) : node; } // @api function createParenthesizedType(type: TypeNode) { const node = createBaseNode(SyntaxKind.ParenthesizedType); node.type = type; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode) { return node.type !== type ? update(createParenthesizedType(type), node) : node; } // @api function createThisTypeNode() { const node = createBaseNode(SyntaxKind.ThisType); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode { const node = createBaseNode(SyntaxKind.TypeOperator); node.operator = operator; node.type = parenthesizerRules().parenthesizeMemberOfElementType(type); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode) { return node.type !== type ? update(createTypeOperatorNode(node.operator, type), node) : node; } // @api function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) { const node = createBaseNode(SyntaxKind.IndexedAccessType); node.objectType = parenthesizerRules().parenthesizeMemberOfElementType(objectType); node.indexType = indexType; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode) { return node.objectType !== objectType || node.indexType !== indexType ? update(createIndexedAccessTypeNode(objectType, indexType), node) : node; } // @api function createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode { const node = createBaseNode(SyntaxKind.MappedType); node.readonlyToken = readonlyToken; node.typeParameter = typeParameter; node.questionToken = questionToken; node.type = type; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode { return node.readonlyToken !== readonlyToken || node.typeParameter !== typeParameter || node.questionToken !== questionToken || node.type !== type ? update(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), node) : node; } // @api function createLiteralTypeNode(literal: LiteralTypeNode["literal"]) { const node = createBaseNode(SyntaxKind.LiteralType); node.literal = literal; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]) { return node.literal !== literal ? update(createLiteralTypeNode(literal), node) : node; } // // Binding Patterns // // @api function createObjectBindingPattern(elements: readonly BindingElement[]) { const node = createBaseNode(SyntaxKind.ObjectBindingPattern); node.elements = createNodeArray(elements); node.transformFlags |= propagateChildrenFlags(node.elements) | TransformFlags.ContainsES2015 | TransformFlags.ContainsBindingPattern; if (node.transformFlags & TransformFlags.ContainsRestOrSpread) { node.transformFlags |= TransformFlags.ContainsES2018 | TransformFlags.ContainsObjectRestOrSpread; } return node; } // @api function updateObjectBindingPattern(node: ObjectBindingPattern, elements: readonly BindingElement[]) { return node.elements !== elements ? update(createObjectBindingPattern(elements), node) : node; } // @api function createArrayBindingPattern(elements: readonly ArrayBindingElement[]) { const node = createBaseNode(SyntaxKind.ArrayBindingPattern); node.elements = createNodeArray(elements); node.transformFlags |= propagateChildrenFlags(node.elements) | TransformFlags.ContainsES2015 | TransformFlags.ContainsBindingPattern; return node; } // @api function updateArrayBindingPattern(node: ArrayBindingPattern, elements: readonly ArrayBindingElement[]) { return node.elements !== elements ? update(createArrayBindingPattern(elements), node) : node; } // @api function createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression) { const node = createBaseBindingLikeDeclaration( SyntaxKind.BindingElement, /*decorators*/ undefined, /*modifiers*/ undefined, name, initializer ); node.propertyName = asName(propertyName); node.dotDotDotToken = dotDotDotToken; node.transformFlags |= propagateChildFlags(node.dotDotDotToken) | TransformFlags.ContainsES2015; if (node.propertyName) { node.transformFlags |= isIdentifier(node.propertyName) ? propagateIdentifierNameFlags(node.propertyName) : propagateChildFlags(node.propertyName); } if (dotDotDotToken) node.transformFlags |= TransformFlags.ContainsRestOrSpread; return node; } // @api function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined) { return node.propertyName !== propertyName || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.initializer !== initializer ? update(createBindingElement(dotDotDotToken, propertyName, name, initializer), node) : node; } // // Expression // function createBaseExpression(kind: T["kind"]) { const node = createBaseNode(kind); // the following properties are commonly set by the checker/binder return node; } // @api function createArrayLiteralExpression(elements?: readonly Expression[], multiLine?: boolean) { const node = createBaseExpression(SyntaxKind.ArrayLiteralExpression); node.elements = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(elements)); node.multiLine = multiLine; node.transformFlags |= propagateChildrenFlags(node.elements); return node; } // @api function updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]) { return node.elements !== elements ? update(createArrayLiteralExpression(elements, node.multiLine), node) : node; } // @api function createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean) { const node = createBaseExpression(SyntaxKind.ObjectLiteralExpression); node.properties = createNodeArray(properties); node.multiLine = multiLine; node.transformFlags |= propagateChildrenFlags(node.properties); return node; } // @api function updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) { return node.properties !== properties ? update(createObjectLiteralExpression(properties, node.multiLine), node) : node; } // @api function createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier) { const node = createBaseExpression(SyntaxKind.PropertyAccessExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.name = asName(name); node.transformFlags = propagateChildFlags(node.expression) | (isIdentifier(node.name) ? propagateIdentifierNameFlags(node.name) : propagateChildFlags(node.name)); if (isSuperKeyword(expression)) { // super method calls require a lexical 'this' // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators node.transformFlags |= TransformFlags.ContainsES2017 | TransformFlags.ContainsES2018; } return node; } // @api function updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) { if (isPropertyAccessChain(node)) { return updatePropertyAccessChain(node, expression, node.questionDotToken, cast(name, isIdentifier)); } return node.expression !== expression || node.name !== name ? update(createPropertyAccessExpression(expression, name), node) : node; } // @api function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) { const node = createBaseExpression(SyntaxKind.PropertyAccessExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.questionDotToken = questionDotToken; node.name = asName(name); node.transformFlags |= TransformFlags.ContainsES2020 | propagateChildFlags(node.expression) | propagateChildFlags(node.questionDotToken) | (isIdentifier(node.name) ? propagateIdentifierNameFlags(node.name) : propagateChildFlags(node.name)); return node; } // @api function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) { Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead."); // Because we are updating an existing PropertyAccessChain we want to inherit its emitFlags // instead of using the default from createPropertyAccess return node.expression !== expression || node.questionDotToken !== questionDotToken || node.name !== name ? update(createPropertyAccessChain(expression, questionDotToken, name), node) : node; } // @api function createElementAccessExpression(expression: Expression, index: number | Expression) { const node = createBaseExpression(SyntaxKind.ElementAccessExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.argumentExpression = asExpression(index); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.argumentExpression); if (isSuperKeyword(expression)) { // super method calls require a lexical 'this' // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators node.transformFlags |= TransformFlags.ContainsES2017 | TransformFlags.ContainsES2018; } return node; } // @api function updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) { if (isElementAccessChain(node)) { return updateElementAccessChain(node, expression, node.questionDotToken, argumentExpression); } return node.expression !== expression || node.argumentExpression !== argumentExpression ? update(createElementAccessExpression(expression, argumentExpression), node) : node; } // @api function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression) { const node = createBaseExpression(SyntaxKind.ElementAccessExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.questionDotToken = questionDotToken; node.argumentExpression = asExpression(index); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.questionDotToken) | propagateChildFlags(node.argumentExpression) | TransformFlags.ContainsES2020; return node; } // @api function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression) { Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead."); // Because we are updating an existing ElementAccessChain we want to inherit its emitFlags // instead of using the default from createElementAccess return node.expression !== expression || node.questionDotToken !== questionDotToken || node.argumentExpression !== argumentExpression ? update(createElementAccessChain(expression, questionDotToken, argumentExpression), node) : node; } // @api function createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { const node = createBaseExpression(SyntaxKind.CallExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.typeArguments = asNodeArray(typeArguments); node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray)); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildrenFlags(node.typeArguments) | propagateChildrenFlags(node.arguments); if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } if (isImportKeyword(node.expression)) { node.transformFlags |= TransformFlags.ContainsDynamicImport; } else if (isSuperProperty(node.expression)) { node.transformFlags |= TransformFlags.ContainsLexicalThis; } return node; } // @api function updateCallExpression(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) { if (isCallChain(node)) { return updateCallChain(node, expression, node.questionDotToken, typeArguments, argumentsArray); } return node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray ? update(createCallExpression(expression, typeArguments, argumentsArray), node) : node; } // @api function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { const node = createBaseExpression(SyntaxKind.CallExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.questionDotToken = questionDotToken; node.typeArguments = asNodeArray(typeArguments); node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray)); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.questionDotToken) | propagateChildrenFlags(node.typeArguments) | propagateChildrenFlags(node.arguments) | TransformFlags.ContainsES2020; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } if (isSuperProperty(node.expression)) { node.transformFlags |= TransformFlags.ContainsLexicalThis; } return node; } // @api function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) { Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallExpression using updateCallChain. Use updateCall instead."); return node.expression !== expression || node.questionDotToken !== questionDotToken || node.typeArguments !== typeArguments || node.arguments !== argumentsArray ? update(createCallChain(expression, questionDotToken, typeArguments, argumentsArray), node) : node; } // @api function createNewExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { const node = createBaseExpression(SyntaxKind.NewExpression); node.expression = parenthesizerRules().parenthesizeExpressionOfNew(expression); node.typeArguments = asNodeArray(typeArguments); node.arguments = argumentsArray ? parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(argumentsArray) : undefined; node.transformFlags |= propagateChildFlags(node.expression) | propagateChildrenFlags(node.typeArguments) | propagateChildrenFlags(node.arguments) | TransformFlags.ContainsES2020; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } return node; } // @api function updateNewExpression(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { return node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray ? update(createNewExpression(expression, typeArguments, argumentsArray), node) : node; } // @api function createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) { const node = createBaseExpression(SyntaxKind.TaggedTemplateExpression); node.tag = parenthesizerRules().parenthesizeLeftSideOfAccess(tag); node.typeArguments = asNodeArray(typeArguments); node.template = template; node.transformFlags |= propagateChildFlags(node.tag) | propagateChildrenFlags(node.typeArguments) | propagateChildFlags(node.template) | TransformFlags.ContainsES2015; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } if (hasInvalidEscape(node.template)) { node.transformFlags |= TransformFlags.ContainsES2018; } return node; } // @api function updateTaggedTemplateExpression(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) { return node.tag !== tag || node.typeArguments !== typeArguments || node.template !== template ? update(createTaggedTemplateExpression(tag, typeArguments, template), node) : node; } // @api function createTypeAssertion(type: TypeNode, expression: Expression) { const node = createBaseExpression(SyntaxKind.TypeAssertionExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); node.type = type; node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.type) | TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression) { return node.type !== type || node.expression !== expression ? update(createTypeAssertion(type, expression), node) : node; } // @api function createParenthesizedExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.ParenthesizedExpression); node.expression = expression; node.transformFlags = propagateChildFlags(node.expression); return node; } // @api function updateParenthesizedExpression(node: ParenthesizedExpression, expression: Expression) { return node.expression !== expression ? update(createParenthesizedExpression(expression), node) : node; } // @api function 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 ) { const node = createBaseFunctionLikeDeclaration( SyntaxKind.FunctionExpression, /*decorators*/ undefined, modifiers, name, typeParameters, parameters, type, body ); node.asteriskToken = asteriskToken; node.transformFlags |= propagateChildFlags(node.asteriskToken); if (node.typeParameters) { node.transformFlags |= TransformFlags.ContainsTypeScript; } if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) { if (node.asteriskToken) { node.transformFlags |= TransformFlags.ContainsES2018; } else { node.transformFlags |= TransformFlags.ContainsES2017; } } else if (node.asteriskToken) { node.transformFlags |= TransformFlags.ContainsGenerator; } return node; } // @api function 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 ) { return node.name !== name || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body ? updateBaseFunctionLikeDeclaration(createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node) : node; } // @api function createArrowFunction( modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody ) { const node = createBaseFunctionLikeDeclaration( SyntaxKind.ArrowFunction, /*decorators*/ undefined, modifiers, /*name*/ undefined, typeParameters, parameters, type, parenthesizerRules().parenthesizeConciseBodyOfArrowFunction(body) ); node.equalsGreaterThanToken = equalsGreaterThanToken ?? createToken(SyntaxKind.EqualsGreaterThanToken); node.transformFlags |= propagateChildFlags(node.equalsGreaterThanToken) | TransformFlags.ContainsES2015; if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) { node.transformFlags |= TransformFlags.ContainsES2017; } return node; } // @api function updateArrowFunction( node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody ): ArrowFunction { return node.modifiers !== modifiers || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.equalsGreaterThanToken !== equalsGreaterThanToken || node.body !== body ? updateBaseFunctionLikeDeclaration(createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), node) : node; } // @api function createDeleteExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.DeleteExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); node.transformFlags |= propagateChildFlags(node.expression); return node; } // @api function updateDeleteExpression(node: DeleteExpression, expression: Expression) { return node.expression !== expression ? update(createDeleteExpression(expression), node) : node; } // @api function createTypeOfExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.TypeOfExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); node.transformFlags |= propagateChildFlags(node.expression); return node; } // @api function updateTypeOfExpression(node: TypeOfExpression, expression: Expression) { return node.expression !== expression ? update(createTypeOfExpression(expression), node) : node; } // @api function createVoidExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.VoidExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); node.transformFlags |= propagateChildFlags(node.expression); return node; } // @api function updateVoidExpression(node: VoidExpression, expression: Expression) { return node.expression !== expression ? update(createVoidExpression(expression), node) : node; } // @api function createAwaitExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.AwaitExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsES2017 | TransformFlags.ContainsES2018 | TransformFlags.ContainsAwait; return node; } // @api function updateAwaitExpression(node: AwaitExpression, expression: Expression) { return node.expression !== expression ? update(createAwaitExpression(expression), node) : node; } // @api function createPrefixUnaryExpression(operator: PrefixUnaryOperator, operand: Expression) { const node = createBaseExpression(SyntaxKind.PrefixUnaryExpression); node.operator = operator; node.operand = parenthesizerRules().parenthesizeOperandOfPrefixUnary(operand); node.transformFlags |= propagateChildFlags(node.operand); return node; } // @api function updatePrefixUnaryExpression(node: PrefixUnaryExpression, operand: Expression) { return node.operand !== operand ? update(createPrefixUnaryExpression(node.operator, operand), node) : node; } // @api function createPostfixUnaryExpression(operand: Expression, operator: PostfixUnaryOperator) { const node = createBaseExpression(SyntaxKind.PostfixUnaryExpression); node.operator = operator; node.operand = parenthesizerRules().parenthesizeOperandOfPostfixUnary(operand); node.transformFlags = propagateChildFlags(node.operand); return node; } // @api function updatePostfixUnaryExpression(node: PostfixUnaryExpression, operand: Expression) { return node.operand !== operand ? update(createPostfixUnaryExpression(operand, node.operator), node) : node; } // @api function createBinaryExpression(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression) { const node = createBaseExpression(SyntaxKind.BinaryExpression); const operatorToken = asToken(operator); const operatorKind = operatorToken.kind; node.left = parenthesizerRules().parenthesizeLeftSideOfBinary(operatorKind, left); node.operatorToken = operatorToken; node.right = parenthesizerRules().parenthesizeRightSideOfBinary(operatorKind, node.left, right); node.transformFlags |= propagateChildFlags(node.left) | propagateChildFlags(node.operatorToken) | propagateChildFlags(node.right); if (operatorKind === SyntaxKind.QuestionQuestionToken) { node.transformFlags |= TransformFlags.ContainsES2020; } else if (operatorKind === SyntaxKind.EqualsToken) { if (isObjectLiteralExpression(node.left)) { node.transformFlags |= TransformFlags.ContainsES2015 | TransformFlags.ContainsES2018 | TransformFlags.ContainsDestructuringAssignment; } else if (isArrayLiteralExpression(node.left)) { node.transformFlags |= TransformFlags.ContainsES2015 | TransformFlags.ContainsDestructuringAssignment; } } else if (operatorKind === SyntaxKind.AsteriskAsteriskToken || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken) { node.transformFlags |= TransformFlags.ContainsES2016; } else if (isLogicalOrCoalescingAssignmentOperator(operatorKind)) { node.transformFlags |= TransformFlags.ContainsESNext; } return node; } // @api function updateBinaryExpression(node: BinaryExpression, left: Expression, operator: BinaryOperatorToken, right: Expression) { return node.left !== left || node.operatorToken !== operator || node.right !== right ? update(createBinaryExpression(left, operator, right), node) : node; } // @api function createConditionalExpression(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression) { const node = createBaseExpression(SyntaxKind.ConditionalExpression); node.condition = parenthesizerRules().parenthesizeConditionOfConditionalExpression(condition); node.questionToken = questionToken ?? createToken(SyntaxKind.QuestionToken); node.whenTrue = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenTrue); node.colonToken = colonToken ?? createToken(SyntaxKind.ColonToken); node.whenFalse = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenFalse); node.transformFlags |= propagateChildFlags(node.condition) | propagateChildFlags(node.questionToken) | propagateChildFlags(node.whenTrue) | propagateChildFlags(node.colonToken) | propagateChildFlags(node.whenFalse); return node; } // @api function updateConditionalExpression( node: ConditionalExpression, condition: Expression, questionToken: Token, whenTrue: Expression, colonToken: Token, whenFalse: Expression ): ConditionalExpression { return node.condition !== condition || node.questionToken !== questionToken || node.whenTrue !== whenTrue || node.colonToken !== colonToken || node.whenFalse !== whenFalse ? update(createConditionalExpression(condition, questionToken, whenTrue, colonToken, whenFalse), node) : node; } // @api function createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]) { const node = createBaseExpression(SyntaxKind.TemplateExpression); node.head = head; node.templateSpans = createNodeArray(templateSpans); node.transformFlags |= propagateChildFlags(node.head) | propagateChildrenFlags(node.templateSpans) | TransformFlags.ContainsES2015; return node; } // @api function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]) { return node.head !== head || node.templateSpans !== templateSpans ? update(createTemplateExpression(head, templateSpans), node) : node; } function createTemplateLiteralLikeNodeChecked(kind: TemplateLiteralToken["kind"], text: string | undefined, rawText: string | undefined, templateFlags = TokenFlags.None) { Debug.assert(!(templateFlags & ~TokenFlags.TemplateLiteralLikeFlags), "Unsupported template flags."); // NOTE: without the assignment to `undefined`, we don't narrow the initial type of `cooked`. // eslint-disable-next-line no-undef-init let cooked: string | object | undefined = undefined; if (rawText !== undefined && rawText !== text) { cooked = getCookedText(kind, rawText); if (typeof cooked === "object") { return Debug.fail("Invalid raw text"); } } if (text === undefined) { if (cooked === undefined) { return Debug.fail("Arguments 'text' and 'rawText' may not both be undefined."); } text = cooked; } else if (cooked !== undefined) { Debug.assert(text === cooked, "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'."); } return createTemplateLiteralLikeNode(kind, text, rawText, templateFlags); } // @api function createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string | undefined, templateFlags: TokenFlags | undefined) { const node = createBaseToken(kind); node.text = text; node.rawText = rawText; node.templateFlags = templateFlags! & TokenFlags.TemplateLiteralLikeFlags; node.transformFlags |= TransformFlags.ContainsES2015; if (node.templateFlags) { node.transformFlags |= TransformFlags.ContainsES2018; } return node; } // @api function createTemplateHead(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { return createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateHead, text, rawText, templateFlags); } // @api function createTemplateMiddle(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { return createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateMiddle, text, rawText, templateFlags); } // @api function createTemplateTail(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { return createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateTail, text, rawText, templateFlags); } // @api function createNoSubstitutionTemplateLiteral(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { return createTemplateLiteralLikeNodeChecked(SyntaxKind.NoSubstitutionTemplateLiteral, text, rawText, templateFlags); } // @api function createYieldExpression(asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression { Debug.assert(!asteriskToken || !!expression, "A `YieldExpression` with an asteriskToken must have an expression."); const node = createBaseExpression(SyntaxKind.YieldExpression); node.expression = expression && parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.asteriskToken = asteriskToken; node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.asteriskToken) | TransformFlags.ContainsES2015 | TransformFlags.ContainsES2018 | TransformFlags.ContainsYield; return node; } // @api function updateYieldExpression(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression) { return node.expression !== expression || node.asteriskToken !== asteriskToken ? update(createYieldExpression(asteriskToken, expression), node) : node; } // @api function createSpreadElement(expression: Expression) { const node = createBaseExpression(SyntaxKind.SpreadElement); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsES2015 | TransformFlags.ContainsRestOrSpread; return node; } // @api function updateSpreadElement(node: SpreadElement, expression: Expression) { return node.expression !== expression ? update(createSpreadElement(expression), node) : node; } // @api function createClassExpression( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[] ) { const node = createBaseClassLikeDeclaration( SyntaxKind.ClassExpression, decorators, modifiers, name, typeParameters, heritageClauses, members ); node.transformFlags |= TransformFlags.ContainsES2015; return node; } // @api function updateClassExpression( node: ClassExpression, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[] ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.heritageClauses !== heritageClauses || node.members !== members ? update(createClassExpression(decorators, modifiers, name, typeParameters, heritageClauses, members), node) : node; } // @api function createOmittedExpression() { return createBaseExpression(SyntaxKind.OmittedExpression); } // @api function createExpressionWithTypeArguments(expression: Expression, typeArguments: readonly TypeNode[] | undefined) { const node = createBaseNode(SyntaxKind.ExpressionWithTypeArguments); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildrenFlags(node.typeArguments) | TransformFlags.ContainsES2015; return node; } // @api function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, expression: Expression, typeArguments: readonly TypeNode[] | undefined) { return node.expression !== expression || node.typeArguments !== typeArguments ? update(createExpressionWithTypeArguments(expression, typeArguments), node) : node; } // @api function createAsExpression(expression: Expression, type: TypeNode) { const node = createBaseExpression(SyntaxKind.AsExpression); node.expression = expression; node.type = type; node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.type) | TransformFlags.ContainsTypeScript; return node; } // @api function updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode) { return node.expression !== expression || node.type !== type ? update(createAsExpression(expression, type), node) : node; } // @api function createNonNullExpression(expression: Expression) { const node = createBaseExpression(SyntaxKind.NonNullExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsTypeScript; return node; } // @api function updateNonNullExpression(node: NonNullExpression, expression: Expression) { if (isNonNullChain(node)) { return updateNonNullChain(node, expression); } return node.expression !== expression ? update(createNonNullExpression(expression), node) : node; } // @api function createNonNullChain(expression: Expression) { const node = createBaseExpression(SyntaxKind.NonNullExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsTypeScript; return node; } // @api function updateNonNullChain(node: NonNullChain, expression: Expression) { Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead."); return node.expression !== expression ? update(createNonNullChain(expression), node) : node; } // @api function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier) { const node = createBaseExpression(SyntaxKind.MetaProperty); node.keywordToken = keywordToken; node.name = name; node.transformFlags |= propagateChildFlags(node.name); switch (keywordToken) { case SyntaxKind.NewKeyword: node.transformFlags |= TransformFlags.ContainsES2015; break; case SyntaxKind.ImportKeyword: node.transformFlags |= TransformFlags.ContainsESNext; break; default: return Debug.assertNever(keywordToken); } return node; } // @api function updateMetaProperty(node: MetaProperty, name: Identifier) { return node.name !== name ? update(createMetaProperty(node.keywordToken, name), node) : node; } // // Misc // // @api function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail) { const node = createBaseNode(SyntaxKind.TemplateSpan); node.expression = expression; node.literal = literal; node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.literal) | TransformFlags.ContainsES2015; return node; } // @api function updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail) { return node.expression !== expression || node.literal !== literal ? update(createTemplateSpan(expression, literal), node) : node; } // @api function createSemicolonClassElement() { const node = createBaseNode(SyntaxKind.SemicolonClassElement); node.transformFlags |= TransformFlags.ContainsES2015; return node; } // // Element // // @api function createBlock(statements: readonly Statement[], multiLine?: boolean): Block { const node = createBaseNode(SyntaxKind.Block); node.statements = createNodeArray(statements); node.multiLine = multiLine; node.transformFlags |= propagateChildrenFlags(node.statements); return node; } // @api function updateBlock(node: Block, statements: readonly Statement[]) { return node.statements !== statements ? update(createBlock(statements, node.multiLine), node) : node; } // @api function createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]) { const node = createBaseDeclaration(SyntaxKind.VariableStatement, /*decorators*/ undefined, modifiers); node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList; node.transformFlags |= propagateChildFlags(node.declarationList); if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; } return node; } // @api function updateVariableStatement(node: VariableStatement, modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList) { return node.modifiers !== modifiers || node.declarationList !== declarationList ? update(createVariableStatement(modifiers, declarationList), node) : node; } // @api function createEmptyStatement() { return createBaseNode(SyntaxKind.EmptyStatement); } // @api function createExpressionStatement(expression: Expression): ExpressionStatement { const node = createBaseNode(SyntaxKind.ExpressionStatement); node.expression = parenthesizerRules().parenthesizeExpressionOfExpressionStatement(expression); node.transformFlags |= propagateChildFlags(node.expression); return node; } // @api function updateExpressionStatement(node: ExpressionStatement, expression: Expression) { return node.expression !== expression ? update(createExpressionStatement(expression), node) : node; } // @api function createIfStatement(expression: Expression, thenStatement: Statement, elseStatement?: Statement) { const node = createBaseNode(SyntaxKind.IfStatement); node.expression = expression; node.thenStatement = asEmbeddedStatement(thenStatement); node.elseStatement = asEmbeddedStatement(elseStatement); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.thenStatement) | propagateChildFlags(node.elseStatement); return node; } // @api function updateIfStatement(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined) { return node.expression !== expression || node.thenStatement !== thenStatement || node.elseStatement !== elseStatement ? update(createIfStatement(expression, thenStatement, elseStatement), node) : node; } // @api function createDoStatement(statement: Statement, expression: Expression) { const node = createBaseNode(SyntaxKind.DoStatement); node.statement = asEmbeddedStatement(statement); node.expression = expression; node.transformFlags |= propagateChildFlags(node.statement) | propagateChildFlags(node.expression); return node; } // @api function updateDoStatement(node: DoStatement, statement: Statement, expression: Expression) { return node.statement !== statement || node.expression !== expression ? update(createDoStatement(statement, expression), node) : node; } // @api function createWhileStatement(expression: Expression, statement: Statement) { const node = createBaseNode(SyntaxKind.WhileStatement); node.expression = expression; node.statement = asEmbeddedStatement(statement); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.statement); return node; } // @api function updateWhileStatement(node: WhileStatement, expression: Expression, statement: Statement) { return node.expression !== expression || node.statement !== statement ? update(createWhileStatement(expression, statement), node) : node; } // @api function createForStatement(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) { const node = createBaseNode(SyntaxKind.ForStatement); node.initializer = initializer; node.condition = condition; node.incrementor = incrementor; node.statement = asEmbeddedStatement(statement); node.transformFlags |= propagateChildFlags(node.initializer) | propagateChildFlags(node.condition) | propagateChildFlags(node.incrementor) | propagateChildFlags(node.statement); return node; } // @api function updateForStatement(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) { return node.initializer !== initializer || node.condition !== condition || node.incrementor !== incrementor || node.statement !== statement ? update(createForStatement(initializer, condition, incrementor, statement), node) : node; } // @api function createForInStatement(initializer: ForInitializer, expression: Expression, statement: Statement) { const node = createBaseNode(SyntaxKind.ForInStatement); node.initializer = initializer; node.expression = expression; node.statement = asEmbeddedStatement(statement); node.transformFlags |= propagateChildFlags(node.initializer) | propagateChildFlags(node.expression) | propagateChildFlags(node.statement); return node; } // @api function updateForInStatement(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement) { return node.initializer !== initializer || node.expression !== expression || node.statement !== statement ? update(createForInStatement(initializer, expression, statement), node) : node; } // @api function createForOfStatement(awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) { const node = createBaseNode(SyntaxKind.ForOfStatement); node.awaitModifier = awaitModifier; node.initializer = initializer; node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.statement = asEmbeddedStatement(statement); node.transformFlags |= propagateChildFlags(node.awaitModifier) | propagateChildFlags(node.initializer) | propagateChildFlags(node.expression) | propagateChildFlags(node.statement) | TransformFlags.ContainsES2015; if (awaitModifier) node.transformFlags |= TransformFlags.ContainsES2018; return node; } // @api function updateForOfStatement(node: ForOfStatement, awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) { return node.awaitModifier !== awaitModifier || node.initializer !== initializer || node.expression !== expression || node.statement !== statement ? update(createForOfStatement(awaitModifier, initializer, expression, statement), node) : node; } // @api function createContinueStatement(label?: string | Identifier): ContinueStatement { const node = createBaseNode(SyntaxKind.ContinueStatement); node.label = asName(label); node.transformFlags |= propagateChildFlags(node.label) | TransformFlags.ContainsHoistedDeclarationOrCompletion; return node; } // @api function updateContinueStatement(node: ContinueStatement, label: Identifier | undefined) { return node.label !== label ? update(createContinueStatement(label), node) : node; } // @api function createBreakStatement(label?: string | Identifier): BreakStatement { const node = createBaseNode(SyntaxKind.BreakStatement); node.label = asName(label); node.transformFlags |= propagateChildFlags(node.label) | TransformFlags.ContainsHoistedDeclarationOrCompletion; return node; } // @api function updateBreakStatement(node: BreakStatement, label: Identifier | undefined) { return node.label !== label ? update(createBreakStatement(label), node) : node; } // @api function createReturnStatement(expression?: Expression): ReturnStatement { const node = createBaseNode(SyntaxKind.ReturnStatement); node.expression = expression; // return in an ES2018 async generator must be awaited node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsES2018 | TransformFlags.ContainsHoistedDeclarationOrCompletion; return node; } // @api function updateReturnStatement(node: ReturnStatement, expression: Expression | undefined) { return node.expression !== expression ? update(createReturnStatement(expression), node) : node; } // @api function createWithStatement(expression: Expression, statement: Statement) { const node = createBaseNode(SyntaxKind.WithStatement); node.expression = expression; node.statement = asEmbeddedStatement(statement); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.statement); return node; } // @api function updateWithStatement(node: WithStatement, expression: Expression, statement: Statement) { return node.expression !== expression || node.statement !== statement ? update(createWithStatement(expression, statement), node) : node; } // @api function createSwitchStatement(expression: Expression, caseBlock: CaseBlock): SwitchStatement { const node = createBaseNode(SyntaxKind.SwitchStatement); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.caseBlock = caseBlock; node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.caseBlock); return node; } // @api function updateSwitchStatement(node: SwitchStatement, expression: Expression, caseBlock: CaseBlock) { return node.expression !== expression || node.caseBlock !== caseBlock ? update(createSwitchStatement(expression, caseBlock), node) : node; } // @api function createLabeledStatement(label: string | Identifier, statement: Statement) { const node = createBaseNode(SyntaxKind.LabeledStatement); node.label = asName(label); node.statement = asEmbeddedStatement(statement); node.transformFlags |= propagateChildFlags(node.label) | propagateChildFlags(node.statement); return node; } // @api function updateLabeledStatement(node: LabeledStatement, label: Identifier, statement: Statement) { return node.label !== label || node.statement !== statement ? update(createLabeledStatement(label, statement), node) : node; } // @api function createThrowStatement(expression: Expression) { const node = createBaseNode(SyntaxKind.ThrowStatement); node.expression = expression; node.transformFlags |= propagateChildFlags(node.expression); return node; } // @api function updateThrowStatement(node: ThrowStatement, expression: Expression) { return node.expression !== expression ? update(createThrowStatement(expression), node) : node; } // @api function createTryStatement(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) { const node = createBaseNode(SyntaxKind.TryStatement); node.tryBlock = tryBlock; node.catchClause = catchClause; node.finallyBlock = finallyBlock; node.transformFlags |= propagateChildFlags(node.tryBlock) | propagateChildFlags(node.catchClause) | propagateChildFlags(node.finallyBlock); return node; } // @api function updateTryStatement(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) { return node.tryBlock !== tryBlock || node.catchClause !== catchClause || node.finallyBlock !== finallyBlock ? update(createTryStatement(tryBlock, catchClause, finallyBlock), node) : node; } // @api function createDebuggerStatement() { return createBaseNode(SyntaxKind.DebuggerStatement); } // @api function createVariableDeclaration(name: string | BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { const node = createBaseVariableLikeDeclaration( SyntaxKind.VariableDeclaration, /*decorators*/ undefined, /*modifiers*/ undefined, name, type, initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer) ); node.exclamationToken = exclamationToken; node.transformFlags |= propagateChildFlags(node.exclamationToken); if (exclamationToken) { node.transformFlags |= TransformFlags.ContainsTypeScript; } return node; } // @api function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { return node.name !== name || node.type !== type || node.exclamationToken !== exclamationToken || node.initializer !== initializer ? update(createVariableDeclaration(name, exclamationToken, type, initializer), node) : node; } // @api function createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags = NodeFlags.None) { const node = createBaseNode(SyntaxKind.VariableDeclarationList); node.flags |= flags & NodeFlags.BlockScoped; node.declarations = createNodeArray(declarations); node.transformFlags |= propagateChildrenFlags(node.declarations) | TransformFlags.ContainsHoistedDeclarationOrCompletion; if (flags & NodeFlags.BlockScoped) { node.transformFlags |= TransformFlags.ContainsES2015 | TransformFlags.ContainsBlockScopedBinding; } return node; } // @api function updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]) { return node.declarations !== declarations ? update(createVariableDeclarationList(declarations, node.flags), node) : node; } // @api function createFunctionDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined ) { const node = createBaseFunctionLikeDeclaration( SyntaxKind.FunctionDeclaration, decorators, modifiers, name, typeParameters, parameters, type, body ); node.asteriskToken = asteriskToken; if (!node.body || modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; } else { node.transformFlags |= propagateChildFlags(node.asteriskToken) | TransformFlags.ContainsHoistedDeclarationOrCompletion; if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) { if (node.asteriskToken) { node.transformFlags |= TransformFlags.ContainsES2018; } else { node.transformFlags |= TransformFlags.ContainsES2017; } } else if (node.asteriskToken) { node.transformFlags |= TransformFlags.ContainsGenerator; } } return node; } // @api function updateFunctionDeclaration( node: FunctionDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body ? updateBaseFunctionLikeDeclaration(createFunctionDeclaration(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body), node) : node; } // @api function createClassDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[] ) { const node = createBaseClassLikeDeclaration( SyntaxKind.ClassDeclaration, decorators, modifiers, name, typeParameters, heritageClauses, members ); if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; } else { node.transformFlags |= TransformFlags.ContainsES2015; if (node.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax) { node.transformFlags |= TransformFlags.ContainsTypeScript; } } return node; } // @api function updateClassDeclaration( node: ClassDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[] ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.heritageClauses !== heritageClauses || node.members !== members ? update(createClassDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node) : node; } // @api function createInterfaceDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[] ) { const node = createBaseInterfaceOrClassLikeDeclaration( SyntaxKind.InterfaceDeclaration, decorators, modifiers, name, typeParameters, heritageClauses ); node.members = createNodeArray(members); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateInterfaceDeclaration( node: InterfaceDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[] ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.heritageClauses !== heritageClauses || node.members !== members ? update(createInterfaceDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node) : node; } // @api function createTypeAliasDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode ) { const node = createBaseGenericNamedDeclaration( SyntaxKind.TypeAliasDeclaration, decorators, modifiers, name, typeParameters ); node.type = type; node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeAliasDeclaration( node: TypeAliasDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.type !== type ? update(createTypeAliasDeclaration(decorators, modifiers, name, typeParameters, type), node) : node; } // @api function createEnumDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, members: readonly EnumMember[] ) { const node = createBaseNamedDeclaration( SyntaxKind.EnumDeclaration, decorators, modifiers, name ); node.members = createNodeArray(members); node.transformFlags |= propagateChildrenFlags(node.members) | TransformFlags.ContainsTypeScript; node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Enum declarations cannot contain `await` return node; } // @api function updateEnumDeclaration( node: EnumDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, members: readonly EnumMember[]) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.members !== members ? update(createEnumDeclaration(decorators, modifiers, name, members), node) : node; } // @api function createModuleDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags = NodeFlags.None ) { const node = createBaseDeclaration( SyntaxKind.ModuleDeclaration, decorators, modifiers ); node.flags |= flags & (NodeFlags.Namespace | NodeFlags.NestedNamespace | NodeFlags.GlobalAugmentation); node.name = name; node.body = body; if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; } else { node.transformFlags |= propagateChildFlags(node.name) | propagateChildFlags(node.body) | TransformFlags.ContainsTypeScript; } node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Module declarations cannot contain `await`. return node; } // @api function updateModuleDeclaration( node: ModuleDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.body !== body ? update(createModuleDeclaration(decorators, modifiers, name, body, node.flags), node) : node; } // @api function createModuleBlock(statements: readonly Statement[]) { const node = createBaseNode(SyntaxKind.ModuleBlock); node.statements = createNodeArray(statements); node.transformFlags |= propagateChildrenFlags(node.statements); return node; } // @api function updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]) { return node.statements !== statements ? update(createModuleBlock(statements), node) : node; } // @api function createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock { const node = createBaseNode(SyntaxKind.CaseBlock); node.clauses = createNodeArray(clauses); node.transformFlags |= propagateChildrenFlags(node.clauses); return node; } // @api function updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]) { return node.clauses !== clauses ? update(createCaseBlock(clauses), node) : node; } // @api function createNamespaceExportDeclaration(name: string | Identifier) { const node = createBaseNamedDeclaration( SyntaxKind.NamespaceExportDeclaration, /*decorators*/ undefined, /*modifiers*/ undefined, name ); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api function updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier) { return node.name !== name ? update(createNamespaceExportDeclaration(name), node) : node; } // @api function createImportEqualsDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference ) { const node = createBaseNamedDeclaration( SyntaxKind.ImportEqualsDeclaration, decorators, modifiers, name ); node.moduleReference = moduleReference; node.transformFlags |= propagateChildFlags(node.moduleReference); if (!isExternalModuleReference(node.moduleReference)) node.transformFlags |= TransformFlags.ContainsTypeScript; node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Import= declaration is always parsed in an Await context return node; } // @api function updateImportEqualsDeclaration( node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.moduleReference !== moduleReference ? update(createImportEqualsDeclaration(decorators, modifiers, name, moduleReference), node) : node; } // @api function createImportDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression ): ImportDeclaration { const node = createBaseDeclaration( SyntaxKind.ImportDeclaration, decorators, modifiers ); node.importClause = importClause; node.moduleSpecifier = moduleSpecifier; node.transformFlags |= propagateChildFlags(node.importClause) | propagateChildFlags(node.moduleSpecifier); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateImportDeclaration( node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.importClause !== importClause || node.moduleSpecifier !== moduleSpecifier ? update(createImportDeclaration(decorators, modifiers, importClause, moduleSpecifier), node) : node; } // @api function createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause { const node = createBaseNode(SyntaxKind.ImportClause); node.isTypeOnly = isTypeOnly; node.name = name; node.namedBindings = namedBindings; node.transformFlags |= propagateChildFlags(node.name) | propagateChildFlags(node.namedBindings); if (isTypeOnly) { node.transformFlags |= TransformFlags.ContainsTypeScript; } node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined) { return node.isTypeOnly !== isTypeOnly || node.name !== name || node.namedBindings !== namedBindings ? update(createImportClause(isTypeOnly, name, namedBindings), node) : node; } // @api function createNamespaceImport(name: Identifier): NamespaceImport { const node = createBaseNode(SyntaxKind.NamespaceImport); node.name = name; node.transformFlags |= propagateChildFlags(node.name); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateNamespaceImport(node: NamespaceImport, name: Identifier) { return node.name !== name ? update(createNamespaceImport(name), node) : node; } // @api function createNamespaceExport(name: Identifier): NamespaceExport { const node = createBaseNode(SyntaxKind.NamespaceExport); node.name = name; node.transformFlags |= propagateChildFlags(node.name) | TransformFlags.ContainsESNext; node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateNamespaceExport(node: NamespaceExport, name: Identifier) { return node.name !== name ? update(createNamespaceExport(name), node) : node; } // @api function createNamedImports(elements: readonly ImportSpecifier[]): NamedImports { const node = createBaseNode(SyntaxKind.NamedImports); node.elements = createNodeArray(elements); node.transformFlags |= propagateChildrenFlags(node.elements); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateNamedImports(node: NamedImports, elements: readonly ImportSpecifier[]) { return node.elements !== elements ? update(createNamedImports(elements), node) : node; } // @api function createImportSpecifier(propertyName: Identifier | undefined, name: Identifier) { const node = createBaseNode(SyntaxKind.ImportSpecifier); node.propertyName = propertyName; node.name = name; node.transformFlags |= propagateChildFlags(node.propertyName) | propagateChildFlags(node.name); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier) { return node.propertyName !== propertyName || node.name !== name ? update(createImportSpecifier(propertyName, name), node) : node; } // @api function createExportAssignment( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression ) { const node = createBaseDeclaration( SyntaxKind.ExportAssignment, decorators, modifiers ); node.isExportEquals = isExportEquals; node.expression = isExportEquals ? parenthesizerRules().parenthesizeRightSideOfBinary(SyntaxKind.EqualsToken, /*leftSide*/ undefined, expression) : parenthesizerRules().parenthesizeExpressionOfExportDefault(expression); node.transformFlags |= propagateChildFlags(node.expression); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateExportAssignment( node: ExportAssignment, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, expression: Expression ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.expression !== expression ? update(createExportAssignment(decorators, modifiers, node.isExportEquals, expression), node) : node; } // @api function createExportDeclaration( decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression ) { const node = createBaseDeclaration( SyntaxKind.ExportDeclaration, decorators, modifiers ); node.isTypeOnly = isTypeOnly; node.exportClause = exportClause; node.moduleSpecifier = moduleSpecifier; node.transformFlags |= propagateChildFlags(node.exportClause) | propagateChildFlags(node.moduleSpecifier); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateExportDeclaration( node: ExportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined ) { return node.decorators !== decorators || node.modifiers !== modifiers || node.isTypeOnly !== isTypeOnly || node.exportClause !== exportClause || node.moduleSpecifier !== moduleSpecifier ? update(createExportDeclaration(decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier), node) : node; } // @api function createNamedExports(elements: readonly ExportSpecifier[]) { const node = createBaseNode(SyntaxKind.NamedExports); node.elements = createNodeArray(elements); node.transformFlags |= propagateChildrenFlags(node.elements); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]) { return node.elements !== elements ? update(createNamedExports(elements), node) : node; } // @api function createExportSpecifier(propertyName: string | Identifier | undefined, name: string | Identifier) { const node = createBaseNode(SyntaxKind.ExportSpecifier); node.propertyName = asName(propertyName); node.name = asName(name); node.transformFlags |= propagateChildFlags(node.propertyName) | propagateChildFlags(node.name); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateExportSpecifier(node: ExportSpecifier, propertyName: Identifier | undefined, name: Identifier) { return node.propertyName !== propertyName || node.name !== name ? update(createExportSpecifier(propertyName, name), node) : node; } // @api function createMissingDeclaration() { const node = createBaseDeclaration( SyntaxKind.MissingDeclaration, /*decorators*/ undefined, /*modifiers*/ undefined ); return node; } // // Module references // // @api function createExternalModuleReference(expression: Expression) { const node = createBaseNode(SyntaxKind.ExternalModuleReference); node.expression = expression; node.transformFlags |= propagateChildFlags(node.expression); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression) { return node.expression !== expression ? update(createExternalModuleReference(expression), node) : node; } // // JSDoc // // @api // createJSDocAllType // createJSDocUnknownType function createJSDocPrimaryTypeWorker(kind: T["kind"]) { return createBaseNode(kind); } // @api // createJSDocNonNullableType // createJSDocNullableType // createJSDocOptionalType // createJSDocVariadicType // createJSDocNamepathType function createJSDocUnaryTypeWorker(kind: T["kind"], type: T["type"]): T { const node = createBaseNode(kind); node.type = type; return node; } // @api // updateJSDocNonNullableType // updateJSDocNullableType // updateJSDocOptionalType // updateJSDocVariadicType // updateJSDocNamepathType function updateJSDocUnaryTypeWorker(kind: T["kind"], node: T, type: T["type"]): T { return node.type !== type ? update(createJSDocUnaryTypeWorker(kind, type), node) : node; } // @api function createJSDocFunctionType(parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType { const node = createBaseSignatureDeclaration( SyntaxKind.JSDocFunctionType, /*decorators*/ undefined, /*modifiers*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, parameters, type ); return node; } // @api function updateJSDocFunctionType(node: JSDocFunctionType, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType { return node.parameters !== parameters || node.type !== type ? update(createJSDocFunctionType(parameters, type), node) : node; } // @api function createJSDocTypeLiteral(propertyTags?: readonly JSDocPropertyLikeTag[], isArrayType = false): JSDocTypeLiteral { const node = createBaseNode(SyntaxKind.JSDocTypeLiteral); node.jsDocPropertyTags = asNodeArray(propertyTags); node.isArrayType = isArrayType; return node; } // @api function updateJSDocTypeLiteral(node: JSDocTypeLiteral, propertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean): JSDocTypeLiteral { return node.jsDocPropertyTags !== propertyTags || node.isArrayType !== isArrayType ? update(createJSDocTypeLiteral(propertyTags, isArrayType), node) : node; } // @api function createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression { const node = createBaseNode(SyntaxKind.JSDocTypeExpression); node.type = type; return node; } // @api function updateJSDocTypeExpression(node: JSDocTypeExpression, type: TypeNode): JSDocTypeExpression { return node.type !== type ? update(createJSDocTypeExpression(type), node) : node; } // @api function createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature { const node = createBaseNode(SyntaxKind.JSDocSignature); node.typeParameters = asNodeArray(typeParameters); node.parameters = createNodeArray(parameters); node.type = type; return node; } // @api function updateJSDocSignature(node: JSDocSignature, typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type: JSDocReturnTag | undefined): JSDocSignature { return node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type ? update(createJSDocSignature(typeParameters, parameters, type), node) : node; } function getDefaultTagName(node: JSDocTag) { const defaultTagName = getDefaultTagNameForKind(node.kind); return node.tagName.escapedText === escapeLeadingUnderscores(defaultTagName) ? node.tagName : createIdentifier(defaultTagName); } // @api function createBaseJSDocTag(kind: T["kind"], tagName: Identifier, comment: string | undefined) { const node = createBaseNode(kind); node.tagName = tagName; node.comment = comment; return node; } // @api function createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string): JSDocTemplateTag { const node = createBaseJSDocTag(SyntaxKind.JSDocTemplateTag, tagName ?? createIdentifier("template"), comment); node.constraint = constraint; node.typeParameters = createNodeArray(typeParameters); return node; } // @api function updateJSDocTemplateTag(node: JSDocTemplateTag, tagName: Identifier = getDefaultTagName(node), constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment: string | undefined): JSDocTemplateTag { return node.tagName !== tagName || node.constraint !== constraint || node.typeParameters !== typeParameters || node.comment !== comment ? update(createJSDocTemplateTag(tagName, constraint, typeParameters, comment), node) : node; } // @api function createJSDocTypedefTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string): JSDocTypedefTag { const node = createBaseJSDocTag(SyntaxKind.JSDocTypedefTag, tagName ?? createIdentifier("typedef"), comment); node.typeExpression = typeExpression; node.fullName = fullName; node.name = getJSDocTypeAliasName(fullName); return node; } // @api function updateJSDocTypedefTag(node: JSDocTypedefTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | undefined): JSDocTypedefTag { return node.tagName !== tagName || node.typeExpression !== typeExpression || node.fullName !== fullName || node.comment !== comment ? update(createJSDocTypedefTag(tagName, typeExpression, fullName, comment), node) : node; } // @api function createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocParameterTag { const node = createBaseJSDocTag(SyntaxKind.JSDocParameterTag, tagName ?? createIdentifier("param"), comment); node.typeExpression = typeExpression; node.name = name; node.isNameFirst = !!isNameFirst; node.isBracketed = isBracketed; return node; } // @api function updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocParameterTag { return node.tagName !== tagName || node.name !== name || node.isBracketed !== isBracketed || node.typeExpression !== typeExpression || node.isNameFirst !== isNameFirst || node.comment !== comment ? update(createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), node) : node; } // @api function createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocPropertyTag { const node = createBaseJSDocTag(SyntaxKind.JSDocPropertyTag, tagName ?? createIdentifier("prop"), comment); node.typeExpression = typeExpression; node.name = name; node.isNameFirst = !!isNameFirst; node.isBracketed = isBracketed; return node; } // @api function updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocPropertyTag { return node.tagName !== tagName || node.name !== name || node.isBracketed !== isBracketed || node.typeExpression !== typeExpression || node.isNameFirst !== isNameFirst || node.comment !== comment ? update(createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), node) : node; } // @api function createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string): JSDocCallbackTag { const node = createBaseJSDocTag(SyntaxKind.JSDocCallbackTag, tagName ?? createIdentifier("callback"), comment); node.typeExpression = typeExpression; node.fullName = fullName; node.name = getJSDocTypeAliasName(fullName); return node; } // @api function updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | undefined): JSDocCallbackTag { return node.tagName !== tagName || node.typeExpression !== typeExpression || node.fullName !== fullName || node.comment !== comment ? update(createJSDocCallbackTag(tagName, typeExpression, fullName, comment), node) : node; } // @api function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string): JSDocAugmentsTag { const node = createBaseJSDocTag(SyntaxKind.JSDocAugmentsTag, tagName ?? createIdentifier("augments"), comment); node.class = className; return node; } // @api function updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocAugmentsTag["class"], comment: string | undefined): JSDocAugmentsTag { return node.tagName !== tagName || node.class !== className || node.comment !== comment ? update(createJSDocAugmentsTag(tagName, className, comment), node) : node; } // @api function createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string): JSDocImplementsTag { const node = createBaseJSDocTag(SyntaxKind.JSDocImplementsTag, tagName ?? createIdentifier("implements"), comment); node.class = className; return node; } // @api function updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag { return node.tagName !== tagName || node.class !== className || node.comment !== comment ? update(createJSDocImplementsTag(tagName, className, comment), node) : node; } // @api // createJSDocAuthorTag // createJSDocClassTag // createJSDocPublicTag // createJSDocPrivateTag // createJSDocProtectedTag // createJSDocReadonlyTag // createJSDocDeprecatedTag function createJSDocSimpleTagWorker(kind: T["kind"], tagName: Identifier | undefined, comment?: string) { const node = createBaseJSDocTag(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment); return node; } // @api // updateJSDocAuthorTag // updateJSDocClassTag // updateJSDocPublicTag // updateJSDocPrivateTag // updateJSDocProtectedTag // updateJSDocReadonlyTag // updateJSDocDeprecatedTag function updateJSDocSimpleTagWorker(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), comment: string | undefined) { return node.tagName !== tagName || node.comment !== comment ? update(createJSDocSimpleTagWorker(kind, tagName, comment), node) : node; } // @api // createJSDocTypeTag // createJSDocReturnTag // createJSDocThisTag // createJSDocEnumTag function createJSDocTypeLikeTagWorker(kind: T["kind"], tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string) { const node = createBaseJSDocTag(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment); node.typeExpression = typeExpression; return node; } // @api // updateJSDocTypeTag // updateJSDocReturnTag // updateJSDocThisTag // updateJSDocEnumTag function updateJSDocTypeLikeTagWorker(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, comment: string | undefined) { return node.tagName !== tagName || node.typeExpression !== typeExpression || node.comment !== comment ? update(createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment), node) : node; } // @api function createJSDocUnknownTag(tagName: Identifier, comment?: string): JSDocUnknownTag { const node = createBaseJSDocTag(SyntaxKind.JSDocTag, tagName, comment); return node; } // @api function updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | undefined): JSDocUnknownTag { return node.tagName !== tagName || node.comment !== comment ? update(createJSDocUnknownTag(tagName, comment), node) : node; } // @api function createJSDocComment(comment?: string | undefined, tags?: readonly JSDocTag[] | undefined) { const node = createBaseNode(SyntaxKind.JSDocComment); node.comment = comment; node.tags = asNodeArray(tags); return node; } // @api function updateJSDocComment(node: JSDoc, comment: string | undefined, tags: readonly JSDocTag[] | undefined) { return node.comment !== comment || node.tags !== tags ? update(createJSDocComment(comment, tags), node) : node; } // // JSX // // @api function createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) { const node = createBaseNode(SyntaxKind.JsxElement); node.openingElement = openingElement; node.children = createNodeArray(children); node.closingElement = closingElement; node.transformFlags |= propagateChildFlags(node.openingElement) | propagateChildrenFlags(node.children) | propagateChildFlags(node.closingElement) | TransformFlags.ContainsJsx; return node; } // @api function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) { return node.openingElement !== openingElement || node.children !== children || node.closingElement !== closingElement ? update(createJsxElement(openingElement, children, closingElement), node) : node; } // @api function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { const node = createBaseNode(SyntaxKind.JsxSelfClosingElement); node.tagName = tagName; node.typeArguments = asNodeArray(typeArguments); node.attributes = attributes; node.transformFlags |= propagateChildFlags(node.tagName) | propagateChildrenFlags(node.typeArguments) | propagateChildFlags(node.attributes) | TransformFlags.ContainsJsx; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } return node; } // @api function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { return node.tagName !== tagName || node.typeArguments !== typeArguments || node.attributes !== attributes ? update(createJsxSelfClosingElement(tagName, typeArguments, attributes), node) : node; } // @api function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { const node = createBaseNode(SyntaxKind.JsxOpeningElement); node.tagName = tagName; node.typeArguments = asNodeArray(typeArguments); node.attributes = attributes; node.transformFlags |= propagateChildFlags(node.tagName) | propagateChildrenFlags(node.typeArguments) | propagateChildFlags(node.attributes) | TransformFlags.ContainsJsx; if (typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } return node; } // @api function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { return node.tagName !== tagName || node.typeArguments !== typeArguments || node.attributes !== attributes ? update(createJsxOpeningElement(tagName, typeArguments, attributes), node) : node; } // @api function createJsxClosingElement(tagName: JsxTagNameExpression) { const node = createBaseNode(SyntaxKind.JsxClosingElement); node.tagName = tagName; node.transformFlags |= propagateChildFlags(node.tagName) | TransformFlags.ContainsJsx; return node; } // @api function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression) { return node.tagName !== tagName ? update(createJsxClosingElement(tagName), node) : node; } // @api function createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) { const node = createBaseNode(SyntaxKind.JsxFragment); node.openingFragment = openingFragment; node.children = createNodeArray(children); node.closingFragment = closingFragment; node.transformFlags |= propagateChildFlags(node.openingFragment) | propagateChildrenFlags(node.children) | propagateChildFlags(node.closingFragment) | TransformFlags.ContainsJsx; return node; } // @api function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) { return node.openingFragment !== openingFragment || node.children !== children || node.closingFragment !== closingFragment ? update(createJsxFragment(openingFragment, children, closingFragment), node) : node; } // @api function createJsxText(text: string, containsOnlyTriviaWhiteSpaces?: boolean) { const node = createBaseNode(SyntaxKind.JsxText); node.text = text; node.containsOnlyTriviaWhiteSpaces = !!containsOnlyTriviaWhiteSpaces; node.transformFlags |= TransformFlags.ContainsJsx; return node; } // @api function updateJsxText(node: JsxText, text: string, containsOnlyTriviaWhiteSpaces?: boolean) { return node.text !== text || node.containsOnlyTriviaWhiteSpaces !== containsOnlyTriviaWhiteSpaces ? update(createJsxText(text, containsOnlyTriviaWhiteSpaces), node) : node; } // @api function createJsxOpeningFragment() { const node = createBaseNode(SyntaxKind.JsxOpeningFragment); node.transformFlags |= TransformFlags.ContainsJsx; return node; } // @api function createJsxJsxClosingFragment() { const node = createBaseNode(SyntaxKind.JsxClosingFragment); node.transformFlags |= TransformFlags.ContainsJsx; return node; } // @api function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression | undefined) { const node = createBaseNode(SyntaxKind.JsxAttribute); node.name = name; node.initializer = initializer; node.transformFlags |= propagateChildFlags(node.name) | propagateChildFlags(node.initializer) | TransformFlags.ContainsJsx; return node; } // @api function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression | undefined) { return node.name !== name || node.initializer !== initializer ? update(createJsxAttribute(name, initializer), node) : node; } // @api function createJsxAttributes(properties: readonly JsxAttributeLike[]) { const node = createBaseNode(SyntaxKind.JsxAttributes); node.properties = createNodeArray(properties); node.transformFlags |= propagateChildrenFlags(node.properties) | TransformFlags.ContainsJsx; return node; } // @api function updateJsxAttributes(node: JsxAttributes, properties: readonly JsxAttributeLike[]) { return node.properties !== properties ? update(createJsxAttributes(properties), node) : node; } // @api function createJsxSpreadAttribute(expression: Expression) { const node = createBaseNode(SyntaxKind.JsxSpreadAttribute); node.expression = expression; node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsJsx; return node; } // @api function updateJsxSpreadAttribute(node: JsxSpreadAttribute, expression: Expression) { return node.expression !== expression ? update(createJsxSpreadAttribute(expression), node) : node; } // @api function createJsxExpression(dotDotDotToken: DotDotDotToken | undefined, expression: Expression | undefined) { const node = createBaseNode(SyntaxKind.JsxExpression); node.dotDotDotToken = dotDotDotToken; node.expression = expression; node.transformFlags |= propagateChildFlags(node.dotDotDotToken) | propagateChildFlags(node.expression) | TransformFlags.ContainsJsx; return node; } // @api function updateJsxExpression(node: JsxExpression, expression: Expression | undefined) { return node.expression !== expression ? update(createJsxExpression(node.dotDotDotToken, expression), node) : node; } // // Clauses // // @api function createCaseClause(expression: Expression, statements: readonly Statement[]) { const node = createBaseNode(SyntaxKind.CaseClause); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.statements = createNodeArray(statements); node.transformFlags |= propagateChildFlags(node.expression) | propagateChildrenFlags(node.statements); return node; } // @api function updateCaseClause(node: CaseClause, expression: Expression, statements: readonly Statement[]) { return node.expression !== expression || node.statements !== statements ? update(createCaseClause(expression, statements), node) : node; } // @api function createDefaultClause(statements: readonly Statement[]) { const node = createBaseNode(SyntaxKind.DefaultClause); node.statements = createNodeArray(statements); node.transformFlags = propagateChildrenFlags(node.statements); return node; } // @api function updateDefaultClause(node: DefaultClause, statements: readonly Statement[]) { return node.statements !== statements ? update(createDefaultClause(statements), node) : node; } // @api function createHeritageClause(token: HeritageClause["token"], types: readonly ExpressionWithTypeArguments[]) { const node = createBaseNode(SyntaxKind.HeritageClause); node.token = token; node.types = createNodeArray(types); node.transformFlags |= propagateChildrenFlags(node.types); switch (token) { case SyntaxKind.ExtendsKeyword: node.transformFlags |= TransformFlags.ContainsES2015; break; case SyntaxKind.ImplementsKeyword: node.transformFlags |= TransformFlags.ContainsTypeScript; break; default: return Debug.assertNever(token); } return node; } // @api function updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]) { return node.types !== types ? update(createHeritageClause(node.token, types), node) : node; } // @api function createCatchClause(variableDeclaration: string | VariableDeclaration | undefined, block: Block) { const node = createBaseNode(SyntaxKind.CatchClause); variableDeclaration = !isString(variableDeclaration) ? variableDeclaration : createVariableDeclaration( variableDeclaration, /*exclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined ); node.variableDeclaration = variableDeclaration; node.block = block; node.transformFlags |= propagateChildFlags(node.variableDeclaration) | propagateChildFlags(node.block); if (!variableDeclaration) node.transformFlags |= TransformFlags.ContainsES2019; return node; } // @api function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block) { return node.variableDeclaration !== variableDeclaration || node.block !== block ? update(createCatchClause(variableDeclaration, block), node) : node; } // // Property assignments // // @api function createPropertyAssignment(name: string | PropertyName, initializer: Expression) { const node = createBaseNamedDeclaration( SyntaxKind.PropertyAssignment, /*decorators*/ undefined, /*modifiers*/ undefined, name ); node.initializer = parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); node.transformFlags |= propagateChildFlags(node.name) | propagateChildFlags(node.initializer); return node; } function finishUpdatePropertyAssignment(updated: Mutable, original: PropertyAssignment) { // copy children used only for error reporting if (original.decorators) updated.decorators = original.decorators; if (original.modifiers) updated.modifiers = original.modifiers; if (original.questionToken) updated.questionToken = original.questionToken; if (original.exclamationToken) updated.exclamationToken = original.exclamationToken; return update(updated, original); } // @api function updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression) { return node.name !== name || node.initializer !== initializer ? finishUpdatePropertyAssignment(createPropertyAssignment(name, initializer), node) : node; } // @api function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression) { const node = createBaseNamedDeclaration( SyntaxKind.ShorthandPropertyAssignment, /*decorators*/ undefined, /*modifiers*/ undefined, name ); node.objectAssignmentInitializer = objectAssignmentInitializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(objectAssignmentInitializer); node.transformFlags |= propagateChildFlags(node.objectAssignmentInitializer) | TransformFlags.ContainsES2015; return node; } function finishUpdateShorthandPropertyAssignment(updated: Mutable, original: ShorthandPropertyAssignment) { // copy children used only for error reporting if (original.decorators) updated.decorators = original.decorators; if (original.modifiers) updated.modifiers = original.modifiers; if (original.equalsToken) updated.equalsToken = original.equalsToken; if (original.questionToken) updated.questionToken = original.questionToken; if (original.exclamationToken) updated.exclamationToken = original.exclamationToken; return update(updated, original); } // @api function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined) { return node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer ? finishUpdateShorthandPropertyAssignment(createShorthandPropertyAssignment(name, objectAssignmentInitializer), node) : node; } // @api function createSpreadAssignment(expression: Expression) { const node = createBaseNode(SyntaxKind.SpreadAssignment); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsES2018 | TransformFlags.ContainsObjectRestOrSpread; return node; } // @api function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) { return node.expression !== expression ? update(createSpreadAssignment(expression), node) : node; } // // Enum // // @api function createEnumMember(name: string | PropertyName, initializer?: Expression) { const node = createBaseNode(SyntaxKind.EnumMember); node.name = asName(name); node.initializer = initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); node.transformFlags |= propagateChildFlags(node.name) | propagateChildFlags(node.initializer) | TransformFlags.ContainsTypeScript; return node; } // @api function updateEnumMember(node: EnumMember, name: PropertyName, initializer: Expression | undefined) { return node.name !== name || node.initializer !== initializer ? update(createEnumMember(name, initializer), node) : node; } // // Top-level nodes // // @api function createSourceFile( statements: readonly Statement[], endOfFileToken: EndOfFileToken, flags: NodeFlags ) { const node = baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as Mutable; node.statements = createNodeArray(statements); node.endOfFileToken = endOfFileToken; node.flags |= flags; node.fileName = ""; node.text = ""; node.languageVersion = 0; node.languageVariant = 0; node.scriptKind = 0; node.isDeclarationFile = false; node.hasNoDefaultLib = false; node.transformFlags |= propagateChildrenFlags(node.statements) | propagateChildFlags(node.endOfFileToken); return node; } function cloneSourceFileWithChanges( source: SourceFile, statements: readonly Statement[], isDeclarationFile: boolean, referencedFiles: readonly FileReference[], typeReferences: readonly FileReference[], hasNoDefaultLib: boolean, libReferences: readonly FileReference[] ) { const node = baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as Mutable; for (const p in source) { if (p === "emitNode" || hasProperty(node, p) || !hasProperty(source, p)) continue; (node as any)[p] = (source as any)[p]; } node.flags |= source.flags; node.statements = createNodeArray(statements); node.endOfFileToken = source.endOfFileToken; node.isDeclarationFile = isDeclarationFile; node.referencedFiles = referencedFiles; node.typeReferenceDirectives = typeReferences; node.hasNoDefaultLib = hasNoDefaultLib; node.libReferenceDirectives = libReferences; node.transformFlags = propagateChildrenFlags(node.statements) | propagateChildFlags(node.endOfFileToken); return node; } // @api function updateSourceFile( node: SourceFile, statements: readonly Statement[], isDeclarationFile = node.isDeclarationFile, referencedFiles = node.referencedFiles, typeReferenceDirectives = node.typeReferenceDirectives, hasNoDefaultLib = node.hasNoDefaultLib, libReferenceDirectives = node.libReferenceDirectives ) { return node.statements !== statements || node.isDeclarationFile !== isDeclarationFile || node.referencedFiles !== referencedFiles || node.typeReferenceDirectives !== typeReferenceDirectives || node.hasNoDefaultLib !== hasNoDefaultLib || node.libReferenceDirectives !== libReferenceDirectives ? update(cloneSourceFileWithChanges(node, statements, isDeclarationFile, referencedFiles, typeReferenceDirectives, hasNoDefaultLib, libReferenceDirectives), node) : node; } // @api function createBundle(sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) { const node = createBaseNode(SyntaxKind.Bundle); node.prepends = prepends; node.sourceFiles = sourceFiles; return node; } // @api function updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) { return node.sourceFiles !== sourceFiles || node.prepends !== prepends ? update(createBundle(sourceFiles, prepends), node) : node; } // @api function createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]) { const node = createBaseNode(SyntaxKind.UnparsedSource); node.prologues = prologues; node.syntheticReferences = syntheticReferences; node.texts = texts; node.fileName = ""; node.text = ""; node.referencedFiles = emptyArray; node.libReferenceDirectives = emptyArray; node.getLineAndCharacterOfPosition = pos => getLineAndCharacterOfPosition(node, pos); return node; } function createBaseUnparsedNode(kind: T["kind"], data?: string) { 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); 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.javascriptText = ""; node.declarationText = ""; return node; } // // Synthetic Nodes (used by checker) // // @api function createSyntheticExpression(type: Type, isSpread = false, tupleNameSource?: ParameterDeclaration | NamedTupleMember) { const node = createBaseNode(SyntaxKind.SyntheticExpression); node.type = type; node.isSpread = isSpread; node.tupleNameSource = tupleNameSource; return node; } // @api function createSyntaxList(children: Node[]) { const node = createBaseNode(SyntaxKind.SyntaxList); node._children = children; return node; } // // Transformation nodes // /** * Creates a synthetic statement to act as a placeholder for a not-emitted statement in * order to preserve comments. * * @param original The original statement. */ // @api function createNotEmittedStatement(original: Node) { const node = createBaseNode(SyntaxKind.NotEmittedStatement); node.original = original; setTextRange(node, original); return node; } /** * Creates a synthetic expression to act as a placeholder for a not-emitted expression in * order to preserve comments or sourcemap positions. * * @param expression The inner expression to emit. * @param original The original outer expression. */ // @api function createPartiallyEmittedExpression(expression: Expression, original?: Node) { const node = createBaseNode(SyntaxKind.PartiallyEmittedExpression); node.expression = expression; node.original = original; node.transformFlags |= propagateChildFlags(node.expression) | TransformFlags.ContainsTypeScript; setTextRange(node, original); return node; } // @api function updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression) { return node.expression !== expression ? update(createPartiallyEmittedExpression(expression, node.original), node) : node; } function flattenCommaElements(node: Expression): Expression | readonly Expression[] { if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode && !node.id) { if (isCommaListExpression(node)) { return node.elements; } if (isBinaryExpression(node) && isCommaToken(node.operatorToken)) { return [node.left, node.right]; } } return node; } // @api function createCommaListExpression(elements: readonly Expression[]) { const node = createBaseNode(SyntaxKind.CommaListExpression); node.elements = createNodeArray(sameFlatMap(elements, flattenCommaElements)); node.transformFlags |= propagateChildrenFlags(node.elements); return node; } // @api function updateCommaListExpression(node: CommaListExpression, elements: readonly Expression[]) { return node.elements !== elements ? update(createCommaListExpression(elements), node) : node; } /** * Creates a synthetic element to act as a placeholder for the end of an emitted declaration in * order to properly emit exports. */ // @api function createEndOfDeclarationMarker(original: Node) { const node = createBaseNode(SyntaxKind.EndOfDeclarationMarker); node.emitNode = {} as EmitNode; node.original = original; return node; } /** * Creates a synthetic element to act as a placeholder for the beginning of a merged declaration in * order to properly emit exports. */ // @api function createMergeDeclarationMarker(original: Node) { const node = createBaseNode(SyntaxKind.MergeDeclarationMarker); node.emitNode = {} as EmitNode; node.original = original; return node; } // @api function createSyntheticReferenceExpression(expression: Expression, thisArg: Expression) { const node = createBaseNode(SyntaxKind.SyntheticReferenceExpression); node.expression = expression; node.thisArg = thisArg; node.transformFlags |= propagateChildFlags(node.expression) | propagateChildFlags(node.thisArg); return node; } // @api function updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression) { return node.expression !== expression || node.thisArg !== thisArg ? 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 = isSourceFile(node) ? baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as T : isIdentifier(node) ? baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as T : isPrivateIdentifier(node) ? baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as T : !isNodeKind(node.kind) ? baseFactory.createBaseTokenNode(node.kind) as T : baseFactory.createBaseNode(node.kind) as T; (clone as Mutable).flags |= (node.flags & ~NodeFlags.Synthesized); (clone as Mutable).transformFlags = node.transformFlags; setOriginalNode(clone, node); for (const key in node) { if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { continue; } clone[key] = node[key]; } return clone; } // compound nodes function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression; function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) { return createCallExpression( createFunctionExpression( /*modifiers*/ undefined, /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, /*parameters*/ param ? [param] : [], /*type*/ undefined, createBlock(statements, /*multiLine*/ true) ), /*typeArguments*/ undefined, /*argumentsArray*/ paramValue ? [paramValue] : [] ); } function createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression; function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) { return createCallExpression( createArrowFunction( /*modifiers*/ undefined, /*typeParameters*/ undefined, /*parameters*/ param ? [param] : [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, createBlock(statements, /*multiLine*/ true) ), /*typeArguments*/ undefined, /*argumentsArray*/ paramValue ? [paramValue] : [] ); } function createVoidZero() { return createVoidExpression(createNumericLiteral("0")); } function createExportDefault(expression: Expression) { return createExportAssignment( /*decorators*/ undefined, /*modifiers*/ undefined, /*isExportEquals*/ false, expression); } function createExternalModuleExport(exportName: Identifier) { return createExportDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, /*isTypeOnly*/ false, createNamedExports([ createExportSpecifier(/*propertyName*/ undefined, exportName) ]) ); } // // Utilities // function createTypeCheck(value: Expression, tag: TypeOfTag) { return tag === "undefined" ? factory.createStrictEquality(value, createVoidZero()) : factory.createStrictEquality(createTypeOfExpression(value), createStringLiteral(tag)); } function createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]) { return createCallExpression( createPropertyAccessExpression(object, methodName), /*typeArguments*/ undefined, argumentsList ); } function createFunctionBindCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]) { return createMethodCall(target, "bind", [thisArg, ...argumentsList]); } function createFunctionCallCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]) { return createMethodCall(target, "call", [thisArg, ...argumentsList]); } function createFunctionApplyCall(target: Expression, thisArg: Expression, argumentsExpression: Expression) { return createMethodCall(target, "apply", [thisArg, argumentsExpression]); } function createGlobalMethodCall(globalObjectName: string, methodName: string, argumentsList: readonly Expression[]) { return createMethodCall(createIdentifier(globalObjectName), methodName, argumentsList); } function createArraySliceCall(array: Expression, start?: number | Expression) { return createMethodCall(array, "slice", start === undefined ? [] : [asExpression(start)]); } function createArrayConcatCall(array: Expression, argumentsList: readonly Expression[]) { return createMethodCall(array, "concat", argumentsList); } function createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression) { return createGlobalMethodCall("Object", "defineProperty", [target, asExpression(propertyName), attributes]); } function tryAddPropertyAssignment(properties: Push, propertyName: string, expression: Expression | undefined) { if (expression) { properties.push(createPropertyAssignment(propertyName, expression)); return true; } return false; } function createPropertyDescriptor(attributes: PropertyDescriptorAttributes, singleLine?: boolean) { const properties: PropertyAssignment[] = []; tryAddPropertyAssignment(properties, "enumerable", asExpression(attributes.enumerable)); tryAddPropertyAssignment(properties, "configurable", asExpression(attributes.configurable)); let isData = tryAddPropertyAssignment(properties, "writable", asExpression(attributes.writable)); isData = tryAddPropertyAssignment(properties, "value", attributes.value) || isData; let isAccessor = tryAddPropertyAssignment(properties, "get", attributes.get); isAccessor = tryAddPropertyAssignment(properties, "set", attributes.set) || isAccessor; Debug.assert(!(isData && isAccessor), "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor."); return createObjectLiteralExpression(properties, !singleLine); } function updateOuterExpression(outerExpression: OuterExpression, expression: Expression) { switch (outerExpression.kind) { case SyntaxKind.ParenthesizedExpression: return updateParenthesizedExpression(outerExpression, expression); case SyntaxKind.TypeAssertionExpression: return updateTypeAssertion(outerExpression, outerExpression.type, expression); case SyntaxKind.AsExpression: return updateAsExpression(outerExpression, expression, outerExpression.type); case SyntaxKind.NonNullExpression: return updateNonNullExpression(outerExpression, expression); case SyntaxKind.PartiallyEmittedExpression: return updatePartiallyEmittedExpression(outerExpression, expression); } } /** * Determines whether a node is a parenthesized expression that can be ignored when recreating outer expressions. * * A parenthesized expression can be ignored when all of the following are true: * * - It's `pos` and `end` are not -1 * - It does not have a custom source map range * - It does not have a custom comment range * - It does not have synthetic leading or trailing comments * * If an outermost parenthesized expression is ignored, but the containing expression requires a parentheses around * the expression to maintain precedence, a new parenthesized expression should be created automatically when * the containing expression is created/updated. */ function isIgnorableParen(node: Expression) { return isParenthesizedExpression(node) && nodeIsSynthesized(node) && nodeIsSynthesized(getSourceMapRange(node)) && nodeIsSynthesized(getCommentRange(node)) && !some(getSyntheticLeadingComments(node)) && !some(getSyntheticTrailingComments(node)); } function restoreOuterExpressions(outerExpression: Expression | undefined, innerExpression: Expression, kinds = OuterExpressionKinds.All): Expression { if (outerExpression && isOuterExpression(outerExpression, kinds) && !isIgnorableParen(outerExpression)) { return updateOuterExpression( outerExpression, restoreOuterExpressions(outerExpression.expression, innerExpression) ); } return innerExpression; } function restoreEnclosingLabel(node: Statement, outermostLabeledStatement: LabeledStatement | undefined, afterRestoreLabelCallback?: (node: LabeledStatement) => void): Statement { if (!outermostLabeledStatement) { return node; } const updated = updateLabeledStatement( outermostLabeledStatement, outermostLabeledStatement.label, isLabeledStatement(outermostLabeledStatement.statement) ? restoreEnclosingLabel(node, outermostLabeledStatement.statement) : node ); if (afterRestoreLabelCallback) { afterRestoreLabelCallback(outermostLabeledStatement); } return updated; } function shouldBeCapturedInTempVariable(node: Expression, cacheIdentifiers: boolean): boolean { const target = skipParentheses(node); switch (target.kind) { case SyntaxKind.Identifier: return cacheIdentifiers; case SyntaxKind.ThisKeyword: case SyntaxKind.NumericLiteral: case SyntaxKind.BigIntLiteral: case SyntaxKind.StringLiteral: return false; case SyntaxKind.ArrayLiteralExpression: const elements = (target).elements; if (elements.length === 0) { return false; } return true; case SyntaxKind.ObjectLiteralExpression: return (target).properties.length > 0; default: return true; } } function createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget, cacheIdentifiers = false): CallBinding { const callee = skipOuterExpressions(expression, OuterExpressionKinds.All); let thisArg: Expression; let target: LeftHandSideExpression; if (isSuperProperty(callee)) { thisArg = createThis(); target = callee; } else if (isSuperKeyword(callee)) { thisArg = createThis(); target = languageVersion !== undefined && languageVersion < ScriptTarget.ES2015 ? setTextRange(createIdentifier("_super"), callee) : callee; } else if (getEmitFlags(callee) & EmitFlags.HelperName) { thisArg = createVoidZero(); target = parenthesizerRules().parenthesizeLeftSideOfAccess(callee); } else if (isPropertyAccessExpression(callee)) { if (shouldBeCapturedInTempVariable(callee.expression, cacheIdentifiers)) { // for `a.b()` target is `(_a = a).b` and thisArg is `_a` thisArg = createTempVariable(recordTempVariable); target = createPropertyAccessExpression( setTextRange( factory.createAssignment( thisArg, callee.expression ), callee.expression ), callee.name ); setTextRange(target, callee); } else { thisArg = callee.expression; target = callee; } } else if (isElementAccessExpression(callee)) { if (shouldBeCapturedInTempVariable(callee.expression, cacheIdentifiers)) { // for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a` thisArg = createTempVariable(recordTempVariable); target = createElementAccessExpression( setTextRange( factory.createAssignment( thisArg, callee.expression ), callee.expression ), callee.argumentExpression ); setTextRange(target, callee); } else { thisArg = callee.expression; target = callee; } } else { // for `a()` target is `a` and thisArg is `void 0` thisArg = createVoidZero(); target = parenthesizerRules().parenthesizeLeftSideOfAccess(expression); } return { target, thisArg }; } function inlineExpressions(expressions: readonly Expression[]) { // Avoid deeply nested comma expressions as traversing them during emit can result in "Maximum call // stack size exceeded" errors. return expressions.length > 10 ? createCommaListExpression(expressions) : reduceLeft(expressions, factory.createComma)!; } function getName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) { const nodeName = getNameOfDeclaration(node); if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) { // TODO(rbuckton): Does this need to be parented? const name = setParent(setTextRange(cloneNode(nodeName), nodeName), nodeName.parent); emitFlags |= getEmitFlags(nodeName); if (!allowSourceMaps) emitFlags |= EmitFlags.NoSourceMap; if (!allowComments) emitFlags |= EmitFlags.NoComments; if (emitFlags) setEmitFlags(name, emitFlags); return name; } return getGeneratedNameForNode(node); } /** * Gets the internal name of a declaration. This is primarily used for declarations that can be * referred to by name in the body of an ES5 class function body. An internal name will *never* * be prefixed with an module or namespace export modifier like "exports." when emitted as an * expression. An internal name will also *never* be renamed due to a collision with a block * scoped variable. * * @param node The declaration. * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ function getInternalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) { return getName(node, allowComments, allowSourceMaps, EmitFlags.LocalName | EmitFlags.InternalName); } /** * Gets the local name of a declaration. This is primarily used for declarations that can be * referred to by name in the declaration's immediate scope (classes, enums, namespaces). A * local name will *never* be prefixed with an module or namespace export modifier like * "exports." when emitted as an expression. * * @param node The declaration. * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ function getLocalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) { return getName(node, allowComments, allowSourceMaps, EmitFlags.LocalName); } /** * Gets the export name of a declaration. This is primarily used for declarations that can be * referred to by name in the declaration's immediate scope (classes, enums, namespaces). An * export name will *always* be prefixed with an module or namespace export modifier like * `"exports."` when emitted as an expression if the name points to an exported symbol. * * @param node The declaration. * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ function getExportName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier { return getName(node, allowComments, allowSourceMaps, EmitFlags.ExportName); } /** * Gets the name of a declaration for use in declarations. * * @param node The declaration. * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ function getDeclarationName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) { return getName(node, allowComments, allowSourceMaps); } /** * Gets a namespace-qualified name for use in expressions. * * @param ns The namespace identifier. * @param name The name. * @param allowComments A value indicating whether comments may be emitted for the name. * @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 = createPropertyAccessExpression(ns, nodeIsSynthesized(name) ? name : cloneNode(name)); setTextRange(qualifiedName, name); let emitFlags: EmitFlags = 0; if (!allowSourceMaps) emitFlags |= EmitFlags.NoSourceMap; if (!allowComments) emitFlags |= EmitFlags.NoComments; if (emitFlags) setEmitFlags(qualifiedName, emitFlags); return qualifiedName; } /** * Gets the exported name of a declaration for use in expressions. * * An exported name will *always* be prefixed with an module or namespace export modifier like * "exports." if the name points to an exported symbol. * * @param ns The namespace identifier. * @param node The declaration. * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ function getExternalModuleOrNamespaceExportName(ns: Identifier | undefined, node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier | PropertyAccessExpression { if (ns && hasSyntacticModifier(node, ModifierFlags.Export)) { return getNamespaceMemberName(ns, getName(node), allowComments, allowSourceMaps); } return getExportName(node, allowComments, allowSourceMaps); } /** * Copies any necessary standard and custom prologue-directives into target array. * @param source origin statements array * @param target result statements array * @param ensureUseStrict boolean determining whether the function need to add prologue-directives * @param visitor Optional callback used to visit any custom prologue directives. */ function copyPrologue(source: readonly Statement[], target: Push, ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { const offset = copyStandardPrologue(source, target, ensureUseStrict); return copyCustomPrologue(source, target, offset, visitor); } function isUseStrictPrologue(node: ExpressionStatement): boolean { return isStringLiteral(node.expression) && node.expression.text === "use strict"; } function createUseStrictPrologue() { return startOnNewLine(createExpressionStatement(createStringLiteral("use strict"))) as PrologueDirective; } /** * Copies only the standard (string-expression) prologue-directives into the target statement-array. * @param source origin statements array * @param target result statements array * @param ensureUseStrict boolean determining whether the function need to add prologue-directives */ function copyStandardPrologue(source: readonly Statement[], target: Push, ensureUseStrict?: boolean): number { Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array"); let foundUseStrict = false; let statementOffset = 0; const numStatements = source.length; while (statementOffset < numStatements) { const statement = source[statementOffset]; if (isPrologueDirective(statement)) { if (isUseStrictPrologue(statement)) { foundUseStrict = true; } target.push(statement); } else { break; } statementOffset++; } if (ensureUseStrict && !foundUseStrict) { target.push(createUseStrictPrologue()); } return statementOffset; } /** * Copies only the custom prologue-directives into target statement-array. * @param source origin statements array * @param target result statements array * @param statementOffset The offset at which to begin the copy. * @param visitor Optional callback used to visit any custom prologue directives. */ function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number; function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number | undefined; function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter: (node: Node) => boolean = returnTrue): number | undefined { const numStatements = source.length; while (statementOffset !== undefined && statementOffset < numStatements) { const statement = source[statementOffset]; if (getEmitFlags(statement) & EmitFlags.CustomPrologue && filter(statement)) { append(target, visitor ? visitNode(statement, visitor, isStatement) : statement); } else { break; } statementOffset++; } return statementOffset; } /** * Ensures "use strict" directive is added * * @param statements An array of statements */ function ensureUseStrict(statements: NodeArray): NodeArray { const foundUseStrict = findUseStrictPrologue(statements); if (!foundUseStrict) { return setTextRange(createNodeArray([createUseStrictPrologue(), ...statements]), statements); } return statements; } /** * Lifts a NodeArray containing only Statement nodes to a block. * * @param nodes The NodeArray. */ function liftToBlock(nodes: readonly Node[]): Statement { Debug.assert(every(nodes, isStatementOrBlock), "Cannot lift nodes to a Block."); return singleOrUndefined(nodes) || createBlock(nodes); } function findSpanEnd(array: readonly T[], test: (value: T) => boolean, start: number) { let i = start; while (i < array.length && test(array[i])) { i++; } return i; } function mergeLexicalEnvironment(statements: NodeArray, declarations: readonly Statement[] | undefined): NodeArray; function mergeLexicalEnvironment(statements: Statement[], declarations: readonly Statement[] | undefined): Statement[]; function mergeLexicalEnvironment(statements: Statement[] | NodeArray, declarations: readonly Statement[] | undefined) { if (!some(declarations)) { return statements; } // When we merge new lexical statements into an existing statement list, we merge them in the following manner: // // Given: // // | Left | Right | // |------------------------------------|-------------------------------------| // | [standard prologues (left)] | [standard prologues (right)] | // | [hoisted functions (left)] | [hoisted functions (right)] | // | [hoisted variables (left)] | [hoisted variables (right)] | // | [lexical init statements (left)] | [lexical init statements (right)] | // | [other statements (left)] | | // // The resulting statement list will be: // // | Result | // |-------------------------------------| // | [standard prologues (right)] | // | [standard prologues (left)] | // | [hoisted functions (right)] | // | [hoisted functions (left)] | // | [hoisted variables (right)] | // | [hoisted variables (left)] | // | [lexical init statements (right)] | // | [lexical init statements (left)] | // | [other statements (left)] | // // NOTE: It is expected that new lexical init statements must be evaluated before existing lexical init statements, // as the prior transformation may depend on the evaluation of the lexical init statements to be in the correct state. // find standard prologues on left in the following order: standard directives, hoisted functions, hoisted variables, other custom const leftStandardPrologueEnd = findSpanEnd(statements, isPrologueDirective, 0); const leftHoistedFunctionsEnd = findSpanEnd(statements, isHoistedFunction, leftStandardPrologueEnd); const leftHoistedVariablesEnd = findSpanEnd(statements, isHoistedVariableStatement, leftHoistedFunctionsEnd); // find standard prologues on right in the following order: standard directives, hoisted functions, hoisted variables, other custom const rightStandardPrologueEnd = findSpanEnd(declarations, isPrologueDirective, 0); const rightHoistedFunctionsEnd = findSpanEnd(declarations, isHoistedFunction, rightStandardPrologueEnd); const rightHoistedVariablesEnd = findSpanEnd(declarations, isHoistedVariableStatement, rightHoistedFunctionsEnd); const rightCustomPrologueEnd = findSpanEnd(declarations, isCustomPrologue, rightHoistedVariablesEnd); Debug.assert(rightCustomPrologueEnd === declarations.length, "Expected declarations to be valid standard or custom prologues"); // splice prologues from the right into the left. We do this in reverse order // so that we don't need to recompute the index on the left when we insert items. const left = isNodeArray(statements) ? statements.slice() : statements; // splice other custom prologues from right into left if (rightCustomPrologueEnd > rightHoistedVariablesEnd) { left.splice(leftHoistedVariablesEnd, 0, ...declarations.slice(rightHoistedVariablesEnd, rightCustomPrologueEnd)); } // splice hoisted variables from right into left if (rightHoistedVariablesEnd > rightHoistedFunctionsEnd) { left.splice(leftHoistedFunctionsEnd, 0, ...declarations.slice(rightHoistedFunctionsEnd, rightHoistedVariablesEnd)); } // splice hoisted functions from right into left if (rightHoistedFunctionsEnd > rightStandardPrologueEnd) { left.splice(leftStandardPrologueEnd, 0, ...declarations.slice(rightStandardPrologueEnd, rightHoistedFunctionsEnd)); } // splice standard prologues from right into left (that are not already in left) if (rightStandardPrologueEnd > 0) { if (leftStandardPrologueEnd === 0) { left.splice(0, 0, ...declarations.slice(0, rightStandardPrologueEnd)); } else { const leftPrologues = new Map(); for (let i = 0; i < leftStandardPrologueEnd; i++) { const leftPrologue = statements[i] as PrologueDirective; leftPrologues.set(leftPrologue.expression.text, true); } for (let i = rightStandardPrologueEnd - 1; i >= 0; i--) { const rightPrologue = declarations[i] as PrologueDirective; if (!leftPrologues.has(rightPrologue.expression.text)) { left.unshift(rightPrologue); } } } } if (isNodeArray(statements)) { return setTextRange(createNodeArray(left, statements.hasTrailingComma), statements); } return statements; } function updateModifiers(node: T, modifiers: readonly Modifier[] | ModifierFlags): T; function updateModifiers(node: HasModifiers, modifiers: readonly Modifier[] | ModifierFlags) { if (typeof modifiers === "number") { modifiers = createModifiersFromModifierFlags(modifiers); } return isParameter(node) ? updateParameterDeclaration(node, node.decorators, modifiers, node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer) : isPropertySignature(node) ? updatePropertySignature(node, modifiers, node.name, node.questionToken, node.type) : isPropertyDeclaration(node) ? updatePropertyDeclaration(node, node.decorators, modifiers, node.name, node.questionToken ?? node.exclamationToken, node.type, node.initializer) : isMethodSignature(node) ? updateMethodSignature(node, modifiers, node.name, node.questionToken, node.typeParameters, node.parameters, node.type) : isMethodDeclaration(node) ? updateMethodDeclaration(node, node.decorators, modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, node.body) : isConstructorDeclaration(node) ? updateConstructorDeclaration(node, node.decorators, modifiers, node.parameters, node.body) : isGetAccessorDeclaration(node) ? updateGetAccessorDeclaration(node, node.decorators, modifiers, node.name, node.parameters, node.type, node.body) : isSetAccessorDeclaration(node) ? updateSetAccessorDeclaration(node, node.decorators, modifiers, node.name, node.parameters, node.body) : isIndexSignatureDeclaration(node) ? updateIndexSignature(node, node.decorators, modifiers, node.parameters, node.type) : isFunctionExpression(node) ? updateFunctionExpression(node, modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) : isArrowFunction(node) ? updateArrowFunction(node, modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, node.body) : isClassExpression(node) ? updateClassExpression(node, node.decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members) : isVariableStatement(node) ? updateVariableStatement(node, modifiers, node.declarationList) : isFunctionDeclaration(node) ? updateFunctionDeclaration(node, node.decorators, modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) : isClassDeclaration(node) ? updateClassDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members) : isInterfaceDeclaration(node) ? updateInterfaceDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members) : isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.type) : isEnumDeclaration(node) ? updateEnumDeclaration(node, node.decorators, modifiers, node.name, node.members) : isModuleDeclaration(node) ? updateModuleDeclaration(node, node.decorators, modifiers, node.name, node.body) : isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, node.decorators, modifiers, node.name, node.moduleReference) : isImportDeclaration(node) ? updateImportDeclaration(node, node.decorators, modifiers, node.importClause, node.moduleSpecifier) : isExportAssignment(node) ? updateExportAssignment(node, node.decorators, modifiers, node.expression) : isExportDeclaration(node) ? updateExportDeclaration(node, node.decorators, modifiers, node.isTypeOnly, node.exportClause, node.moduleSpecifier) : Debug.assertNever(node); } function asNodeArray(array: readonly T[]): NodeArray; function asNodeArray(array: readonly T[] | undefined): NodeArray | undefined; function asNodeArray(array: readonly T[] | undefined): NodeArray | undefined { return array ? createNodeArray(array) : undefined; } function asName(name: string | T): T | Identifier { return typeof name === "string" ? createIdentifier(name) : name; } function asExpression(value: string | number | boolean | T): T | StringLiteral | NumericLiteral | BooleanLiteral { return typeof value === "string" ? createStringLiteral(value) : typeof value === "number" ? createNumericLiteral(value) : typeof value === "boolean" ? value ? createTrue() : createFalse() : value; } function asToken(value: TKind | Token): Token { return typeof value === "number" ? createToken(value) : value; } function asEmbeddedStatement(statement: T): T | EmptyStatement; function asEmbeddedStatement(statement: T | undefined): T | EmptyStatement | undefined; function asEmbeddedStatement(statement: T | undefined): T | EmptyStatement | undefined { return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement; } } function updateWithoutOriginal(updated: T, original: T): T { if (updated !== original) { setTextRange(updated, original); } return updated; } function updateWithOriginal(updated: T, original: T): T { if (updated !== original) { setOriginalNode(updated, original); setTextRange(updated, original); } return updated; } function getDefaultTagNameForKind(kind: JSDocTag["kind"]): string { switch (kind) { case SyntaxKind.JSDocTypeTag: return "type"; case SyntaxKind.JSDocReturnTag: return "returns"; case SyntaxKind.JSDocThisTag: return "this"; case SyntaxKind.JSDocEnumTag: return "enum"; case SyntaxKind.JSDocAuthorTag: return "author"; case SyntaxKind.JSDocClassTag: return "class"; case SyntaxKind.JSDocPublicTag: return "public"; case SyntaxKind.JSDocPrivateTag: return "private"; case SyntaxKind.JSDocProtectedTag: return "protected"; case SyntaxKind.JSDocReadonlyTag: return "readonly"; case SyntaxKind.JSDocTemplateTag: return "template"; case SyntaxKind.JSDocTypedefTag: return "typedef"; case SyntaxKind.JSDocParameterTag: return "param"; case SyntaxKind.JSDocPropertyTag: return "prop"; case SyntaxKind.JSDocCallbackTag: return "callback"; case SyntaxKind.JSDocAugmentsTag: return "augments"; case SyntaxKind.JSDocImplementsTag: return "implements"; default: return Debug.fail(`Unsupported kind: ${Debug.formatSyntaxKind(kind)}`); } } let rawTextScanner: Scanner | undefined; const invalidValueSentinel: object = { }; function getCookedText(kind: TemplateLiteralToken["kind"], rawText: string) { if (!rawTextScanner) { rawTextScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.Standard); } switch (kind) { case SyntaxKind.NoSubstitutionTemplateLiteral: rawTextScanner.setText("`" + rawText + "`"); break; case SyntaxKind.TemplateHead: // tslint:disable-next-line no-invalid-template-strings rawTextScanner.setText("`" + rawText + "${"); break; case SyntaxKind.TemplateMiddle: // tslint:disable-next-line no-invalid-template-strings rawTextScanner.setText("}" + rawText + "${"); break; case SyntaxKind.TemplateTail: rawTextScanner.setText("}" + rawText + "`"); break; } let token = rawTextScanner.scan(); if (token === SyntaxKind.CloseBracketToken) { token = rawTextScanner.reScanTemplateToken(/*isTaggedTemplate*/ false); } if (rawTextScanner.isUnterminated()) { rawTextScanner.setText(undefined); return invalidValueSentinel; } let tokenValue: string | undefined; switch (token) { case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.TemplateHead: case SyntaxKind.TemplateMiddle: case SyntaxKind.TemplateTail: tokenValue = rawTextScanner.getTokenValue(); break; } if (tokenValue === undefined || rawTextScanner.scan() !== SyntaxKind.EndOfFileToken) { rawTextScanner.setText(undefined); return invalidValueSentinel; } rawTextScanner.setText(undefined); return tokenValue; } function propagateIdentifierNameFlags(node: Identifier) { // An IdentifierName is allowed to be `await` return propagateChildFlags(node) & ~TransformFlags.ContainsPossibleTopLevelAwait; } function propagatePropertyNameFlagsOfChild(node: PropertyName, transformFlags: TransformFlags) { return transformFlags | (node.transformFlags & TransformFlags.PropertyNamePropagatingFlags); } function propagateChildFlags(child: Node | undefined): TransformFlags { if (!child) return TransformFlags.None; const childFlags = child.transformFlags & ~getTransformFlagsSubtreeExclusions(child.kind); return isNamedDeclaration(child) && isPropertyName(child.name) ? propagatePropertyNameFlagsOfChild(child.name, childFlags) : childFlags; } function propagateChildrenFlags(children: NodeArray | undefined): TransformFlags { return children ? children.transformFlags : TransformFlags.None; } function aggregateChildrenFlags(children: MutableNodeArray) { let subtreeFlags = TransformFlags.None; for (const child of children) { subtreeFlags |= propagateChildFlags(child); } children.transformFlags = subtreeFlags; } /** * Gets the transform flags to exclude when unioning the transform flags of a subtree. */ /* @internal */ export function getTransformFlagsSubtreeExclusions(kind: SyntaxKind) { if (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) { return TransformFlags.TypeExcludes; } switch (kind) { case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: case SyntaxKind.ArrayLiteralExpression: return TransformFlags.ArrayLiteralOrCallOrNewExcludes; case SyntaxKind.ModuleDeclaration: return TransformFlags.ModuleExcludes; case SyntaxKind.Parameter: return TransformFlags.ParameterExcludes; case SyntaxKind.ArrowFunction: return TransformFlags.ArrowFunctionExcludes; case SyntaxKind.FunctionExpression: case SyntaxKind.FunctionDeclaration: return TransformFlags.FunctionExcludes; case SyntaxKind.VariableDeclarationList: return TransformFlags.VariableDeclarationListExcludes; case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: return TransformFlags.ClassExcludes; case SyntaxKind.Constructor: return TransformFlags.ConstructorExcludes; case SyntaxKind.PropertyDeclaration: return TransformFlags.PropertyExcludes; case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: return TransformFlags.MethodOrAccessorExcludes; case SyntaxKind.AnyKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.BigIntKeyword: case SyntaxKind.NeverKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.ObjectKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.VoidKeyword: case SyntaxKind.TypeParameter: case SyntaxKind.PropertySignature: case SyntaxKind.MethodSignature: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.IndexSignature: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.TypeAliasDeclaration: return TransformFlags.TypeExcludes; case SyntaxKind.ObjectLiteralExpression: return TransformFlags.ObjectLiteralExcludes; case SyntaxKind.CatchClause: return TransformFlags.CatchClauseExcludes; case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: return TransformFlags.BindingPatternExcludes; case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: case SyntaxKind.PartiallyEmittedExpression: case SyntaxKind.ParenthesizedExpression: case SyntaxKind.SuperKeyword: return TransformFlags.OuterExpressionExcludes; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: return TransformFlags.PropertyAccessExcludes; default: return TransformFlags.NodeExcludes; } } const baseFactory = createBaseNodeFactory(); function makeSynthetic(node: Node) { (node as Mutable).flags |= NodeFlags.Synthesized; return node; } const syntheticFactory: BaseNodeFactory = { createBaseSourceFileNode: kind => makeSynthetic(baseFactory.createBaseSourceFileNode(kind)), createBaseIdentifierNode: kind => makeSynthetic(baseFactory.createBaseIdentifierNode(kind)), createBasePrivateIdentifierNode: kind => makeSynthetic(baseFactory.createBasePrivateIdentifierNode(kind)), createBaseTokenNode: kind => makeSynthetic(baseFactory.createBaseTokenNode(kind)), createBaseNode: kind => makeSynthetic(baseFactory.createBaseNode(kind)), }; export const factory = createNodeFactory(NodeFactoryFlags.NoIndentationOnFreshPropertyAccess, syntheticFactory); 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 { 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"); 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) { Debug.assert(mapTextOrStripInternal === undefined || typeof mapTextOrStripInternal === "boolean"); stripInternal = mapTextOrStripInternal; bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js : textOrInputFiles.buildInfo.bundle.dts; oldFileOfCurrentEmit = textOrInputFiles.oldFileOfCurrentEmit; } } else { fileName = ""; text = textOrInputFiles; length = textOrInputFiles.length; sourceMapPath = mapPathOrType; sourceMapText = mapTextOrStripInternal as string; } 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(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 = append(prologues, setTextRange(factory.createUnparsedPrologue(section.data), section)); break; case BundleFileSectionKind.EmitHelpers: helpers = append(helpers, getAllUnscopedEmitHelpers().get(section.data)!); break; case BundleFileSectionKind.NoDefaultLib: hasNoDefaultLib = true; break; case BundleFileSectionKind.Reference: referencedFiles = append(referencedFiles, { pos: -1, end: -1, fileName: section.data }); break; case BundleFileSectionKind.Type: typeReferenceDirectives = append(typeReferenceDirectives, section.data); break; case BundleFileSectionKind.Lib: libReferenceDirectives = append(libReferenceDirectives, { pos: -1, end: -1, fileName: section.data }); break; case BundleFileSectionKind.Prepend: let prependTexts: UnparsedTextLike[] | undefined; for (const text of section.texts) { if (!stripInternal || text.kind !== BundleFileSectionKind.Internal) { prependTexts = append(prependTexts, setTextRange(factory.createUnparsedTextLike(text.data, text.kind === BundleFileSectionKind.Internal), text)); } } prependChildren = addRange(prependChildren, prependTexts); texts = append(texts, factory.createUnparsedPrepend(section.data, prependTexts ?? emptyArray)); break; case BundleFileSectionKind.Internal: if (stripInternal) { if (!texts) texts = []; break; } // falls through case BundleFileSectionKind.Text: texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section)); break; default: Debug.assertNever(section); } } if (!texts) { const textNode = factory.createUnparsedTextLike(/*data*/ undefined, /*internal*/ false); setTextRangePosWidth(textNode, 0, 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; return node; } 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 = 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 = append(syntheticReferences, setTextRange(factory.createUnparsedSyntheticReference(section), section)); break; // Ignore case BundleFileSectionKind.Prologue: case BundleFileSectionKind.EmitHelpers: case BundleFileSectionKind.Prepend: break; default: Debug.assertNever(section); } } 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)!); return node; } // TODO(rbuckton): Move part of this to factory export function createInputFiles( javascriptText: string, declarationText: string ): InputFiles; export function createInputFiles( readFileText: (path: string) => string | undefined, javascriptPath: string, javascriptMapPath: string | undefined, declarationPath: string, declarationMapPath: string | undefined, buildInfoPath: string | undefined ): InputFiles; export function createInputFiles( javascriptText: string, declarationText: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined ): InputFiles; /*@internal*/ export function createInputFiles( javascriptText: string, declarationText: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined, javascriptPath: string | undefined, declarationPath: string | undefined, buildInfoPath?: string | undefined, buildInfo?: BuildInfo, oldFileOfCurrentEmit?: boolean ): InputFiles; export function createInputFiles( javascriptTextOrReadFileText: string | ((path: string) => string | undefined), declarationTextOrJavascriptPath: string, javascriptMapPath?: string, javascriptMapTextOrDeclarationPath?: string, declarationMapPath?: string, declarationMapTextOrBuildInfoPath?: string, javascriptPath?: string | undefined, declarationPath?: string | undefined, buildInfoPath?: string | undefined, buildInfo?: BuildInfo, oldFileOfCurrentEmit?: boolean ): InputFiles { const node = parseNodeFactory.createInputFiles(); if (!isString(javascriptTextOrReadFileText)) { const cache = new Map(); const textGetter = (path: string | undefined) => { if (path === undefined) return undefined; let value = cache.get(path); if (value === undefined) { value = javascriptTextOrReadFileText(path); cache.set(path, value !== undefined ? value : false); } return value !== false ? value as string : undefined; }; const definedTextGetter = (path: string) => { const result = textGetter(path); return result !== undefined ? result : `/* Input file ${path} was missing */\r\n`; }; let buildInfo: BuildInfo | false; const getAndCacheBuildInfo = (getText: () => string | undefined) => { if (buildInfo === undefined) { const result = getText(); buildInfo = result !== undefined ? getBuildInfo(result) : false; } return buildInfo || undefined; }; node.javascriptPath = declarationTextOrJavascriptPath; node.javascriptMapPath = javascriptMapPath; node.declarationPath = Debug.assertDefined(javascriptMapTextOrDeclarationPath); node.declarationMapPath = declarationMapPath; node.buildInfoPath = declarationMapTextOrBuildInfoPath; Object.defineProperties(node, { javascriptText: { get() { return definedTextGetter(declarationTextOrJavascriptPath); } }, javascriptMapText: { get() { return textGetter(javascriptMapPath); } }, // TODO:: if there is inline sourceMap in jsFile, use that declarationText: { get() { return definedTextGetter(Debug.assertDefined(javascriptMapTextOrDeclarationPath)); } }, declarationMapText: { get() { return textGetter(declarationMapPath); } }, // TODO:: if there is inline sourceMap in dtsFile, use that buildInfo: { get() { return getAndCacheBuildInfo(() => textGetter(declarationMapTextOrBuildInfoPath)); } } }); } else { node.javascriptText = javascriptTextOrReadFileText; node.javascriptMapPath = javascriptMapPath; node.javascriptMapText = javascriptMapTextOrDeclarationPath; node.declarationText = declarationTextOrJavascriptPath; node.declarationMapPath = declarationMapPath; node.declarationMapText = declarationMapTextOrBuildInfoPath; node.javascriptPath = javascriptPath; node.declarationPath = declarationPath; node.buildInfoPath = buildInfoPath; node.buildInfo = buildInfo; node.oldFileOfCurrentEmit = oldFileOfCurrentEmit; } return node; } // tslint:disable-next-line variable-name let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource; /** * Create an external source map source file reference */ export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource { return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia); } // Utilities export function setOriginalNode(node: T, original: Node | undefined): T { node.original = original; if (original) { const emitNode = original.emitNode; if (emitNode) node.emitNode = mergeEmitNode(emitNode, node.emitNode); } return node; } function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode | undefined) { const { flags, leadingComments, trailingComments, commentRange, sourceMapRange, tokenSourceMapRanges, constantValue, helpers, startsOnNewLine, } = sourceEmitNode; if (!destEmitNode) destEmitNode = {} as EmitNode; // We are using `.slice()` here in case `destEmitNode.leadingComments` is pushed to later. if (leadingComments) destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments); if (trailingComments) destEmitNode.trailingComments = addRange(trailingComments.slice(), destEmitNode.trailingComments); if (flags) destEmitNode.flags = flags; if (commentRange) destEmitNode.commentRange = commentRange; if (sourceMapRange) destEmitNode.sourceMapRange = sourceMapRange; if (tokenSourceMapRanges) destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges!); if (constantValue !== undefined) destEmitNode.constantValue = constantValue; if (helpers) { for (const helper of helpers) { destEmitNode.helpers = appendIfUnique(destEmitNode.helpers, helper); } } if (startsOnNewLine !== undefined) destEmitNode.startsOnNewLine = startsOnNewLine; return destEmitNode; } function mergeTokenSourceMapRanges(sourceRanges: (TextRange | undefined)[], destRanges: (TextRange | undefined)[]) { if (!destRanges) destRanges = []; for (const key in sourceRanges) { destRanges[key] = sourceRanges[key]; } return destRanges; } }