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