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