• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    export function isExternalModuleNameRelative(moduleName: string): boolean {
3        // TypeScript 1.0 spec (April 2014): 11.2.1
4        // An external module name is "relative" if the first term is "." or "..".
5        // Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules`, `oh_modules` or treat it as an ambient module.
6        return pathIsRelative(moduleName) || isRootedDiskPath(moduleName);
7    }
8
9    export function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: readonly T[]): SortedReadonlyArray<T> {
10        return sortAndDeduplicate<T>(diagnostics, compareDiagnostics);
11    }
12
13    export function getDefaultLibFileName(options: CompilerOptions): string {
14        switch (getEmitScriptTarget(options)) {
15            case ScriptTarget.ESNext:
16                return "lib.esnext.full.d.ts";
17            case ScriptTarget.ES2022:
18                return "lib.es2022.full.d.ts";
19            case ScriptTarget.ES2021:
20                return "lib.es2021.full.d.ts";
21            case ScriptTarget.ES2020:
22                return "lib.es2020.full.d.ts";
23            case ScriptTarget.ES2019:
24                return "lib.es2019.full.d.ts";
25            case ScriptTarget.ES2018:
26                return "lib.es2018.full.d.ts";
27            case ScriptTarget.ES2017:
28                return "lib.es2017.full.d.ts";
29            case ScriptTarget.ES2016:
30                return "lib.es2016.full.d.ts";
31            case ScriptTarget.ES2015:
32                return "lib.es6.d.ts";  // We don't use lib.es2015.full.d.ts due to breaking change.
33            default:
34                return "lib.d.ts";
35        }
36    }
37
38    export function textSpanEnd(span: TextSpan) {
39        return span.start + span.length;
40    }
41
42    export function textSpanIsEmpty(span: TextSpan) {
43        return span.length === 0;
44    }
45
46    export function textSpanContainsPosition(span: TextSpan, position: number) {
47        return position >= span.start && position < textSpanEnd(span);
48    }
49
50    /* @internal */
51    export function textRangeContainsPositionInclusive(span: TextRange, position: number): boolean {
52        return position >= span.pos && position <= span.end;
53    }
54
55    // Returns true if 'span' contains 'other'.
56    export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) {
57        return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span);
58    }
59
60    export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) {
61        return textSpanOverlap(span, other) !== undefined;
62    }
63
64    export function textSpanOverlap(span1: TextSpan, span2: TextSpan): TextSpan | undefined {
65        const overlap = textSpanIntersection(span1, span2);
66        return overlap && overlap.length === 0 ? undefined : overlap;
67    }
68
69    export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) {
70        return decodedTextSpanIntersectsWith(span.start, span.length, other.start, other.length);
71    }
72
73    export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) {
74        return decodedTextSpanIntersectsWith(span.start, span.length, start, length);
75    }
76
77    export function decodedTextSpanIntersectsWith(start1: number, length1: number, start2: number, length2: number) {
78        const end1 = start1 + length1;
79        const end2 = start2 + length2;
80        return start2 <= end1 && end2 >= start1;
81    }
82
83    export function textSpanIntersectsWithPosition(span: TextSpan, position: number) {
84        return position <= textSpanEnd(span) && position >= span.start;
85    }
86
87    export function textSpanIntersection(span1: TextSpan, span2: TextSpan): TextSpan | undefined {
88        const start = Math.max(span1.start, span2.start);
89        const end = Math.min(textSpanEnd(span1), textSpanEnd(span2));
90        return start <= end ? createTextSpanFromBounds(start, end) : undefined;
91    }
92
93    export function createTextSpan(start: number, length: number): TextSpan {
94        if (start < 0) {
95            throw new Error("start < 0");
96        }
97        if (length < 0) {
98            throw new Error("length < 0");
99        }
100
101        return { start, length };
102    }
103
104    export function createTextSpanFromBounds(start: number, end: number) {
105        return createTextSpan(start, end - start);
106    }
107
108    export function textChangeRangeNewSpan(range: TextChangeRange) {
109        return createTextSpan(range.span.start, range.newLength);
110    }
111
112    export function textChangeRangeIsUnchanged(range: TextChangeRange) {
113        return textSpanIsEmpty(range.span) && range.newLength === 0;
114    }
115
116    export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange {
117        if (newLength < 0) {
118            throw new Error("newLength < 0");
119        }
120
121        return { span, newLength };
122    }
123
124    export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0); // eslint-disable-line prefer-const
125
126    /**
127     * Called to merge all the changes that occurred across several versions of a script snapshot
128     * into a single change.  i.e. if a user keeps making successive edits to a script we will
129     * have a text change from V1 to V2, V2 to V3, ..., Vn.
130     *
131     * This function will then merge those changes into a single change range valid between V1 and
132     * Vn.
133     */
134    export function collapseTextChangeRangesAcrossMultipleVersions(changes: readonly TextChangeRange[]): TextChangeRange {
135        if (changes.length === 0) {
136            return unchangedTextChangeRange;
137        }
138
139        if (changes.length === 1) {
140            return changes[0];
141        }
142
143        // We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
144        // as it makes things much easier to reason about.
145        const change0 = changes[0];
146
147        let oldStartN = change0.span.start;
148        let oldEndN = textSpanEnd(change0.span);
149        let newEndN = oldStartN + change0.newLength;
150
151        for (let i = 1; i < changes.length; i++) {
152            const nextChange = changes[i];
153
154            // Consider the following case:
155            // i.e. two edits.  The first represents the text change range { { 10, 50 }, 30 }.  i.e. The span starting
156            // at 10, with length 50 is reduced to length 30.  The second represents the text change range { { 30, 30 }, 40 }.
157            // i.e. the span starting at 30 with length 30 is increased to length 40.
158            //
159            //      0         10        20        30        40        50        60        70        80        90        100
160            //      -------------------------------------------------------------------------------------------------------
161            //                |                                                 /
162            //                |                                            /----
163            //  T1            |                                       /----
164            //                |                                  /----
165            //                |                             /----
166            //      -------------------------------------------------------------------------------------------------------
167            //                                     |                            \
168            //                                     |                               \
169            //   T2                                |                                 \
170            //                                     |                                   \
171            //                                     |                                      \
172            //      -------------------------------------------------------------------------------------------------------
173            //
174            // Merging these turns out to not be too difficult.  First, determining the new start of the change is trivial
175            // it's just the min of the old and new starts.  i.e.:
176            //
177            //      0         10        20        30        40        50        60        70        80        90        100
178            //      ------------------------------------------------------------*------------------------------------------
179            //                |                                                 /
180            //                |                                            /----
181            //  T1            |                                       /----
182            //                |                                  /----
183            //                |                             /----
184            //      ----------------------------------------$-------------------$------------------------------------------
185            //                .                    |                            \
186            //                .                    |                               \
187            //   T2           .                    |                                 \
188            //                .                    |                                   \
189            //                .                    |                                      \
190            //      ----------------------------------------------------------------------*--------------------------------
191            //
192            // (Note the dots represent the newly inferred start.
193            // Determining the new and old end is also pretty simple.  Basically it boils down to paying attention to the
194            // absolute positions at the asterisks, and the relative change between the dollar signs. Basically, we see
195            // which if the two $'s precedes the other, and we move that one forward until they line up.  in this case that
196            // means:
197            //
198            //      0         10        20        30        40        50        60        70        80        90        100
199            //      --------------------------------------------------------------------------------*----------------------
200            //                |                                                                     /
201            //                |                                                                /----
202            //  T1            |                                                           /----
203            //                |                                                      /----
204            //                |                                                 /----
205            //      ------------------------------------------------------------$------------------------------------------
206            //                .                    |                            \
207            //                .                    |                               \
208            //   T2           .                    |                                 \
209            //                .                    |                                   \
210            //                .                    |                                      \
211            //      ----------------------------------------------------------------------*--------------------------------
212            //
213            // In other words (in this case), we're recognizing that the second edit happened after where the first edit
214            // ended with a delta of 20 characters (60 - 40).  Thus, if we go back in time to where the first edit started
215            // that's the same as if we started at char 80 instead of 60.
216            //
217            // As it so happens, the same logic applies if the second edit precedes the first edit.  In that case rather
218            // than pushing the first edit forward to match the second, we'll push the second edit forward to match the
219            // first.
220            //
221            // In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
222            // semantics: { { start: 10, length: 70 }, newLength: 60 }
223            //
224            // The math then works out as follows.
225            // If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
226            // final result like so:
227            //
228            // {
229            //      oldStart3: Min(oldStart1, oldStart2),
230            //      oldEnd3: Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
231            //      newEnd3: Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
232            // }
233
234            const oldStart1 = oldStartN;
235            const oldEnd1 = oldEndN;
236            const newEnd1 = newEndN;
237
238            const oldStart2 = nextChange.span.start;
239            const oldEnd2 = textSpanEnd(nextChange.span);
240            const newEnd2 = oldStart2 + nextChange.newLength;
241
242            oldStartN = Math.min(oldStart1, oldStart2);
243            oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
244            newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
245        }
246
247        return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength*/ newEndN - oldStartN);
248    }
249
250    export function getTypeParameterOwner(d: Declaration): Declaration | undefined {
251        if (d && d.kind === SyntaxKind.TypeParameter) {
252            for (let current: Node = d; current; current = current.parent) {
253                if (isFunctionLike(current) || isClassLike(current) || current.kind === SyntaxKind.InterfaceDeclaration) {
254                    return current as Declaration;
255                }
256            }
257        }
258    }
259
260    export type ParameterPropertyDeclaration = ParameterDeclaration & { parent: ConstructorDeclaration, name: Identifier };
261    export function isParameterPropertyDeclaration(node: Node, parent: Node): node is ParameterPropertyDeclaration {
262        return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) && parent.kind === SyntaxKind.Constructor;
263    }
264
265    export function isEmptyBindingPattern(node: BindingName): node is BindingPattern {
266        if (isBindingPattern(node)) {
267            return every(node.elements, isEmptyBindingElement);
268        }
269        return false;
270    }
271
272    export function isEmptyBindingElement(node: BindingElement): boolean {
273        if (isOmittedExpression(node)) {
274            return true;
275        }
276        return isEmptyBindingPattern(node.name);
277    }
278
279    export function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration {
280        let node = binding.parent;
281        while (isBindingElement(node.parent)) {
282            node = node.parent.parent;
283        }
284        return node.parent;
285    }
286
287    function getCombinedFlags(node: Node, getFlags: (n: Node) => number): number {
288        if (isBindingElement(node)) {
289            node = walkUpBindingElementsAndPatterns(node);
290        }
291        let flags = getFlags(node);
292        if (node.kind === SyntaxKind.VariableDeclaration) {
293            node = node.parent;
294        }
295        if (node && node.kind === SyntaxKind.VariableDeclarationList) {
296            flags |= getFlags(node);
297            node = node.parent;
298        }
299        if (node && node.kind === SyntaxKind.VariableStatement) {
300            flags |= getFlags(node);
301        }
302        return flags;
303    }
304
305    export function getCombinedModifierFlags(node: Declaration): ModifierFlags {
306        return getCombinedFlags(node, getEffectiveModifierFlags);
307    }
308
309    /* @internal */
310    export function getCombinedNodeFlagsAlwaysIncludeJSDoc(node: Declaration): ModifierFlags {
311        return getCombinedFlags(node, getEffectiveModifierFlagsAlwaysIncludeJSDoc);
312    }
313
314    // Returns the node flags for this node and all relevant parent nodes.  This is done so that
315    // nodes like variable declarations and binding elements can returned a view of their flags
316    // that includes the modifiers from their container.  i.e. flags like export/declare aren't
317    // stored on the variable declaration directly, but on the containing variable statement
318    // (if it has one).  Similarly, flags for let/const are stored on the variable declaration
319    // list.  By calling this function, all those flags are combined so that the client can treat
320    // the node as if it actually had those flags.
321    export function getCombinedNodeFlags(node: Node): NodeFlags {
322        return getCombinedFlags(node, n => n.flags);
323    }
324
325    /* @internal */
326    export const supportedLocaleDirectories = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"];
327
328    /**
329     * Checks to see if the locale is in the appropriate format,
330     * and if it is, attempts to set the appropriate language.
331     */
332    export function validateLocaleAndSetLanguage(
333        locale: string,
334        sys: { getExecutingFilePath(): string, resolvePath(path: string): string, fileExists(fileName: string): boolean, readFile(fileName: string): string | undefined },
335        errors?: Push<Diagnostic>) {
336        const lowerCaseLocale = locale.toLowerCase();
337        const matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(lowerCaseLocale);
338
339        if (!matchResult) {
340            if (errors) {
341                errors.push(createCompilerDiagnostic(Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, "en", "ja-jp"));
342            }
343            return;
344        }
345
346        const language = matchResult[1];
347        const territory = matchResult[3];
348
349        // First try the entire locale, then fall back to just language if that's all we have.
350        // Either ways do not fail, and fallback to the English diagnostic strings.
351        if (contains(supportedLocaleDirectories, lowerCaseLocale) && !trySetLanguageAndTerritory(language, territory, errors)) {
352            trySetLanguageAndTerritory(language, /*territory*/ undefined, errors);
353        }
354
355        // Set the UI locale for string collation
356        setUILocale(locale);
357
358        function trySetLanguageAndTerritory(language: string, territory: string | undefined, errors?: Push<Diagnostic>): boolean {
359            const compilerFilePath = normalizePath(sys.getExecutingFilePath());
360            const containingDirectoryPath = getDirectoryPath(compilerFilePath);
361
362            let filePath = combinePaths(containingDirectoryPath, language);
363
364            if (territory) {
365                filePath = filePath + "-" + territory;
366            }
367
368            filePath = sys.resolvePath(combinePaths(filePath, "diagnosticMessages.generated.json"));
369
370            if (!sys.fileExists(filePath)) {
371                return false;
372            }
373
374            // TODO: Add codePage support for readFile?
375            let fileContents: string | undefined = "";
376            try {
377                fileContents = sys.readFile(filePath);
378            }
379            catch (e) {
380                if (errors) {
381                    errors.push(createCompilerDiagnostic(Diagnostics.Unable_to_open_file_0, filePath));
382                }
383                return false;
384            }
385            try {
386                // this is a global mutation (or live binding update)!
387                setLocalizedDiagnosticMessages(JSON.parse(fileContents!));
388            }
389            catch {
390                if (errors) {
391                    errors.push(createCompilerDiagnostic(Diagnostics.Corrupted_locale_file_0, filePath));
392                }
393                return false;
394            }
395
396            return true;
397        }
398    }
399
400    export function getOriginalNode(node: Node): Node;
401    export function getOriginalNode<T extends Node>(node: Node, nodeTest: (node: Node) => node is T): T;
402    export function getOriginalNode(node: Node | undefined): Node | undefined;
403    export function getOriginalNode<T extends Node>(node: Node | undefined, nodeTest: (node: Node | undefined) => node is T): T | undefined;
404    export function getOriginalNode(node: Node | undefined, nodeTest?: (node: Node | undefined) => boolean): Node | undefined {
405        if (node) {
406            while (node.original !== undefined) {
407                node = node.original;
408            }
409        }
410
411        return !nodeTest || nodeTest(node) ? node : undefined;
412    }
413
414    /**
415     * Iterates through the parent chain of a node and performs the callback on each parent until the callback
416     * returns a truthy value, then returns that value.
417     * If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit"
418     * At that point findAncestor returns undefined.
419     */
420    export function findAncestor<T extends Node>(node: Node | undefined, callback: (element: Node) => element is T): T | undefined;
421    export function findAncestor(node: Node | undefined, callback: (element: Node) => boolean | "quit"): Node | undefined;
422    export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node | undefined {
423        while (node) {
424            const result = callback(node);
425            if (result === "quit") {
426                return undefined;
427            }
428            else if (result) {
429                return node;
430            }
431            node = node.parent;
432        }
433        return undefined;
434    }
435
436    /**
437     * Gets a value indicating whether a node originated in the parse tree.
438     *
439     * @param node The node to test.
440     */
441    export function isParseTreeNode(node: Node): boolean {
442        return (node.flags & NodeFlags.Synthesized) === 0;
443    }
444
445    /**
446     * Gets the original parse tree node for a node.
447     *
448     * @param node The original node.
449     * @returns The original parse tree node if found; otherwise, undefined.
450     */
451    export function getParseTreeNode(node: Node | undefined): Node | undefined;
452
453    /**
454     * Gets the original parse tree node for a node.
455     *
456     * @param node The original node.
457     * @param nodeTest A callback used to ensure the correct type of parse tree node is returned.
458     * @returns The original parse tree node if found; otherwise, undefined.
459     */
460    export function getParseTreeNode<T extends Node>(node: T | undefined, nodeTest?: (node: Node) => node is T): T | undefined;
461    export function getParseTreeNode(node: Node | undefined, nodeTest?: (node: Node) => boolean): Node | undefined {
462        if (node === undefined || isParseTreeNode(node)) {
463            return node;
464        }
465
466        node = node.original;
467        while (node) {
468            if (isParseTreeNode(node)) {
469                return !nodeTest || nodeTest(node) ? node : undefined;
470            }
471            node = node.original;
472        }
473    }
474
475    /** Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' */
476    export function escapeLeadingUnderscores(identifier: string): __String {
477        return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String;
478    }
479
480    /**
481     * Remove extra underscore from escaped identifier text content.
482     *
483     * @param identifier The escaped identifier text.
484     * @returns The unescaped identifier text.
485     */
486    export function unescapeLeadingUnderscores(identifier: __String): string {
487        const id = identifier as string;
488        return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id;
489    }
490
491    export function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string {
492        return unescapeLeadingUnderscores(identifierOrPrivateName.escapedText);
493    }
494    export function symbolName(symbol: Symbol): string {
495        if (symbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration)) {
496            return idText(symbol.valueDeclaration.name);
497        }
498        return unescapeLeadingUnderscores(symbol.escapedName);
499    }
500
501    /**
502     * A JSDocTypedef tag has an _optional_ name field - if a name is not directly present, we should
503     * attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol
504     * will be merged with)
505     */
506    function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag | JSDocEnumTag): Identifier | PrivateIdentifier | undefined {
507        const hostNode = declaration.parent.parent;
508        if (!hostNode) {
509            return undefined;
510        }
511        // Covers classes, functions - any named declaration host node
512        if (isDeclaration(hostNode)) {
513            return getDeclarationIdentifier(hostNode);
514        }
515        // Covers remaining cases (returning undefined if none match).
516        switch (hostNode.kind) {
517            case SyntaxKind.VariableStatement:
518                if (hostNode.declarationList && hostNode.declarationList.declarations[0]) {
519                    return getDeclarationIdentifier(hostNode.declarationList.declarations[0]);
520                }
521                break;
522            case SyntaxKind.ExpressionStatement:
523                let expr = hostNode.expression;
524                if (expr.kind === SyntaxKind.BinaryExpression && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
525                    expr = (expr as BinaryExpression).left;
526                }
527                switch (expr.kind) {
528                    case SyntaxKind.PropertyAccessExpression:
529                        return (expr as PropertyAccessExpression).name;
530                    case SyntaxKind.ElementAccessExpression:
531                        const arg = (expr as ElementAccessExpression).argumentExpression;
532                        if (isIdentifier(arg)) {
533                            return arg;
534                        }
535                }
536                break;
537            case SyntaxKind.ParenthesizedExpression: {
538                return getDeclarationIdentifier(hostNode.expression);
539            }
540            case SyntaxKind.LabeledStatement: {
541                if (isDeclaration(hostNode.statement) || isExpression(hostNode.statement)) {
542                    return getDeclarationIdentifier(hostNode.statement);
543                }
544                break;
545            }
546        }
547    }
548
549    function getDeclarationIdentifier(node: Declaration | Expression): Identifier | undefined {
550        const name = getNameOfDeclaration(node);
551        return name && isIdentifier(name) ? name : undefined;
552    }
553
554    /** @internal */
555    export function nodeHasName(statement: Node, name: Identifier) {
556        if (isNamedDeclaration(statement) && isIdentifier(statement.name) && idText(statement.name as Identifier) === idText(name)) {
557            return true;
558        }
559        if (isVariableStatement(statement) && some(statement.declarationList.declarations, d => nodeHasName(d, name))) {
560            return true;
561        }
562        return false;
563    }
564
565    export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined {
566        return declaration.name || nameForNamelessJSDocTypedef(declaration);
567    }
568
569    /** @internal */
570    export function isNamedDeclaration(node: Node): node is NamedDeclaration & { name: DeclarationName } {
571        return !!(node as NamedDeclaration).name; // A 'name' property should always be a DeclarationName.
572    }
573
574    /** @internal */
575    export function getNonAssignedNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined {
576        switch (declaration.kind) {
577            case SyntaxKind.Identifier:
578                return declaration as Identifier;
579            case SyntaxKind.JSDocPropertyTag:
580            case SyntaxKind.JSDocParameterTag: {
581                const { name } = declaration as JSDocPropertyLikeTag;
582                if (name.kind === SyntaxKind.QualifiedName) {
583                    return name.right;
584                }
585                break;
586            }
587            case SyntaxKind.CallExpression:
588            case SyntaxKind.BinaryExpression: {
589                const expr = declaration as BinaryExpression | CallExpression;
590                switch (getAssignmentDeclarationKind(expr)) {
591                    case AssignmentDeclarationKind.ExportsProperty:
592                    case AssignmentDeclarationKind.ThisProperty:
593                    case AssignmentDeclarationKind.Property:
594                    case AssignmentDeclarationKind.PrototypeProperty:
595                        return getElementOrPropertyAccessArgumentExpressionOrName((expr as BinaryExpression).left as AccessExpression);
596                    case AssignmentDeclarationKind.ObjectDefinePropertyValue:
597                    case AssignmentDeclarationKind.ObjectDefinePropertyExports:
598                    case AssignmentDeclarationKind.ObjectDefinePrototypeProperty:
599                        return (expr as BindableObjectDefinePropertyCall).arguments[1];
600                    default:
601                        return undefined;
602                }
603            }
604            case SyntaxKind.JSDocTypedefTag:
605                return getNameOfJSDocTypedef(declaration as JSDocTypedefTag);
606            case SyntaxKind.JSDocEnumTag:
607                return nameForNamelessJSDocTypedef(declaration as JSDocEnumTag);
608            case SyntaxKind.ExportAssignment: {
609                const { expression } = declaration as ExportAssignment;
610                return isIdentifier(expression) ? expression : undefined;
611            }
612            case SyntaxKind.ElementAccessExpression:
613                const expr = declaration as ElementAccessExpression;
614                if (isBindableStaticElementAccessExpression(expr)) {
615                    return expr.argumentExpression;
616                }
617        }
618        return (declaration as NamedDeclaration).name;
619    }
620
621    export function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined {
622        if (declaration === undefined) return undefined;
623        return getNonAssignedNameOfDeclaration(declaration) ||
624            (isFunctionExpression(declaration) || isArrowFunction(declaration) || isClassExpression(declaration) ? getAssignedName(declaration) : undefined);
625    }
626
627    /*@internal*/
628    export function getAssignedName(node: Node): DeclarationName | undefined {
629        if (!node.parent) {
630            return undefined;
631        }
632        else if (isPropertyAssignment(node.parent) || isBindingElement(node.parent)) {
633            return node.parent.name;
634        }
635        else if (isBinaryExpression(node.parent) && node === node.parent.right) {
636            if (isIdentifier(node.parent.left)) {
637                return node.parent.left;
638            }
639            else if (isAccessExpression(node.parent.left)) {
640                return getElementOrPropertyAccessArgumentExpressionOrName(node.parent.left);
641            }
642        }
643        else if (isVariableDeclaration(node.parent) && isIdentifier(node.parent.name)) {
644            return node.parent.name;
645        }
646    }
647
648    export function getDecorators(node: HasDecorators): readonly Decorator[] | undefined {
649        if (hasDecorators(node)) {
650            return filter(node.modifiers, isDecorator);
651        }
652    }
653
654    export function getModifiers(node: HasModifiers): readonly Modifier[] | undefined {
655        if (hasSyntacticModifier(node, ModifierFlags.Modifier)) {
656            return filter(node.modifiers, isModifier);
657        }
658    }
659
660    export function getAllDecorators(node: Node | undefined): readonly Decorator[] {
661        const allDecorators: Decorator[] = [];
662        if (!node) {
663            return allDecorators;
664        }
665        const decorators = getDecorators(node as HasDecorators);
666        if (decorators) {
667            allDecorators.push(...decorators);
668        }
669        const illegalDecorators = getIllegalDecorators(node as HasIllegalDecorators);
670        if (illegalDecorators) {
671            allDecorators.push(...illegalDecorators);
672        }
673        return allDecorators;
674    }
675
676    export function getIllegalDecorators(node: HasIllegalDecorators): readonly Decorator[] | undefined {
677        if (hasIllegalDecorators(node)) {
678            return node.illegalDecorators;
679        }
680    }
681
682    function getJSDocParameterTagsWorker(param: ParameterDeclaration, noCache?: boolean): readonly JSDocParameterTag[] {
683        if (param.name) {
684            if (isIdentifier(param.name)) {
685                const name = param.name.escapedText;
686                return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name);
687            }
688            else {
689                const i = param.parent.parameters.indexOf(param);
690                Debug.assert(i > -1, "Parameters should always be in their parents' parameter list");
691                const paramTags = getJSDocTagsWorker(param.parent, noCache).filter(isJSDocParameterTag);
692                if (i < paramTags.length) {
693                    return [paramTags[i]];
694                }
695            }
696        }
697        // return empty array for: out-of-order binding patterns and JSDoc function syntax, which has un-named parameters
698        return emptyArray;
699    }
700
701    /**
702     * Gets the JSDoc parameter tags for the node if present.
703     *
704     * @remarks Returns any JSDoc param tag whose name matches the provided
705     * parameter, whether a param tag on a containing function
706     * expression, or a param tag on a variable declaration whose
707     * initializer is the containing function. The tags closest to the
708     * node are returned first, so in the previous example, the param
709     * tag on the containing function expression would be first.
710     *
711     * For binding patterns, parameter tags are matched by position.
712     */
713    export function getJSDocParameterTags(param: ParameterDeclaration): readonly JSDocParameterTag[] {
714        return getJSDocParameterTagsWorker(param, /*noCache*/ false);
715    }
716
717    /* @internal */
718    export function getJSDocParameterTagsNoCache(param: ParameterDeclaration): readonly JSDocParameterTag[] {
719        return getJSDocParameterTagsWorker(param, /*noCache*/ true);
720    }
721
722    function getJSDocTypeParameterTagsWorker(param: TypeParameterDeclaration, noCache?: boolean): readonly JSDocTemplateTag[] {
723        const name = param.name.escapedText;
724        return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocTemplateTag =>
725            isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name));
726    }
727
728    /**
729     * Gets the JSDoc type parameter tags for the node if present.
730     *
731     * @remarks Returns any JSDoc template tag whose names match the provided
732     * parameter, whether a template tag on a containing function
733     * expression, or a template tag on a variable declaration whose
734     * initializer is the containing function. The tags closest to the
735     * node are returned first, so in the previous example, the template
736     * tag on the containing function expression would be first.
737     */
738    export function getJSDocTypeParameterTags(param: TypeParameterDeclaration): readonly JSDocTemplateTag[] {
739        return getJSDocTypeParameterTagsWorker(param, /*noCache*/ false);
740    }
741
742    /* @internal */
743    export function getJSDocTypeParameterTagsNoCache(param: TypeParameterDeclaration): readonly JSDocTemplateTag[] {
744        return getJSDocTypeParameterTagsWorker(param, /*noCache*/ true);
745    }
746
747    /**
748     * Return true if the node has JSDoc parameter tags.
749     *
750     * @remarks Includes parameter tags that are not directly on the node,
751     * for example on a variable declaration whose initializer is a function expression.
752     */
753    export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean {
754        return !!getFirstJSDocTag(node, isJSDocParameterTag);
755    }
756
757    /** Gets the JSDoc augments tag for the node if present */
758    export function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined {
759        return getFirstJSDocTag(node, isJSDocAugmentsTag);
760    }
761
762    /** Gets the JSDoc implements tags for the node if present */
763    export function getJSDocImplementsTags(node: Node): readonly JSDocImplementsTag[] {
764        return getAllJSDocTags(node, isJSDocImplementsTag);
765    }
766
767    /** Gets the JSDoc class tag for the node if present */
768    export function getJSDocClassTag(node: Node): JSDocClassTag | undefined {
769        return getFirstJSDocTag(node, isJSDocClassTag);
770    }
771
772    /** Gets the JSDoc public tag for the node if present */
773    export function getJSDocPublicTag(node: Node): JSDocPublicTag | undefined {
774        return getFirstJSDocTag(node, isJSDocPublicTag);
775    }
776
777    /*@internal*/
778    export function getJSDocPublicTagNoCache(node: Node): JSDocPublicTag | undefined {
779        return getFirstJSDocTag(node, isJSDocPublicTag, /*noCache*/ true);
780    }
781
782    /** Gets the JSDoc private tag for the node if present */
783    export function getJSDocPrivateTag(node: Node): JSDocPrivateTag | undefined {
784        return getFirstJSDocTag(node, isJSDocPrivateTag);
785    }
786
787    /*@internal*/
788    export function getJSDocPrivateTagNoCache(node: Node): JSDocPrivateTag | undefined {
789        return getFirstJSDocTag(node, isJSDocPrivateTag, /*noCache*/ true);
790    }
791
792    /** Gets the JSDoc protected tag for the node if present */
793    export function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined {
794        return getFirstJSDocTag(node, isJSDocProtectedTag);
795    }
796
797    /*@internal*/
798    export function getJSDocProtectedTagNoCache(node: Node): JSDocProtectedTag | undefined {
799        return getFirstJSDocTag(node, isJSDocProtectedTag, /*noCache*/ true);
800    }
801
802    /** Gets the JSDoc protected tag for the node if present */
803    export function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined {
804        return getFirstJSDocTag(node, isJSDocReadonlyTag);
805    }
806
807    /*@internal*/
808    export function getJSDocReadonlyTagNoCache(node: Node): JSDocReadonlyTag | undefined {
809        return getFirstJSDocTag(node, isJSDocReadonlyTag, /*noCache*/ true);
810    }
811
812    export function getJSDocOverrideTagNoCache(node: Node): JSDocOverrideTag | undefined {
813        return getFirstJSDocTag(node, isJSDocOverrideTag, /*noCache*/ true);
814    }
815
816    /** Gets the JSDoc deprecated tag for the node if present */
817    export function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined {
818        return getFirstJSDocTag(node, isJSDocDeprecatedTag);
819    }
820
821    /*@internal */
822    export function getJSDocDeprecatedTagNoCache(node: Node): JSDocDeprecatedTag | undefined {
823        return getFirstJSDocTag(node, isJSDocDeprecatedTag, /*noCache*/ true);
824    }
825
826    /** Gets the JSDoc enum tag for the node if present */
827    export function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined {
828        return getFirstJSDocTag(node, isJSDocEnumTag);
829    }
830
831    /** Gets the JSDoc this tag for the node if present */
832    export function getJSDocThisTag(node: Node): JSDocThisTag | undefined {
833        return getFirstJSDocTag(node, isJSDocThisTag);
834    }
835
836    /** Gets the JSDoc return tag for the node if present */
837    export function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined {
838        return getFirstJSDocTag(node, isJSDocReturnTag);
839    }
840
841    /** Gets the JSDoc template tag for the node if present */
842    export function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined {
843        return getFirstJSDocTag(node, isJSDocTemplateTag);
844    }
845
846    /** Gets the JSDoc type tag for the node if present and valid */
847    export function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined {
848        // We should have already issued an error if there were multiple type jsdocs, so just use the first one.
849        const tag = getFirstJSDocTag(node, isJSDocTypeTag);
850        if (tag && tag.typeExpression && tag.typeExpression.type) {
851            return tag;
852        }
853        return undefined;
854    }
855
856    /**
857     * Gets the type node for the node if provided via JSDoc.
858     *
859     * @remarks The search includes any JSDoc param tag that relates
860     * to the provided parameter, for example a type tag on the
861     * parameter itself, or a param tag on a containing function
862     * expression, or a param tag on a variable declaration whose
863     * initializer is the containing function. The tags closest to the
864     * node are examined first, so in the previous example, the type
865     * tag directly on the node would be returned.
866     */
867    export function getJSDocType(node: Node): TypeNode | undefined {
868        let tag: JSDocTypeTag | JSDocParameterTag | undefined = getFirstJSDocTag(node, isJSDocTypeTag);
869        if (!tag && isParameter(node)) {
870            tag = find(getJSDocParameterTags(node), tag => !!tag.typeExpression);
871        }
872
873        return tag && tag.typeExpression && tag.typeExpression.type;
874    }
875
876    /**
877     * Gets the return type node for the node if provided via JSDoc return tag or type tag.
878     *
879     * @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
880     * gets the type from inside the braces, after the fat arrow, etc.
881     */
882    export function getJSDocReturnType(node: Node): TypeNode | undefined {
883        const returnTag = getJSDocReturnTag(node);
884        if (returnTag && returnTag.typeExpression) {
885            return returnTag.typeExpression.type;
886        }
887        const typeTag = getJSDocTypeTag(node);
888        if (typeTag && typeTag.typeExpression) {
889            const type = typeTag.typeExpression.type;
890            if (isTypeLiteralNode(type)) {
891                const sig = find(type.members, isCallSignatureDeclaration);
892                return sig && sig.type;
893            }
894            if (isFunctionTypeNode(type) || isJSDocFunctionType(type)) {
895                return type.type;
896            }
897        }
898    }
899
900    function getJSDocTagsWorker(node: Node, noCache?: boolean): readonly JSDocTag[] {
901        let tags = (node as JSDocContainer).jsDocCache;
902        // If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
903        if (tags === undefined || noCache) {
904            const comments = getJSDocCommentsAndTags(node, noCache);
905            Debug.assert(comments.length < 2 || comments[0] !== comments[1]);
906            tags = flatMap(comments, j => isJSDoc(j) ? j.tags : j);
907            if (!noCache) {
908                (node as JSDocContainer).jsDocCache = tags;
909            }
910        }
911        return tags;
912    }
913
914    /** Get all JSDoc tags related to a node, including those on parent nodes. */
915    export function getJSDocTags(node: Node): readonly JSDocTag[] {
916        return getJSDocTagsWorker(node, /*noCache*/ false);
917    }
918
919    /* @internal */
920    export function getJSDocTagsNoCache(node: Node): readonly JSDocTag[] {
921        return getJSDocTagsWorker(node, /*noCache*/ true);
922    }
923
924    /** Get the first JSDoc tag of a specified kind, or undefined if not present. */
925    function getFirstJSDocTag<T extends JSDocTag>(node: Node, predicate: (tag: JSDocTag) => tag is T, noCache?: boolean): T | undefined {
926        return find(getJSDocTagsWorker(node, noCache), predicate);
927    }
928
929    /** Gets all JSDoc tags that match a specified predicate */
930    export function getAllJSDocTags<T extends JSDocTag>(node: Node, predicate: (tag: JSDocTag) => tag is T): readonly T[] {
931        return getJSDocTags(node).filter(predicate);
932    }
933
934    /** Gets all JSDoc tags of a specified kind */
935    export function getAllJSDocTagsOfKind(node: Node, kind: SyntaxKind): readonly JSDocTag[] {
936        return getJSDocTags(node).filter(doc => doc.kind === kind);
937    }
938
939    /** Gets the text of a jsdoc comment, flattening links to their text. */
940    export function getTextOfJSDocComment(comment?: string | NodeArray<JSDocComment>) {
941        return typeof comment === "string" ? comment
942            : comment?.map(c => c.kind === SyntaxKind.JSDocText ? c.text : formatJSDocLink(c)).join("");
943    }
944
945    function formatJSDocLink(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain) {
946        const kind = link.kind === SyntaxKind.JSDocLink ? "link"
947            : link.kind === SyntaxKind.JSDocLinkCode ? "linkcode"
948            : "linkplain";
949        const name = link.name ? entityNameToString(link.name) : "";
950        const space = link.name && link.text.startsWith("://") ? "" : " ";
951        return `{@${kind} ${name}${space}${link.text}}`;
952    }
953
954    /**
955     * Gets the effective type parameters. If the node was parsed in a
956     * JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
957     *
958     * This does *not* return type parameters from a jsdoc reference to a generic type, eg
959     *
960     * type Id = <T>(x: T) => T
961     * /** @type {Id} /
962     * function id(x) { return x }
963     */
964    export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] {
965        if (isJSDocSignature(node)) {
966            return emptyArray;
967        }
968        if (isJSDocTypeAlias(node)) {
969            Debug.assert(node.parent.kind === SyntaxKind.JSDoc);
970            return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined);
971        }
972        if (node.typeParameters) {
973            return node.typeParameters;
974        }
975        if (canHaveIllegalTypeParameters(node) && node.typeParameters) {
976            return node.typeParameters;
977        }
978        if (isInJSFile(node)) {
979            const decls = getJSDocTypeParameterDeclarations(node);
980            if (decls.length) {
981                return decls;
982            }
983            const typeTag = getJSDocType(node);
984            if (typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters) {
985                return typeTag.typeParameters;
986            }
987        }
988        return emptyArray;
989    }
990
991    export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined {
992        return node.constraint ? node.constraint :
993            isJSDocTemplateTag(node.parent) && node === node.parent.typeParameters[0] ? node.parent.constraint :
994            undefined;
995    }
996
997    // #region
998
999    export function isMemberName(node: Node): node is MemberName {
1000        return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier;
1001    }
1002
1003    /* @internal */
1004    export function isGetOrSetAccessorDeclaration(node: Node): node is AccessorDeclaration {
1005        return node.kind === SyntaxKind.SetAccessor || node.kind === SyntaxKind.GetAccessor;
1006    }
1007
1008    export function isPropertyAccessChain(node: Node): node is PropertyAccessChain {
1009        return isPropertyAccessExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
1010    }
1011
1012    export function isElementAccessChain(node: Node): node is ElementAccessChain {
1013        return isElementAccessExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
1014    }
1015
1016    export function isCallChain(node: Node): node is CallChain {
1017        return isCallExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
1018    }
1019
1020    export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain {
1021        const kind = node.kind;
1022        return !!(node.flags & NodeFlags.OptionalChain) &&
1023            (kind === SyntaxKind.PropertyAccessExpression
1024                || kind === SyntaxKind.ElementAccessExpression
1025                || kind === SyntaxKind.CallExpression
1026                || kind === SyntaxKind.NonNullExpression);
1027    }
1028
1029    /* @internal */
1030    export function isOptionalChainRoot(node: Node): node is OptionalChainRoot {
1031        return isOptionalChain(node) && !isNonNullExpression(node) && !!node.questionDotToken;
1032    }
1033
1034    /**
1035     * Determines whether a node is the expression preceding an optional chain (i.e. `a` in `a?.b`).
1036     */
1037    /* @internal */
1038    export function isExpressionOfOptionalChainRoot(node: Node): node is Expression & { parent: OptionalChainRoot } {
1039        return isOptionalChainRoot(node.parent) && node.parent.expression === node;
1040    }
1041
1042    /**
1043     * Determines whether a node is the outermost `OptionalChain` in an ECMAScript `OptionalExpression`:
1044     *
1045     * 1. For `a?.b.c`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.`)
1046     * 2. For `a?.b!`, the outermost chain is `a?.b` (`b` is the end of the chain starting at `a?.`)
1047     * 3. For `(a?.b.c).d`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.` since parens end the chain)
1048     * 4. For `a?.b.c?.d`, both `a?.b.c` and `a?.b.c?.d` are outermost (`c` is the end of the chain starting at `a?.`, and `d` is
1049     *   the end of the chain starting at `c?.`)
1050     * 5. For `a?.(b?.c).d`, both `b?.c` and `a?.(b?.c)d` are outermost (`c` is the end of the chain starting at `b`, and `d` is
1051     *   the end of the chain starting at `a?.`)
1052     */
1053    /* @internal */
1054    export function isOutermostOptionalChain(node: OptionalChain) {
1055        return !isOptionalChain(node.parent) // cases 1, 2, and 3
1056            || isOptionalChainRoot(node.parent) // case 4
1057            || node !== node.parent.expression; // case 5
1058    }
1059
1060    export function isNullishCoalesce(node: Node) {
1061        return node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken;
1062    }
1063
1064    export function isConstTypeReference(node: Node) {
1065        return isTypeReferenceNode(node) && isIdentifier(node.typeName) &&
1066            node.typeName.escapedText === "const" && !node.typeArguments;
1067    }
1068
1069    export function skipPartiallyEmittedExpressions(node: Expression): Expression;
1070    export function skipPartiallyEmittedExpressions(node: Node): Node;
1071    export function skipPartiallyEmittedExpressions(node: Node) {
1072        return skipOuterExpressions(node, OuterExpressionKinds.PartiallyEmittedExpressions);
1073    }
1074
1075    export function isNonNullChain(node: Node): node is NonNullChain {
1076        return isNonNullExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
1077    }
1078
1079    export function isBreakOrContinueStatement(node: Node): node is BreakOrContinueStatement {
1080        return node.kind === SyntaxKind.BreakStatement || node.kind === SyntaxKind.ContinueStatement;
1081    }
1082
1083    export function isNamedExportBindings(node: Node): node is NamedExportBindings {
1084        return node.kind === SyntaxKind.NamespaceExport || node.kind === SyntaxKind.NamedExports;
1085    }
1086
1087    export function isUnparsedTextLike(node: Node): node is UnparsedTextLike {
1088        switch (node.kind) {
1089            case SyntaxKind.UnparsedText:
1090            case SyntaxKind.UnparsedInternalText:
1091                return true;
1092            default:
1093                return false;
1094        }
1095    }
1096
1097    export function isUnparsedNode(node: Node): node is UnparsedNode {
1098        return isUnparsedTextLike(node) ||
1099            node.kind === SyntaxKind.UnparsedPrologue ||
1100            node.kind === SyntaxKind.UnparsedSyntheticReference;
1101    }
1102
1103    export function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag {
1104        return node.kind === SyntaxKind.JSDocPropertyTag || node.kind === SyntaxKind.JSDocParameterTag;
1105    }
1106
1107    // #endregion
1108
1109    // #region
1110    // Node tests
1111    //
1112    // All node tests in the following list should *not* reference parent pointers so that
1113    // they may be used with transformations.
1114    /* @internal */
1115    export function isNode(node: Node) {
1116        return isNodeKind(node.kind);
1117    }
1118
1119    /* @internal */
1120    export function isNodeKind(kind: SyntaxKind) {
1121        return kind >= SyntaxKind.FirstNode;
1122    }
1123
1124    /**
1125     * True if kind is of some token syntax kind.
1126     * For example, this is true for an IfKeyword but not for an IfStatement.
1127     * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail.
1128     */
1129    export function isTokenKind(kind: SyntaxKind): boolean {
1130        return kind >= SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken;
1131    }
1132
1133    /**
1134     * True if node is of some token syntax kind.
1135     * For example, this is true for an IfKeyword but not for an IfStatement.
1136     * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail.
1137     */
1138    export function isToken(n: Node): boolean {
1139        return isTokenKind(n.kind);
1140    }
1141
1142    // Node Arrays
1143
1144    /* @internal */
1145    export function isNodeArray<T extends Node>(array: readonly T[]): array is NodeArray<T> {
1146        return hasProperty(array, "pos") && hasProperty(array, "end");
1147    }
1148
1149    // Literals
1150
1151    /* @internal */
1152    export function isLiteralKind(kind: SyntaxKind): kind is LiteralToken["kind"] {
1153        return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
1154    }
1155
1156    export function isLiteralExpression(node: Node): node is LiteralExpression {
1157        return isLiteralKind(node.kind);
1158    }
1159
1160    /** @internal */
1161    export function isLiteralExpressionOfObject(node: Node) {
1162        switch (node.kind) {
1163            case SyntaxKind.ObjectLiteralExpression:
1164            case SyntaxKind.ArrayLiteralExpression:
1165            case SyntaxKind.RegularExpressionLiteral:
1166            case SyntaxKind.FunctionExpression:
1167            case SyntaxKind.ClassExpression:
1168                return true;
1169        }
1170        return false;
1171    }
1172
1173    // Pseudo-literals
1174
1175    /* @internal */
1176    export function isTemplateLiteralKind(kind: SyntaxKind): kind is TemplateLiteralToken["kind"] {
1177        return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
1178    }
1179
1180    export function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken {
1181        return isTemplateLiteralKind(node.kind);
1182    }
1183
1184    export function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail {
1185        const kind = node.kind;
1186        return kind === SyntaxKind.TemplateMiddle
1187            || kind === SyntaxKind.TemplateTail;
1188    }
1189
1190    export function isImportOrExportSpecifier(node: Node): node is ImportSpecifier | ExportSpecifier {
1191        return isImportSpecifier(node) || isExportSpecifier(node);
1192    }
1193
1194    export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration {
1195        switch (node.kind) {
1196            case SyntaxKind.ImportSpecifier:
1197            case SyntaxKind.ExportSpecifier:
1198                return (node as ImportOrExportSpecifier).isTypeOnly || (node as ImportOrExportSpecifier).parent.parent.isTypeOnly;
1199            case SyntaxKind.NamespaceImport:
1200                return (node as NamespaceImport).parent.isTypeOnly;
1201            case SyntaxKind.ImportClause:
1202            case SyntaxKind.ImportEqualsDeclaration:
1203                return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly;
1204            default:
1205                return false;
1206        }
1207    }
1208
1209    export function isAssertionKey(node: Node): node is AssertionKey {
1210        return isStringLiteral(node) || isIdentifier(node);
1211    }
1212
1213    export function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken {
1214        return node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind);
1215    }
1216
1217    // Identifiers
1218
1219    /* @internal */
1220    export function isGeneratedIdentifier(node: Node): node is GeneratedIdentifier {
1221        return isIdentifier(node) && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None;
1222    }
1223
1224    /* @internal */
1225    export function isGeneratedPrivateIdentifier(node: Node): node is GeneratedPrivateIdentifier {
1226        return isPrivateIdentifier(node) && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None;
1227    }
1228
1229    // Private Identifiers
1230    /*@internal*/
1231    export function isPrivateIdentifierClassElementDeclaration(node: Node): node is PrivateClassElementDeclaration {
1232        return (isPropertyDeclaration(node) || isMethodOrAccessor(node)) && isPrivateIdentifier(node.name);
1233    }
1234
1235    /*@internal*/
1236    export function isPrivateIdentifierPropertyAccessExpression(node: Node): node is PrivateIdentifierPropertyAccessExpression {
1237        return isPropertyAccessExpression(node) && isPrivateIdentifier(node.name);
1238    }
1239
1240    // Keywords
1241
1242    /* @internal */
1243    export function isModifierKind(token: SyntaxKind): token is Modifier["kind"] {
1244        switch (token) {
1245            case SyntaxKind.AbstractKeyword:
1246            case SyntaxKind.AccessorKeyword:
1247            case SyntaxKind.AsyncKeyword:
1248            case SyntaxKind.ConstKeyword:
1249            case SyntaxKind.DeclareKeyword:
1250            case SyntaxKind.DefaultKeyword:
1251            case SyntaxKind.ExportKeyword:
1252            case SyntaxKind.InKeyword:
1253            case SyntaxKind.PublicKeyword:
1254            case SyntaxKind.PrivateKeyword:
1255            case SyntaxKind.ProtectedKeyword:
1256            case SyntaxKind.ReadonlyKeyword:
1257            case SyntaxKind.StaticKeyword:
1258            case SyntaxKind.OutKeyword:
1259            case SyntaxKind.OverrideKeyword:
1260                return true;
1261        }
1262        return false;
1263    }
1264
1265    /* @internal */
1266    export function isParameterPropertyModifier(kind: SyntaxKind): boolean {
1267        return !!(modifierToFlag(kind) & ModifierFlags.ParameterPropertyModifier);
1268    }
1269
1270    /* @internal */
1271    export function isClassMemberModifier(idToken: SyntaxKind): boolean {
1272        return isParameterPropertyModifier(idToken) ||
1273            idToken === SyntaxKind.StaticKeyword ||
1274            idToken === SyntaxKind.OverrideKeyword ||
1275            idToken === SyntaxKind.AccessorKeyword;
1276    }
1277
1278    export function isModifier(node: Node): node is Modifier {
1279        return isModifierKind(node.kind);
1280    }
1281
1282    export function isEntityName(node: Node): node is EntityName {
1283        const kind = node.kind;
1284        return kind === SyntaxKind.QualifiedName
1285            || kind === SyntaxKind.Identifier;
1286    }
1287
1288    export function isPropertyName(node: Node): node is PropertyName {
1289        const kind = node.kind;
1290        return kind === SyntaxKind.Identifier
1291            || kind === SyntaxKind.PrivateIdentifier
1292            || kind === SyntaxKind.StringLiteral
1293            || kind === SyntaxKind.NumericLiteral
1294            || kind === SyntaxKind.ComputedPropertyName;
1295    }
1296
1297    export function isBindingName(node: Node): node is BindingName {
1298        const kind = node.kind;
1299        return kind === SyntaxKind.Identifier
1300            || kind === SyntaxKind.ObjectBindingPattern
1301            || kind === SyntaxKind.ArrayBindingPattern;
1302    }
1303
1304    // Functions
1305
1306    export function isFunctionLike(node: Node | undefined): node is SignatureDeclaration {
1307        return !!node && isFunctionLikeKind(node.kind);
1308    }
1309
1310    /* @internal */
1311    export function isFunctionLikeOrClassStaticBlockDeclaration(node: Node | undefined): node is SignatureDeclaration | ClassStaticBlockDeclaration {
1312        return !!node && (isFunctionLikeKind(node.kind) || isClassStaticBlockDeclaration(node));
1313    }
1314
1315    /* @internal */
1316    export function isFunctionLikeDeclaration(node: Node): node is FunctionLikeDeclaration {
1317        return node && isFunctionLikeDeclarationKind(node.kind);
1318    }
1319
1320    /* @internal */
1321    export function isBooleanLiteral(node: Node): node is BooleanLiteral {
1322        return node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword;
1323    }
1324
1325    function isFunctionLikeDeclarationKind(kind: SyntaxKind): boolean {
1326        switch (kind) {
1327            case SyntaxKind.FunctionDeclaration:
1328            case SyntaxKind.MethodDeclaration:
1329            case SyntaxKind.Constructor:
1330            case SyntaxKind.GetAccessor:
1331            case SyntaxKind.SetAccessor:
1332            case SyntaxKind.FunctionExpression:
1333            case SyntaxKind.ArrowFunction:
1334                return true;
1335            default:
1336                return false;
1337        }
1338    }
1339
1340    /* @internal */
1341    export function isFunctionLikeKind(kind: SyntaxKind): boolean {
1342        switch (kind) {
1343            case SyntaxKind.MethodSignature:
1344            case SyntaxKind.CallSignature:
1345            case SyntaxKind.JSDocSignature:
1346            case SyntaxKind.ConstructSignature:
1347            case SyntaxKind.IndexSignature:
1348            case SyntaxKind.FunctionType:
1349            case SyntaxKind.JSDocFunctionType:
1350            case SyntaxKind.ConstructorType:
1351                return true;
1352            default:
1353                return isFunctionLikeDeclarationKind(kind);
1354        }
1355    }
1356
1357    /* @internal */
1358    export function isFunctionOrModuleBlock(node: Node): boolean {
1359        return isSourceFile(node) || isModuleBlock(node) || isBlock(node) && isFunctionLike(node.parent);
1360    }
1361
1362    export function isAnnotationElement(node: Node): node is AnnotationElement {
1363        const kind = node.kind;
1364        return kind === SyntaxKind.AnnotationPropertyDeclaration;
1365    }
1366
1367    // Classes
1368    export function isClassElement(node: Node): node is ClassElement {
1369        const kind = node.kind;
1370        return kind === SyntaxKind.Constructor
1371            || kind === SyntaxKind.PropertyDeclaration
1372            || kind === SyntaxKind.MethodDeclaration
1373            || kind === SyntaxKind.GetAccessor
1374            || kind === SyntaxKind.SetAccessor
1375            || kind === SyntaxKind.IndexSignature
1376            || kind === SyntaxKind.ClassStaticBlockDeclaration
1377            || kind === SyntaxKind.SemicolonClassElement;
1378    }
1379
1380    export function isClassLike(node: Node): node is ClassLikeDeclaration {
1381        return node && (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.StructDeclaration);
1382    }
1383
1384    export function isStruct(node: Node): node is StructDeclaration {
1385        return node && node.kind === SyntaxKind.StructDeclaration;
1386    }
1387
1388    export function isAccessor(node: Node): node is AccessorDeclaration {
1389        return node && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor);
1390    }
1391
1392    export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAccessorPropertyDeclaration {
1393        return isPropertyDeclaration(node) && hasAccessorModifier(node);
1394    }
1395
1396    /* @internal */
1397    export function isMethodOrAccessor(node: Node): node is MethodDeclaration | AccessorDeclaration {
1398        switch (node.kind) {
1399            case SyntaxKind.MethodDeclaration:
1400            case SyntaxKind.GetAccessor:
1401            case SyntaxKind.SetAccessor:
1402                return true;
1403            default:
1404                return false;
1405        }
1406    }
1407
1408    /* @internal */
1409    export function isNamedClassElement(node: Node): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration {
1410        switch (node.kind) {
1411            case SyntaxKind.MethodDeclaration:
1412            case SyntaxKind.GetAccessor:
1413            case SyntaxKind.SetAccessor:
1414            case SyntaxKind.PropertyDeclaration:
1415                return true;
1416            default:
1417                return false;
1418        }
1419    }
1420
1421    // Type members
1422
1423    export function isModifierLike(node: Node): node is ModifierLike {
1424        return isModifier(node) || isDecorator(node);
1425    }
1426
1427    export function isTypeElement(node: Node): node is TypeElement {
1428        const kind = node.kind;
1429        return kind === SyntaxKind.ConstructSignature
1430            || kind === SyntaxKind.CallSignature
1431            || kind === SyntaxKind.PropertySignature
1432            || kind === SyntaxKind.MethodSignature
1433            || kind === SyntaxKind.IndexSignature
1434            || kind === SyntaxKind.GetAccessor
1435            || kind === SyntaxKind.SetAccessor;
1436    }
1437
1438    export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement {
1439        return isTypeElement(node) || isClassElement(node);
1440    }
1441
1442    export function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike {
1443        const kind = node.kind;
1444        return kind === SyntaxKind.PropertyAssignment
1445            || kind === SyntaxKind.ShorthandPropertyAssignment
1446            || kind === SyntaxKind.SpreadAssignment
1447            || kind === SyntaxKind.MethodDeclaration
1448            || kind === SyntaxKind.GetAccessor
1449            || kind === SyntaxKind.SetAccessor;
1450    }
1451
1452    // Type
1453
1454    /**
1455     * Node test that determines whether a node is a valid type node.
1456     * This differs from the `isPartOfTypeNode` function which determines whether a node is *part*
1457     * of a TypeNode.
1458     */
1459    export function isTypeNode(node: Node): node is TypeNode {
1460        return isTypeNodeKind(node.kind);
1461    }
1462
1463    export function isFunctionOrConstructorTypeNode(node: Node): node is FunctionTypeNode | ConstructorTypeNode {
1464        switch (node.kind) {
1465            case SyntaxKind.FunctionType:
1466            case SyntaxKind.ConstructorType:
1467                return true;
1468        }
1469
1470        return false;
1471    }
1472
1473    // Binding patterns
1474
1475    /* @internal */
1476    export function isBindingPattern(node: Node | undefined): node is BindingPattern {
1477        if (node) {
1478            const kind = node.kind;
1479            return kind === SyntaxKind.ArrayBindingPattern
1480                || kind === SyntaxKind.ObjectBindingPattern;
1481        }
1482
1483        return false;
1484    }
1485
1486    /* @internal */
1487    export function isAssignmentPattern(node: Node): node is AssignmentPattern {
1488        const kind = node.kind;
1489        return kind === SyntaxKind.ArrayLiteralExpression
1490            || kind === SyntaxKind.ObjectLiteralExpression;
1491    }
1492
1493
1494    /* @internal */
1495    export function isArrayBindingElement(node: Node): node is ArrayBindingElement {
1496        const kind = node.kind;
1497        return kind === SyntaxKind.BindingElement
1498            || kind === SyntaxKind.OmittedExpression;
1499    }
1500
1501
1502    /**
1503     * Determines whether the BindingOrAssignmentElement is a BindingElement-like declaration
1504     */
1505    /* @internal */
1506    export function isDeclarationBindingElement(bindingElement: BindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement {
1507        switch (bindingElement.kind) {
1508            case SyntaxKind.VariableDeclaration:
1509            case SyntaxKind.Parameter:
1510            case SyntaxKind.BindingElement:
1511                return true;
1512        }
1513
1514        return false;
1515    }
1516
1517    /**
1518     * Determines whether a node is a BindingOrAssignmentPattern
1519     */
1520    /* @internal */
1521    export function isBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is BindingOrAssignmentPattern {
1522        return isObjectBindingOrAssignmentPattern(node)
1523            || isArrayBindingOrAssignmentPattern(node);
1524    }
1525
1526    /**
1527     * Determines whether a node is an ObjectBindingOrAssignmentPattern
1528     */
1529    /* @internal */
1530    export function isObjectBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ObjectBindingOrAssignmentPattern {
1531        switch (node.kind) {
1532            case SyntaxKind.ObjectBindingPattern:
1533            case SyntaxKind.ObjectLiteralExpression:
1534                return true;
1535        }
1536
1537        return false;
1538    }
1539
1540    /* @internal */
1541    export function isObjectBindingOrAssignmentElement(node: Node): node is ObjectBindingOrAssignmentElement {
1542        switch (node.kind) {
1543            case SyntaxKind.BindingElement:
1544            case SyntaxKind.PropertyAssignment: // AssignmentProperty
1545            case SyntaxKind.ShorthandPropertyAssignment: // AssignmentProperty
1546            case SyntaxKind.SpreadAssignment: // AssignmentRestProperty
1547                return true;
1548        }
1549        return false;
1550    }
1551
1552    /**
1553     * Determines whether a node is an ArrayBindingOrAssignmentPattern
1554     */
1555    /* @internal */
1556    export function isArrayBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ArrayBindingOrAssignmentPattern {
1557        switch (node.kind) {
1558            case SyntaxKind.ArrayBindingPattern:
1559            case SyntaxKind.ArrayLiteralExpression:
1560                return true;
1561        }
1562
1563        return false;
1564    }
1565
1566    /* @internal */
1567    export function isPropertyAccessOrQualifiedNameOrImportTypeNode(node: Node): node is PropertyAccessExpression | QualifiedName | ImportTypeNode {
1568        const kind = node.kind;
1569        return kind === SyntaxKind.PropertyAccessExpression
1570            || kind === SyntaxKind.QualifiedName
1571            || kind === SyntaxKind.ImportType;
1572    }
1573
1574    // Expression
1575
1576    export function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAccessExpression | QualifiedName {
1577        const kind = node.kind;
1578        return kind === SyntaxKind.PropertyAccessExpression
1579            || kind === SyntaxKind.QualifiedName;
1580    }
1581
1582    export function isCallLikeExpression(node: Node): node is CallLikeExpression {
1583        switch (node.kind) {
1584            case SyntaxKind.JsxOpeningElement:
1585            case SyntaxKind.JsxSelfClosingElement:
1586            case SyntaxKind.CallExpression:
1587            case SyntaxKind.NewExpression:
1588            case SyntaxKind.TaggedTemplateExpression:
1589            case SyntaxKind.Decorator:
1590            case SyntaxKind.EtsComponentExpression:
1591                return true;
1592            default:
1593                return false;
1594        }
1595    }
1596
1597    export function isCallOrNewExpression(node: Node): node is CallExpression | NewExpression {
1598        return node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.NewExpression;
1599    }
1600
1601    export function isTemplateLiteral(node: Node): node is TemplateLiteral {
1602        const kind = node.kind;
1603        return kind === SyntaxKind.TemplateExpression
1604            || kind === SyntaxKind.NoSubstitutionTemplateLiteral;
1605    }
1606
1607    /* @internal */
1608    export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
1609        return isLeftHandSideExpressionKind(skipPartiallyEmittedExpressions(node).kind);
1610    }
1611
1612    function isLeftHandSideExpressionKind(kind: SyntaxKind): boolean {
1613        switch (kind) {
1614            case SyntaxKind.PropertyAccessExpression:
1615            case SyntaxKind.ElementAccessExpression:
1616            case SyntaxKind.NewExpression:
1617            case SyntaxKind.CallExpression:
1618            case SyntaxKind.JsxElement:
1619            case SyntaxKind.JsxSelfClosingElement:
1620            case SyntaxKind.JsxFragment:
1621            case SyntaxKind.TaggedTemplateExpression:
1622            case SyntaxKind.ArrayLiteralExpression:
1623            case SyntaxKind.ParenthesizedExpression:
1624            case SyntaxKind.ObjectLiteralExpression:
1625            case SyntaxKind.ClassExpression:
1626            case SyntaxKind.FunctionExpression:
1627            case SyntaxKind.EtsComponentExpression:
1628            case SyntaxKind.Identifier:
1629            case SyntaxKind.PrivateIdentifier: // technically this is only an Expression if it's in a `#field in expr` BinaryExpression
1630            case SyntaxKind.RegularExpressionLiteral:
1631            case SyntaxKind.NumericLiteral:
1632            case SyntaxKind.BigIntLiteral:
1633            case SyntaxKind.StringLiteral:
1634            case SyntaxKind.NoSubstitutionTemplateLiteral:
1635            case SyntaxKind.TemplateExpression:
1636            case SyntaxKind.FalseKeyword:
1637            case SyntaxKind.NullKeyword:
1638            case SyntaxKind.ThisKeyword:
1639            case SyntaxKind.TrueKeyword:
1640            case SyntaxKind.SuperKeyword:
1641            case SyntaxKind.NonNullExpression:
1642            case SyntaxKind.ExpressionWithTypeArguments:
1643            case SyntaxKind.MetaProperty:
1644            case SyntaxKind.ImportKeyword: // technically this is only an Expression if it's in a CallExpression
1645                return true;
1646            default:
1647                return false;
1648        }
1649    }
1650
1651    /* @internal */
1652    export function isUnaryExpression(node: Node): node is UnaryExpression {
1653        return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind);
1654    }
1655
1656    function isUnaryExpressionKind(kind: SyntaxKind): boolean {
1657        switch (kind) {
1658            case SyntaxKind.PrefixUnaryExpression:
1659            case SyntaxKind.PostfixUnaryExpression:
1660            case SyntaxKind.DeleteExpression:
1661            case SyntaxKind.TypeOfExpression:
1662            case SyntaxKind.VoidExpression:
1663            case SyntaxKind.AwaitExpression:
1664            case SyntaxKind.TypeAssertionExpression:
1665                return true;
1666            default:
1667                return isLeftHandSideExpressionKind(kind);
1668        }
1669    }
1670
1671    /* @internal */
1672    export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpression | PostfixUnaryExpression {
1673        switch (expr.kind) {
1674            case SyntaxKind.PostfixUnaryExpression:
1675                return true;
1676            case SyntaxKind.PrefixUnaryExpression:
1677                return (expr as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken ||
1678                    (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken;
1679            default:
1680                return false;
1681        }
1682    }
1683
1684    /* @internal */
1685    /**
1686     * Determines whether a node is an expression based only on its kind.
1687     * Use `isExpressionNode` if not in transforms.
1688     */
1689    export function isExpression(node: Node): node is Expression {
1690        return isExpressionKind(skipPartiallyEmittedExpressions(node).kind);
1691    }
1692
1693    function isExpressionKind(kind: SyntaxKind): boolean {
1694        switch (kind) {
1695            case SyntaxKind.ConditionalExpression:
1696            case SyntaxKind.YieldExpression:
1697            case SyntaxKind.ArrowFunction:
1698            case SyntaxKind.BinaryExpression:
1699            case SyntaxKind.SpreadElement:
1700            case SyntaxKind.AsExpression:
1701            case SyntaxKind.OmittedExpression:
1702            case SyntaxKind.CommaListExpression:
1703            case SyntaxKind.PartiallyEmittedExpression:
1704            case SyntaxKind.SatisfiesExpression:
1705                return true;
1706            default:
1707                return isUnaryExpressionKind(kind);
1708        }
1709    }
1710
1711    export function isAssertionExpression(node: Node): node is AssertionExpression {
1712        const kind = node.kind;
1713        return kind === SyntaxKind.TypeAssertionExpression
1714            || kind === SyntaxKind.AsExpression;
1715    }
1716
1717    /* @internal */
1718    export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmittedStatement | PartiallyEmittedExpression {
1719        return isNotEmittedStatement(node)
1720            || isPartiallyEmittedExpression(node);
1721    }
1722
1723    // Statement
1724
1725    export function isIterationStatement(node: Node, lookInLabeledStatements: false): node is IterationStatement;
1726    export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement | LabeledStatement;
1727    export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement {
1728        switch (node.kind) {
1729            case SyntaxKind.ForStatement:
1730            case SyntaxKind.ForInStatement:
1731            case SyntaxKind.ForOfStatement:
1732            case SyntaxKind.DoStatement:
1733            case SyntaxKind.WhileStatement:
1734                return true;
1735            case SyntaxKind.LabeledStatement:
1736                return lookInLabeledStatements && isIterationStatement((node as LabeledStatement).statement, lookInLabeledStatements);
1737        }
1738
1739        return false;
1740    }
1741
1742    /* @internal */
1743    export function isScopeMarker(node: Node) {
1744        return isExportAssignment(node) || isExportDeclaration(node);
1745    }
1746
1747    /* @internal */
1748    export function hasScopeMarker(statements: readonly Statement[]) {
1749        return some(statements, isScopeMarker);
1750    }
1751
1752    /* @internal */
1753    export function needsScopeMarker(result: Statement) {
1754        return !isAnyImportOrReExport(result) && !isExportAssignment(result) && !hasSyntacticModifier(result, ModifierFlags.Export) && !isAmbientModule(result);
1755    }
1756
1757    /* @internal */
1758    export function isExternalModuleIndicator(result: Statement) {
1759        // Exported top-level member indicates moduleness
1760        return isAnyImportOrReExport(result) || isExportAssignment(result) || hasSyntacticModifier(result, ModifierFlags.Export);
1761    }
1762
1763    /**
1764     * Semantics of annotations is not defined for JS. The presence of AnnotationDeclaration
1765     * in SourceFile shouldn't effect on resulting JS code.
1766     * But AnnotationDeclaration reuse a general mechanics for declaration importing and exporting.
1767     * It may lead to generation of boilerplate code in process of transformation into JS.
1768     * For example,
1769     * // A.ts
1770     * export @inteface Anno {}
1771     *
1772     * // A.js
1773     * exports.__esModule = true; // <-- side effect
1774     *
1775     * Following function returns true if SourceFile contains only AnnotationDeclaration
1776     * as importing or exporting entity.
1777     */
1778    /* @internal */
1779    export function isOnlyAnnotationsAreExportedOrImported(s: SourceFile, resolver: EmitResolver) {
1780        // Ingnore any files except ets
1781        if (!isInEtsFile(s)) {
1782            return false;
1783        }
1784        // SourceFile exports or imports contains only annotation declarations
1785        const exports = mapDefined(s.statements, (s: Statement) => {
1786            const os = getOriginalNode(s) as Statement;
1787            return isExternalModuleIndicator(os) ? os : undefined;
1788        });
1789        const imports = s.imports;
1790        if (exports.length === 0 && imports.length === 0) {
1791            return false;
1792        }
1793        return every(exports, e => {
1794            if (isAnnotationDeclaration(e)) {
1795                return true;
1796            }
1797            else if (isExportDeclaration(e) && e.exportClause && isNamedExports(e.exportClause)) {
1798                return e.exportClause.elements.length > 0 && every(e.exportClause.elements, e => resolver.isReferredToAnnotation(e) === true);
1799            }
1800            else if (isExportAssignment(e) && resolver.isReferredToAnnotation(e) === true) {
1801                return true;
1802            }
1803            else if (isImportDeclaration(e) && e.importClause && e.importClause.namedBindings && isNamedImports(e.importClause.namedBindings)) {
1804                return e.importClause.namedBindings.elements.length > 0 && every(e.importClause.namedBindings.elements, e => resolver.isReferredToAnnotation(e) === true);
1805            }
1806            return false;
1807        }) && every(imports, i => {
1808            if (isImportDeclaration(i.parent) && i.parent.importClause && i.parent.importClause.namedBindings && isNamedImports(i.parent.importClause.namedBindings)) {
1809                return i.parent.importClause.namedBindings.elements.length > 0 && every(i.parent.importClause.namedBindings.elements, e => resolver.isReferredToAnnotation(e) === true);
1810            }
1811            else if (isExportDeclaration(i.parent) && i.parent.exportClause && isNamedExports(i.parent.exportClause)) {
1812                return i.parent.exportClause.elements.length > 0 && every(i.parent.exportClause.elements, e => resolver.isReferredToAnnotation(e) === true);
1813            }
1814            return false;
1815        });
1816    }
1817
1818
1819    /* @internal */
1820    export function isForInOrOfStatement(node: Node): node is ForInOrOfStatement {
1821        return node.kind === SyntaxKind.ForInStatement || node.kind === SyntaxKind.ForOfStatement;
1822    }
1823
1824    // Element
1825
1826    /* @internal */
1827    export function isConciseBody(node: Node): node is ConciseBody {
1828        return isBlock(node)
1829            || isExpression(node);
1830    }
1831
1832    /* @internal */
1833    export function isFunctionBody(node: Node): node is FunctionBody {
1834        return isBlock(node);
1835    }
1836
1837    /* @internal */
1838    export function isForInitializer(node: Node): node is ForInitializer {
1839        return isVariableDeclarationList(node)
1840            || isExpression(node);
1841    }
1842
1843    /* @internal */
1844    export function isModuleBody(node: Node): node is ModuleBody {
1845        const kind = node.kind;
1846        return kind === SyntaxKind.ModuleBlock
1847            || kind === SyntaxKind.ModuleDeclaration
1848            || kind === SyntaxKind.Identifier;
1849    }
1850
1851    /* @internal */
1852    export function isNamespaceBody(node: Node): node is NamespaceBody {
1853        const kind = node.kind;
1854        return kind === SyntaxKind.ModuleBlock
1855            || kind === SyntaxKind.ModuleDeclaration;
1856    }
1857
1858    /* @internal */
1859    export function isJSDocNamespaceBody(node: Node): node is JSDocNamespaceBody {
1860        const kind = node.kind;
1861        return kind === SyntaxKind.Identifier
1862            || kind === SyntaxKind.ModuleDeclaration;
1863    }
1864
1865    /* @internal */
1866    export function isNamedImportBindings(node: Node): node is NamedImportBindings {
1867        const kind = node.kind;
1868        return kind === SyntaxKind.NamedImports
1869            || kind === SyntaxKind.NamespaceImport;
1870    }
1871
1872    /* @internal */
1873    export function isModuleOrEnumDeclaration(node: Node): node is ModuleDeclaration | EnumDeclaration {
1874        return node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration;
1875    }
1876
1877    function isDeclarationKind(kind: SyntaxKind) {
1878        return kind === SyntaxKind.ArrowFunction
1879            || kind === SyntaxKind.BindingElement
1880            || kind === SyntaxKind.ClassDeclaration
1881            || kind === SyntaxKind.ClassExpression
1882            || kind === SyntaxKind.ClassStaticBlockDeclaration
1883            || kind === SyntaxKind.StructDeclaration
1884            || kind === SyntaxKind.AnnotationDeclaration
1885            || kind === SyntaxKind.Constructor
1886            || kind === SyntaxKind.EnumDeclaration
1887            || kind === SyntaxKind.EnumMember
1888            || kind === SyntaxKind.ExportSpecifier
1889            || kind === SyntaxKind.FunctionDeclaration
1890            || kind === SyntaxKind.FunctionExpression
1891            || kind === SyntaxKind.GetAccessor
1892            || kind === SyntaxKind.ImportClause
1893            || kind === SyntaxKind.ImportEqualsDeclaration
1894            || kind === SyntaxKind.ImportSpecifier
1895            || kind === SyntaxKind.InterfaceDeclaration
1896            || kind === SyntaxKind.JsxAttribute
1897            || kind === SyntaxKind.MethodDeclaration
1898            || kind === SyntaxKind.MethodSignature
1899            || kind === SyntaxKind.ModuleDeclaration
1900            || kind === SyntaxKind.NamespaceExportDeclaration
1901            || kind === SyntaxKind.NamespaceImport
1902            || kind === SyntaxKind.NamespaceExport
1903            || kind === SyntaxKind.Parameter
1904            || kind === SyntaxKind.PropertyAssignment
1905            || kind === SyntaxKind.PropertyDeclaration
1906            || kind === SyntaxKind.AnnotationPropertyDeclaration
1907            || kind === SyntaxKind.PropertySignature
1908            || kind === SyntaxKind.SetAccessor
1909            || kind === SyntaxKind.ShorthandPropertyAssignment
1910            || kind === SyntaxKind.TypeAliasDeclaration
1911            || kind === SyntaxKind.TypeParameter
1912            || kind === SyntaxKind.VariableDeclaration
1913            || kind === SyntaxKind.JSDocTypedefTag
1914            || kind === SyntaxKind.JSDocCallbackTag
1915            || kind === SyntaxKind.JSDocPropertyTag;
1916    }
1917
1918    function isDeclarationStatementKind(kind: SyntaxKind) {
1919        return kind === SyntaxKind.FunctionDeclaration
1920            || kind === SyntaxKind.MissingDeclaration
1921            || kind === SyntaxKind.ClassDeclaration
1922            || kind === SyntaxKind.StructDeclaration
1923            || kind === SyntaxKind.AnnotationDeclaration
1924            || kind === SyntaxKind.InterfaceDeclaration
1925            || kind === SyntaxKind.TypeAliasDeclaration
1926            || kind === SyntaxKind.EnumDeclaration
1927            || kind === SyntaxKind.ModuleDeclaration
1928            || kind === SyntaxKind.ImportDeclaration
1929            || kind === SyntaxKind.ImportEqualsDeclaration
1930            || kind === SyntaxKind.ExportDeclaration
1931            || kind === SyntaxKind.ExportAssignment
1932            || kind === SyntaxKind.NamespaceExportDeclaration;
1933    }
1934
1935    function isStatementKindButNotDeclarationKind(kind: SyntaxKind) {
1936        return kind === SyntaxKind.BreakStatement
1937            || kind === SyntaxKind.ContinueStatement
1938            || kind === SyntaxKind.DebuggerStatement
1939            || kind === SyntaxKind.DoStatement
1940            || kind === SyntaxKind.ExpressionStatement
1941            || kind === SyntaxKind.EmptyStatement
1942            || kind === SyntaxKind.ForInStatement
1943            || kind === SyntaxKind.ForOfStatement
1944            || kind === SyntaxKind.ForStatement
1945            || kind === SyntaxKind.IfStatement
1946            || kind === SyntaxKind.LabeledStatement
1947            || kind === SyntaxKind.ReturnStatement
1948            || kind === SyntaxKind.SwitchStatement
1949            || kind === SyntaxKind.ThrowStatement
1950            || kind === SyntaxKind.TryStatement
1951            || kind === SyntaxKind.VariableStatement
1952            || kind === SyntaxKind.WhileStatement
1953            || kind === SyntaxKind.WithStatement
1954            || kind === SyntaxKind.NotEmittedStatement
1955            || kind === SyntaxKind.EndOfDeclarationMarker
1956            || kind === SyntaxKind.MergeDeclarationMarker;
1957    }
1958
1959    /* @internal */
1960    export function isDeclaration(node: Node): node is NamedDeclaration {
1961        if (node.kind === SyntaxKind.TypeParameter) {
1962            return (node.parent && node.parent.kind !== SyntaxKind.JSDocTemplateTag) || isInJSFile(node);
1963        }
1964
1965        return isDeclarationKind(node.kind);
1966    }
1967
1968    /* @internal */
1969    export function isDeclarationStatement(node: Node): node is DeclarationStatement {
1970        return isDeclarationStatementKind(node.kind);
1971    }
1972
1973    /**
1974     * Determines whether the node is a statement that is not also a declaration
1975     */
1976    /* @internal */
1977    export function isStatementButNotDeclaration(node: Node): node is Statement {
1978        return isStatementKindButNotDeclarationKind(node.kind);
1979    }
1980
1981    /* @internal */
1982    export function isStatement(node: Node): node is Statement {
1983        const kind = node.kind;
1984        return isStatementKindButNotDeclarationKind(kind)
1985            || isDeclarationStatementKind(kind)
1986            || isBlockStatement(node);
1987    }
1988
1989    function isBlockStatement(node: Node): node is Block {
1990        if (node.kind !== SyntaxKind.Block) return false;
1991        if (node.parent !== undefined) {
1992            if (node.parent.kind === SyntaxKind.TryStatement || node.parent.kind === SyntaxKind.CatchClause) {
1993                return false;
1994            }
1995        }
1996        return !isFunctionBlock(node);
1997    }
1998
1999    /**
2000     * NOTE: This is similar to `isStatement` but does not access parent pointers.
2001     */
2002    /* @internal */
2003    export function isStatementOrBlock(node: Node): node is Statement | Block {
2004        const kind = node.kind;
2005        return isStatementKindButNotDeclarationKind(kind)
2006            || isDeclarationStatementKind(kind)
2007            || kind === SyntaxKind.Block;
2008    }
2009
2010    // Module references
2011
2012    /* @internal */
2013    export function isModuleReference(node: Node): node is ModuleReference {
2014        const kind = node.kind;
2015        return kind === SyntaxKind.ExternalModuleReference
2016            || kind === SyntaxKind.QualifiedName
2017            || kind === SyntaxKind.Identifier;
2018    }
2019
2020    // JSX
2021
2022    /* @internal */
2023    export function isJsxTagNameExpression(node: Node): node is JsxTagNameExpression {
2024        const kind = node.kind;
2025        return kind === SyntaxKind.ThisKeyword
2026            || kind === SyntaxKind.Identifier
2027            || kind === SyntaxKind.PropertyAccessExpression;
2028    }
2029
2030    /* @internal */
2031    export function isJsxChild(node: Node): node is JsxChild {
2032        const kind = node.kind;
2033        return kind === SyntaxKind.JsxElement
2034            || kind === SyntaxKind.JsxExpression
2035            || kind === SyntaxKind.JsxSelfClosingElement
2036            || kind === SyntaxKind.JsxText
2037            || kind === SyntaxKind.JsxFragment;
2038    }
2039
2040    /* @internal */
2041    export function isJsxAttributeLike(node: Node): node is JsxAttributeLike {
2042        const kind = node.kind;
2043        return kind === SyntaxKind.JsxAttribute
2044            || kind === SyntaxKind.JsxSpreadAttribute;
2045    }
2046
2047    /* @internal */
2048    export function isStringLiteralOrJsxExpression(node: Node): node is StringLiteral | JsxExpression {
2049        const kind = node.kind;
2050        return kind === SyntaxKind.StringLiteral
2051            || kind === SyntaxKind.JsxExpression;
2052    }
2053
2054    export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement {
2055        const kind = node.kind;
2056        return kind === SyntaxKind.JsxOpeningElement
2057            || kind === SyntaxKind.JsxSelfClosingElement;
2058    }
2059
2060    // Clauses
2061
2062    export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause {
2063        const kind = node.kind;
2064        return kind === SyntaxKind.CaseClause
2065            || kind === SyntaxKind.DefaultClause;
2066    }
2067
2068    // JSDoc
2069
2070    /** True if node is of some JSDoc syntax kind. */
2071    /* @internal */
2072    export function isJSDocNode(node: Node): boolean {
2073        return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode;
2074    }
2075
2076    /** True if node is of a kind that may contain comment text. */
2077    export function isJSDocCommentContainingNode(node: Node): boolean {
2078        return node.kind === SyntaxKind.JSDoc
2079            || node.kind === SyntaxKind.JSDocNamepathType
2080            || node.kind === SyntaxKind.JSDocText
2081            || isJSDocLinkLike(node)
2082            || isJSDocTag(node)
2083            || isJSDocTypeLiteral(node)
2084            || isJSDocSignature(node);
2085    }
2086
2087    // TODO: determine what this does before making it public.
2088    /* @internal */
2089    export function isJSDocTag(node: Node): node is JSDocTag {
2090        return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode;
2091    }
2092
2093    export function isSetAccessor(node: Node): node is SetAccessorDeclaration {
2094        return node.kind === SyntaxKind.SetAccessor;
2095    }
2096
2097    export function isGetAccessor(node: Node): node is GetAccessorDeclaration {
2098        return node.kind === SyntaxKind.GetAccessor;
2099    }
2100
2101    /** True if has jsdoc nodes attached to it. */
2102    /* @internal */
2103    // TODO: GH#19856 Would like to return `node is Node & { jsDoc: JSDoc[] }` but it causes long compile times
2104    export function hasJSDocNodes(node: Node): node is HasJSDoc {
2105        const { jsDoc } = node as JSDocContainer;
2106        return !!jsDoc && jsDoc.length > 0;
2107    }
2108
2109    /** True if has type node attached to it. */
2110    /* @internal */
2111    export function hasType(node: Node): node is HasType {
2112        return !!(node as HasType).type;
2113    }
2114
2115    /** True if has initializer node attached to it. */
2116    /* @internal */
2117    export function hasInitializer(node: Node): node is HasInitializer {
2118        return !!(node as HasInitializer).initializer;
2119    }
2120
2121    /** True if has initializer node attached to it. */
2122    export function hasOnlyExpressionInitializer(node: Node): node is HasExpressionInitializer {
2123        switch (node.kind) {
2124            case SyntaxKind.VariableDeclaration:
2125            case SyntaxKind.Parameter:
2126            case SyntaxKind.BindingElement:
2127            case SyntaxKind.PropertyDeclaration:
2128            case SyntaxKind.AnnotationPropertyDeclaration:
2129            case SyntaxKind.PropertyAssignment:
2130            case SyntaxKind.EnumMember:
2131                return true;
2132            default:
2133                return false;
2134        }
2135    }
2136
2137    export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
2138        return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute || isObjectLiteralElementLike(node);
2139    }
2140
2141    /* @internal */
2142    export function isTypeReferenceType(node: Node): node is TypeReferenceType {
2143        return node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ExpressionWithTypeArguments;
2144    }
2145
2146    const MAX_SMI_X86 = 0x3fff_ffff;
2147    /* @internal */
2148    export function guessIndentation(lines: string[]) {
2149        let indentation = MAX_SMI_X86;
2150        for (const line of lines) {
2151            if (!line.length) {
2152                continue;
2153            }
2154            let i = 0;
2155            for (; i < line.length && i < indentation; i++) {
2156                if (!isWhiteSpaceLike(line.charCodeAt(i))) {
2157                    break;
2158                }
2159            }
2160            if (i < indentation) {
2161                indentation = i;
2162            }
2163            if (indentation === 0) {
2164                return 0;
2165            }
2166        }
2167        return indentation === MAX_SMI_X86 ? undefined : indentation;
2168    }
2169
2170    export function isStringLiteralLike(node: Node): node is StringLiteralLike {
2171        return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
2172    }
2173
2174    export function isJSDocLinkLike(node: Node): node is JSDocLink | JSDocLinkCode | JSDocLinkPlain {
2175        return node.kind === SyntaxKind.JSDocLink || node.kind === SyntaxKind.JSDocLinkCode || node.kind === SyntaxKind.JSDocLinkPlain;
2176    }
2177
2178    export function hasRestParameter(s: SignatureDeclaration | JSDocSignature): boolean {
2179        const last = lastOrUndefined<ParameterDeclaration | JSDocParameterTag>(s.parameters);
2180        return !!last && isRestParameter(last);
2181    }
2182
2183    export function isRestParameter(node: ParameterDeclaration | JSDocParameterTag): boolean {
2184        const type = isJSDocParameterTag(node) ? (node.typeExpression && node.typeExpression.type) : node.type;
2185        return (node as ParameterDeclaration).dotDotDotToken !== undefined || !!type && type.kind === SyntaxKind.JSDocVariadicType;
2186    }
2187
2188    // #endregion
2189}
2190