• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import * as FourSlash from "./_namespaces/FourSlash";
2import * as ts from "./_namespaces/ts";
3
4export class Test {
5    constructor(private state: FourSlash.TestState) {
6    }
7
8    public markers(): FourSlash.Marker[] {
9        return this.state.getMarkers();
10    }
11
12    public markerNames(): string[] {
13        return this.state.getMarkerNames();
14    }
15
16    public marker(name: string): FourSlash.Marker {
17        return this.state.getMarkerByName(name);
18    }
19
20    public markerName(m: FourSlash.Marker) {
21        return this.state.markerName(m);
22    }
23
24    public ranges(): FourSlash.Range[] {
25        return this.state.getRanges();
26    }
27
28    public rangesInFile(fileName?: string): FourSlash.Range[] {
29        return this.state.getRangesInFile(fileName);
30    }
31
32    public spans(): ts.TextSpan[] {
33        return this.ranges().map(r => ts.createTextSpan(r.pos, r.end - r.pos));
34    }
35
36    public rangesByText(): ts.ESMap<string, FourSlash.Range[]> {
37        return this.state.rangesByText();
38    }
39
40    public markerByName(s: string): FourSlash.Marker {
41        return this.state.getMarkerByName(s);
42    }
43
44    public symbolsInScope(range: FourSlash.Range): ts.Symbol[] {
45        return this.state.symbolsInScope(range);
46    }
47
48    public setTypesRegistry(map: ts.MapLike<void>): void {
49        this.state.setTypesRegistry(map);
50    }
51}
52
53export class Config {
54    constructor(private state: FourSlash.TestState) {
55    }
56
57    public configurePlugin(pluginName: string, configuration: any): void {
58        this.state.configurePlugin(pluginName, configuration);
59    }
60
61    public setCompilerOptionsForInferredProjects(options: ts.server.protocol.CompilerOptions): void {
62        this.state.setCompilerOptionsForInferredProjects(options);
63    }
64}
65
66export class GoTo {
67    constructor(private state: FourSlash.TestState) {
68    }
69    // Moves the caret to the specified marker,
70    // or the anonymous marker ('/**/') if no name
71    // is given
72    public marker(name?: string | FourSlash.Marker) {
73        this.state.goToMarker(name);
74    }
75
76    public eachMarker(markers: readonly string[], action: (marker: FourSlash.Marker, index: number) => void): void;
77    public eachMarker(action: (marker: FourSlash.Marker, index: number) => void): void;
78    public eachMarker(a: readonly string[] | ((marker: FourSlash.Marker, index: number) => void), b?: (marker: FourSlash.Marker, index: number) => void): void {
79        const markers = typeof a === "function" ? this.state.getMarkers() : a.map(m => this.state.getMarkerByName(m));
80        this.state.goToEachMarker(markers, typeof a === "function" ? a : b!);
81    }
82
83
84    public rangeStart(range: FourSlash.Range) {
85        this.state.goToRangeStart(range);
86    }
87
88    public eachRange(action: (range: FourSlash.Range) => void) {
89        this.state.goToEachRange(action);
90    }
91
92    public bof() {
93        this.state.goToBOF();
94    }
95
96    public eof() {
97        this.state.goToEOF();
98    }
99
100    public implementation() {
101        this.state.goToImplementation();
102    }
103
104    public position(positionOrLineAndCharacter: number | ts.LineAndCharacter, fileNameOrIndex?: string | number): void {
105        if (fileNameOrIndex !== undefined) {
106            this.file(fileNameOrIndex);
107        }
108        this.state.goToPosition(positionOrLineAndCharacter);
109    }
110
111    // Opens a file, given either its index as it
112    // appears in the test source, or its filename
113    // as specified in the test metadata
114    public file(indexOrName: number | string, content?: string, scriptKindName?: string): void {
115        this.state.openFile(indexOrName, content, scriptKindName);
116    }
117
118    public select(startMarker: string, endMarker: string) {
119        this.state.select(startMarker, endMarker);
120    }
121
122    public selectAllInFile(fileName: string) {
123        this.state.selectAllInFile(fileName);
124    }
125
126    public selectRange(range: FourSlash.Range): void {
127        this.state.selectRange(range);
128    }
129}
130
131export class VerifyNegatable {
132    public not: VerifyNegatable | undefined;
133
134    constructor(protected state: FourSlash.TestState, private negative = false) {
135        if (!negative) {
136            this.not = new VerifyNegatable(state, true);
137        }
138    }
139
140    public assertHasRanges(ranges: FourSlash.Range[]) {
141        assert(ranges.length !== 0, "Array of ranges is expected to be non-empty");
142    }
143
144    public noSignatureHelp(...markers: (string | FourSlash.Marker)[]): void {
145        this.state.verifySignatureHelpPresence(/*expectPresent*/ false, /*triggerReason*/ undefined, markers);
146    }
147
148    public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void {
149        this.state.verifySignatureHelpPresence(/*expectPresent*/ false, reason, markers);
150    }
151
152    public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void {
153        this.state.verifySignatureHelpPresence(/*expectPresent*/ true, reason, markers);
154    }
155
156    public signatureHelp(...options: VerifySignatureHelpOptions[]): void {
157        this.state.verifySignatureHelp(options);
158    }
159
160    public errorExistsBetweenMarkers(startMarker: string, endMarker: string) {
161        this.state.verifyErrorExistsBetweenMarkers(startMarker, endMarker, !this.negative);
162    }
163
164    public errorExistsAfterMarker(markerName = "") {
165        this.state.verifyErrorExistsAfterMarker(markerName, !this.negative, /*after*/ true);
166    }
167
168    public errorExistsBeforeMarker(markerName = "") {
169        this.state.verifyErrorExistsAfterMarker(markerName, !this.negative, /*after*/ false);
170    }
171
172    public quickInfoExists() {
173        this.state.verifyQuickInfoExists(this.negative);
174    }
175
176    public typeDefinitionCountIs(expectedCount: number) {
177        this.state.verifyTypeDefinitionsCount(this.negative, expectedCount);
178    }
179
180    public implementationListIsEmpty() {
181        this.state.verifyImplementationListIsEmpty(this.negative);
182    }
183
184    public isValidBraceCompletionAtPosition(openingBrace: string) {
185        this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
186    }
187
188    public jsxClosingTag(map: { [markerName: string]: ts.JsxClosingTagInfo | undefined }): void {
189        this.state.verifyJsxClosingTag(map);
190    }
191
192    public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
193        this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
194    }
195
196    public codeFix(options: VerifyCodeFixOptions) {
197        this.state.verifyCodeFix(options);
198    }
199
200    public codeFixAvailable(options?: VerifyCodeFixAvailableOptions[]) {
201        this.state.verifyCodeFixAvailable(this.negative, options);
202    }
203
204    public codeFixAllAvailable(fixName: string) {
205        this.state.verifyCodeFixAllAvailable(this.negative, fixName);
206    }
207
208    public applicableRefactorAvailableAtMarker(markerName: string) {
209        this.state.verifyApplicableRefactorAvailableAtMarker(this.negative, markerName);
210    }
211
212    public applicableRefactorAvailableForRange() {
213        this.state.verifyApplicableRefactorAvailableForRange(this.negative);
214    }
215
216    public refactorsAvailable(names: readonly string[]): void {
217        this.state.verifyRefactorsAvailable(names);
218    }
219
220    public refactorAvailable(name: string, actionName?: string, actionDescription?: string) {
221        this.state.verifyRefactorAvailable(this.negative, "implicit", name, actionName, actionDescription);
222    }
223
224    public refactorAvailableForTriggerReason(triggerReason: ts.RefactorTriggerReason, name: string, actionName?: string) {
225        this.state.verifyRefactorAvailable(this.negative, triggerReason, name, actionName);
226    }
227
228    public refactorKindAvailable(kind: string, expected: string[], preferences = ts.emptyOptions) {
229        this.state.verifyRefactorKindsAvailable(kind, expected, preferences);
230    }
231
232    public toggleLineComment(newFileContent: string) {
233        this.state.toggleLineComment(newFileContent);
234    }
235
236    public toggleMultilineComment(newFileContent: string) {
237        this.state.toggleMultilineComment(newFileContent);
238    }
239
240    public commentSelection(newFileContent: string) {
241        this.state.commentSelection(newFileContent);
242    }
243
244    public uncommentSelection(newFileContent: string) {
245        this.state.uncommentSelection(newFileContent);
246    }
247}
248
249export class Verify extends VerifyNegatable {
250    constructor(state: FourSlash.TestState) {
251        super(state);
252    }
253
254    public completions(...optionsArray: VerifyCompletionsOptions[]) {
255        for (const options of optionsArray) {
256            this.state.verifyCompletions(options);
257        }
258    }
259
260    public getInlayHints(expected: readonly VerifyInlayHintsOptions[], span: ts.TextSpan, preference?: ts.UserPreferences) {
261        this.state.verifyInlayHints(expected, span, preference);
262    }
263
264    public quickInfoIs(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) {
265        this.state.verifyQuickInfoString(expectedText, expectedDocumentation, expectedTags);
266    }
267
268    public quickInfoAt(markerName: string | FourSlash.Range, expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) {
269        this.state.verifyQuickInfoAt(markerName, expectedText, expectedDocumentation, expectedTags);
270    }
271
272    public quickInfos(namesAndTexts: { [name: string]: string }) {
273        this.state.verifyQuickInfos(namesAndTexts);
274    }
275
276    public caretAtMarker(markerName?: string) {
277        this.state.verifyCaretAtMarker(markerName);
278    }
279
280    public indentationIs(numberOfSpaces: number) {
281        this.state.verifyIndentationAtCurrentPosition(numberOfSpaces);
282    }
283
284    public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) {
285        this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle, baseIndentSize);
286    }
287
288    public textAtCaretIs(text: string) {
289        this.state.verifyTextAtCaretIs(text);
290    }
291
292    /**
293     * Compiles the current file and evaluates 'expr' in a context containing
294     * the emitted output, then compares (using ===) the result of that expression
295     * to 'value'. Do not use this function with external modules as it is not supported.
296     */
297    public eval(expr: string, value: any) {
298        this.state.verifyEval(expr, value);
299    }
300
301    public currentLineContentIs(text: string) {
302        this.state.verifyCurrentLineContent(text);
303    }
304
305    public currentFileContentIs(text: string) {
306        this.state.verifyCurrentFileContent(text);
307    }
308
309    public formatDocumentChangesNothing(): void {
310        this.state.verifyFormatDocumentChangesNothing();
311    }
312
313    public goToDefinitionIs(endMarkers: ArrayOrSingle<string>) {
314        this.state.verifyGoToDefinitionIs(endMarkers);
315    }
316
317    public goToDefinition(startMarkerName: ArrayOrSingle<string>, endMarkerName: ArrayOrSingle<string>, range?: FourSlash.Range): void;
318    public goToDefinition(startsAndEnds: [ArrayOrSingle<string>, ArrayOrSingle<string>][] | { [startMarkerName: string]: ArrayOrSingle<string> }): void;
319    public goToDefinition(arg0: any, endMarkerName?: ArrayOrSingle<string>) {
320        this.state.verifyGoToDefinition(arg0, endMarkerName);
321    }
322
323    public goToType(startMarkerName: ArrayOrSingle<string>, endMarkerName: ArrayOrSingle<string>): void;
324    public goToType(startsAndEnds: [ArrayOrSingle<string>, ArrayOrSingle<string>][] | { [startMarkerName: string]: ArrayOrSingle<string> }): void;
325    public goToType(arg0: any, endMarkerName?: ArrayOrSingle<string>) {
326        this.state.verifyGoToType(arg0, endMarkerName);
327    }
328
329    public goToSourceDefinition(startMarkerNames: ArrayOrSingle<string>, end: { file: string } | ArrayOrSingle<string>) {
330        this.state.verifyGoToSourceDefinition(startMarkerNames, end);
331    }
332
333    public goToDefinitionForMarkers(...markerNames: string[]) {
334        this.state.verifyGoToDefinitionForMarkers(markerNames);
335    }
336
337    public goToDefinitionName(name: string, containerName: string) {
338        this.state.verifyGoToDefinitionName(name, containerName);
339    }
340
341    public verifyGetEmitOutputForCurrentFile(expected: string): void {
342        this.state.verifyGetEmitOutputForCurrentFile(expected);
343    }
344
345    public verifyGetEmitOutputContentsForCurrentFile(expected: ts.OutputFile[]): void {
346        this.state.verifyGetEmitOutputContentsForCurrentFile(expected);
347    }
348
349    public symbolAtLocation(startRange: FourSlash.Range, ...declarationRanges: FourSlash.Range[]) {
350        this.state.verifySymbolAtLocation(startRange, declarationRanges);
351    }
352
353    public typeOfSymbolAtLocation(range: FourSlash.Range, symbol: ts.Symbol, expected: string) {
354        this.state.verifyTypeOfSymbolAtLocation(range, symbol, expected);
355    }
356
357    public baselineFindAllReferences(...markerNames: string[]) {
358        this.state.verifyBaselineFindAllReferences(...markerNames);
359    }
360
361    public baselineFindAllReferencesMulti(seq: number, ...markerNames: string[]) {
362        this.state.verifyBaselineFindAllReferencesMulti(seq, ...markerNames);
363    }
364
365    public baselineGetFileReferences(fileName: string) {
366        this.state.verifyBaselineGetFileReferences(fileName);
367    }
368
369    public findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]) {
370        this.state.verifyDisplayPartsOfReferencedSymbol(expected);
371    }
372
373    public noErrors() {
374        this.state.verifyNoErrors();
375    }
376
377    public errorExistsAtRange(range: FourSlash.Range, code: number, message?: string) {
378        this.state.verifyErrorExistsAtRange(range, code, message);
379    }
380
381    public numberOfErrorsInCurrentFile(expected: number) {
382        this.state.verifyNumberOfErrorsInCurrentFile(expected);
383    }
384
385    public baselineCurrentFileBreakpointLocations() {
386        this.state.baselineCurrentFileBreakpointLocations();
387    }
388
389    public baselineCurrentFileNameOrDottedNameSpans() {
390        this.state.baselineCurrentFileNameOrDottedNameSpans();
391    }
392
393    public getEmitOutput(expectedOutputFiles: readonly string[]): void {
394        this.state.verifyGetEmitOutput(expectedOutputFiles);
395    }
396
397    public baselineGetEmitOutput() {
398        this.state.baselineGetEmitOutput();
399    }
400
401    public baselineQuickInfo() {
402        this.state.baselineQuickInfo();
403    }
404
405    public baselineSignatureHelp() {
406        this.state.baselineSignatureHelp();
407    }
408
409    public baselineCompletions(preferences?: ts.UserPreferences) {
410        this.state.baselineCompletions(preferences);
411    }
412
413    public baselineSmartSelection() {
414        this.state.baselineSmartSelection();
415    }
416
417    public baselineSyntacticDiagnostics() {
418        this.state.baselineSyntacticDiagnostics();
419    }
420
421    public baselineSyntacticAndSemanticDiagnostics() {
422        this.state.baselineSyntacticAndSemanticDiagnostics();
423    }
424
425    public nameOrDottedNameSpanTextIs(text: string) {
426        this.state.verifyCurrentNameOrDottedNameSpanText(text);
427    }
428
429    public outliningSpansInCurrentFile(spans: FourSlash.Range[], kind?: "comment" | "region" | "code" | "imports") {
430        this.state.verifyOutliningSpans(spans, kind);
431    }
432
433    public outliningHintSpansInCurrentFile(spans: FourSlash.Range[]) {
434        this.state.verifyOutliningHintSpans(spans);
435    }
436
437    public todoCommentsInCurrentFile(descriptors: string[]) {
438        this.state.verifyTodoComments(descriptors, this.state.getRanges());
439    }
440
441    public matchingBracePositionInCurrentFile(bracePosition: number, expectedMatchPosition: number) {
442        this.state.verifyMatchingBracePosition(bracePosition, expectedMatchPosition);
443    }
444
445    public noMatchingBracePositionInCurrentFile(bracePosition: number) {
446        this.state.verifyNoMatchingBracePosition(bracePosition);
447    }
448
449    public docCommentTemplateAt(marker: string | FourSlash.Marker, expectedOffset: number, expectedText: string, options?: ts.DocCommentTemplateOptions) {
450        this.state.goToMarker(marker);
451        this.state.verifyDocCommentTemplate({ newText: expectedText.replace(/\r?\n/g, "\r\n"), caretOffset: expectedOffset }, options);
452    }
453
454    public noDocCommentTemplateAt(marker: string | FourSlash.Marker) {
455        this.state.goToMarker(marker);
456        this.state.verifyDocCommentTemplate(/*expected*/ undefined);
457    }
458
459    public rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void {
460        this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index);
461    }
462
463    public codeFixAll(options: VerifyCodeFixAllOptions): void {
464        this.state.verifyCodeFixAll(options);
465    }
466
467    public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: ts.FormatCodeSettings): void {
468        this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, actionName, formattingOptions);
469    }
470
471    public rangeIs(expectedText: string, includeWhiteSpace?: boolean): void {
472        this.state.verifyRangeIs(expectedText, includeWhiteSpace);
473    }
474
475    public getAndApplyCodeFix(errorCode?: number, index?: number): void {
476        this.state.getAndApplyCodeActions(errorCode, index);
477    }
478
479    public applyCodeActionFromCompletion(markerName: string, options: VerifyCompletionActionOptions): void {
480        this.state.applyCodeActionFromCompletion(markerName, options);
481    }
482
483    public importFixAtPosition(expectedTextArray: string[], errorCode?: number, preferences?: ts.UserPreferences): void {
484        this.state.verifyImportFixAtPosition(expectedTextArray, errorCode, preferences);
485    }
486
487    public importFixModuleSpecifiers(marker: string, moduleSpecifiers: string[], preferences?: ts.UserPreferences) {
488        this.state.verifyImportFixModuleSpecifiers(marker, moduleSpecifiers, preferences);
489    }
490
491    public navigationBar(json: any, options?: { checkSpans?: boolean }) {
492        this.state.verifyNavigationBar(json, options);
493    }
494
495    public navigationTree(json: any, options?: { checkSpans?: boolean }) {
496        this.state.verifyNavigationTree(json, options);
497    }
498
499    public navigateTo(...options: VerifyNavigateToOptions[]): void {
500        this.state.verifyNavigateTo(options);
501    }
502
503    public occurrencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean) {
504        this.state.verifyOccurrencesAtPositionListContains(range.fileName, range.pos, range.end, isWriteAccess);
505    }
506
507    public occurrencesAtPositionCount(expectedCount: number) {
508        this.state.verifyOccurrencesAtPositionListCount(expectedCount);
509    }
510
511    public rangesAreOccurrences(isWriteAccess?: boolean, ranges?: FourSlash.Range[]) {
512        this.state.verifyRangesAreOccurrences(isWriteAccess, ranges);
513    }
514
515    public rangesWithSameTextAreRenameLocations(...texts: string[]) {
516        this.state.verifyRangesWithSameTextAreRenameLocations(...texts);
517    }
518
519    public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: FourSlash.Range[], providePrefixAndSuffixTextForRename?: boolean }) {
520        this.state.verifyRangesAreRenameLocations(options);
521    }
522
523    public rangesAreDocumentHighlights(ranges?: FourSlash.Range[], options?: VerifyDocumentHighlightsOptions) {
524        this.state.verifyRangesAreDocumentHighlights(ranges, options);
525    }
526
527    public rangesWithSameTextAreDocumentHighlights() {
528        this.state.verifyRangesWithSameTextAreDocumentHighlights();
529    }
530
531    public documentHighlightsOf(startRange: FourSlash.Range, ranges: FourSlash.Range[], options?: VerifyDocumentHighlightsOptions) {
532        this.state.verifyDocumentHighlightsOf(startRange, ranges, options);
533    }
534
535    public noDocumentHighlights(startRange: FourSlash.Range) {
536        this.state.verifyNoDocumentHighlights(startRange);
537    }
538
539    /**
540     * This method *requires* a contiguous, complete, and ordered stream of classifications for a file.
541     */
542    public syntacticClassificationsAre(...classifications: { classificationType: string; text: string }[]) {
543        this.state.verifySyntacticClassifications(classifications);
544    }
545
546    public encodedSyntacticClassificationsLength(length: number) {
547        this.state.verifyEncodedSyntacticClassificationsLength(length);
548    }
549
550    public encodedSemanticClassificationsLength(format: ts.SemanticClassificationFormat, length: number) {
551        this.state.verifyEncodedSemanticClassificationsLength(format, length);
552    }
553
554    /**
555     * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended.
556     */
557    public semanticClassificationsAre(format: ts.SemanticClassificationFormat, ...classifications: Classification[]) {
558        this.state.verifySemanticClassifications(format, classifications);
559    }
560
561    public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) {
562        this.state.replaceWithSemanticClassifications(format);
563    }
564
565    public renameInfoSucceeded(
566        displayName?: string,
567        fullDisplayName?: string,
568        kind?: string,
569        kindModifiers?: string,
570        fileToRename?: string,
571        expectedRange?: FourSlash.Range,
572        preferences?: ts.UserPreferences) {
573        this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange, preferences);
574    }
575
576    public renameInfoFailed(message?: string, preferences?: ts.UserPreferences) {
577        this.state.verifyRenameInfoFailed(message, preferences);
578    }
579
580    public renameLocations(startRanges: ArrayOrSingle<FourSlash.Range>, options: RenameLocationsOptions) {
581        this.state.verifyRenameLocations(startRanges, options);
582    }
583
584    public baselineRename(marker: string, options: RenameOptions) {
585        this.state.baselineRename(marker, options);
586    }
587
588    public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: FourSlash.TextSpan,
589        displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]) {
590        this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation, tags);
591    }
592
593    public getSyntacticDiagnostics(expected: readonly Diagnostic[]) {
594        this.state.getSyntacticDiagnostics(expected);
595    }
596
597    public getSemanticDiagnostics(expected: readonly Diagnostic[]) {
598        this.state.getSemanticDiagnostics(expected);
599    }
600
601    public getSuggestionDiagnostics(expected: readonly Diagnostic[]) {
602        this.state.getSuggestionDiagnostics(expected);
603    }
604
605    public ProjectInfo(expected: string[]) {
606        this.state.verifyProjectInfo(expected);
607    }
608
609    public allRangesAppearInImplementationList(markerName: string) {
610        this.state.verifyRangesInImplementationList(markerName);
611    }
612
613    public getEditsForFileRename(options: GetEditsForFileRenameOptions) {
614        this.state.getEditsForFileRename(options);
615    }
616
617    public baselineCallHierarchy() {
618        this.state.baselineCallHierarchy();
619    }
620
621    public moveToNewFile(options: MoveToNewFileOptions): void {
622        this.state.moveToNewFile(options);
623    }
624
625    public noMoveToNewFile(): void {
626        this.state.noMoveToNewFile();
627    }
628
629    public organizeImports(newContent: string, mode?: ts.OrganizeImportsMode): void {
630        this.state.verifyOrganizeImports(newContent, mode);
631    }
632}
633
634export class Edit {
635    constructor(private state: FourSlash.TestState) {
636    }
637    public backspace(count?: number) {
638        this.state.deleteCharBehindMarker(count);
639    }
640
641    public deleteAtCaret(times?: number) {
642        this.state.deleteChar(times);
643    }
644
645    public replace(start: number, length: number, text: string) {
646        this.state.replace(start, length, text);
647    }
648
649    public paste(text: string) {
650        this.state.paste(text);
651    }
652
653    public insert(text: string) {
654        this.insertLines(text);
655    }
656
657    public insertLine(text: string) {
658        this.insertLines(text + "\n");
659    }
660
661    public insertLines(...lines: string[]) {
662        this.state.type(lines.join("\n"));
663    }
664
665    public deleteLine(index: number) {
666        this.deleteLineRange(index, index);
667    }
668
669    public deleteLineRange(startIndex: number, endIndexInclusive: number) {
670        this.state.deleteLineRange(startIndex, endIndexInclusive);
671    }
672
673    public replaceLine(index: number, text: string) {
674        this.state.selectLine(index);
675        this.state.type(text);
676    }
677
678    public moveRight(count?: number) {
679        this.state.moveCaretRight(count);
680    }
681
682    public moveLeft(count?: number) {
683        if (typeof count === "undefined") {
684            count = 1;
685        }
686        this.state.moveCaretRight(count * -1);
687    }
688
689    public enableFormatting() {
690        this.state.enableFormatting = true;
691    }
692
693    public disableFormatting() {
694        this.state.enableFormatting = false;
695    }
696
697    public applyRefactor(options: ApplyRefactorOptions) {
698        this.state.applyRefactor(options);
699    }
700}
701
702export class Debug {
703    constructor(private state: FourSlash.TestState) {
704    }
705
706    public printCurrentParameterHelp() {
707        this.state.printCurrentParameterHelp();
708    }
709
710    public printCurrentFileState() {
711        this.state.printCurrentFileState(/*showWhitespace*/ false, /*makeCaretVisible*/ true);
712    }
713
714    public printCurrentFileStateWithWhitespace() {
715        this.state.printCurrentFileState(/*showWhitespace*/ true, /*makeCaretVisible*/ true);
716    }
717
718    public printCurrentFileStateWithoutCaret() {
719        this.state.printCurrentFileState(/*showWhitespace*/ false, /*makeCaretVisible*/ false);
720    }
721
722    public printCurrentQuickInfo() {
723        this.state.printCurrentQuickInfo();
724    }
725
726    public printCurrentSignatureHelp() {
727        this.state.printCurrentSignatureHelp();
728    }
729
730    public printCompletionListMembers(options: ts.UserPreferences | undefined) {
731        this.state.printCompletionListMembers(options);
732    }
733
734    public printAvailableCodeFixes() {
735        this.state.printAvailableCodeFixes();
736    }
737
738    public printBreakpointLocation(pos: number) {
739        this.state.printBreakpointLocation(pos);
740    }
741    public printBreakpointAtCurrentLocation() {
742        this.state.printBreakpointAtCurrentLocation();
743    }
744
745    public printNameOrDottedNameSpans(pos: number) {
746        this.state.printNameOrDottedNameSpans(pos);
747    }
748
749    public printErrorList() {
750        this.state.printErrorList();
751    }
752
753    public printNavigationItems(searchValue = ".*") {
754        this.state.printNavigationItems(searchValue);
755    }
756
757    public printNavigationBar() {
758        this.state.printNavigationBar();
759    }
760
761    public printContext() {
762        this.state.printContext();
763    }
764
765    public printOutliningSpans() {
766        this.state.printOutliningSpans();
767    }
768}
769
770export class Format {
771    constructor(private state: FourSlash.TestState) {
772    }
773
774    public document() {
775        this.state.formatDocument();
776    }
777
778    public copyFormatOptions(): ts.FormatCodeSettings {
779        return this.state.copyFormatOptions();
780    }
781
782    public setFormatOptions(options: ts.FormatCodeOptions) {
783        return this.state.setFormatOptions(options);
784    }
785
786    public selection(startMarker: string, endMarker: string) {
787        this.state.formatSelection(this.state.getMarkerByName(startMarker).position, this.state.getMarkerByName(endMarker).position);
788    }
789
790    public onType(posMarker: string, key: string) {
791        this.state.formatOnType(this.state.getMarkerByName(posMarker).position, key);
792    }
793
794    public setOption(name: keyof ts.FormatCodeSettings, value: number | string | boolean): void {
795        this.state.setFormatOptions({ ...this.state.formatCodeSettings, [name]: value });
796    }
797}
798
799export class Cancellation {
800    constructor(private state: FourSlash.TestState) {
801    }
802
803    public resetCancelled() {
804        this.state.resetCancelled();
805    }
806
807    public setCancelled(numberOfCalls = 0) {
808        this.state.setCancelled(numberOfCalls);
809    }
810}
811
812interface OlderClassification {
813    classificationType: ts.ClassificationTypeNames;
814    text: string;
815    textSpan?: FourSlash.TextSpan;
816}
817
818// The VS Code LSP
819interface ModernClassification {
820    classificationType: string;
821    text?: string;
822    textSpan?: FourSlash.TextSpan;
823}
824
825type Classification = OlderClassification | ModernClassification;
826
827export function classification(format: ts.SemanticClassificationFormat) {
828
829    function semanticToken(identifier: string, text: string, _position: number): Classification {
830        return {
831            classificationType: identifier,
832            text
833         };
834    }
835
836    if (format === ts.SemanticClassificationFormat.TwentyTwenty) {
837        return {
838            semanticToken
839        };
840    }
841
842    // Defaults to the previous semantic classifier factory functions
843
844    function comment(text: string, position?: number): Classification {
845        return getClassification(ts.ClassificationTypeNames.comment, text, position);
846    }
847
848    function identifier(text: string, position?: number): Classification {
849        return getClassification(ts.ClassificationTypeNames.identifier, text, position);
850    }
851
852    function keyword(text: string, position?: number): Classification {
853        return getClassification(ts.ClassificationTypeNames.keyword, text, position);
854    }
855
856    function numericLiteral(text: string, position?: number): Classification {
857        return getClassification(ts.ClassificationTypeNames.numericLiteral, text, position);
858    }
859
860    function operator(text: string, position?: number): Classification {
861        return getClassification(ts.ClassificationTypeNames.operator, text, position);
862    }
863
864    function stringLiteral(text: string, position?: number): Classification {
865        return getClassification(ts.ClassificationTypeNames.stringLiteral, text, position);
866    }
867
868    function whiteSpace(text: string, position?: number): Classification {
869        return getClassification(ts.ClassificationTypeNames.whiteSpace, text, position);
870    }
871
872    function text(text: string, position?: number): Classification {
873        return getClassification(ts.ClassificationTypeNames.text, text, position);
874    }
875
876    function punctuation(text: string, position?: number): Classification {
877        return getClassification(ts.ClassificationTypeNames.punctuation, text, position);
878    }
879
880    function docCommentTagName(text: string, position?: number): Classification {
881        return getClassification(ts.ClassificationTypeNames.docCommentTagName, text, position);
882    }
883
884    function className(text: string, position?: number): Classification {
885        return getClassification(ts.ClassificationTypeNames.className, text, position);
886    }
887
888    function enumName(text: string, position?: number): Classification {
889        return getClassification(ts.ClassificationTypeNames.enumName, text, position);
890    }
891
892    function interfaceName(text: string, position?: number): Classification {
893        return getClassification(ts.ClassificationTypeNames.interfaceName, text, position);
894    }
895
896    function moduleName(text: string, position?: number): Classification {
897        return getClassification(ts.ClassificationTypeNames.moduleName, text, position);
898    }
899
900    function typeParameterName(text: string, position?: number): Classification {
901        return getClassification(ts.ClassificationTypeNames.typeParameterName, text, position);
902    }
903
904    function parameterName(text: string, position?: number): Classification {
905        return getClassification(ts.ClassificationTypeNames.parameterName, text, position);
906    }
907
908    function typeAliasName(text: string, position?: number): Classification {
909        return getClassification(ts.ClassificationTypeNames.typeAliasName, text, position);
910    }
911
912    function jsxOpenTagName(text: string, position?: number): Classification {
913        return getClassification(ts.ClassificationTypeNames.jsxOpenTagName, text, position);
914    }
915
916    function jsxCloseTagName(text: string, position?: number): Classification {
917        return getClassification(ts.ClassificationTypeNames.jsxCloseTagName, text, position);
918    }
919
920    function jsxSelfClosingTagName(text: string, position?: number): Classification {
921        return getClassification(ts.ClassificationTypeNames.jsxSelfClosingTagName, text, position);
922    }
923
924    function jsxAttribute(text: string, position?: number): Classification {
925        return getClassification(ts.ClassificationTypeNames.jsxAttribute, text, position);
926    }
927
928    function jsxText(text: string, position?: number): Classification {
929        return getClassification(ts.ClassificationTypeNames.jsxText, text, position);
930    }
931
932    function jsxAttributeStringLiteralValue(text: string, position?: number): Classification {
933        return getClassification(ts.ClassificationTypeNames.jsxAttributeStringLiteralValue, text, position);
934    }
935
936    function getClassification(classificationType: ts.ClassificationTypeNames, text: string, position?: number): Classification {
937        const textSpan = position === undefined ? undefined : { start: position, end: position + text.length };
938        return { classificationType, text, textSpan };
939    }
940
941    return {
942        comment,
943        identifier,
944        keyword,
945        numericLiteral,
946        operator,
947        stringLiteral,
948        whiteSpace,
949        text,
950        punctuation,
951        docCommentTagName,
952        className,
953        enumName,
954        interfaceName,
955        moduleName,
956        typeParameterName,
957        parameterName,
958        typeAliasName,
959        jsxOpenTagName,
960        jsxCloseTagName,
961        jsxSelfClosingTagName,
962        jsxAttribute,
963        jsxText,
964        jsxAttributeStringLiteralValue,
965        getClassification
966    };
967}
968
969export namespace Completion {
970    import SortTextType = ts.Completions.SortText;
971    export type SortText = SortTextType;
972    export import CompletionSource = ts.Completions.CompletionSource;
973
974    export const SortText = {
975        // Presets
976        LocalDeclarationPriority: "10" as SortText,
977        LocationPriority: "11" as SortText,
978        OptionalMember: "12" as SortText,
979        MemberDeclaredBySpreadAssignment: "13" as SortText,
980        SuggestedClassMembers: "14" as SortText,
981        GlobalsOrKeywords: "15" as SortText,
982        AutoImportSuggestions: "16" as SortText,
983        ClassMemberSnippets: "17" as SortText,
984        JavascriptIdentifiers: "18" as SortText,
985
986        // Transformations
987        Deprecated(sortText: SortText): SortText {
988            return "z" + sortText as SortText;
989        },
990
991        ObjectLiteralProperty(presetSortText: SortText, symbolDisplayName: string): SortText {
992            return `${presetSortText}\0${symbolDisplayName}\0` as SortText;
993        },
994
995        SortBelow(sortText: SortText): SortText {
996            return sortText + "1" as SortText;
997        },
998    };
999
1000    const functionEntry = (name: string): ExpectedCompletionEntryObject => ({
1001        name,
1002        kind: "function",
1003        kindModifiers: "declare",
1004        sortText: SortText.GlobalsOrKeywords
1005    });
1006    const deprecatedFunctionEntry = (name: string): ExpectedCompletionEntryObject => ({
1007        name,
1008        kind: "function",
1009        kindModifiers: "deprecated,declare",
1010        sortText: "z15" as SortText,
1011    });
1012    const varEntry = (name: string): ExpectedCompletionEntryObject => ({
1013        name,
1014        kind: "var",
1015        kindModifiers: "declare",
1016        sortText: SortText.GlobalsOrKeywords
1017    });
1018    const moduleEntry = (name: string): ExpectedCompletionEntryObject => ({
1019        name,
1020        kind: "module",
1021        kindModifiers: "declare",
1022        sortText: SortText.GlobalsOrKeywords
1023    });
1024    const keywordEntry = (name: string): ExpectedCompletionEntryObject => ({
1025        name,
1026        kind: "keyword",
1027        sortText: SortText.GlobalsOrKeywords
1028    });
1029    const methodEntry = (name: string): ExpectedCompletionEntryObject => ({
1030        name,
1031        kind: "method",
1032        kindModifiers: "declare",
1033        sortText: SortText.LocationPriority
1034    });
1035    const deprecatedMethodEntry = (name: string): ExpectedCompletionEntryObject => ({
1036        name,
1037        kind: "method",
1038        kindModifiers: "deprecated,declare",
1039        sortText: "z11" as SortText,
1040    });
1041    const propertyEntry = (name: string): ExpectedCompletionEntryObject => ({
1042        name,
1043        kind: "property",
1044        kindModifiers: "declare",
1045        sortText: SortText.LocationPriority
1046    });
1047    const interfaceEntry = (name: string): ExpectedCompletionEntryObject => ({
1048        name,
1049        kind: "interface",
1050        kindModifiers: "declare",
1051        sortText: SortText.GlobalsOrKeywords
1052    });
1053    const typeEntry = (name: string): ExpectedCompletionEntryObject => ({
1054        name,
1055        kind: "type",
1056        kindModifiers: "declare",
1057        sortText: SortText.GlobalsOrKeywords
1058    });
1059
1060    const res: ExpectedCompletionEntryObject[] = [];
1061    for (let i = ts.SyntaxKind.FirstKeyword; i <= ts.SyntaxKind.LastKeyword; i++) {
1062        res.push({
1063            name: ts.Debug.checkDefined(ts.tokenToString(i)),
1064            kind: "keyword",
1065            sortText: SortText.GlobalsOrKeywords
1066        });
1067    }
1068    export const keywordsWithUndefined: readonly ExpectedCompletionEntryObject[] = res;
1069    export const keywords: readonly ExpectedCompletionEntryObject[] = keywordsWithUndefined.filter(k => k.name !== "undefined");
1070
1071    export const typeKeywords: readonly ExpectedCompletionEntryObject[] = [
1072        "any",
1073        "asserts",
1074        "bigint",
1075        "boolean",
1076        "false",
1077        "infer",
1078        "keyof",
1079        "never",
1080        "null",
1081        "number",
1082        "object",
1083        "readonly",
1084        "string",
1085        "symbol",
1086        "true",
1087        "undefined",
1088        "unique",
1089        "unknown",
1090        "void",
1091    ].map(keywordEntry);
1092
1093    export function sorted(entries: readonly ExpectedCompletionEntry[]): readonly ExpectedCompletionEntry[] {
1094        return ts.stableSort(entries, compareExpectedCompletionEntries);
1095    }
1096
1097    // If you want to use a function like `globalsPlus`, that function needs to sort
1098    // the concatted array since the entries provided as "plus" could be interleaved
1099    // among the "globals." However, we still want to assert that the "plus" array
1100    // was internally sorted correctly, so we tack it onto the sorted concatted array
1101    // so `verify.completions` can assert that it represents the same order as the response.
1102    function combineExpectedCompletionEntries(
1103        functionName: string,
1104        providedByHarness: readonly ExpectedCompletionEntry[],
1105        providedByTest: readonly ExpectedCompletionEntry[],
1106    ): ExpectedExactCompletionsPlus {
1107        return Object.assign(sorted([...providedByHarness, ...providedByTest]), { plusFunctionName: functionName, plusArgument: providedByTest });
1108    }
1109
1110    export function typeKeywordsPlus(plus: readonly ExpectedCompletionEntry[]) {
1111        return combineExpectedCompletionEntries("typeKeywordsPlus", typeKeywords, plus);
1112    }
1113
1114    const globalTypeDecls: readonly ExpectedCompletionEntryObject[] = [
1115        interfaceEntry("Symbol"),
1116        typeEntry("PropertyKey"),
1117        interfaceEntry("PropertyDescriptor"),
1118        interfaceEntry("PropertyDescriptorMap"),
1119        varEntry("Object"),
1120        interfaceEntry("ObjectConstructor"),
1121        varEntry("Function"),
1122        interfaceEntry("FunctionConstructor"),
1123        typeEntry("ThisParameterType"),
1124        typeEntry("OmitThisParameter"),
1125        interfaceEntry("CallableFunction"),
1126        interfaceEntry("NewableFunction"),
1127        interfaceEntry("IArguments"),
1128        varEntry("String"),
1129        interfaceEntry("StringConstructor"),
1130        varEntry("Boolean"),
1131        interfaceEntry("BooleanConstructor"),
1132        varEntry("Number"),
1133        interfaceEntry("NumberConstructor"),
1134        interfaceEntry("TemplateStringsArray"),
1135        interfaceEntry("ImportMeta"),
1136        interfaceEntry("ImportCallOptions"),
1137        interfaceEntry("ImportAssertions"),
1138        varEntry("Math"),
1139        varEntry("Date"),
1140        interfaceEntry("DateConstructor"),
1141        interfaceEntry("RegExpMatchArray"),
1142        interfaceEntry("RegExpExecArray"),
1143        varEntry("RegExp"),
1144        interfaceEntry("RegExpConstructor"),
1145        varEntry("Error"),
1146        interfaceEntry("ErrorConstructor"),
1147        varEntry("EvalError"),
1148        interfaceEntry("EvalErrorConstructor"),
1149        varEntry("RangeError"),
1150        interfaceEntry("RangeErrorConstructor"),
1151        varEntry("ReferenceError"),
1152        interfaceEntry("ReferenceErrorConstructor"),
1153        varEntry("SyntaxError"),
1154        interfaceEntry("SyntaxErrorConstructor"),
1155        varEntry("TypeError"),
1156        interfaceEntry("TypeErrorConstructor"),
1157        varEntry("URIError"),
1158        interfaceEntry("URIErrorConstructor"),
1159        varEntry("JSON"),
1160        interfaceEntry("ReadonlyArray"),
1161        interfaceEntry("ConcatArray"),
1162        varEntry("Array"),
1163        interfaceEntry("ArrayConstructor"),
1164        interfaceEntry("TypedPropertyDescriptor"),
1165        typeEntry("ClassDecorator"),
1166        typeEntry("PropertyDecorator"),
1167        typeEntry("MethodDecorator"),
1168        typeEntry("ParameterDecorator"),
1169        typeEntry("PromiseConstructorLike"),
1170        interfaceEntry("PromiseLike"),
1171        interfaceEntry("Promise"),
1172        typeEntry("Awaited"),
1173        interfaceEntry("ArrayLike"),
1174        typeEntry("Partial"),
1175        typeEntry("Required"),
1176        typeEntry("Readonly"),
1177        typeEntry("Pick"),
1178        typeEntry("Record"),
1179        typeEntry("Exclude"),
1180        typeEntry("Extract"),
1181        typeEntry("Omit"),
1182        typeEntry("NonNullable"),
1183        typeEntry("Parameters"),
1184        typeEntry("ConstructorParameters"),
1185        typeEntry("ReturnType"),
1186        typeEntry("InstanceType"),
1187        typeEntry("Uppercase"),
1188        typeEntry("Lowercase"),
1189        typeEntry("Capitalize"),
1190        typeEntry("Uncapitalize"),
1191        interfaceEntry("ThisType"),
1192        varEntry("ArrayBuffer"),
1193        interfaceEntry("ArrayBufferTypes"),
1194        typeEntry("ArrayBufferLike"),
1195        interfaceEntry("ArrayBufferConstructor"),
1196        interfaceEntry("ArrayBufferView"),
1197        varEntry("DataView"),
1198        interfaceEntry("DataViewConstructor"),
1199        varEntry("Int8Array"),
1200        interfaceEntry("Int8ArrayConstructor"),
1201        varEntry("Uint8Array"),
1202        interfaceEntry("Uint8ArrayConstructor"),
1203        varEntry("Uint8ClampedArray"),
1204        interfaceEntry("Uint8ClampedArrayConstructor"),
1205        varEntry("Int16Array"),
1206        interfaceEntry("Int16ArrayConstructor"),
1207        varEntry("Uint16Array"),
1208        interfaceEntry("Uint16ArrayConstructor"),
1209        varEntry("Int32Array"),
1210        interfaceEntry("Int32ArrayConstructor"),
1211        varEntry("Uint32Array"),
1212        interfaceEntry("Uint32ArrayConstructor"),
1213        varEntry("Float32Array"),
1214        interfaceEntry("Float32ArrayConstructor"),
1215        varEntry("Float64Array"),
1216        interfaceEntry("Float64ArrayConstructor"),
1217        moduleEntry("Intl"),
1218        typeEntry("ESObject"),
1219    ];
1220
1221    export const globalThisEntry: ExpectedCompletionEntry = {
1222        name: "globalThis",
1223        kind: "module",
1224        sortText: SortText.GlobalsOrKeywords
1225    };
1226    export const globalTypes = globalTypesPlus([]);
1227    export function globalTypesPlus(plus: readonly ExpectedCompletionEntry[]) {
1228        return combineExpectedCompletionEntries(
1229            "globalTypesPlus",
1230            [globalThisEntry, ...globalTypeDecls, ...typeKeywords],
1231            plus
1232        );
1233    }
1234
1235    export const typeAssertionKeywords: readonly ExpectedCompletionEntry[] =
1236        globalTypesPlus([keywordEntry("const")]);
1237
1238    function getInJsKeywords(keywords: readonly ExpectedCompletionEntryObject[]): readonly ExpectedCompletionEntryObject[] {
1239        return keywords.filter(keyword => {
1240            switch (keyword.name) {
1241                case "enum":
1242                case "interface":
1243                case "implements":
1244                case "private":
1245                case "protected":
1246                case "public":
1247                case "abstract":
1248                case "any":
1249                case "boolean":
1250                case "declare":
1251                case "infer":
1252                case "is":
1253                case "keyof":
1254                case "module":
1255                case "namespace":
1256                case "never":
1257                case "readonly":
1258                case "number":
1259                case "object":
1260                case "string":
1261                case "symbol":
1262                case "type":
1263                case "unique":
1264                case "override":
1265                case "unknown":
1266                case "global":
1267                case "bigint":
1268                    return false;
1269                default:
1270                    return true;
1271            }
1272        });
1273    }
1274
1275    export const classElementKeywords: readonly ExpectedCompletionEntryObject[] = [
1276        "abstract",
1277        "accessor",
1278        "async",
1279        "constructor",
1280        "declare",
1281        "get",
1282        "override",
1283        "private",
1284        "protected",
1285        "public",
1286        "readonly",
1287        "set",
1288        "static",
1289    ].map(keywordEntry);
1290
1291    export const classElementInJsKeywords = getInJsKeywords(classElementKeywords);
1292
1293    export const constructorParameterKeywords: readonly ExpectedCompletionEntryObject[] =
1294        ["override", "private", "protected", "public", "readonly"].map((name): ExpectedCompletionEntryObject => ({
1295            name,
1296            kind: "keyword",
1297            sortText: SortText.GlobalsOrKeywords
1298        }));
1299
1300    export const functionMembers: readonly ExpectedCompletionEntryObject[] = [
1301        methodEntry("apply"),
1302        methodEntry("call"),
1303        methodEntry("bind"),
1304        methodEntry("toString"),
1305        propertyEntry("length"),
1306        { name: "arguments", kind: "property", kindModifiers: "declare", text: "(property) Function.arguments: any" },
1307        propertyEntry("caller"),
1308    ].sort(compareExpectedCompletionEntries);
1309
1310    export function functionMembersPlus(plus: readonly ExpectedCompletionEntryObject[]) {
1311        return combineExpectedCompletionEntries("functionMembersPlus", functionMembers, plus);
1312    }
1313
1314    export const stringMembers: readonly ExpectedCompletionEntryObject[] = [
1315        methodEntry("toString"),
1316        methodEntry("charAt"),
1317        methodEntry("charCodeAt"),
1318        methodEntry("concat"),
1319        methodEntry("indexOf"),
1320        methodEntry("lastIndexOf"),
1321        methodEntry("localeCompare"),
1322        methodEntry("match"),
1323        methodEntry("replace"),
1324        methodEntry("search"),
1325        methodEntry("slice"),
1326        methodEntry("split"),
1327        methodEntry("substring"),
1328        methodEntry("toLowerCase"),
1329        methodEntry("toLocaleLowerCase"),
1330        methodEntry("toUpperCase"),
1331        methodEntry("toLocaleUpperCase"),
1332        methodEntry("trim"),
1333        propertyEntry("length"),
1334        deprecatedMethodEntry("substr"),
1335        methodEntry("valueOf"),
1336    ].sort(compareExpectedCompletionEntries);
1337
1338    export const functionMembersWithPrototype: readonly ExpectedCompletionEntryObject[] = [
1339        ...functionMembers,
1340        propertyEntry("prototype"),
1341    ].sort(compareExpectedCompletionEntries);
1342
1343    export function functionMembersWithPrototypePlus(plus: readonly ExpectedCompletionEntryObject[]) {
1344        return [...functionMembersWithPrototype, ...plus].sort(compareExpectedCompletionEntries);
1345    }
1346
1347    // TODO: Shouldn't propose type keywords in statement position
1348    export const statementKeywordsWithTypes: readonly ExpectedCompletionEntryObject[] = [
1349        "abstract",
1350        "any",
1351        "as",
1352        "asserts",
1353        "async",
1354        "await",
1355        "bigint",
1356        "boolean",
1357        "break",
1358        "case",
1359        "catch",
1360        "class",
1361        "struct",
1362        "const",
1363        "continue",
1364        "debugger",
1365        "declare",
1366        "default",
1367        "delete",
1368        "do",
1369        "else",
1370        "enum",
1371        "export",
1372        "extends",
1373        "false",
1374        "finally",
1375        "for",
1376        "function",
1377        "if",
1378        "implements",
1379        "import",
1380        "in",
1381        "infer",
1382        "instanceof",
1383        "interface",
1384        "keyof",
1385        "let",
1386        "module",
1387        "namespace",
1388        "never",
1389        "new",
1390        "null",
1391        "number",
1392        "object",
1393        "package",
1394        "readonly",
1395        "return",
1396        "satisfies",
1397        "string",
1398        "super",
1399        "switch",
1400        "symbol",
1401        "this",
1402        "throw",
1403        "true",
1404        "try",
1405        "type",
1406        "typeof",
1407        "unique",
1408        "unknown",
1409        "var",
1410        "void",
1411        "while",
1412        "with",
1413        "yield",
1414    ].map(keywordEntry);
1415
1416    export const statementKeywords: readonly ExpectedCompletionEntryObject[] = statementKeywordsWithTypes.filter(k => {
1417        const name = k.name;
1418        switch (name) {
1419            case "false":
1420            case "true":
1421            case "null":
1422            case "void":
1423                return true;
1424            case "declare":
1425            case "module":
1426                return false;
1427            default:
1428                return !ts.contains(typeKeywords, k);
1429        }
1430    });
1431
1432    export const statementInJsKeywords = getInJsKeywords(statementKeywords);
1433
1434    export const globalsVars: readonly ExpectedCompletionEntryObject[] = [
1435        varEntry("Array"),
1436        varEntry("ArrayBuffer"),
1437        varEntry("Boolean"),
1438        varEntry("DataView"),
1439        varEntry("Date"),
1440        functionEntry("decodeURI"),
1441        functionEntry("decodeURIComponent"),
1442        functionEntry("encodeURI"),
1443        functionEntry("encodeURIComponent"),
1444        varEntry("Error"),
1445        deprecatedFunctionEntry("escape"),
1446        functionEntry("eval"),
1447        varEntry("EvalError"),
1448        varEntry("Float32Array"),
1449        varEntry("Float64Array"),
1450        varEntry("Function"),
1451        varEntry("Infinity"),
1452        moduleEntry("Intl"),
1453        varEntry("Int16Array"),
1454        varEntry("Int32Array"),
1455        varEntry("Int8Array"),
1456        functionEntry("isFinite"),
1457        functionEntry("isNaN"),
1458        varEntry("JSON"),
1459        varEntry("Math"),
1460        varEntry("NaN"),
1461        varEntry("Number"),
1462        varEntry("Object"),
1463        functionEntry("parseFloat"),
1464        functionEntry("parseInt"),
1465        varEntry("RangeError"),
1466        varEntry("ReferenceError"),
1467        varEntry("RegExp"),
1468        varEntry("String"),
1469        varEntry("SyntaxError"),
1470        varEntry("TypeError"),
1471        varEntry("Uint16Array"),
1472        varEntry("Uint32Array"),
1473        varEntry("Uint8Array"),
1474        varEntry("Uint8ClampedArray"),
1475        deprecatedFunctionEntry("unescape"),
1476        varEntry("URIError"),
1477    ];
1478
1479    const globalKeywordsInsideFunction: readonly ExpectedCompletionEntryObject[] = [
1480        "as",
1481        "async",
1482        "await",
1483        "break",
1484        "case",
1485        "catch",
1486        "class",
1487        "const",
1488        "continue",
1489        "debugger",
1490        "default",
1491        "delete",
1492        "do",
1493        "else",
1494        "enum",
1495        "export",
1496        "extends",
1497        "false",
1498        "finally",
1499        "for",
1500        "function",
1501        "if",
1502        "implements",
1503        "import",
1504        "in",
1505        "instanceof",
1506        "interface",
1507        "let",
1508        "new",
1509        "null",
1510        "package",
1511        "return",
1512        "satisfies",
1513        "struct",
1514        "super",
1515        "switch",
1516        "this",
1517        "throw",
1518        "true",
1519        "try",
1520        "type",
1521        "typeof",
1522        "var",
1523        "void",
1524        "while",
1525        "with",
1526        "yield",
1527    ].map(keywordEntry);
1528
1529    function compareExpectedCompletionEntries(a: ExpectedCompletionEntry, b: ExpectedCompletionEntry) {
1530        const aSortText = typeof a !== "string" && a.sortText || ts.Completions.SortText.LocationPriority;
1531        const bSortText = typeof b !== "string" && b.sortText || ts.Completions.SortText.LocationPriority;
1532        const bySortText = ts.compareStringsCaseSensitiveUI(aSortText, bSortText);
1533        if (bySortText !== ts.Comparison.EqualTo) return bySortText;
1534        return ts.compareStringsCaseSensitiveUI(typeof a === "string" ? a : a.name, typeof b === "string" ? b : b.name);
1535    }
1536
1537    export const undefinedVarEntry: ExpectedCompletionEntryObject = {
1538        name: "undefined",
1539        kind: "var",
1540        sortText: SortText.GlobalsOrKeywords
1541    };
1542    // TODO: many of these are inappropriate to always provide
1543    export const globalsInsideFunction = (plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }): readonly ExpectedCompletionEntry[] => [
1544        { name: "arguments", kind: "local var" },
1545        ...plus,
1546        globalThisEntry,
1547        ...options?.noLib ? [] : globalsVars,
1548        undefinedVarEntry,
1549        ...globalKeywordsInsideFunction,
1550    ].sort(compareExpectedCompletionEntries);
1551
1552    const globalInJsKeywordsInsideFunction = getInJsKeywords(globalKeywordsInsideFunction);
1553
1554    // TODO: many of these are inappropriate to always provide
1555    export const globalsInJsInsideFunction = (plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }): readonly ExpectedCompletionEntry[] => [
1556        { name: "arguments", kind: "local var" },
1557        globalThisEntry,
1558        ...options?.noLib ? [] : globalsVars,
1559        ...plus,
1560        undefinedVarEntry,
1561        ...globalInJsKeywordsInsideFunction,
1562    ].sort(compareExpectedCompletionEntries);
1563
1564    // TODO: many of these are inappropriate to always provide
1565    export const globalKeywords: readonly ExpectedCompletionEntryObject[] = [
1566        "abstract",
1567        "any",
1568        "as",
1569        "asserts",
1570        "async",
1571        "await",
1572        "bigint",
1573        "boolean",
1574        "break",
1575        "case",
1576        "catch",
1577        "class",
1578        "const",
1579        "continue",
1580        "debugger",
1581        "declare",
1582        "default",
1583        "delete",
1584        "do",
1585        "else",
1586        "enum",
1587        "export",
1588        "extends",
1589        "false",
1590        "finally",
1591        "for",
1592        "function",
1593        "if",
1594        "implements",
1595        "import",
1596        "in",
1597        "infer",
1598        "instanceof",
1599        "interface",
1600        "keyof",
1601        "let",
1602        "module",
1603        "namespace",
1604        "never",
1605        "new",
1606        "null",
1607        "number",
1608        "object",
1609        "package",
1610        "readonly",
1611        "return",
1612        "satisfies",
1613        "string",
1614        "struct",
1615        "super",
1616        "switch",
1617        "symbol",
1618        "this",
1619        "throw",
1620        "true",
1621        "try",
1622        "type",
1623        "typeof",
1624        "unique",
1625        "unknown",
1626        "var",
1627        "void",
1628        "while",
1629        "with",
1630        "yield",
1631    ].map(keywordEntry);
1632
1633    export const globalInJsKeywords = getInJsKeywords(globalKeywords);
1634
1635    export const insideMethodKeywords: readonly ExpectedCompletionEntryObject[] = [
1636        "as",
1637        "async",
1638        "await",
1639        "break",
1640        "case",
1641        "catch",
1642        "class",
1643        "const",
1644        "continue",
1645        "debugger",
1646        "default",
1647        "delete",
1648        "do",
1649        "else",
1650        "enum",
1651        "export",
1652        "extends",
1653        "false",
1654        "finally",
1655        "for",
1656        "function",
1657        "if",
1658        "implements",
1659        "import",
1660        "in",
1661        "instanceof",
1662        "interface",
1663        "let",
1664        "new",
1665        "null",
1666        "package",
1667        "return",
1668        "satisfies",
1669        "struct",
1670        "super",
1671        "switch",
1672        "this",
1673        "throw",
1674        "true",
1675        "try",
1676        "type",
1677        "typeof",
1678        "var",
1679        "void",
1680        "while",
1681        "with",
1682        "yield",
1683    ].map(keywordEntry);
1684
1685    export const insideMethodInJsKeywords = getInJsKeywords(insideMethodKeywords);
1686
1687    export const globals: readonly ExpectedCompletionEntryObject[] = [
1688        globalThisEntry,
1689        ...globalsVars,
1690        undefinedVarEntry,
1691        ...globalKeywords
1692    ].sort(compareExpectedCompletionEntries);
1693
1694    export const globalsInJs: readonly ExpectedCompletionEntryObject[] = [
1695        globalThisEntry,
1696        ...globalsVars,
1697        undefinedVarEntry,
1698        ...globalInJsKeywords
1699    ].sort(compareExpectedCompletionEntries);
1700
1701    export function globalsPlus(plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }) {
1702        return combineExpectedCompletionEntries("globalsPlus", [
1703            globalThisEntry,
1704            ...options?.noLib ? [] : globalsVars,
1705            undefinedVarEntry,
1706            ...globalKeywords,
1707        ], plus);
1708    }
1709
1710    export function globalsInJsPlus(plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }) {
1711        return combineExpectedCompletionEntries("globalsInJsPlus", [
1712            globalThisEntry,
1713            ...options?.noLib ? [] : globalsVars,
1714            undefinedVarEntry,
1715            ...globalInJsKeywords,
1716        ], plus);
1717    }
1718}
1719
1720export interface ReferenceGroup {
1721    definition: ReferenceGroupDefinition;
1722    ranges: FourSlash.Range[];
1723}
1724
1725export type ReferenceGroupDefinition = string | { text: string, range: FourSlash.Range };
1726
1727export interface ApplyRefactorOptions {
1728    refactorName: string;
1729    actionName: string;
1730    actionDescription: string;
1731    newContent: NewFileContent;
1732    triggerReason?: ts.RefactorTriggerReason;
1733}
1734
1735export type ExpectedCompletionEntry = string | ExpectedCompletionEntryObject;
1736export interface ExpectedCompletionEntryObject {
1737    readonly name: string;
1738    readonly source?: string;
1739    readonly insertText?: string;
1740    readonly replacementSpan?: FourSlash.Range;
1741    readonly hasAction?: boolean; // If not specified, will assert that this is false.
1742    readonly isRecommended?: boolean; // If not specified, will assert that this is false.
1743    readonly isFromUncheckedFile?: boolean; // If not specified, won't assert about this
1744    readonly kind?: string; // If not specified, won't assert about this
1745    readonly isPackageJsonImport?: boolean; // If not specified, won't assert about this
1746    readonly isSnippet?: boolean;
1747    readonly kindModifiers?: string; // Must be paired with 'kind'
1748    readonly text?: string;
1749    readonly documentation?: string;
1750    readonly sourceDisplay?: string;
1751    readonly labelDetails?: ExpectedCompletionEntryLabelDetails;
1752    readonly tags?: readonly ts.JSDocTagInfo[];
1753    readonly sortText?: ts.Completions.SortText;
1754}
1755
1756export interface ExpectedCompletionEntryLabelDetails {
1757    detail?: string;
1758    description?: string;
1759}
1760
1761export type ExpectedExactCompletionsPlus = readonly ExpectedCompletionEntry[] & {
1762    plusFunctionName: string,
1763    plusArgument: readonly ExpectedCompletionEntry[]
1764};
1765
1766export interface VerifyCompletionsOptions {
1767    readonly marker?: ArrayOrSingle<string | FourSlash.Marker>;
1768    readonly isNewIdentifierLocation?: boolean; // Always tested
1769    readonly isGlobalCompletion?: boolean; // Only tested if set
1770    readonly optionalReplacementSpan?: FourSlash.Range; // Only tested if set
1771    readonly exact?: ArrayOrSingle<ExpectedCompletionEntry> | ExpectedExactCompletionsPlus;
1772    readonly unsorted?: readonly ExpectedCompletionEntry[];
1773    readonly includes?: ArrayOrSingle<ExpectedCompletionEntry>;
1774    readonly excludes?: ArrayOrSingle<string>;
1775    readonly preferences?: ts.UserPreferences;
1776    readonly triggerCharacter?: ts.CompletionsTriggerCharacter;
1777}
1778
1779export interface VerifySignatureHelpOptions {
1780    readonly marker?: ArrayOrSingle<string | FourSlash.Marker>;
1781    /** @default 1 */
1782    readonly overloadsCount?: number;
1783    /** @default undefined */
1784    readonly docComment?: string;
1785    readonly text?: string;
1786    readonly parameterName?: string;
1787    readonly parameterSpan?: string;
1788    /** @default undefined */
1789    readonly parameterDocComment?: string;
1790    readonly parameterCount?: number;
1791    readonly argumentCount?: number;
1792    /** @default false */
1793    readonly isVariadic?: boolean;
1794    /** @default ts.emptyArray */
1795    readonly tags?: readonly ts.JSDocTagInfo[];
1796    readonly triggerReason?: ts.SignatureHelpTriggerReason;
1797    readonly overrideSelectedItemIndex?: number;
1798}
1799
1800export interface VerifyNavigateToOptions {
1801    readonly pattern: string;
1802    readonly fileName?: string;
1803    readonly expected: readonly ExpectedNavigateToItem[];
1804}
1805
1806export interface ExpectedNavigateToItem {
1807    readonly name: string;
1808    readonly kind: ts.ScriptElementKind;
1809    readonly kindModifiers?: string;
1810    readonly matchKind?: keyof typeof ts.PatternMatchKind;
1811    readonly isCaseSensitive?: boolean;
1812    readonly range: FourSlash.Range;
1813    readonly containerName?: string;
1814    readonly containerKind?: ts.ScriptElementKind;
1815}
1816
1817export interface VerifyInlayHintsOptions {
1818    text: string;
1819    position: number;
1820    kind?: ts.InlayHintKind;
1821    whitespaceBefore?: boolean;
1822    whitespaceAfter?: boolean;
1823}
1824
1825export type ArrayOrSingle<T> = T | readonly T[];
1826
1827export interface VerifyCompletionListContainsOptions extends ts.UserPreferences {
1828    triggerCharacter?: ts.CompletionsTriggerCharacter;
1829    sourceDisplay: string;
1830    isRecommended?: true;
1831    insertText?: string;
1832    replacementSpan?: FourSlash.Range;
1833}
1834
1835export interface VerifyDocumentHighlightsOptions {
1836    filesToSearch?: readonly string[];
1837}
1838
1839export type NewFileContent = string | { readonly [filename: string]: string };
1840
1841export interface NewContentOptions {
1842    // Exactly one of these should be defined.
1843    newFileContent?: NewFileContent;
1844    newRangeContent?: string;
1845}
1846
1847export interface VerifyCodeFixOptions extends NewContentOptions {
1848    readonly description: string | [string, ...(string | number)[]] | DiagnosticIgnoredInterpolations;
1849    readonly errorCode?: number;
1850    readonly index?: number;
1851    readonly preferences?: ts.UserPreferences;
1852    readonly applyChanges?: boolean;
1853    readonly commands?: readonly ts.CodeActionCommand[];
1854}
1855
1856export interface VerifyCodeFixAvailableOptions {
1857    description: string;
1858    commands?: ts.CodeActionCommand[];
1859}
1860
1861export interface VerifyCodeFixAllOptions {
1862    fixId: string;
1863    fixAllDescription: string;
1864    newFileContent: NewFileContent;
1865    commands: readonly {}[];
1866}
1867
1868export interface VerifyRefactorOptions {
1869    name: string;
1870    actionName: string;
1871    refactors: readonly ts.ApplicableRefactorInfo[];
1872}
1873
1874export interface VerifyCompletionActionOptions extends NewContentOptions {
1875    name: string;
1876    source?: string;
1877    data?: ts.CompletionEntryData;
1878    description: string;
1879    preferences?: ts.UserPreferences;
1880}
1881
1882export interface Diagnostic {
1883    message: string;
1884    range?: FourSlash.Range;
1885    code: number;
1886    reportsUnnecessary?: true;
1887    reportsDeprecated?: true;
1888}
1889
1890export interface GetEditsForFileRenameOptions {
1891    readonly oldPath: string;
1892    readonly newPath: string;
1893    readonly newFileContents: { readonly [fileName: string]: string };
1894    readonly preferences?: ts.UserPreferences;
1895}
1896
1897export interface MoveToNewFileOptions {
1898    readonly newFileContents: { readonly [fileName: string]: string };
1899    readonly preferences?: ts.UserPreferences;
1900}
1901
1902export type RenameLocationsOptions = readonly RenameLocationOptions[] | {
1903    readonly findInStrings?: boolean;
1904    readonly findInComments?: boolean;
1905    readonly ranges: readonly RenameLocationOptions[];
1906    readonly providePrefixAndSuffixTextForRename?: boolean;
1907};
1908export interface DiagnosticIgnoredInterpolations {
1909    template: string
1910}
1911export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string };
1912export interface RenameOptions {
1913    readonly findInStrings?: boolean;
1914    readonly findInComments?: boolean;
1915    readonly providePrefixAndSuffixTextForRename?: boolean;
1916}
1917