From 5f705990546500c1e2bb6bd883af999b320a4d77 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Wed, 12 Nov 2025 14:34:59 -0800 Subject: [PATCH 1/4] WIP: VerifyDiagnostics --- .../fourslash/_scripts/convertFourslash.mts | 119 ++++++++++++++++-- internal/fourslash/fourslash.go | 24 ++++ .../gen/annotateWithTypeFromJSDoc2_test.go | 19 +++ .../tests/gen/autoImportModuleNone1_test.go | 37 ++++++ .../tests/gen/autoImportModuleNone2_test.go | 48 +++++++ ...odeFixInferFromUsageBindingElement_test.go | 19 +++ ...xRemoveUnnecessaryAwait_mixedUnion_test.go | 24 ++++ ...ecessaryAwait_notAvailableOnReturn_test.go | 20 +++ ...achableCode_noSuggestionIfDisabled_test.go | 18 +++ ...UnusedLabel_noSuggestionIfDisabled_test.go | 18 +++ ...nsDotInArrayLiteralInObjectLiteral_test.go | 31 +++++ ...etJavaScriptSyntacticDiagnostics21_test.go | 20 +++ ...etJavaScriptSyntacticDiagnostics22_test.go | 19 +++ ...etJavaScriptSyntacticDiagnostics23_test.go | 26 ++++ ...eclarationDiagnosticsNoServerError_test.go | 26 ++++ .../fourslash/tests/gen/issue57429_test.go | 41 ++++++ .../fourslash/tests/gen/issue57585-2_test.go | 87 +++++++++++++ .../tests/gen/jsDocAugmentsAndExtends_test.go | 43 +++++++ .../gen/jsdocDeprecated_suggestion22_test.go | 26 ++++ .../gen/jsdocDeprecated_suggestion5_test.go | 33 +++++ .../gen/jsdocDeprecated_suggestion7_test.go | 25 ++++ .../tests/gen/jsdocParam_suggestion1_test.go | 30 +++++ .../gen/jsxElementExtendsNoCrash1_test.go | 18 +++ .../gen/jsxElementExtendsNoCrash2_test.go | 18 +++ .../gen/jsxElementExtendsNoCrash3_test.go | 18 +++ ...eDeclarationDeprecated_suggestion2_test.go | 18 +++ .../parserCorruptionAfterMapInClass_test.go | 28 +++++ ...torConvertToEsModule_notAtTopLevel_test.go | 22 ++++ ...ertToEsModule_notInCommonjsProject_test.go | 19 +++ .../gen/sideEffectImportsSuggestion1_test.go | 28 +++++ .../tests/gen/suggestionNoDuplicates_test.go | 30 +++++ ...OfUnusedVariableWithExternalModule_test.go | 45 +++++++ .../gen/tsconfigComputedPropertyError_test.go | 24 ++++ ...AfterStringCompletionsInNestedCall_test.go | 62 +++++++++ 34 files changed, 1075 insertions(+), 8 deletions(-) create mode 100644 internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go create mode 100644 internal/fourslash/tests/gen/autoImportModuleNone1_test.go create mode 100644 internal/fourslash/tests/gen/autoImportModuleNone2_test.go create mode 100644 internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go create mode 100644 internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go create mode 100644 internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go create mode 100644 internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go create mode 100644 internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go create mode 100644 internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go create mode 100644 internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go create mode 100644 internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go create mode 100644 internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go create mode 100644 internal/fourslash/tests/gen/importTypesDeclarationDiagnosticsNoServerError_test.go create mode 100644 internal/fourslash/tests/gen/issue57429_test.go create mode 100644 internal/fourslash/tests/gen/issue57585-2_test.go create mode 100644 internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go create mode 100644 internal/fourslash/tests/gen/jsdocDeprecated_suggestion22_test.go create mode 100644 internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go create mode 100644 internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go create mode 100644 internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go create mode 100644 internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go create mode 100644 internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go create mode 100644 internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go create mode 100644 internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go create mode 100644 internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go create mode 100644 internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go create mode 100644 internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go create mode 100644 internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go create mode 100644 internal/fourslash/tests/gen/suggestionNoDuplicates_test.go create mode 100644 internal/fourslash/tests/gen/suggestionOfUnusedVariableWithExternalModule_test.go create mode 100644 internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go create mode 100644 internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index dedcc358b7..7110902357 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -210,6 +210,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....` @@ -1217,6 +1221,103 @@ 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", + }]; +} + +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)) { + 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": @@ -1337,7 +1438,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; } @@ -1658,12 +1759,6 @@ interface VerifyBaselineFindAllReferencesCmd { ranges?: boolean; } -interface VerifyBaselineFindAllReferencesCmd { - kind: "verifyBaselineFindAllReferences"; - markers: string[]; - ranges?: boolean; -} - interface VerifyBaselineGoToDefinitionCmd { kind: "verifyBaselineGoToDefinition" | "verifyBaselineGoToType"; markers: string[]; @@ -1725,6 +1820,11 @@ interface VerifyRenameInfoCmd { preferences: string; } +interface VerifyDiagnosticsCmd { + kind: "verifyDiagnostics"; + arg: string; +} + type Cmd = | VerifyCompletionsCmd | VerifyApplyCodeActionFromCompletionCmd @@ -1739,7 +1839,8 @@ type Cmd = | VerifyQuickInfoCmd | VerifyBaselineRenameCmd | VerifyRenameInfoCmd - | VerifyBaselineInlayHintsCmd; + | VerifyBaselineInlayHintsCmd + | VerifyDiagnosticsCmd; function generateVerifyCompletions({ marker, args, isNewIdentifierLocation, andApplyCodeActionArgs }: VerifyCompletionsCmd): string { let expectedList: string; @@ -1878,6 +1979,8 @@ function generateCmd(cmd: Cmd): string { return `f.VerifyRenameFailed(t, ${cmd.preferences})`; case "verifyBaselineInlayHints": return generateBaselineInlayHints(cmd); + case "verifyDiagnostics": + return `f.VerifyDiagnostics(t, ${cmd.arg})`; default: let neverCommand: never = cmd; throw new Error(`Unknown command kind: ${neverCommand as Cmd["kind"]}`); diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 6edbbf1be6..12de627d3a 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -2314,6 +2314,30 @@ func (f *FourslashTest) VerifyBaselineInlayHints( f.addResultToBaseline(t, "Inlay Hints", strings.Join(annotations, "\n\n")) } +func (f *FourslashTest) VerifyDiagnostics(t *testing.T, expected []*lsproto.Diagnostic) { + var actualDiagnostics []*lsproto.Diagnostic + for fileName := range f.scriptInfos { + params := &lsproto.DocumentDiagnosticParams{ + TextDocument: lsproto.TextDocumentIdentifier{ + Uri: lsconv.FileNameToDocumentURI(fileName), + }, + } + 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) + } + + if result.FullDocumentDiagnosticReport != nil { + actualDiagnostics = append(actualDiagnostics, result.FullDocumentDiagnosticReport.Items...) + } + } + // !!! HERE + assertDeepEqual(t, actualDiagnostics, expected, "Diagnostics do not match expected") +} + 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..6961f488eb --- /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.VerifyDiagnostics(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..5fcfd36e99 --- /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() + + 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.VerifyDiagnostics(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..e3851248c3 --- /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.VerifyDiagnostics(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..488481295e --- /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.VerifyDiagnostics(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..6593e22973 --- /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.VerifyDiagnostics(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..26686afd29 --- /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.VerifyDiagnostics(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..6aeeb98d5d --- /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.VerifyDiagnostics(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..45242233e2 --- /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.VerifyDiagnostics(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..575afa0288 --- /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.VerifyDiagnostics(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..8dda0bb776 --- /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.VerifyDiagnostics(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..ab8d735d16 --- /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.VerifyDiagnostics(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..debe4d2530 --- /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.VerifyDiagnostics(t, nil) + f.VerifyDiagnostics(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..88ea869f14 --- /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.VerifyDiagnostics(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..648060b121 --- /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.VerifyDiagnostics(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..36742d7a37 --- /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.VerifyDiagnostics(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..3b6199cbe1 --- /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() + + 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.VerifyDiagnostics(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..ee786c8ab2 --- /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.VerifyDiagnostics(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..f1acaf0a5a --- /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.VerifyDiagnostics(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..13fc5a704f --- /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.VerifyDiagnostics(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..6d4576f914 --- /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.VerifyDiagnostics(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..4bab24c0ce --- /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.VerifyDiagnostics(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..e957036480 --- /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.VerifyDiagnostics(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..dec5fabc69 --- /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.VerifyDiagnostics(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..c373073cbe --- /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.VerifyDiagnostics(t, nil) +} diff --git a/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go b/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go new file mode 100644 index 0000000000..0d218ae31f --- /dev/null +++ b/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_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 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/*$*/ + + foo() { + + } +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "$") + f.Insert(t, "()") + f.VerifyDiagnostics(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..636a73934e --- /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.VerifyDiagnostics(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..c55e116b41 --- /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.VerifyDiagnostics(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..f17e08a45a --- /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.VerifyDiagnostics(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..32aa5e6d1d --- /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.VerifyDiagnostics(t, nil) + f.VerifyDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](7016)}, + Message: "Could not find a declaration file for module 'm'. '/tests/cases/fourslash/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..a4d7180fb2 --- /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.VerifyDiagnostics(t, nil) + f.GoToFile(t, "/mymodule.js") + f.VerifyDiagnostics(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..02764f024b --- /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.VerifyDiagnostics(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..d50eefc5f9 --- /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.VerifyDiagnostics(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\"'.", + }, + }) +} From 29b027f76c3fdce1f91c25891bb0027b1c87aa06 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Thu, 13 Nov 2025 10:17:23 -0800 Subject: [PATCH 2/4] finish verify diagnostics port --- .../fourslash/_scripts/convertFourslash.mts | 6 +- internal/fourslash/fourslash.go | 88 ++++++++++++++----- .../gen/annotateWithTypeFromJSDoc2_test.go | 2 +- .../tests/gen/autoImportModuleNone1_test.go | 2 +- .../tests/gen/autoImportModuleNone2_test.go | 2 +- ...odeFixInferFromUsageBindingElement_test.go | 2 +- ...xRemoveUnnecessaryAwait_mixedUnion_test.go | 2 +- ...ecessaryAwait_notAvailableOnReturn_test.go | 2 +- ...achableCode_noSuggestionIfDisabled_test.go | 2 +- ...UnusedLabel_noSuggestionIfDisabled_test.go | 2 +- ...nsDotInArrayLiteralInObjectLiteral_test.go | 2 +- ...etJavaScriptSyntacticDiagnostics21_test.go | 2 +- ...etJavaScriptSyntacticDiagnostics22_test.go | 2 +- ...etJavaScriptSyntacticDiagnostics23_test.go | 4 +- ...eclarationDiagnosticsNoServerError_test.go | 2 +- .../fourslash/tests/gen/issue57429_test.go | 2 +- .../fourslash/tests/gen/issue57585-2_test.go | 2 +- .../tests/gen/jsDocAugmentsAndExtends_test.go | 2 +- .../gen/jsdocDeprecated_suggestion22_test.go | 2 +- .../gen/jsdocDeprecated_suggestion5_test.go | 2 +- .../gen/jsdocDeprecated_suggestion7_test.go | 2 +- .../tests/gen/jsdocParam_suggestion1_test.go | 2 +- .../gen/jsxElementExtendsNoCrash1_test.go | 2 +- .../gen/jsxElementExtendsNoCrash2_test.go | 2 +- .../gen/jsxElementExtendsNoCrash3_test.go | 2 +- ...eDeclarationDeprecated_suggestion2_test.go | 2 +- .../parserCorruptionAfterMapInClass_test.go | 2 +- ...torConvertToEsModule_notAtTopLevel_test.go | 2 +- ...ertToEsModule_notInCommonjsProject_test.go | 2 +- .../gen/sideEffectImportsSuggestion1_test.go | 2 +- .../tests/gen/suggestionNoDuplicates_test.go | 6 +- ...OfUnusedVariableWithExternalModule_test.go | 4 +- .../gen/tsconfigComputedPropertyError_test.go | 2 +- ...AfterStringCompletionsInNestedCall_test.go | 2 +- 34 files changed, 108 insertions(+), 58 deletions(-) diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 7110902357..49cdd84b56 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -1237,6 +1237,7 @@ function parseVerifyDiagnostics(funcName: string, args: readonly ts.Expression[] return [{ kind: "verifyDiagnostics", arg: goArgs.length > 0 ? `[]*lsproto.Diagnostic{\n${goArgs.join(",\n")},\n}` : "nil", + isSuggestion: funcName === "getSuggestionDiagnostics", }]; } @@ -1261,6 +1262,7 @@ function parseExpectedDiagnostic(expr: ts.Expression): string | undefined { case "message": { let messageInit; if (messageInit = getStringLiteralLike(init)) { + messageInit.text = messageInit.text.replace("/tests/cases/fourslash", ""); diagnosticProps.push(`Message: ${getGoStringLiteral(messageInit.text)},`); } else { @@ -1823,6 +1825,7 @@ interface VerifyRenameInfoCmd { interface VerifyDiagnosticsCmd { kind: "verifyDiagnostics"; arg: string; + isSuggestion: boolean; } type Cmd = @@ -1980,7 +1983,8 @@ function generateCmd(cmd: Cmd): string { case "verifyBaselineInlayHints": return generateBaselineInlayHints(cmd); case "verifyDiagnostics": - return `f.VerifyDiagnostics(t, ${cmd.arg})`; + 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/fourslash.go b/internal/fourslash/fourslash.go index 12de627d3a..a3446b8315 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -531,6 +531,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) @@ -888,8 +898,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) { @@ -1655,7 +1666,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))) } @@ -2315,27 +2331,57 @@ func (f *FourslashTest) VerifyBaselineInlayHints( } func (f *FourslashTest) VerifyDiagnostics(t *testing.T, expected []*lsproto.Diagnostic) { - var actualDiagnostics []*lsproto.Diagnostic - for fileName := range f.scriptInfos { - params := &lsproto.DocumentDiagnosticParams{ - TextDocument: lsproto.TextDocumentIdentifier{ - Uri: lsconv.FileNameToDocumentURI(fileName), - }, - } - 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) - } + f.verifyDiagnostics(t, expected, func(d *lsproto.Diagnostic) bool { return true }) +} - if result.FullDocumentDiagnosticReport != nil { - actualDiagnostics = append(actualDiagnostics, result.FullDocumentDiagnosticReport.Items...) +// 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{} + for _, 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) + } + diag.Range = rangesInFile[0].LSRange } } - // !!! HERE - assertDeepEqual(t, actualDiagnostics, expected, "Diagnostics do not match expected") + if len(actualDiagnostics) == 0 { + actualDiagnostics = nil + } + assertDeepEqual(t, actualDiagnostics, expected, "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 { diff --git a/internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go b/internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go index 6961f488eb..b4be6d4cad 100644 --- a/internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go +++ b/internal/fourslash/tests/gen/annotateWithTypeFromJSDoc2_test.go @@ -15,5 +15,5 @@ func TestAnnotateWithTypeFromJSDoc2(t *testing.T) { /** @type {number} */ var [|x|]: string;` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/autoImportModuleNone1_test.go b/internal/fourslash/tests/gen/autoImportModuleNone1_test.go index 5fcfd36e99..d356b9f775 100644 --- a/internal/fourslash/tests/gen/autoImportModuleNone1_test.go +++ b/internal/fourslash/tests/gen/autoImportModuleNone1_test.go @@ -33,5 +33,5 @@ export const x: number; }, }) f.ReplaceLine(t, 0, "import { x } from 'dep'; x;") - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/autoImportModuleNone2_test.go b/internal/fourslash/tests/gen/autoImportModuleNone2_test.go index e3851248c3..ffa9951af4 100644 --- a/internal/fourslash/tests/gen/autoImportModuleNone2_test.go +++ b/internal/fourslash/tests/gen/autoImportModuleNone2_test.go @@ -44,5 +44,5 @@ export const x: number; }, }) f.ReplaceLine(t, 0, "import { x } from 'dep'; x;") - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go b/internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go index 488481295e..b186df0321 100644 --- a/internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go +++ b/internal/fourslash/tests/gen/codeFixInferFromUsageBindingElement_test.go @@ -15,5 +15,5 @@ func TestCodeFixInferFromUsageBindingElement(t *testing.T) { return car + cdr + 1 }` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go index 6593e22973..40bcd52600 100644 --- a/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go +++ b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_mixedUnion_test.go @@ -20,5 +20,5 @@ async function fn2 | void>(a: T) { await a; }` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go index 26686afd29..b795b91523 100644 --- a/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go +++ b/internal/fourslash/tests/gen/codeFixRemoveUnnecessaryAwait_notAvailableOnReturn_test.go @@ -16,5 +16,5 @@ async function fn(): Promise { return 0; }` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go b/internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go index 6aeeb98d5d..63f9f0d954 100644 --- a/internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go +++ b/internal/fourslash/tests/gen/codeFixUnreachableCode_noSuggestionIfDisabled_test.go @@ -14,5 +14,5 @@ func TestCodeFixUnreachableCode_noSuggestionIfDisabled(t *testing.T) { const content = `// @allowUnreachableCode: true if (false) 0;` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go b/internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go index 45242233e2..1f238e081f 100644 --- a/internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go +++ b/internal/fourslash/tests/gen/codeFixUnusedLabel_noSuggestionIfDisabled_test.go @@ -14,5 +14,5 @@ func TestCodeFixUnusedLabel_noSuggestionIfDisabled(t *testing.T) { const content = `// @allowUnusedLabels: true foo: while (true) {}` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go b/internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go index 575afa0288..690efe9698 100644 --- a/internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go +++ b/internal/fourslash/tests/gen/completionsDotInArrayLiteralInObjectLiteral_test.go @@ -15,7 +15,7 @@ func TestCompletionsDotInArrayLiteralInObjectLiteral(t *testing.T) { defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `const o = { x: [[|.|][||]/**/` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, []*lsproto.Diagnostic{ + f.VerifyNonSuggestionDiagnostics(t, []*lsproto.Diagnostic{ { Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](1109)}, Message: "Expression expected.", diff --git a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go index 8dda0bb776..639cb7e585 100644 --- a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go +++ b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics21_test.go @@ -16,5 +16,5 @@ func TestGetJavaScriptSyntacticDiagnostics21(t *testing.T) { // @Filename: a.js @internal class C {}` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go index ab8d735d16..59b854c310 100644 --- a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go +++ b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics22_test.go @@ -15,5 +15,5 @@ func TestGetJavaScriptSyntacticDiagnostics22(t *testing.T) { // @Filename: a.js function foo(...a) {}` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go index debe4d2530..9d77d39070 100644 --- a/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go +++ b/internal/fourslash/tests/gen/getJavaScriptSyntacticDiagnostics23_test.go @@ -21,6 +21,6 @@ function Person(age) { } }` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) - f.VerifyDiagnostics(t, nil) + 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 index 88ea869f14..52acdbbea4 100644 --- a/internal/fourslash/tests/gen/importTypesDeclarationDiagnosticsNoServerError_test.go +++ b/internal/fourslash/tests/gen/importTypesDeclarationDiagnosticsNoServerError_test.go @@ -22,5 +22,5 @@ import { f } from "foo"; export const x = f();` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.GoToFileNumber(t, 1) - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/issue57429_test.go b/internal/fourslash/tests/gen/issue57429_test.go index 648060b121..26985271fd 100644 --- a/internal/fourslash/tests/gen/issue57429_test.go +++ b/internal/fourslash/tests/gen/issue57429_test.go @@ -32,7 +32,7 @@ Builder({ })` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyQuickInfoAt(t, "1", "const value: any", "") - f.VerifyDiagnostics(t, []*lsproto.Diagnostic{ + 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 index 36742d7a37..480c3837ab 100644 --- a/internal/fourslash/tests/gen/issue57585-2_test.go +++ b/internal/fourslash/tests/gen/issue57585-2_test.go @@ -83,5 +83,5 @@ gen(function* () { });` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyQuickInfoAt(t, "1", "const b: number", "") - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go b/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go index 3b6199cbe1..678541bbca 100644 --- a/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go +++ b/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go @@ -34,7 +34,7 @@ declare class Thing { f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.GoToMarker(t, "") f.VerifyQuickInfoIs(t, "(local var) x: number", "") - f.VerifyDiagnostics(t, []*lsproto.Diagnostic{ + 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 index ee786c8ab2..ae9c7f20d8 100644 --- a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion22_test.go +++ b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion22_test.go @@ -22,5 +22,5 @@ const foo: { [|foo|](1, 1);` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go index f1acaf0a5a..11c6cac6f2 100644 --- a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go +++ b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion5_test.go @@ -29,5 +29,5 @@ const DOOM = { e: 1, m: 1 } /** @type {DOOM} */ const kneeDeep = DOOM.e` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go index 13fc5a704f..3576d35c72 100644 --- a/internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go +++ b/internal/fourslash/tests/gen/jsdocDeprecated_suggestion7_test.go @@ -21,5 +21,5 @@ const x = 1 type x = string var y: x = 'hi'` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go b/internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go index 6d4576f914..d11af52b5e 100644 --- a/internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go +++ b/internal/fourslash/tests/gen/jsdocParam_suggestion1_test.go @@ -26,5 +26,5 @@ function worse(): void { }` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.GoToFile(t, "a.ts") - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go index 4bab24c0ce..2831a1ee38 100644 --- a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go +++ b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash1_test.go @@ -14,5 +14,5 @@ func TestJsxElementExtendsNoCrash1(t *testing.T) { const content = `// @filename: index.tsx ` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go index e957036480..6be1dca04d 100644 --- a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go +++ b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash2_test.go @@ -14,5 +14,5 @@ func TestJsxElementExtendsNoCrash2(t *testing.T) { const content = `// @filename: index.tsx ` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go index dec5fabc69..ba8dde6417 100644 --- a/internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go +++ b/internal/fourslash/tests/gen/jsxElementExtendsNoCrash3_test.go @@ -14,5 +14,5 @@ func TestJsxElementExtendsNoCrash3(t *testing.T) { const content = `// @filename: index.tsx ` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go b/internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go index c373073cbe..acb0a5dfc8 100644 --- a/internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go +++ b/internal/fourslash/tests/gen/moduleDeclarationDeprecated_suggestion2_test.go @@ -14,5 +14,5 @@ func TestModuleDeclarationDeprecated_suggestion2(t *testing.T) { const content = `// @Filename: a.ts declare module` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go b/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go index 0d218ae31f..427284e9e7 100644 --- a/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go +++ b/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go @@ -24,5 +24,5 @@ class C { f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.GoToMarker(t, "$") f.Insert(t, "()") - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go b/internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go index 636a73934e..5538b18a20 100644 --- a/internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go +++ b/internal/fourslash/tests/gen/refactorConvertToEsModule_notAtTopLevel_test.go @@ -18,5 +18,5 @@ func TestRefactorConvertToEsModule_notAtTopLevel(t *testing.T) { module.exports = 0; })();` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go b/internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go index c55e116b41..ef1e05ee19 100644 --- a/internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go +++ b/internal/fourslash/tests/gen/refactorConvertToEsModule_notInCommonjsProject_test.go @@ -15,5 +15,5 @@ func TestRefactorConvertToEsModule_notInCommonjsProject(t *testing.T) { // @Filename: /a.js exports.x = 0;` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go b/internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go index f17e08a45a..2d648c21ed 100644 --- a/internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go +++ b/internal/fourslash/tests/gen/sideEffectImportsSuggestion1_test.go @@ -24,5 +24,5 @@ var a = 10; exports.a = 10; c = 10;` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/suggestionNoDuplicates_test.go b/internal/fourslash/tests/gen/suggestionNoDuplicates_test.go index 32aa5e6d1d..873d115ecd 100644 --- a/internal/fourslash/tests/gen/suggestionNoDuplicates_test.go +++ b/internal/fourslash/tests/gen/suggestionNoDuplicates_test.go @@ -20,11 +20,11 @@ f // @Filename: node_modules/m/index.js module.exports.f = function (x) { return x }` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) - f.VerifyDiagnostics(t, []*lsproto.Diagnostic{ + 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'. '/tests/cases/fourslash/node_modules/m/index.js' implicitly has an 'any' type.", + 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 index a4d7180fb2..a18d6ac801 100644 --- a/internal/fourslash/tests/gen/suggestionOfUnusedVariableWithExternalModule_test.go +++ b/internal/fourslash/tests/gen/suggestionOfUnusedVariableWithExternalModule_test.go @@ -26,9 +26,9 @@ func TestSuggestionOfUnusedVariableWithExternalModule(t *testing.T) { require("./mymodule");` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.GoToFile(t, "/app.js") - f.VerifyDiagnostics(t, nil) + f.VerifySuggestionDiagnostics(t, nil) f.GoToFile(t, "/mymodule.js") - f.VerifyDiagnostics(t, []*lsproto.Diagnostic{ + f.VerifySuggestionDiagnostics(t, []*lsproto.Diagnostic{ { Message: "'root' is declared but its value is never read.", Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](6133)}, diff --git a/internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go b/internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go index 02764f024b..a631296955 100644 --- a/internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go +++ b/internal/fourslash/tests/gen/tsconfigComputedPropertyError_test.go @@ -20,5 +20,5 @@ func TestTsconfigComputedPropertyError(t *testing.T) { "compileOnSave": true }` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) - f.VerifyDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, nil) } diff --git a/internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go b/internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go index d50eefc5f9..4026b74c4a 100644 --- a/internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go +++ b/internal/fourslash/tests/gen/typeErrorAfterStringCompletionsInNestedCall_test.go @@ -53,7 +53,7 @@ createMachine({ }, }, }) - f.VerifyDiagnostics(t, []*lsproto.Diagnostic{ + 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\"'.", From 1603f1ffb98a51c812ca35bc98c2b5d4fe93e621 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Thu, 13 Nov 2025 10:32:23 -0800 Subject: [PATCH 3/4] update tests --- internal/fourslash/_scripts/failingTests.txt | 2 ++ internal/fourslash/_scripts/manualTests.txt | 1 + .../fourslash/tests/gen/autoImportModuleNone1_test.go | 2 +- .../tests/gen/jsDocAugmentsAndExtends_test.go | 2 +- .../parserCorruptionAfterMapInClass_test.go | 11 +++++++++-- 5 files changed, 14 insertions(+), 4 deletions(-) rename internal/fourslash/tests/{gen => manual}/parserCorruptionAfterMapInClass_test.go (57%) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 29254c11a0..70616b20bb 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -10,6 +10,7 @@ TestAutoImportCompletionExportListAugmentation2 TestAutoImportCompletionExportListAugmentation3 TestAutoImportCompletionExportListAugmentation4 TestAutoImportFileExcludePatterns3 +TestAutoImportModuleNone1 TestAutoImportPathsAliasesAndBarrels TestAutoImportProvider_exportMap1 TestAutoImportProvider_exportMap2 @@ -285,6 +286,7 @@ TestJavascriptModules20 TestJavascriptModules21 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/tests/gen/autoImportModuleNone1_test.go b/internal/fourslash/tests/gen/autoImportModuleNone1_test.go index d356b9f775..ccaa1dbf54 100644 --- a/internal/fourslash/tests/gen/autoImportModuleNone1_test.go +++ b/internal/fourslash/tests/gen/autoImportModuleNone1_test.go @@ -10,7 +10,7 @@ import ( func TestAutoImportModuleNone1(t *testing.T) { t.Parallel() - + t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: none // @moduleResolution: bundler diff --git a/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go b/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go index 678541bbca..e5faf61d71 100644 --- a/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go +++ b/internal/fourslash/tests/gen/jsDocAugmentsAndExtends_test.go @@ -11,7 +11,7 @@ import ( func TestJsDocAugmentsAndExtends(t *testing.T) { t.Parallel() - + t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @allowJs: true // @checkJs: true diff --git a/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go b/internal/fourslash/tests/manual/parserCorruptionAfterMapInClass_test.go similarity index 57% rename from internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go rename to internal/fourslash/tests/manual/parserCorruptionAfterMapInClass_test.go index 427284e9e7..7de5ecef19 100644 --- a/internal/fourslash/tests/gen/parserCorruptionAfterMapInClass_test.go +++ b/internal/fourslash/tests/manual/parserCorruptionAfterMapInClass_test.go @@ -4,6 +4,8 @@ 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" ) @@ -15,7 +17,7 @@ func TestParserCorruptionAfterMapInClass(t *testing.T) { // @lib: es2015 // @strict: true class C { - map = new Set/*$*/ + map = new Set<[|string, number|]>/*$*/ foo() { @@ -24,5 +26,10 @@ class C { f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.GoToMarker(t, "$") f.Insert(t, "()") - f.VerifyNonSuggestionDiagnostics(t, nil) + f.VerifyNonSuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: PtrTo[int32](2558)}, + Message: "Expected 1 type arguments, but got 2.", + }, + }) } From 229b2701dc8d33db42c25626974b2d424329079a Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Thu, 13 Nov 2025 11:27:37 -0800 Subject: [PATCH 4/4] CR fix --- internal/fourslash/fourslash.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 027c8568c1..e09e4fe637 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -2524,19 +2524,24 @@ func (f *FourslashTest) verifyDiagnostics(t *testing.T, expected []*lsproto.Diag } actualDiagnostics = core.Filter(actualDiagnostics, filterDiagnostics) emptyRange := lsproto.Range{} - for _, diag := range expected { + 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) } - diag.Range = rangesInFile[0].LSRange + diagWithRange := *diag + diagWithRange.Range = rangesInFile[0].LSRange + expectedWithRanges[i] = &diagWithRange + } else { + expectedWithRanges[i] = diag } } - if len(actualDiagnostics) == 0 { - actualDiagnostics = nil + if len(actualDiagnostics) == 0 && len(expectedWithRanges) == 0 { + return } - assertDeepEqual(t, actualDiagnostics, expected, "Diagnostics do not match expected", diagnosticsIgnoreOpts) + assertDeepEqual(t, actualDiagnostics, expectedWithRanges, "Diagnostics do not match expected", diagnosticsIgnoreOpts) } func isSuggestionDiagnostic(diag *lsproto.Diagnostic) bool {