diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 53c52829f3..d2d3a504ad 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -213,6 +213,10 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined { case "renameInfoSucceeded": case "renameInfoFailed": return parseRenameInfo(func.text, callExpression.arguments); + case "getSemanticDiagnostics": + case "getSuggestionDiagnostics": + case "getSyntacticDiagnostics": + return parseVerifyDiagnostics(func.text, callExpression.arguments); } } // `goTo....` @@ -1260,6 +1264,105 @@ function parseBaselineInlayHints(args: readonly ts.Expression[]): [VerifyBaselin }]; } +function parseVerifyDiagnostics(funcName: string, args: readonly ts.Expression[]): [VerifyDiagnosticsCmd] | undefined { + if (!args[0] || !ts.isArrayLiteralExpression(args[0])) { + console.error(`Expected an array literal argument in verify.${funcName}`); + return undefined; + } + const goArgs: string[] = []; + for (const expr of args[0].elements) { + const diag = parseExpectedDiagnostic(expr); + if (diag === undefined) { + return undefined; + } + goArgs.push(diag); + } + return [{ + kind: "verifyDiagnostics", + arg: goArgs.length > 0 ? `[]*lsproto.Diagnostic{\n${goArgs.join(",\n")},\n}` : "nil", + isSuggestion: funcName === "getSuggestionDiagnostics", + }]; +} + +function parseExpectedDiagnostic(expr: ts.Expression): string | undefined { + if (!ts.isObjectLiteralExpression(expr)) { + console.error(`Expected object literal expression for expected diagnostic, got ${expr.getText()}`); + return undefined; + } + + const diagnosticProps: string[] = []; + + for (const prop of expr.properties) { + if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) { + console.error(`Expected property assignment with identifier name for expected diagnostic, got ${prop.getText()}`); + return undefined; + } + + const propName = prop.name.text; + const init = prop.initializer; + + switch (propName) { + case "message": { + let messageInit; + if (messageInit = getStringLiteralLike(init)) { + messageInit.text = messageInit.text.replace("/tests/cases/fourslash", ""); + diagnosticProps.push(`Message: ${getGoStringLiteral(messageInit.text)},`); + } + else { + console.error(`Expected string literal for diagnostic message, got ${init.getText()}`); + return undefined; + } + break; + } + case "code": { + let codeInit; + if (codeInit = getNumericLiteral(init)) { + diagnosticProps.push(`Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](${codeInit.text})},`); + } + else { + console.error(`Expected numeric literal for diagnostic code, got ${init.getText()}`); + return undefined; + } + break; + } + case "range": { + // Handle range references like ranges[0] + const rangeArg = parseBaselineMarkerOrRangeArg(init); + if (rangeArg) { + diagnosticProps.push(`Range: ${rangeArg}.LSRange,`); + } + else { + console.error(`Expected range reference for diagnostic range, got ${init.getText()}`); + return undefined; + } + break; + } + case "reportsDeprecated": { + if (init.kind === ts.SyntaxKind.TrueKeyword) { + diagnosticProps.push(`Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated},`); + } + break; + } + case "reportsUnnecessary": { + if (init.kind === ts.SyntaxKind.TrueKeyword) { + diagnosticProps.push(`Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagUnnecessary},`); + } + break; + } + default: + console.error(`Unrecognized property in expected diagnostic: ${propName}`); + return undefined; + } + } + + if (diagnosticProps.length === 0) { + console.error(`No valid properties found in diagnostic object`); + return undefined; + } + + return `&lsproto.Diagnostic{\n${diagnosticProps.join("\n")}\n}`; +} + function stringToTristate(s: string): string { switch (s) { case "true": @@ -1395,7 +1498,7 @@ function parseBaselineMarkerOrRangeArg(arg: ts.Expression): string | undefined { return result; } } - console.error(`Unrecognized argument in verify.baselineRename: ${arg.getText()}`); + console.error(`Unrecognized range argument: ${arg.getText()}`); return undefined; } @@ -1716,12 +1819,6 @@ interface VerifyBaselineFindAllReferencesCmd { ranges?: boolean; } -interface VerifyBaselineFindAllReferencesCmd { - kind: "verifyBaselineFindAllReferences"; - markers: string[]; - ranges?: boolean; -} - interface VerifyBaselineGoToDefinitionCmd { kind: "verifyBaselineGoToDefinition" | "verifyBaselineGoToType"; markers: string[]; @@ -1789,6 +1886,12 @@ interface VerifyRenameInfoCmd { preferences: string; } +interface VerifyDiagnosticsCmd { + kind: "verifyDiagnostics"; + arg: string; + isSuggestion: boolean; +} + type Cmd = | VerifyCompletionsCmd | VerifyApplyCodeActionFromCompletionCmd @@ -1804,7 +1907,8 @@ type Cmd = | VerifyBaselineRenameCmd | VerifyRenameInfoCmd | VerifyBaselineInlayHintsCmd - | VerifyImportFixAtPositionCmd; + | VerifyImportFixAtPositionCmd + | VerifyDiagnosticsCmd; function generateVerifyCompletions({ marker, args, isNewIdentifierLocation, andApplyCodeActionArgs }: VerifyCompletionsCmd): string { let expectedList: string; @@ -1953,6 +2057,9 @@ function generateCmd(cmd: Cmd): string { return generateBaselineInlayHints(cmd); case "verifyImportFixAtPosition": return generateImportFixAtPosition(cmd); + case "verifyDiagnostics": + const funcName = cmd.isSuggestion ? "VerifySuggestionDiagnostics" : "VerifyNonSuggestionDiagnostics"; + return `f.${funcName}(t, ${cmd.arg})`; default: let neverCommand: never = cmd; throw new Error(`Unknown command kind: ${neverCommand as Cmd["kind"]}`); diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index a54667b7b0..5db600146a 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -13,6 +13,7 @@ TestAutoImportCrossProject_symlinks_toDist TestAutoImportCrossProject_symlinks_toSrc TestAutoImportFileExcludePatterns3 TestAutoImportJsDocImport1 +TestAutoImportModuleNone1 TestAutoImportNodeNextJSRequire TestAutoImportPathsAliasesAndBarrels TestAutoImportPnpm @@ -328,6 +329,7 @@ TestInstanceTypesForGenericType1 TestJavascriptModules20 TestJavascriptModulesTypeImport TestJsDocAugments +TestJsDocAugmentsAndExtends TestJsDocExtends TestJsDocFunctionSignatures10 TestJsDocFunctionSignatures11 diff --git a/internal/fourslash/_scripts/manualTests.txt b/internal/fourslash/_scripts/manualTests.txt index 492d95e520..4c1c0b91fb 100644 --- a/internal/fourslash/_scripts/manualTests.txt +++ b/internal/fourslash/_scripts/manualTests.txt @@ -2,6 +2,7 @@ completionListInClosedFunction05 completionsAtIncompleteObjectLiteralProperty completionsSelfDeclaring1 completionsWithDeprecatedTag4 +parserCorruptionAfterMapInClass renameDefaultKeyword renameForDefaultExport01 tsxCompletion12 diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 4a1a78d139..e09e4fe637 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -556,6 +556,16 @@ func (f *FourslashTest) Ranges() []*RangeMarker { return f.testData.Ranges } +func (f *FourslashTest) getRangesInFile(fileName string) []*RangeMarker { + var rangesInFile []*RangeMarker + for _, rangeMarker := range f.testData.Ranges { + if rangeMarker.FileName() == fileName { + rangesInFile = append(rangesInFile, rangeMarker) + } + } + return rangesInFile +} + func (f *FourslashTest) ensureActiveFile(t *testing.T, filename string) { if f.activeFilename != filename { f.openFile(t, filename) @@ -913,8 +923,9 @@ func ignorePaths(paths ...string) cmp.Option { } var ( - completionIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data") - autoImportIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data", ".LabelDetails", ".Detail", ".AdditionalTextEdits") + completionIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data") + autoImportIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data", ".LabelDetails", ".Detail", ".AdditionalTextEdits") + diagnosticsIgnoreOpts = ignorePaths(".Severity", ".Source", ".RelatedInformation") ) func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual *lsproto.CompletionItem, expected *lsproto.CompletionItem) { @@ -1815,7 +1826,12 @@ func (f *FourslashTest) ReplaceLine(t *testing.T, lineIndex int, text string) { func (f *FourslashTest) selectLine(t *testing.T, lineIndex int) { script := f.getScriptInfo(f.activeFilename) start := script.lineMap.LineStarts[lineIndex] - end := script.lineMap.LineStarts[lineIndex+1] - 1 + var end core.TextPos + if lineIndex+1 >= len(script.lineMap.LineStarts) { + end = core.TextPos(len(script.content)) + } else { + end = script.lineMap.LineStarts[lineIndex+1] - 1 + } f.selectRange(t, core.NewTextRange(int(start), int(end))) } @@ -2474,6 +2490,65 @@ func (f *FourslashTest) VerifyBaselineInlayHints( f.addResultToBaseline(t, "Inlay Hints", strings.Join(annotations, "\n\n")) } +func (f *FourslashTest) VerifyDiagnostics(t *testing.T, expected []*lsproto.Diagnostic) { + f.verifyDiagnostics(t, expected, func(d *lsproto.Diagnostic) bool { return true }) +} + +// Similar to `VerifyDiagnostics`, but excludes suggestion diagnostics returned from server. +func (f *FourslashTest) VerifyNonSuggestionDiagnostics(t *testing.T, expected []*lsproto.Diagnostic) { + f.verifyDiagnostics(t, expected, func(d *lsproto.Diagnostic) bool { return !isSuggestionDiagnostic(d) }) +} + +// Similar to `VerifyDiagnostics`, but includes only suggestion diagnostics returned from server. +func (f *FourslashTest) VerifySuggestionDiagnostics(t *testing.T, expected []*lsproto.Diagnostic) { + f.verifyDiagnostics(t, expected, isSuggestionDiagnostic) +} + +func (f *FourslashTest) verifyDiagnostics(t *testing.T, expected []*lsproto.Diagnostic, filterDiagnostics func(*lsproto.Diagnostic) bool) { + params := &lsproto.DocumentDiagnosticParams{ + TextDocument: lsproto.TextDocumentIdentifier{ + Uri: lsconv.FileNameToDocumentURI(f.activeFilename), + }, + } + resMsg, result, resultOk := sendRequest(t, f, lsproto.TextDocumentDiagnosticInfo, params) + if resMsg == nil { + t.Fatal("Nil response received for diagnostics request") + } + if !resultOk { + t.Fatalf("Unexpected response type for diagnostics request: %T", resMsg.AsResponse().Result) + } + + var actualDiagnostics []*lsproto.Diagnostic + if result.FullDocumentDiagnosticReport != nil { + actualDiagnostics = append(actualDiagnostics, result.FullDocumentDiagnosticReport.Items...) + } + actualDiagnostics = core.Filter(actualDiagnostics, filterDiagnostics) + emptyRange := lsproto.Range{} + expectedWithRanges := make([]*lsproto.Diagnostic, len(expected)) + for i, diag := range expected { + if diag.Range == emptyRange { + rangesInFile := f.getRangesInFile(f.activeFilename) + if len(rangesInFile) == 0 { + t.Fatalf("No ranges found in file %s to assign to diagnostic with empty range", f.activeFilename) + } + diagWithRange := *diag + diagWithRange.Range = rangesInFile[0].LSRange + expectedWithRanges[i] = &diagWithRange + } else { + expectedWithRanges[i] = diag + } + } + if len(actualDiagnostics) == 0 && len(expectedWithRanges) == 0 { + return + } + assertDeepEqual(t, actualDiagnostics, expectedWithRanges, "Diagnostics do not match expected", diagnosticsIgnoreOpts) +} + +func isSuggestionDiagnostic(diag *lsproto.Diagnostic) bool { + return diag.Tags != nil && len(*diag.Tags) > 0 || + (diag.Severity != nil && *diag.Severity == lsproto.DiagnosticSeverityHint) +} + func isLibFile(fileName string) bool { baseName := tspath.GetBaseFileName(fileName) if strings.HasPrefix(baseName, "lib.") && strings.HasSuffix(baseName, ".d.ts") { diff --git a/internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go b/internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go new file mode 100644 index 0000000000..b4be6d4cad --- /dev/null +++ b/internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go @@ -0,0 +1,19 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestAnnotateWithTypeFromJSDoc2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: test123.ts +/** @type {number} */ +var [|x|]: string;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/autoImportModuleNone1_test.go b/internal/fourslash/tests/gen/autoImportModuleNone1_test.go new file mode 100644 index 0000000000..ccaa1dbf54 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportModuleNone1_test.go @@ -0,0 +1,37 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestAutoImportModuleNone1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: none +// @moduleResolution: bundler +// @target: es5 +// @Filename: /node_modules/dep/index.d.ts +export const x: number; +// @Filename: /index.ts + x/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Excludes: []string{ + "x", + }, + }, + }) + f.ReplaceLine(t, 0, "import { x } from 'dep'; x;") + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/autoImportModuleNone2_test.go b/internal/fourslash/tests/gen/autoImportModuleNone2_test.go new file mode 100644 index 0000000000..ffa9951af4 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportModuleNone2_test.go @@ -0,0 +1,48 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/ls" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestAutoImportModuleNone2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: none +// @moduleResolution: bundler +// @target: es2015 +// @Filename: /node_modules/dep/index.d.ts +export const x: number; +// @Filename: /index.ts + x/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "x", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dep", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.ReplaceLine(t, 0, "import { x } from 'dep'; x;") + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go b/internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go new file mode 100644 index 0000000000..b186df0321 --- /dev/null +++ b/internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go @@ -0,0 +1,19 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCodeFixInferFromUsageBindingElement(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function f([car, cdr]) { + return car + cdr + 1 +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go new file mode 100644 index 0000000000..40bcd52600 --- /dev/null +++ b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go @@ -0,0 +1,24 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCodeFixRemoveUnnecessaryAwait_mixedUnion(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: esnext +async function fn1(a: Promise | void) { + await a; +} + +async function fn2 | void>(a: T) { + await a; +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go new file mode 100644 index 0000000000..b795b91523 --- /dev/null +++ b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCodeFixRemoveUnnecessaryAwait_notAvailableOnReturn(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: esnext +async function fn(): Promise { + return 0; +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go b/internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go new file mode 100644 index 0000000000..63f9f0d954 --- /dev/null +++ b/internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go @@ -0,0 +1,18 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCodeFixUnreachableCode_noSuggestionIfDisabled(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowUnreachableCode: true +if (false) 0;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go b/internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go new file mode 100644 index 0000000000..1f238e081f --- /dev/null +++ b/internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go @@ -0,0 +1,18 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCodeFixUnusedLabel_noSuggestionIfDisabled(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowUnusedLabels: true +foo: while (true) {}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go b/internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go new file mode 100644 index 0000000000..690efe9698 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go @@ -0,0 +1,31 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCompletionsDotInArrayLiteralInObjectLiteral(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `const o = { x: [[|.|][||]/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyNonSuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](1109)}, + Message: "Expression expected.", + Range: f.Ranges()[0].LSRange, + }, + { + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](1003)}, + Message: "Identifier expected.", + Range: f.Ranges()[1].LSRange, + }, + }) + f.VerifyCompletions(t, "", nil) +} diff --git a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go new file mode 100644 index 0000000000..639cb7e585 --- /dev/null +++ b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGetJavaScriptSyntacticDiagnostics21(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @experimentalDecorators: true +// @Filename: a.js +@internal class C {}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go new file mode 100644 index 0000000000..59b854c310 --- /dev/null +++ b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go @@ -0,0 +1,19 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGetJavaScriptSyntacticDiagnostics22(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: a.js +function foo(...a) {}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go new file mode 100644 index 0000000000..9d77d39070 --- /dev/null +++ b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGetJavaScriptSyntacticDiagnostics23(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: a.js +function Person(age) { + if (age >= 18) { + this.canVote = true; + } else { + this.canVote = false; + } +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyNonSuggestionDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/importTypesDeclarationDiagnosticsNoServerError_test.go b/internal/fourslash/tests/gen/importTypesDeclarationDiagnosticsNoServerError_test.go new file mode 100644 index 0000000000..52acdbbea4 --- /dev/null +++ b/internal/fourslash/tests/gen/importTypesDeclarationDiagnosticsNoServerError_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestImportTypesDeclarationDiagnosticsNoServerError(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @declaration: true +// @Filename: node_modules/foo/index.d.ts +export function f(): I; +export interface I { + x: number; +} +// @Filename: a.ts +import { f } from "foo"; +export const x = f();` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFileNumber(t, 1) + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/issue57429_test.go b/internal/fourslash/tests/gen/issue57429_test.go new file mode 100644 index 0000000000..26985271fd --- /dev/null +++ b/internal/fourslash/tests/gen/issue57429_test.go @@ -0,0 +1,41 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestIssue57429(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +function Builder(def: I) { + return def; +} + +interface IThing { + doThing: (args: { value: object }) => string + doAnotherThing: () => void +} + +Builder({ + doThing(args: { value: object }) { + const { v/*1*/alue } = this.[|args|] + return ` + "`" + `${value}` + "`" + ` + }, + doAnotherThing() { }, +})` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyQuickInfoAt(t, "1", "const value: any", "") + f.VerifyNonSuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Message: "Property 'args' does not exist on type 'IThing'.", + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](2339)}, + }, + }) +} diff --git a/internal/fourslash/tests/gen/issue57585-2_test.go b/internal/fourslash/tests/gen/issue57585-2_test.go new file mode 100644 index 0000000000..480c3837ab --- /dev/null +++ b/internal/fourslash/tests/gen/issue57585-2_test.go @@ -0,0 +1,87 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestIssue57585_2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// @target: esnext +// @lib: esnext +declare const EffectTypeId: unique symbol; + +type Covariant = (_: never) => A; + +interface VarianceStruct { + readonly _V: string; + readonly _A: Covariant; + readonly _E: Covariant; + readonly _R: Covariant; +} + +interface Variance { + readonly [EffectTypeId]: VarianceStruct; +} + +type Success> = [T] extends [ + Effect, +] + ? _A + : never; + +declare const YieldWrapTypeId: unique symbol; + +class YieldWrap { + readonly #value: T; + constructor(value: T) { + this.#value = value; + } + [YieldWrapTypeId](): T { + return this.#value; + } +} + +interface EffectGenerator> { + next(...args: ReadonlyArray): IteratorResult, Success>; +} + +interface Effect + extends Variance { + [Symbol.iterator](): EffectGenerator>; +} + +declare const gen: { + >, AEff>( + f: () => Generator, + ): Effect< + AEff, + [Eff] extends [never] + ? never + : [Eff] extends [YieldWrap>] + ? E + : never, + [Eff] extends [never] + ? never + : [Eff] extends [YieldWrap>] + ? R + : never + >; +}; + +declare const succeed: (value: A) => Effect; + +gen(function* () { + const a = yield* succeed(1); + const b/*1*/ = yield* succeed(2); + return a + b; +});` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyQuickInfoAt(t, "1", "const b: number", "") + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go b/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go new file mode 100644 index 0000000000..e5faf61d71 --- /dev/null +++ b/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go @@ -0,0 +1,43 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsDocAugmentsAndExtends(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @checkJs: true +// @Filename: dummy.js +/** + * @augments {Thing} + * [|@extends {Thing}|] + */ +class MyStringThing extends Thing { + constructor() { + super(); + var x = this.mine; + x/**/; + } +} +// @Filename: declarations.d.ts +declare class Thing { + mine: T; +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyQuickInfoIs(t, "(local var) x: number", "") + f.VerifyNonSuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Message: "Class declarations cannot have more than one '@augments' or '@extends' tag.", + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](8025)}, + }, + }) +} diff --git a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion22_test.go b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion22_test.go new file mode 100644 index 0000000000..ae9c7f20d8 --- /dev/null +++ b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion22_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsdocDeprecated_suggestion22(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: /a.ts +const foo: { + /** + * @deprecated + */ + (a: string, b: string): string; + (a: string, b: number): string; +} = (a: string, b: string | number) => a + b; + +[|foo|](1, 1);` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go new file mode 100644 index 0000000000..11c6cac6f2 --- /dev/null +++ b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go @@ -0,0 +1,33 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsdocDeprecated_suggestion5(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @checkJs: true +// @allowJs: true +// @Filename: jsdocDeprecated_suggestion5.js +/** @typedef {{ email: string, nickName?: string }} U2 */ +/** @type {U2} */ +const u2 = { email: "" } +/** + * @callback K + * @param {any} ctx + * @return {void} + */ +/** @type {K} */ +const cc = _k => {} +/** @enum {number} */ +const DOOM = { e: 1, m: 1 } +/** @type {DOOM} */ +const kneeDeep = DOOM.e` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go new file mode 100644 index 0000000000..3576d35c72 --- /dev/null +++ b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go @@ -0,0 +1,25 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsdocDeprecated_suggestion7(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `enum Direction { + Left = -1, + Right = 1, +} +type T = Direction.Left +/** @deprecated */ +const x = 1 +type x = string +var y: x = 'hi'` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go b/internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go new file mode 100644 index 0000000000..d11af52b5e --- /dev/null +++ b/internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go @@ -0,0 +1,30 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsdocParam_suggestion1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: a.ts +/** + * @param options - whatever + * @param options.zone - equally bad + */ +declare function bad(options: any): void + +/** + * @param {number} obtuse + */ +function worse(): void { + arguments +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "a.ts") + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go new file mode 100644 index 0000000000..2831a1ee38 --- /dev/null +++ b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go @@ -0,0 +1,18 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsxElementExtendsNoCrash1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: index.tsx +` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go new file mode 100644 index 0000000000..6be1dca04d --- /dev/null +++ b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go @@ -0,0 +1,18 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsxElementExtendsNoCrash2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: index.tsx +` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go new file mode 100644 index 0000000000..ba8dde6417 --- /dev/null +++ b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go @@ -0,0 +1,18 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestJsxElementExtendsNoCrash3(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: index.tsx +` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go b/internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go new file mode 100644 index 0000000000..acb0a5dfc8 --- /dev/null +++ b/internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go @@ -0,0 +1,18 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestModuleDeclarationDeprecated_suggestion2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: a.ts +declare module` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go b/internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go new file mode 100644 index 0000000000..5538b18a20 --- /dev/null +++ b/internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go @@ -0,0 +1,22 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestRefactorConvertToEsModule_notAtTopLevel(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @target: esnext +// @Filename: /a.js +(function() { + module.exports = 0; +})();` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go b/internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go new file mode 100644 index 0000000000..ef1e05ee19 --- /dev/null +++ b/internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go @@ -0,0 +1,19 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestRefactorConvertToEsModule_notInCommonjsProject(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: /a.js +exports.x = 0;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go b/internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go new file mode 100644 index 0000000000..2d648c21ed --- /dev/null +++ b/internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go @@ -0,0 +1,28 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSideEffectImportsSuggestion1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @noEmit: true +// @module: commonjs +// @noUncheckedSideEffectImports: true +// @filename: moduleA/a.js +import "b"; +import "c"; +// @filename: node_modules/b.ts +var a = 10; +// @filename: node_modules/c.js +exports.a = 10; +c = 10;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifySuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/suggestionNoDuplicates_test.go b/internal/fourslash/tests/gen/suggestionNoDuplicates_test.go new file mode 100644 index 0000000000..873d115ecd --- /dev/null +++ b/internal/fourslash/tests/gen/suggestionNoDuplicates_test.go @@ -0,0 +1,30 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSuggestionNoDuplicates(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: false +// @Filename: foo.ts +import { f } from [|'m'|] +f +// @Filename: node_modules/m/index.js +module.exports.f = function (x) { return x }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyNonSuggestionDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](7016)}, + Message: "Could not find a declaration file for module 'm'. '/node_modules/m/index.js' implicitly has an 'any' type.", + }, + }) +} diff --git a/internal/fourslash/tests/gen/suggestionOfUnusedVariableWithExternalModule_test.go b/internal/fourslash/tests/gen/suggestionOfUnusedVariableWithExternalModule_test.go new file mode 100644 index 0000000000..a18d6ac801 --- /dev/null +++ b/internal/fourslash/tests/gen/suggestionOfUnusedVariableWithExternalModule_test.go @@ -0,0 +1,45 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestSuggestionOfUnusedVariableWithExternalModule(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@allowJs: true +// @Filename: /mymodule.js +(function ([|root|], factory) { + module.exports = factory(); +}(this, function () { + var [|unusedVar|] = "something"; + return {}; +})); +// @Filename: /app.js +//@ts-check +require("./mymodule");` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/app.js") + f.VerifySuggestionDiagnostics(t, nil) + f.GoToFile(t, "/mymodule.js") + f.VerifySuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Message: "'root' is declared but its value is never read.", + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](6133)}, + Range: f.Ranges()[0].LSRange, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagUnnecessary}, + }, + { + Message: "'unusedVar' is declared but its value is never read.", + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](6133)}, + Range: f.Ranges()[1].LSRange, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagUnnecessary}, + }, + }) +} diff --git a/internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go b/internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go new file mode 100644 index 0000000000..a631296955 --- /dev/null +++ b/internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go @@ -0,0 +1,24 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestTsconfigComputedPropertyError(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: tsconfig.json +{ + ["oops!" + 42]: "true", + "files": [ + "nonexistentfile.ts" + ], + "compileOnSave": true +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyNonSuggestionDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go b/internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go new file mode 100644 index 0000000000..4026b74c4a --- /dev/null +++ b/internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go @@ -0,0 +1,62 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestTypeErrorAfterStringCompletionsInNestedCall(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true + +type GreetingEvent = + | { type: "MORNING" } + | { type: "LUNCH_TIME" } + | { type: "ALOHA" }; + +interface RaiseActionObject { + type: "raise"; + event: TEvent; +} + +declare function raise( + ev: TEvent +): RaiseActionObject; + +declare function createMachine(config: { + actions: RaiseActionObject; +}): void; + +createMachine({ + [|/*error*/actions|]: raise({ type: "ALOHA/*1*/" }), +});` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "1") + f.Insert(t, "x") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + "ALOHA", + "LUNCH_TIME", + "MORNING", + }, + }, + }) + f.VerifyNonSuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](2322)}, + Message: "Type 'RaiseActionObject<{ type: \"ALOHAx\"; }>' is not assignable to type 'RaiseActionObject'.\n Type '{ type: \"ALOHAx\"; }' is not assignable to type 'GreetingEvent'.\n Type '{ type: \"ALOHAx\"; }' is not assignable to type '{ type: \"ALOHA\"; }'.\n Types of property 'type' are incompatible.\n Type '\"ALOHAx\"' is not assignable to type '\"ALOHA\"'.", + }, + }) +} diff --git a/internal/fourslash/tests/manual/parserCorruptionAfterMapInClass_test.go b/internal/fourslash/tests/manual/parserCorruptionAfterMapInClass_test.go new file mode 100644 index 0000000000..7de5ecef19 --- /dev/null +++ b/internal/fourslash/tests/manual/parserCorruptionAfterMapInClass_test.go @@ -0,0 +1,35 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestParserCorruptionAfterMapInClass(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: esnext +// @lib: es2015 +// @strict: true +class C { + map = new Set<[|string, number|]>/*$*/ + + foo() { + + } +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "$") + f.Insert(t, "()") + f.VerifyNonSuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](2558)}, + Message: "Expected 1 type arguments, but got 2.", + }, + }) +}