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