• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* @internal */ // Don't expose that we use this
2// Based on lib.es6.d.ts
3interface PromiseConstructor {
4    new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
5    reject(reason: any): Promise<never>;
6    all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;
7}
8/* @internal */
9declare var Promise: PromiseConstructor; // eslint-disable-line no-var
10
11/* @internal */
12namespace ts {
13    // These utilities are common to multiple language service features.
14    //#region
15    export const scanner: Scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);
16
17    export const enum SemanticMeaning {
18        None = 0x0,
19        Value = 0x1,
20        Type = 0x2,
21        Namespace = 0x4,
22        All = Value | Type | Namespace
23    }
24
25    export function getMeaningFromDeclaration(node: Node): SemanticMeaning {
26        switch (node.kind) {
27            case SyntaxKind.VariableDeclaration:
28                return isInJSFile(node) && getJSDocEnumTag(node) ? SemanticMeaning.All : SemanticMeaning.Value;
29
30            case SyntaxKind.Parameter:
31            case SyntaxKind.BindingElement:
32            case SyntaxKind.PropertyDeclaration:
33            case SyntaxKind.PropertySignature:
34            case SyntaxKind.PropertyAssignment:
35            case SyntaxKind.ShorthandPropertyAssignment:
36            case SyntaxKind.MethodDeclaration:
37            case SyntaxKind.MethodSignature:
38            case SyntaxKind.Constructor:
39            case SyntaxKind.GetAccessor:
40            case SyntaxKind.SetAccessor:
41            case SyntaxKind.FunctionDeclaration:
42            case SyntaxKind.FunctionExpression:
43            case SyntaxKind.ArrowFunction:
44            case SyntaxKind.CatchClause:
45            case SyntaxKind.JsxAttribute:
46                return SemanticMeaning.Value;
47
48            case SyntaxKind.TypeParameter:
49            case SyntaxKind.InterfaceDeclaration:
50            case SyntaxKind.TypeAliasDeclaration:
51            case SyntaxKind.TypeLiteral:
52                return SemanticMeaning.Type;
53
54            case SyntaxKind.JSDocTypedefTag:
55                // If it has no name node, it shares the name with the value declaration below it.
56                return (node as JSDocTypedefTag).name === undefined ? SemanticMeaning.Value | SemanticMeaning.Type : SemanticMeaning.Type;
57
58            case SyntaxKind.EnumMember:
59            case SyntaxKind.ClassDeclaration:
60            case SyntaxKind.StructDeclaration:
61                return SemanticMeaning.Value | SemanticMeaning.Type;
62
63            case SyntaxKind.ModuleDeclaration:
64                if (isAmbientModule(<ModuleDeclaration>node)) {
65                    return SemanticMeaning.Namespace | SemanticMeaning.Value;
66                }
67                else if (getModuleInstanceState(node as ModuleDeclaration) === ModuleInstanceState.Instantiated) {
68                    return SemanticMeaning.Namespace | SemanticMeaning.Value;
69                }
70                else {
71                    return SemanticMeaning.Namespace;
72                }
73
74            case SyntaxKind.EnumDeclaration:
75            case SyntaxKind.NamedImports:
76            case SyntaxKind.ImportSpecifier:
77            case SyntaxKind.ImportEqualsDeclaration:
78            case SyntaxKind.ImportDeclaration:
79            case SyntaxKind.ExportAssignment:
80            case SyntaxKind.ExportDeclaration:
81                return SemanticMeaning.All;
82
83            // An external module can be a Value
84            case SyntaxKind.SourceFile:
85                return SemanticMeaning.Namespace | SemanticMeaning.Value;
86        }
87
88        return SemanticMeaning.All;
89    }
90
91    export function getMeaningFromLocation(node: Node): SemanticMeaning {
92        node = getAdjustedReferenceLocation(node);
93        if (node.kind === SyntaxKind.SourceFile) {
94            return SemanticMeaning.Value;
95        }
96        else if (node.parent.kind === SyntaxKind.ExportAssignment
97            || node.parent.kind === SyntaxKind.ExternalModuleReference
98            || node.parent.kind === SyntaxKind.ImportSpecifier
99            || node.parent.kind === SyntaxKind.ImportClause
100            || isImportEqualsDeclaration(node.parent) && node === node.parent.name) {
101            return SemanticMeaning.All;
102        }
103        else if (isInRightSideOfInternalImportEqualsDeclaration(node)) {
104            return getMeaningFromRightHandSideOfImportEquals(node as Identifier);
105        }
106        else if (isDeclarationName(node)) {
107            return getMeaningFromDeclaration(node.parent);
108        }
109        else if (isEntityName(node) && isJSDocNameReference(node.parent)) {
110            return SemanticMeaning.All;
111        }
112        else if (isTypeReference(node)) {
113            return SemanticMeaning.Type;
114        }
115        else if (isNamespaceReference(node)) {
116            return SemanticMeaning.Namespace;
117        }
118        else if (isTypeParameterDeclaration(node.parent)) {
119            Debug.assert(isJSDocTemplateTag(node.parent.parent)); // Else would be handled by isDeclarationName
120            return SemanticMeaning.Type;
121        }
122        else if (isLiteralTypeNode(node.parent)) {
123            // This might be T["name"], which is actually referencing a property and not a type. So allow both meanings.
124            return SemanticMeaning.Type | SemanticMeaning.Value;
125        }
126        else {
127            return SemanticMeaning.Value;
128        }
129    }
130
131    function getMeaningFromRightHandSideOfImportEquals(node: Node): SemanticMeaning {
132        //     import a = |b|; // Namespace
133        //     import a = |b.c|; // Value, type, namespace
134        //     import a = |b.c|.d; // Namespace
135        const name = node.kind === SyntaxKind.QualifiedName ? node : isQualifiedName(node.parent) && node.parent.right === node ? node.parent : undefined;
136        return name && name.parent.kind === SyntaxKind.ImportEqualsDeclaration ? SemanticMeaning.All : SemanticMeaning.Namespace;
137    }
138
139    export function isInRightSideOfInternalImportEqualsDeclaration(node: Node) {
140        while (node.parent.kind === SyntaxKind.QualifiedName) {
141            node = node.parent;
142        }
143        return isInternalModuleImportEqualsDeclaration(node.parent) && node.parent.moduleReference === node;
144    }
145
146    function isNamespaceReference(node: Node): boolean {
147        return isQualifiedNameNamespaceReference(node) || isPropertyAccessNamespaceReference(node);
148    }
149
150    function isQualifiedNameNamespaceReference(node: Node): boolean {
151        let root = node;
152        let isLastClause = true;
153        if (root.parent.kind === SyntaxKind.QualifiedName) {
154            while (root.parent && root.parent.kind === SyntaxKind.QualifiedName) {
155                root = root.parent;
156            }
157
158            isLastClause = (<QualifiedName>root).right === node;
159        }
160
161        return root.parent.kind === SyntaxKind.TypeReference && !isLastClause;
162    }
163
164    function isPropertyAccessNamespaceReference(node: Node): boolean {
165        let root = node;
166        let isLastClause = true;
167        if (root.parent.kind === SyntaxKind.PropertyAccessExpression) {
168            while (root.parent && root.parent.kind === SyntaxKind.PropertyAccessExpression) {
169                root = root.parent;
170            }
171
172            isLastClause = (<PropertyAccessExpression>root).name === node;
173        }
174
175        if (!isLastClause && root.parent.kind === SyntaxKind.ExpressionWithTypeArguments && root.parent.parent.kind === SyntaxKind.HeritageClause) {
176            const decl = root.parent.parent.parent;
177            return ((decl.kind === SyntaxKind.ClassDeclaration || decl.kind === SyntaxKind.StructDeclaration) && (<HeritageClause>root.parent.parent).token === SyntaxKind.ImplementsKeyword) ||
178                (decl.kind === SyntaxKind.InterfaceDeclaration && (<HeritageClause>root.parent.parent).token === SyntaxKind.ExtendsKeyword);
179        }
180
181        return false;
182    }
183
184    function isTypeReference(node: Node): boolean {
185        if (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
186            node = node.parent;
187        }
188
189        switch (node.kind) {
190            case SyntaxKind.ThisKeyword:
191                return !isExpressionNode(node);
192            case SyntaxKind.ThisType:
193                return true;
194        }
195
196        switch (node.parent.kind) {
197            case SyntaxKind.TypeReference:
198                return true;
199            case SyntaxKind.ImportType:
200                return !(node.parent as ImportTypeNode).isTypeOf;
201            case SyntaxKind.ExpressionWithTypeArguments:
202                return !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent);
203        }
204
205        return false;
206    }
207
208    export function isCallExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
209        return isCalleeWorker(node, isCallExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
210    }
211
212    export function isNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
213        return isCalleeWorker(node, isNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
214    }
215
216    export function isCallOrNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
217        return isCalleeWorker(node, isCallOrNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
218    }
219
220    export function isTaggedTemplateTag(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
221        return isCalleeWorker(node, isTaggedTemplateExpression, selectTagOfTaggedTemplateExpression, includeElementAccess, skipPastOuterExpressions);
222    }
223
224    export function isDecoratorTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
225        return isCalleeWorker(node, isDecorator, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
226    }
227
228    export function isJsxOpeningLikeElementTagName(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
229        return isCalleeWorker(node, isJsxOpeningLikeElement, selectTagNameOfJsxOpeningLikeElement, includeElementAccess, skipPastOuterExpressions);
230    }
231
232    function selectExpressionOfCallOrNewExpressionOrDecorator(node: CallExpression | NewExpression | Decorator) {
233        return node.expression;
234    }
235
236    function selectTagOfTaggedTemplateExpression(node: TaggedTemplateExpression) {
237        return node.tag;
238    }
239
240    function selectTagNameOfJsxOpeningLikeElement(node: JsxOpeningLikeElement) {
241        return node.tagName;
242    }
243
244    function isCalleeWorker<T extends CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement>(node: Node, pred: (node: Node) => node is T, calleeSelector: (node: T) => Expression, includeElementAccess: boolean, skipPastOuterExpressions: boolean) {
245        let target = includeElementAccess ? climbPastPropertyOrElementAccess(node) : climbPastPropertyAccess(node);
246        if (skipPastOuterExpressions) {
247            target = skipOuterExpressions(target);
248        }
249        return !!target && !!target.parent && pred(target.parent) && calleeSelector(target.parent) === target;
250    }
251
252    export function climbPastPropertyAccess(node: Node) {
253        return isRightSideOfPropertyAccess(node) ? node.parent : node;
254    }
255
256    export function climbPastPropertyOrElementAccess(node: Node) {
257        return isRightSideOfPropertyAccess(node) || isArgumentExpressionOfElementAccess(node) ? node.parent : node;
258    }
259
260    export function getTargetLabel(referenceNode: Node, labelName: string): Identifier | undefined {
261        while (referenceNode) {
262            if (referenceNode.kind === SyntaxKind.LabeledStatement && (<LabeledStatement>referenceNode).label.escapedText === labelName) {
263                return (<LabeledStatement>referenceNode).label;
264            }
265            referenceNode = referenceNode.parent;
266        }
267        return undefined;
268    }
269
270    export function hasPropertyAccessExpressionWithName(node: CallExpression, funcName: string): boolean {
271        if (!isPropertyAccessExpression(node.expression)) {
272            return false;
273        }
274
275        return node.expression.name.text === funcName;
276    }
277
278    export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } {
279        return isIdentifier(node) && tryCast(node.parent, isBreakOrContinueStatement)?.label === node;
280    }
281
282    export function isLabelOfLabeledStatement(node: Node): node is Identifier {
283        return isIdentifier(node) && tryCast(node.parent, isLabeledStatement)?.label === node;
284    }
285
286    export function isLabelName(node: Node): boolean {
287        return isLabelOfLabeledStatement(node) || isJumpStatementTarget(node);
288    }
289
290    export function isTagName(node: Node): boolean {
291        return tryCast(node.parent, isJSDocTag)?.tagName === node;
292    }
293
294    export function isRightSideOfQualifiedName(node: Node) {
295        return tryCast(node.parent, isQualifiedName)?.right === node;
296    }
297
298    export function isRightSideOfPropertyAccess(node: Node) {
299        return tryCast(node.parent, isPropertyAccessExpression)?.name === node;
300    }
301
302    export function isArgumentExpressionOfElementAccess(node: Node) {
303        return tryCast(node.parent, isElementAccessExpression)?.argumentExpression === node;
304    }
305
306    export function isNameOfModuleDeclaration(node: Node) {
307        return tryCast(node.parent, isModuleDeclaration)?.name === node;
308    }
309
310    export function isNameOfFunctionDeclaration(node: Node): boolean {
311        return isIdentifier(node) && tryCast(node.parent, isFunctionLike)?.name === node;
312    }
313
314    export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: StringLiteral | NumericLiteral | NoSubstitutionTemplateLiteral): boolean {
315        switch (node.parent.kind) {
316            case SyntaxKind.PropertyDeclaration:
317            case SyntaxKind.PropertySignature:
318            case SyntaxKind.PropertyAssignment:
319            case SyntaxKind.EnumMember:
320            case SyntaxKind.MethodDeclaration:
321            case SyntaxKind.MethodSignature:
322            case SyntaxKind.GetAccessor:
323            case SyntaxKind.SetAccessor:
324            case SyntaxKind.ModuleDeclaration:
325                return getNameOfDeclaration(<Declaration>node.parent) === node;
326            case SyntaxKind.ElementAccessExpression:
327                return (<ElementAccessExpression>node.parent).argumentExpression === node;
328            case SyntaxKind.ComputedPropertyName:
329                return true;
330            case SyntaxKind.LiteralType:
331                return node.parent.parent.kind === SyntaxKind.IndexedAccessType;
332            default:
333                return false;
334        }
335    }
336
337    export function isExpressionOfExternalModuleImportEqualsDeclaration(node: Node) {
338        return isExternalModuleImportEqualsDeclaration(node.parent.parent) &&
339            getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node;
340    }
341
342    export function getContainerNode(node: Node): Declaration | undefined {
343        if (isJSDocTypeAlias(node)) {
344            // This doesn't just apply to the node immediately under the comment, but to everything in its parent's scope.
345            // node.parent = the JSDoc comment, node.parent.parent = the node having the comment.
346            // Then we get parent again in the loop.
347            node = node.parent.parent;
348        }
349
350        while (true) {
351            node = node.parent;
352            if (!node) {
353                return undefined;
354            }
355            switch (node.kind) {
356                case SyntaxKind.SourceFile:
357                case SyntaxKind.MethodDeclaration:
358                case SyntaxKind.MethodSignature:
359                case SyntaxKind.FunctionDeclaration:
360                case SyntaxKind.FunctionExpression:
361                case SyntaxKind.GetAccessor:
362                case SyntaxKind.SetAccessor:
363                case SyntaxKind.ClassDeclaration:
364                case SyntaxKind.StructDeclaration:
365                case SyntaxKind.InterfaceDeclaration:
366                case SyntaxKind.EnumDeclaration:
367                case SyntaxKind.ModuleDeclaration:
368                    return <Declaration>node;
369            }
370        }
371    }
372
373    export function getNodeKind(node: Node): ScriptElementKind {
374        switch (node.kind) {
375            case SyntaxKind.SourceFile:
376                return isExternalModule(<SourceFile>node) ? ScriptElementKind.moduleElement : ScriptElementKind.scriptElement;
377            case SyntaxKind.ModuleDeclaration:
378                return ScriptElementKind.moduleElement;
379            case SyntaxKind.ClassDeclaration:
380            case SyntaxKind.ClassExpression:
381                return ScriptElementKind.classElement;
382            case SyntaxKind.StructDeclaration:
383                return ScriptElementKind.structElement;
384            case SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement;
385            case SyntaxKind.TypeAliasDeclaration:
386            case SyntaxKind.JSDocCallbackTag:
387            case SyntaxKind.JSDocTypedefTag:
388                return ScriptElementKind.typeElement;
389            case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement;
390            case SyntaxKind.VariableDeclaration:
391                return getKindOfVariableDeclaration(<VariableDeclaration>node);
392            case SyntaxKind.BindingElement:
393                return getKindOfVariableDeclaration(<VariableDeclaration>getRootDeclaration(node));
394            case SyntaxKind.ArrowFunction:
395            case SyntaxKind.FunctionDeclaration:
396            case SyntaxKind.FunctionExpression:
397                return ScriptElementKind.functionElement;
398            case SyntaxKind.GetAccessor: return ScriptElementKind.memberGetAccessorElement;
399            case SyntaxKind.SetAccessor: return ScriptElementKind.memberSetAccessorElement;
400            case SyntaxKind.MethodDeclaration:
401            case SyntaxKind.MethodSignature:
402                return ScriptElementKind.memberFunctionElement;
403            case SyntaxKind.PropertyAssignment:
404                const { initializer } = node as PropertyAssignment;
405                return isFunctionLike(initializer) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement;
406            case SyntaxKind.PropertyDeclaration:
407            case SyntaxKind.PropertySignature:
408            case SyntaxKind.ShorthandPropertyAssignment:
409            case SyntaxKind.SpreadAssignment:
410                return ScriptElementKind.memberVariableElement;
411            case SyntaxKind.IndexSignature: return ScriptElementKind.indexSignatureElement;
412            case SyntaxKind.ConstructSignature: return ScriptElementKind.constructSignatureElement;
413            case SyntaxKind.CallSignature: return ScriptElementKind.callSignatureElement;
414            case SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement;
415            case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement;
416            case SyntaxKind.EnumMember: return ScriptElementKind.enumMemberElement;
417            case SyntaxKind.Parameter: return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement;
418            case SyntaxKind.ImportEqualsDeclaration:
419            case SyntaxKind.ImportSpecifier:
420            case SyntaxKind.ExportSpecifier:
421            case SyntaxKind.NamespaceImport:
422            case SyntaxKind.NamespaceExport:
423                return ScriptElementKind.alias;
424            case SyntaxKind.BinaryExpression:
425                const kind = getAssignmentDeclarationKind(node as BinaryExpression);
426                const { right } = node as BinaryExpression;
427                switch (kind) {
428                    case AssignmentDeclarationKind.ObjectDefinePropertyValue:
429                    case AssignmentDeclarationKind.ObjectDefinePropertyExports:
430                    case AssignmentDeclarationKind.ObjectDefinePrototypeProperty:
431                    case AssignmentDeclarationKind.None:
432                        return ScriptElementKind.unknown;
433                    case AssignmentDeclarationKind.ExportsProperty:
434                    case AssignmentDeclarationKind.ModuleExports:
435                        const rightKind = getNodeKind(right);
436                        return rightKind === ScriptElementKind.unknown ? ScriptElementKind.constElement : rightKind;
437                    case AssignmentDeclarationKind.PrototypeProperty:
438                        return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement;
439                    case AssignmentDeclarationKind.ThisProperty:
440                        return ScriptElementKind.memberVariableElement; // property
441                    case AssignmentDeclarationKind.Property:
442                        // static method / property
443                        return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement;
444                    case AssignmentDeclarationKind.Prototype:
445                        return ScriptElementKind.localClassElement;
446                    default: {
447                        assertType<never>(kind);
448                        return ScriptElementKind.unknown;
449                    }
450                }
451            case SyntaxKind.Identifier:
452                return isImportClause(node.parent) ? ScriptElementKind.alias : ScriptElementKind.unknown;
453            case SyntaxKind.ExportAssignment:
454                const scriptKind = getNodeKind((node as ExportAssignment).expression);
455                // If the expression didn't come back with something (like it does for an identifiers)
456                return scriptKind === ScriptElementKind.unknown ? ScriptElementKind.constElement : scriptKind;
457            default:
458                return ScriptElementKind.unknown;
459        }
460
461        function getKindOfVariableDeclaration(v: VariableDeclaration): ScriptElementKind {
462            return isVarConst(v)
463                ? ScriptElementKind.constElement
464                : isLet(v)
465                    ? ScriptElementKind.letElement
466                    : ScriptElementKind.variableElement;
467        }
468    }
469
470    export function isThis(node: Node): boolean {
471        switch (node.kind) {
472            case SyntaxKind.ThisKeyword:
473                // case SyntaxKind.ThisType: TODO: GH#9267
474                return true;
475            case SyntaxKind.Identifier:
476                // 'this' as a parameter
477                return identifierIsThisKeyword(node as Identifier) && node.parent.kind === SyntaxKind.Parameter;
478            default:
479                return false;
480        }
481    }
482
483    // Matches the beginning of a triple slash directive
484    const tripleSlashDirectivePrefixRegex = /^\/\/\/\s*</;
485
486    export interface ListItemInfo {
487        listItemIndex: number;
488        list: Node;
489    }
490
491    export function getLineStartPositionForPosition(position: number, sourceFile: SourceFileLike): number {
492        const lineStarts = getLineStarts(sourceFile);
493        const line = sourceFile.getLineAndCharacterOfPosition(position).line;
494        return lineStarts[line];
495    }
496
497    export function rangeContainsRange(r1: TextRange, r2: TextRange): boolean {
498        return startEndContainsRange(r1.pos, r1.end, r2);
499    }
500
501    export function rangeContainsRangeExclusive(r1: TextRange, r2: TextRange): boolean {
502        return rangeContainsPositionExclusive(r1, r2.pos) && rangeContainsPositionExclusive(r1, r2.end);
503    }
504
505    export function rangeContainsPosition(r: TextRange, pos: number): boolean {
506        return r.pos <= pos && pos <= r.end;
507    }
508
509    export function rangeContainsPositionExclusive(r: TextRange, pos: number) {
510        return r.pos < pos && pos < r.end;
511    }
512
513    export function startEndContainsRange(start: number, end: number, range: TextRange): boolean {
514        return start <= range.pos && end >= range.end;
515    }
516
517    export function rangeContainsStartEnd(range: TextRange, start: number, end: number): boolean {
518        return range.pos <= start && range.end >= end;
519    }
520
521    export function rangeOverlapsWithStartEnd(r1: TextRange, start: number, end: number) {
522        return startEndOverlapsWithStartEnd(r1.pos, r1.end, start, end);
523    }
524
525    export function nodeOverlapsWithStartEnd(node: Node, sourceFile: SourceFile, start: number, end: number) {
526        return startEndOverlapsWithStartEnd(node.getStart(sourceFile), node.end, start, end);
527    }
528
529    export function startEndOverlapsWithStartEnd(start1: number, end1: number, start2: number, end2: number) {
530        const start = Math.max(start1, start2);
531        const end = Math.min(end1, end2);
532        return start < end;
533    }
534
535    /**
536     * Assumes `candidate.start <= position` holds.
537     */
538    export function positionBelongsToNode(candidate: Node, position: number, sourceFile: SourceFile): boolean {
539        Debug.assert(candidate.pos <= position);
540        return position < candidate.end || !isCompletedNode(candidate, sourceFile);
541    }
542
543    function isCompletedNode(n: Node | undefined, sourceFile: SourceFile): boolean {
544        if (n === undefined || nodeIsMissing(n)) {
545            return false;
546        }
547
548        switch (n.kind) {
549            case SyntaxKind.ClassDeclaration:
550            case SyntaxKind.StructDeclaration:
551            case SyntaxKind.InterfaceDeclaration:
552            case SyntaxKind.EnumDeclaration:
553            case SyntaxKind.ObjectLiteralExpression:
554            case SyntaxKind.ObjectBindingPattern:
555            case SyntaxKind.TypeLiteral:
556            case SyntaxKind.Block:
557            case SyntaxKind.ModuleBlock:
558            case SyntaxKind.CaseBlock:
559            case SyntaxKind.NamedImports:
560            case SyntaxKind.NamedExports:
561                return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile);
562            case SyntaxKind.CatchClause:
563                return isCompletedNode((<CatchClause>n).block, sourceFile);
564            case SyntaxKind.NewExpression:
565                if (!(<NewExpression>n).arguments) {
566                    return true;
567                }
568            // falls through
569
570            case SyntaxKind.CallExpression:
571            case SyntaxKind.ParenthesizedExpression:
572            case SyntaxKind.ParenthesizedType:
573                return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
574
575            case SyntaxKind.FunctionType:
576            case SyntaxKind.ConstructorType:
577                return isCompletedNode((<SignatureDeclaration>n).type, sourceFile);
578
579            case SyntaxKind.Constructor:
580            case SyntaxKind.GetAccessor:
581            case SyntaxKind.SetAccessor:
582            case SyntaxKind.FunctionDeclaration:
583            case SyntaxKind.FunctionExpression:
584            case SyntaxKind.MethodDeclaration:
585            case SyntaxKind.MethodSignature:
586            case SyntaxKind.ConstructSignature:
587            case SyntaxKind.CallSignature:
588            case SyntaxKind.ArrowFunction:
589                if ((<FunctionLikeDeclaration>n).body) {
590                    return isCompletedNode((<FunctionLikeDeclaration>n).body, sourceFile);
591                }
592
593                if ((<FunctionLikeDeclaration>n).type) {
594                    return isCompletedNode((<FunctionLikeDeclaration>n).type, sourceFile);
595                }
596
597                // Even though type parameters can be unclosed, we can get away with
598                // having at least a closing paren.
599                return hasChildOfKind(n, SyntaxKind.CloseParenToken, sourceFile);
600
601            case SyntaxKind.ModuleDeclaration:
602                return !!(<ModuleDeclaration>n).body && isCompletedNode((<ModuleDeclaration>n).body, sourceFile);
603
604            case SyntaxKind.IfStatement:
605                if ((<IfStatement>n).elseStatement) {
606                    return isCompletedNode((<IfStatement>n).elseStatement, sourceFile);
607                }
608                return isCompletedNode((<IfStatement>n).thenStatement, sourceFile);
609
610            case SyntaxKind.ExpressionStatement:
611                return isCompletedNode((<ExpressionStatement>n).expression, sourceFile) ||
612                    hasChildOfKind(n, SyntaxKind.SemicolonToken, sourceFile);
613
614            case SyntaxKind.ArrayLiteralExpression:
615            case SyntaxKind.ArrayBindingPattern:
616            case SyntaxKind.ElementAccessExpression:
617            case SyntaxKind.ComputedPropertyName:
618            case SyntaxKind.TupleType:
619                return nodeEndsWith(n, SyntaxKind.CloseBracketToken, sourceFile);
620
621            case SyntaxKind.IndexSignature:
622                if ((<IndexSignatureDeclaration>n).type) {
623                    return isCompletedNode((<IndexSignatureDeclaration>n).type, sourceFile);
624                }
625
626                return hasChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
627
628            case SyntaxKind.CaseClause:
629            case SyntaxKind.DefaultClause:
630                // there is no such thing as terminator token for CaseClause/DefaultClause so for simplicity always consider them non-completed
631                return false;
632
633            case SyntaxKind.ForStatement:
634            case SyntaxKind.ForInStatement:
635            case SyntaxKind.ForOfStatement:
636            case SyntaxKind.WhileStatement:
637                return isCompletedNode((<IterationStatement>n).statement, sourceFile);
638            case SyntaxKind.DoStatement:
639                // rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')';
640                return hasChildOfKind(n, SyntaxKind.WhileKeyword, sourceFile)
641                    ? nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile)
642                    : isCompletedNode((<DoStatement>n).statement, sourceFile);
643
644            case SyntaxKind.TypeQuery:
645                return isCompletedNode((<TypeQueryNode>n).exprName, sourceFile);
646
647            case SyntaxKind.TypeOfExpression:
648            case SyntaxKind.DeleteExpression:
649            case SyntaxKind.VoidExpression:
650            case SyntaxKind.YieldExpression:
651            case SyntaxKind.SpreadElement:
652                const unaryWordExpression = n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement);
653                return isCompletedNode(unaryWordExpression.expression, sourceFile);
654
655            case SyntaxKind.TaggedTemplateExpression:
656                return isCompletedNode((<TaggedTemplateExpression>n).template, sourceFile);
657            case SyntaxKind.TemplateExpression:
658                const lastSpan = lastOrUndefined((<TemplateExpression>n).templateSpans);
659                return isCompletedNode(lastSpan, sourceFile);
660            case SyntaxKind.TemplateSpan:
661                return nodeIsPresent((<TemplateSpan>n).literal);
662
663            case SyntaxKind.ExportDeclaration:
664            case SyntaxKind.ImportDeclaration:
665                return nodeIsPresent((<ExportDeclaration | ImportDeclaration>n).moduleSpecifier);
666
667            case SyntaxKind.PrefixUnaryExpression:
668                return isCompletedNode((<PrefixUnaryExpression>n).operand, sourceFile);
669            case SyntaxKind.BinaryExpression:
670                return isCompletedNode((<BinaryExpression>n).right, sourceFile);
671            case SyntaxKind.ConditionalExpression:
672                return isCompletedNode((<ConditionalExpression>n).whenFalse, sourceFile);
673
674            default:
675                return true;
676        }
677    }
678
679    /*
680     * Checks if node ends with 'expectedLastToken'.
681     * If child at position 'length - 1' is 'SemicolonToken' it is skipped and 'expectedLastToken' is compared with child at position 'length - 2'.
682     */
683    function nodeEndsWith(n: Node, expectedLastToken: SyntaxKind, sourceFile: SourceFile): boolean {
684        const children = n.getChildren(sourceFile);
685        if (children.length) {
686            const lastChild = last(children);
687            if (lastChild.kind === expectedLastToken) {
688                return true;
689            }
690            else if (lastChild.kind === SyntaxKind.SemicolonToken && children.length !== 1) {
691                return children[children.length - 2].kind === expectedLastToken;
692            }
693        }
694        return false;
695    }
696
697    export function findListItemInfo(node: Node): ListItemInfo | undefined {
698        const list = findContainingList(node);
699
700        // It is possible at this point for syntaxList to be undefined, either if
701        // node.parent had no list child, or if none of its list children contained
702        // the span of node. If this happens, return undefined. The caller should
703        // handle this case.
704        if (!list) {
705            return undefined;
706        }
707
708        const children = list.getChildren();
709        const listItemIndex = indexOfNode(children, node);
710
711        return {
712            listItemIndex,
713            list
714        };
715    }
716
717    export function hasChildOfKind(n: Node, kind: SyntaxKind, sourceFile: SourceFile): boolean {
718        return !!findChildOfKind(n, kind, sourceFile);
719    }
720
721    export function findChildOfKind<T extends Node>(n: Node, kind: T["kind"], sourceFile: SourceFileLike): T | undefined {
722        return find(n.getChildren(sourceFile), (c): c is T => c.kind === kind);
723    }
724
725    export function findContainingList(node: Node): SyntaxList | undefined {
726        // The node might be a list element (nonsynthetic) or a comma (synthetic). Either way, it will
727        // be parented by the container of the SyntaxList, not the SyntaxList itself.
728        // In order to find the list item index, we first need to locate SyntaxList itself and then search
729        // for the position of the relevant node (or comma).
730        const syntaxList = find(node.parent.getChildren(), (c): c is SyntaxList => isSyntaxList(c) && rangeContainsRange(c, node));
731        // Either we didn't find an appropriate list, or the list must contain us.
732        Debug.assert(!syntaxList || contains(syntaxList.getChildren(), node));
733        return syntaxList;
734    }
735
736    function isDefaultModifier(node: Node) {
737        return node.kind === SyntaxKind.DefaultKeyword;
738    }
739
740    function isClassKeyword(node: Node) {
741        return node.kind === SyntaxKind.ClassKeyword;
742    }
743
744    function isFunctionKeyword(node: Node) {
745        return node.kind === SyntaxKind.FunctionKeyword;
746    }
747
748    function getAdjustedLocationForClass(node: ClassDeclaration | ClassExpression | StructDeclaration) {
749        if (isNamedDeclaration(node)) {
750            return node.name;
751        }
752        if (isClassDeclaration(node) || isStructDeclaration(node)) {
753            // for class and function declarations, use the `default` modifier
754            // when the declaration is unnamed.
755            const defaultModifier = find(node.modifiers!, isDefaultModifier);
756            if (defaultModifier) return defaultModifier;
757        }
758        if (isClassExpression(node)) {
759            // for class expressions, use the `class` keyword when the class is unnamed
760            const classKeyword = find(node.getChildren(), isClassKeyword);
761            if (classKeyword) return classKeyword;
762        }
763    }
764
765    function getAdjustedLocationForFunction(node: FunctionDeclaration | FunctionExpression) {
766        if (isNamedDeclaration(node)) {
767            return node.name;
768        }
769        if (isFunctionDeclaration(node)) {
770            // for class and function declarations, use the `default` modifier
771            // when the declaration is unnamed.
772            const defaultModifier = find(node.modifiers!, isDefaultModifier);
773            if (defaultModifier) return defaultModifier;
774        }
775        if (isFunctionExpression(node)) {
776            // for function expressions, use the `function` keyword when the function is unnamed
777            const functionKeyword = find(node.getChildren(), isFunctionKeyword);
778            if (functionKeyword) return functionKeyword;
779        }
780    }
781
782    function getAncestorTypeNode(node: Node) {
783        let lastTypeNode: TypeNode | undefined;
784        findAncestor(node, a => {
785            if (isTypeNode(a)) {
786                lastTypeNode = a;
787            }
788            return !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent);
789        });
790        return lastTypeNode;
791    }
792
793    export function getContextualTypeOrAncestorTypeNodeType(node: Expression, checker: TypeChecker) {
794        const contextualType = checker.getContextualType(node);
795        if (contextualType) {
796            return contextualType;
797        }
798
799        const ancestorTypeNode = getAncestorTypeNode(node);
800        return ancestorTypeNode && checker.getTypeAtLocation(ancestorTypeNode);
801    }
802
803    function getAdjustedLocationForDeclaration(node: Node, forRename: boolean) {
804        if (!forRename) {
805            switch (node.kind) {
806                case SyntaxKind.ClassDeclaration:
807                case SyntaxKind.ClassExpression:
808                case SyntaxKind.StructDeclaration:
809                    return getAdjustedLocationForClass(node as ClassDeclaration | ClassExpression | StructDeclaration);
810                case SyntaxKind.FunctionDeclaration:
811                case SyntaxKind.FunctionExpression:
812                    return getAdjustedLocationForFunction(node as FunctionDeclaration | FunctionExpression);
813            }
814        }
815        if (isNamedDeclaration(node)) {
816            return node.name;
817        }
818    }
819
820    function getAdjustedLocationForImportDeclaration(node: ImportDeclaration, forRename: boolean) {
821        if (node.importClause) {
822            if (node.importClause.name && node.importClause.namedBindings) {
823                // do not adjust if we have both a name and named bindings
824                return;
825            }
826
827            // /**/import [|name|] from ...;
828            // import /**/type [|name|] from ...;
829            if (node.importClause.name) {
830                return node.importClause.name;
831            }
832
833            // /**/import { [|name|] } from ...;
834            // /**/import { propertyName as [|name|] } from ...;
835            // /**/import * as [|name|] from ...;
836            // import /**/type { [|name|] } from ...;
837            // import /**/type { propertyName as [|name|] } from ...;
838            // import /**/type * as [|name|] from ...;
839            if (node.importClause.namedBindings) {
840                if (isNamedImports(node.importClause.namedBindings)) {
841                    // do nothing if there is more than one binding
842                    const onlyBinding = singleOrUndefined(node.importClause.namedBindings.elements);
843                    if (!onlyBinding) {
844                        return;
845                    }
846                    return onlyBinding.name;
847                }
848                else if (isNamespaceImport(node.importClause.namedBindings)) {
849                    return node.importClause.namedBindings.name;
850                }
851            }
852        }
853        if (!forRename) {
854            // /**/import "[|module|]";
855            // /**/import ... from "[|module|]";
856            // import /**/type ... from "[|module|]";
857            return node.moduleSpecifier;
858        }
859    }
860
861    function getAdjustedLocationForExportDeclaration(node: ExportDeclaration, forRename: boolean) {
862        if (node.exportClause) {
863            // /**/export { [|name|] } ...
864            // /**/export { propertyName as [|name|] } ...
865            // /**/export * as [|name|] ...
866            // export /**/type { [|name|] } from ...
867            // export /**/type { propertyName as [|name|] } from ...
868            // export /**/type * as [|name|] ...
869            if (isNamedExports(node.exportClause)) {
870                // do nothing if there is more than one binding
871                const onlyBinding = singleOrUndefined(node.exportClause.elements);
872                if (!onlyBinding) {
873                    return;
874                }
875                return node.exportClause.elements[0].name;
876            }
877            else if (isNamespaceExport(node.exportClause)) {
878                return node.exportClause.name;
879            }
880        }
881        if (!forRename) {
882            // /**/export * from "[|module|]";
883            // export /**/type * from "[|module|]";
884            return node.moduleSpecifier;
885        }
886    }
887
888    function getAdjustedLocationForHeritageClause(node: HeritageClause) {
889        // /**/extends [|name|]
890        // /**/implements [|name|]
891        if (node.types.length === 1) {
892            return node.types[0].expression;
893        }
894
895        // /**/extends name1, name2 ...
896        // /**/implements name1, name2 ...
897    }
898
899    function getAdjustedLocation(node: Node, forRename: boolean): Node {
900        const { parent } = node;
901        // /**/<modifier> [|name|] ...
902        // /**/<modifier> <class|interface|type|enum|module|namespace|function|get|set> [|name|] ...
903        // /**/<class|interface|type|enum|module|namespace|function|get|set> [|name|] ...
904        // /**/import [|name|] = ...
905        //
906        // NOTE: If the node is a modifier, we don't adjust its location if it is the `default` modifier as that is handled
907        // specially by `getSymbolAtLocation`.
908        if (isModifier(node) && (forRename || node.kind !== SyntaxKind.DefaultKeyword) ? contains(parent.modifiers, node) :
909            node.kind === SyntaxKind.ClassKeyword ? isClassDeclaration(parent) || isClassExpression(node) :
910                node.kind === SyntaxKind.FunctionKeyword ? isFunctionDeclaration(parent) || isFunctionExpression(node) :
911                    node.kind === SyntaxKind.InterfaceKeyword ? isInterfaceDeclaration(parent) :
912                        node.kind === SyntaxKind.EnumKeyword ? isEnumDeclaration(parent) :
913                            node.kind === SyntaxKind.TypeKeyword ? isTypeAliasDeclaration(parent) :
914                                node.kind === SyntaxKind.NamespaceKeyword || node.kind === SyntaxKind.ModuleKeyword ? isModuleDeclaration(parent) :
915                                    node.kind === SyntaxKind.ImportKeyword ? isImportEqualsDeclaration(parent) :
916                                        node.kind === SyntaxKind.GetKeyword ? isGetAccessorDeclaration(parent) :
917                                            node.kind === SyntaxKind.SetKeyword && isSetAccessorDeclaration(parent)) {
918            const location = getAdjustedLocationForDeclaration(parent, forRename);
919            if (location) {
920                return location;
921            }
922        }
923        // /**/<var|let|const> [|name|] ...
924        if ((node.kind === SyntaxKind.VarKeyword || node.kind === SyntaxKind.ConstKeyword || node.kind === SyntaxKind.LetKeyword) &&
925            isVariableDeclarationList(parent) && parent.declarations.length === 1) {
926            const decl = parent.declarations[0];
927            if (isIdentifier(decl.name)) {
928                return decl.name;
929            }
930        }
931        if (node.kind === SyntaxKind.TypeKeyword) {
932            // import /**/type [|name|] from ...;
933            // import /**/type { [|name|] } from ...;
934            // import /**/type { propertyName as [|name|] } from ...;
935            // import /**/type ... from "[|module|]";
936            if (isImportClause(parent) && parent.isTypeOnly) {
937                const location = getAdjustedLocationForImportDeclaration(parent.parent, forRename);
938                if (location) {
939                    return location;
940                }
941            }
942            // export /**/type { [|name|] } from ...;
943            // export /**/type { propertyName as [|name|] } from ...;
944            // export /**/type * from "[|module|]";
945            // export /**/type * as ... from "[|module|]";
946            if (isExportDeclaration(parent) && parent.isTypeOnly) {
947                const location = getAdjustedLocationForExportDeclaration(parent, forRename);
948                if (location) {
949                    return location;
950                }
951            }
952        }
953        // import { propertyName /**/as [|name|] } ...
954        // import * /**/as [|name|] ...
955        // export { propertyName /**/as [|name|] } ...
956        // export * /**/as [|name|] ...
957        if (node.kind === SyntaxKind.AsKeyword) {
958            if (isImportSpecifier(parent) && parent.propertyName ||
959                isExportSpecifier(parent) && parent.propertyName ||
960                isNamespaceImport(parent) ||
961                isNamespaceExport(parent)) {
962                return parent.name;
963            }
964            if (isExportDeclaration(parent) && parent.exportClause && isNamespaceExport(parent.exportClause)) {
965                return parent.exportClause.name;
966            }
967        }
968        // /**/import [|name|] from ...;
969        // /**/import { [|name|] } from ...;
970        // /**/import { propertyName as [|name|] } from ...;
971        // /**/import ... from "[|module|]";
972        // /**/import "[|module|]";
973        if (node.kind === SyntaxKind.ImportKeyword && isImportDeclaration(parent)) {
974            const location = getAdjustedLocationForImportDeclaration(parent, forRename);
975            if (location) {
976                return location;
977            }
978        }
979        if (node.kind === SyntaxKind.ExportKeyword) {
980            // /**/export { [|name|] } ...;
981            // /**/export { propertyName as [|name|] } ...;
982            // /**/export * from "[|module|]";
983            // /**/export * as ... from "[|module|]";
984            if (isExportDeclaration(parent)) {
985                const location = getAdjustedLocationForExportDeclaration(parent, forRename);
986                if (location) {
987                    return location;
988                }
989            }
990            // NOTE: We don't adjust the location of the `default` keyword as that is handled specially by `getSymbolAtLocation`.
991            // /**/export default [|name|];
992            // /**/export = [|name|];
993            if (isExportAssignment(parent)) {
994                return skipOuterExpressions(parent.expression);
995            }
996        }
997        // import name = /**/require("[|module|]");
998        if (node.kind === SyntaxKind.RequireKeyword && isExternalModuleReference(parent)) {
999            return parent.expression;
1000        }
1001        // import ... /**/from "[|module|]";
1002        // export ... /**/from "[|module|]";
1003        if (node.kind === SyntaxKind.FromKeyword && (isImportDeclaration(parent) || isExportDeclaration(parent)) && parent.moduleSpecifier) {
1004            return parent.moduleSpecifier;
1005        }
1006        // class ... /**/extends [|name|] ...
1007        // class ... /**/implements [|name|] ...
1008        // class ... /**/implements name1, name2 ...
1009        // interface ... /**/extends [|name|] ...
1010        // interface ... /**/extends name1, name2 ...
1011        if ((node.kind === SyntaxKind.ExtendsKeyword || node.kind === SyntaxKind.ImplementsKeyword) && isHeritageClause(parent) && parent.token === node.kind) {
1012            const location = getAdjustedLocationForHeritageClause(parent);
1013            if (location) {
1014                return location;
1015            }
1016        }
1017        if (node.kind === SyntaxKind.ExtendsKeyword) {
1018            // ... <T /**/extends [|U|]> ...
1019            if (isTypeParameterDeclaration(parent) && parent.constraint && isTypeReferenceNode(parent.constraint)) {
1020                return parent.constraint.typeName;
1021            }
1022            // ... T /**/extends [|U|] ? ...
1023            if (isConditionalTypeNode(parent) && isTypeReferenceNode(parent.extendsType)) {
1024                return parent.extendsType.typeName;
1025            }
1026        }
1027        // ... T extends /**/infer [|U|] ? ...
1028        if (node.kind === SyntaxKind.InferKeyword && isInferTypeNode(parent)) {
1029            return parent.typeParameter.name;
1030        }
1031        // { [ [|K|] /**/in keyof T]: ... }
1032        if (node.kind === SyntaxKind.InKeyword && isTypeParameterDeclaration(parent) && isMappedTypeNode(parent.parent)) {
1033            return parent.name;
1034        }
1035        // /**/keyof [|T|]
1036        if (node.kind === SyntaxKind.KeyOfKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.KeyOfKeyword &&
1037            isTypeReferenceNode(parent.type)) {
1038            return parent.type.typeName;
1039        }
1040        // /**/readonly [|name|][]
1041        if (node.kind === SyntaxKind.ReadonlyKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.ReadonlyKeyword &&
1042            isArrayTypeNode(parent.type) && isTypeReferenceNode(parent.type.elementType)) {
1043            return parent.type.elementType.typeName;
1044        }
1045        if (!forRename) {
1046            // /**/new [|name|]
1047            // /**/void [|name|]
1048            // /**/void obj.[|name|]
1049            // /**/typeof [|name|]
1050            // /**/typeof obj.[|name|]
1051            // /**/await [|name|]
1052            // /**/await obj.[|name|]
1053            // /**/yield [|name|]
1054            // /**/yield obj.[|name|]
1055            // /**/delete obj.[|name|]
1056            if (node.kind === SyntaxKind.NewKeyword && isNewExpression(parent) ||
1057                node.kind === SyntaxKind.VoidKeyword && isVoidExpression(parent) ||
1058                node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) ||
1059                node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) ||
1060                node.kind === SyntaxKind.YieldKeyword && isYieldExpression(parent) ||
1061                node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent)) {
1062                if (parent.expression) {
1063                    return skipOuterExpressions(parent.expression);
1064                }
1065            }
1066            // left /**/in [|name|]
1067            // left /**/instanceof [|name|]
1068            if ((node.kind === SyntaxKind.InKeyword || node.kind === SyntaxKind.InstanceOfKeyword) && isBinaryExpression(parent) && parent.operatorToken === node) {
1069                return skipOuterExpressions(parent.right);
1070            }
1071            // left /**/as [|name|]
1072            if (node.kind === SyntaxKind.AsKeyword && isAsExpression(parent) && isTypeReferenceNode(parent.type)) {
1073                return parent.type.typeName;
1074            }
1075            // for (... /**/in [|name|])
1076            // for (... /**/of [|name|])
1077            if (node.kind === SyntaxKind.InKeyword && isForInStatement(parent) ||
1078                node.kind === SyntaxKind.OfKeyword && isForOfStatement(parent)) {
1079                return skipOuterExpressions(parent.expression);
1080            }
1081        }
1082        return node;
1083    }
1084
1085    /**
1086     * Adjusts the location used for "find references" and "go to definition" when the cursor was not
1087     * on a property name.
1088     */
1089    export function getAdjustedReferenceLocation(node: Node): Node {
1090        return getAdjustedLocation(node, /*forRename*/ false);
1091    }
1092
1093    /**
1094     * Adjusts the location used for "rename" when the cursor was not on a property name.
1095     */
1096    export function getAdjustedRenameLocation(node: Node): Node {
1097        return getAdjustedLocation(node, /*forRename*/ true);
1098    }
1099
1100    /**
1101     * Gets the token whose text has range [start, end) and
1102     * position >= start and (position < end or (position === end && token is literal or keyword or identifier))
1103     */
1104    export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
1105        return getTouchingToken(sourceFile, position, n => isPropertyNameLiteral(n) || isKeyword(n.kind) || isPrivateIdentifier(n));
1106    }
1107
1108    /**
1109     * Returns the token if position is in [start, end).
1110     * If position === end, returns the preceding token if includeItemAtEndPosition(previousToken) === true
1111     */
1112    export function getTouchingToken(sourceFile: SourceFile, position: number, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node {
1113        return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includePrecedingTokenAtEndPosition, /*includeEndPosition*/ false);
1114    }
1115
1116    /** Returns a token if position is in [start-of-leading-trivia, end) */
1117    export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node {
1118        return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false);
1119    }
1120
1121    /** Get the token whose text contains the position */
1122    function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includePrecedingTokenAtEndPosition: ((n: Node) => boolean) | undefined, includeEndPosition: boolean): Node {
1123        let current: Node = sourceFile;
1124        outer: while (true) {
1125            // find the child that contains 'position'
1126            for (const child of current.getChildren(sourceFile)) {
1127                const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, /*includeJsDoc*/ true);
1128                if (start > position) {
1129                    // If this child begins after position, then all subsequent children will as well.
1130                    break;
1131                }
1132
1133                const end = child.getEnd();
1134                if (position < end || (position === end && (child.kind === SyntaxKind.EndOfFileToken || includeEndPosition))) {
1135                    current = child;
1136                    continue outer;
1137                }
1138                else if (includePrecedingTokenAtEndPosition && end === position) {
1139                    const previousToken = findPrecedingToken(position, sourceFile, child);
1140                    if (previousToken && includePrecedingTokenAtEndPosition(previousToken)) {
1141                        return previousToken;
1142                    }
1143                }
1144            }
1145
1146            return current;
1147        }
1148    }
1149
1150    /**
1151     * The token on the left of the position is the token that strictly includes the position
1152     * or sits to the left of the cursor if it is on a boundary. For example
1153     *
1154     *   fo|o               -> will return foo
1155     *   foo <comment> |bar -> will return foo
1156     *
1157     */
1158    export function findTokenOnLeftOfPosition(file: SourceFile, position: number): Node | undefined {
1159        // Ideally, getTokenAtPosition should return a token. However, it is currently
1160        // broken, so we do a check to make sure the result was indeed a token.
1161        const tokenAtPosition = getTokenAtPosition(file, position);
1162        if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) {
1163            return tokenAtPosition;
1164        }
1165
1166        return findPrecedingToken(position, file);
1167    }
1168
1169    export function findNextToken(previousToken: Node, parent: Node, sourceFile: SourceFileLike): Node | undefined {
1170        return find(parent);
1171
1172        function find(n: Node): Node | undefined {
1173            if (isToken(n) && n.pos === previousToken.end) {
1174                // this is token that starts at the end of previous token - return it
1175                return n;
1176            }
1177            return firstDefined(n.getChildren(sourceFile), child => {
1178                const shouldDiveInChildNode =
1179                    // previous token is enclosed somewhere in the child
1180                    (child.pos <= previousToken.pos && child.end > previousToken.end) ||
1181                    // previous token ends exactly at the beginning of child
1182                    (child.pos === previousToken.end);
1183                return shouldDiveInChildNode && nodeHasTokens(child, sourceFile) ? find(child) : undefined;
1184            });
1185        }
1186    }
1187
1188    /**
1189     * Finds the rightmost token satisfying `token.end <= position`,
1190     * excluding `JsxText` tokens containing only whitespace.
1191     */
1192    export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, excludeJsdoc?: boolean): Node | undefined {
1193        const result = find(startNode || sourceFile);
1194        Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result)));
1195        return result;
1196
1197        function find(n: Node): Node | undefined {
1198            if (isNonWhitespaceToken(n) && n.kind !== SyntaxKind.EndOfFileToken) {
1199                return n;
1200            }
1201
1202            const children = n.getChildren(sourceFile);
1203            const i = binarySearchKey(children, position, (_, i) => i, (middle, _) => {
1204                // This last callback is more of a selector than a comparator -
1205                // `EqualTo` causes the `middle` result to be returned
1206                // `GreaterThan` causes recursion on the left of the middle
1207                // `LessThan` causes recursion on the right of the middle
1208                if (position < children[middle].end) {
1209                    // first element whose end position is greater than the input position
1210                    if (!children[middle - 1] || position >= children[middle - 1].end) {
1211                        return Comparison.EqualTo;
1212                    }
1213                    return Comparison.GreaterThan;
1214                }
1215                return Comparison.LessThan;
1216            });
1217            if (i >= 0 && children[i]) {
1218                const child = children[i];
1219                // Note that the span of a node's tokens is [node.getStart(...), node.end).
1220                // Given that `position < child.end` and child has constituent tokens, we distinguish these cases:
1221                // 1) `position` precedes `child`'s tokens or `child` has no tokens (ie: in a comment or whitespace preceding `child`):
1222                // we need to find the last token in a previous child.
1223                // 2) `position` is within the same span: we recurse on `child`.
1224                if (position < child.end) {
1225                    const start = child.getStart(sourceFile, /*includeJsDoc*/ !excludeJsdoc);
1226                    const lookInPreviousChild =
1227                        (start >= position) || // cursor in the leading trivia
1228                        !nodeHasTokens(child, sourceFile) ||
1229                        isWhiteSpaceOnlyJsxText(child);
1230
1231                    if (lookInPreviousChild) {
1232                        // actual start of the node is past the position - previous token should be at the end of previous child
1233                        const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i, sourceFile);
1234                        return candidate && findRightmostToken(candidate, sourceFile);
1235                    }
1236                    else {
1237                        // candidate should be in this node
1238                        return find(child);
1239                    }
1240                }
1241            }
1242
1243            Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken || isJSDocCommentContainingNode(n));
1244
1245            // Here we know that none of child token nodes embrace the position,
1246            // the only known case is when position is at the end of the file.
1247            // Try to find the rightmost token in the file without filtering.
1248            // Namely we are skipping the check: 'position < node.end'
1249            const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
1250            return candidate && findRightmostToken(candidate, sourceFile);
1251        }
1252    }
1253
1254    function isNonWhitespaceToken(n: Node): boolean {
1255        return isToken(n) && !isWhiteSpaceOnlyJsxText(n);
1256    }
1257
1258    function findRightmostToken(n: Node, sourceFile: SourceFile): Node | undefined {
1259        if (isNonWhitespaceToken(n)) {
1260            return n;
1261        }
1262
1263        const children = n.getChildren(sourceFile);
1264        if (children.length === 0) {
1265            return n;
1266        }
1267
1268        const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
1269        return candidate && findRightmostToken(candidate, sourceFile);
1270    }
1271
1272    /**
1273     * Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens.
1274     */
1275    function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFile): Node | undefined {
1276        for (let i = exclusiveStartPosition - 1; i >= 0; i--) {
1277            const child = children[i];
1278
1279            if (isWhiteSpaceOnlyJsxText(child)) {
1280                Debug.assert(i > 0, "`JsxText` tokens should not be the first child of `JsxElement | JsxSelfClosingElement`");
1281            }
1282            else if (nodeHasTokens(children[i], sourceFile)) {
1283                return children[i];
1284            }
1285        }
1286    }
1287
1288    export function isInString(sourceFile: SourceFile, position: number, previousToken = findPrecedingToken(position, sourceFile)): boolean {
1289        if (previousToken && isStringTextContainingNode(previousToken)) {
1290            const start = previousToken.getStart(sourceFile);
1291            const end = previousToken.getEnd();
1292
1293            // To be "in" one of these literals, the position has to be:
1294            //   1. entirely within the token text.
1295            //   2. at the end position of an unterminated token.
1296            //   3. at the end of a regular expression (due to trailing flags like '/foo/g').
1297            if (start < position && position < end) {
1298                return true;
1299            }
1300
1301            if (position === end) {
1302                return !!(<LiteralExpression>previousToken).isUnterminated;
1303            }
1304        }
1305
1306        return false;
1307    }
1308
1309    /**
1310     * returns true if the position is in between the open and close elements of an JSX expression.
1311     */
1312    export function isInsideJsxElementOrAttribute(sourceFile: SourceFile, position: number) {
1313        const token = getTokenAtPosition(sourceFile, position);
1314
1315        if (!token) {
1316            return false;
1317        }
1318
1319        if (token.kind === SyntaxKind.JsxText) {
1320            return true;
1321        }
1322
1323        // <div>Hello |</div>
1324        if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxText) {
1325            return true;
1326        }
1327
1328        // <div> { | </div> or <div a={| </div>
1329        if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxExpression) {
1330            return true;
1331        }
1332
1333        // <div> {
1334        // |
1335        // } < /div>
1336        if (token && token.kind === SyntaxKind.CloseBraceToken && token.parent.kind === SyntaxKind.JsxExpression) {
1337            return true;
1338        }
1339
1340        // <div>|</div>
1341        if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxClosingElement) {
1342            return true;
1343        }
1344
1345        return false;
1346    }
1347
1348    function isWhiteSpaceOnlyJsxText(node: Node): boolean {
1349        return isJsxText(node) && node.containsOnlyTriviaWhiteSpaces;
1350    }
1351
1352    export function isInTemplateString(sourceFile: SourceFile, position: number) {
1353        const token = getTokenAtPosition(sourceFile, position);
1354        return isTemplateLiteralKind(token.kind) && position > token.getStart(sourceFile);
1355    }
1356
1357    export function isInJSXText(sourceFile: SourceFile, position: number) {
1358        const token = getTokenAtPosition(sourceFile, position);
1359        if (isJsxText(token)) {
1360            return true;
1361        }
1362        if (token.kind === SyntaxKind.OpenBraceToken && isJsxExpression(token.parent) && isJsxElement(token.parent.parent)) {
1363            return true;
1364        }
1365        if (token.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(token.parent) && isJsxElement(token.parent.parent)) {
1366            return true;
1367        }
1368        return false;
1369    }
1370
1371    export function isInsideJsxElement(sourceFile: SourceFile, position: number): boolean {
1372        function isInsideJsxElementTraversal(node: Node): boolean {
1373            while (node) {
1374                if (node.kind >= SyntaxKind.JsxSelfClosingElement && node.kind <= SyntaxKind.JsxExpression
1375                    || node.kind === SyntaxKind.JsxText
1376                    || node.kind === SyntaxKind.LessThanToken
1377                    || node.kind === SyntaxKind.GreaterThanToken
1378                    || node.kind === SyntaxKind.Identifier
1379                    || node.kind === SyntaxKind.CloseBraceToken
1380                    || node.kind === SyntaxKind.OpenBraceToken
1381                    || node.kind === SyntaxKind.SlashToken) {
1382                    node = node.parent;
1383                }
1384                else if (node.kind === SyntaxKind.JsxElement) {
1385                    if (position > node.getStart(sourceFile)) return true;
1386
1387                    node = node.parent;
1388                }
1389                else {
1390                    return false;
1391                }
1392            }
1393
1394            return false;
1395        }
1396
1397        return isInsideJsxElementTraversal(getTokenAtPosition(sourceFile, position));
1398    }
1399
1400    export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind.OpenBraceToken | SyntaxKind.OpenParenToken | SyntaxKind.OpenBracketToken, sourceFile: SourceFile) {
1401        const closeTokenText = tokenToString(token.kind)!;
1402        const matchingTokenText = tokenToString(matchingTokenKind)!;
1403        const tokenFullStart = token.getFullStart();
1404        // Text-scan based fast path - can be bamboozled by comments and other trivia, but often provides
1405        // a good, fast approximation without too much extra work in the cases where it fails.
1406        const bestGuessIndex = sourceFile.text.lastIndexOf(matchingTokenText, tokenFullStart);
1407        if (bestGuessIndex === -1) {
1408            return undefined; // if the token text doesn't appear in the file, there can't be a match - super fast bail
1409        }
1410        // we can only use the textual result directly if we didn't have to count any close tokens within the range
1411        if (sourceFile.text.lastIndexOf(closeTokenText, tokenFullStart - 1) < bestGuessIndex) {
1412            const nodeAtGuess = findPrecedingToken(bestGuessIndex + 1, sourceFile);
1413            if (nodeAtGuess && nodeAtGuess.kind === matchingTokenKind) {
1414                return nodeAtGuess;
1415            }
1416        }
1417        const tokenKind = token.kind;
1418        let remainingMatchingTokens = 0;
1419        while (true) {
1420            const preceding = findPrecedingToken(token.getFullStart(), sourceFile);
1421            if (!preceding) {
1422                return undefined;
1423            }
1424            token = preceding;
1425
1426            if (token.kind === matchingTokenKind) {
1427                if (remainingMatchingTokens === 0) {
1428                    return token;
1429                }
1430
1431                remainingMatchingTokens--;
1432            }
1433            else if (token.kind === tokenKind) {
1434                remainingMatchingTokens++;
1435            }
1436        }
1437    }
1438
1439    export function removeOptionality(type: Type, isOptionalExpression: boolean, isOptionalChain: boolean) {
1440        return isOptionalExpression ? type.getNonNullableType() :
1441            isOptionalChain ? type.getNonOptionalType() :
1442                type;
1443    }
1444
1445    export function isPossiblyTypeArgumentPosition(token: Node, sourceFile: SourceFile, checker: TypeChecker): boolean {
1446        const info = getPossibleTypeArgumentsInfo(token, sourceFile);
1447        return info !== undefined && (isPartOfTypeNode(info.called) ||
1448            getPossibleGenericSignatures(info.called, info.nTypeArguments, checker).length !== 0 ||
1449            isPossiblyTypeArgumentPosition(info.called, sourceFile, checker));
1450    }
1451
1452    export function getPossibleGenericSignatures(called: Expression, typeArgumentCount: number, checker: TypeChecker): readonly Signature[] {
1453        let type = checker.getTypeAtLocation(called);
1454        if (isOptionalChain(called.parent)) {
1455            type = removeOptionality(type, isOptionalChainRoot(called.parent), /*isOptionalChain*/ true);
1456        }
1457
1458        const signatures = isNewExpression(called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
1459        return signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount);
1460    }
1461
1462    export interface PossibleTypeArgumentInfo {
1463        readonly called: Identifier;
1464        readonly nTypeArguments: number;
1465    }
1466
1467    export interface PossibleProgramFileInfo {
1468        ProgramFiles?: string[];
1469    }
1470
1471    // Get info for an expression like `f <` that may be the start of type arguments.
1472    export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
1473        // This is a rare case, but one that saves on a _lot_ of work if true - if the source file has _no_ `<` character,
1474        // then there obviously can't be any type arguments - no expensive brace-matching backwards scanning required
1475
1476        if (sourceFile.text.lastIndexOf("<", tokenIn ? tokenIn.pos : sourceFile.text.length) === -1) {
1477            return undefined;
1478        }
1479
1480        let token: Node | undefined = tokenIn;
1481        // This function determines if the node could be type argument position
1482        // Since during editing, when type argument list is not complete,
1483        // the tree could be of any shape depending on the tokens parsed before current node,
1484        // scanning of the previous identifier followed by "<" before current node would give us better result
1485        // Note that we also balance out the already provided type arguments, arrays, object literals while doing so
1486        let remainingLessThanTokens = 0;
1487        let nTypeArguments = 0;
1488        while (token) {
1489            switch (token.kind) {
1490                case SyntaxKind.LessThanToken:
1491                    // Found the beginning of the generic argument expression
1492                    token = findPrecedingToken(token.getFullStart(), sourceFile);
1493                    if (token && token.kind === SyntaxKind.QuestionDotToken) {
1494                        token = findPrecedingToken(token.getFullStart(), sourceFile);
1495                    }
1496                    if (!token || !isIdentifier(token)) return undefined;
1497                    if (!remainingLessThanTokens) {
1498                        return isDeclarationName(token) ? undefined : { called: token, nTypeArguments };
1499                    }
1500                    remainingLessThanTokens--;
1501                    break;
1502
1503                case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
1504                    remainingLessThanTokens = + 3;
1505                    break;
1506
1507                case SyntaxKind.GreaterThanGreaterThanToken:
1508                    remainingLessThanTokens = + 2;
1509                    break;
1510
1511                case SyntaxKind.GreaterThanToken:
1512                    remainingLessThanTokens++;
1513                    break;
1514
1515                case SyntaxKind.CloseBraceToken:
1516                    // This can be object type, skip until we find the matching open brace token
1517                    // Skip until the matching open brace token
1518                    token = findPrecedingMatchingToken(token, SyntaxKind.OpenBraceToken, sourceFile);
1519                    if (!token) return undefined;
1520                    break;
1521
1522                case SyntaxKind.CloseParenToken:
1523                    // This can be object type, skip until we find the matching open brace token
1524                    // Skip until the matching open brace token
1525                    token = findPrecedingMatchingToken(token, SyntaxKind.OpenParenToken, sourceFile);
1526                    if (!token) return undefined;
1527                    break;
1528
1529                case SyntaxKind.CloseBracketToken:
1530                    // This can be object type, skip until we find the matching open brace token
1531                    // Skip until the matching open brace token
1532                    token = findPrecedingMatchingToken(token, SyntaxKind.OpenBracketToken, sourceFile);
1533                    if (!token) return undefined;
1534                    break;
1535
1536                // Valid tokens in a type name. Skip.
1537                case SyntaxKind.CommaToken:
1538                    nTypeArguments++;
1539                    break;
1540
1541                case SyntaxKind.EqualsGreaterThanToken:
1542                // falls through
1543
1544                case SyntaxKind.Identifier:
1545                case SyntaxKind.StringLiteral:
1546                case SyntaxKind.NumericLiteral:
1547                case SyntaxKind.BigIntLiteral:
1548                case SyntaxKind.TrueKeyword:
1549                case SyntaxKind.FalseKeyword:
1550                // falls through
1551
1552                case SyntaxKind.TypeOfKeyword:
1553                case SyntaxKind.ExtendsKeyword:
1554                case SyntaxKind.KeyOfKeyword:
1555                case SyntaxKind.DotToken:
1556                case SyntaxKind.BarToken:
1557                case SyntaxKind.QuestionToken:
1558                case SyntaxKind.ColonToken:
1559                    break;
1560
1561                default:
1562                    if (isTypeNode(token)) {
1563                        break;
1564                    }
1565
1566                    // Invalid token in type
1567                    return undefined;
1568            }
1569
1570            token = findPrecedingToken(token.getFullStart(), sourceFile);
1571        }
1572
1573        return undefined;
1574    }
1575
1576    /**
1577     * Returns true if the cursor at position in sourceFile is within a comment.
1578     *
1579     * @param tokenAtPosition Must equal `getTokenAtPosition(sourceFile, position)
1580     * @param predicate Additional predicate to test on the comment range.
1581     */
1582    export function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition?: Node): CommentRange | undefined {
1583        return formatting.getRangeOfEnclosingComment(sourceFile, position, /*precedingToken*/ undefined, tokenAtPosition);
1584    }
1585
1586    export function hasDocComment(sourceFile: SourceFile, position: number): boolean {
1587        const token = getTokenAtPosition(sourceFile, position);
1588        return !!findAncestor(token, isJSDoc);
1589    }
1590
1591    function nodeHasTokens(n: Node, sourceFile: SourceFileLike): boolean {
1592        // If we have a token or node that has a non-zero width, it must have tokens.
1593        // Note: getWidth() does not take trivia into account.
1594        return n.kind === SyntaxKind.EndOfFileToken ? !!(n as EndOfFileToken).jsDoc : n.getWidth(sourceFile) !== 0;
1595    }
1596
1597    export function getNodeModifiers(node: Node, excludeFlags = ModifierFlags.None): string {
1598        const result: string[] = [];
1599        const flags = isDeclaration(node)
1600            ? getCombinedNodeFlagsAlwaysIncludeJSDoc(node) & ~excludeFlags
1601            : ModifierFlags.None;
1602
1603        if (flags & ModifierFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier);
1604        if (flags & ModifierFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier);
1605        if (flags & ModifierFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier);
1606        if (flags & ModifierFlags.Static) result.push(ScriptElementKindModifier.staticModifier);
1607        if (flags & ModifierFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier);
1608        if (flags & ModifierFlags.Export) result.push(ScriptElementKindModifier.exportedModifier);
1609        if (flags & ModifierFlags.Deprecated) result.push(ScriptElementKindModifier.deprecatedModifier);
1610        if (node.flags & NodeFlags.Ambient) result.push(ScriptElementKindModifier.ambientModifier);
1611        if (node.kind === SyntaxKind.ExportAssignment) result.push(ScriptElementKindModifier.exportedModifier);
1612
1613        return result.length > 0 ? result.join(",") : ScriptElementKindModifier.none;
1614    }
1615
1616    export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray<Node> | undefined {
1617        if (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.CallExpression) {
1618            return (<CallExpression>node).typeArguments;
1619        }
1620
1621        if (isFunctionLike(node) || node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.InterfaceDeclaration) {
1622            return (<FunctionLikeDeclaration>node).typeParameters;
1623        }
1624
1625        return undefined;
1626    }
1627
1628    export function isComment(kind: SyntaxKind): boolean {
1629        return kind === SyntaxKind.SingleLineCommentTrivia || kind === SyntaxKind.MultiLineCommentTrivia;
1630    }
1631
1632    export function isStringOrRegularExpressionOrTemplateLiteral(kind: SyntaxKind): boolean {
1633        if (kind === SyntaxKind.StringLiteral
1634            || kind === SyntaxKind.RegularExpressionLiteral
1635            || isTemplateLiteralKind(kind)) {
1636            return true;
1637        }
1638        return false;
1639    }
1640
1641    export function isPunctuation(kind: SyntaxKind): boolean {
1642        return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation;
1643    }
1644
1645    export function isInsideTemplateLiteral(node: TemplateLiteralToken, position: number, sourceFile: SourceFile): boolean {
1646        return isTemplateLiteralKind(node.kind)
1647            && (node.getStart(sourceFile) < position && position < node.end) || (!!node.isUnterminated && position === node.end);
1648    }
1649
1650    export function isAccessibilityModifier(kind: SyntaxKind) {
1651        switch (kind) {
1652            case SyntaxKind.PublicKeyword:
1653            case SyntaxKind.PrivateKeyword:
1654            case SyntaxKind.ProtectedKeyword:
1655                return true;
1656        }
1657
1658        return false;
1659    }
1660
1661    export function cloneCompilerOptions(options: CompilerOptions): CompilerOptions {
1662        const result = clone(options);
1663        setConfigFileInOptions(result, options && options.configFile);
1664        return result;
1665    }
1666
1667    export function isArrayLiteralOrObjectLiteralDestructuringPattern(node: Node) {
1668        if (node.kind === SyntaxKind.ArrayLiteralExpression ||
1669            node.kind === SyntaxKind.ObjectLiteralExpression) {
1670            // [a,b,c] from:
1671            // [a, b, c] = someExpression;
1672            if (node.parent.kind === SyntaxKind.BinaryExpression &&
1673                (<BinaryExpression>node.parent).left === node &&
1674                (<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
1675                return true;
1676            }
1677
1678            // [a, b, c] from:
1679            // for([a, b, c] of expression)
1680            if (node.parent.kind === SyntaxKind.ForOfStatement &&
1681                (<ForOfStatement>node.parent).initializer === node) {
1682                return true;
1683            }
1684
1685            // [a, b, c] of
1686            // [x, [a, b, c] ] = someExpression
1687            // or
1688            // {x, a: {a, b, c} } = someExpression
1689            if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) {
1690                return true;
1691            }
1692        }
1693
1694        return false;
1695    }
1696
1697    export function isInReferenceComment(sourceFile: SourceFile, position: number): boolean {
1698        return isInReferenceCommentWorker(sourceFile, position, /*shouldBeReference*/ true);
1699    }
1700
1701    export function isInNonReferenceComment(sourceFile: SourceFile, position: number): boolean {
1702        return isInReferenceCommentWorker(sourceFile, position, /*shouldBeReference*/ false);
1703    }
1704
1705    function isInReferenceCommentWorker(sourceFile: SourceFile, position: number, shouldBeReference: boolean): boolean {
1706        const range = isInComment(sourceFile, position, /*tokenAtPosition*/ undefined);
1707        return !!range && shouldBeReference === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end));
1708    }
1709
1710    export function getReplacementSpanForContextToken(contextToken: Node | undefined) {
1711        if (!contextToken) return undefined;
1712
1713        switch (contextToken.kind) {
1714            case SyntaxKind.StringLiteral:
1715            case SyntaxKind.NoSubstitutionTemplateLiteral:
1716                return createTextSpanFromStringLiteralLikeContent(<StringLiteralLike>contextToken);
1717            default:
1718                return createTextSpanFromNode(contextToken);
1719        }
1720    }
1721
1722    export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile, endNode?: Node): TextSpan {
1723        return createTextSpanFromBounds(node.getStart(sourceFile), (endNode || node).getEnd());
1724    }
1725
1726    export function createTextSpanFromStringLiteralLikeContent(node: StringLiteralLike) {
1727        if (node.isUnterminated) return undefined;
1728        return createTextSpanFromBounds(node.getStart() + 1, node.getEnd() - 1);
1729    }
1730
1731    export function createTextRangeFromNode(node: Node, sourceFile: SourceFile): TextRange {
1732        return createRange(node.getStart(sourceFile), node.end);
1733    }
1734
1735    export function createTextSpanFromRange(range: TextRange): TextSpan {
1736        return createTextSpanFromBounds(range.pos, range.end);
1737    }
1738
1739    export function createTextRangeFromSpan(span: TextSpan): TextRange {
1740        return createRange(span.start, span.start + span.length);
1741    }
1742
1743    export function createTextChangeFromStartLength(start: number, length: number, newText: string): TextChange {
1744        return createTextChange(createTextSpan(start, length), newText);
1745    }
1746
1747    export function createTextChange(span: TextSpan, newText: string): TextChange {
1748        return { span, newText };
1749    }
1750
1751    export const typeKeywords: readonly SyntaxKind[] = [
1752        SyntaxKind.AnyKeyword,
1753        SyntaxKind.AssertsKeyword,
1754        SyntaxKind.BigIntKeyword,
1755        SyntaxKind.BooleanKeyword,
1756        SyntaxKind.FalseKeyword,
1757        SyntaxKind.InferKeyword,
1758        SyntaxKind.KeyOfKeyword,
1759        SyntaxKind.NeverKeyword,
1760        SyntaxKind.NullKeyword,
1761        SyntaxKind.NumberKeyword,
1762        SyntaxKind.ObjectKeyword,
1763        SyntaxKind.ReadonlyKeyword,
1764        SyntaxKind.StringKeyword,
1765        SyntaxKind.SymbolKeyword,
1766        SyntaxKind.TrueKeyword,
1767        SyntaxKind.VoidKeyword,
1768        SyntaxKind.UndefinedKeyword,
1769        SyntaxKind.UniqueKeyword,
1770        SyntaxKind.UnknownKeyword,
1771    ];
1772
1773    export function isTypeKeyword(kind: SyntaxKind): boolean {
1774        return contains(typeKeywords, kind);
1775    }
1776
1777    export function isTypeKeywordToken(node: Node): node is Token<SyntaxKind.TypeKeyword> {
1778        return node.kind === SyntaxKind.TypeKeyword;
1779    }
1780
1781    /** True if the symbol is for an external module, as opposed to a namespace. */
1782    export function isExternalModuleSymbol(moduleSymbol: Symbol): boolean {
1783        return !!(moduleSymbol.flags & SymbolFlags.Module) && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote;
1784    }
1785
1786    /** Returns `true` the first time it encounters a node and `false` afterwards. */
1787    export type NodeSeenTracker<T = Node> = (node: T) => boolean;
1788    export function nodeSeenTracker<T extends Node>(): NodeSeenTracker<T> {
1789        const seen: true[] = [];
1790        return node => {
1791            const id = getNodeId(node);
1792            return !seen[id] && (seen[id] = true);
1793        };
1794    }
1795
1796    export function getSnapshotText(snap: IScriptSnapshot): string {
1797        return snap.getText(0, snap.getLength());
1798    }
1799
1800    export function repeatString(str: string, count: number): string {
1801        let result = "";
1802        for (let i = 0; i < count; i++) {
1803            result += str;
1804        }
1805        return result;
1806    }
1807
1808    export function skipConstraint(type: Type): Type {
1809        return type.isTypeParameter() ? type.getConstraint() || type : type;
1810    }
1811
1812    export function getNameFromPropertyName(name: PropertyName): string | undefined {
1813        return name.kind === SyntaxKind.ComputedPropertyName
1814            // treat computed property names where expression is string/numeric literal as just string/numeric literal
1815            ? isStringOrNumericLiteralLike(name.expression) ? name.expression.text : undefined
1816            : isPrivateIdentifier(name) ? idText(name) : getTextOfIdentifierOrLiteral(name);
1817    }
1818
1819    export function programContainsModules(program: Program): boolean {
1820        return program.getSourceFiles().some(s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!(s.externalModuleIndicator || s.commonJsModuleIndicator));
1821    }
1822    export function programContainsEs6Modules(program: Program): boolean {
1823        return program.getSourceFiles().some(s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!s.externalModuleIndicator);
1824    }
1825    export function compilerOptionsIndicateEs6Modules(compilerOptions: CompilerOptions): boolean {
1826        return !!compilerOptions.module || compilerOptions.target! >= ScriptTarget.ES2015 || !!compilerOptions.noEmit;
1827    }
1828
1829    export function createModuleSpecifierResolutionHost(program: Program, host: LanguageServiceHost): ModuleSpecifierResolutionHost {
1830        // Mix in `getProbableSymlinks` from Program when host doesn't have it
1831        // in order for non-Project hosts to have a symlinks cache.
1832        return {
1833            fileExists: fileName => program.fileExists(fileName),
1834            getCurrentDirectory: () => host.getCurrentDirectory(),
1835            readFile: maybeBind(host, host.readFile),
1836            useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
1837            getSymlinkCache: maybeBind(host, host.getSymlinkCache) || program.getSymlinkCache,
1838            getGlobalTypingsCacheLocation: maybeBind(host, host.getGlobalTypingsCacheLocation),
1839            getSourceFiles: () => program.getSourceFiles(),
1840            redirectTargetsMap: program.redirectTargetsMap,
1841            getProjectReferenceRedirect: fileName => program.getProjectReferenceRedirect(fileName),
1842            isSourceOfProjectReferenceRedirect: fileName => program.isSourceOfProjectReferenceRedirect(fileName),
1843            getNearestAncestorDirectoryWithPackageJson: maybeBind(host, host.getNearestAncestorDirectoryWithPackageJson),
1844            getFileIncludeReasons: () => program.getFileIncludeReasons(),
1845        };
1846    }
1847
1848    export function getModuleSpecifierResolverHost(program: Program, host: LanguageServiceHost): SymbolTracker["moduleResolverHost"] {
1849        return {
1850            ...createModuleSpecifierResolutionHost(program, host),
1851            getCommonSourceDirectory: () => program.getCommonSourceDirectory(),
1852        };
1853    }
1854
1855    export function makeImportIfNecessary(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string, quotePreference: QuotePreference): ImportDeclaration | undefined {
1856        return defaultImport || namedImports && namedImports.length ? makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference) : undefined;
1857    }
1858
1859    export function makeImport(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string | Expression, quotePreference: QuotePreference, isTypeOnly?: boolean): ImportDeclaration {
1860        return factory.createImportDeclaration(
1861            /*decorators*/ undefined,
1862            /*modifiers*/ undefined,
1863            defaultImport || namedImports
1864                ? factory.createImportClause(!!isTypeOnly, defaultImport, namedImports && namedImports.length ? factory.createNamedImports(namedImports) : undefined)
1865                : undefined,
1866            typeof moduleSpecifier === "string" ? makeStringLiteral(moduleSpecifier, quotePreference) : moduleSpecifier);
1867    }
1868
1869    export function makeStringLiteral(text: string, quotePreference: QuotePreference): StringLiteral {
1870        return factory.createStringLiteral(text, quotePreference === QuotePreference.Single);
1871    }
1872
1873    export const enum QuotePreference { Single, Double }
1874
1875    export function quotePreferenceFromString(str: StringLiteral, sourceFile: SourceFile): QuotePreference {
1876        return isStringDoubleQuoted(str, sourceFile) ? QuotePreference.Double : QuotePreference.Single;
1877    }
1878
1879    export function getQuotePreference(sourceFile: SourceFile, preferences: UserPreferences): QuotePreference {
1880        if (preferences.quotePreference && preferences.quotePreference !== "auto") {
1881            return preferences.quotePreference === "single" ? QuotePreference.Single : QuotePreference.Double;
1882        }
1883        else {
1884            // ignore synthetic import added when importHelpers: true
1885            const firstModuleSpecifier = sourceFile.imports &&
1886                find(sourceFile.imports, n => isStringLiteral(n) && !nodeIsSynthesized(n.parent)) as StringLiteral;
1887            return firstModuleSpecifier ? quotePreferenceFromString(firstModuleSpecifier, sourceFile) : QuotePreference.Double;
1888        }
1889    }
1890
1891    export function getQuoteFromPreference(qp: QuotePreference): string {
1892        switch (qp) {
1893            case QuotePreference.Single: return "'";
1894            case QuotePreference.Double: return '"';
1895            default: return Debug.assertNever(qp);
1896        }
1897    }
1898
1899    export function symbolNameNoDefault(symbol: Symbol): string | undefined {
1900        const escaped = symbolEscapedNameNoDefault(symbol);
1901        return escaped === undefined ? undefined : unescapeLeadingUnderscores(escaped);
1902    }
1903
1904    export function symbolEscapedNameNoDefault(symbol: Symbol): __String | undefined {
1905        if (symbol.escapedName !== InternalSymbolName.Default) {
1906            return symbol.escapedName;
1907        }
1908
1909        return firstDefined(symbol.declarations, decl => {
1910            const name = getNameOfDeclaration(decl);
1911            return name && name.kind === SyntaxKind.Identifier ? name.escapedText : undefined;
1912        });
1913    }
1914
1915    export type ObjectBindingElementWithoutPropertyName = BindingElement & { name: Identifier };
1916
1917    export function isObjectBindingElementWithoutPropertyName(bindingElement: Node): bindingElement is ObjectBindingElementWithoutPropertyName {
1918        return isBindingElement(bindingElement) &&
1919            isObjectBindingPattern(bindingElement.parent) &&
1920            isIdentifier(bindingElement.name) &&
1921            !bindingElement.propertyName;
1922    }
1923
1924    export function getPropertySymbolFromBindingElement(checker: TypeChecker, bindingElement: ObjectBindingElementWithoutPropertyName): Symbol | undefined {
1925        const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent);
1926        return typeOfPattern && checker.getPropertyOfType(typeOfPattern, bindingElement.name.text);
1927    }
1928
1929    export function getParentNodeInSpan(node: Node | undefined, file: SourceFile, span: TextSpan): Node | undefined {
1930        if (!node) return undefined;
1931
1932        while (node.parent) {
1933            if (isSourceFile(node.parent) || !spanContainsNode(span, node.parent, file)) {
1934                return node;
1935            }
1936
1937            node = node.parent;
1938        }
1939    }
1940
1941    function spanContainsNode(span: TextSpan, node: Node, file: SourceFile): boolean {
1942        return textSpanContainsPosition(span, node.getStart(file)) &&
1943            node.getEnd() <= textSpanEnd(span);
1944    }
1945
1946    export function findModifier(node: Node, kind: Modifier["kind"]): Modifier | undefined {
1947        return node.modifiers && find(node.modifiers, m => m.kind === kind);
1948    }
1949
1950    export function insertImports(changes: textChanges.ChangeTracker, sourceFile: SourceFile, imports: AnyImportOrRequireStatement | readonly AnyImportOrRequireStatement[], blankLineBetween: boolean): void {
1951        const decl = isArray(imports) ? imports[0] : imports;
1952        const importKindPredicate: (node: Node) => node is AnyImportOrRequireStatement = decl.kind === SyntaxKind.VariableStatement ? isRequireVariableStatement : isAnyImportSyntax;
1953        const existingImportStatements = filter(sourceFile.statements, importKindPredicate);
1954        const sortedNewImports = isArray(imports) ? stableSort(imports, OrganizeImports.compareImportsOrRequireStatements) : [imports];
1955        if (!existingImportStatements.length) {
1956            changes.insertNodesAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween);
1957        }
1958        else if (existingImportStatements && OrganizeImports.importsAreSorted(existingImportStatements)) {
1959            for (const newImport of sortedNewImports) {
1960                const insertionIndex = OrganizeImports.getImportDeclarationInsertionIndex(existingImportStatements, newImport);
1961                if (insertionIndex === 0) {
1962                    // If the first import is top-of-file, insert after the leading comment which is likely the header.
1963                    const options = existingImportStatements[0] === sourceFile.statements[0] ?
1964                    { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude } : {};
1965                    changes.insertNodeBefore(sourceFile, existingImportStatements[0], newImport, /*blankLineBetween*/ false, options);
1966                }
1967                else {
1968                    const prevImport = existingImportStatements[insertionIndex - 1];
1969                    changes.insertNodeAfter(sourceFile, prevImport, newImport);
1970                }
1971            }
1972        }
1973        else {
1974            const lastExistingImport = lastOrUndefined(existingImportStatements);
1975            if (lastExistingImport) {
1976                changes.insertNodesAfter(sourceFile, lastExistingImport, sortedNewImports);
1977            }
1978            else {
1979                changes.insertNodesAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween);
1980            }
1981        }
1982    }
1983
1984    export function getTypeKeywordOfTypeOnlyImport(importClause: ImportClause, sourceFile: SourceFile): Token<SyntaxKind.TypeKeyword> {
1985        Debug.assert(importClause.isTypeOnly);
1986        return cast(importClause.getChildAt(0, sourceFile), isTypeKeywordToken);
1987    }
1988
1989    export function textSpansEqual(a: TextSpan | undefined, b: TextSpan | undefined): boolean {
1990        return !!a && !!b && a.start === b.start && a.length === b.length;
1991    }
1992    export function documentSpansEqual(a: DocumentSpan, b: DocumentSpan): boolean {
1993        return a.fileName === b.fileName && textSpansEqual(a.textSpan, b.textSpan);
1994    }
1995
1996    /**
1997     * Iterates through 'array' by index and performs the callback on each element of array until the callback
1998     * returns a truthy value, then returns that value.
1999     * If no such value is found, the callback is applied to each element of array and undefined is returned.
2000     */
2001    export function forEachUnique<T, U>(array: readonly T[] | undefined, callback: (element: T, index: number) => U): U | undefined {
2002        if (array) {
2003            for (let i = 0; i < array.length; i++) {
2004                if (array.indexOf(array[i]) === i) {
2005                    const result = callback(array[i], i);
2006                    if (result) {
2007                        return result;
2008                    }
2009                }
2010            }
2011        }
2012        return undefined;
2013    }
2014
2015    export function isTextWhiteSpaceLike(text: string, startPos: number, endPos: number): boolean {
2016        for (let i = startPos; i < endPos; i++) {
2017            if (!isWhiteSpaceLike(text.charCodeAt(i))) {
2018                return false;
2019            }
2020        }
2021
2022        return true;
2023    }
2024
2025    // #endregion
2026
2027    // Display-part writer helpers
2028    // #region
2029    export function isFirstDeclarationOfSymbolParameter(symbol: Symbol) {
2030        return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter;
2031    }
2032
2033    const displayPartWriter = getDisplayPartWriter();
2034    function getDisplayPartWriter(): DisplayPartsSymbolWriter {
2035        const absoluteMaximumLength = defaultMaximumTruncationLength * 10; // A hard cutoff to avoid overloading the messaging channel in worst-case scenarios
2036        let displayParts: SymbolDisplayPart[];
2037        let lineStart: boolean;
2038        let indent: number;
2039        let length: number;
2040
2041        resetWriter();
2042        const unknownWrite = (text: string) => writeKind(text, SymbolDisplayPartKind.text);
2043        return {
2044            displayParts: () => {
2045                const finalText = displayParts.length && displayParts[displayParts.length - 1].text;
2046                if (length > absoluteMaximumLength && finalText && finalText !== "...") {
2047                    if (!isWhiteSpaceLike(finalText.charCodeAt(finalText.length - 1))) {
2048                        displayParts.push(displayPart(" ", SymbolDisplayPartKind.space));
2049                    }
2050                    displayParts.push(displayPart("...", SymbolDisplayPartKind.punctuation));
2051                }
2052                return displayParts;
2053            },
2054            writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
2055            writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
2056            writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
2057            writeTrailingSemicolon: text => writeKind(text, SymbolDisplayPartKind.punctuation),
2058            writeSpace: text => writeKind(text, SymbolDisplayPartKind.space),
2059            writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
2060            writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName),
2061            writeProperty: text => writeKind(text, SymbolDisplayPartKind.propertyName),
2062            writeLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
2063            writeSymbol,
2064            writeLine,
2065            write: unknownWrite,
2066            writeComment: unknownWrite,
2067            getText: () => "",
2068            getTextPos: () => 0,
2069            getColumn: () => 0,
2070            getLine: () => 0,
2071            isAtStartOfLine: () => false,
2072            hasTrailingWhitespace: () => false,
2073            hasTrailingComment: () => false,
2074            rawWrite: notImplemented,
2075            getIndent: () => indent,
2076            increaseIndent: () => { indent++; },
2077            decreaseIndent: () => { indent--; },
2078            clear: resetWriter,
2079            trackSymbol: noop,
2080            reportInaccessibleThisError: noop,
2081            reportInaccessibleUniqueSymbolError: noop,
2082            reportPrivateInBaseOfClassExpression: noop,
2083        };
2084
2085        function writeIndent() {
2086            if (length > absoluteMaximumLength) return;
2087            if (lineStart) {
2088                const indentString = getIndentString(indent);
2089                if (indentString) {
2090                    length += indentString.length;
2091                    displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space));
2092                }
2093                lineStart = false;
2094            }
2095        }
2096
2097        function writeKind(text: string, kind: SymbolDisplayPartKind) {
2098            if (length > absoluteMaximumLength) return;
2099            writeIndent();
2100            length += text.length;
2101            displayParts.push(displayPart(text, kind));
2102        }
2103
2104        function writeSymbol(text: string, symbol: Symbol) {
2105            if (length > absoluteMaximumLength) return;
2106            writeIndent();
2107            length += text.length;
2108            displayParts.push(symbolPart(text, symbol));
2109        }
2110
2111        function writeLine() {
2112            if (length > absoluteMaximumLength) return;
2113            length += 1;
2114            displayParts.push(lineBreakPart());
2115            lineStart = true;
2116        }
2117
2118        function resetWriter() {
2119            displayParts = [];
2120            lineStart = true;
2121            indent = 0;
2122            length = 0;
2123        }
2124    }
2125
2126    export function symbolPart(text: string, symbol: Symbol) {
2127        return displayPart(text, displayPartKind(symbol));
2128
2129        function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
2130            const flags = symbol.flags;
2131
2132            if (flags & SymbolFlags.Variable) {
2133                return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName;
2134            }
2135            else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
2136            else if (flags & SymbolFlags.GetAccessor) { return SymbolDisplayPartKind.propertyName; }
2137            else if (flags & SymbolFlags.SetAccessor) { return SymbolDisplayPartKind.propertyName; }
2138            else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
2139            else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
2140            else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
2141            else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
2142            else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
2143            else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
2144            else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
2145            else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
2146            else if (flags & SymbolFlags.TypeAlias) { return SymbolDisplayPartKind.aliasName; }
2147            else if (flags & SymbolFlags.Alias) { return SymbolDisplayPartKind.aliasName; }
2148
2149            return SymbolDisplayPartKind.text;
2150        }
2151    }
2152
2153    export function displayPart(text: string, kind: SymbolDisplayPartKind): SymbolDisplayPart {
2154        return { text, kind: SymbolDisplayPartKind[kind] };
2155    }
2156
2157    export function spacePart() {
2158        return displayPart(" ", SymbolDisplayPartKind.space);
2159    }
2160
2161    export function keywordPart(kind: SyntaxKind) {
2162        return displayPart(tokenToString(kind)!, SymbolDisplayPartKind.keyword);
2163    }
2164
2165    export function punctuationPart(kind: SyntaxKind) {
2166        return displayPart(tokenToString(kind)!, SymbolDisplayPartKind.punctuation);
2167    }
2168
2169    export function operatorPart(kind: SyntaxKind) {
2170        return displayPart(tokenToString(kind)!, SymbolDisplayPartKind.operator);
2171    }
2172
2173    export function textOrKeywordPart(text: string) {
2174        const kind = stringToToken(text);
2175        return kind === undefined
2176            ? textPart(text)
2177            : keywordPart(kind);
2178    }
2179
2180    export function textPart(text: string) {
2181        return displayPart(text, SymbolDisplayPartKind.text);
2182    }
2183
2184    const carriageReturnLineFeed = "\r\n";
2185    /**
2186     * The default is CRLF.
2187     */
2188    export function getNewLineOrDefaultFromHost(host: FormattingHost, formatSettings?: FormatCodeSettings) {
2189        return formatSettings?.newLineCharacter ||
2190            host.getNewLine?.() ||
2191            carriageReturnLineFeed;
2192    }
2193
2194    export function lineBreakPart() {
2195        return displayPart("\n", SymbolDisplayPartKind.lineBreak);
2196    }
2197
2198    export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
2199        try {
2200            writeDisplayParts(displayPartWriter);
2201            return displayPartWriter.displayParts();
2202        }
2203        finally {
2204            displayPartWriter.clear();
2205        }
2206    }
2207
2208    export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.None): SymbolDisplayPart[] {
2209        return mapToDisplayParts(writer => {
2210            typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer);
2211        });
2212    }
2213
2214    export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.None): SymbolDisplayPart[] {
2215        return mapToDisplayParts(writer => {
2216            typeChecker.writeSymbol(symbol, enclosingDeclaration, meaning, flags | SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope, writer);
2217        });
2218    }
2219
2220    export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.None): SymbolDisplayPart[] {
2221        flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers;
2222        return mapToDisplayParts(writer => {
2223            typechecker.writeSignature(signature, enclosingDeclaration, flags, /*signatureKind*/ undefined, writer);
2224        });
2225    }
2226
2227    export function isImportOrExportSpecifierName(location: Node): location is Identifier {
2228        return !!location.parent && isImportOrExportSpecifier(location.parent) && location.parent.propertyName === location;
2229    }
2230
2231    export function getScriptKind(fileName: string, host: LanguageServiceHost): ScriptKind {
2232        // First check to see if the script kind was specified by the host. Chances are the host
2233        // may override the default script kind for the file extension.
2234        return ensureScriptKind(fileName, host.getScriptKind && host.getScriptKind(fileName));
2235    }
2236
2237    export function getSymbolTarget(symbol: Symbol, checker: TypeChecker): Symbol {
2238        let next: Symbol = symbol;
2239        while (isAliasSymbol(next) || (isTransientSymbol(next) && next.target)) {
2240            if (isTransientSymbol(next) && next.target) {
2241                next = next.target;
2242            }
2243            else {
2244                next = skipAlias(next, checker);
2245            }
2246        }
2247        return next;
2248    }
2249
2250    function isTransientSymbol(symbol: Symbol): symbol is TransientSymbol {
2251        return (symbol.flags & SymbolFlags.Transient) !== 0;
2252    }
2253
2254    function isAliasSymbol(symbol: Symbol): boolean {
2255        return (symbol.flags & SymbolFlags.Alias) !== 0;
2256    }
2257
2258    export function getUniqueSymbolId(symbol: Symbol, checker: TypeChecker) {
2259        return getSymbolId(skipAlias(symbol, checker));
2260    }
2261
2262    export function getFirstNonSpaceCharacterPosition(text: string, position: number) {
2263        while (isWhiteSpaceLike(text.charCodeAt(position))) {
2264            position += 1;
2265        }
2266        return position;
2267    }
2268
2269    export function getPrecedingNonSpaceCharacterPosition(text: string, position: number) {
2270        while (position > -1 && isWhiteSpaceSingleLine(text.charCodeAt(position))) {
2271            position -= 1;
2272        }
2273        return position + 1;
2274    }
2275
2276    /**
2277     * Creates a deep, memberwise clone of a node with no source map location.
2278     *
2279     * WARNING: This is an expensive operation and is only intended to be used in refactorings
2280     * and code fixes (because those are triggered by explicit user actions).
2281     */
2282    export function getSynthesizedDeepClone<T extends Node | undefined>(node: T, includeTrivia = true): T {
2283        const clone = node && getSynthesizedDeepCloneWorker(node as NonNullable<T>);
2284        if (clone && !includeTrivia) suppressLeadingAndTrailingTrivia(clone);
2285        return clone;
2286    }
2287
2288    export function getSynthesizedDeepCloneWithReplacements<T extends Node>(
2289        node: T,
2290        includeTrivia: boolean,
2291        replaceNode: (node: Node) => Node | undefined
2292    ): T {
2293        let clone = replaceNode(node);
2294        if (clone) {
2295            setOriginalNode(clone, node);
2296        }
2297        else {
2298            clone = getSynthesizedDeepCloneWorker(node as NonNullable<T>, replaceNode);
2299        }
2300
2301        if (clone && !includeTrivia) suppressLeadingAndTrailingTrivia(clone);
2302        return clone as T;
2303    }
2304
2305    function getSynthesizedDeepCloneWorker<T extends Node>(node: T, replaceNode?: (node: Node) => Node | undefined): T {
2306        const visited = replaceNode ?
2307            visitEachChild(node, n => getSynthesizedDeepCloneWithReplacements(n, /*includeTrivia*/ true, replaceNode), nullTransformationContext) :
2308            visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext);
2309
2310        if (visited === node) {
2311            // This only happens for leaf nodes - internal nodes always see their children change.
2312            const clone =
2313                isStringLiteral(node) ? setOriginalNode(factory.createStringLiteralFromNode(node), node) as Node as T :
2314                    isNumericLiteral(node) ? setOriginalNode(factory.createNumericLiteral(node.text, node.numericLiteralFlags), node) as Node as T :
2315                        factory.cloneNode(node);
2316            return setTextRange(clone, node);
2317        }
2318
2319        // PERF: As an optimization, rather than calling getSynthesizedClone, we'll update
2320        // the new node created by visitEachChild with the extra changes getSynthesizedClone
2321        // would have made.
2322        (visited as Mutable<T>).parent = undefined!;
2323        return visited;
2324    }
2325
2326    export function getSynthesizedDeepClones<T extends Node>(nodes: NodeArray<T>, includeTrivia?: boolean): NodeArray<T>;
2327    export function getSynthesizedDeepClones<T extends Node>(nodes: NodeArray<T> | undefined, includeTrivia?: boolean): NodeArray<T> | undefined;
2328    export function getSynthesizedDeepClones<T extends Node>(nodes: NodeArray<T> | undefined, includeTrivia = true): NodeArray<T> | undefined {
2329        return nodes && factory.createNodeArray(nodes.map(n => getSynthesizedDeepClone(n, includeTrivia)), nodes.hasTrailingComma);
2330    }
2331
2332    export function getSynthesizedDeepClonesWithReplacements<T extends Node>(
2333        nodes: NodeArray<T>,
2334        includeTrivia: boolean,
2335        replaceNode: (node: Node) => Node | undefined
2336    ): NodeArray<T> {
2337        return factory.createNodeArray(nodes.map(n => getSynthesizedDeepCloneWithReplacements(n, includeTrivia, replaceNode)), nodes.hasTrailingComma);
2338    }
2339
2340    /**
2341     * Sets EmitFlags to suppress leading and trailing trivia on the node.
2342     */
2343    export function suppressLeadingAndTrailingTrivia(node: Node) {
2344        suppressLeadingTrivia(node);
2345        suppressTrailingTrivia(node);
2346    }
2347
2348    /**
2349     * Sets EmitFlags to suppress leading trivia on the node.
2350     */
2351    export function suppressLeadingTrivia(node: Node) {
2352        addEmitFlagsRecursively(node, EmitFlags.NoLeadingComments, getFirstChild);
2353    }
2354
2355    /**
2356     * Sets EmitFlags to suppress trailing trivia on the node.
2357     */
2358    export function suppressTrailingTrivia(node: Node) {
2359        addEmitFlagsRecursively(node, EmitFlags.NoTrailingComments, getLastChild);
2360    }
2361
2362    export function copyComments(sourceNode: Node, targetNode: Node) {
2363        const sourceFile = sourceNode.getSourceFile();
2364        const text = sourceFile.text;
2365        if (hasLeadingLineBreak(sourceNode, text)) {
2366            copyLeadingComments(sourceNode, targetNode, sourceFile);
2367        }
2368        else {
2369            copyTrailingAsLeadingComments(sourceNode, targetNode, sourceFile);
2370        }
2371        copyTrailingComments(sourceNode, targetNode, sourceFile);
2372    }
2373
2374    function hasLeadingLineBreak(node: Node, text: string) {
2375        const start = node.getFullStart();
2376        const end = node.getStart();
2377        for (let i = start; i < end; i++) {
2378            if (text.charCodeAt(i) === CharacterCodes.lineFeed) return true;
2379        }
2380        return false;
2381    }
2382
2383    function addEmitFlagsRecursively(node: Node, flag: EmitFlags, getChild: (n: Node) => Node | undefined) {
2384        addEmitFlags(node, flag);
2385        const child = getChild(node);
2386        if (child) addEmitFlagsRecursively(child, flag, getChild);
2387    }
2388
2389    function getFirstChild(node: Node): Node | undefined {
2390        return node.forEachChild(child => child);
2391    }
2392
2393    export function getUniqueName(baseName: string, sourceFile: SourceFile): string {
2394        let nameText = baseName;
2395        for (let i = 1; !isFileLevelUniqueName(sourceFile, nameText); i++) {
2396            nameText = `${baseName}_${i}`;
2397        }
2398        return nameText;
2399    }
2400
2401    /**
2402     * @return The index of the (only) reference to the extracted symbol.  We want the cursor
2403     * to be on the reference, rather than the declaration, because it's closer to where the
2404     * user was before extracting it.
2405     */
2406    export function getRenameLocation(edits: readonly FileTextChanges[], renameFilename: string, name: string, preferLastLocation: boolean): number {
2407        let delta = 0;
2408        let lastPos = -1;
2409        for (const { fileName, textChanges } of edits) {
2410            Debug.assert(fileName === renameFilename);
2411            for (const change of textChanges) {
2412                const { span, newText } = change;
2413                const index = indexInTextChange(newText, name);
2414                if (index !== -1) {
2415                    lastPos = span.start + delta + index;
2416
2417                    // If the reference comes first, return immediately.
2418                    if (!preferLastLocation) {
2419                        return lastPos;
2420                    }
2421                }
2422                delta += newText.length - span.length;
2423            }
2424        }
2425
2426        // If the declaration comes first, return the position of the last occurrence.
2427        Debug.assert(preferLastLocation);
2428        Debug.assert(lastPos >= 0);
2429        return lastPos;
2430    }
2431
2432    export function copyLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) {
2433        forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment));
2434    }
2435
2436
2437    export function copyTrailingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) {
2438        forEachTrailingCommentRange(sourceFile.text, sourceNode.end, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticTrailingComment));
2439    }
2440
2441    /**
2442     * This function copies the trailing comments for the token that comes before `sourceNode`, as leading comments of `targetNode`.
2443     * This is useful because sometimes a comment that refers to `sourceNode` will be a leading comment for `sourceNode`, according to the
2444     * notion of trivia ownership, and instead will be a trailing comment for the token before `sourceNode`, e.g.:
2445     * `function foo(\* not leading comment for a *\ a: string) {}`
2446     * The comment refers to `a` but belongs to the `(` token, but we might want to copy it.
2447     */
2448    export function copyTrailingAsLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) {
2449        forEachTrailingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment));
2450    }
2451
2452    function getAddCommentsFunction(targetNode: Node, sourceFile: SourceFile, commentKind: CommentKind | undefined, hasTrailingNewLine: boolean | undefined, cb: (node: Node, kind: CommentKind, text: string, hasTrailingNewLine?: boolean) => void) {
2453        return (pos: number, end: number, kind: CommentKind, htnl: boolean) => {
2454            if (kind === SyntaxKind.MultiLineCommentTrivia) {
2455                // Remove leading /*
2456                pos += 2;
2457                // Remove trailing */
2458                end -= 2;
2459            }
2460            else {
2461                // Remove leading //
2462                pos += 2;
2463            }
2464            cb(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl);
2465        };
2466    }
2467
2468    function indexInTextChange(change: string, name: string): number {
2469        if (startsWith(change, name)) return 0;
2470        // Add a " " to avoid references inside words
2471        let idx = change.indexOf(" " + name);
2472        if (idx === -1) idx = change.indexOf("." + name);
2473        if (idx === -1) idx = change.indexOf('"' + name);
2474        return idx === -1 ? -1 : idx + 1;
2475    }
2476
2477    /* @internal */
2478    export function needsParentheses(expression: Expression) {
2479        return isBinaryExpression(expression) && expression.operatorToken.kind === SyntaxKind.CommaToken || isObjectLiteralExpression(expression);
2480    }
2481
2482    export function getContextualTypeFromParent(node: Expression, checker: TypeChecker): Type | undefined {
2483        const { parent } = node;
2484        switch (parent.kind) {
2485            case SyntaxKind.NewExpression:
2486                return checker.getContextualType(parent as NewExpression);
2487            case SyntaxKind.BinaryExpression: {
2488                const { left, operatorToken, right } = parent as BinaryExpression;
2489                return isEqualityOperatorKind(operatorToken.kind)
2490                    ? checker.getTypeAtLocation(node === right ? left : right)
2491                    : checker.getContextualType(node);
2492            }
2493            case SyntaxKind.CaseClause:
2494                return (parent as CaseClause).expression === node ? getSwitchedType(parent as CaseClause, checker) : undefined;
2495            default:
2496                return checker.getContextualType(node);
2497        }
2498    }
2499
2500    export function quote(sourceFile: SourceFile, preferences: UserPreferences, text: string): string {
2501        // Editors can pass in undefined or empty string - we want to infer the preference in those cases.
2502        const quotePreference = getQuotePreference(sourceFile, preferences);
2503        const quoted = JSON.stringify(text);
2504        return quotePreference === QuotePreference.Single ? `'${stripQuotes(quoted).replace(/'/g, "\\'").replace(/\\"/g, '"')}'` : quoted;
2505    }
2506
2507    export function isEqualityOperatorKind(kind: SyntaxKind): kind is EqualityOperator {
2508        switch (kind) {
2509            case SyntaxKind.EqualsEqualsEqualsToken:
2510            case SyntaxKind.EqualsEqualsToken:
2511            case SyntaxKind.ExclamationEqualsEqualsToken:
2512            case SyntaxKind.ExclamationEqualsToken:
2513                return true;
2514            default:
2515                return false;
2516        }
2517    }
2518
2519    export function isStringLiteralOrTemplate(node: Node): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression {
2520        switch (node.kind) {
2521            case SyntaxKind.StringLiteral:
2522            case SyntaxKind.NoSubstitutionTemplateLiteral:
2523            case SyntaxKind.TemplateExpression:
2524            case SyntaxKind.TaggedTemplateExpression:
2525                return true;
2526            default:
2527                return false;
2528        }
2529    }
2530
2531    export function hasIndexSignature(type: Type): boolean {
2532        return !!type.getStringIndexType() || !!type.getNumberIndexType();
2533    }
2534
2535    export function getSwitchedType(caseClause: CaseClause, checker: TypeChecker): Type | undefined {
2536        return checker.getTypeAtLocation(caseClause.parent.parent.expression);
2537    }
2538
2539    export const ANONYMOUS = "anonymous function";
2540
2541    export function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, program: Program, host: LanguageServiceHost): TypeNode | undefined {
2542        const checker = program.getTypeChecker();
2543        let typeIsAccessible = true;
2544        const notAccessible = () => { typeIsAccessible = false; };
2545        const res = checker.typeToTypeNode(type, enclosingScope, NodeBuilderFlags.NoTruncation, {
2546            trackSymbol: (symbol, declaration, meaning) => {
2547                typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible;
2548            },
2549            reportInaccessibleThisError: notAccessible,
2550            reportPrivateInBaseOfClassExpression: notAccessible,
2551            reportInaccessibleUniqueSymbolError: notAccessible,
2552            moduleResolverHost: getModuleSpecifierResolverHost(program, host)
2553        });
2554        return typeIsAccessible ? res : undefined;
2555    }
2556
2557    export function syntaxRequiresTrailingCommaOrSemicolonOrASI(kind: SyntaxKind) {
2558        return kind === SyntaxKind.CallSignature
2559            || kind === SyntaxKind.ConstructSignature
2560            || kind === SyntaxKind.IndexSignature
2561            || kind === SyntaxKind.PropertySignature
2562            || kind === SyntaxKind.MethodSignature;
2563    }
2564
2565    export function syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI(kind: SyntaxKind) {
2566        return kind === SyntaxKind.FunctionDeclaration
2567            || kind === SyntaxKind.Constructor
2568            || kind === SyntaxKind.MethodDeclaration
2569            || kind === SyntaxKind.GetAccessor
2570            || kind === SyntaxKind.SetAccessor;
2571    }
2572
2573    export function syntaxRequiresTrailingModuleBlockOrSemicolonOrASI(kind: SyntaxKind) {
2574        return kind === SyntaxKind.ModuleDeclaration;
2575    }
2576
2577    export function syntaxRequiresTrailingSemicolonOrASI(kind: SyntaxKind) {
2578        return kind === SyntaxKind.VariableStatement
2579            || kind === SyntaxKind.ExpressionStatement
2580            || kind === SyntaxKind.DoStatement
2581            || kind === SyntaxKind.ContinueStatement
2582            || kind === SyntaxKind.BreakStatement
2583            || kind === SyntaxKind.ReturnStatement
2584            || kind === SyntaxKind.ThrowStatement
2585            || kind === SyntaxKind.DebuggerStatement
2586            || kind === SyntaxKind.PropertyDeclaration
2587            || kind === SyntaxKind.TypeAliasDeclaration
2588            || kind === SyntaxKind.ImportDeclaration
2589            || kind === SyntaxKind.ImportEqualsDeclaration
2590            || kind === SyntaxKind.ExportDeclaration
2591            || kind === SyntaxKind.NamespaceExportDeclaration
2592            || kind === SyntaxKind.ExportAssignment;
2593    }
2594
2595    export const syntaxMayBeASICandidate = or(
2596        syntaxRequiresTrailingCommaOrSemicolonOrASI,
2597        syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI,
2598        syntaxRequiresTrailingModuleBlockOrSemicolonOrASI,
2599        syntaxRequiresTrailingSemicolonOrASI);
2600
2601    function nodeIsASICandidate(node: Node, sourceFile: SourceFileLike): boolean {
2602        const lastToken = node.getLastToken(sourceFile);
2603        if (lastToken && lastToken.kind === SyntaxKind.SemicolonToken) {
2604            return false;
2605        }
2606
2607        if (syntaxRequiresTrailingCommaOrSemicolonOrASI(node.kind)) {
2608            if (lastToken && lastToken.kind === SyntaxKind.CommaToken) {
2609                return false;
2610            }
2611        }
2612        else if (syntaxRequiresTrailingModuleBlockOrSemicolonOrASI(node.kind)) {
2613            const lastChild = last(node.getChildren(sourceFile));
2614            if (lastChild && isModuleBlock(lastChild)) {
2615                return false;
2616            }
2617        }
2618        else if (syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI(node.kind)) {
2619            const lastChild = last(node.getChildren(sourceFile));
2620            if (lastChild && isFunctionBlock(lastChild)) {
2621                return false;
2622            }
2623        }
2624        else if (!syntaxRequiresTrailingSemicolonOrASI(node.kind)) {
2625            return false;
2626        }
2627
2628        // See comment in parser’s `parseDoStatement`
2629        if (node.kind === SyntaxKind.DoStatement) {
2630            return true;
2631        }
2632
2633        const topNode = findAncestor(node, ancestor => !ancestor.parent)!;
2634        const nextToken = findNextToken(node, topNode, sourceFile);
2635        if (!nextToken || nextToken.kind === SyntaxKind.CloseBraceToken) {
2636            return true;
2637        }
2638
2639        const startLine = sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line;
2640        const endLine = sourceFile.getLineAndCharacterOfPosition(nextToken.getStart(sourceFile)).line;
2641        return startLine !== endLine;
2642    }
2643
2644    export function positionIsASICandidate(pos: number, context: Node, sourceFile: SourceFileLike): boolean {
2645        const contextAncestor = findAncestor(context, ancestor => {
2646            if (ancestor.end !== pos) {
2647                return "quit";
2648            }
2649            return syntaxMayBeASICandidate(ancestor.kind);
2650        });
2651
2652        return !!contextAncestor && nodeIsASICandidate(contextAncestor, sourceFile);
2653    }
2654
2655    export function probablyUsesSemicolons(sourceFile: SourceFile): boolean {
2656        let withSemicolon = 0;
2657        let withoutSemicolon = 0;
2658        const nStatementsToObserve = 5;
2659        forEachChild(sourceFile, function visit(node): boolean | undefined {
2660            if (syntaxRequiresTrailingSemicolonOrASI(node.kind)) {
2661                const lastToken = node.getLastToken(sourceFile);
2662                if (lastToken && lastToken.kind === SyntaxKind.SemicolonToken) {
2663                    withSemicolon++;
2664                }
2665                else {
2666                    withoutSemicolon++;
2667                }
2668            }
2669            if (withSemicolon + withoutSemicolon >= nStatementsToObserve) {
2670                return true;
2671            }
2672
2673            return forEachChild(node, visit);
2674        });
2675
2676        // One statement missing a semicolon isn’t sufficient evidence to say the user
2677        // doesn’t want semicolons, because they may not even be done writing that statement.
2678        if (withSemicolon === 0 && withoutSemicolon <= 1) {
2679            return true;
2680        }
2681
2682        // If even 2/5 places have a semicolon, the user probably wants semicolons
2683        return withSemicolon / withoutSemicolon > 1 / nStatementsToObserve;
2684    }
2685
2686    export function tryGetDirectories(host: Pick<LanguageServiceHost, "getDirectories">, directoryName: string): string[] {
2687        return tryIOAndConsumeErrors(host, host.getDirectories, directoryName) || [];
2688    }
2689
2690    export function tryReadDirectory(host: Pick<LanguageServiceHost, "readDirectory">, path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[]): readonly string[] {
2691        return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include) || emptyArray;
2692    }
2693
2694    export function tryFileExists(host: Pick<LanguageServiceHost, "fileExists">, path: string): boolean {
2695        return tryIOAndConsumeErrors(host, host.fileExists, path);
2696    }
2697
2698    export function tryDirectoryExists(host: LanguageServiceHost, path: string): boolean {
2699        return tryAndIgnoreErrors(() => directoryProbablyExists(path, host)) || false;
2700    }
2701
2702    export function tryAndIgnoreErrors<T>(cb: () => T): T | undefined {
2703        try { return cb(); }
2704        catch { return undefined; }
2705    }
2706
2707    export function tryIOAndConsumeErrors<T>(host: unknown, toApply: ((...a: any[]) => T) | undefined, ...args: any[]) {
2708        return tryAndIgnoreErrors(() => toApply && toApply.apply(host, args));
2709    }
2710
2711    export function findPackageJsons(startDirectory: string, host: LanguageServiceHost, stopDirectory?: string): string[] {
2712        const paths: string[] = [];
2713        forEachAncestorDirectory(startDirectory, ancestor => {
2714            if (ancestor === stopDirectory) {
2715                return true;
2716            }
2717            const currentConfigPath = combinePaths(ancestor, getPackageJsonByPMType(host.getCompilationSettings().packageManagerType));
2718            if (tryFileExists(host, currentConfigPath)) {
2719                paths.push(currentConfigPath);
2720            }
2721        });
2722        return paths;
2723    }
2724
2725    export function findPackageJson(directory: string, host: LanguageServiceHost): string | undefined {
2726        let packageJson: string | undefined;
2727        forEachAncestorDirectory(directory, ancestor => {
2728            const moduleType: string = getModuleByPMType(host.getCompilationSettings().packageManagerType);
2729            const packageJsonType: string = getPackageJsonByPMType(host.getCompilationSettings().packageManagerType);
2730            if (ancestor === moduleType) return true;
2731            packageJson = findConfigFile(ancestor, (f) => tryFileExists(host, f), packageJsonType);
2732            if (packageJson) {
2733                return true; // break out
2734            }
2735        });
2736        return packageJson;
2737    }
2738
2739    export function getPackageJsonsVisibleToFile(fileName: string, host: LanguageServiceHost): readonly PackageJsonInfo[] {
2740        if (!host.fileExists) {
2741            return [];
2742        }
2743        const packageJsons: PackageJsonInfo[] = [];
2744        forEachAncestorDirectory(getDirectoryPath(fileName), ancestor => {
2745            const packageJsonFileName = combinePaths(ancestor, getPackageJsonByPMType(host.getCompilationSettings().packageManagerType));
2746            if (host.fileExists!(packageJsonFileName)) {
2747                const info = createPackageJsonInfo(packageJsonFileName, host);
2748                if (info) {
2749                    packageJsons.push(info);
2750                }
2751            }
2752        });
2753
2754        return packageJsons;
2755    }
2756
2757    export function createPackageJsonInfo(fileName: string, host: { readFile?(fileName: string): string | undefined }): PackageJsonInfo | undefined {
2758        if (!host.readFile) {
2759            return undefined;
2760        }
2761
2762        type PackageJsonRaw = Record<typeof dependencyKeys[number], Record<string, string> | undefined>;
2763        const dependencyKeys = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"] as const;
2764        const stringContent = host.readFile(fileName) || "";
2765        const content = tryParseJson(stringContent) as PackageJsonRaw | undefined;
2766        const info: Pick<PackageJsonInfo, typeof dependencyKeys[number]> = {};
2767        if (content) {
2768            for (const key of dependencyKeys) {
2769                const dependencies = content[key];
2770                if (!dependencies) {
2771                    continue;
2772                }
2773                const dependencyMap = new Map<string, string>();
2774                for (const packageName in dependencies) {
2775                    dependencyMap.set(packageName, dependencies[packageName]);
2776                }
2777                info[key] = dependencyMap;
2778            }
2779        }
2780
2781        const dependencyGroups = [
2782            [PackageJsonDependencyGroup.Dependencies, info.dependencies],
2783            [PackageJsonDependencyGroup.DevDependencies, info.devDependencies],
2784            [PackageJsonDependencyGroup.OptionalDependencies, info.optionalDependencies],
2785            [PackageJsonDependencyGroup.PeerDependencies, info.peerDependencies],
2786        ] as const;
2787
2788        return {
2789            ...info,
2790            parseable: !!content,
2791            fileName,
2792            get,
2793            has(dependencyName, inGroups) {
2794                return !!get(dependencyName, inGroups);
2795            },
2796        };
2797
2798        function get(dependencyName: string, inGroups = PackageJsonDependencyGroup.All) {
2799            for (const [group, deps] of dependencyGroups) {
2800                if (deps && (inGroups & group)) {
2801                    const dep = deps.get(dependencyName);
2802                    if (dep !== undefined) {
2803                        return dep;
2804                    }
2805                }
2806            }
2807        }
2808    }
2809
2810    function tryParseJson(text: string) {
2811        try {
2812            return JSON.parse(text);
2813        }
2814        catch {
2815            return undefined;
2816        }
2817    }
2818
2819    export function consumesNodeCoreModules(sourceFile: SourceFile): boolean {
2820        return some(sourceFile.imports, ({ text }) => JsTyping.nodeCoreModules.has(text));
2821    }
2822
2823    export function isInsideNodeModules(fileOrDirectory: string): boolean {
2824        return contains(getPathComponents(fileOrDirectory), "node_modules");
2825    }
2826
2827    export function isDiagnosticWithLocation(diagnostic: Diagnostic): diagnostic is DiagnosticWithLocation {
2828        return diagnostic.file !== undefined && diagnostic.start !== undefined && diagnostic.length !== undefined;
2829    }
2830
2831    export function findDiagnosticForNode(node: Node, sortedFileDiagnostics: readonly Diagnostic[]): DiagnosticWithLocation | undefined {
2832        const span: Partial<TextSpan> = createTextSpanFromNode(node);
2833        const index = binarySearchKey(sortedFileDiagnostics, span, identity, compareTextSpans);
2834        if (index >= 0) {
2835            const diagnostic = sortedFileDiagnostics[index];
2836            Debug.assertEqual(diagnostic.file, node.getSourceFile(), "Diagnostics proided to 'findDiagnosticForNode' must be from a single SourceFile");
2837            return cast(diagnostic, isDiagnosticWithLocation);
2838        }
2839    }
2840
2841    export function getDiagnosticsWithinSpan(span: TextSpan, sortedFileDiagnostics: readonly Diagnostic[]): readonly DiagnosticWithLocation[] {
2842        let index = binarySearchKey(sortedFileDiagnostics, span.start, diag => diag.start, compareValues);
2843        if (index < 0) {
2844            index = ~index;
2845        }
2846        while (sortedFileDiagnostics[index - 1]?.start === span.start) {
2847            index--;
2848        }
2849
2850        const result: DiagnosticWithLocation[] = [];
2851        const end = textSpanEnd(span);
2852        while (true) {
2853            const diagnostic = tryCast(sortedFileDiagnostics[index], isDiagnosticWithLocation);
2854            if (!diagnostic || diagnostic.start > end) {
2855                break;
2856            }
2857            if (textSpanContainsTextSpan(span, diagnostic)) {
2858                result.push(diagnostic);
2859            }
2860            index++;
2861        }
2862
2863        return result;
2864    }
2865
2866    /* @internal */
2867    export function getRefactorContextSpan({ startPosition, endPosition }: RefactorContext): TextSpan {
2868        return createTextSpanFromBounds(startPosition, endPosition === undefined ? startPosition : endPosition);
2869    }
2870
2871    /**
2872     * If the provided value is an array, the mapping function is applied to each element; otherwise, the mapping function is applied
2873     * to the provided value itself.
2874     */
2875    export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[], f: (x: T, i: number) => U): U | U[];
2876    export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U): U | U[] | undefined;
2877    export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[], f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U;
2878    export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U | undefined;
2879    export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U | U[] = identity): U | U[] | undefined {
2880        return valueOrArray ? isArray(valueOrArray) ? resultSelector(map(valueOrArray, f)) : f(valueOrArray, 0) : undefined;
2881    }
2882
2883    /**
2884     * If the provided value is an array, the first element of the array is returned; otherwise, the provided value is returned instead.
2885     */
2886    export function firstOrOnly<T>(valueOrArray: T | readonly T[]): T {
2887        return isArray(valueOrArray) ? first(valueOrArray) : valueOrArray;
2888    }
2889
2890    export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined) {
2891        if (!(symbol.flags & SymbolFlags.Transient) && (symbol.escapedName === InternalSymbolName.ExportEquals || symbol.escapedName === InternalSymbolName.Default)) {
2892            // Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase.
2893            return firstDefined(symbol.declarations, d => isExportAssignment(d) ? tryCast(skipOuterExpressions(d.expression), isIdentifier)?.text : undefined)
2894                || codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget);
2895        }
2896        return symbol.name;
2897    }
2898
2899    function getSymbolParentOrFail(symbol: Symbol) {
2900        return Debug.checkDefined(
2901            symbol.parent,
2902            `Symbol parent was undefined. Flags: ${Debug.formatSymbolFlags(symbol.flags)}. ` +
2903            `Declarations: ${symbol.declarations?.map(d => {
2904                const kind = Debug.formatSyntaxKind(d.kind);
2905                const inJS = isInJSFile(d);
2906                const { expression } = d as any;
2907                return (inJS ? "[JS]" : "") + kind + (expression ? ` (expression: ${Debug.formatSyntaxKind(expression.kind)})` : "");
2908            }).join(", ")}.`);
2909    }
2910
2911    /**
2912     * Useful to check whether a string contains another string at a specific index
2913     * without allocating another string or traversing the entire contents of the outer string.
2914     *
2915     * This function is useful in place of either of the following:
2916     *
2917     * ```ts
2918     * // Allocates
2919     * haystack.substr(startIndex, needle.length) === needle
2920     *
2921     * // Full traversal
2922     * haystack.indexOf(needle, startIndex) === startIndex
2923     * ```
2924     *
2925     * @param haystack The string that potentially contains `needle`.
2926     * @param needle The string whose content might sit within `haystack`.
2927     * @param startIndex The index within `haystack` to start searching for `needle`.
2928     */
2929    export function stringContainsAt(haystack: string, needle: string, startIndex: number) {
2930        const needleLength = needle.length;
2931        if (needleLength + startIndex > haystack.length) {
2932            return false;
2933        }
2934        for (let i = 0; i < needleLength; i++) {
2935            if (needle.charCodeAt(i) !== haystack.charCodeAt(i + startIndex)) return false;
2936        }
2937        return true;
2938    }
2939
2940    export function startsWithUnderscore(name: string): boolean {
2941        return name.charCodeAt(0) === CharacterCodes._;
2942    }
2943
2944    export function isGlobalDeclaration(declaration: Declaration) {
2945        return !isNonGlobalDeclaration(declaration);
2946    }
2947
2948    export function isNonGlobalDeclaration(declaration: Declaration) {
2949        const sourceFile = declaration.getSourceFile();
2950        // If the file is not a module, the declaration is global
2951        if (!sourceFile.externalModuleIndicator && !sourceFile.commonJsModuleIndicator) {
2952            return false;
2953        }
2954        // If the file is a module written in TypeScript, it still might be in a `declare global` augmentation
2955        return isInJSFile(declaration) || !findAncestor(declaration, isGlobalScopeAugmentation);
2956    }
2957
2958    export function isVirtualConstructor(checker: TypeChecker, symbol: Symbol, node: Node): boolean {
2959        const symbolName = checker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
2960        const symbolKind = SymbolDisplay.getSymbolKind(checker, symbol, node);
2961        if (node.virtual && symbolName === InternalSymbolName.Constructor && symbolKind === ScriptElementKind.constructorImplementationElement) {
2962            return true;
2963        }
2964        return false;
2965    }
2966
2967    // #endregion
2968}
2969