• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    let nextAutoGenerateId = 0;
3
4    /* @internal */
5    export const enum NodeFactoryFlags {
6        None = 0,
7        // Disables the parenthesizer rules for the factory.
8        NoParenthesizerRules = 1 << 0,
9        // Disables the node converters for the factory.
10        NoNodeConverters = 1 << 1,
11        // Ensures new `PropertyAccessExpression` nodes are created with the `NoIndentation` emit flag set.
12        NoIndentationOnFreshPropertyAccess = 1 << 2,
13        // Do not set an `original` pointer when updating a node.
14        NoOriginalNode = 1 << 3,
15    }
16
17    /**
18     * Creates a `NodeFactory` that can be used to create and update a syntax tree.
19     * @param flags Flags that control factory behavior.
20     * @param baseFactory A `BaseNodeFactory` used to create the base `Node` objects.
21     */
22    /* @internal */
23    export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNodeFactory): NodeFactory {
24        const update = flags & NodeFactoryFlags.NoOriginalNode ? updateWithoutOriginal : updateWithOriginal;
25
26        // Lazily load the parenthesizer, node converters, and some factory methods until they are used.
27        const parenthesizerRules = memoize(() => flags & NodeFactoryFlags.NoParenthesizerRules ? nullParenthesizerRules : createParenthesizerRules(factory));
28        const converters = memoize(() => flags & NodeFactoryFlags.NoNodeConverters ? nullNodeConverters : createNodeConverters(factory));
29
30        // lazy initializaton of common operator factories
31        const getBinaryCreateFunction = memoizeOne((operator: BinaryOperator) => (left: Expression, right: Expression) => createBinaryExpression(left, operator, right));
32        const getPrefixUnaryCreateFunction = memoizeOne((operator: PrefixUnaryOperator) => (operand: Expression) => createPrefixUnaryExpression(operator, operand));
33        const getPostfixUnaryCreateFunction = memoizeOne((operator: PostfixUnaryOperator) => (operand: Expression) => createPostfixUnaryExpression(operand, operator));
34        const getJSDocPrimaryTypeCreateFunction = memoizeOne(<T extends JSDocType>(kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind));
35        const getJSDocUnaryTypeCreateFunction = memoizeOne(<T extends JSDocType & { readonly type: TypeNode | undefined; }>(kind: T["kind"]) => (type: T["type"]) => createJSDocUnaryTypeWorker<T>(kind, type));
36        const getJSDocUnaryTypeUpdateFunction = memoizeOne(<T extends JSDocType & { readonly type: TypeNode | undefined; }>(kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker<T>(kind, node, type));
37        const getJSDocSimpleTagCreateFunction = memoizeOne(<T extends JSDocTag>(kind: T["kind"]) => (tagName: Identifier | undefined, comment?: string) => createJSDocSimpleTagWorker(kind, tagName, comment));
38        const getJSDocSimpleTagUpdateFunction = memoizeOne(<T extends JSDocTag>(kind: T["kind"]) => (node: T, tagName: Identifier | undefined, comment?: string) => updateJSDocSimpleTagWorker(kind, node, tagName, comment));
39        const getJSDocTypeLikeTagCreateFunction = memoizeOne(<T extends JSDocTag & { typeExpression?: JSDocTypeExpression }>(kind: T["kind"]) => (tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string) => createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment));
40        const getJSDocTypeLikeTagUpdateFunction = memoizeOne(<T extends JSDocTag & { typeExpression?: JSDocTypeExpression }>(kind: T["kind"]) => (node: T, tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string) => updateJSDocTypeLikeTagWorker(kind, node, tagName, typeExpression, comment));
41
42        const factory: NodeFactory = {
43            get parenthesizer() { return parenthesizerRules(); },
44            get converters() { return converters(); },
45            createNodeArray,
46            createNumericLiteral,
47            createBigIntLiteral,
48            createStringLiteral,
49            createStringLiteralFromNode,
50            createRegularExpressionLiteral,
51            createLiteralLikeNode,
52            createIdentifier,
53            updateIdentifier,
54            createTempVariable,
55            createLoopVariable,
56            createUniqueName,
57            getGeneratedNameForNode,
58            createPrivateIdentifier,
59            createToken,
60            createSuper,
61            createThis,
62            createNull,
63            createTrue,
64            createFalse,
65            createModifier,
66            createModifiersFromModifierFlags,
67            createQualifiedName,
68            updateQualifiedName,
69            createComputedPropertyName,
70            updateComputedPropertyName,
71            createTypeParameterDeclaration,
72            updateTypeParameterDeclaration,
73            createParameterDeclaration,
74            updateParameterDeclaration,
75            createDecorator,
76            updateDecorator,
77            createPropertySignature,
78            updatePropertySignature,
79            createPropertyDeclaration,
80            updatePropertyDeclaration,
81            createMethodSignature,
82            updateMethodSignature,
83            createMethodDeclaration,
84            updateMethodDeclaration,
85            createConstructorDeclaration,
86            updateConstructorDeclaration,
87            createGetAccessorDeclaration,
88            updateGetAccessorDeclaration,
89            createSetAccessorDeclaration,
90            updateSetAccessorDeclaration,
91            createCallSignature,
92            updateCallSignature,
93            createConstructSignature,
94            updateConstructSignature,
95            createIndexSignature,
96            updateIndexSignature,
97            createTemplateLiteralTypeSpan,
98            updateTemplateLiteralTypeSpan,
99            createKeywordTypeNode,
100            createTypePredicateNode,
101            updateTypePredicateNode,
102            createTypeReferenceNode,
103            updateTypeReferenceNode,
104            createFunctionTypeNode,
105            updateFunctionTypeNode,
106            createConstructorTypeNode,
107            updateConstructorTypeNode,
108            createTypeQueryNode,
109            updateTypeQueryNode,
110            createTypeLiteralNode,
111            updateTypeLiteralNode,
112            createArrayTypeNode,
113            updateArrayTypeNode,
114            createTupleTypeNode,
115            updateTupleTypeNode,
116            createNamedTupleMember,
117            updateNamedTupleMember,
118            createOptionalTypeNode,
119            updateOptionalTypeNode,
120            createRestTypeNode,
121            updateRestTypeNode,
122            createUnionTypeNode,
123            updateUnionTypeNode,
124            createIntersectionTypeNode,
125            updateIntersectionTypeNode,
126            createConditionalTypeNode,
127            updateConditionalTypeNode,
128            createInferTypeNode,
129            updateInferTypeNode,
130            createImportTypeNode,
131            updateImportTypeNode,
132            createParenthesizedType,
133            updateParenthesizedType,
134            createThisTypeNode,
135            createTypeOperatorNode,
136            updateTypeOperatorNode,
137            createIndexedAccessTypeNode,
138            updateIndexedAccessTypeNode,
139            createMappedTypeNode,
140            updateMappedTypeNode,
141            createLiteralTypeNode,
142            updateLiteralTypeNode,
143            createTemplateLiteralType,
144            updateTemplateLiteralType,
145            createObjectBindingPattern,
146            updateObjectBindingPattern,
147            createArrayBindingPattern,
148            updateArrayBindingPattern,
149            createBindingElement,
150            updateBindingElement,
151            createArrayLiteralExpression,
152            updateArrayLiteralExpression,
153            createObjectLiteralExpression,
154            updateObjectLiteralExpression,
155            createPropertyAccessExpression: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ?
156                (expression, name) => setEmitFlags(createPropertyAccessExpression(expression, name), EmitFlags.NoIndentation) :
157                createPropertyAccessExpression,
158            updatePropertyAccessExpression,
159            createPropertyAccessChain: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ?
160                (expression, questionDotToken, name) => setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), EmitFlags.NoIndentation) :
161                createPropertyAccessChain,
162            updatePropertyAccessChain,
163            createElementAccessExpression,
164            updateElementAccessExpression,
165            createElementAccessChain,
166            updateElementAccessChain,
167            createCallExpression,
168            updateCallExpression,
169            createCallChain,
170            updateCallChain,
171            createNewExpression,
172            updateNewExpression,
173            createTaggedTemplateExpression,
174            updateTaggedTemplateExpression,
175            createTypeAssertion,
176            updateTypeAssertion,
177            createParenthesizedExpression,
178            updateParenthesizedExpression,
179            createFunctionExpression,
180            updateFunctionExpression,
181            createEtsComponentExpression,
182            updateEtsComponentExpression,
183            createArrowFunction,
184            updateArrowFunction,
185            createDeleteExpression,
186            updateDeleteExpression,
187            createTypeOfExpression,
188            updateTypeOfExpression,
189            createVoidExpression,
190            updateVoidExpression,
191            createAwaitExpression,
192            updateAwaitExpression,
193            createPrefixUnaryExpression,
194            updatePrefixUnaryExpression,
195            createPostfixUnaryExpression,
196            updatePostfixUnaryExpression,
197            createBinaryExpression,
198            updateBinaryExpression,
199            createConditionalExpression,
200            updateConditionalExpression,
201            createTemplateExpression,
202            updateTemplateExpression,
203            createTemplateHead,
204            createTemplateMiddle,
205            createTemplateTail,
206            createNoSubstitutionTemplateLiteral,
207            createTemplateLiteralLikeNode,
208            createYieldExpression,
209            updateYieldExpression,
210            createSpreadElement,
211            updateSpreadElement,
212            createClassExpression,
213            updateClassExpression,
214            createOmittedExpression,
215            createExpressionWithTypeArguments,
216            updateExpressionWithTypeArguments,
217            createAsExpression,
218            updateAsExpression,
219            createNonNullExpression,
220            updateNonNullExpression,
221            createNonNullChain,
222            updateNonNullChain,
223            createMetaProperty,
224            updateMetaProperty,
225            createTemplateSpan,
226            updateTemplateSpan,
227            createSemicolonClassElement,
228            createBlock,
229            updateBlock,
230            createVariableStatement,
231            updateVariableStatement,
232            createEmptyStatement,
233            createExpressionStatement,
234            updateExpressionStatement,
235            createIfStatement,
236            updateIfStatement,
237            createDoStatement,
238            updateDoStatement,
239            createWhileStatement,
240            updateWhileStatement,
241            createForStatement,
242            updateForStatement,
243            createForInStatement,
244            updateForInStatement,
245            createForOfStatement,
246            updateForOfStatement,
247            createContinueStatement,
248            updateContinueStatement,
249            createBreakStatement,
250            updateBreakStatement,
251            createReturnStatement,
252            updateReturnStatement,
253            createWithStatement,
254            updateWithStatement,
255            createSwitchStatement,
256            updateSwitchStatement,
257            createLabeledStatement,
258            updateLabeledStatement,
259            createThrowStatement,
260            updateThrowStatement,
261            createTryStatement,
262            updateTryStatement,
263            createDebuggerStatement,
264            createVariableDeclaration,
265            updateVariableDeclaration,
266            createVariableDeclarationList,
267            updateVariableDeclarationList,
268            createFunctionDeclaration,
269            updateFunctionDeclaration,
270            createClassDeclaration,
271            updateClassDeclaration,
272            createStructDeclaration,
273            updateStructDeclaration,
274            createInterfaceDeclaration,
275            updateInterfaceDeclaration,
276            createTypeAliasDeclaration,
277            updateTypeAliasDeclaration,
278            createEnumDeclaration,
279            updateEnumDeclaration,
280            createModuleDeclaration,
281            updateModuleDeclaration,
282            createModuleBlock,
283            updateModuleBlock,
284            createCaseBlock,
285            updateCaseBlock,
286            createNamespaceExportDeclaration,
287            updateNamespaceExportDeclaration,
288            createImportEqualsDeclaration,
289            updateImportEqualsDeclaration,
290            createImportDeclaration,
291            updateImportDeclaration,
292            createImportClause,
293            updateImportClause,
294            createNamespaceImport,
295            updateNamespaceImport,
296            createNamespaceExport,
297            updateNamespaceExport,
298            createNamedImports,
299            updateNamedImports,
300            createImportSpecifier,
301            updateImportSpecifier,
302            createExportAssignment,
303            updateExportAssignment,
304            createExportDeclaration,
305            updateExportDeclaration,
306            createNamedExports,
307            updateNamedExports,
308            createExportSpecifier,
309            updateExportSpecifier,
310            createMissingDeclaration,
311            createExternalModuleReference,
312            updateExternalModuleReference,
313            // lazily load factory members for JSDoc types with similar structure
314            get createJSDocAllType() { return getJSDocPrimaryTypeCreateFunction<JSDocAllType>(SyntaxKind.JSDocAllType); },
315            get createJSDocUnknownType() { return getJSDocPrimaryTypeCreateFunction<JSDocUnknownType>(SyntaxKind.JSDocUnknownType); },
316            get createJSDocNonNullableType() { return getJSDocUnaryTypeCreateFunction<JSDocNonNullableType>(SyntaxKind.JSDocNonNullableType); },
317            get updateJSDocNonNullableType() { return getJSDocUnaryTypeUpdateFunction<JSDocNonNullableType>(SyntaxKind.JSDocNonNullableType); },
318            get createJSDocNullableType() { return getJSDocUnaryTypeCreateFunction<JSDocNullableType>(SyntaxKind.JSDocNullableType); },
319            get updateJSDocNullableType() { return getJSDocUnaryTypeUpdateFunction<JSDocNullableType>(SyntaxKind.JSDocNullableType); },
320            get createJSDocOptionalType() { return getJSDocUnaryTypeCreateFunction<JSDocOptionalType>(SyntaxKind.JSDocOptionalType); },
321            get updateJSDocOptionalType() { return getJSDocUnaryTypeUpdateFunction<JSDocOptionalType>(SyntaxKind.JSDocOptionalType); },
322            get createJSDocVariadicType() { return getJSDocUnaryTypeCreateFunction<JSDocVariadicType>(SyntaxKind.JSDocVariadicType); },
323            get updateJSDocVariadicType() { return getJSDocUnaryTypeUpdateFunction<JSDocVariadicType>(SyntaxKind.JSDocVariadicType); },
324            get createJSDocNamepathType() { return getJSDocUnaryTypeCreateFunction<JSDocNamepathType>(SyntaxKind.JSDocNamepathType); },
325            get updateJSDocNamepathType() { return getJSDocUnaryTypeUpdateFunction<JSDocNamepathType>(SyntaxKind.JSDocNamepathType); },
326            createJSDocFunctionType,
327            updateJSDocFunctionType,
328            createJSDocTypeLiteral,
329            updateJSDocTypeLiteral,
330            createJSDocTypeExpression,
331            updateJSDocTypeExpression,
332            createJSDocSignature,
333            updateJSDocSignature,
334            createJSDocTemplateTag,
335            updateJSDocTemplateTag,
336            createJSDocTypedefTag,
337            updateJSDocTypedefTag,
338            createJSDocParameterTag,
339            updateJSDocParameterTag,
340            createJSDocPropertyTag,
341            updateJSDocPropertyTag,
342            createJSDocCallbackTag,
343            updateJSDocCallbackTag,
344            createJSDocAugmentsTag,
345            updateJSDocAugmentsTag,
346            createJSDocImplementsTag,
347            updateJSDocImplementsTag,
348            createJSDocSeeTag,
349            updateJSDocSeeTag,
350            createJSDocNameReference,
351            updateJSDocNameReference,
352            // lazily load factory members for JSDoc tags with similar structure
353            get createJSDocTypeTag() { return getJSDocTypeLikeTagCreateFunction<JSDocTypeTag>(SyntaxKind.JSDocTypeTag); },
354            get updateJSDocTypeTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocTypeTag>(SyntaxKind.JSDocTypeTag); },
355            get createJSDocReturnTag() { return getJSDocTypeLikeTagCreateFunction<JSDocReturnTag>(SyntaxKind.JSDocReturnTag); },
356            get updateJSDocReturnTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocReturnTag>(SyntaxKind.JSDocReturnTag); },
357            get createJSDocThisTag() { return getJSDocTypeLikeTagCreateFunction<JSDocThisTag>(SyntaxKind.JSDocThisTag); },
358            get updateJSDocThisTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocThisTag>(SyntaxKind.JSDocThisTag); },
359            get createJSDocEnumTag() { return getJSDocTypeLikeTagCreateFunction<JSDocEnumTag>(SyntaxKind.JSDocEnumTag); },
360            get updateJSDocEnumTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocEnumTag>(SyntaxKind.JSDocEnumTag); },
361            get createJSDocAuthorTag() { return getJSDocSimpleTagCreateFunction<JSDocAuthorTag>(SyntaxKind.JSDocAuthorTag); },
362            get updateJSDocAuthorTag() { return getJSDocSimpleTagUpdateFunction<JSDocAuthorTag>(SyntaxKind.JSDocAuthorTag); },
363            get createJSDocClassTag() { return getJSDocSimpleTagCreateFunction<JSDocClassTag>(SyntaxKind.JSDocClassTag); },
364            get updateJSDocClassTag() { return getJSDocSimpleTagUpdateFunction<JSDocClassTag>(SyntaxKind.JSDocClassTag); },
365            get createJSDocPublicTag() { return getJSDocSimpleTagCreateFunction<JSDocPublicTag>(SyntaxKind.JSDocPublicTag); },
366            get updateJSDocPublicTag() { return getJSDocSimpleTagUpdateFunction<JSDocPublicTag>(SyntaxKind.JSDocPublicTag); },
367            get createJSDocPrivateTag() { return getJSDocSimpleTagCreateFunction<JSDocPrivateTag>(SyntaxKind.JSDocPrivateTag); },
368            get updateJSDocPrivateTag() { return getJSDocSimpleTagUpdateFunction<JSDocPrivateTag>(SyntaxKind.JSDocPrivateTag); },
369            get createJSDocProtectedTag() { return getJSDocSimpleTagCreateFunction<JSDocProtectedTag>(SyntaxKind.JSDocProtectedTag); },
370            get updateJSDocProtectedTag() { return getJSDocSimpleTagUpdateFunction<JSDocProtectedTag>(SyntaxKind.JSDocProtectedTag); },
371            get createJSDocReadonlyTag() { return getJSDocSimpleTagCreateFunction<JSDocReadonlyTag>(SyntaxKind.JSDocReadonlyTag); },
372            get updateJSDocReadonlyTag() { return getJSDocSimpleTagUpdateFunction<JSDocReadonlyTag>(SyntaxKind.JSDocReadonlyTag); },
373            get createJSDocDeprecatedTag() { return getJSDocSimpleTagCreateFunction<JSDocDeprecatedTag>(SyntaxKind.JSDocDeprecatedTag); },
374            get updateJSDocDeprecatedTag() { return getJSDocSimpleTagUpdateFunction<JSDocDeprecatedTag>(SyntaxKind.JSDocDeprecatedTag); },
375            createJSDocUnknownTag,
376            updateJSDocUnknownTag,
377            createJSDocComment,
378            updateJSDocComment,
379            createJsxElement,
380            updateJsxElement,
381            createJsxSelfClosingElement,
382            updateJsxSelfClosingElement,
383            createJsxOpeningElement,
384            updateJsxOpeningElement,
385            createJsxClosingElement,
386            updateJsxClosingElement,
387            createJsxFragment,
388            createJsxText,
389            updateJsxText,
390            createJsxOpeningFragment,
391            createJsxJsxClosingFragment,
392            updateJsxFragment,
393            createJsxAttribute,
394            updateJsxAttribute,
395            createJsxAttributes,
396            updateJsxAttributes,
397            createJsxSpreadAttribute,
398            updateJsxSpreadAttribute,
399            createJsxExpression,
400            updateJsxExpression,
401            createCaseClause,
402            updateCaseClause,
403            createDefaultClause,
404            updateDefaultClause,
405            createHeritageClause,
406            updateHeritageClause,
407            createCatchClause,
408            updateCatchClause,
409            createPropertyAssignment,
410            updatePropertyAssignment,
411            createShorthandPropertyAssignment,
412            updateShorthandPropertyAssignment,
413            createSpreadAssignment,
414            updateSpreadAssignment,
415            createEnumMember,
416            updateEnumMember,
417            createSourceFile,
418            updateSourceFile,
419            createBundle,
420            updateBundle,
421            createUnparsedSource,
422            createUnparsedPrologue,
423            createUnparsedPrepend,
424            createUnparsedTextLike,
425            createUnparsedSyntheticReference,
426            createInputFiles,
427            createSyntheticExpression,
428            createSyntaxList,
429            createNotEmittedStatement,
430            createPartiallyEmittedExpression,
431            updatePartiallyEmittedExpression,
432            createCommaListExpression,
433            updateCommaListExpression,
434            createEndOfDeclarationMarker,
435            createMergeDeclarationMarker,
436            createSyntheticReferenceExpression,
437            updateSyntheticReferenceExpression,
438            cloneNode,
439
440            // Lazily load factory methods for common operator factories and utilities
441            get createComma() { return getBinaryCreateFunction(SyntaxKind.CommaToken); },
442            get createAssignment() { return getBinaryCreateFunction(SyntaxKind.EqualsToken) as NodeFactory["createAssignment"]; },
443            get createLogicalOr() { return getBinaryCreateFunction(SyntaxKind.BarBarToken); },
444            get createLogicalAnd() { return getBinaryCreateFunction(SyntaxKind.AmpersandAmpersandToken); },
445            get createBitwiseOr() { return getBinaryCreateFunction(SyntaxKind.BarToken); },
446            get createBitwiseXor() { return getBinaryCreateFunction(SyntaxKind.CaretToken); },
447            get createBitwiseAnd() { return getBinaryCreateFunction(SyntaxKind.AmpersandToken); },
448            get createStrictEquality() { return getBinaryCreateFunction(SyntaxKind.EqualsEqualsEqualsToken); },
449            get createStrictInequality() { return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsEqualsToken); },
450            get createEquality() { return getBinaryCreateFunction(SyntaxKind.EqualsEqualsToken); },
451            get createInequality() { return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsToken); },
452            get createLessThan() { return getBinaryCreateFunction(SyntaxKind.LessThanToken); },
453            get createLessThanEquals() { return getBinaryCreateFunction(SyntaxKind.LessThanEqualsToken); },
454            get createGreaterThan() { return getBinaryCreateFunction(SyntaxKind.GreaterThanToken); },
455            get createGreaterThanEquals() { return getBinaryCreateFunction(SyntaxKind.GreaterThanEqualsToken); },
456            get createLeftShift() { return getBinaryCreateFunction(SyntaxKind.LessThanLessThanToken); },
457            get createRightShift() { return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanToken); },
458            get createUnsignedRightShift() { return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); },
459            get createAdd() { return getBinaryCreateFunction(SyntaxKind.PlusToken); },
460            get createSubtract() { return getBinaryCreateFunction(SyntaxKind.MinusToken); },
461            get createMultiply() { return getBinaryCreateFunction(SyntaxKind.AsteriskToken); },
462            get createDivide() { return getBinaryCreateFunction(SyntaxKind.SlashToken); },
463            get createModulo() { return getBinaryCreateFunction(SyntaxKind.PercentToken); },
464            get createExponent() { return getBinaryCreateFunction(SyntaxKind.AsteriskAsteriskToken); },
465            get createPrefixPlus() { return getPrefixUnaryCreateFunction(SyntaxKind.PlusToken); },
466            get createPrefixMinus() { return getPrefixUnaryCreateFunction(SyntaxKind.MinusToken); },
467            get createPrefixIncrement() { return getPrefixUnaryCreateFunction(SyntaxKind.PlusPlusToken); },
468            get createPrefixDecrement() { return getPrefixUnaryCreateFunction(SyntaxKind.MinusMinusToken); },
469            get createBitwiseNot() { return getPrefixUnaryCreateFunction(SyntaxKind.TildeToken); },
470            get createLogicalNot() { return getPrefixUnaryCreateFunction(SyntaxKind.ExclamationToken); },
471            get createPostfixIncrement() { return getPostfixUnaryCreateFunction(SyntaxKind.PlusPlusToken); },
472            get createPostfixDecrement() { return getPostfixUnaryCreateFunction(SyntaxKind.MinusMinusToken); },
473
474            // Compound nodes
475            createImmediatelyInvokedFunctionExpression,
476            createImmediatelyInvokedArrowFunction,
477            createVoidZero,
478            createExportDefault,
479            createExternalModuleExport,
480            createTypeCheck,
481            createMethodCall,
482            createGlobalMethodCall,
483            createFunctionBindCall,
484            createFunctionCallCall,
485            createFunctionApplyCall,
486            createArraySliceCall,
487            createArrayConcatCall,
488            createObjectDefinePropertyCall,
489            createPropertyDescriptor,
490            createCallBinding,
491
492            // Utilities
493            inlineExpressions,
494            getInternalName,
495            getLocalName,
496            getExportName,
497            getDeclarationName,
498            getNamespaceMemberName,
499            getExternalModuleOrNamespaceExportName,
500            restoreOuterExpressions,
501            restoreEnclosingLabel,
502            createUseStrictPrologue,
503            copyPrologue,
504            copyStandardPrologue,
505            copyCustomPrologue,
506            ensureUseStrict,
507            liftToBlock,
508            mergeLexicalEnvironment,
509            updateModifiers,
510        };
511
512        return factory;
513
514        // @api
515        function createNodeArray<T extends Node>(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray<T> {
516            if (elements === undefined || elements === emptyArray) {
517                elements = [];
518            }
519            else if (isNodeArray(elements)) {
520                // Ensure the transform flags have been aggregated for this NodeArray
521                if (elements.transformFlags === undefined) {
522                    aggregateChildrenFlags(elements as MutableNodeArray<T>);
523                }
524                Debug.attachNodeArrayDebugInfo(elements);
525                return elements;
526            }
527
528            // Since the element list of a node array is typically created by starting with an empty array and
529            // repeatedly calling push(), the list may not have the optimal memory layout. We invoke slice() for
530            // small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation.
531            const length = elements.length;
532            const array = <MutableNodeArray<T>>(length >= 1 && length <= 4 ? elements.slice() : elements);
533            setTextRangePosEnd(array, -1, -1);
534            array.hasTrailingComma = !!hasTrailingComma;
535            aggregateChildrenFlags(array);
536            Debug.attachNodeArrayDebugInfo(array);
537            return array;
538        }
539
540        function createBaseNode<T extends Node>(kind: T["kind"]) {
541            return baseFactory.createBaseNode(kind) as Mutable<T>;
542        }
543
544        function createBaseDeclaration<T extends Declaration | VariableStatement | ImportDeclaration>(
545            kind: T["kind"],
546            decorators: readonly Decorator[] | undefined,
547            modifiers: readonly Modifier[] | undefined
548        ) {
549            const node = createBaseNode(kind);
550            node.decorators = asNodeArray(decorators);
551            node.modifiers = asNodeArray(modifiers);
552            node.transformFlags |=
553                propagateChildrenFlags(node.decorators) |
554                propagateChildrenFlags(node.modifiers);
555            // NOTE: The following properties are commonly set by the binder and are added here to
556            // ensure declarations have a stable shape.
557            node.symbol = undefined!; // initialized by binder
558            node.localSymbol = undefined!; // initialized by binder
559            node.locals = undefined!; // initialized by binder
560            node.nextContainer = undefined!; // initialized by binder
561            return node;
562        }
563
564        function createBaseNamedDeclaration<T extends NamedDeclaration>(
565            kind: T["kind"],
566            decorators: readonly Decorator[] | undefined,
567            modifiers: readonly Modifier[] | undefined,
568            name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined
569        ) {
570            const node = createBaseDeclaration(
571                kind,
572                decorators,
573                modifiers
574            );
575            name = asName(name);
576            node.name = name;
577
578            // The PropertyName of a member is allowed to be `await`.
579            // We don't need to exclude `await` for type signatures since types
580            // don't propagate child flags.
581            if (name) {
582                switch (node.kind) {
583                    case SyntaxKind.MethodDeclaration:
584                    case SyntaxKind.GetAccessor:
585                    case SyntaxKind.SetAccessor:
586                    case SyntaxKind.PropertyDeclaration:
587                    case SyntaxKind.PropertyAssignment:
588                        if (isIdentifier(name)) {
589                            node.transformFlags |= propagateIdentifierNameFlags(name);
590                            break;
591                        }
592                        // fall through
593                    default:
594                        node.transformFlags |= propagateChildFlags(name);
595                        break;
596                }
597            }
598            return node;
599        }
600
601        function createBaseGenericNamedDeclaration<T extends NamedDeclaration & { typeParameters?: NodeArray<TypeParameterDeclaration> }>(
602            kind: T["kind"],
603            decorators: readonly Decorator[] | undefined,
604            modifiers: readonly Modifier[] | undefined,
605            name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined,
606            typeParameters: readonly TypeParameterDeclaration[] | undefined
607        ) {
608            const node = createBaseNamedDeclaration(
609                kind,
610                decorators,
611                modifiers,
612                name
613            );
614            node.typeParameters = asNodeArray(typeParameters);
615            node.transformFlags |= propagateChildrenFlags(node.typeParameters);
616            if (typeParameters) node.transformFlags |= TransformFlags.ContainsTypeScript;
617            return node;
618        }
619
620        function createBaseSignatureDeclaration<T extends SignatureDeclarationBase>(
621            kind: T["kind"],
622            decorators: readonly Decorator[] | undefined,
623            modifiers: readonly Modifier[] | undefined,
624            name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined,
625            typeParameters: readonly TypeParameterDeclaration[] | undefined,
626            parameters: readonly ParameterDeclaration[] | undefined,
627            type: TypeNode | undefined
628        ) {
629            const node = createBaseGenericNamedDeclaration(
630                kind,
631                decorators,
632                modifiers,
633                name,
634                typeParameters
635            );
636            node.parameters = createNodeArray(parameters);
637            node.type = type;
638            node.transformFlags |=
639                propagateChildrenFlags(node.parameters) |
640                propagateChildFlags(node.type);
641            if (type) node.transformFlags |= TransformFlags.ContainsTypeScript;
642            return node;
643        }
644
645        function updateBaseSignatureDeclaration<T extends SignatureDeclarationBase>(updated: Mutable<T>, original: T) {
646            // copy children used only for error reporting
647            if (original.typeArguments) updated.typeArguments = original.typeArguments;
648            return update(updated, original);
649        }
650
651        function createBaseFunctionLikeDeclaration<T extends FunctionLikeDeclaration>(
652            kind: T["kind"],
653            decorators: readonly Decorator[] | undefined,
654            modifiers: readonly Modifier[] | undefined,
655            name: Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern | string | undefined,
656            typeParameters: readonly TypeParameterDeclaration[] | undefined,
657            parameters: readonly ParameterDeclaration[] | undefined,
658            type: TypeNode | undefined,
659            body: T["body"]
660        ) {
661            const node = createBaseSignatureDeclaration(
662                kind,
663                decorators,
664                modifiers,
665                name,
666                typeParameters,
667                parameters,
668                type
669            );
670            node.body = body;
671            node.transformFlags |= propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait;
672            if (!body) node.transformFlags |= TransformFlags.ContainsTypeScript;
673            return node;
674        }
675
676        function updateBaseFunctionLikeDeclaration<T extends FunctionLikeDeclaration>(updated: Mutable<T>, original: T) {
677            // copy children used only for error reporting
678            if (original.exclamationToken) updated.exclamationToken = original.exclamationToken;
679            if (original.typeArguments) updated.typeArguments = original.typeArguments;
680            return updateBaseSignatureDeclaration(updated, original);
681        }
682
683        function createBaseInterfaceOrClassLikeDeclaration<T extends InterfaceDeclaration | ClassLikeDeclaration>(
684            kind: T["kind"],
685            decorators: readonly Decorator[] | undefined,
686            modifiers: readonly Modifier[] | undefined,
687            name: string | Identifier | undefined,
688            typeParameters: readonly TypeParameterDeclaration[] | undefined,
689            heritageClauses: readonly HeritageClause[] | undefined
690        ) {
691            const node = createBaseGenericNamedDeclaration(
692                kind,
693                decorators,
694                modifiers,
695                name,
696                typeParameters
697            );
698            node.heritageClauses = asNodeArray(heritageClauses);
699            node.transformFlags |= propagateChildrenFlags(node.heritageClauses);
700            return node;
701        }
702
703        function createBaseClassLikeDeclaration<T extends ClassLikeDeclaration>(
704            kind: T["kind"],
705            decorators: readonly Decorator[] | undefined,
706            modifiers: readonly Modifier[] | undefined,
707            name: string | Identifier | undefined,
708            typeParameters: readonly TypeParameterDeclaration[] | undefined,
709            heritageClauses: readonly HeritageClause[] | undefined,
710            members: readonly ClassElement[]
711        ) {
712            const node = createBaseInterfaceOrClassLikeDeclaration(
713                kind,
714                decorators,
715                modifiers,
716                name,
717                typeParameters,
718                heritageClauses
719            );
720            node.members = createNodeArray(members);
721            node.transformFlags |= propagateChildrenFlags(node.members);
722            return node;
723        }
724
725        function createBaseBindingLikeDeclaration<T extends PropertyDeclaration | VariableDeclaration | ParameterDeclaration | BindingElement>(
726            kind: T["kind"],
727            decorators: readonly Decorator[] | undefined,
728            modifiers: readonly Modifier[] | undefined,
729            name: string | T["name"] | undefined,
730            initializer: Expression | undefined
731        ) {
732            const node = createBaseNamedDeclaration(
733                kind,
734                decorators,
735                modifiers,
736                name
737            );
738            node.initializer = initializer;
739            node.transformFlags |= propagateChildFlags(node.initializer);
740            return node;
741        }
742
743        function createBaseVariableLikeDeclaration<T extends PropertyDeclaration | VariableDeclaration | ParameterDeclaration>(
744            kind: T["kind"],
745            decorators: readonly Decorator[] | undefined,
746            modifiers: readonly Modifier[] | undefined,
747            name: string | T["name"] | undefined,
748            type: TypeNode | undefined,
749            initializer: Expression | undefined
750        ) {
751            const node = createBaseBindingLikeDeclaration(
752                kind,
753                decorators,
754                modifiers,
755                name,
756                initializer
757            );
758            node.type = type;
759            node.transformFlags |= propagateChildFlags(type);
760            if (type) node.transformFlags |= TransformFlags.ContainsTypeScript;
761            return node;
762        }
763
764        //
765        // Literals
766        //
767
768        function createBaseLiteral<T extends LiteralToken>(
769            kind: T["kind"],
770            text: string
771        ) {
772            const node = createBaseToken(kind);
773            node.text = text;
774            return node;
775        }
776
777        // @api
778        function createNumericLiteral(value: string | number, numericLiteralFlags: TokenFlags = TokenFlags.None): NumericLiteral {
779            const node = createBaseLiteral<NumericLiteral>(SyntaxKind.NumericLiteral, typeof value === "number" ? value + "" : value);
780            node.numericLiteralFlags = numericLiteralFlags;
781            if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) node.transformFlags |= TransformFlags.ContainsES2015;
782            return node;
783        }
784
785        // @api
786        function createBigIntLiteral(value: string | PseudoBigInt): BigIntLiteral {
787            const node = createBaseLiteral<BigIntLiteral>(SyntaxKind.BigIntLiteral, typeof value === "string" ? value : pseudoBigIntToString(value) + "n");
788            node.transformFlags |= TransformFlags.ContainsESNext;
789            return node;
790        }
791
792        function createBaseStringLiteral(text: string, isSingleQuote?: boolean) {
793            const node = createBaseLiteral<StringLiteral>(SyntaxKind.StringLiteral, text);
794            node.singleQuote = isSingleQuote;
795            return node;
796        }
797
798        // @api
799        function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral {
800            const node = createBaseStringLiteral(text, isSingleQuote);
801            node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape;
802            if (hasExtendedUnicodeEscape) node.transformFlags |= TransformFlags.ContainsES2015;
803            return node;
804        }
805
806        // @api
807        function createStringLiteralFromNode(sourceNode: PropertyNameLiteral): StringLiteral {
808            const node = createBaseStringLiteral(getTextOfIdentifierOrLiteral(sourceNode), /*isSingleQuote*/ undefined);
809            node.textSourceNode = sourceNode;
810            return node;
811        }
812
813        // @api
814        function createRegularExpressionLiteral(text: string): RegularExpressionLiteral {
815            const node = createBaseLiteral<RegularExpressionLiteral>(SyntaxKind.RegularExpressionLiteral, text);
816            return node;
817        }
818
819        // @api
820        function createLiteralLikeNode(kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, text: string): LiteralToken {
821            switch (kind) {
822                case SyntaxKind.NumericLiteral: return createNumericLiteral(text, /*numericLiteralFlags*/ 0);
823                case SyntaxKind.BigIntLiteral: return createBigIntLiteral(text);
824                case SyntaxKind.StringLiteral: return createStringLiteral(text, /*isSingleQuote*/ undefined);
825                case SyntaxKind.JsxText: return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ false);
826                case SyntaxKind.JsxTextAllWhiteSpaces: return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ true);
827                case SyntaxKind.RegularExpressionLiteral: return createRegularExpressionLiteral(text);
828                case SyntaxKind.NoSubstitutionTemplateLiteral: return createTemplateLiteralLikeNode(kind, text, /*rawText*/ undefined, /*templateFlags*/ 0) as NoSubstitutionTemplateLiteral;
829            }
830        }
831
832        //
833        // Identifiers
834        //
835
836        function createBaseIdentifier(text: string, originalKeywordKind: SyntaxKind | undefined) {
837            if (originalKeywordKind === undefined && text) {
838                originalKeywordKind = stringToToken(text);
839            }
840            if (originalKeywordKind === SyntaxKind.Identifier) {
841                originalKeywordKind = undefined;
842            }
843            const node = baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as Mutable<Identifier>;
844            node.originalKeywordKind = originalKeywordKind;
845            node.escapedText = escapeLeadingUnderscores(text);
846            return node;
847        }
848
849        function createBaseGeneratedIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags) {
850            const node = createBaseIdentifier(text, /*originalKeywordKind*/ undefined) as Mutable<GeneratedIdentifier>;
851            node.autoGenerateFlags = autoGenerateFlags;
852            node.autoGenerateId = nextAutoGenerateId;
853            nextAutoGenerateId++;
854            return node;
855        }
856
857        // @api
858        function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind): Identifier {
859            const node = createBaseIdentifier(text, originalKeywordKind);
860            if (typeArguments) {
861                // NOTE: we do not use `setChildren` here because typeArguments in an identifier do not contribute to transformations
862                node.typeArguments = createNodeArray(typeArguments);
863            }
864            if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) {
865                node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait;
866            }
867            return node;
868        }
869
870        // @api
871        function updateIdentifier(node: Identifier, typeArguments?: NodeArray<TypeNode | TypeParameterDeclaration> | undefined): Identifier {
872            return node.typeArguments !== typeArguments
873                ? update(createIdentifier(idText(node), typeArguments), node)
874                : node;
875        }
876
877        // @api
878        function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean): GeneratedIdentifier {
879            let flags = GeneratedIdentifierFlags.Auto;
880            if (reservedInNestedScopes) flags |= GeneratedIdentifierFlags.ReservedInNestedScopes;
881            const name = createBaseGeneratedIdentifier("", flags);
882            if (recordTempVariable) {
883                recordTempVariable(name);
884            }
885            return name;
886        }
887
888        /** Create a unique temporary variable for use in a loop. */
889        // @api
890        function createLoopVariable(): Identifier {
891            return createBaseGeneratedIdentifier("", GeneratedIdentifierFlags.Loop);
892        }
893
894        /** Create a unique name based on the supplied text. */
895        // @api
896        function createUniqueName(text: string, flags: GeneratedIdentifierFlags = GeneratedIdentifierFlags.None): Identifier {
897            Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags");
898            Debug.assert((flags & (GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)) !== GeneratedIdentifierFlags.FileLevel, "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic");
899            return createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Unique | flags);
900        }
901
902        /** Create a unique name generated for a node. */
903        // @api
904        function getGeneratedNameForNode(node: Node | undefined, flags: GeneratedIdentifierFlags = 0): Identifier {
905            Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags");
906            const name = createBaseGeneratedIdentifier(node && isIdentifier(node) ? idText(node) : "", GeneratedIdentifierFlags.Node | flags);
907            name.original = node;
908            return name;
909        }
910
911        // @api
912        function createPrivateIdentifier(text: string): PrivateIdentifier {
913            if (!startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text);
914            const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable<PrivateIdentifier>;
915            node.escapedText = escapeLeadingUnderscores(text);
916            node.transformFlags |= TransformFlags.ContainsClassFields;
917            return node;
918        }
919
920        //
921        // Punctuation
922        //
923
924        function createBaseToken<T extends Node>(kind: T["kind"]) {
925            return baseFactory.createBaseTokenNode(kind) as Mutable<T>;
926        }
927
928        // @api
929        function createToken(token: SyntaxKind.SuperKeyword): SuperExpression;
930        function createToken(token: SyntaxKind.ThisKeyword): ThisExpression;
931        function createToken(token: SyntaxKind.NullKeyword): NullLiteral;
932        function createToken(token: SyntaxKind.TrueKeyword): TrueLiteral;
933        function createToken(token: SyntaxKind.FalseKeyword): FalseLiteral;
934        function createToken<TKind extends PunctuationSyntaxKind>(token: TKind): PunctuationToken<TKind>;
935        function createToken<TKind extends KeywordTypeSyntaxKind>(token: TKind): KeywordTypeNode<TKind>;
936        function createToken<TKind extends ModifierSyntaxKind>(token: TKind): ModifierToken<TKind>;
937        function createToken<TKind extends KeywordSyntaxKind>(token: TKind): KeywordToken<TKind>;
938        function createToken<TKind extends SyntaxKind.Unknown | SyntaxKind.EndOfFileToken>(token: TKind): Token<TKind>;
939        function createToken<TKind extends SyntaxKind>(token: TKind): Token<TKind>;
940        function createToken<TKind extends SyntaxKind>(token: TKind) {
941            Debug.assert(token >= SyntaxKind.FirstToken && token <= SyntaxKind.LastToken, "Invalid token");
942            Debug.assert(token <= SyntaxKind.FirstTemplateToken || token >= SyntaxKind.LastTemplateToken, "Invalid token. Use 'createTemplateLiteralLikeNode' to create template literals.");
943            Debug.assert(token <= SyntaxKind.FirstLiteralToken || token >= SyntaxKind.LastLiteralToken, "Invalid token. Use 'createLiteralLikeNode' to create literals.");
944            Debug.assert(token !== SyntaxKind.Identifier, "Invalid token. Use 'createIdentifier' to create identifiers");
945            const node = createBaseToken<Token<TKind>>(token);
946            let transformFlags = TransformFlags.None;
947            switch (token) {
948                case SyntaxKind.AsyncKeyword:
949                    // 'async' modifier is ES2017 (async functions) or ES2018 (async generators)
950                    transformFlags =
951                        TransformFlags.ContainsES2017 |
952                        TransformFlags.ContainsES2018;
953                    break;
954
955                case SyntaxKind.PublicKeyword:
956                case SyntaxKind.PrivateKeyword:
957                case SyntaxKind.ProtectedKeyword:
958                case SyntaxKind.ReadonlyKeyword:
959                case SyntaxKind.AbstractKeyword:
960                case SyntaxKind.DeclareKeyword:
961                case SyntaxKind.ConstKeyword:
962                case SyntaxKind.AnyKeyword:
963                case SyntaxKind.NumberKeyword:
964                case SyntaxKind.BigIntKeyword:
965                case SyntaxKind.NeverKeyword:
966                case SyntaxKind.ObjectKeyword:
967                case SyntaxKind.StringKeyword:
968                case SyntaxKind.BooleanKeyword:
969                case SyntaxKind.SymbolKeyword:
970                case SyntaxKind.VoidKeyword:
971                case SyntaxKind.UnknownKeyword:
972                case SyntaxKind.UndefinedKeyword: // `undefined` is an Identifier in the expression case.
973                    transformFlags = TransformFlags.ContainsTypeScript;
974                    break;
975                case SyntaxKind.StaticKeyword:
976                case SyntaxKind.SuperKeyword:
977                    transformFlags = TransformFlags.ContainsES2015;
978                    break;
979                case SyntaxKind.ThisKeyword:
980                    // 'this' indicates a lexical 'this'
981                    transformFlags = TransformFlags.ContainsLexicalThis;
982                    break;
983            }
984            if (transformFlags) {
985                node.transformFlags |= transformFlags;
986            }
987            return node;
988        }
989
990        //
991        // Reserved words
992        //
993
994        // @api
995        function createSuper() {
996            return createToken(SyntaxKind.SuperKeyword);
997        }
998
999        // @api
1000        function createThis() {
1001            return createToken(SyntaxKind.ThisKeyword);
1002        }
1003
1004        // @api
1005        function createNull() {
1006            return createToken(SyntaxKind.NullKeyword);
1007        }
1008
1009        // @api
1010        function createTrue() {
1011            return createToken(SyntaxKind.TrueKeyword);
1012        }
1013
1014        // @api
1015        function createFalse() {
1016            return createToken(SyntaxKind.FalseKeyword);
1017        }
1018
1019        //
1020        // Modifiers
1021        //
1022
1023        // @api
1024        function createModifier<T extends ModifierSyntaxKind>(kind: T) {
1025            return createToken(kind);
1026        }
1027
1028        // @api
1029        function createModifiersFromModifierFlags(flags: ModifierFlags) {
1030            const result: Modifier[] = [];
1031            if (flags & ModifierFlags.Export) { result.push(createModifier(SyntaxKind.ExportKeyword)); }
1032            if (flags & ModifierFlags.Ambient) { result.push(createModifier(SyntaxKind.DeclareKeyword)); }
1033            if (flags & ModifierFlags.Default) { result.push(createModifier(SyntaxKind.DefaultKeyword)); }
1034            if (flags & ModifierFlags.Const) { result.push(createModifier(SyntaxKind.ConstKeyword)); }
1035            if (flags & ModifierFlags.Public) { result.push(createModifier(SyntaxKind.PublicKeyword)); }
1036            if (flags & ModifierFlags.Private) { result.push(createModifier(SyntaxKind.PrivateKeyword)); }
1037            if (flags & ModifierFlags.Protected) { result.push(createModifier(SyntaxKind.ProtectedKeyword)); }
1038            if (flags & ModifierFlags.Abstract) { result.push(createModifier(SyntaxKind.AbstractKeyword)); }
1039            if (flags & ModifierFlags.Static) { result.push(createModifier(SyntaxKind.StaticKeyword)); }
1040            if (flags & ModifierFlags.Readonly) { result.push(createModifier(SyntaxKind.ReadonlyKeyword)); }
1041            if (flags & ModifierFlags.Async) { result.push(createModifier(SyntaxKind.AsyncKeyword)); }
1042            return result;
1043        }
1044
1045        //
1046        // Names
1047        //
1048
1049        // @api
1050        function createQualifiedName(left: EntityName, right: string | Identifier) {
1051            const node = createBaseNode<QualifiedName>(SyntaxKind.QualifiedName);
1052            node.left = left;
1053            node.right = asName(right);
1054            node.transformFlags |=
1055                propagateChildFlags(node.left) |
1056                propagateIdentifierNameFlags(node.right);
1057            return node;
1058        }
1059
1060        // @api
1061        function updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier) {
1062            return node.left !== left
1063                || node.right !== right
1064                ? update(createQualifiedName(left, right), node)
1065                : node;
1066        }
1067
1068        // @api
1069        function createComputedPropertyName(expression: Expression) {
1070            const node = createBaseNode<ComputedPropertyName>(SyntaxKind.ComputedPropertyName);
1071            node.expression = parenthesizerRules().parenthesizeExpressionOfComputedPropertyName(expression);
1072            node.transformFlags |=
1073                propagateChildFlags(node.expression) |
1074                TransformFlags.ContainsES2015 |
1075                TransformFlags.ContainsComputedPropertyName;
1076            return node;
1077        }
1078
1079        // @api
1080        function updateComputedPropertyName(node: ComputedPropertyName, expression: Expression) {
1081            return node.expression !== expression
1082                ? update(createComputedPropertyName(expression), node)
1083                : node;
1084        }
1085
1086        //
1087        // Signature elements
1088        //
1089
1090        // @api
1091        function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) {
1092            const node = createBaseNamedDeclaration<TypeParameterDeclaration>(
1093                SyntaxKind.TypeParameter,
1094                /*decorators*/ undefined,
1095                /*modifiers*/ undefined,
1096                name
1097            );
1098            node.constraint = constraint;
1099            node.default = defaultType;
1100            node.transformFlags = TransformFlags.ContainsTypeScript;
1101            return node;
1102        }
1103
1104        // @api
1105        function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
1106            return node.name !== name
1107                || node.constraint !== constraint
1108                || node.default !== defaultType
1109                ? update(createTypeParameterDeclaration(name, constraint, defaultType), node)
1110                : node;
1111        }
1112
1113        // @api
1114        function createParameterDeclaration(
1115            decorators: readonly Decorator[] | undefined,
1116            modifiers: readonly Modifier[] | undefined,
1117            dotDotDotToken: DotDotDotToken | undefined,
1118            name: string | BindingName,
1119            questionToken?: QuestionToken,
1120            type?: TypeNode,
1121            initializer?: Expression
1122        ) {
1123            const node = createBaseVariableLikeDeclaration<ParameterDeclaration>(
1124                SyntaxKind.Parameter,
1125                decorators,
1126                modifiers,
1127                name,
1128                type,
1129                initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer)
1130            );
1131            node.dotDotDotToken = dotDotDotToken;
1132            node.questionToken = questionToken;
1133            if (isThisIdentifier(node.name)) {
1134                node.transformFlags = TransformFlags.ContainsTypeScript;
1135            }
1136            else {
1137                node.transformFlags |=
1138                    propagateChildFlags(node.dotDotDotToken) |
1139                    propagateChildFlags(node.questionToken);
1140                if (questionToken) node.transformFlags |= TransformFlags.ContainsTypeScript;
1141                if (modifiersToFlags(node.modifiers) & ModifierFlags.ParameterPropertyModifier) node.transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax;
1142                if (initializer || dotDotDotToken) node.transformFlags |= TransformFlags.ContainsES2015;
1143            }
1144            return node;
1145        }
1146
1147        // @api
1148        function updateParameterDeclaration(
1149            node: ParameterDeclaration,
1150            decorators: readonly Decorator[] | undefined,
1151            modifiers: readonly Modifier[] | undefined,
1152            dotDotDotToken: DotDotDotToken | undefined,
1153            name: string | BindingName,
1154            questionToken: QuestionToken | undefined,
1155            type: TypeNode | undefined,
1156            initializer: Expression | undefined
1157        ) {
1158            return node.decorators !== decorators
1159                || node.modifiers !== modifiers
1160                || node.dotDotDotToken !== dotDotDotToken
1161                || node.name !== name
1162                || node.questionToken !== questionToken
1163                || node.type !== type
1164                || node.initializer !== initializer
1165                ? update(createParameterDeclaration(decorators, modifiers, dotDotDotToken, name, questionToken, type, initializer), node)
1166                : node;
1167        }
1168
1169        // @api
1170        function createDecorator(expression: Expression) {
1171            const node = createBaseNode<Decorator>(SyntaxKind.Decorator);
1172            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
1173            node.transformFlags |=
1174                propagateChildFlags(node.expression) |
1175                TransformFlags.ContainsTypeScript |
1176                TransformFlags.ContainsTypeScriptClassSyntax;
1177            return node;
1178        }
1179
1180        // @api
1181        function updateDecorator(node: Decorator, expression: Expression) {
1182            return node.expression !== expression
1183                ? update(createDecorator(expression), node)
1184                : node;
1185        }
1186
1187        //
1188        // Type Elements
1189        //
1190
1191        // @api
1192        function createPropertySignature(
1193            modifiers: readonly Modifier[] | undefined,
1194            name: PropertyName | string,
1195            questionToken: QuestionToken | undefined,
1196            type: TypeNode | undefined
1197        ): PropertySignature {
1198            const node = createBaseNamedDeclaration<PropertySignature>(
1199                SyntaxKind.PropertySignature,
1200                /*decorators*/ undefined,
1201                modifiers,
1202                name
1203            );
1204            node.type = type;
1205            node.questionToken = questionToken;
1206            node.transformFlags = TransformFlags.ContainsTypeScript;
1207            return node;
1208        }
1209
1210        // @api
1211        function updatePropertySignature(
1212            node: PropertySignature,
1213            modifiers: readonly Modifier[] | undefined,
1214            name: PropertyName,
1215            questionToken: QuestionToken | undefined,
1216            type: TypeNode | undefined
1217        ) {
1218            return node.modifiers !== modifiers
1219                || node.name !== name
1220                || node.questionToken !== questionToken
1221                || node.type !== type
1222                ? update(createPropertySignature(modifiers, name, questionToken, type), node)
1223                : node;
1224        }
1225
1226        // @api
1227        function createPropertyDeclaration(
1228            decorators: readonly Decorator[] | undefined,
1229            modifiers: readonly Modifier[] | undefined,
1230            name: string | PropertyName,
1231            questionOrExclamationToken: QuestionToken | ExclamationToken | undefined,
1232            type: TypeNode | undefined,
1233            initializer: Expression | undefined
1234        ) {
1235            const node = createBaseVariableLikeDeclaration<PropertyDeclaration>(
1236                SyntaxKind.PropertyDeclaration,
1237                decorators,
1238                modifiers,
1239                name,
1240                type,
1241                initializer
1242            );
1243            node.questionToken = questionOrExclamationToken && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined;
1244            node.exclamationToken = questionOrExclamationToken && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined;
1245            node.transformFlags |=
1246                propagateChildFlags(node.questionToken) |
1247                propagateChildFlags(node.exclamationToken) |
1248                TransformFlags.ContainsClassFields;
1249            if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) {
1250                node.transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax;
1251            }
1252            if (questionOrExclamationToken || modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) {
1253                node.transformFlags |= TransformFlags.ContainsTypeScript;
1254            }
1255            return node;
1256        }
1257
1258        // @api
1259        function updatePropertyDeclaration(
1260            node: PropertyDeclaration,
1261            decorators: readonly Decorator[] | undefined,
1262            modifiers: readonly Modifier[] | undefined,
1263            name: string | PropertyName,
1264            questionOrExclamationToken: QuestionToken | ExclamationToken | undefined,
1265            type: TypeNode | undefined,
1266            initializer: Expression | undefined
1267        ) {
1268            return node.decorators !== decorators
1269                || node.modifiers !== modifiers
1270                || node.name !== name
1271                || node.questionToken !== (questionOrExclamationToken !== undefined && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined)
1272                || node.exclamationToken !== (questionOrExclamationToken !== undefined && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined)
1273                || node.type !== type
1274                || node.initializer !== initializer
1275                ? update(createPropertyDeclaration(decorators, modifiers, name, questionOrExclamationToken, type, initializer), node)
1276                : node;
1277        }
1278
1279        // @api
1280        function createMethodSignature(
1281            modifiers: readonly Modifier[] | undefined,
1282            name: string | PropertyName,
1283            questionToken: QuestionToken | undefined,
1284            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1285            parameters: readonly ParameterDeclaration[],
1286            type: TypeNode | undefined
1287        ) {
1288            const node = createBaseSignatureDeclaration<MethodSignature>(
1289                SyntaxKind.MethodSignature,
1290                /*decorators*/ undefined,
1291                modifiers,
1292                name,
1293                typeParameters,
1294                parameters,
1295                type
1296            );
1297            node.questionToken = questionToken;
1298            node.transformFlags = TransformFlags.ContainsTypeScript;
1299            return node;
1300        }
1301
1302        // @api
1303        function updateMethodSignature(
1304            node: MethodSignature,
1305            modifiers: readonly Modifier[] | undefined,
1306            name: PropertyName,
1307            questionToken: QuestionToken | undefined,
1308            typeParameters: NodeArray<TypeParameterDeclaration> | undefined,
1309            parameters: NodeArray<ParameterDeclaration>,
1310            type: TypeNode | undefined
1311        ) {
1312            return node.modifiers !== modifiers
1313                || node.name !== name
1314                || node.questionToken !== questionToken
1315                || node.typeParameters !== typeParameters
1316                || node.parameters !== parameters
1317                || node.type !== type
1318                ? updateBaseSignatureDeclaration(createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type), node)
1319                : node;
1320        }
1321
1322        // @api
1323        function createMethodDeclaration(
1324            decorators: readonly Decorator[] | undefined,
1325            modifiers: readonly Modifier[] | undefined,
1326            asteriskToken: AsteriskToken | undefined,
1327            name: string | PropertyName,
1328            questionToken: QuestionToken | undefined,
1329            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1330            parameters: readonly ParameterDeclaration[],
1331            type: TypeNode | undefined,
1332            body: Block | undefined
1333        ) {
1334            const node = createBaseFunctionLikeDeclaration<MethodDeclaration>(
1335                SyntaxKind.MethodDeclaration,
1336                decorators,
1337                modifiers,
1338                name,
1339                typeParameters,
1340                parameters,
1341                type,
1342                body
1343            );
1344            node.asteriskToken = asteriskToken;
1345            node.questionToken = questionToken;
1346            node.transformFlags |=
1347                propagateChildFlags(node.asteriskToken) |
1348                propagateChildFlags(node.questionToken) |
1349                TransformFlags.ContainsES2015;
1350            if (questionToken) {
1351                node.transformFlags |= TransformFlags.ContainsTypeScript;
1352            }
1353            if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) {
1354                if (asteriskToken) {
1355                    node.transformFlags |= TransformFlags.ContainsES2018;
1356                }
1357                else {
1358                    node.transformFlags |= TransformFlags.ContainsES2017;
1359                }
1360            }
1361            else if (asteriskToken) {
1362                node.transformFlags |= TransformFlags.ContainsGenerator;
1363            }
1364            return node;
1365        }
1366
1367        // @api
1368        function updateMethodDeclaration(
1369            node: MethodDeclaration,
1370            decorators: readonly Decorator[] | undefined,
1371            modifiers: readonly Modifier[] | undefined,
1372            asteriskToken: AsteriskToken | undefined,
1373            name: PropertyName,
1374            questionToken: QuestionToken | undefined,
1375            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1376            parameters: readonly ParameterDeclaration[],
1377            type: TypeNode | undefined,
1378            body: Block | undefined
1379        ) {
1380            return node.decorators !== decorators
1381                || node.modifiers !== modifiers
1382                || node.asteriskToken !== asteriskToken
1383                || node.name !== name
1384                || node.questionToken !== questionToken
1385                || node.typeParameters !== typeParameters
1386                || node.parameters !== parameters
1387                || node.type !== type
1388                || node.body !== body
1389                ? updateBaseFunctionLikeDeclaration(createMethodDeclaration(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node)
1390                : node;
1391        }
1392
1393        // @api
1394        function createConstructorDeclaration(
1395            decorators: readonly Decorator[] | undefined,
1396            modifiers: readonly Modifier[] | undefined,
1397            parameters: readonly ParameterDeclaration[],
1398            body: Block | undefined
1399        ) {
1400            const node = createBaseFunctionLikeDeclaration<ConstructorDeclaration>(
1401                SyntaxKind.Constructor,
1402                decorators,
1403                modifiers,
1404                /*name*/ undefined,
1405                /*typeParameters*/ undefined,
1406                parameters,
1407                /*type*/ undefined,
1408                body
1409            );
1410            node.transformFlags |= TransformFlags.ContainsES2015;
1411            return node;
1412        }
1413
1414        // @api
1415        function updateConstructorDeclaration(
1416            node: ConstructorDeclaration,
1417            decorators: readonly Decorator[] | undefined,
1418            modifiers: readonly Modifier[] | undefined,
1419            parameters: readonly ParameterDeclaration[],
1420            body: Block | undefined
1421        ) {
1422            return node.decorators !== decorators
1423                || node.modifiers !== modifiers
1424                || node.parameters !== parameters
1425                || node.body !== body
1426                ? updateBaseFunctionLikeDeclaration(createConstructorDeclaration(decorators, modifiers, parameters, body), node)
1427                : node;
1428        }
1429
1430        // @api
1431        function createGetAccessorDeclaration(
1432            decorators: readonly Decorator[] | undefined,
1433            modifiers: readonly Modifier[] | undefined,
1434            name: string | PropertyName,
1435            parameters: readonly ParameterDeclaration[],
1436            type: TypeNode | undefined,
1437            body: Block | undefined
1438        ) {
1439            return createBaseFunctionLikeDeclaration<GetAccessorDeclaration>(
1440                SyntaxKind.GetAccessor,
1441                decorators,
1442                modifiers,
1443                name,
1444                /*typeParameters*/ undefined,
1445                parameters,
1446                type,
1447                body
1448            );
1449        }
1450
1451        // @api
1452        function updateGetAccessorDeclaration(
1453            node: GetAccessorDeclaration,
1454            decorators: readonly Decorator[] | undefined,
1455            modifiers: readonly Modifier[] | undefined,
1456            name: PropertyName,
1457            parameters: readonly ParameterDeclaration[],
1458            type: TypeNode | undefined,
1459            body: Block | undefined
1460        ) {
1461            return node.decorators !== decorators
1462                || node.modifiers !== modifiers
1463                || node.name !== name
1464                || node.parameters !== parameters
1465                || node.type !== type
1466                || node.body !== body
1467                ? updateBaseFunctionLikeDeclaration(createGetAccessorDeclaration(decorators, modifiers, name, parameters, type, body), node)
1468                : node;
1469        }
1470
1471        // @api
1472        function createSetAccessorDeclaration(
1473            decorators: readonly Decorator[] | undefined,
1474            modifiers: readonly Modifier[] | undefined,
1475            name: string | PropertyName,
1476            parameters: readonly ParameterDeclaration[],
1477            body: Block | undefined
1478        ) {
1479            return createBaseFunctionLikeDeclaration<SetAccessorDeclaration>(
1480                SyntaxKind.SetAccessor,
1481                decorators,
1482                modifiers,
1483                name,
1484                /*typeParameters*/ undefined,
1485                parameters,
1486                /*type*/ undefined,
1487                body
1488            );
1489        }
1490
1491        // @api
1492        function updateSetAccessorDeclaration(
1493            node: SetAccessorDeclaration,
1494            decorators: readonly Decorator[] | undefined,
1495            modifiers: readonly Modifier[] | undefined,
1496            name: PropertyName,
1497            parameters: readonly ParameterDeclaration[],
1498            body: Block | undefined
1499        ) {
1500            return node.decorators !== decorators
1501                || node.modifiers !== modifiers
1502                || node.name !== name
1503                || node.parameters !== parameters
1504                || node.body !== body
1505                ? updateBaseFunctionLikeDeclaration(createSetAccessorDeclaration(decorators, modifiers, name, parameters, body), node)
1506                : node;
1507        }
1508
1509        // @api
1510        function createCallSignature(
1511            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1512            parameters: readonly ParameterDeclaration[],
1513            type: TypeNode | undefined
1514        ): CallSignatureDeclaration {
1515            const node = createBaseSignatureDeclaration<CallSignatureDeclaration>(
1516                SyntaxKind.CallSignature,
1517                /*decorators*/ undefined,
1518                /*modifiers*/ undefined,
1519                /*name*/ undefined,
1520                typeParameters,
1521                parameters,
1522                type
1523            );
1524            node.transformFlags = TransformFlags.ContainsTypeScript;
1525            return node;
1526        }
1527
1528        // @api
1529        function updateCallSignature(
1530            node: CallSignatureDeclaration,
1531            typeParameters: NodeArray<TypeParameterDeclaration> | undefined,
1532            parameters: NodeArray<ParameterDeclaration>,
1533            type: TypeNode | undefined
1534        ) {
1535            return node.typeParameters !== typeParameters
1536                || node.parameters !== parameters
1537                || node.type !== type
1538                ? updateBaseSignatureDeclaration(createCallSignature(typeParameters, parameters, type), node)
1539                : node;
1540        }
1541
1542        // @api
1543        function createConstructSignature(
1544            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1545            parameters: readonly ParameterDeclaration[],
1546            type: TypeNode | undefined
1547        ): ConstructSignatureDeclaration {
1548            const node = createBaseSignatureDeclaration<ConstructSignatureDeclaration>(
1549                SyntaxKind.ConstructSignature,
1550                /*decorators*/ undefined,
1551                /*modifiers*/ undefined,
1552                /*name*/ undefined,
1553                typeParameters,
1554                parameters,
1555                type
1556            );
1557            node.transformFlags = TransformFlags.ContainsTypeScript;
1558            return node;
1559        }
1560
1561        // @api
1562        function updateConstructSignature(
1563            node: ConstructSignatureDeclaration,
1564            typeParameters: NodeArray<TypeParameterDeclaration> | undefined,
1565            parameters: NodeArray<ParameterDeclaration>,
1566            type: TypeNode | undefined
1567        ) {
1568            return node.typeParameters !== typeParameters
1569                || node.parameters !== parameters
1570                || node.type !== type
1571                ? updateBaseSignatureDeclaration(createConstructSignature(typeParameters, parameters, type), node)
1572                : node;
1573        }
1574
1575        // @api
1576        function createIndexSignature(
1577            decorators: readonly Decorator[] | undefined,
1578            modifiers: readonly Modifier[] | undefined,
1579            parameters: readonly ParameterDeclaration[],
1580            type: TypeNode | undefined
1581        ): IndexSignatureDeclaration {
1582            const node = createBaseSignatureDeclaration<IndexSignatureDeclaration>(
1583                SyntaxKind.IndexSignature,
1584                decorators,
1585                modifiers,
1586                /*name*/ undefined,
1587                /*typeParameters*/ undefined,
1588                parameters,
1589                type
1590            );
1591            node.transformFlags = TransformFlags.ContainsTypeScript;
1592            return node;
1593        }
1594
1595        // @api
1596        function updateIndexSignature(
1597            node: IndexSignatureDeclaration,
1598            decorators: readonly Decorator[] | undefined,
1599            modifiers: readonly Modifier[] | undefined,
1600            parameters: readonly ParameterDeclaration[],
1601            type: TypeNode
1602        ) {
1603            return node.parameters !== parameters
1604                || node.type !== type
1605                || node.decorators !== decorators
1606                || node.modifiers !== modifiers
1607                ? updateBaseSignatureDeclaration(createIndexSignature(decorators, modifiers, parameters, type), node)
1608                : node;
1609        }
1610
1611        // @api
1612        function createTemplateLiteralTypeSpan(type: TypeNode, literal: TemplateMiddle | TemplateTail) {
1613            const node = createBaseNode<TemplateLiteralTypeSpan>(SyntaxKind.TemplateLiteralTypeSpan);
1614            node.type = type;
1615            node.literal = literal;
1616            node.transformFlags = TransformFlags.ContainsTypeScript;
1617            return node;
1618        }
1619
1620        // @api
1621        function updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail) {
1622            return node.type !== type
1623                || node.literal !== literal
1624                ? update(createTemplateLiteralTypeSpan(type, literal), node)
1625                : node;
1626        }
1627
1628        //
1629        // Types
1630        //
1631
1632        // @api
1633        function createKeywordTypeNode<TKind extends KeywordTypeSyntaxKind>(kind: TKind) {
1634            return createToken(kind);
1635        }
1636
1637        // @api
1638        function createTypePredicateNode(assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) {
1639            const node = createBaseNode<TypePredicateNode>(SyntaxKind.TypePredicate);
1640            node.assertsModifier = assertsModifier;
1641            node.parameterName = asName(parameterName);
1642            node.type = type;
1643            node.transformFlags = TransformFlags.ContainsTypeScript;
1644            return node;
1645        }
1646
1647        // @api
1648        function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) {
1649            return node.assertsModifier !== assertsModifier
1650                || node.parameterName !== parameterName
1651                || node.type !== type
1652                ? update(createTypePredicateNode(assertsModifier, parameterName, type), node)
1653                : node;
1654        }
1655
1656        // @api
1657        function createTypeReferenceNode(typeName: string | EntityName, typeArguments: readonly TypeNode[] | undefined) {
1658            const node = createBaseNode<TypeReferenceNode>(SyntaxKind.TypeReference);
1659            node.typeName = asName(typeName);
1660            node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments));
1661            node.transformFlags = TransformFlags.ContainsTypeScript;
1662            return node;
1663        }
1664
1665        // @api
1666        function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray<TypeNode> | undefined) {
1667            return node.typeName !== typeName
1668                || node.typeArguments !== typeArguments
1669                ? update(createTypeReferenceNode(typeName, typeArguments), node)
1670                : node;
1671        }
1672
1673        // @api
1674        function createFunctionTypeNode(
1675            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1676            parameters: readonly ParameterDeclaration[],
1677            type: TypeNode | undefined
1678        ): FunctionTypeNode {
1679            const node = createBaseSignatureDeclaration<FunctionTypeNode>(
1680                SyntaxKind.FunctionType,
1681                /*decorators*/ undefined,
1682                /*modifiers*/ undefined,
1683                /*name*/ undefined,
1684                typeParameters,
1685                parameters,
1686                type
1687            );
1688            node.transformFlags = TransformFlags.ContainsTypeScript;
1689            return node;
1690        }
1691
1692        // @api
1693        function updateFunctionTypeNode(
1694            node: FunctionTypeNode,
1695            typeParameters: NodeArray<TypeParameterDeclaration> | undefined,
1696            parameters: NodeArray<ParameterDeclaration>,
1697            type: TypeNode | undefined
1698        ) {
1699            return node.typeParameters !== typeParameters
1700                || node.parameters !== parameters
1701                || node.type !== type
1702                ? updateBaseSignatureDeclaration(createFunctionTypeNode(typeParameters, parameters, type), node)
1703                : node;
1704        }
1705
1706        // @api
1707        function createConstructorTypeNode(...args: Parameters<typeof createConstructorTypeNode1 | typeof createConstructorTypeNode2>) {
1708            return args.length === 4 ? createConstructorTypeNode1(...args) :
1709                args.length === 3 ? createConstructorTypeNode2(...args) :
1710                Debug.fail("Incorrect number of arguments specified.");
1711        }
1712
1713        function createConstructorTypeNode1(
1714            modifiers: readonly Modifier[] | undefined,
1715            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1716            parameters: readonly ParameterDeclaration[],
1717            type: TypeNode | undefined
1718        ): ConstructorTypeNode {
1719            const node = createBaseSignatureDeclaration<ConstructorTypeNode>(
1720                SyntaxKind.ConstructorType,
1721                /*decorators*/ undefined,
1722                modifiers,
1723                /*name*/ undefined,
1724                typeParameters,
1725                parameters,
1726                type
1727            );
1728            node.transformFlags = TransformFlags.ContainsTypeScript;
1729            return node;
1730        }
1731
1732        /** @deprecated */
1733        function createConstructorTypeNode2(
1734            typeParameters: readonly TypeParameterDeclaration[] | undefined,
1735            parameters: readonly ParameterDeclaration[],
1736            type: TypeNode | undefined
1737        ): ConstructorTypeNode {
1738            return createConstructorTypeNode1(/*modifiers*/ undefined, typeParameters, parameters, type);
1739        }
1740
1741        // @api
1742        function updateConstructorTypeNode(...args: Parameters<typeof updateConstructorTypeNode1 | typeof updateConstructorTypeNode2>) {
1743            return args.length === 5 ? updateConstructorTypeNode1(...args) :
1744                args.length === 4 ? updateConstructorTypeNode2(...args) :
1745                Debug.fail("Incorrect number of arguments specified.");
1746        }
1747
1748        function updateConstructorTypeNode1(
1749            node: ConstructorTypeNode,
1750            modifiers: readonly Modifier[] | undefined,
1751            typeParameters: NodeArray<TypeParameterDeclaration> | undefined,
1752            parameters: NodeArray<ParameterDeclaration>,
1753            type: TypeNode | undefined
1754        ) {
1755            return node.modifiers !== modifiers
1756                || node.typeParameters !== typeParameters
1757                || node.parameters !== parameters
1758                || node.type !== type
1759                ? updateBaseSignatureDeclaration(createConstructorTypeNode(modifiers, typeParameters, parameters, type), node)
1760                : node;
1761        }
1762
1763        /** @deprecated */
1764        function updateConstructorTypeNode2(
1765            node: ConstructorTypeNode,
1766            typeParameters: NodeArray<TypeParameterDeclaration> | undefined,
1767            parameters: NodeArray<ParameterDeclaration>,
1768            type: TypeNode | undefined
1769        ) {
1770            return updateConstructorTypeNode1(node, node.modifiers, typeParameters, parameters, type);
1771        }
1772
1773        // @api
1774        function createTypeQueryNode(exprName: EntityName) {
1775            const node = createBaseNode<TypeQueryNode>(SyntaxKind.TypeQuery);
1776            node.exprName = exprName;
1777            node.transformFlags = TransformFlags.ContainsTypeScript;
1778            return node;
1779        }
1780
1781        // @api
1782        function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName) {
1783            return node.exprName !== exprName
1784                ? update(createTypeQueryNode(exprName), node)
1785                : node;
1786        }
1787
1788        // @api
1789        function createTypeLiteralNode(members: readonly TypeElement[] | undefined) {
1790            const node = createBaseNode<TypeLiteralNode>(SyntaxKind.TypeLiteral);
1791            node.members = createNodeArray(members);
1792            node.transformFlags = TransformFlags.ContainsTypeScript;
1793            return node;
1794        }
1795
1796        // @api
1797        function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray<TypeElement>) {
1798            return node.members !== members
1799                ? update(createTypeLiteralNode(members), node)
1800                : node;
1801        }
1802
1803        // @api
1804        function createArrayTypeNode(elementType: TypeNode) {
1805            const node = createBaseNode<ArrayTypeNode>(SyntaxKind.ArrayType);
1806            node.elementType = parenthesizerRules().parenthesizeElementTypeOfArrayType(elementType);
1807            node.transformFlags = TransformFlags.ContainsTypeScript;
1808            return node;
1809        }
1810
1811        // @api
1812        function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode {
1813            return node.elementType !== elementType
1814                ? update(createArrayTypeNode(elementType), node)
1815                : node;
1816        }
1817
1818        // @api
1819        function createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]) {
1820            const node = createBaseNode<TupleTypeNode>(SyntaxKind.TupleType);
1821            node.elements = createNodeArray(elements);
1822            node.transformFlags = TransformFlags.ContainsTypeScript;
1823            return node;
1824        }
1825
1826        // @api
1827        function updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]) {
1828            return node.elements !== elements
1829                ? update(createTupleTypeNode(elements), node)
1830                : node;
1831        }
1832
1833        // @api
1834        function createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) {
1835            const node = createBaseNode<NamedTupleMember>(SyntaxKind.NamedTupleMember);
1836            node.dotDotDotToken = dotDotDotToken;
1837            node.name = name;
1838            node.questionToken = questionToken;
1839            node.type = type;
1840            node.transformFlags = TransformFlags.ContainsTypeScript;
1841            return node;
1842        }
1843
1844        // @api
1845        function updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) {
1846            return node.dotDotDotToken !== dotDotDotToken
1847                || node.name !== name
1848                || node.questionToken !== questionToken
1849                || node.type !== type
1850                ? update(createNamedTupleMember(dotDotDotToken, name, questionToken, type), node)
1851                : node;
1852        }
1853
1854        // @api
1855        function createOptionalTypeNode(type: TypeNode) {
1856            const node = createBaseNode<OptionalTypeNode>(SyntaxKind.OptionalType);
1857            node.type = parenthesizerRules().parenthesizeElementTypeOfArrayType(type);
1858            node.transformFlags = TransformFlags.ContainsTypeScript;
1859            return node;
1860        }
1861
1862        // @api
1863        function updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode {
1864            return node.type !== type
1865                ? update(createOptionalTypeNode(type), node)
1866                : node;
1867        }
1868
1869        // @api
1870        function createRestTypeNode(type: TypeNode) {
1871            const node = createBaseNode<RestTypeNode>(SyntaxKind.RestType);
1872            node.type = type;
1873            node.transformFlags = TransformFlags.ContainsTypeScript;
1874            return node;
1875        }
1876
1877        // @api
1878        function updateRestTypeNode(node: RestTypeNode, type: TypeNode): RestTypeNode {
1879            return node.type !== type
1880                ? update(createRestTypeNode(type), node)
1881                : node;
1882        }
1883
1884        function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[]) {
1885            const node = createBaseNode<UnionTypeNode | IntersectionTypeNode>(kind);
1886            node.types = parenthesizerRules().parenthesizeConstituentTypesOfUnionOrIntersectionType(types);
1887            node.transformFlags = TransformFlags.ContainsTypeScript;
1888            return node;
1889        }
1890
1891        function updateUnionOrIntersectionTypeNode<T extends UnionOrIntersectionTypeNode>(node: T, types: NodeArray<TypeNode>): T {
1892            return node.types !== types
1893                ? update(<T>createUnionOrIntersectionTypeNode(node.kind, types), node)
1894                : node;
1895        }
1896
1897        // @api
1898        function createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode {
1899            return <UnionTypeNode>createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types);
1900        }
1901
1902        // @api
1903        function updateUnionTypeNode(node: UnionTypeNode, types: NodeArray<TypeNode>) {
1904            return updateUnionOrIntersectionTypeNode(node, types);
1905        }
1906
1907        // @api
1908        function createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode {
1909            return <IntersectionTypeNode>createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types);
1910        }
1911
1912        // @api
1913        function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray<TypeNode>) {
1914            return updateUnionOrIntersectionTypeNode(node, types);
1915        }
1916
1917        // @api
1918        function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) {
1919            const node = createBaseNode<ConditionalTypeNode>(SyntaxKind.ConditionalType);
1920            node.checkType = parenthesizerRules().parenthesizeMemberOfConditionalType(checkType);
1921            node.extendsType = parenthesizerRules().parenthesizeMemberOfConditionalType(extendsType);
1922            node.trueType = trueType;
1923            node.falseType = falseType;
1924            node.transformFlags = TransformFlags.ContainsTypeScript;
1925            return node;
1926        }
1927
1928        // @api
1929        function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) {
1930            return node.checkType !== checkType
1931                || node.extendsType !== extendsType
1932                || node.trueType !== trueType
1933                || node.falseType !== falseType
1934                ? update(createConditionalTypeNode(checkType, extendsType, trueType, falseType), node)
1935                : node;
1936        }
1937
1938        // @api
1939        function createInferTypeNode(typeParameter: TypeParameterDeclaration) {
1940            const node = createBaseNode<InferTypeNode>(SyntaxKind.InferType);
1941            node.typeParameter = typeParameter;
1942            node.transformFlags = TransformFlags.ContainsTypeScript;
1943            return node;
1944        }
1945
1946        // @api
1947        function updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration) {
1948            return node.typeParameter !== typeParameter
1949                ? update(createInferTypeNode(typeParameter), node)
1950                : node;
1951        }
1952
1953        // @api
1954        function createTemplateLiteralType(head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]) {
1955            const node = createBaseNode<TemplateLiteralTypeNode>(SyntaxKind.TemplateLiteralType);
1956            node.head = head;
1957            node.templateSpans = createNodeArray(templateSpans);
1958            node.transformFlags = TransformFlags.ContainsTypeScript;
1959            return node;
1960        }
1961
1962        // @api
1963        function updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]) {
1964            return node.head !== head
1965                || node.templateSpans !== templateSpans
1966                ? update(createTemplateLiteralType(head, templateSpans), node)
1967                : node;
1968        }
1969
1970        // @api
1971        function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf = false) {
1972            const node = createBaseNode<ImportTypeNode>(SyntaxKind.ImportType);
1973            node.argument = argument;
1974            node.qualifier = qualifier;
1975            node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments);
1976            node.isTypeOf = isTypeOf;
1977            node.transformFlags = TransformFlags.ContainsTypeScript;
1978            return node;
1979        }
1980
1981        // @api
1982        function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf = node.isTypeOf) {
1983            return node.argument !== argument
1984                || node.qualifier !== qualifier
1985                || node.typeArguments !== typeArguments
1986                || node.isTypeOf !== isTypeOf
1987                ? update(createImportTypeNode(argument, qualifier, typeArguments, isTypeOf), node)
1988                : node;
1989        }
1990
1991        // @api
1992        function createParenthesizedType(type: TypeNode) {
1993            const node = createBaseNode<ParenthesizedTypeNode>(SyntaxKind.ParenthesizedType);
1994            node.type = type;
1995            node.transformFlags = TransformFlags.ContainsTypeScript;
1996            return node;
1997        }
1998
1999        // @api
2000        function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode) {
2001            return node.type !== type
2002                ? update(createParenthesizedType(type), node)
2003                : node;
2004        }
2005
2006        // @api
2007        function createThisTypeNode() {
2008            const node = createBaseNode<ThisTypeNode>(SyntaxKind.ThisType);
2009            node.transformFlags = TransformFlags.ContainsTypeScript;
2010            return node;
2011        }
2012
2013        // @api
2014        function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode {
2015            const node = createBaseNode<TypeOperatorNode>(SyntaxKind.TypeOperator);
2016            node.operator = operator;
2017            node.type = parenthesizerRules().parenthesizeMemberOfElementType(type);
2018            node.transformFlags = TransformFlags.ContainsTypeScript;
2019            return node;
2020        }
2021
2022        // @api
2023        function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode) {
2024            return node.type !== type
2025                ? update(createTypeOperatorNode(node.operator, type), node)
2026                : node;
2027        }
2028
2029        // @api
2030        function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
2031            const node = createBaseNode<IndexedAccessTypeNode>(SyntaxKind.IndexedAccessType);
2032            node.objectType = parenthesizerRules().parenthesizeMemberOfElementType(objectType);
2033            node.indexType = indexType;
2034            node.transformFlags = TransformFlags.ContainsTypeScript;
2035            return node;
2036        }
2037
2038        // @api
2039        function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode) {
2040            return node.objectType !== objectType
2041                || node.indexType !== indexType
2042                ? update(createIndexedAccessTypeNode(objectType, indexType), node)
2043                : node;
2044        }
2045
2046        // @api
2047        function createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
2048            const node = createBaseNode<MappedTypeNode>(SyntaxKind.MappedType);
2049            node.readonlyToken = readonlyToken;
2050            node.typeParameter = typeParameter;
2051            node.nameType = nameType;
2052            node.questionToken = questionToken;
2053            node.type = type;
2054            node.transformFlags = TransformFlags.ContainsTypeScript;
2055            return node;
2056        }
2057
2058        // @api
2059        function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
2060            return node.readonlyToken !== readonlyToken
2061                || node.typeParameter !== typeParameter
2062                || node.nameType !== nameType
2063                || node.questionToken !== questionToken
2064                || node.type !== type
2065                ? update(createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type), node)
2066                : node;
2067        }
2068
2069        // @api
2070        function createLiteralTypeNode(literal: LiteralTypeNode["literal"]) {
2071            const node = createBaseNode<LiteralTypeNode>(SyntaxKind.LiteralType);
2072            node.literal = literal;
2073            node.transformFlags = TransformFlags.ContainsTypeScript;
2074            return node;
2075        }
2076
2077        // @api
2078        function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]) {
2079            return node.literal !== literal
2080                ? update(createLiteralTypeNode(literal), node)
2081                : node;
2082        }
2083
2084        //
2085        // Binding Patterns
2086        //
2087
2088        // @api
2089        function createObjectBindingPattern(elements: readonly BindingElement[]) {
2090            const node = createBaseNode<ObjectBindingPattern>(SyntaxKind.ObjectBindingPattern);
2091            node.elements = createNodeArray(elements);
2092            node.transformFlags |=
2093                propagateChildrenFlags(node.elements) |
2094                TransformFlags.ContainsES2015 |
2095                TransformFlags.ContainsBindingPattern;
2096            if (node.transformFlags & TransformFlags.ContainsRestOrSpread) {
2097                node.transformFlags |=
2098                    TransformFlags.ContainsES2018 |
2099                    TransformFlags.ContainsObjectRestOrSpread;
2100            }
2101            return node;
2102        }
2103
2104        // @api
2105        function updateObjectBindingPattern(node: ObjectBindingPattern, elements: readonly BindingElement[]) {
2106            return node.elements !== elements
2107                ? update(createObjectBindingPattern(elements), node)
2108                : node;
2109        }
2110
2111        // @api
2112        function createArrayBindingPattern(elements: readonly ArrayBindingElement[]) {
2113            const node = createBaseNode<ArrayBindingPattern>(SyntaxKind.ArrayBindingPattern);
2114            node.elements = createNodeArray(elements);
2115            node.transformFlags |=
2116                propagateChildrenFlags(node.elements) |
2117                TransformFlags.ContainsES2015 |
2118                TransformFlags.ContainsBindingPattern;
2119            return node;
2120        }
2121
2122        // @api
2123        function updateArrayBindingPattern(node: ArrayBindingPattern, elements: readonly ArrayBindingElement[]) {
2124            return node.elements !== elements
2125                ? update(createArrayBindingPattern(elements), node)
2126                : node;
2127        }
2128
2129        // @api
2130        function createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression) {
2131            const node = createBaseBindingLikeDeclaration<BindingElement>(
2132                SyntaxKind.BindingElement,
2133                /*decorators*/ undefined,
2134                /*modifiers*/ undefined,
2135                name,
2136                initializer
2137            );
2138            node.propertyName = asName(propertyName);
2139            node.dotDotDotToken = dotDotDotToken;
2140            node.transformFlags |=
2141                propagateChildFlags(node.dotDotDotToken) |
2142                TransformFlags.ContainsES2015;
2143            if (node.propertyName) {
2144                node.transformFlags |= isIdentifier(node.propertyName) ?
2145                    propagateIdentifierNameFlags(node.propertyName) :
2146                    propagateChildFlags(node.propertyName);
2147            }
2148            if (dotDotDotToken) node.transformFlags |= TransformFlags.ContainsRestOrSpread;
2149            return node;
2150        }
2151
2152        // @api
2153        function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined) {
2154            return node.propertyName !== propertyName
2155                || node.dotDotDotToken !== dotDotDotToken
2156                || node.name !== name
2157                || node.initializer !== initializer
2158                ? update(createBindingElement(dotDotDotToken, propertyName, name, initializer), node)
2159                : node;
2160        }
2161
2162        //
2163        // Expression
2164        //
2165
2166        function createBaseExpression<T extends Expression>(kind: T["kind"]) {
2167            const node = createBaseNode(kind);
2168            // the following properties are commonly set by the checker/binder
2169            return node;
2170        }
2171
2172        // @api
2173        function createArrayLiteralExpression(elements?: readonly Expression[], multiLine?: boolean) {
2174            const node = createBaseExpression<ArrayLiteralExpression>(SyntaxKind.ArrayLiteralExpression);
2175            node.elements = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(elements));
2176            node.multiLine = multiLine;
2177            node.transformFlags |= propagateChildrenFlags(node.elements);
2178            return node;
2179        }
2180
2181        // @api
2182        function updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]) {
2183            return node.elements !== elements
2184                ? update(createArrayLiteralExpression(elements, node.multiLine), node)
2185                : node;
2186        }
2187
2188        // @api
2189        function createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean) {
2190            const node = createBaseExpression<ObjectLiteralExpression>(SyntaxKind.ObjectLiteralExpression);
2191            node.properties = createNodeArray(properties);
2192            node.multiLine = multiLine;
2193            node.transformFlags |= propagateChildrenFlags(node.properties);
2194            return node;
2195        }
2196
2197        // @api
2198        function updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) {
2199            return node.properties !== properties
2200                ? update(createObjectLiteralExpression(properties, node.multiLine), node)
2201                : node;
2202        }
2203
2204        // @api
2205        function createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier) {
2206            const node = createBaseExpression<PropertyAccessExpression>(SyntaxKind.PropertyAccessExpression);
2207            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
2208            node.name = asName(name);
2209            node.transformFlags =
2210                propagateChildFlags(node.expression) |
2211                (isIdentifier(node.name) ?
2212                    propagateIdentifierNameFlags(node.name) :
2213                    propagateChildFlags(node.name));
2214            if (isSuperKeyword(expression)) {
2215                // super method calls require a lexical 'this'
2216                // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators
2217                node.transformFlags |=
2218                    TransformFlags.ContainsES2017 |
2219                    TransformFlags.ContainsES2018;
2220            }
2221            return node;
2222        }
2223
2224        // @api
2225        function updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) {
2226            if (isPropertyAccessChain(node)) {
2227                return updatePropertyAccessChain(node, expression, node.questionDotToken, cast(name, isIdentifier));
2228            }
2229            return node.expression !== expression
2230                || node.name !== name
2231                ? update(createPropertyAccessExpression(expression, name), node)
2232                : node;
2233        }
2234
2235        // @api
2236        function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) {
2237            const node = createBaseExpression<PropertyAccessChain>(SyntaxKind.PropertyAccessExpression);
2238            node.flags |= NodeFlags.OptionalChain;
2239            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
2240            node.questionDotToken = questionDotToken;
2241            node.name = asName(name);
2242            node.transformFlags |=
2243                TransformFlags.ContainsES2020 |
2244                propagateChildFlags(node.expression) |
2245                propagateChildFlags(node.questionDotToken) |
2246                (isIdentifier(node.name) ?
2247                    propagateIdentifierNameFlags(node.name) :
2248                    propagateChildFlags(node.name));
2249            return node;
2250        }
2251
2252        // @api
2253        function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) {
2254            Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead.");
2255            // Because we are updating an existing PropertyAccessChain we want to inherit its emitFlags
2256            // instead of using the default from createPropertyAccess
2257            return node.expression !== expression
2258                || node.questionDotToken !== questionDotToken
2259                || node.name !== name
2260                ? update(createPropertyAccessChain(expression, questionDotToken, name), node)
2261                : node;
2262        }
2263
2264        // @api
2265        function createElementAccessExpression(expression: Expression, index: number | Expression) {
2266            const node = createBaseExpression<ElementAccessExpression>(SyntaxKind.ElementAccessExpression);
2267            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
2268            node.argumentExpression = asExpression(index);
2269            node.transformFlags |=
2270                propagateChildFlags(node.expression) |
2271                propagateChildFlags(node.argumentExpression);
2272            if (isSuperKeyword(expression)) {
2273                // super method calls require a lexical 'this'
2274                // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators
2275                node.transformFlags |=
2276                    TransformFlags.ContainsES2017 |
2277                    TransformFlags.ContainsES2018;
2278            }
2279            return node;
2280        }
2281
2282        // @api
2283        function updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) {
2284            if (isElementAccessChain(node)) {
2285                return updateElementAccessChain(node, expression, node.questionDotToken, argumentExpression);
2286            }
2287            return node.expression !== expression
2288                || node.argumentExpression !== argumentExpression
2289                ? update(createElementAccessExpression(expression, argumentExpression), node)
2290                : node;
2291        }
2292
2293        // @api
2294        function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression) {
2295            const node = createBaseExpression<ElementAccessChain>(SyntaxKind.ElementAccessExpression);
2296            node.flags |= NodeFlags.OptionalChain;
2297            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
2298            node.questionDotToken = questionDotToken;
2299            node.argumentExpression = asExpression(index);
2300            node.transformFlags |=
2301                propagateChildFlags(node.expression) |
2302                propagateChildFlags(node.questionDotToken) |
2303                propagateChildFlags(node.argumentExpression) |
2304                TransformFlags.ContainsES2020;
2305            return node;
2306        }
2307
2308        // @api
2309        function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression) {
2310            Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead.");
2311            // Because we are updating an existing ElementAccessChain we want to inherit its emitFlags
2312            // instead of using the default from createElementAccess
2313            return node.expression !== expression
2314                || node.questionDotToken !== questionDotToken
2315                || node.argumentExpression !== argumentExpression
2316                ? update(createElementAccessChain(expression, questionDotToken, argumentExpression), node)
2317                : node;
2318        }
2319
2320        // @api
2321        function createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
2322            const node = createBaseExpression<CallExpression>(SyntaxKind.CallExpression);
2323            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
2324            node.typeArguments = asNodeArray(typeArguments);
2325            node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray));
2326            node.transformFlags |=
2327                propagateChildFlags(node.expression) |
2328                propagateChildrenFlags(node.typeArguments) |
2329                propagateChildrenFlags(node.arguments);
2330            if (node.typeArguments) {
2331                node.transformFlags |= TransformFlags.ContainsTypeScript;
2332            }
2333            if (isImportKeyword(node.expression)) {
2334                node.transformFlags |= TransformFlags.ContainsDynamicImport;
2335            }
2336            else if (isSuperProperty(node.expression)) {
2337                node.transformFlags |= TransformFlags.ContainsLexicalThis;
2338            }
2339            return node;
2340        }
2341
2342        // @api
2343        function updateCallExpression(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) {
2344            if (isCallChain(node)) {
2345                return updateCallChain(node, expression, node.questionDotToken, typeArguments, argumentsArray);
2346            }
2347            return node.expression !== expression
2348                || node.typeArguments !== typeArguments
2349                || node.arguments !== argumentsArray
2350                ? update(createCallExpression(expression, typeArguments, argumentsArray), node)
2351                : node;
2352        }
2353
2354        // @api
2355        function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
2356            const node = createBaseExpression<CallChain>(SyntaxKind.CallExpression);
2357            node.flags |= NodeFlags.OptionalChain;
2358            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
2359            node.questionDotToken = questionDotToken;
2360            node.typeArguments = asNodeArray(typeArguments);
2361            node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray));
2362            node.transformFlags |=
2363                propagateChildFlags(node.expression) |
2364                propagateChildFlags(node.questionDotToken) |
2365                propagateChildrenFlags(node.typeArguments) |
2366                propagateChildrenFlags(node.arguments) |
2367                TransformFlags.ContainsES2020;
2368            if (node.typeArguments) {
2369                node.transformFlags |= TransformFlags.ContainsTypeScript;
2370            }
2371            if (isSuperProperty(node.expression)) {
2372                node.transformFlags |= TransformFlags.ContainsLexicalThis;
2373            }
2374            return node;
2375        }
2376
2377        // @api
2378        function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) {
2379            Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallExpression using updateCallChain. Use updateCall instead.");
2380            return node.expression !== expression
2381                || node.questionDotToken !== questionDotToken
2382                || node.typeArguments !== typeArguments
2383                || node.arguments !== argumentsArray
2384                ? update(createCallChain(expression, questionDotToken, typeArguments, argumentsArray), node)
2385                : node;
2386        }
2387
2388        // @api
2389        function createNewExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
2390            const node = createBaseExpression<NewExpression>(SyntaxKind.NewExpression);
2391            node.expression = parenthesizerRules().parenthesizeExpressionOfNew(expression);
2392            node.typeArguments = asNodeArray(typeArguments);
2393            node.arguments = argumentsArray ? parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(argumentsArray) : undefined;
2394            node.transformFlags |=
2395                propagateChildFlags(node.expression) |
2396                propagateChildrenFlags(node.typeArguments) |
2397                propagateChildrenFlags(node.arguments) |
2398                TransformFlags.ContainsES2020;
2399            if (node.typeArguments) {
2400                node.transformFlags |= TransformFlags.ContainsTypeScript;
2401            }
2402            return node;
2403        }
2404
2405        // @api
2406        function updateNewExpression(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
2407            return node.expression !== expression
2408                || node.typeArguments !== typeArguments
2409                || node.arguments !== argumentsArray
2410                ? update(createNewExpression(expression, typeArguments, argumentsArray), node)
2411                : node;
2412        }
2413
2414        // @api
2415        function createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) {
2416            const node = createBaseExpression<TaggedTemplateExpression>(SyntaxKind.TaggedTemplateExpression);
2417            node.tag = parenthesizerRules().parenthesizeLeftSideOfAccess(tag);
2418            node.typeArguments = asNodeArray(typeArguments);
2419            node.template = template;
2420            node.transformFlags |=
2421                propagateChildFlags(node.tag) |
2422                propagateChildrenFlags(node.typeArguments) |
2423                propagateChildFlags(node.template) |
2424                TransformFlags.ContainsES2015;
2425            if (node.typeArguments) {
2426                node.transformFlags |= TransformFlags.ContainsTypeScript;
2427            }
2428            if (hasInvalidEscape(node.template)) {
2429                node.transformFlags |= TransformFlags.ContainsES2018;
2430            }
2431            return node;
2432        }
2433
2434        // @api
2435        function updateTaggedTemplateExpression(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) {
2436            return node.tag !== tag
2437                || node.typeArguments !== typeArguments
2438                || node.template !== template
2439                ? update(createTaggedTemplateExpression(tag, typeArguments, template), node)
2440                : node;
2441        }
2442
2443        // @api
2444        function createTypeAssertion(type: TypeNode, expression: Expression) {
2445            const node = createBaseExpression<TypeAssertion>(SyntaxKind.TypeAssertionExpression);
2446            node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression);
2447            node.type = type;
2448            node.transformFlags |=
2449                propagateChildFlags(node.expression) |
2450                propagateChildFlags(node.type) |
2451                TransformFlags.ContainsTypeScript;
2452            return node;
2453        }
2454
2455        // @api
2456        function updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression) {
2457            return node.type !== type
2458                || node.expression !== expression
2459                ? update(createTypeAssertion(type, expression), node)
2460                : node;
2461        }
2462
2463        // @api
2464        function createParenthesizedExpression(expression: Expression) {
2465            const node = createBaseExpression<ParenthesizedExpression>(SyntaxKind.ParenthesizedExpression);
2466            node.expression = expression;
2467            node.transformFlags = propagateChildFlags(node.expression);
2468            return node;
2469        }
2470
2471        // @api
2472        function updateParenthesizedExpression(node: ParenthesizedExpression, expression: Expression) {
2473            return node.expression !== expression
2474                ? update(createParenthesizedExpression(expression), node)
2475                : node;
2476        }
2477
2478        // @api
2479        function createFunctionExpression(
2480            modifiers: readonly Modifier[] | undefined,
2481            asteriskToken: AsteriskToken | undefined,
2482            name: string | Identifier | undefined,
2483            typeParameters: readonly TypeParameterDeclaration[] | undefined,
2484            parameters: readonly ParameterDeclaration[] | undefined,
2485            type: TypeNode | undefined,
2486            body: Block
2487        ) {
2488            const node = createBaseFunctionLikeDeclaration<FunctionExpression>(
2489                SyntaxKind.FunctionExpression,
2490                /*decorators*/ undefined,
2491                modifiers,
2492                name,
2493                typeParameters,
2494                parameters,
2495                type,
2496                body
2497            );
2498            node.asteriskToken = asteriskToken;
2499            node.transformFlags |= propagateChildFlags(node.asteriskToken);
2500            if (node.typeParameters) {
2501                node.transformFlags |= TransformFlags.ContainsTypeScript;
2502            }
2503            if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) {
2504                if (node.asteriskToken) {
2505                    node.transformFlags |= TransformFlags.ContainsES2018;
2506                }
2507                else {
2508                    node.transformFlags |= TransformFlags.ContainsES2017;
2509                }
2510            }
2511            else if (node.asteriskToken) {
2512                node.transformFlags |= TransformFlags.ContainsGenerator;
2513            }
2514            return node;
2515        }
2516
2517        // @api
2518        function updateFunctionExpression(
2519            node: FunctionExpression,
2520            modifiers: readonly Modifier[] | undefined,
2521            asteriskToken: AsteriskToken | undefined,
2522            name: Identifier | undefined,
2523            typeParameters: readonly TypeParameterDeclaration[] | undefined,
2524            parameters: readonly ParameterDeclaration[],
2525            type: TypeNode | undefined,
2526            body: Block
2527        ) {
2528            return node.name !== name
2529                || node.modifiers !== modifiers
2530                || node.asteriskToken !== asteriskToken
2531                || node.typeParameters !== typeParameters
2532                || node.parameters !== parameters
2533                || node.type !== type
2534                || node.body !== body
2535                ? updateBaseFunctionLikeDeclaration(createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node)
2536                : node;
2537        }
2538
2539        // @api
2540        function createEtsComponentExpression(
2541            name: Identifier,
2542            argumentsArray: readonly Expression[] | undefined,
2543            body: Block | undefined
2544        ) {
2545            const node = createBaseExpression<EtsComponentExpression>(SyntaxKind.EtsComponentExpression);
2546            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(name);
2547            node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray));
2548            node.body = body;
2549            return node;
2550        }
2551
2552        // @api
2553        function updateEtsComponentExpression(
2554            node: EtsComponentExpression,
2555            name: Identifier,
2556            argumentsArray: readonly Expression[] | undefined,
2557            body: Block | undefined
2558        ) {
2559            return node.expression !== name
2560                || node.arguments !== argumentsArray
2561                || node.body !== body
2562                ? createEtsComponentExpression(name, argumentsArray, body)
2563                : node;
2564        }
2565
2566        // @api
2567        function createArrowFunction(
2568            modifiers: readonly Modifier[] | undefined,
2569            typeParameters: readonly TypeParameterDeclaration[] | undefined,
2570            parameters: readonly ParameterDeclaration[],
2571            type: TypeNode | undefined,
2572            equalsGreaterThanToken: EqualsGreaterThanToken | undefined,
2573            body: ConciseBody
2574        ) {
2575            const node = createBaseFunctionLikeDeclaration<ArrowFunction>(
2576                SyntaxKind.ArrowFunction,
2577                /*decorators*/ undefined,
2578                modifiers,
2579                /*name*/ undefined,
2580                typeParameters,
2581                parameters,
2582                type,
2583                parenthesizerRules().parenthesizeConciseBodyOfArrowFunction(body)
2584            );
2585            node.equalsGreaterThanToken = equalsGreaterThanToken ?? createToken(SyntaxKind.EqualsGreaterThanToken);
2586            node.transformFlags |=
2587                propagateChildFlags(node.equalsGreaterThanToken) |
2588                TransformFlags.ContainsES2015;
2589            if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) {
2590                node.transformFlags |= TransformFlags.ContainsES2017;
2591            }
2592            return node;
2593        }
2594
2595        // @api
2596        function updateArrowFunction(
2597            node: ArrowFunction,
2598            modifiers: readonly Modifier[] | undefined,
2599            typeParameters: readonly TypeParameterDeclaration[] | undefined,
2600            parameters: readonly ParameterDeclaration[],
2601            type: TypeNode | undefined,
2602            equalsGreaterThanToken: EqualsGreaterThanToken,
2603            body: ConciseBody
2604        ): ArrowFunction {
2605            return node.modifiers !== modifiers
2606                || node.typeParameters !== typeParameters
2607                || node.parameters !== parameters
2608                || node.type !== type
2609                || node.equalsGreaterThanToken !== equalsGreaterThanToken
2610                || node.body !== body
2611                ? updateBaseFunctionLikeDeclaration(createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), node)
2612                : node;
2613        }
2614
2615        // @api
2616        function createDeleteExpression(expression: Expression) {
2617            const node = createBaseExpression<DeleteExpression>(SyntaxKind.DeleteExpression);
2618            node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression);
2619            node.transformFlags |= propagateChildFlags(node.expression);
2620            return node;
2621        }
2622
2623        // @api
2624        function updateDeleteExpression(node: DeleteExpression, expression: Expression) {
2625            return node.expression !== expression
2626                ? update(createDeleteExpression(expression), node)
2627                : node;
2628        }
2629
2630        // @api
2631        function createTypeOfExpression(expression: Expression) {
2632            const node = createBaseExpression<TypeOfExpression>(SyntaxKind.TypeOfExpression);
2633            node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression);
2634            node.transformFlags |= propagateChildFlags(node.expression);
2635            return node;
2636        }
2637
2638        // @api
2639        function updateTypeOfExpression(node: TypeOfExpression, expression: Expression) {
2640            return node.expression !== expression
2641                ? update(createTypeOfExpression(expression), node)
2642                : node;
2643        }
2644
2645        // @api
2646        function createVoidExpression(expression: Expression) {
2647            const node = createBaseExpression<VoidExpression>(SyntaxKind.VoidExpression);
2648            node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression);
2649            node.transformFlags |= propagateChildFlags(node.expression);
2650            return node;
2651        }
2652
2653        // @api
2654        function updateVoidExpression(node: VoidExpression, expression: Expression) {
2655            return node.expression !== expression
2656                ? update(createVoidExpression(expression), node)
2657                : node;
2658        }
2659
2660        // @api
2661        function createAwaitExpression(expression: Expression) {
2662            const node = createBaseExpression<AwaitExpression>(SyntaxKind.AwaitExpression);
2663            node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression);
2664            node.transformFlags |=
2665                propagateChildFlags(node.expression) |
2666                TransformFlags.ContainsES2017 |
2667                TransformFlags.ContainsES2018 |
2668                TransformFlags.ContainsAwait;
2669            return node;
2670        }
2671
2672        // @api
2673        function updateAwaitExpression(node: AwaitExpression, expression: Expression) {
2674            return node.expression !== expression
2675                ? update(createAwaitExpression(expression), node)
2676                : node;
2677        }
2678
2679        // @api
2680        function createPrefixUnaryExpression(operator: PrefixUnaryOperator, operand: Expression) {
2681            const node = createBaseExpression<PrefixUnaryExpression>(SyntaxKind.PrefixUnaryExpression);
2682            node.operator = operator;
2683            node.operand = parenthesizerRules().parenthesizeOperandOfPrefixUnary(operand);
2684            node.transformFlags |= propagateChildFlags(node.operand);
2685            return node;
2686        }
2687
2688        // @api
2689        function updatePrefixUnaryExpression(node: PrefixUnaryExpression, operand: Expression) {
2690            return node.operand !== operand
2691                ? update(createPrefixUnaryExpression(node.operator, operand), node)
2692                : node;
2693        }
2694
2695        // @api
2696        function createPostfixUnaryExpression(operand: Expression, operator: PostfixUnaryOperator) {
2697            const node = createBaseExpression<PostfixUnaryExpression>(SyntaxKind.PostfixUnaryExpression);
2698            node.operator = operator;
2699            node.operand = parenthesizerRules().parenthesizeOperandOfPostfixUnary(operand);
2700            node.transformFlags = propagateChildFlags(node.operand);
2701            return node;
2702        }
2703
2704        // @api
2705        function updatePostfixUnaryExpression(node: PostfixUnaryExpression, operand: Expression) {
2706            return node.operand !== operand
2707                ? update(createPostfixUnaryExpression(operand, node.operator), node)
2708                : node;
2709        }
2710
2711        // @api
2712        function createBinaryExpression(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression) {
2713            const node = createBaseExpression<BinaryExpression>(SyntaxKind.BinaryExpression);
2714            const operatorToken = asToken(operator);
2715            const operatorKind = operatorToken.kind;
2716            node.left = parenthesizerRules().parenthesizeLeftSideOfBinary(operatorKind, left);
2717            node.operatorToken = operatorToken;
2718            node.right = parenthesizerRules().parenthesizeRightSideOfBinary(operatorKind, node.left, right);
2719            node.transformFlags |=
2720                propagateChildFlags(node.left) |
2721                propagateChildFlags(node.operatorToken) |
2722                propagateChildFlags(node.right);
2723            if (operatorKind === SyntaxKind.QuestionQuestionToken) {
2724                node.transformFlags |= TransformFlags.ContainsES2020;
2725            }
2726            else if (operatorKind === SyntaxKind.EqualsToken) {
2727                if (isObjectLiteralExpression(node.left)) {
2728                    node.transformFlags |=
2729                        TransformFlags.ContainsES2015 |
2730                        TransformFlags.ContainsES2018 |
2731                        TransformFlags.ContainsDestructuringAssignment |
2732                        propagateAssignmentPatternFlags(node.left);
2733                }
2734                else if (isArrayLiteralExpression(node.left)) {
2735                    node.transformFlags |=
2736                        TransformFlags.ContainsES2015 |
2737                        TransformFlags.ContainsDestructuringAssignment |
2738                        propagateAssignmentPatternFlags(node.left);
2739                }
2740            }
2741            else if (operatorKind === SyntaxKind.AsteriskAsteriskToken || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken) {
2742                node.transformFlags |= TransformFlags.ContainsES2016;
2743            }
2744            else if (isLogicalOrCoalescingAssignmentOperator(operatorKind)) {
2745                node.transformFlags |= TransformFlags.ContainsESNext;
2746            }
2747            return node;
2748        }
2749
2750        function propagateAssignmentPatternFlags(node: AssignmentPattern): TransformFlags {
2751            if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) return TransformFlags.ContainsObjectRestOrSpread;
2752            if (node.transformFlags & TransformFlags.ContainsES2018) {
2753                // check for nested spread assignments, otherwise '{ x: { a, ...b } = foo } = c'
2754                // will not be correctly interpreted by the ES2018 transformer
2755                for (const element of getElementsOfBindingOrAssignmentPattern(node)) {
2756                    const target = getTargetOfBindingOrAssignmentElement(element);
2757                    if (target && isAssignmentPattern(target)) {
2758                        if (target.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
2759                            return TransformFlags.ContainsObjectRestOrSpread;
2760                        }
2761                        if (target.transformFlags & TransformFlags.ContainsES2018) {
2762                            const flags = propagateAssignmentPatternFlags(target);
2763                            if (flags) return flags;
2764                        }
2765                    }
2766                }
2767            }
2768            return TransformFlags.None;
2769        }
2770
2771        // @api
2772        function updateBinaryExpression(node: BinaryExpression, left: Expression, operator: BinaryOperatorToken, right: Expression) {
2773            return node.left !== left
2774                || node.operatorToken !== operator
2775                || node.right !== right
2776                ? update(createBinaryExpression(left, operator, right), node)
2777                : node;
2778        }
2779
2780        // @api
2781        function createConditionalExpression(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression) {
2782            const node = createBaseExpression<ConditionalExpression>(SyntaxKind.ConditionalExpression);
2783            node.condition = parenthesizerRules().parenthesizeConditionOfConditionalExpression(condition);
2784            node.questionToken = questionToken ?? createToken(SyntaxKind.QuestionToken);
2785            node.whenTrue = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenTrue);
2786            node.colonToken = colonToken ?? createToken(SyntaxKind.ColonToken);
2787            node.whenFalse = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenFalse);
2788            node.transformFlags |=
2789                propagateChildFlags(node.condition) |
2790                propagateChildFlags(node.questionToken) |
2791                propagateChildFlags(node.whenTrue) |
2792                propagateChildFlags(node.colonToken) |
2793                propagateChildFlags(node.whenFalse);
2794            return node;
2795        }
2796
2797        // @api
2798        function updateConditionalExpression(
2799            node: ConditionalExpression,
2800            condition: Expression,
2801            questionToken: Token<SyntaxKind.QuestionToken>,
2802            whenTrue: Expression,
2803            colonToken: Token<SyntaxKind.ColonToken>,
2804            whenFalse: Expression
2805        ): ConditionalExpression {
2806            return node.condition !== condition
2807                || node.questionToken !== questionToken
2808                || node.whenTrue !== whenTrue
2809                || node.colonToken !== colonToken
2810                || node.whenFalse !== whenFalse
2811                ? update(createConditionalExpression(condition, questionToken, whenTrue, colonToken, whenFalse), node)
2812                : node;
2813        }
2814
2815        // @api
2816        function createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]) {
2817            const node = createBaseExpression<TemplateExpression>(SyntaxKind.TemplateExpression);
2818            node.head = head;
2819            node.templateSpans = createNodeArray(templateSpans);
2820            node.transformFlags |=
2821                propagateChildFlags(node.head) |
2822                propagateChildrenFlags(node.templateSpans) |
2823                TransformFlags.ContainsES2015;
2824            return node;
2825        }
2826
2827        // @api
2828        function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]) {
2829            return node.head !== head
2830                || node.templateSpans !== templateSpans
2831                ? update(createTemplateExpression(head, templateSpans), node)
2832                : node;
2833        }
2834
2835        function createTemplateLiteralLikeNodeChecked(kind: TemplateLiteralToken["kind"], text: string | undefined, rawText: string | undefined, templateFlags = TokenFlags.None) {
2836            Debug.assert(!(templateFlags & ~TokenFlags.TemplateLiteralLikeFlags), "Unsupported template flags.");
2837            // NOTE: without the assignment to `undefined`, we don't narrow the initial type of `cooked`.
2838            // eslint-disable-next-line no-undef-init
2839            let cooked: string | object | undefined = undefined;
2840            if (rawText !== undefined && rawText !== text) {
2841                cooked = getCookedText(kind, rawText);
2842                if (typeof cooked === "object") {
2843                    return Debug.fail("Invalid raw text");
2844                }
2845            }
2846            if (text === undefined) {
2847                if (cooked === undefined) {
2848                    return Debug.fail("Arguments 'text' and 'rawText' may not both be undefined.");
2849                }
2850                text = cooked;
2851            }
2852            else if (cooked !== undefined) {
2853                Debug.assert(text === cooked, "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.");
2854            }
2855            return createTemplateLiteralLikeNode(kind, text, rawText, templateFlags);
2856        }
2857
2858        // @api
2859        function createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string | undefined, templateFlags: TokenFlags | undefined) {
2860            const node = createBaseToken<TemplateLiteralLikeNode>(kind);
2861            node.text = text;
2862            node.rawText = rawText;
2863            node.templateFlags = templateFlags! & TokenFlags.TemplateLiteralLikeFlags;
2864            node.transformFlags |= TransformFlags.ContainsES2015;
2865            if (node.templateFlags) {
2866                node.transformFlags |= TransformFlags.ContainsES2018;
2867            }
2868            return node;
2869        }
2870
2871        // @api
2872        function createTemplateHead(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) {
2873            return <TemplateHead>createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateHead, text, rawText, templateFlags);
2874        }
2875
2876        // @api
2877        function createTemplateMiddle(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) {
2878            return <TemplateMiddle>createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateMiddle, text, rawText, templateFlags);
2879        }
2880
2881        // @api
2882        function createTemplateTail(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) {
2883            return <TemplateTail>createTemplateLiteralLikeNodeChecked(SyntaxKind.TemplateTail, text, rawText, templateFlags);
2884        }
2885
2886        // @api
2887        function createNoSubstitutionTemplateLiteral(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) {
2888            return <NoSubstitutionTemplateLiteral>createTemplateLiteralLikeNodeChecked(SyntaxKind.NoSubstitutionTemplateLiteral, text, rawText, templateFlags);
2889        }
2890
2891        // @api
2892        function createYieldExpression(asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression {
2893            Debug.assert(!asteriskToken || !!expression, "A `YieldExpression` with an asteriskToken must have an expression.");
2894            const node = createBaseExpression<YieldExpression>(SyntaxKind.YieldExpression);
2895            node.expression = expression && parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
2896            node.asteriskToken = asteriskToken;
2897            node.transformFlags |=
2898                propagateChildFlags(node.expression) |
2899                propagateChildFlags(node.asteriskToken) |
2900                TransformFlags.ContainsES2015 |
2901                TransformFlags.ContainsES2018 |
2902                TransformFlags.ContainsYield;
2903            return node;
2904        }
2905
2906        // @api
2907        function updateYieldExpression(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression) {
2908            return node.expression !== expression
2909                || node.asteriskToken !== asteriskToken
2910                ? update(createYieldExpression(asteriskToken, expression), node)
2911                : node;
2912        }
2913
2914        // @api
2915        function createSpreadElement(expression: Expression) {
2916            const node = createBaseExpression<SpreadElement>(SyntaxKind.SpreadElement);
2917            node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
2918            node.transformFlags |=
2919                propagateChildFlags(node.expression) |
2920                TransformFlags.ContainsES2015 |
2921                TransformFlags.ContainsRestOrSpread;
2922            return node;
2923        }
2924
2925        // @api
2926        function updateSpreadElement(node: SpreadElement, expression: Expression) {
2927            return node.expression !== expression
2928                ? update(createSpreadElement(expression), node)
2929                : node;
2930        }
2931
2932        // @api
2933        function createClassExpression(
2934            decorators: readonly Decorator[] | undefined,
2935            modifiers: readonly Modifier[] | undefined,
2936            name: string | Identifier | undefined,
2937            typeParameters: readonly TypeParameterDeclaration[] | undefined,
2938            heritageClauses: readonly HeritageClause[] | undefined,
2939            members: readonly ClassElement[]
2940        ) {
2941            const node = createBaseClassLikeDeclaration<ClassExpression>(
2942                SyntaxKind.ClassExpression,
2943                decorators,
2944                modifiers,
2945                name,
2946                typeParameters,
2947                heritageClauses,
2948                members
2949            );
2950            node.transformFlags |= TransformFlags.ContainsES2015;
2951            return node;
2952        }
2953
2954        // @api
2955        function updateClassExpression(
2956            node: ClassExpression,
2957            decorators: readonly Decorator[] | undefined,
2958            modifiers: readonly Modifier[] | undefined,
2959            name: Identifier | undefined,
2960            typeParameters: readonly TypeParameterDeclaration[] | undefined,
2961            heritageClauses: readonly HeritageClause[] | undefined,
2962            members: readonly ClassElement[]
2963        ) {
2964            return node.decorators !== decorators
2965                || node.modifiers !== modifiers
2966                || node.name !== name
2967                || node.typeParameters !== typeParameters
2968                || node.heritageClauses !== heritageClauses
2969                || node.members !== members
2970                ? update(createClassExpression(decorators, modifiers, name, typeParameters, heritageClauses, members), node)
2971                : node;
2972        }
2973
2974        // @api
2975        function createOmittedExpression() {
2976            return createBaseExpression<OmittedExpression>(SyntaxKind.OmittedExpression);
2977        }
2978
2979        // @api
2980        function createExpressionWithTypeArguments(expression: Expression, typeArguments: readonly TypeNode[] | undefined) {
2981            const node = createBaseNode<ExpressionWithTypeArguments>(SyntaxKind.ExpressionWithTypeArguments);
2982            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
2983            node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments);
2984            node.transformFlags |=
2985                propagateChildFlags(node.expression) |
2986                propagateChildrenFlags(node.typeArguments) |
2987                TransformFlags.ContainsES2015;
2988            return node;
2989        }
2990
2991        // @api
2992        function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, expression: Expression, typeArguments: readonly TypeNode[] | undefined) {
2993            return node.expression !== expression
2994                || node.typeArguments !== typeArguments
2995                ? update(createExpressionWithTypeArguments(expression, typeArguments), node)
2996                : node;
2997        }
2998
2999        // @api
3000        function createAsExpression(expression: Expression, type: TypeNode) {
3001            const node = createBaseExpression<AsExpression>(SyntaxKind.AsExpression);
3002            node.expression = expression;
3003            node.type = type;
3004            node.transformFlags |=
3005                propagateChildFlags(node.expression) |
3006                propagateChildFlags(node.type) |
3007                TransformFlags.ContainsTypeScript;
3008            return node;
3009        }
3010
3011        // @api
3012        function updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode) {
3013            return node.expression !== expression
3014                || node.type !== type
3015                ? update(createAsExpression(expression, type), node)
3016                : node;
3017        }
3018
3019        // @api
3020        function createNonNullExpression(expression: Expression) {
3021            const node = createBaseExpression<NonNullExpression>(SyntaxKind.NonNullExpression);
3022            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
3023            node.transformFlags |=
3024                propagateChildFlags(node.expression) |
3025                TransformFlags.ContainsTypeScript;
3026            return node;
3027        }
3028
3029        // @api
3030        function updateNonNullExpression(node: NonNullExpression, expression: Expression) {
3031            if (isNonNullChain(node)) {
3032                return updateNonNullChain(node, expression);
3033            }
3034            return node.expression !== expression
3035                ? update(createNonNullExpression(expression), node)
3036                : node;
3037        }
3038
3039        // @api
3040        function createNonNullChain(expression: Expression) {
3041            const node = createBaseExpression<NonNullChain>(SyntaxKind.NonNullExpression);
3042            node.flags |= NodeFlags.OptionalChain;
3043            node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
3044            node.transformFlags |=
3045                propagateChildFlags(node.expression) |
3046                TransformFlags.ContainsTypeScript;
3047            return node;
3048        }
3049
3050        // @api
3051        function updateNonNullChain(node: NonNullChain, expression: Expression) {
3052            Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead.");
3053            return node.expression !== expression
3054                ? update(createNonNullChain(expression), node)
3055                : node;
3056        }
3057
3058        // @api
3059        function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier) {
3060            const node = createBaseExpression<MetaProperty>(SyntaxKind.MetaProperty);
3061            node.keywordToken = keywordToken;
3062            node.name = name;
3063            node.transformFlags |= propagateChildFlags(node.name);
3064            switch (keywordToken) {
3065                case SyntaxKind.NewKeyword:
3066                    node.transformFlags |= TransformFlags.ContainsES2015;
3067                    break;
3068                case SyntaxKind.ImportKeyword:
3069                    node.transformFlags |= TransformFlags.ContainsESNext;
3070                    break;
3071                default:
3072                    return Debug.assertNever(keywordToken);
3073            }
3074            return node;
3075        }
3076
3077        // @api
3078        function updateMetaProperty(node: MetaProperty, name: Identifier) {
3079            return node.name !== name
3080                ? update(createMetaProperty(node.keywordToken, name), node)
3081                : node;
3082        }
3083
3084        //
3085        // Misc
3086        //
3087
3088        // @api
3089        function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail) {
3090            const node = createBaseNode<TemplateSpan>(SyntaxKind.TemplateSpan);
3091            node.expression = expression;
3092            node.literal = literal;
3093            node.transformFlags |=
3094                propagateChildFlags(node.expression) |
3095                propagateChildFlags(node.literal) |
3096                TransformFlags.ContainsES2015;
3097            return node;
3098        }
3099
3100        // @api
3101        function updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail) {
3102            return node.expression !== expression
3103                || node.literal !== literal
3104                ? update(createTemplateSpan(expression, literal), node)
3105                : node;
3106        }
3107
3108        // @api
3109        function createSemicolonClassElement() {
3110            const node = createBaseNode<SemicolonClassElement>(SyntaxKind.SemicolonClassElement);
3111            node.transformFlags |= TransformFlags.ContainsES2015;
3112            return node;
3113        }
3114
3115        //
3116        // Element
3117        //
3118
3119        // @api
3120        function createBlock(statements: readonly Statement[], multiLine?: boolean): Block {
3121            const node = createBaseNode<Block>(SyntaxKind.Block);
3122            node.statements = createNodeArray(statements);
3123            node.multiLine = multiLine;
3124            node.transformFlags |= propagateChildrenFlags(node.statements);
3125            return node;
3126        }
3127
3128        // @api
3129        function updateBlock(node: Block, statements: readonly Statement[]) {
3130            return node.statements !== statements
3131                ? update(createBlock(statements, node.multiLine), node)
3132                : node;
3133        }
3134
3135        // @api
3136        function createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]) {
3137            const node = createBaseDeclaration<VariableStatement>(SyntaxKind.VariableStatement, /*decorators*/ undefined, modifiers);
3138            node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList;
3139            node.transformFlags |=
3140                propagateChildFlags(node.declarationList);
3141            if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) {
3142                node.transformFlags = TransformFlags.ContainsTypeScript;
3143            }
3144            return node;
3145        }
3146
3147        // @api
3148        function updateVariableStatement(node: VariableStatement, modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList) {
3149            return node.modifiers !== modifiers
3150                || node.declarationList !== declarationList
3151                ? update(createVariableStatement(modifiers, declarationList), node)
3152                : node;
3153        }
3154
3155        // @api
3156        function createEmptyStatement() {
3157            return createBaseNode<EmptyStatement>(SyntaxKind.EmptyStatement);
3158        }
3159
3160        // @api
3161        function createExpressionStatement(expression: Expression): ExpressionStatement {
3162            const node = createBaseNode<ExpressionStatement>(SyntaxKind.ExpressionStatement);
3163            node.expression = parenthesizerRules().parenthesizeExpressionOfExpressionStatement(expression);
3164            node.transformFlags |= propagateChildFlags(node.expression);
3165            return node;
3166        }
3167
3168        // @api
3169        function updateExpressionStatement(node: ExpressionStatement, expression: Expression) {
3170            return node.expression !== expression
3171                ? update(createExpressionStatement(expression), node)
3172                : node;
3173        }
3174
3175        // @api
3176        function createIfStatement(expression: Expression, thenStatement: Statement, elseStatement?: Statement) {
3177            const node = createBaseNode<IfStatement>(SyntaxKind.IfStatement);
3178            node.expression = expression;
3179            node.thenStatement = asEmbeddedStatement(thenStatement);
3180            node.elseStatement = asEmbeddedStatement(elseStatement);
3181            node.transformFlags |=
3182                propagateChildFlags(node.expression) |
3183                propagateChildFlags(node.thenStatement) |
3184                propagateChildFlags(node.elseStatement);
3185            return node;
3186        }
3187
3188        // @api
3189        function updateIfStatement(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined) {
3190            return node.expression !== expression
3191                || node.thenStatement !== thenStatement
3192                || node.elseStatement !== elseStatement
3193                ? update(createIfStatement(expression, thenStatement, elseStatement), node)
3194                : node;
3195        }
3196
3197        // @api
3198        function createDoStatement(statement: Statement, expression: Expression) {
3199            const node = createBaseNode<DoStatement>(SyntaxKind.DoStatement);
3200            node.statement = asEmbeddedStatement(statement);
3201            node.expression = expression;
3202            node.transformFlags |=
3203                propagateChildFlags(node.statement) |
3204                propagateChildFlags(node.expression);
3205            return node;
3206        }
3207
3208        // @api
3209        function updateDoStatement(node: DoStatement, statement: Statement, expression: Expression) {
3210            return node.statement !== statement
3211                || node.expression !== expression
3212                ? update(createDoStatement(statement, expression), node)
3213                : node;
3214        }
3215
3216        // @api
3217        function createWhileStatement(expression: Expression, statement: Statement) {
3218            const node = createBaseNode<WhileStatement>(SyntaxKind.WhileStatement);
3219            node.expression = expression;
3220            node.statement = asEmbeddedStatement(statement);
3221            node.transformFlags |=
3222                propagateChildFlags(node.expression) |
3223                propagateChildFlags(node.statement);
3224            return node;
3225        }
3226
3227        // @api
3228        function updateWhileStatement(node: WhileStatement, expression: Expression, statement: Statement) {
3229            return node.expression !== expression
3230                || node.statement !== statement
3231                ? update(createWhileStatement(expression, statement), node)
3232                : node;
3233        }
3234
3235        // @api
3236        function createForStatement(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) {
3237            const node = createBaseNode<ForStatement>(SyntaxKind.ForStatement);
3238            node.initializer = initializer;
3239            node.condition = condition;
3240            node.incrementor = incrementor;
3241            node.statement = asEmbeddedStatement(statement);
3242            node.transformFlags |=
3243                propagateChildFlags(node.initializer) |
3244                propagateChildFlags(node.condition) |
3245                propagateChildFlags(node.incrementor) |
3246                propagateChildFlags(node.statement);
3247            return node;
3248        }
3249
3250        // @api
3251        function updateForStatement(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) {
3252            return node.initializer !== initializer
3253                || node.condition !== condition
3254                || node.incrementor !== incrementor
3255                || node.statement !== statement
3256                ? update(createForStatement(initializer, condition, incrementor, statement), node)
3257                : node;
3258        }
3259
3260        // @api
3261        function createForInStatement(initializer: ForInitializer, expression: Expression, statement: Statement) {
3262            const node = createBaseNode<ForInStatement>(SyntaxKind.ForInStatement);
3263            node.initializer = initializer;
3264            node.expression = expression;
3265            node.statement = asEmbeddedStatement(statement);
3266            node.transformFlags |=
3267                propagateChildFlags(node.initializer) |
3268                propagateChildFlags(node.expression) |
3269                propagateChildFlags(node.statement);
3270            return node;
3271        }
3272
3273        // @api
3274        function updateForInStatement(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement) {
3275            return node.initializer !== initializer
3276                || node.expression !== expression
3277                || node.statement !== statement
3278                ? update(createForInStatement(initializer, expression, statement), node)
3279                : node;
3280        }
3281
3282        // @api
3283        function createForOfStatement(awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) {
3284            const node = createBaseNode<ForOfStatement>(SyntaxKind.ForOfStatement);
3285            node.awaitModifier = awaitModifier;
3286            node.initializer = initializer;
3287            node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
3288            node.statement = asEmbeddedStatement(statement);
3289            node.transformFlags |=
3290                propagateChildFlags(node.awaitModifier) |
3291                propagateChildFlags(node.initializer) |
3292                propagateChildFlags(node.expression) |
3293                propagateChildFlags(node.statement) |
3294                TransformFlags.ContainsES2015;
3295            if (awaitModifier) node.transformFlags |= TransformFlags.ContainsES2018;
3296            return node;
3297        }
3298
3299        // @api
3300        function updateForOfStatement(node: ForOfStatement, awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) {
3301            return node.awaitModifier !== awaitModifier
3302                || node.initializer !== initializer
3303                || node.expression !== expression
3304                || node.statement !== statement
3305                ? update(createForOfStatement(awaitModifier, initializer, expression, statement), node)
3306                : node;
3307        }
3308
3309        // @api
3310        function createContinueStatement(label?: string | Identifier): ContinueStatement {
3311            const node = createBaseNode<ContinueStatement>(SyntaxKind.ContinueStatement);
3312            node.label = asName(label);
3313            node.transformFlags |=
3314                propagateChildFlags(node.label) |
3315                TransformFlags.ContainsHoistedDeclarationOrCompletion;
3316            return node;
3317        }
3318
3319        // @api
3320        function updateContinueStatement(node: ContinueStatement, label: Identifier | undefined) {
3321            return node.label !== label
3322                ? update(createContinueStatement(label), node)
3323                : node;
3324        }
3325
3326        // @api
3327        function createBreakStatement(label?: string | Identifier): BreakStatement {
3328            const node = createBaseNode<BreakStatement>(SyntaxKind.BreakStatement);
3329            node.label = asName(label);
3330            node.transformFlags |=
3331                propagateChildFlags(node.label) |
3332                TransformFlags.ContainsHoistedDeclarationOrCompletion;
3333            return node;
3334        }
3335
3336        // @api
3337        function updateBreakStatement(node: BreakStatement, label: Identifier | undefined) {
3338            return node.label !== label
3339                ? update(createBreakStatement(label), node)
3340                : node;
3341        }
3342
3343        // @api
3344        function createReturnStatement(expression?: Expression): ReturnStatement {
3345            const node = createBaseNode<ReturnStatement>(SyntaxKind.ReturnStatement);
3346            node.expression = expression;
3347            // return in an ES2018 async generator must be awaited
3348            node.transformFlags |=
3349                propagateChildFlags(node.expression) |
3350                TransformFlags.ContainsES2018 |
3351                TransformFlags.ContainsHoistedDeclarationOrCompletion;
3352            return node;
3353        }
3354
3355        // @api
3356        function updateReturnStatement(node: ReturnStatement, expression: Expression | undefined) {
3357            return node.expression !== expression
3358                ? update(createReturnStatement(expression), node)
3359                : node;
3360        }
3361
3362        // @api
3363        function createWithStatement(expression: Expression, statement: Statement) {
3364            const node = createBaseNode<WithStatement>(SyntaxKind.WithStatement);
3365            node.expression = expression;
3366            node.statement = asEmbeddedStatement(statement);
3367            node.transformFlags |=
3368                propagateChildFlags(node.expression) |
3369                propagateChildFlags(node.statement);
3370            return node;
3371        }
3372
3373        // @api
3374        function updateWithStatement(node: WithStatement, expression: Expression, statement: Statement) {
3375            return node.expression !== expression
3376                || node.statement !== statement
3377                ? update(createWithStatement(expression, statement), node)
3378                : node;
3379        }
3380
3381        // @api
3382        function createSwitchStatement(expression: Expression, caseBlock: CaseBlock): SwitchStatement {
3383            const node = createBaseNode<SwitchStatement>(SyntaxKind.SwitchStatement);
3384            node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
3385            node.caseBlock = caseBlock;
3386            node.transformFlags |=
3387                propagateChildFlags(node.expression) |
3388                propagateChildFlags(node.caseBlock);
3389            return node;
3390        }
3391
3392        // @api
3393        function updateSwitchStatement(node: SwitchStatement, expression: Expression, caseBlock: CaseBlock) {
3394            return node.expression !== expression
3395                || node.caseBlock !== caseBlock
3396                ? update(createSwitchStatement(expression, caseBlock), node)
3397                : node;
3398        }
3399
3400        // @api
3401        function createLabeledStatement(label: string | Identifier, statement: Statement) {
3402            const node = createBaseNode<LabeledStatement>(SyntaxKind.LabeledStatement);
3403            node.label = asName(label);
3404            node.statement = asEmbeddedStatement(statement);
3405            node.transformFlags |=
3406                propagateChildFlags(node.label) |
3407                propagateChildFlags(node.statement);
3408            return node;
3409        }
3410
3411        // @api
3412        function updateLabeledStatement(node: LabeledStatement, label: Identifier, statement: Statement) {
3413            return node.label !== label
3414                || node.statement !== statement
3415                ? update(createLabeledStatement(label, statement), node)
3416                : node;
3417        }
3418
3419        // @api
3420        function createThrowStatement(expression: Expression) {
3421            const node = createBaseNode<ThrowStatement>(SyntaxKind.ThrowStatement);
3422            node.expression = expression;
3423            node.transformFlags |= propagateChildFlags(node.expression);
3424            return node;
3425        }
3426
3427        // @api
3428        function updateThrowStatement(node: ThrowStatement, expression: Expression) {
3429            return node.expression !== expression
3430                ? update(createThrowStatement(expression), node)
3431                : node;
3432        }
3433
3434        // @api
3435        function createTryStatement(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) {
3436            const node = createBaseNode<TryStatement>(SyntaxKind.TryStatement);
3437            node.tryBlock = tryBlock;
3438            node.catchClause = catchClause;
3439            node.finallyBlock = finallyBlock;
3440            node.transformFlags |=
3441                propagateChildFlags(node.tryBlock) |
3442                propagateChildFlags(node.catchClause) |
3443                propagateChildFlags(node.finallyBlock);
3444            return node;
3445        }
3446
3447        // @api
3448        function updateTryStatement(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) {
3449            return node.tryBlock !== tryBlock
3450                || node.catchClause !== catchClause
3451                || node.finallyBlock !== finallyBlock
3452                ? update(createTryStatement(tryBlock, catchClause, finallyBlock), node)
3453                : node;
3454        }
3455
3456        // @api
3457        function createDebuggerStatement() {
3458            return createBaseNode<DebuggerStatement>(SyntaxKind.DebuggerStatement);
3459        }
3460
3461        // @api
3462        function createVariableDeclaration(name: string | BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
3463            const node = createBaseVariableLikeDeclaration<VariableDeclaration>(
3464                SyntaxKind.VariableDeclaration,
3465                /*decorators*/ undefined,
3466                /*modifiers*/ undefined,
3467                name,
3468                type,
3469                initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer)
3470            );
3471            node.exclamationToken = exclamationToken;
3472            node.transformFlags |= propagateChildFlags(node.exclamationToken);
3473            if (exclamationToken) {
3474                node.transformFlags |= TransformFlags.ContainsTypeScript;
3475            }
3476            return node;
3477        }
3478
3479        // @api
3480        function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
3481            return node.name !== name
3482                || node.type !== type
3483                || node.exclamationToken !== exclamationToken
3484                || node.initializer !== initializer
3485                ? update(createVariableDeclaration(name, exclamationToken, type, initializer), node)
3486                : node;
3487        }
3488
3489        // @api
3490        function createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags = NodeFlags.None) {
3491            const node = createBaseNode<VariableDeclarationList>(SyntaxKind.VariableDeclarationList);
3492            node.flags |= flags & NodeFlags.BlockScoped;
3493            node.declarations = createNodeArray(declarations);
3494            node.transformFlags |=
3495                propagateChildrenFlags(node.declarations) |
3496                TransformFlags.ContainsHoistedDeclarationOrCompletion;
3497            if (flags & NodeFlags.BlockScoped) {
3498                node.transformFlags |=
3499                    TransformFlags.ContainsES2015 |
3500                    TransformFlags.ContainsBlockScopedBinding;
3501            }
3502            return node;
3503        }
3504
3505        // @api
3506        function updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]) {
3507            return node.declarations !== declarations
3508                ? update(createVariableDeclarationList(declarations, node.flags), node)
3509                : node;
3510        }
3511
3512        // @api
3513        function createFunctionDeclaration(
3514            decorators: readonly Decorator[] | undefined,
3515            modifiers: readonly Modifier[] | undefined,
3516            asteriskToken: AsteriskToken | undefined,
3517            name: string | Identifier | undefined,
3518            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3519            parameters: readonly ParameterDeclaration[],
3520            type: TypeNode | undefined,
3521            body: Block | undefined
3522        ) {
3523            const node = createBaseFunctionLikeDeclaration<FunctionDeclaration>(
3524                SyntaxKind.FunctionDeclaration,
3525                decorators,
3526                modifiers,
3527                name,
3528                typeParameters,
3529                parameters,
3530                type,
3531                body
3532            );
3533            node.asteriskToken = asteriskToken;
3534            if (!node.body || modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) {
3535                node.transformFlags = TransformFlags.ContainsTypeScript;
3536            }
3537            else {
3538                node.transformFlags |=
3539                    propagateChildFlags(node.asteriskToken) |
3540                    TransformFlags.ContainsHoistedDeclarationOrCompletion;
3541                if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) {
3542                    if (node.asteriskToken) {
3543                        node.transformFlags |= TransformFlags.ContainsES2018;
3544                    }
3545                    else {
3546                        node.transformFlags |= TransformFlags.ContainsES2017;
3547                    }
3548                }
3549                else if (node.asteriskToken) {
3550                    node.transformFlags |= TransformFlags.ContainsGenerator;
3551                }
3552            }
3553            return node;
3554        }
3555
3556        // @api
3557        function updateFunctionDeclaration(
3558            node: FunctionDeclaration,
3559            decorators: readonly Decorator[] | undefined,
3560            modifiers: readonly Modifier[] | undefined,
3561            asteriskToken: AsteriskToken | undefined,
3562            name: Identifier | undefined,
3563            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3564            parameters: readonly ParameterDeclaration[],
3565            type: TypeNode | undefined,
3566            body: Block | undefined
3567        ) {
3568            return node.decorators !== decorators
3569                || node.modifiers !== modifiers
3570                || node.asteriskToken !== asteriskToken
3571                || node.name !== name
3572                || node.typeParameters !== typeParameters
3573                || node.parameters !== parameters
3574                || node.type !== type
3575                || node.body !== body
3576                ? updateBaseFunctionLikeDeclaration(createFunctionDeclaration(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body), node)
3577                : node;
3578        }
3579
3580        // @api
3581        function createClassDeclaration(
3582            decorators: readonly Decorator[] | undefined,
3583            modifiers: readonly Modifier[] | undefined,
3584            name: string | Identifier | undefined,
3585            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3586            heritageClauses: readonly HeritageClause[] | undefined,
3587            members: readonly ClassElement[]
3588        ) {
3589            const node = createBaseClassLikeDeclaration<ClassDeclaration>(
3590                SyntaxKind.ClassDeclaration,
3591                decorators,
3592                modifiers,
3593                name,
3594                typeParameters,
3595                heritageClauses,
3596                members
3597            );
3598            if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) {
3599                node.transformFlags = TransformFlags.ContainsTypeScript;
3600            }
3601            else {
3602                node.transformFlags |= TransformFlags.ContainsES2015;
3603                if (node.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax) {
3604                    node.transformFlags |= TransformFlags.ContainsTypeScript;
3605                }
3606            }
3607            return node;
3608        }
3609
3610        // @api
3611        function updateClassDeclaration(
3612            node: ClassDeclaration,
3613            decorators: readonly Decorator[] | undefined,
3614            modifiers: readonly Modifier[] | undefined,
3615            name: Identifier | undefined,
3616            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3617            heritageClauses: readonly HeritageClause[] | undefined,
3618            members: readonly ClassElement[]
3619        ) {
3620            return node.decorators !== decorators
3621                || node.modifiers !== modifiers
3622                || node.name !== name
3623                || node.typeParameters !== typeParameters
3624                || node.heritageClauses !== heritageClauses
3625                || node.members !== members
3626                ? update(createClassDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node)
3627                : node;
3628        }
3629
3630        // @api
3631        function createStructDeclaration(
3632            decorators: readonly Decorator[] | undefined,
3633            modifiers: readonly Modifier[] | undefined,
3634            name: string | Identifier | undefined,
3635            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3636            heritageClauses: readonly HeritageClause[] | undefined,
3637            members: readonly ClassElement[]
3638        ) {
3639            const node = createBaseClassLikeDeclaration<StructDeclaration>(
3640                SyntaxKind.StructDeclaration,
3641                decorators,
3642                modifiers,
3643                name,
3644                typeParameters,
3645                heritageClauses,
3646                members
3647            );
3648            if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) {
3649                node.transformFlags = TransformFlags.ContainsTypeScript;
3650            }
3651            else {
3652                node.transformFlags |= TransformFlags.ContainsES2015;
3653                if (node.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax) {
3654                    node.transformFlags |= TransformFlags.ContainsTypeScript;
3655                }
3656            }
3657            return node;
3658        }
3659
3660        // @api
3661        function updateStructDeclaration(
3662            node: StructDeclaration,
3663            decorators: readonly Decorator[] | undefined,
3664            modifiers: readonly Modifier[] | undefined,
3665            name: Identifier | undefined,
3666            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3667            heritageClauses: readonly HeritageClause[] | undefined,
3668            members: readonly ClassElement[]
3669        ) {
3670            return node.decorators !== decorators
3671                || node.modifiers !== modifiers
3672                || node.name !== name
3673                || node.typeParameters !== typeParameters
3674                || node.heritageClauses !== heritageClauses
3675                || node.members !== members
3676                ? update(createStructDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node)
3677                : node;
3678        }
3679
3680        // @api
3681        function createInterfaceDeclaration(
3682            decorators: readonly Decorator[] | undefined,
3683            modifiers: readonly Modifier[] | undefined,
3684            name: string | Identifier,
3685            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3686            heritageClauses: readonly HeritageClause[] | undefined,
3687            members: readonly TypeElement[]
3688        ) {
3689            const node = createBaseInterfaceOrClassLikeDeclaration<InterfaceDeclaration>(
3690                SyntaxKind.InterfaceDeclaration,
3691                decorators,
3692                modifiers,
3693                name,
3694                typeParameters,
3695                heritageClauses
3696            );
3697            node.members = createNodeArray(members);
3698            node.transformFlags = TransformFlags.ContainsTypeScript;
3699            return node;
3700        }
3701
3702        // @api
3703        function updateInterfaceDeclaration(
3704            node: InterfaceDeclaration,
3705            decorators: readonly Decorator[] | undefined,
3706            modifiers: readonly Modifier[] | undefined,
3707            name: Identifier,
3708            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3709            heritageClauses: readonly HeritageClause[] | undefined,
3710            members: readonly TypeElement[]
3711        ) {
3712            return node.decorators !== decorators
3713                || node.modifiers !== modifiers
3714                || node.name !== name
3715                || node.typeParameters !== typeParameters
3716                || node.heritageClauses !== heritageClauses
3717                || node.members !== members
3718                ? update(createInterfaceDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node)
3719                : node;
3720        }
3721
3722        // @api
3723        function createTypeAliasDeclaration(
3724            decorators: readonly Decorator[] | undefined,
3725            modifiers: readonly Modifier[] | undefined,
3726            name: string | Identifier,
3727            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3728            type: TypeNode
3729        ) {
3730            const node = createBaseGenericNamedDeclaration<TypeAliasDeclaration>(
3731                SyntaxKind.TypeAliasDeclaration,
3732                decorators,
3733                modifiers,
3734                name,
3735                typeParameters
3736            );
3737            node.type = type;
3738            node.transformFlags = TransformFlags.ContainsTypeScript;
3739            return node;
3740        }
3741
3742        // @api
3743        function updateTypeAliasDeclaration(
3744            node: TypeAliasDeclaration,
3745            decorators: readonly Decorator[] | undefined,
3746            modifiers: readonly Modifier[] | undefined,
3747            name: Identifier,
3748            typeParameters: readonly TypeParameterDeclaration[] | undefined,
3749            type: TypeNode
3750        ) {
3751            return node.decorators !== decorators
3752                || node.modifiers !== modifiers
3753                || node.name !== name
3754                || node.typeParameters !== typeParameters
3755                || node.type !== type
3756                ? update(createTypeAliasDeclaration(decorators, modifiers, name, typeParameters, type), node)
3757                : node;
3758        }
3759
3760        // @api
3761        function createEnumDeclaration(
3762            decorators: readonly Decorator[] | undefined,
3763            modifiers: readonly Modifier[] | undefined,
3764            name: string | Identifier,
3765            members: readonly EnumMember[]
3766        ) {
3767            const node = createBaseNamedDeclaration<EnumDeclaration>(
3768                SyntaxKind.EnumDeclaration,
3769                decorators,
3770                modifiers,
3771                name
3772            );
3773            node.members = createNodeArray(members);
3774            node.transformFlags |=
3775                propagateChildrenFlags(node.members) |
3776                TransformFlags.ContainsTypeScript;
3777            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Enum declarations cannot contain `await`
3778            return node;
3779        }
3780
3781        // @api
3782        function updateEnumDeclaration(
3783            node: EnumDeclaration,
3784            decorators: readonly Decorator[] | undefined,
3785            modifiers: readonly Modifier[] | undefined,
3786            name: Identifier,
3787            members: readonly EnumMember[]) {
3788            return node.decorators !== decorators
3789                || node.modifiers !== modifiers
3790                || node.name !== name
3791                || node.members !== members
3792                ? update(createEnumDeclaration(decorators, modifiers, name, members), node)
3793                : node;
3794        }
3795
3796        // @api
3797        function createModuleDeclaration(
3798            decorators: readonly Decorator[] | undefined,
3799            modifiers: readonly Modifier[] | undefined,
3800            name: ModuleName,
3801            body: ModuleBody | undefined,
3802            flags = NodeFlags.None
3803        ) {
3804            const node = createBaseDeclaration<ModuleDeclaration>(
3805                SyntaxKind.ModuleDeclaration,
3806                decorators,
3807                modifiers
3808            );
3809            node.flags |= flags & (NodeFlags.Namespace | NodeFlags.NestedNamespace | NodeFlags.GlobalAugmentation);
3810            node.name = name;
3811            node.body = body;
3812            if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) {
3813                node.transformFlags = TransformFlags.ContainsTypeScript;
3814            }
3815            else {
3816                node.transformFlags |=
3817                    propagateChildFlags(node.name) |
3818                    propagateChildFlags(node.body) |
3819                    TransformFlags.ContainsTypeScript;
3820            }
3821            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Module declarations cannot contain `await`.
3822            return node;
3823        }
3824
3825        // @api
3826        function updateModuleDeclaration(
3827            node: ModuleDeclaration,
3828            decorators: readonly Decorator[] | undefined,
3829            modifiers: readonly Modifier[] | undefined,
3830            name: ModuleName,
3831            body: ModuleBody | undefined
3832        ) {
3833            return node.decorators !== decorators
3834                || node.modifiers !== modifiers
3835                || node.name !== name
3836                || node.body !== body
3837                ? update(createModuleDeclaration(decorators, modifiers, name, body, node.flags), node)
3838                : node;
3839        }
3840
3841        // @api
3842        function createModuleBlock(statements: readonly Statement[]) {
3843            const node = createBaseNode<ModuleBlock>(SyntaxKind.ModuleBlock);
3844            node.statements = createNodeArray(statements);
3845            node.transformFlags |= propagateChildrenFlags(node.statements);
3846            return node;
3847        }
3848
3849        // @api
3850        function updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]) {
3851            return node.statements !== statements
3852                ? update(createModuleBlock(statements), node)
3853                : node;
3854        }
3855
3856        // @api
3857        function createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock {
3858            const node = createBaseNode<CaseBlock>(SyntaxKind.CaseBlock);
3859            node.clauses = createNodeArray(clauses);
3860            node.transformFlags |= propagateChildrenFlags(node.clauses);
3861            return node;
3862        }
3863
3864        // @api
3865        function updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]) {
3866            return node.clauses !== clauses
3867                ? update(createCaseBlock(clauses), node)
3868                : node;
3869        }
3870
3871        // @api
3872        function createNamespaceExportDeclaration(name: string | Identifier) {
3873            const node = createBaseNamedDeclaration<NamespaceExportDeclaration>(
3874                SyntaxKind.NamespaceExportDeclaration,
3875                /*decorators*/ undefined,
3876                /*modifiers*/ undefined,
3877                name
3878            );
3879            node.transformFlags = TransformFlags.ContainsTypeScript;
3880            return node;
3881        }
3882
3883        // @api
3884        function updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier) {
3885            return node.name !== name
3886                ? update(createNamespaceExportDeclaration(name), node)
3887                : node;
3888        }
3889
3890        // @api
3891        function createImportEqualsDeclaration(
3892            decorators: readonly Decorator[] | undefined,
3893            modifiers: readonly Modifier[] | undefined,
3894            isTypeOnly: boolean,
3895            name: string | Identifier,
3896            moduleReference: ModuleReference
3897        ) {
3898            const node = createBaseNamedDeclaration<ImportEqualsDeclaration>(
3899                SyntaxKind.ImportEqualsDeclaration,
3900                decorators,
3901                modifiers,
3902                name
3903            );
3904            node.isTypeOnly = isTypeOnly;
3905            node.moduleReference = moduleReference;
3906            node.transformFlags |= propagateChildFlags(node.moduleReference);
3907            if (!isExternalModuleReference(node.moduleReference)) node.transformFlags |= TransformFlags.ContainsTypeScript;
3908            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Import= declaration is always parsed in an Await context
3909            return node;
3910        }
3911
3912        // @api
3913        function updateImportEqualsDeclaration(
3914            node: ImportEqualsDeclaration,
3915            decorators: readonly Decorator[] | undefined,
3916            modifiers: readonly Modifier[] | undefined,
3917            isTypeOnly: boolean,
3918            name: Identifier,
3919            moduleReference: ModuleReference
3920        ) {
3921            return node.decorators !== decorators
3922                || node.modifiers !== modifiers
3923                || node.isTypeOnly !== isTypeOnly
3924                || node.name !== name
3925                || node.moduleReference !== moduleReference
3926                ? update(createImportEqualsDeclaration(decorators, modifiers, isTypeOnly, name, moduleReference), node)
3927                : node;
3928        }
3929
3930        // @api
3931        function createImportDeclaration(
3932            decorators: readonly Decorator[] | undefined,
3933            modifiers: readonly Modifier[] | undefined,
3934            importClause: ImportClause | undefined,
3935            moduleSpecifier: Expression
3936        ): ImportDeclaration {
3937            const node = createBaseDeclaration<ImportDeclaration>(
3938                SyntaxKind.ImportDeclaration,
3939                decorators,
3940                modifiers
3941            );
3942            node.importClause = importClause;
3943            node.moduleSpecifier = moduleSpecifier;
3944            node.transformFlags |=
3945                propagateChildFlags(node.importClause) |
3946                propagateChildFlags(node.moduleSpecifier);
3947            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
3948            return node;
3949        }
3950
3951        // @api
3952        function updateImportDeclaration(
3953            node: ImportDeclaration,
3954            decorators: readonly Decorator[] | undefined,
3955            modifiers: readonly Modifier[] | undefined,
3956            importClause: ImportClause | undefined,
3957            moduleSpecifier: Expression
3958        ) {
3959            return node.decorators !== decorators
3960                || node.modifiers !== modifiers
3961                || node.importClause !== importClause
3962                || node.moduleSpecifier !== moduleSpecifier
3963                ? update(createImportDeclaration(decorators, modifiers, importClause, moduleSpecifier), node)
3964                : node;
3965        }
3966
3967        // @api
3968        function createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause {
3969            const node = createBaseNode<ImportClause>(SyntaxKind.ImportClause);
3970            node.isTypeOnly = isTypeOnly;
3971            node.name = name;
3972            node.namedBindings = namedBindings;
3973            node.transformFlags |=
3974                propagateChildFlags(node.name) |
3975                propagateChildFlags(node.namedBindings);
3976            if (isTypeOnly) {
3977                node.transformFlags |= TransformFlags.ContainsTypeScript;
3978            }
3979            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
3980            return node;
3981        }
3982
3983        // @api
3984        function updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined) {
3985            return node.isTypeOnly !== isTypeOnly
3986                || node.name !== name
3987                || node.namedBindings !== namedBindings
3988                ? update(createImportClause(isTypeOnly, name, namedBindings), node)
3989                : node;
3990        }
3991
3992        // @api
3993        function createNamespaceImport(name: Identifier): NamespaceImport {
3994            const node = createBaseNode<NamespaceImport>(SyntaxKind.NamespaceImport);
3995            node.name = name;
3996            node.transformFlags |= propagateChildFlags(node.name);
3997            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
3998            return node;
3999        }
4000
4001        // @api
4002        function updateNamespaceImport(node: NamespaceImport, name: Identifier) {
4003            return node.name !== name
4004                ? update(createNamespaceImport(name), node)
4005                : node;
4006        }
4007
4008        // @api
4009        function createNamespaceExport(name: Identifier): NamespaceExport {
4010            const node = createBaseNode<NamespaceExport>(SyntaxKind.NamespaceExport);
4011            node.name = name;
4012            node.transformFlags |=
4013                propagateChildFlags(node.name) |
4014                TransformFlags.ContainsESNext;
4015            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4016            return node;
4017        }
4018
4019        // @api
4020        function updateNamespaceExport(node: NamespaceExport, name: Identifier) {
4021            return node.name !== name
4022                ? update(createNamespaceExport(name), node)
4023                : node;
4024        }
4025
4026        // @api
4027        function createNamedImports(elements: readonly ImportSpecifier[]): NamedImports {
4028            const node = createBaseNode<NamedImports>(SyntaxKind.NamedImports);
4029            node.elements = createNodeArray(elements);
4030            node.transformFlags |= propagateChildrenFlags(node.elements);
4031            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4032            return node;
4033        }
4034
4035        // @api
4036        function updateNamedImports(node: NamedImports, elements: readonly ImportSpecifier[]) {
4037            return node.elements !== elements
4038                ? update(createNamedImports(elements), node)
4039                : node;
4040        }
4041
4042        // @api
4043        function createImportSpecifier(propertyName: Identifier | undefined, name: Identifier) {
4044            const node = createBaseNode<ImportSpecifier>(SyntaxKind.ImportSpecifier);
4045            node.propertyName = propertyName;
4046            node.name = name;
4047            node.transformFlags |=
4048                propagateChildFlags(node.propertyName) |
4049                propagateChildFlags(node.name);
4050            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4051            return node;
4052        }
4053
4054        // @api
4055        function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
4056            return node.propertyName !== propertyName
4057                || node.name !== name
4058                ? update(createImportSpecifier(propertyName, name), node)
4059                : node;
4060        }
4061
4062        // @api
4063        function createExportAssignment(
4064            decorators: readonly Decorator[] | undefined,
4065            modifiers: readonly Modifier[] | undefined,
4066            isExportEquals: boolean | undefined,
4067            expression: Expression
4068        ) {
4069            const node = createBaseDeclaration<ExportAssignment>(
4070                SyntaxKind.ExportAssignment,
4071                decorators,
4072                modifiers
4073            );
4074            node.isExportEquals = isExportEquals;
4075            node.expression = isExportEquals
4076                ? parenthesizerRules().parenthesizeRightSideOfBinary(SyntaxKind.EqualsToken, /*leftSide*/ undefined, expression)
4077                : parenthesizerRules().parenthesizeExpressionOfExportDefault(expression);
4078            node.transformFlags |= propagateChildFlags(node.expression);
4079            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4080            return node;
4081        }
4082
4083        // @api
4084        function updateExportAssignment(
4085            node: ExportAssignment,
4086            decorators: readonly Decorator[] | undefined,
4087            modifiers: readonly Modifier[] | undefined,
4088            expression: Expression
4089        ) {
4090            return node.decorators !== decorators
4091                || node.modifiers !== modifiers
4092                || node.expression !== expression
4093                ? update(createExportAssignment(decorators, modifiers, node.isExportEquals, expression), node)
4094                : node;
4095        }
4096
4097        // @api
4098        function createExportDeclaration(
4099            decorators: readonly Decorator[] | undefined,
4100            modifiers: readonly Modifier[] | undefined,
4101            isTypeOnly: boolean,
4102            exportClause: NamedExportBindings | undefined,
4103            moduleSpecifier?: Expression
4104        ) {
4105            const node = createBaseDeclaration<ExportDeclaration>(
4106                SyntaxKind.ExportDeclaration,
4107                decorators,
4108                modifiers
4109            );
4110            node.isTypeOnly = isTypeOnly;
4111            node.exportClause = exportClause;
4112            node.moduleSpecifier = moduleSpecifier;
4113            node.transformFlags |=
4114                propagateChildFlags(node.exportClause) |
4115                propagateChildFlags(node.moduleSpecifier);
4116            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4117            return node;
4118        }
4119
4120        // @api
4121        function updateExportDeclaration(
4122            node: ExportDeclaration,
4123            decorators: readonly Decorator[] | undefined,
4124            modifiers: readonly Modifier[] | undefined,
4125            isTypeOnly: boolean,
4126            exportClause: NamedExportBindings | undefined,
4127            moduleSpecifier: Expression | undefined
4128        ) {
4129            return node.decorators !== decorators
4130                || node.modifiers !== modifiers
4131                || node.isTypeOnly !== isTypeOnly
4132                || node.exportClause !== exportClause
4133                || node.moduleSpecifier !== moduleSpecifier
4134                ? update(createExportDeclaration(decorators, modifiers, isTypeOnly, exportClause, moduleSpecifier), node)
4135                : node;
4136        }
4137
4138        // @api
4139        function createNamedExports(elements: readonly ExportSpecifier[]) {
4140            const node = createBaseNode<NamedExports>(SyntaxKind.NamedExports);
4141            node.elements = createNodeArray(elements);
4142            node.transformFlags |= propagateChildrenFlags(node.elements);
4143            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4144            return node;
4145        }
4146
4147        // @api
4148        function updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]) {
4149            return node.elements !== elements
4150                ? update(createNamedExports(elements), node)
4151                : node;
4152        }
4153
4154        // @api
4155        function createExportSpecifier(propertyName: string | Identifier | undefined, name: string | Identifier) {
4156            const node = createBaseNode<ExportSpecifier>(SyntaxKind.ExportSpecifier);
4157            node.propertyName = asName(propertyName);
4158            node.name = asName(name);
4159            node.transformFlags |=
4160                propagateChildFlags(node.propertyName) |
4161                propagateChildFlags(node.name);
4162            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4163            return node;
4164        }
4165
4166        // @api
4167        function updateExportSpecifier(node: ExportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
4168            return node.propertyName !== propertyName
4169                || node.name !== name
4170                ? update(createExportSpecifier(propertyName, name), node)
4171                : node;
4172        }
4173
4174        // @api
4175        function createMissingDeclaration() {
4176            const node = createBaseDeclaration<MissingDeclaration>(
4177                SyntaxKind.MissingDeclaration,
4178                /*decorators*/ undefined,
4179                /*modifiers*/ undefined
4180            );
4181            return node;
4182        }
4183
4184        //
4185        // Module references
4186        //
4187
4188        // @api
4189        function createExternalModuleReference(expression: Expression) {
4190            const node = createBaseNode<ExternalModuleReference>(SyntaxKind.ExternalModuleReference);
4191            node.expression = expression;
4192            node.transformFlags |= propagateChildFlags(node.expression);
4193            node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
4194            return node;
4195        }
4196
4197        // @api
4198        function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression) {
4199            return node.expression !== expression
4200                ? update(createExternalModuleReference(expression), node)
4201                : node;
4202        }
4203
4204        //
4205        // JSDoc
4206        //
4207
4208        // @api
4209        // createJSDocAllType
4210        // createJSDocUnknownType
4211        function createJSDocPrimaryTypeWorker<T extends JSDocType>(kind: T["kind"]) {
4212            return createBaseNode(kind);
4213        }
4214
4215        // @api
4216        // createJSDocNonNullableType
4217        // createJSDocNullableType
4218        // createJSDocOptionalType
4219        // createJSDocVariadicType
4220        // createJSDocNamepathType
4221
4222        function createJSDocUnaryTypeWorker<T extends JSDocType & { readonly type: TypeNode | undefined; }>(kind: T["kind"], type: T["type"]): T {
4223            const node = createBaseNode<T>(kind);
4224            node.type = type;
4225            return node;
4226        }
4227
4228        // @api
4229        // updateJSDocNonNullableType
4230        // updateJSDocNullableType
4231        // updateJSDocOptionalType
4232        // updateJSDocVariadicType
4233        // updateJSDocNamepathType
4234        function updateJSDocUnaryTypeWorker<T extends JSDocType & { readonly type: TypeNode | undefined; }>(kind: T["kind"], node: T, type: T["type"]): T {
4235            return node.type !== type
4236                ? update(createJSDocUnaryTypeWorker(kind, type), node)
4237                : node;
4238        }
4239
4240        // @api
4241        function createJSDocFunctionType(parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType {
4242            const node = createBaseSignatureDeclaration<JSDocFunctionType>(
4243                SyntaxKind.JSDocFunctionType,
4244                /*decorators*/ undefined,
4245                /*modifiers*/ undefined,
4246                /*name*/ undefined,
4247                /*typeParameters*/ undefined,
4248                parameters,
4249                type
4250            );
4251            return node;
4252        }
4253
4254        // @api
4255        function updateJSDocFunctionType(node: JSDocFunctionType, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType {
4256            return node.parameters !== parameters
4257                || node.type !== type
4258                ? update(createJSDocFunctionType(parameters, type), node)
4259                : node;
4260        }
4261
4262        // @api
4263        function createJSDocTypeLiteral(propertyTags?: readonly JSDocPropertyLikeTag[], isArrayType = false): JSDocTypeLiteral {
4264            const node = createBaseNode<JSDocTypeLiteral>(SyntaxKind.JSDocTypeLiteral);
4265            node.jsDocPropertyTags = asNodeArray(propertyTags);
4266            node.isArrayType = isArrayType;
4267            return node;
4268        }
4269
4270        // @api
4271        function updateJSDocTypeLiteral(node: JSDocTypeLiteral, propertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean): JSDocTypeLiteral {
4272            return node.jsDocPropertyTags !== propertyTags
4273                || node.isArrayType !== isArrayType
4274                ? update(createJSDocTypeLiteral(propertyTags, isArrayType), node)
4275                : node;
4276        }
4277
4278        // @api
4279        function createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression {
4280            const node = createBaseNode<JSDocTypeExpression>(SyntaxKind.JSDocTypeExpression);
4281            node.type = type;
4282            return node;
4283        }
4284
4285        // @api
4286        function updateJSDocTypeExpression(node: JSDocTypeExpression, type: TypeNode): JSDocTypeExpression {
4287            return node.type !== type
4288                ? update(createJSDocTypeExpression(type), node)
4289                : node;
4290        }
4291
4292        // @api
4293        function createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature {
4294            const node = createBaseNode<JSDocSignature>(SyntaxKind.JSDocSignature);
4295            node.typeParameters = asNodeArray(typeParameters);
4296            node.parameters = createNodeArray(parameters);
4297            node.type = type;
4298            return node;
4299        }
4300
4301        // @api
4302        function updateJSDocSignature(node: JSDocSignature, typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type: JSDocReturnTag | undefined): JSDocSignature {
4303            return node.typeParameters !== typeParameters
4304                || node.parameters !== parameters
4305                || node.type !== type
4306                ? update(createJSDocSignature(typeParameters, parameters, type), node)
4307                : node;
4308        }
4309
4310        function getDefaultTagName(node: JSDocTag) {
4311            const defaultTagName = getDefaultTagNameForKind(node.kind);
4312            return node.tagName.escapedText === escapeLeadingUnderscores(defaultTagName)
4313                ? node.tagName
4314                : createIdentifier(defaultTagName);
4315        }
4316
4317        // @api
4318        function createBaseJSDocTag<T extends JSDocTag>(kind: T["kind"], tagName: Identifier, comment: string | undefined) {
4319            const node = createBaseNode<T>(kind);
4320            node.tagName = tagName;
4321            node.comment = comment;
4322            return node;
4323        }
4324
4325        // @api
4326        function createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string): JSDocTemplateTag {
4327            const node = createBaseJSDocTag<JSDocTemplateTag>(SyntaxKind.JSDocTemplateTag, tagName ?? createIdentifier("template"), comment);
4328            node.constraint = constraint;
4329            node.typeParameters = createNodeArray(typeParameters);
4330            return node;
4331        }
4332
4333        // @api
4334        function updateJSDocTemplateTag(node: JSDocTemplateTag, tagName: Identifier = getDefaultTagName(node), constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment: string | undefined): JSDocTemplateTag {
4335            return node.tagName !== tagName
4336                || node.constraint !== constraint
4337                || node.typeParameters !== typeParameters
4338                || node.comment !== comment
4339                ? update(createJSDocTemplateTag(tagName, constraint, typeParameters, comment), node)
4340                : node;
4341        }
4342
4343        // @api
4344        function createJSDocTypedefTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string): JSDocTypedefTag {
4345            const node = createBaseJSDocTag<JSDocTypedefTag>(SyntaxKind.JSDocTypedefTag, tagName ?? createIdentifier("typedef"), comment);
4346            node.typeExpression = typeExpression;
4347            node.fullName = fullName;
4348            node.name = getJSDocTypeAliasName(fullName);
4349            return node;
4350        }
4351
4352        // @api
4353        function updateJSDocTypedefTag(node: JSDocTypedefTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | undefined): JSDocTypedefTag {
4354            return node.tagName !== tagName
4355                || node.typeExpression !== typeExpression
4356                || node.fullName !== fullName
4357                || node.comment !== comment
4358                ? update(createJSDocTypedefTag(tagName, typeExpression, fullName, comment), node)
4359                : node;
4360        }
4361
4362        // @api
4363        function createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocParameterTag {
4364            const node = createBaseJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, tagName ?? createIdentifier("param"), comment);
4365            node.typeExpression = typeExpression;
4366            node.name = name;
4367            node.isNameFirst = !!isNameFirst;
4368            node.isBracketed = isBracketed;
4369            return node;
4370        }
4371
4372        // @api
4373        function updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocParameterTag {
4374            return node.tagName !== tagName
4375                || node.name !== name
4376                || node.isBracketed !== isBracketed
4377                || node.typeExpression !== typeExpression
4378                || node.isNameFirst !== isNameFirst
4379                || node.comment !== comment
4380                ? update(createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), node)
4381                : node;
4382        }
4383
4384        // @api
4385        function createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string): JSDocPropertyTag {
4386            const node = createBaseJSDocTag<JSDocPropertyTag>(SyntaxKind.JSDocPropertyTag, tagName ?? createIdentifier("prop"), comment);
4387            node.typeExpression = typeExpression;
4388            node.name = name;
4389            node.isNameFirst = !!isNameFirst;
4390            node.isBracketed = isBracketed;
4391            return node;
4392        }
4393
4394        // @api
4395        function updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocPropertyTag {
4396            return node.tagName !== tagName
4397                || node.name !== name
4398                || node.isBracketed !== isBracketed
4399                || node.typeExpression !== typeExpression
4400                || node.isNameFirst !== isNameFirst
4401                || node.comment !== comment
4402                ? update(createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), node)
4403                : node;
4404        }
4405
4406        // @api
4407        function createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string): JSDocCallbackTag {
4408            const node = createBaseJSDocTag<JSDocCallbackTag>(SyntaxKind.JSDocCallbackTag, tagName ?? createIdentifier("callback"), comment);
4409            node.typeExpression = typeExpression;
4410            node.fullName = fullName;
4411            node.name = getJSDocTypeAliasName(fullName);
4412            return node;
4413        }
4414
4415        // @api
4416        function updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | undefined): JSDocCallbackTag {
4417            return node.tagName !== tagName
4418                || node.typeExpression !== typeExpression
4419                || node.fullName !== fullName
4420                || node.comment !== comment
4421                ? update(createJSDocCallbackTag(tagName, typeExpression, fullName, comment), node)
4422                : node;
4423        }
4424
4425        // @api
4426        function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string): JSDocAugmentsTag {
4427            const node = createBaseJSDocTag<JSDocAugmentsTag>(SyntaxKind.JSDocAugmentsTag, tagName ?? createIdentifier("augments"), comment);
4428            node.class = className;
4429            return node;
4430        }
4431
4432        // @api
4433        function updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocAugmentsTag["class"], comment: string | undefined): JSDocAugmentsTag {
4434            return node.tagName !== tagName
4435                || node.class !== className
4436                || node.comment !== comment
4437                ? update(createJSDocAugmentsTag(tagName, className, comment), node)
4438                : node;
4439        }
4440
4441        // @api
4442        function createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string): JSDocImplementsTag {
4443            const node = createBaseJSDocTag<JSDocImplementsTag>(SyntaxKind.JSDocImplementsTag, tagName ?? createIdentifier("implements"), comment);
4444            node.class = className;
4445            return node;
4446        }
4447
4448        // @api
4449        function createJSDocSeeTag(tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string): JSDocSeeTag {
4450            const node = createBaseJSDocTag<JSDocSeeTag>(SyntaxKind.JSDocSeeTag, tagName ?? createIdentifier("see"), comment);
4451            node.name = name;
4452            return node;
4453        }
4454
4455        // @api
4456        function updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string): JSDocSeeTag {
4457            return node.tagName !== tagName
4458                || node.name !== name
4459                || node.comment !== comment
4460                ? update(createJSDocSeeTag(tagName, name, comment), node)
4461                : node;
4462        }
4463
4464        // @api
4465        function createJSDocNameReference(name: EntityName): JSDocNameReference {
4466            const node = createBaseNode<JSDocNameReference>(SyntaxKind.JSDocNameReference);
4467            node.name = name;
4468            return node;
4469        }
4470
4471        // @api
4472        function updateJSDocNameReference(node: JSDocNameReference, name: EntityName): JSDocNameReference {
4473            return node.name !== name
4474                ? update(createJSDocNameReference(name), node)
4475                : node;
4476        }
4477
4478        // @api
4479        function updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag {
4480            return node.tagName !== tagName
4481                || node.class !== className
4482                || node.comment !== comment
4483                ? update(createJSDocImplementsTag(tagName, className, comment), node)
4484                : node;
4485        }
4486
4487        // @api
4488        // createJSDocAuthorTag
4489        // createJSDocClassTag
4490        // createJSDocPublicTag
4491        // createJSDocPrivateTag
4492        // createJSDocProtectedTag
4493        // createJSDocReadonlyTag
4494        // createJSDocDeprecatedTag
4495        function createJSDocSimpleTagWorker<T extends JSDocTag>(kind: T["kind"], tagName: Identifier | undefined, comment?: string) {
4496            const node = createBaseJSDocTag<T>(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment);
4497            return node;
4498        }
4499
4500        // @api
4501        // updateJSDocAuthorTag
4502        // updateJSDocClassTag
4503        // updateJSDocPublicTag
4504        // updateJSDocPrivateTag
4505        // updateJSDocProtectedTag
4506        // updateJSDocReadonlyTag
4507        // updateJSDocDeprecatedTag
4508        function updateJSDocSimpleTagWorker<T extends JSDocTag>(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), comment: string | undefined) {
4509            return node.tagName !== tagName
4510                || node.comment !== comment
4511                ? update(createJSDocSimpleTagWorker(kind, tagName, comment), node) :
4512                node;
4513        }
4514
4515        // @api
4516        // createJSDocTypeTag
4517        // createJSDocReturnTag
4518        // createJSDocThisTag
4519        // createJSDocEnumTag
4520        function createJSDocTypeLikeTagWorker<T extends JSDocTag & { typeExpression?: JSDocTypeExpression }>(kind: T["kind"], tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string) {
4521            const node = createBaseJSDocTag<T>(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment);
4522            node.typeExpression = typeExpression;
4523            return node;
4524        }
4525
4526        // @api
4527        // updateJSDocTypeTag
4528        // updateJSDocReturnTag
4529        // updateJSDocThisTag
4530        // updateJSDocEnumTag
4531        function updateJSDocTypeLikeTagWorker<T extends JSDocTag & { typeExpression?: JSDocTypeExpression }>(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, comment: string | undefined) {
4532            return node.tagName !== tagName
4533                || node.typeExpression !== typeExpression
4534                || node.comment !== comment
4535                ? update(createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment), node)
4536                : node;
4537        }
4538
4539        // @api
4540        function createJSDocUnknownTag(tagName: Identifier, comment?: string): JSDocUnknownTag {
4541            const node = createBaseJSDocTag<JSDocUnknownTag>(SyntaxKind.JSDocTag, tagName, comment);
4542            return node;
4543        }
4544
4545        // @api
4546        function updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | undefined): JSDocUnknownTag {
4547            return node.tagName !== tagName
4548                || node.comment !== comment
4549                ? update(createJSDocUnknownTag(tagName, comment), node)
4550                : node;
4551        }
4552
4553        // @api
4554        function createJSDocComment(comment?: string | undefined, tags?: readonly JSDocTag[] | undefined) {
4555            const node = createBaseNode<JSDoc>(SyntaxKind.JSDocComment);
4556            node.comment = comment;
4557            node.tags = asNodeArray(tags);
4558            return node;
4559        }
4560
4561        // @api
4562        function updateJSDocComment(node: JSDoc, comment: string | undefined, tags: readonly JSDocTag[] | undefined) {
4563            return node.comment !== comment
4564                || node.tags !== tags
4565                ? update(createJSDocComment(comment, tags), node)
4566                : node;
4567        }
4568
4569        //
4570        // JSX
4571        //
4572
4573        // @api
4574        function createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) {
4575            const node = createBaseNode<JsxElement>(SyntaxKind.JsxElement);
4576            node.openingElement = openingElement;
4577            node.children = createNodeArray(children);
4578            node.closingElement = closingElement;
4579            node.transformFlags |=
4580                propagateChildFlags(node.openingElement) |
4581                propagateChildrenFlags(node.children) |
4582                propagateChildFlags(node.closingElement) |
4583                TransformFlags.ContainsJsx;
4584            return node;
4585        }
4586
4587        // @api
4588        function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) {
4589            return node.openingElement !== openingElement
4590                || node.children !== children
4591                || node.closingElement !== closingElement
4592                ? update(createJsxElement(openingElement, children, closingElement), node)
4593                : node;
4594        }
4595
4596        // @api
4597        function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
4598            const node = createBaseNode<JsxSelfClosingElement>(SyntaxKind.JsxSelfClosingElement);
4599            node.tagName = tagName;
4600            node.typeArguments = asNodeArray(typeArguments);
4601            node.attributes = attributes;
4602            node.transformFlags |=
4603                propagateChildFlags(node.tagName) |
4604                propagateChildrenFlags(node.typeArguments) |
4605                propagateChildFlags(node.attributes) |
4606                TransformFlags.ContainsJsx;
4607            if (node.typeArguments) {
4608                node.transformFlags |= TransformFlags.ContainsTypeScript;
4609            }
4610            return node;
4611        }
4612
4613        // @api
4614        function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
4615            return node.tagName !== tagName
4616                || node.typeArguments !== typeArguments
4617                || node.attributes !== attributes
4618                ? update(createJsxSelfClosingElement(tagName, typeArguments, attributes), node)
4619                : node;
4620        }
4621
4622        // @api
4623        function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
4624            const node = createBaseNode<JsxOpeningElement>(SyntaxKind.JsxOpeningElement);
4625            node.tagName = tagName;
4626            node.typeArguments = asNodeArray(typeArguments);
4627            node.attributes = attributes;
4628            node.transformFlags |=
4629                propagateChildFlags(node.tagName) |
4630                propagateChildrenFlags(node.typeArguments) |
4631                propagateChildFlags(node.attributes) |
4632                TransformFlags.ContainsJsx;
4633            if (typeArguments) {
4634                node.transformFlags |= TransformFlags.ContainsTypeScript;
4635            }
4636            return node;
4637        }
4638
4639        // @api
4640        function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
4641            return node.tagName !== tagName
4642                || node.typeArguments !== typeArguments
4643                || node.attributes !== attributes
4644                ? update(createJsxOpeningElement(tagName, typeArguments, attributes), node)
4645                : node;
4646        }
4647
4648        // @api
4649        function createJsxClosingElement(tagName: JsxTagNameExpression) {
4650            const node = createBaseNode<JsxClosingElement>(SyntaxKind.JsxClosingElement);
4651            node.tagName = tagName;
4652            node.transformFlags |=
4653                propagateChildFlags(node.tagName) |
4654                TransformFlags.ContainsJsx;
4655            return node;
4656        }
4657
4658        // @api
4659        function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression) {
4660            return node.tagName !== tagName
4661                ? update(createJsxClosingElement(tagName), node)
4662                : node;
4663        }
4664
4665        // @api
4666        function createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) {
4667            const node = createBaseNode<JsxFragment>(SyntaxKind.JsxFragment);
4668            node.openingFragment = openingFragment;
4669            node.children = createNodeArray(children);
4670            node.closingFragment = closingFragment;
4671            node.transformFlags |=
4672                propagateChildFlags(node.openingFragment) |
4673                propagateChildrenFlags(node.children) |
4674                propagateChildFlags(node.closingFragment) |
4675                TransformFlags.ContainsJsx;
4676            return node;
4677        }
4678
4679        // @api
4680        function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) {
4681            return node.openingFragment !== openingFragment
4682                || node.children !== children
4683                || node.closingFragment !== closingFragment
4684                ? update(createJsxFragment(openingFragment, children, closingFragment), node)
4685                : node;
4686        }
4687
4688        // @api
4689        function createJsxText(text: string, containsOnlyTriviaWhiteSpaces?: boolean) {
4690            const node = createBaseNode<JsxText>(SyntaxKind.JsxText);
4691            node.text = text;
4692            node.containsOnlyTriviaWhiteSpaces = !!containsOnlyTriviaWhiteSpaces;
4693            node.transformFlags |= TransformFlags.ContainsJsx;
4694            return node;
4695        }
4696
4697        // @api
4698        function updateJsxText(node: JsxText, text: string, containsOnlyTriviaWhiteSpaces?: boolean) {
4699            return node.text !== text
4700                || node.containsOnlyTriviaWhiteSpaces !== containsOnlyTriviaWhiteSpaces
4701                ? update(createJsxText(text, containsOnlyTriviaWhiteSpaces), node)
4702                : node;
4703        }
4704
4705        // @api
4706        function createJsxOpeningFragment() {
4707            const node = createBaseNode<JsxOpeningFragment>(SyntaxKind.JsxOpeningFragment);
4708            node.transformFlags |= TransformFlags.ContainsJsx;
4709            return node;
4710        }
4711
4712        // @api
4713        function createJsxJsxClosingFragment() {
4714            const node = createBaseNode<JsxClosingFragment>(SyntaxKind.JsxClosingFragment);
4715            node.transformFlags |= TransformFlags.ContainsJsx;
4716            return node;
4717        }
4718
4719        // @api
4720        function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression | undefined) {
4721            const node = createBaseNode<JsxAttribute>(SyntaxKind.JsxAttribute);
4722            node.name = name;
4723            node.initializer = initializer;
4724            node.transformFlags |=
4725                propagateChildFlags(node.name) |
4726                propagateChildFlags(node.initializer) |
4727                TransformFlags.ContainsJsx;
4728            return node;
4729        }
4730
4731        // @api
4732        function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression | undefined) {
4733            return node.name !== name
4734                || node.initializer !== initializer
4735                ? update(createJsxAttribute(name, initializer), node)
4736                : node;
4737        }
4738
4739        // @api
4740        function createJsxAttributes(properties: readonly JsxAttributeLike[]) {
4741            const node = createBaseNode<JsxAttributes>(SyntaxKind.JsxAttributes);
4742            node.properties = createNodeArray(properties);
4743            node.transformFlags |=
4744                propagateChildrenFlags(node.properties) |
4745                TransformFlags.ContainsJsx;
4746            return node;
4747        }
4748
4749        // @api
4750        function updateJsxAttributes(node: JsxAttributes, properties: readonly JsxAttributeLike[]) {
4751            return node.properties !== properties
4752                ? update(createJsxAttributes(properties), node)
4753                : node;
4754        }
4755
4756        // @api
4757        function createJsxSpreadAttribute(expression: Expression) {
4758            const node = createBaseNode<JsxSpreadAttribute>(SyntaxKind.JsxSpreadAttribute);
4759            node.expression = expression;
4760            node.transformFlags |=
4761                propagateChildFlags(node.expression) |
4762                TransformFlags.ContainsJsx;
4763            return node;
4764        }
4765
4766        // @api
4767        function updateJsxSpreadAttribute(node: JsxSpreadAttribute, expression: Expression) {
4768            return node.expression !== expression
4769                ? update(createJsxSpreadAttribute(expression), node)
4770                : node;
4771        }
4772
4773        // @api
4774        function createJsxExpression(dotDotDotToken: DotDotDotToken | undefined, expression: Expression | undefined) {
4775            const node = createBaseNode<JsxExpression>(SyntaxKind.JsxExpression);
4776            node.dotDotDotToken = dotDotDotToken;
4777            node.expression = expression;
4778            node.transformFlags |=
4779                propagateChildFlags(node.dotDotDotToken) |
4780                propagateChildFlags(node.expression) |
4781                TransformFlags.ContainsJsx;
4782            return node;
4783        }
4784
4785        // @api
4786        function updateJsxExpression(node: JsxExpression, expression: Expression | undefined) {
4787            return node.expression !== expression
4788                ? update(createJsxExpression(node.dotDotDotToken, expression), node)
4789                : node;
4790        }
4791
4792        //
4793        // Clauses
4794        //
4795
4796        // @api
4797        function createCaseClause(expression: Expression, statements: readonly Statement[]) {
4798            const node = createBaseNode<CaseClause>(SyntaxKind.CaseClause);
4799            node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
4800            node.statements = createNodeArray(statements);
4801            node.transformFlags |=
4802                propagateChildFlags(node.expression) |
4803                propagateChildrenFlags(node.statements);
4804            return node;
4805        }
4806
4807        // @api
4808        function updateCaseClause(node: CaseClause, expression: Expression, statements: readonly Statement[]) {
4809            return node.expression !== expression
4810                || node.statements !== statements
4811                ? update(createCaseClause(expression, statements), node)
4812                : node;
4813        }
4814
4815        // @api
4816        function createDefaultClause(statements: readonly Statement[]) {
4817            const node = createBaseNode<DefaultClause>(SyntaxKind.DefaultClause);
4818            node.statements = createNodeArray(statements);
4819            node.transformFlags = propagateChildrenFlags(node.statements);
4820            return node;
4821        }
4822
4823        // @api
4824        function updateDefaultClause(node: DefaultClause, statements: readonly Statement[]) {
4825            return node.statements !== statements
4826                ? update(createDefaultClause(statements), node)
4827                : node;
4828        }
4829
4830        // @api
4831        function createHeritageClause(token: HeritageClause["token"], types: readonly ExpressionWithTypeArguments[]) {
4832            const node = createBaseNode<HeritageClause>(SyntaxKind.HeritageClause);
4833            node.token = token;
4834            node.types = createNodeArray(types);
4835            node.transformFlags |= propagateChildrenFlags(node.types);
4836            switch (token) {
4837                case SyntaxKind.ExtendsKeyword:
4838                    node.transformFlags |= TransformFlags.ContainsES2015;
4839                    break;
4840                case SyntaxKind.ImplementsKeyword:
4841                    node.transformFlags |= TransformFlags.ContainsTypeScript;
4842                    break;
4843                default:
4844                    return Debug.assertNever(token);
4845            }
4846            return node;
4847        }
4848
4849        // @api
4850        function updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]) {
4851            return node.types !== types
4852                ? update(createHeritageClause(node.token, types), node)
4853                : node;
4854        }
4855
4856        // @api
4857        function createCatchClause(variableDeclaration: string | VariableDeclaration | undefined, block: Block) {
4858            const node = createBaseNode<CatchClause>(SyntaxKind.CatchClause);
4859            variableDeclaration = !isString(variableDeclaration) ? variableDeclaration : createVariableDeclaration(
4860                variableDeclaration,
4861                /*exclamationToken*/ undefined,
4862                /*type*/ undefined,
4863                /*initializer*/ undefined
4864            );
4865            node.variableDeclaration = variableDeclaration;
4866            node.block = block;
4867            node.transformFlags |=
4868                propagateChildFlags(node.variableDeclaration) |
4869                propagateChildFlags(node.block);
4870            if (!variableDeclaration) node.transformFlags |= TransformFlags.ContainsES2019;
4871            return node;
4872        }
4873
4874        // @api
4875        function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block) {
4876            return node.variableDeclaration !== variableDeclaration
4877                || node.block !== block
4878                ? update(createCatchClause(variableDeclaration, block), node)
4879                : node;
4880        }
4881
4882        //
4883        // Property assignments
4884        //
4885
4886        // @api
4887        function createPropertyAssignment(name: string | PropertyName, initializer: Expression) {
4888            const node = createBaseNamedDeclaration<PropertyAssignment>(
4889                SyntaxKind.PropertyAssignment,
4890                /*decorators*/ undefined,
4891                /*modifiers*/ undefined,
4892                name
4893            );
4894            node.initializer = parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer);
4895            node.transformFlags |=
4896                propagateChildFlags(node.name) |
4897                propagateChildFlags(node.initializer);
4898            return node;
4899        }
4900
4901        function finishUpdatePropertyAssignment(updated: Mutable<PropertyAssignment>, original: PropertyAssignment) {
4902            // copy children used only for error reporting
4903            if (original.decorators) updated.decorators = original.decorators;
4904            if (original.modifiers) updated.modifiers = original.modifiers;
4905            if (original.questionToken) updated.questionToken = original.questionToken;
4906            if (original.exclamationToken) updated.exclamationToken = original.exclamationToken;
4907            return update(updated, original);
4908        }
4909
4910        // @api
4911        function updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression) {
4912            return node.name !== name
4913                || node.initializer !== initializer
4914                ? finishUpdatePropertyAssignment(createPropertyAssignment(name, initializer), node)
4915                : node;
4916        }
4917
4918        // @api
4919        function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression) {
4920            const node = createBaseNamedDeclaration<ShorthandPropertyAssignment>(
4921                SyntaxKind.ShorthandPropertyAssignment,
4922                /*decorators*/ undefined,
4923                /*modifiers*/ undefined,
4924                name
4925            );
4926            node.objectAssignmentInitializer = objectAssignmentInitializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(objectAssignmentInitializer);
4927            node.transformFlags |=
4928                propagateChildFlags(node.objectAssignmentInitializer) |
4929                TransformFlags.ContainsES2015;
4930            return node;
4931        }
4932
4933        function finishUpdateShorthandPropertyAssignment(updated: Mutable<ShorthandPropertyAssignment>, original: ShorthandPropertyAssignment) {
4934            // copy children used only for error reporting
4935            if (original.decorators) updated.decorators = original.decorators;
4936            if (original.modifiers) updated.modifiers = original.modifiers;
4937            if (original.equalsToken) updated.equalsToken = original.equalsToken;
4938            if (original.questionToken) updated.questionToken = original.questionToken;
4939            if (original.exclamationToken) updated.exclamationToken = original.exclamationToken;
4940            return update(updated, original);
4941        }
4942
4943        // @api
4944        function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined) {
4945            return node.name !== name
4946                || node.objectAssignmentInitializer !== objectAssignmentInitializer
4947                ? finishUpdateShorthandPropertyAssignment(createShorthandPropertyAssignment(name, objectAssignmentInitializer), node)
4948                : node;
4949        }
4950
4951        // @api
4952        function createSpreadAssignment(expression: Expression) {
4953            const node = createBaseNode<SpreadAssignment>(SyntaxKind.SpreadAssignment);
4954            node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression);
4955            node.transformFlags |=
4956                propagateChildFlags(node.expression) |
4957                TransformFlags.ContainsES2018 |
4958                TransformFlags.ContainsObjectRestOrSpread;
4959            return node;
4960        }
4961
4962        // @api
4963        function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) {
4964            return node.expression !== expression
4965                ? update(createSpreadAssignment(expression), node)
4966                : node;
4967        }
4968
4969        //
4970        // Enum
4971        //
4972
4973        // @api
4974        function createEnumMember(name: string | PropertyName, initializer?: Expression) {
4975            const node = createBaseNode<EnumMember>(SyntaxKind.EnumMember);
4976            node.name = asName(name);
4977            node.initializer = initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer);
4978            node.transformFlags |=
4979                propagateChildFlags(node.name) |
4980                propagateChildFlags(node.initializer) |
4981                TransformFlags.ContainsTypeScript;
4982            return node;
4983        }
4984
4985        // @api
4986        function updateEnumMember(node: EnumMember, name: PropertyName, initializer: Expression | undefined) {
4987            return node.name !== name
4988                || node.initializer !== initializer
4989                ? update(createEnumMember(name, initializer), node)
4990                : node;
4991        }
4992
4993        //
4994        // Top-level nodes
4995        //
4996
4997        // @api
4998        function createSourceFile(
4999            statements: readonly Statement[],
5000            endOfFileToken: EndOfFileToken,
5001            flags: NodeFlags
5002        ) {
5003            const node = baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as Mutable<SourceFile>;
5004            node.statements = createNodeArray(statements);
5005            node.endOfFileToken = endOfFileToken;
5006            node.flags |= flags;
5007            node.fileName = "";
5008            node.text = "";
5009            node.languageVersion = 0;
5010            node.languageVariant = 0;
5011            node.scriptKind = 0;
5012            node.isDeclarationFile = false;
5013            node.hasNoDefaultLib = false;
5014            node.transformFlags |=
5015                propagateChildrenFlags(node.statements) |
5016                propagateChildFlags(node.endOfFileToken);
5017            return node;
5018        }
5019
5020        function cloneSourceFileWithChanges(
5021            source: SourceFile,
5022            statements: readonly Statement[],
5023            isDeclarationFile: boolean,
5024            referencedFiles: readonly FileReference[],
5025            typeReferences: readonly FileReference[],
5026            hasNoDefaultLib: boolean,
5027            libReferences: readonly FileReference[]
5028        ) {
5029            const node = (source.redirectInfo ? Object.create(source.redirectInfo.redirectTarget) : baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile)) as Mutable<SourceFile>;
5030            for (const p in source) {
5031                if (p === "emitNode" || hasProperty(node, p) || !hasProperty(source, p)) continue;
5032                (node as any)[p] = (source as any)[p];
5033            }
5034            node.flags |= source.flags;
5035            node.statements = createNodeArray(statements);
5036            node.endOfFileToken = source.endOfFileToken;
5037            node.isDeclarationFile = isDeclarationFile;
5038            node.referencedFiles = referencedFiles;
5039            node.typeReferenceDirectives = typeReferences;
5040            node.hasNoDefaultLib = hasNoDefaultLib;
5041            node.libReferenceDirectives = libReferences;
5042            node.transformFlags =
5043                propagateChildrenFlags(node.statements) |
5044                propagateChildFlags(node.endOfFileToken);
5045            return node;
5046        }
5047
5048        // @api
5049        function updateSourceFile(
5050            node: SourceFile,
5051            statements: readonly Statement[],
5052            isDeclarationFile = node.isDeclarationFile,
5053            referencedFiles = node.referencedFiles,
5054            typeReferenceDirectives = node.typeReferenceDirectives,
5055            hasNoDefaultLib = node.hasNoDefaultLib,
5056            libReferenceDirectives = node.libReferenceDirectives
5057        ) {
5058            return node.statements !== statements
5059                || node.isDeclarationFile !== isDeclarationFile
5060                || node.referencedFiles !== referencedFiles
5061                || node.typeReferenceDirectives !== typeReferenceDirectives
5062                || node.hasNoDefaultLib !== hasNoDefaultLib
5063                || node.libReferenceDirectives !== libReferenceDirectives
5064                ? update(cloneSourceFileWithChanges(node, statements, isDeclarationFile, referencedFiles, typeReferenceDirectives, hasNoDefaultLib, libReferenceDirectives), node)
5065                : node;
5066        }
5067
5068        // @api
5069        function createBundle(sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) {
5070            const node = createBaseNode<Bundle>(SyntaxKind.Bundle);
5071            node.prepends = prepends;
5072            node.sourceFiles = sourceFiles;
5073            return node;
5074        }
5075
5076        // @api
5077        function updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) {
5078            return node.sourceFiles !== sourceFiles
5079                || node.prepends !== prepends
5080                ? update(createBundle(sourceFiles, prepends), node)
5081                : node;
5082        }
5083
5084        // @api
5085        function createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]) {
5086            const node = createBaseNode<UnparsedSource>(SyntaxKind.UnparsedSource);
5087            node.prologues = prologues;
5088            node.syntheticReferences = syntheticReferences;
5089            node.texts = texts;
5090            node.fileName = "";
5091            node.text = "";
5092            node.referencedFiles = emptyArray;
5093            node.libReferenceDirectives = emptyArray;
5094            node.getLineAndCharacterOfPosition = pos => getLineAndCharacterOfPosition(node, pos);
5095            return node;
5096        }
5097
5098        function createBaseUnparsedNode<T extends UnparsedNode>(kind: T["kind"], data?: string) {
5099            const node = createBaseNode(kind);
5100            node.data = data;
5101            return node;
5102        }
5103
5104        // @api
5105        function createUnparsedPrologue(data?: string): UnparsedPrologue {
5106            return createBaseUnparsedNode(SyntaxKind.UnparsedPrologue, data);
5107        }
5108
5109        // @api
5110        function createUnparsedPrepend(data: string | undefined, texts: readonly UnparsedTextLike[]): UnparsedPrepend {
5111            const node = createBaseUnparsedNode<UnparsedPrepend>(SyntaxKind.UnparsedPrepend, data);
5112            node.texts = texts;
5113            return node;
5114        }
5115
5116        // @api
5117        function createUnparsedTextLike(data: string | undefined, internal: boolean): UnparsedTextLike {
5118            return createBaseUnparsedNode(internal ? SyntaxKind.UnparsedInternalText : SyntaxKind.UnparsedText, data);
5119        }
5120
5121        // @api
5122        function createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference): UnparsedSyntheticReference {
5123            const node = createBaseNode<UnparsedSyntheticReference>(SyntaxKind.UnparsedSyntheticReference);
5124            node.data = section.data;
5125            node.section = section;
5126            return node;
5127        }
5128
5129        // @api
5130        function createInputFiles(): InputFiles {
5131            const node = createBaseNode<InputFiles>(SyntaxKind.InputFiles);
5132            node.javascriptText = "";
5133            node.declarationText = "";
5134            return node;
5135        }
5136
5137        //
5138        // Synthetic Nodes (used by checker)
5139        //
5140
5141        // @api
5142        function createSyntheticExpression(type: Type, isSpread = false, tupleNameSource?: ParameterDeclaration | NamedTupleMember) {
5143            const node = createBaseNode<SyntheticExpression>(SyntaxKind.SyntheticExpression);
5144            node.type = type;
5145            node.isSpread = isSpread;
5146            node.tupleNameSource = tupleNameSource;
5147            return node;
5148        }
5149
5150        // @api
5151        function createSyntaxList(children: Node[]) {
5152            const node = createBaseNode<SyntaxList>(SyntaxKind.SyntaxList);
5153            node._children = children;
5154            return node;
5155        }
5156
5157        //
5158        // Transformation nodes
5159        //
5160
5161        /**
5162         * Creates a synthetic statement to act as a placeholder for a not-emitted statement in
5163         * order to preserve comments.
5164         *
5165         * @param original The original statement.
5166         */
5167        // @api
5168        function createNotEmittedStatement(original: Node) {
5169            const node = createBaseNode<NotEmittedStatement>(SyntaxKind.NotEmittedStatement);
5170            node.original = original;
5171            setTextRange(node, original);
5172            return node;
5173        }
5174
5175        /**
5176         * Creates a synthetic expression to act as a placeholder for a not-emitted expression in
5177         * order to preserve comments or sourcemap positions.
5178         *
5179         * @param expression The inner expression to emit.
5180         * @param original The original outer expression.
5181         */
5182        // @api
5183        function createPartiallyEmittedExpression(expression: Expression, original?: Node) {
5184            const node = createBaseNode<PartiallyEmittedExpression>(SyntaxKind.PartiallyEmittedExpression);
5185            node.expression = expression;
5186            node.original = original;
5187            node.transformFlags |=
5188                propagateChildFlags(node.expression) |
5189                TransformFlags.ContainsTypeScript;
5190            setTextRange(node, original);
5191            return node;
5192        }
5193
5194        // @api
5195        function updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression) {
5196            return node.expression !== expression
5197                ? update(createPartiallyEmittedExpression(expression, node.original), node)
5198                : node;
5199        }
5200
5201        function flattenCommaElements(node: Expression): Expression | readonly Expression[] {
5202            if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode && !node.id) {
5203                if (isCommaListExpression(node)) {
5204                    return node.elements;
5205                }
5206                if (isBinaryExpression(node) && isCommaToken(node.operatorToken)) {
5207                    return [node.left, node.right];
5208                }
5209            }
5210            return node;
5211        }
5212
5213        // @api
5214        function createCommaListExpression(elements: readonly Expression[]) {
5215            const node = createBaseNode<CommaListExpression>(SyntaxKind.CommaListExpression);
5216            node.elements = createNodeArray(sameFlatMap(elements, flattenCommaElements));
5217            node.transformFlags |= propagateChildrenFlags(node.elements);
5218            return node;
5219        }
5220
5221        // @api
5222        function updateCommaListExpression(node: CommaListExpression, elements: readonly Expression[]) {
5223            return node.elements !== elements
5224                ? update(createCommaListExpression(elements), node)
5225                : node;
5226        }
5227
5228        /**
5229         * Creates a synthetic element to act as a placeholder for the end of an emitted declaration in
5230         * order to properly emit exports.
5231         */
5232        // @api
5233        function createEndOfDeclarationMarker(original: Node) {
5234            const node = createBaseNode<EndOfDeclarationMarker>(SyntaxKind.EndOfDeclarationMarker);
5235            node.emitNode = {} as EmitNode;
5236            node.original = original;
5237            return node;
5238        }
5239
5240        /**
5241         * Creates a synthetic element to act as a placeholder for the beginning of a merged declaration in
5242         * order to properly emit exports.
5243         */
5244        // @api
5245        function createMergeDeclarationMarker(original: Node) {
5246            const node = createBaseNode<MergeDeclarationMarker>(SyntaxKind.MergeDeclarationMarker);
5247            node.emitNode = {} as EmitNode;
5248            node.original = original;
5249            return node;
5250        }
5251
5252        // @api
5253        function createSyntheticReferenceExpression(expression: Expression, thisArg: Expression) {
5254            const node = createBaseNode<SyntheticReferenceExpression>(SyntaxKind.SyntheticReferenceExpression);
5255            node.expression = expression;
5256            node.thisArg = thisArg;
5257            node.transformFlags |=
5258                propagateChildFlags(node.expression) |
5259                propagateChildFlags(node.thisArg);
5260            return node;
5261        }
5262
5263        // @api
5264        function updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression) {
5265            return node.expression !== expression
5266                || node.thisArg !== thisArg
5267                ? update(createSyntheticReferenceExpression(expression, thisArg), node)
5268                : node;
5269        }
5270
5271        // @api
5272        function cloneNode<T extends Node | undefined>(node: T): T;
5273        function cloneNode<T extends Node>(node: T) {
5274            // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
5275            // the original node. We also need to exclude specific properties and only include own-
5276            // properties (to skip members already defined on the shared prototype).
5277            if (node === undefined) {
5278                return node;
5279            }
5280
5281            const clone =
5282                isSourceFile(node) ? baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as T :
5283                isIdentifier(node) ? baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as T :
5284                isPrivateIdentifier(node) ? baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as T :
5285                !isNodeKind(node.kind) ? baseFactory.createBaseTokenNode(node.kind) as T :
5286                baseFactory.createBaseNode(node.kind) as T;
5287
5288            (clone as Mutable<T>).flags |= (node.flags & ~NodeFlags.Synthesized);
5289            (clone as Mutable<T>).transformFlags = node.transformFlags;
5290            setOriginalNode(clone, node);
5291
5292            for (const key in node) {
5293                if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) {
5294                    continue;
5295                }
5296
5297                clone[key] = node[key];
5298            }
5299
5300            return clone;
5301        }
5302
5303        // compound nodes
5304        function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression;
5305        function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
5306        function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) {
5307            return createCallExpression(
5308                createFunctionExpression(
5309                    /*modifiers*/ undefined,
5310                    /*asteriskToken*/ undefined,
5311                    /*name*/ undefined,
5312                    /*typeParameters*/ undefined,
5313                    /*parameters*/ param ? [param] : [],
5314                    /*type*/ undefined,
5315                    createBlock(statements, /*multiLine*/ true)
5316                ),
5317                /*typeArguments*/ undefined,
5318                /*argumentsArray*/ paramValue ? [paramValue] : []
5319            );
5320        }
5321
5322        function createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression;
5323        function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
5324        function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) {
5325            return createCallExpression(
5326                createArrowFunction(
5327                    /*modifiers*/ undefined,
5328                    /*typeParameters*/ undefined,
5329                    /*parameters*/ param ? [param] : [],
5330                    /*type*/ undefined,
5331                    /*equalsGreaterThanToken*/ undefined,
5332                    createBlock(statements, /*multiLine*/ true)
5333                ),
5334                /*typeArguments*/ undefined,
5335                /*argumentsArray*/ paramValue ? [paramValue] : []
5336            );
5337        }
5338
5339        function createVoidZero() {
5340            return createVoidExpression(createNumericLiteral("0"));
5341        }
5342
5343        function createExportDefault(expression: Expression) {
5344            return createExportAssignment(
5345                /*decorators*/ undefined,
5346                /*modifiers*/ undefined,
5347                /*isExportEquals*/ false,
5348                expression);
5349        }
5350
5351        function createExternalModuleExport(exportName: Identifier) {
5352            return createExportDeclaration(
5353                /*decorators*/ undefined,
5354                /*modifiers*/ undefined,
5355                /*isTypeOnly*/ false,
5356                createNamedExports([
5357                    createExportSpecifier(/*propertyName*/ undefined, exportName)
5358                ])
5359            );
5360        }
5361
5362        //
5363        // Utilities
5364        //
5365
5366        function createTypeCheck(value: Expression, tag: TypeOfTag) {
5367            return tag === "undefined"
5368                ? factory.createStrictEquality(value, createVoidZero())
5369                : factory.createStrictEquality(createTypeOfExpression(value), createStringLiteral(tag));
5370        }
5371
5372        function createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]) {
5373            return createCallExpression(
5374                createPropertyAccessExpression(object, methodName),
5375                /*typeArguments*/ undefined,
5376                argumentsList
5377            );
5378        }
5379
5380        function createFunctionBindCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]) {
5381            return createMethodCall(target, "bind", [thisArg, ...argumentsList]);
5382        }
5383
5384        function createFunctionCallCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]) {
5385            return createMethodCall(target, "call", [thisArg, ...argumentsList]);
5386        }
5387
5388        function createFunctionApplyCall(target: Expression, thisArg: Expression, argumentsExpression: Expression) {
5389            return createMethodCall(target, "apply", [thisArg, argumentsExpression]);
5390        }
5391
5392        function createGlobalMethodCall(globalObjectName: string, methodName: string, argumentsList: readonly Expression[]) {
5393            return createMethodCall(createIdentifier(globalObjectName), methodName, argumentsList);
5394        }
5395
5396        function createArraySliceCall(array: Expression, start?: number | Expression) {
5397            return createMethodCall(array, "slice", start === undefined ? [] : [asExpression(start)]);
5398        }
5399
5400        function createArrayConcatCall(array: Expression, argumentsList: readonly Expression[]) {
5401            return createMethodCall(array, "concat", argumentsList);
5402        }
5403
5404        function createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression) {
5405            return createGlobalMethodCall("Object", "defineProperty", [target, asExpression(propertyName), attributes]);
5406        }
5407
5408        function tryAddPropertyAssignment(properties: Push<PropertyAssignment>, propertyName: string, expression: Expression | undefined) {
5409            if (expression) {
5410                properties.push(createPropertyAssignment(propertyName, expression));
5411                return true;
5412            }
5413            return false;
5414        }
5415
5416        function createPropertyDescriptor(attributes: PropertyDescriptorAttributes, singleLine?: boolean) {
5417            const properties: PropertyAssignment[] = [];
5418            tryAddPropertyAssignment(properties, "enumerable", asExpression(attributes.enumerable));
5419            tryAddPropertyAssignment(properties, "configurable", asExpression(attributes.configurable));
5420
5421            let isData = tryAddPropertyAssignment(properties, "writable", asExpression(attributes.writable));
5422            isData = tryAddPropertyAssignment(properties, "value", attributes.value) || isData;
5423
5424            let isAccessor = tryAddPropertyAssignment(properties, "get", attributes.get);
5425            isAccessor = tryAddPropertyAssignment(properties, "set", attributes.set) || isAccessor;
5426
5427            Debug.assert(!(isData && isAccessor), "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor.");
5428            return createObjectLiteralExpression(properties, !singleLine);
5429        }
5430
5431        function updateOuterExpression(outerExpression: OuterExpression, expression: Expression) {
5432            switch (outerExpression.kind) {
5433                case SyntaxKind.ParenthesizedExpression: return updateParenthesizedExpression(outerExpression, expression);
5434                case SyntaxKind.TypeAssertionExpression: return updateTypeAssertion(outerExpression, outerExpression.type, expression);
5435                case SyntaxKind.AsExpression: return updateAsExpression(outerExpression, expression, outerExpression.type);
5436                case SyntaxKind.NonNullExpression: return updateNonNullExpression(outerExpression, expression);
5437                case SyntaxKind.PartiallyEmittedExpression: return updatePartiallyEmittedExpression(outerExpression, expression);
5438            }
5439        }
5440
5441        /**
5442         * Determines whether a node is a parenthesized expression that can be ignored when recreating outer expressions.
5443         *
5444         * A parenthesized expression can be ignored when all of the following are true:
5445         *
5446         * - It's `pos` and `end` are not -1
5447         * - It does not have a custom source map range
5448         * - It does not have a custom comment range
5449         * - It does not have synthetic leading or trailing comments
5450         *
5451         * If an outermost parenthesized expression is ignored, but the containing expression requires a parentheses around
5452         * the expression to maintain precedence, a new parenthesized expression should be created automatically when
5453         * the containing expression is created/updated.
5454         */
5455        function isIgnorableParen(node: Expression) {
5456            return isParenthesizedExpression(node)
5457                && nodeIsSynthesized(node)
5458                && nodeIsSynthesized(getSourceMapRange(node))
5459                && nodeIsSynthesized(getCommentRange(node))
5460                && !some(getSyntheticLeadingComments(node))
5461                && !some(getSyntheticTrailingComments(node));
5462        }
5463
5464        function restoreOuterExpressions(outerExpression: Expression | undefined, innerExpression: Expression, kinds = OuterExpressionKinds.All): Expression {
5465            if (outerExpression && isOuterExpression(outerExpression, kinds) && !isIgnorableParen(outerExpression)) {
5466                return updateOuterExpression(
5467                    outerExpression,
5468                    restoreOuterExpressions(outerExpression.expression, innerExpression)
5469                );
5470            }
5471            return innerExpression;
5472        }
5473
5474        function restoreEnclosingLabel(node: Statement, outermostLabeledStatement: LabeledStatement | undefined, afterRestoreLabelCallback?: (node: LabeledStatement) => void): Statement {
5475            if (!outermostLabeledStatement) {
5476                return node;
5477            }
5478            const updated = updateLabeledStatement(
5479                outermostLabeledStatement,
5480                outermostLabeledStatement.label,
5481                isLabeledStatement(outermostLabeledStatement.statement)
5482                    ? restoreEnclosingLabel(node, outermostLabeledStatement.statement)
5483                    : node
5484            );
5485            if (afterRestoreLabelCallback) {
5486                afterRestoreLabelCallback(outermostLabeledStatement);
5487            }
5488            return updated;
5489        }
5490
5491        function shouldBeCapturedInTempVariable(node: Expression, cacheIdentifiers: boolean): boolean {
5492            const target = skipParentheses(node);
5493            switch (target.kind) {
5494                case SyntaxKind.Identifier:
5495                    return cacheIdentifiers;
5496                case SyntaxKind.ThisKeyword:
5497                case SyntaxKind.NumericLiteral:
5498                case SyntaxKind.BigIntLiteral:
5499                case SyntaxKind.StringLiteral:
5500                    return false;
5501                case SyntaxKind.ArrayLiteralExpression:
5502                    const elements = (<ArrayLiteralExpression>target).elements;
5503                    if (elements.length === 0) {
5504                        return false;
5505                    }
5506                    return true;
5507                case SyntaxKind.ObjectLiteralExpression:
5508                    return (<ObjectLiteralExpression>target).properties.length > 0;
5509                default:
5510                    return true;
5511            }
5512        }
5513
5514        function createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget, cacheIdentifiers = false): CallBinding {
5515            const callee = skipOuterExpressions(expression, OuterExpressionKinds.All);
5516            let thisArg: Expression;
5517            let target: LeftHandSideExpression;
5518            if (isSuperProperty(callee)) {
5519                thisArg = createThis();
5520                target = callee;
5521            }
5522            else if (isSuperKeyword(callee)) {
5523                thisArg = createThis();
5524                target = languageVersion !== undefined && languageVersion < ScriptTarget.ES2015
5525                    ? setTextRange(createIdentifier("_super"), callee)
5526                    : <PrimaryExpression>callee;
5527            }
5528            else if (getEmitFlags(callee) & EmitFlags.HelperName) {
5529                thisArg = createVoidZero();
5530                target = parenthesizerRules().parenthesizeLeftSideOfAccess(callee);
5531            }
5532            else if (isPropertyAccessExpression(callee)) {
5533                if (shouldBeCapturedInTempVariable(callee.expression, cacheIdentifiers)) {
5534                    // for `a.b()` target is `(_a = a).b` and thisArg is `_a`
5535                    thisArg = createTempVariable(recordTempVariable);
5536                    target = createPropertyAccessExpression(
5537                        setTextRange(
5538                            factory.createAssignment(
5539                                thisArg,
5540                                callee.expression
5541                            ),
5542                            callee.expression
5543                        ),
5544                        callee.name
5545                    );
5546                    setTextRange(target, callee);
5547                }
5548                else {
5549                    thisArg = callee.expression;
5550                    target = callee;
5551                }
5552            }
5553            else if (isElementAccessExpression(callee)) {
5554                if (shouldBeCapturedInTempVariable(callee.expression, cacheIdentifiers)) {
5555                    // for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a`
5556                    thisArg = createTempVariable(recordTempVariable);
5557                    target = createElementAccessExpression(
5558                        setTextRange(
5559                            factory.createAssignment(
5560                                thisArg,
5561                                callee.expression
5562                            ),
5563                            callee.expression
5564                        ),
5565                        callee.argumentExpression
5566                    );
5567                    setTextRange(target, callee);
5568                }
5569                else {
5570                    thisArg = callee.expression;
5571                    target = callee;
5572                }
5573            }
5574            else {
5575                // for `a()` target is `a` and thisArg is `void 0`
5576                thisArg = createVoidZero();
5577                target = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
5578            }
5579
5580            return { target, thisArg };
5581        }
5582
5583        function inlineExpressions(expressions: readonly Expression[]) {
5584            // Avoid deeply nested comma expressions as traversing them during emit can result in "Maximum call
5585            // stack size exceeded" errors.
5586            return expressions.length > 10
5587                ? createCommaListExpression(expressions)
5588                : reduceLeft(expressions, factory.createComma)!;
5589        }
5590
5591        function getName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) {
5592            const nodeName = getNameOfDeclaration(node);
5593            if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) {
5594                // TODO(rbuckton): Does this need to be parented?
5595                const name = setParent(setTextRange(cloneNode(nodeName), nodeName), nodeName.parent);
5596                emitFlags |= getEmitFlags(nodeName);
5597                if (!allowSourceMaps) emitFlags |= EmitFlags.NoSourceMap;
5598                if (!allowComments) emitFlags |= EmitFlags.NoComments;
5599                if (emitFlags) setEmitFlags(name, emitFlags);
5600                return name;
5601            }
5602            return getGeneratedNameForNode(node);
5603        }
5604
5605        /**
5606         * Gets the internal name of a declaration. This is primarily used for declarations that can be
5607         * referred to by name in the body of an ES5 class function body. An internal name will *never*
5608         * be prefixed with an module or namespace export modifier like "exports." when emitted as an
5609         * expression. An internal name will also *never* be renamed due to a collision with a block
5610         * scoped variable.
5611         *
5612         * @param node The declaration.
5613         * @param allowComments A value indicating whether comments may be emitted for the name.
5614         * @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
5615         */
5616        function getInternalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) {
5617            return getName(node, allowComments, allowSourceMaps, EmitFlags.LocalName | EmitFlags.InternalName);
5618        }
5619
5620        /**
5621         * Gets the local name of a declaration. This is primarily used for declarations that can be
5622         * referred to by name in the declaration's immediate scope (classes, enums, namespaces). A
5623         * local name will *never* be prefixed with an module or namespace export modifier like
5624         * "exports." when emitted as an expression.
5625         *
5626         * @param node The declaration.
5627         * @param allowComments A value indicating whether comments may be emitted for the name.
5628         * @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
5629         */
5630        function getLocalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) {
5631            return getName(node, allowComments, allowSourceMaps, EmitFlags.LocalName);
5632        }
5633
5634        /**
5635         * Gets the export name of a declaration. This is primarily used for declarations that can be
5636         * referred to by name in the declaration's immediate scope (classes, enums, namespaces). An
5637         * export name will *always* be prefixed with an module or namespace export modifier like
5638         * `"exports."` when emitted as an expression if the name points to an exported symbol.
5639         *
5640         * @param node The declaration.
5641         * @param allowComments A value indicating whether comments may be emitted for the name.
5642         * @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
5643         */
5644        function getExportName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier {
5645            return getName(node, allowComments, allowSourceMaps, EmitFlags.ExportName);
5646        }
5647
5648        /**
5649         * Gets the name of a declaration for use in declarations.
5650         *
5651         * @param node The declaration.
5652         * @param allowComments A value indicating whether comments may be emitted for the name.
5653         * @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
5654         */
5655        function getDeclarationName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) {
5656            return getName(node, allowComments, allowSourceMaps);
5657        }
5658
5659        /**
5660         * Gets a namespace-qualified name for use in expressions.
5661         *
5662         * @param ns The namespace identifier.
5663         * @param name The name.
5664         * @param allowComments A value indicating whether comments may be emitted for the name.
5665         * @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
5666         */
5667        function getNamespaceMemberName(ns: Identifier, name: Identifier, allowComments?: boolean, allowSourceMaps?: boolean): PropertyAccessExpression {
5668            const qualifiedName = createPropertyAccessExpression(ns, nodeIsSynthesized(name) ? name : cloneNode(name));
5669            setTextRange(qualifiedName, name);
5670            let emitFlags: EmitFlags = 0;
5671            if (!allowSourceMaps) emitFlags |= EmitFlags.NoSourceMap;
5672            if (!allowComments) emitFlags |= EmitFlags.NoComments;
5673            if (emitFlags) setEmitFlags(qualifiedName, emitFlags);
5674            return qualifiedName;
5675        }
5676
5677        /**
5678         * Gets the exported name of a declaration for use in expressions.
5679         *
5680         * An exported name will *always* be prefixed with an module or namespace export modifier like
5681         * "exports." if the name points to an exported symbol.
5682         *
5683         * @param ns The namespace identifier.
5684         * @param node The declaration.
5685         * @param allowComments A value indicating whether comments may be emitted for the name.
5686         * @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
5687         */
5688        function getExternalModuleOrNamespaceExportName(ns: Identifier | undefined, node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier | PropertyAccessExpression {
5689            if (ns && hasSyntacticModifier(node, ModifierFlags.Export)) {
5690                return getNamespaceMemberName(ns, getName(node), allowComments, allowSourceMaps);
5691            }
5692            return getExportName(node, allowComments, allowSourceMaps);
5693        }
5694
5695        /**
5696         * Copies any necessary standard and custom prologue-directives into target array.
5697         * @param source origin statements array
5698         * @param target result statements array
5699         * @param ensureUseStrict boolean determining whether the function need to add prologue-directives
5700         * @param visitor Optional callback used to visit any custom prologue directives.
5701         */
5702        function copyPrologue(source: readonly Statement[], target: Push<Statement>, ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult<Node>): number {
5703            const offset = copyStandardPrologue(source, target, ensureUseStrict);
5704            return copyCustomPrologue(source, target, offset, visitor);
5705        }
5706
5707        function isUseStrictPrologue(node: ExpressionStatement): boolean {
5708            return isStringLiteral(node.expression) && node.expression.text === "use strict";
5709        }
5710
5711        function createUseStrictPrologue() {
5712            return startOnNewLine(createExpressionStatement(createStringLiteral("use strict"))) as PrologueDirective;
5713        }
5714
5715        /**
5716         * Copies only the standard (string-expression) prologue-directives into the target statement-array.
5717         * @param source origin statements array
5718         * @param target result statements array
5719         * @param ensureUseStrict boolean determining whether the function need to add prologue-directives
5720         */
5721        function copyStandardPrologue(source: readonly Statement[], target: Push<Statement>, ensureUseStrict?: boolean): number {
5722            Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array");
5723            let foundUseStrict = false;
5724            let statementOffset = 0;
5725            const numStatements = source.length;
5726            while (statementOffset < numStatements) {
5727                const statement = source[statementOffset];
5728                if (isPrologueDirective(statement)) {
5729                    if (isUseStrictPrologue(statement)) {
5730                        foundUseStrict = true;
5731                    }
5732                    target.push(statement);
5733                }
5734                else {
5735                    break;
5736                }
5737                statementOffset++;
5738            }
5739            if (ensureUseStrict && !foundUseStrict) {
5740                target.push(createUseStrictPrologue());
5741            }
5742            return statementOffset;
5743        }
5744
5745        /**
5746         * Copies only the custom prologue-directives into target statement-array.
5747         * @param source origin statements array
5748         * @param target result statements array
5749         * @param statementOffset The offset at which to begin the copy.
5750         * @param visitor Optional callback used to visit any custom prologue directives.
5751         */
5752        function copyCustomPrologue(source: readonly Statement[], target: Push<Statement>, statementOffset: number, visitor?: (node: Node) => VisitResult<Node>, filter?: (node: Node) => boolean): number;
5753        function copyCustomPrologue(source: readonly Statement[], target: Push<Statement>, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult<Node>, filter?: (node: Node) => boolean): number | undefined;
5754        function copyCustomPrologue(source: readonly Statement[], target: Push<Statement>, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult<Node>, filter: (node: Node) => boolean = returnTrue): number | undefined {
5755            const numStatements = source.length;
5756            while (statementOffset !== undefined && statementOffset < numStatements) {
5757                const statement = source[statementOffset];
5758                if (getEmitFlags(statement) & EmitFlags.CustomPrologue && filter(statement)) {
5759                    append(target, visitor ? visitNode(statement, visitor, isStatement) : statement);
5760                }
5761                else {
5762                    break;
5763                }
5764                statementOffset++;
5765            }
5766            return statementOffset;
5767        }
5768
5769        /**
5770         * Ensures "use strict" directive is added
5771         *
5772         * @param statements An array of statements
5773         */
5774        function ensureUseStrict(statements: NodeArray<Statement>): NodeArray<Statement> {
5775            const foundUseStrict = findUseStrictPrologue(statements);
5776
5777            if (!foundUseStrict) {
5778                return setTextRange(createNodeArray<Statement>([createUseStrictPrologue(), ...statements]), statements);
5779            }
5780
5781            return statements;
5782        }
5783
5784        /**
5785         * Lifts a NodeArray containing only Statement nodes to a block.
5786         *
5787         * @param nodes The NodeArray.
5788         */
5789        function liftToBlock(nodes: readonly Node[]): Statement {
5790            Debug.assert(every(nodes, isStatementOrBlock), "Cannot lift nodes to a Block.");
5791            return <Statement>singleOrUndefined(nodes) || createBlock(<readonly Statement[]>nodes);
5792        }
5793
5794        function findSpanEnd<T>(array: readonly T[], test: (value: T) => boolean, start: number) {
5795            let i = start;
5796            while (i < array.length && test(array[i])) {
5797                i++;
5798            }
5799            return i;
5800        }
5801
5802        function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: readonly Statement[] | undefined): NodeArray<Statement>;
5803        function mergeLexicalEnvironment(statements: Statement[], declarations: readonly Statement[] | undefined): Statement[];
5804        function mergeLexicalEnvironment(statements: Statement[] | NodeArray<Statement>, declarations: readonly Statement[] | undefined) {
5805            if (!some(declarations)) {
5806                return statements;
5807            }
5808
5809            // When we merge new lexical statements into an existing statement list, we merge them in the following manner:
5810            //
5811            // Given:
5812            //
5813            // | Left                               | Right                               |
5814            // |------------------------------------|-------------------------------------|
5815            // | [standard prologues (left)]        | [standard prologues (right)]        |
5816            // | [hoisted functions (left)]         | [hoisted functions (right)]         |
5817            // | [hoisted variables (left)]         | [hoisted variables (right)]         |
5818            // | [lexical init statements (left)]   | [lexical init statements (right)]   |
5819            // | [other statements (left)]          |                                     |
5820            //
5821            // The resulting statement list will be:
5822            //
5823            // | Result                              |
5824            // |-------------------------------------|
5825            // | [standard prologues (right)]        |
5826            // | [standard prologues (left)]         |
5827            // | [hoisted functions (right)]         |
5828            // | [hoisted functions (left)]          |
5829            // | [hoisted variables (right)]         |
5830            // | [hoisted variables (left)]          |
5831            // | [lexical init statements (right)]   |
5832            // | [lexical init statements (left)]    |
5833            // | [other statements (left)]           |
5834            //
5835            // NOTE: It is expected that new lexical init statements must be evaluated before existing lexical init statements,
5836            // as the prior transformation may depend on the evaluation of the lexical init statements to be in the correct state.
5837
5838            // find standard prologues on left in the following order: standard directives, hoisted functions, hoisted variables, other custom
5839            const leftStandardPrologueEnd = findSpanEnd(statements, isPrologueDirective, 0);
5840            const leftHoistedFunctionsEnd = findSpanEnd(statements, isHoistedFunction, leftStandardPrologueEnd);
5841            const leftHoistedVariablesEnd = findSpanEnd(statements, isHoistedVariableStatement, leftHoistedFunctionsEnd);
5842
5843            // find standard prologues on right in the following order: standard directives, hoisted functions, hoisted variables, other custom
5844            const rightStandardPrologueEnd = findSpanEnd(declarations, isPrologueDirective, 0);
5845            const rightHoistedFunctionsEnd = findSpanEnd(declarations, isHoistedFunction, rightStandardPrologueEnd);
5846            const rightHoistedVariablesEnd = findSpanEnd(declarations, isHoistedVariableStatement, rightHoistedFunctionsEnd);
5847            const rightCustomPrologueEnd = findSpanEnd(declarations, isCustomPrologue, rightHoistedVariablesEnd);
5848            Debug.assert(rightCustomPrologueEnd === declarations.length, "Expected declarations to be valid standard or custom prologues");
5849
5850            // splice prologues from the right into the left. We do this in reverse order
5851            // so that we don't need to recompute the index on the left when we insert items.
5852            const left = isNodeArray(statements) ? statements.slice() : statements;
5853
5854            // splice other custom prologues from right into left
5855            if (rightCustomPrologueEnd > rightHoistedVariablesEnd) {
5856                left.splice(leftHoistedVariablesEnd, 0, ...declarations.slice(rightHoistedVariablesEnd, rightCustomPrologueEnd));
5857            }
5858
5859            // splice hoisted variables from right into left
5860            if (rightHoistedVariablesEnd > rightHoistedFunctionsEnd) {
5861                left.splice(leftHoistedFunctionsEnd, 0, ...declarations.slice(rightHoistedFunctionsEnd, rightHoistedVariablesEnd));
5862            }
5863
5864            // splice hoisted functions from right into left
5865            if (rightHoistedFunctionsEnd > rightStandardPrologueEnd) {
5866                left.splice(leftStandardPrologueEnd, 0, ...declarations.slice(rightStandardPrologueEnd, rightHoistedFunctionsEnd));
5867            }
5868
5869            // splice standard prologues from right into left (that are not already in left)
5870            if (rightStandardPrologueEnd > 0) {
5871                if (leftStandardPrologueEnd === 0) {
5872                    left.splice(0, 0, ...declarations.slice(0, rightStandardPrologueEnd));
5873                }
5874                else {
5875                    const leftPrologues = new Map<string, boolean>();
5876                    for (let i = 0; i < leftStandardPrologueEnd; i++) {
5877                        const leftPrologue = statements[i] as PrologueDirective;
5878                        leftPrologues.set(leftPrologue.expression.text, true);
5879                    }
5880                    for (let i = rightStandardPrologueEnd - 1; i >= 0; i--) {
5881                        const rightPrologue = declarations[i] as PrologueDirective;
5882                        if (!leftPrologues.has(rightPrologue.expression.text)) {
5883                            left.unshift(rightPrologue);
5884                        }
5885                    }
5886                }
5887            }
5888
5889            if (isNodeArray(statements)) {
5890                return setTextRange(createNodeArray(left, statements.hasTrailingComma), statements);
5891            }
5892
5893            return statements;
5894        }
5895
5896        function updateModifiers<T extends HasModifiers>(node: T, modifiers: readonly Modifier[] | ModifierFlags): T;
5897        function updateModifiers(node: HasModifiers, modifiers: readonly Modifier[] | ModifierFlags) {
5898            if (typeof modifiers === "number") {
5899                modifiers = createModifiersFromModifierFlags(modifiers);
5900            }
5901            return isParameter(node) ? updateParameterDeclaration(node, node.decorators, modifiers, node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer) :
5902                isPropertySignature(node) ? updatePropertySignature(node, modifiers, node.name, node.questionToken, node.type) :
5903                isPropertyDeclaration(node) ? updatePropertyDeclaration(node, node.decorators, modifiers, node.name, node.questionToken ?? node.exclamationToken, node.type, node.initializer) :
5904                isMethodSignature(node) ? updateMethodSignature(node, modifiers, node.name, node.questionToken, node.typeParameters, node.parameters, node.type) :
5905                isMethodDeclaration(node) ? updateMethodDeclaration(node, node.decorators, modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, node.body) :
5906                isConstructorDeclaration(node) ? updateConstructorDeclaration(node, node.decorators, modifiers, node.parameters, node.body) :
5907                isGetAccessorDeclaration(node) ? updateGetAccessorDeclaration(node, node.decorators, modifiers, node.name, node.parameters, node.type, node.body) :
5908                isSetAccessorDeclaration(node) ? updateSetAccessorDeclaration(node, node.decorators, modifiers, node.name, node.parameters, node.body) :
5909                isIndexSignatureDeclaration(node) ? updateIndexSignature(node, node.decorators, modifiers, node.parameters, node.type) :
5910                isFunctionExpression(node) ? updateFunctionExpression(node, modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) :
5911                isArrowFunction(node) ? updateArrowFunction(node, modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, node.body) :
5912                isClassExpression(node) ? updateClassExpression(node, node.decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members) :
5913                isVariableStatement(node) ? updateVariableStatement(node, modifiers, node.declarationList) :
5914                isFunctionDeclaration(node) ? updateFunctionDeclaration(node, node.decorators, modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) :
5915                isClassDeclaration(node) ? updateClassDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members) :
5916                isStructDeclaration(node) ? updateStructDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members) :
5917                isInterfaceDeclaration(node) ? updateInterfaceDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members) :
5918                isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.type) :
5919                isEnumDeclaration(node) ? updateEnumDeclaration(node, node.decorators, modifiers, node.name, node.members) :
5920                isModuleDeclaration(node) ? updateModuleDeclaration(node, node.decorators, modifiers, node.name, node.body) :
5921                isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, node.decorators, modifiers, node.isTypeOnly, node.name, node.moduleReference) :
5922                isImportDeclaration(node) ? updateImportDeclaration(node, node.decorators, modifiers, node.importClause, node.moduleSpecifier) :
5923                isExportAssignment(node) ? updateExportAssignment(node, node.decorators, modifiers, node.expression) :
5924                isExportDeclaration(node) ? updateExportDeclaration(node, node.decorators, modifiers, node.isTypeOnly, node.exportClause, node.moduleSpecifier) :
5925                Debug.assertNever(node);
5926        }
5927
5928        function asNodeArray<T extends Node>(array: readonly T[]): NodeArray<T>;
5929        function asNodeArray<T extends Node>(array: readonly T[] | undefined): NodeArray<T> | undefined;
5930        function asNodeArray<T extends Node>(array: readonly T[] | undefined): NodeArray<T> | undefined {
5931            return array ? createNodeArray(array) : undefined;
5932        }
5933
5934        function asName<T extends DeclarationName | Identifier | BindingName | PropertyName | NoSubstitutionTemplateLiteral | EntityName | ThisTypeNode | undefined>(name: string | T): T | Identifier {
5935            return typeof name === "string" ? createIdentifier(name) :
5936                name;
5937        }
5938
5939        function asExpression<T extends Expression | undefined>(value: string | number | boolean | T): T | StringLiteral | NumericLiteral | BooleanLiteral {
5940            return typeof value === "string" ? createStringLiteral(value) :
5941                typeof value === "number" ? createNumericLiteral(value) :
5942                typeof value === "boolean" ? value ? createTrue() : createFalse() :
5943                value;
5944        }
5945
5946        function asToken<TKind extends SyntaxKind>(value: TKind | Token<TKind>): Token<TKind> {
5947            return typeof value === "number" ? createToken(value) : value;
5948        }
5949
5950        function asEmbeddedStatement<T extends Node>(statement: T): T | EmptyStatement;
5951        function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined;
5952        function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined {
5953            return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement;
5954        }
5955    }
5956
5957    function updateWithoutOriginal<T extends Node>(updated: T, original: T): T {
5958        if (updated !== original) {
5959            setTextRange(updated, original);
5960        }
5961        return updated;
5962    }
5963
5964    function updateWithOriginal<T extends Node>(updated: T, original: T): T {
5965        if (updated !== original) {
5966            setOriginalNode(updated, original);
5967            setTextRange(updated, original);
5968        }
5969        return updated;
5970    }
5971
5972    function getDefaultTagNameForKind(kind: JSDocTag["kind"]): string {
5973        switch (kind) {
5974            case SyntaxKind.JSDocTypeTag: return "type";
5975            case SyntaxKind.JSDocReturnTag: return "returns";
5976            case SyntaxKind.JSDocThisTag: return "this";
5977            case SyntaxKind.JSDocEnumTag: return "enum";
5978            case SyntaxKind.JSDocAuthorTag: return "author";
5979            case SyntaxKind.JSDocClassTag: return "class";
5980            case SyntaxKind.JSDocPublicTag: return "public";
5981            case SyntaxKind.JSDocPrivateTag: return "private";
5982            case SyntaxKind.JSDocProtectedTag: return "protected";
5983            case SyntaxKind.JSDocReadonlyTag: return "readonly";
5984            case SyntaxKind.JSDocTemplateTag: return "template";
5985            case SyntaxKind.JSDocTypedefTag: return "typedef";
5986            case SyntaxKind.JSDocParameterTag: return "param";
5987            case SyntaxKind.JSDocPropertyTag: return "prop";
5988            case SyntaxKind.JSDocCallbackTag: return "callback";
5989            case SyntaxKind.JSDocAugmentsTag: return "augments";
5990            case SyntaxKind.JSDocImplementsTag: return "implements";
5991            default:
5992                return Debug.fail(`Unsupported kind: ${Debug.formatSyntaxKind(kind)}`);
5993        }
5994    }
5995
5996    let rawTextScanner: Scanner | undefined;
5997    const invalidValueSentinel: object = { };
5998
5999    function getCookedText(kind: TemplateLiteralToken["kind"], rawText: string) {
6000        if (!rawTextScanner) {
6001            rawTextScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.Standard);
6002        }
6003        switch (kind) {
6004            case SyntaxKind.NoSubstitutionTemplateLiteral:
6005                rawTextScanner.setText("`" + rawText + "`");
6006                break;
6007            case SyntaxKind.TemplateHead:
6008                // tslint:disable-next-line no-invalid-template-strings
6009                rawTextScanner.setText("`" + rawText + "${");
6010                break;
6011            case SyntaxKind.TemplateMiddle:
6012                // tslint:disable-next-line no-invalid-template-strings
6013                rawTextScanner.setText("}" + rawText + "${");
6014                break;
6015            case SyntaxKind.TemplateTail:
6016                rawTextScanner.setText("}" + rawText + "`");
6017                break;
6018        }
6019
6020        let token = rawTextScanner.scan();
6021        if (token === SyntaxKind.CloseBracketToken) {
6022            token = rawTextScanner.reScanTemplateToken(/*isTaggedTemplate*/ false);
6023        }
6024
6025        if (rawTextScanner.isUnterminated()) {
6026            rawTextScanner.setText(undefined);
6027            return invalidValueSentinel;
6028        }
6029
6030        let tokenValue: string | undefined;
6031        switch (token) {
6032            case SyntaxKind.NoSubstitutionTemplateLiteral:
6033            case SyntaxKind.TemplateHead:
6034            case SyntaxKind.TemplateMiddle:
6035            case SyntaxKind.TemplateTail:
6036                tokenValue = rawTextScanner.getTokenValue();
6037                break;
6038        }
6039
6040        if (tokenValue === undefined || rawTextScanner.scan() !== SyntaxKind.EndOfFileToken) {
6041            rawTextScanner.setText(undefined);
6042            return invalidValueSentinel;
6043        }
6044
6045        rawTextScanner.setText(undefined);
6046        return tokenValue;
6047    }
6048
6049    function propagateIdentifierNameFlags(node: Identifier) {
6050        // An IdentifierName is allowed to be `await`
6051        return propagateChildFlags(node) & ~TransformFlags.ContainsPossibleTopLevelAwait;
6052    }
6053
6054    function propagatePropertyNameFlagsOfChild(node: PropertyName, transformFlags: TransformFlags) {
6055        return transformFlags | (node.transformFlags & TransformFlags.PropertyNamePropagatingFlags);
6056    }
6057
6058    function propagateChildFlags(child: Node | undefined): TransformFlags {
6059        if (!child) return TransformFlags.None;
6060        const childFlags = child.transformFlags & ~getTransformFlagsSubtreeExclusions(child.kind);
6061        return isNamedDeclaration(child) && isPropertyName(child.name) ? propagatePropertyNameFlagsOfChild(child.name, childFlags) : childFlags;
6062    }
6063
6064    function propagateChildrenFlags(children: NodeArray<Node> | undefined): TransformFlags {
6065        return children ? children.transformFlags : TransformFlags.None;
6066    }
6067
6068    function aggregateChildrenFlags(children: MutableNodeArray<Node>) {
6069        let subtreeFlags = TransformFlags.None;
6070        for (const child of children) {
6071            subtreeFlags |= propagateChildFlags(child);
6072        }
6073        children.transformFlags = subtreeFlags;
6074    }
6075
6076    /**
6077     * Gets the transform flags to exclude when unioning the transform flags of a subtree.
6078     */
6079    /* @internal */
6080    export function getTransformFlagsSubtreeExclusions(kind: SyntaxKind) {
6081        if (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) {
6082            return TransformFlags.TypeExcludes;
6083        }
6084
6085        switch (kind) {
6086            case SyntaxKind.CallExpression:
6087            case SyntaxKind.NewExpression:
6088            case SyntaxKind.ArrayLiteralExpression:
6089                return TransformFlags.ArrayLiteralOrCallOrNewExcludes;
6090            case SyntaxKind.ModuleDeclaration:
6091                return TransformFlags.ModuleExcludes;
6092            case SyntaxKind.Parameter:
6093                return TransformFlags.ParameterExcludes;
6094            case SyntaxKind.ArrowFunction:
6095                return TransformFlags.ArrowFunctionExcludes;
6096            case SyntaxKind.FunctionExpression:
6097            case SyntaxKind.FunctionDeclaration:
6098                return TransformFlags.FunctionExcludes;
6099            case SyntaxKind.VariableDeclarationList:
6100                return TransformFlags.VariableDeclarationListExcludes;
6101            case SyntaxKind.ClassDeclaration:
6102            case SyntaxKind.ClassExpression:
6103                return TransformFlags.ClassExcludes;
6104            case SyntaxKind.Constructor:
6105                return TransformFlags.ConstructorExcludes;
6106            case SyntaxKind.PropertyDeclaration:
6107                return TransformFlags.PropertyExcludes;
6108            case SyntaxKind.MethodDeclaration:
6109            case SyntaxKind.GetAccessor:
6110            case SyntaxKind.SetAccessor:
6111                return TransformFlags.MethodOrAccessorExcludes;
6112            case SyntaxKind.AnyKeyword:
6113            case SyntaxKind.NumberKeyword:
6114            case SyntaxKind.BigIntKeyword:
6115            case SyntaxKind.NeverKeyword:
6116            case SyntaxKind.StringKeyword:
6117            case SyntaxKind.ObjectKeyword:
6118            case SyntaxKind.BooleanKeyword:
6119            case SyntaxKind.SymbolKeyword:
6120            case SyntaxKind.VoidKeyword:
6121            case SyntaxKind.TypeParameter:
6122            case SyntaxKind.PropertySignature:
6123            case SyntaxKind.MethodSignature:
6124            case SyntaxKind.CallSignature:
6125            case SyntaxKind.ConstructSignature:
6126            case SyntaxKind.IndexSignature:
6127            case SyntaxKind.InterfaceDeclaration:
6128            case SyntaxKind.TypeAliasDeclaration:
6129                return TransformFlags.TypeExcludes;
6130            case SyntaxKind.ObjectLiteralExpression:
6131                return TransformFlags.ObjectLiteralExcludes;
6132            case SyntaxKind.CatchClause:
6133                return TransformFlags.CatchClauseExcludes;
6134            case SyntaxKind.ObjectBindingPattern:
6135            case SyntaxKind.ArrayBindingPattern:
6136                return TransformFlags.BindingPatternExcludes;
6137            case SyntaxKind.TypeAssertionExpression:
6138            case SyntaxKind.AsExpression:
6139            case SyntaxKind.PartiallyEmittedExpression:
6140            case SyntaxKind.ParenthesizedExpression:
6141            case SyntaxKind.SuperKeyword:
6142                return TransformFlags.OuterExpressionExcludes;
6143            case SyntaxKind.PropertyAccessExpression:
6144            case SyntaxKind.ElementAccessExpression:
6145                return TransformFlags.PropertyAccessExcludes;
6146            default:
6147                return TransformFlags.NodeExcludes;
6148        }
6149    }
6150
6151    const baseFactory = createBaseNodeFactory();
6152
6153    function makeSynthetic(node: Node) {
6154        (node as Mutable<Node>).flags |= NodeFlags.Synthesized;
6155        return node;
6156    }
6157
6158    const syntheticFactory: BaseNodeFactory = {
6159        createBaseSourceFileNode: kind => makeSynthetic(baseFactory.createBaseSourceFileNode(kind)),
6160        createBaseIdentifierNode: kind => makeSynthetic(baseFactory.createBaseIdentifierNode(kind)),
6161        createBasePrivateIdentifierNode: kind => makeSynthetic(baseFactory.createBasePrivateIdentifierNode(kind)),
6162        createBaseTokenNode: kind => makeSynthetic(baseFactory.createBaseTokenNode(kind)),
6163        createBaseNode: kind => makeSynthetic(baseFactory.createBaseNode(kind)),
6164    };
6165
6166    export const factory = createNodeFactory(NodeFactoryFlags.NoIndentationOnFreshPropertyAccess, syntheticFactory);
6167
6168    export function createUnparsedSourceFile(text: string): UnparsedSource;
6169    export function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts", stripInternal?: boolean): UnparsedSource;
6170    export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource;
6171    export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, mapPathOrType?: string, mapTextOrStripInternal?: string | boolean): UnparsedSource {
6172        let stripInternal: boolean | undefined;
6173        let bundleFileInfo: BundleFileInfo | undefined;
6174        let fileName: string;
6175        let text: string | undefined;
6176        let length: number | (() => number);
6177        let sourceMapPath: string | undefined;
6178        let sourceMapText: string | undefined;
6179        let getText: (() => string) | undefined;
6180        let getSourceMapText: (() => string | undefined) | undefined;
6181        let oldFileOfCurrentEmit: boolean | undefined;
6182
6183        if (!isString(textOrInputFiles)) {
6184            Debug.assert(mapPathOrType === "js" || mapPathOrType === "dts");
6185            fileName = (mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath) || "";
6186            sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath : textOrInputFiles.declarationMapPath;
6187            getText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptText : textOrInputFiles.declarationText;
6188            getSourceMapText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText;
6189            length = () => getText!().length;
6190            if (textOrInputFiles.buildInfo && textOrInputFiles.buildInfo.bundle) {
6191                Debug.assert(mapTextOrStripInternal === undefined || typeof mapTextOrStripInternal === "boolean");
6192                stripInternal = mapTextOrStripInternal;
6193                bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js : textOrInputFiles.buildInfo.bundle.dts;
6194                oldFileOfCurrentEmit = textOrInputFiles.oldFileOfCurrentEmit;
6195            }
6196        }
6197        else {
6198            fileName = "";
6199            text = textOrInputFiles;
6200            length = textOrInputFiles.length;
6201            sourceMapPath = mapPathOrType;
6202            sourceMapText = mapTextOrStripInternal as string;
6203        }
6204        const node = oldFileOfCurrentEmit ?
6205            parseOldFileOfCurrentEmit(Debug.assertDefined(bundleFileInfo)) :
6206            parseUnparsedSourceFile(bundleFileInfo, stripInternal, length);
6207        node.fileName = fileName;
6208        node.sourceMapPath = sourceMapPath;
6209        node.oldFileOfCurrentEmit = oldFileOfCurrentEmit;
6210        if (getText && getSourceMapText) {
6211            Object.defineProperty(node, "text", { get: getText });
6212            Object.defineProperty(node, "sourceMapText", { get: getSourceMapText });
6213        }
6214        else {
6215            Debug.assert(!oldFileOfCurrentEmit);
6216            node.text = text ?? "";
6217            node.sourceMapText = sourceMapText;
6218        }
6219
6220        return node;
6221    }
6222
6223    function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, stripInternal: boolean | undefined, length: number | (() => number)) {
6224        let prologues: UnparsedPrologue[] | undefined;
6225        let helpers: UnscopedEmitHelper[] | undefined;
6226        let referencedFiles: FileReference[] | undefined;
6227        let typeReferenceDirectives: string[] | undefined;
6228        let libReferenceDirectives: FileReference[] | undefined;
6229        let prependChildren: UnparsedTextLike[] | undefined;
6230        let texts: UnparsedSourceText[] | undefined;
6231        let hasNoDefaultLib: boolean | undefined;
6232
6233        for (const section of bundleFileInfo ? bundleFileInfo.sections : emptyArray) {
6234            switch (section.kind) {
6235                case BundleFileSectionKind.Prologue:
6236                    prologues = append(prologues, setTextRange(factory.createUnparsedPrologue(section.data), section));
6237                    break;
6238                case BundleFileSectionKind.EmitHelpers:
6239                    helpers = append(helpers, getAllUnscopedEmitHelpers().get(section.data)!);
6240                    break;
6241                case BundleFileSectionKind.NoDefaultLib:
6242                    hasNoDefaultLib = true;
6243                    break;
6244                case BundleFileSectionKind.Reference:
6245                    referencedFiles = append(referencedFiles, { pos: -1, end: -1, fileName: section.data });
6246                    break;
6247                case BundleFileSectionKind.Type:
6248                    typeReferenceDirectives = append(typeReferenceDirectives, section.data);
6249                    break;
6250                case BundleFileSectionKind.Lib:
6251                    libReferenceDirectives = append(libReferenceDirectives, { pos: -1, end: -1, fileName: section.data });
6252                    break;
6253                case BundleFileSectionKind.Prepend:
6254                    let prependTexts: UnparsedTextLike[] | undefined;
6255                    for (const text of section.texts) {
6256                        if (!stripInternal || text.kind !== BundleFileSectionKind.Internal) {
6257                            prependTexts = append(prependTexts, setTextRange(factory.createUnparsedTextLike(text.data, text.kind === BundleFileSectionKind.Internal), text));
6258                        }
6259                    }
6260                    prependChildren = addRange(prependChildren, prependTexts);
6261                    texts = append(texts, factory.createUnparsedPrepend(section.data, prependTexts ?? emptyArray));
6262                    break;
6263                case BundleFileSectionKind.Internal:
6264                    if (stripInternal) {
6265                        if (!texts) texts = [];
6266                        break;
6267                    }
6268                    // falls through
6269
6270                case BundleFileSectionKind.Text:
6271                    texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section));
6272                    break;
6273                default:
6274                    Debug.assertNever(section);
6275            }
6276        }
6277
6278        if (!texts) {
6279            const textNode = factory.createUnparsedTextLike(/*data*/ undefined, /*internal*/ false);
6280            setTextRangePosWidth(textNode, 0, typeof length === "function" ? length() : length);
6281            texts = [textNode];
6282        }
6283
6284        const node = parseNodeFactory.createUnparsedSource(prologues ?? emptyArray, /*syntheticReferences*/ undefined, texts);
6285        setEachParent(prologues, node);
6286        setEachParent(texts, node);
6287        setEachParent(prependChildren, node);
6288        node.hasNoDefaultLib = hasNoDefaultLib;
6289        node.helpers = helpers;
6290        node.referencedFiles = referencedFiles || emptyArray;
6291        node.typeReferenceDirectives = typeReferenceDirectives;
6292        node.libReferenceDirectives = libReferenceDirectives || emptyArray;
6293        return node;
6294    }
6295
6296    function parseOldFileOfCurrentEmit(bundleFileInfo: BundleFileInfo) {
6297        let texts: UnparsedTextLike[] | undefined;
6298        let syntheticReferences: UnparsedSyntheticReference[] | undefined;
6299        for (const section of bundleFileInfo.sections) {
6300            switch (section.kind) {
6301                case BundleFileSectionKind.Internal:
6302                case BundleFileSectionKind.Text:
6303                    texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section));
6304                    break;
6305
6306                case BundleFileSectionKind.NoDefaultLib:
6307                case BundleFileSectionKind.Reference:
6308                case BundleFileSectionKind.Type:
6309                case BundleFileSectionKind.Lib:
6310                    syntheticReferences = append(syntheticReferences, setTextRange(factory.createUnparsedSyntheticReference(section), section));
6311                    break;
6312
6313                // Ignore
6314                case BundleFileSectionKind.Prologue:
6315                case BundleFileSectionKind.EmitHelpers:
6316                case BundleFileSectionKind.Prepend:
6317                    break;
6318
6319                default:
6320                    Debug.assertNever(section);
6321            }
6322        }
6323
6324        const node = factory.createUnparsedSource(emptyArray, syntheticReferences, texts ?? emptyArray);
6325        setEachParent(syntheticReferences, node);
6326        setEachParent(texts, node);
6327        node.helpers = map(bundleFileInfo.sources && bundleFileInfo.sources.helpers, name => getAllUnscopedEmitHelpers().get(name)!);
6328        return node;
6329    }
6330
6331    // TODO(rbuckton): Move part of this to factory
6332    export function createInputFiles(
6333        javascriptText: string,
6334        declarationText: string
6335    ): InputFiles;
6336    export function createInputFiles(
6337        readFileText: (path: string) => string | undefined,
6338        javascriptPath: string,
6339        javascriptMapPath: string | undefined,
6340        declarationPath: string,
6341        declarationMapPath: string | undefined,
6342        buildInfoPath: string | undefined
6343    ): InputFiles;
6344    export function createInputFiles(
6345        javascriptText: string,
6346        declarationText: string,
6347        javascriptMapPath: string | undefined,
6348        javascriptMapText: string | undefined,
6349        declarationMapPath: string | undefined,
6350        declarationMapText: string | undefined
6351    ): InputFiles;
6352    /*@internal*/
6353    export function createInputFiles(
6354        javascriptText: string,
6355        declarationText: string,
6356        javascriptMapPath: string | undefined,
6357        javascriptMapText: string | undefined,
6358        declarationMapPath: string | undefined,
6359        declarationMapText: string | undefined,
6360        javascriptPath: string | undefined,
6361        declarationPath: string | undefined,
6362        buildInfoPath?: string | undefined,
6363        buildInfo?: BuildInfo,
6364        oldFileOfCurrentEmit?: boolean
6365    ): InputFiles;
6366    export function createInputFiles(
6367        javascriptTextOrReadFileText: string | ((path: string) => string | undefined),
6368        declarationTextOrJavascriptPath: string,
6369        javascriptMapPath?: string,
6370        javascriptMapTextOrDeclarationPath?: string,
6371        declarationMapPath?: string,
6372        declarationMapTextOrBuildInfoPath?: string,
6373        javascriptPath?: string | undefined,
6374        declarationPath?: string | undefined,
6375        buildInfoPath?: string | undefined,
6376        buildInfo?: BuildInfo,
6377        oldFileOfCurrentEmit?: boolean
6378    ): InputFiles {
6379        const node = parseNodeFactory.createInputFiles();
6380        if (!isString(javascriptTextOrReadFileText)) {
6381            const cache = new Map<string, string | false>();
6382            const textGetter = (path: string | undefined) => {
6383                if (path === undefined) return undefined;
6384                let value = cache.get(path);
6385                if (value === undefined) {
6386                    value = javascriptTextOrReadFileText(path);
6387                    cache.set(path, value !== undefined ? value : false);
6388                }
6389                return value !== false ? value as string : undefined;
6390            };
6391            const definedTextGetter = (path: string) => {
6392                const result = textGetter(path);
6393                return result !== undefined ? result : `/* Input file ${path} was missing */\r\n`;
6394            };
6395            let buildInfo: BuildInfo | false;
6396            const getAndCacheBuildInfo = (getText: () => string | undefined) => {
6397                if (buildInfo === undefined) {
6398                    const result = getText();
6399                    buildInfo = result !== undefined ? getBuildInfo(result) : false;
6400                }
6401                return buildInfo || undefined;
6402            };
6403            node.javascriptPath = declarationTextOrJavascriptPath;
6404            node.javascriptMapPath = javascriptMapPath;
6405            node.declarationPath = Debug.assertDefined(javascriptMapTextOrDeclarationPath);
6406            node.declarationMapPath = declarationMapPath;
6407            node.buildInfoPath = declarationMapTextOrBuildInfoPath;
6408            Object.defineProperties(node, {
6409                javascriptText: { get() { return definedTextGetter(declarationTextOrJavascriptPath); } },
6410                javascriptMapText: { get() { return textGetter(javascriptMapPath); } }, // TODO:: if there is inline sourceMap in jsFile, use that
6411                declarationText: { get() { return definedTextGetter(Debug.assertDefined(javascriptMapTextOrDeclarationPath)); } },
6412                declarationMapText: { get() { return textGetter(declarationMapPath); } }, // TODO:: if there is inline sourceMap in dtsFile, use that
6413                buildInfo: { get() { return getAndCacheBuildInfo(() => textGetter(declarationMapTextOrBuildInfoPath)); } }
6414            });
6415        }
6416        else {
6417            node.javascriptText = javascriptTextOrReadFileText;
6418            node.javascriptMapPath = javascriptMapPath;
6419            node.javascriptMapText = javascriptMapTextOrDeclarationPath;
6420            node.declarationText = declarationTextOrJavascriptPath;
6421            node.declarationMapPath = declarationMapPath;
6422            node.declarationMapText = declarationMapTextOrBuildInfoPath;
6423            node.javascriptPath = javascriptPath;
6424            node.declarationPath = declarationPath;
6425            node.buildInfoPath = buildInfoPath;
6426            node.buildInfo = buildInfo;
6427            node.oldFileOfCurrentEmit = oldFileOfCurrentEmit;
6428        }
6429        return node;
6430    }
6431
6432    // tslint:disable-next-line variable-name
6433    let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource;
6434
6435    /**
6436     * Create an external source map source file reference
6437     */
6438    export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource {
6439        return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia);
6440    }
6441
6442    // Utilities
6443
6444    export function setOriginalNode<T extends Node>(node: T, original: Node | undefined): T {
6445        node.original = original;
6446        if (original) {
6447            const emitNode = original.emitNode;
6448            if (emitNode) node.emitNode = mergeEmitNode(emitNode, node.emitNode);
6449        }
6450        return node;
6451    }
6452
6453    function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode | undefined) {
6454        const {
6455            flags,
6456            leadingComments,
6457            trailingComments,
6458            commentRange,
6459            sourceMapRange,
6460            tokenSourceMapRanges,
6461            constantValue,
6462            helpers,
6463            startsOnNewLine,
6464        } = sourceEmitNode;
6465        if (!destEmitNode) destEmitNode = {} as EmitNode;
6466        // We are using `.slice()` here in case `destEmitNode.leadingComments` is pushed to later.
6467        if (leadingComments) destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments);
6468        if (trailingComments) destEmitNode.trailingComments = addRange(trailingComments.slice(), destEmitNode.trailingComments);
6469        if (flags) destEmitNode.flags = flags;
6470        if (commentRange) destEmitNode.commentRange = commentRange;
6471        if (sourceMapRange) destEmitNode.sourceMapRange = sourceMapRange;
6472        if (tokenSourceMapRanges) destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges!);
6473        if (constantValue !== undefined) destEmitNode.constantValue = constantValue;
6474        if (helpers) {
6475            for (const helper of helpers) {
6476                destEmitNode.helpers = appendIfUnique(destEmitNode.helpers, helper);
6477            }
6478        }
6479        if (startsOnNewLine !== undefined) destEmitNode.startsOnNewLine = startsOnNewLine;
6480        return destEmitNode;
6481    }
6482
6483    function mergeTokenSourceMapRanges(sourceRanges: (TextRange | undefined)[], destRanges: (TextRange | undefined)[]) {
6484        if (!destRanges) destRanges = [];
6485        for (const key in sourceRanges) {
6486            destRanges[key] = sourceRanges[key];
6487        }
6488        return destRanges;
6489    }
6490}
6491