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