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