From 69862248868057785b96d66e520556be15659220 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 17 Oct 2025 10:49:24 -0700 Subject: [PATCH 01/17] Support auto-import completions in fourslash --- .../fourslash/_scripts/convertFourslash.mts | 136 +++++++++++-- internal/fourslash/_scripts/failingTests.txt | 68 +++++++ internal/fourslash/fourslash.go | 122 +++++++++-- .../autoImportFileExcludePatterns3_test.go | 71 +++++++ .../autoImportPathsAliasesAndBarrels_test.go | 83 ++++++++ .../tests/gen/autoImportProvider6_test.go | 50 +++++ .../gen/autoImportProvider_exportMap1_test.go | 83 ++++++++ .../gen/autoImportProvider_exportMap2_test.go | 75 +++++++ .../gen/autoImportProvider_exportMap3_test.go | 69 +++++++ .../gen/autoImportProvider_exportMap4_test.go | 72 +++++++ .../gen/autoImportProvider_exportMap5_test.go | 94 +++++++++ .../gen/autoImportProvider_exportMap6_test.go | 101 ++++++++++ .../gen/autoImportProvider_exportMap7_test.go | 85 ++++++++ .../gen/autoImportProvider_exportMap8_test.go | 103 ++++++++++ .../gen/autoImportProvider_exportMap9_test.go | 73 +++++++ ...oImportProvider_globalTypingsCache_test.go | 57 ++++++ ...vider_namespaceSameNameAsIntrinsic_test.go | 57 ++++++ ...utoImportProvider_wildcardExports1_test.go | 122 +++++++++++ ...utoImportProvider_wildcardExports2_test.go | 67 +++++++ ...utoImportProvider_wildcardExports3_test.go | 71 +++++++ .../autoImportSameNameDefaultExported_test.go | 59 ++++++ .../gen/autoImportTypeOnlyPreferred1_test.go | 63 ++++++ .../gen/completionForObjectProperty_test.go | 189 ++++++++++++++++++ ...PropertyShorthandForObjectLiteral5_test.go | 45 +++++ ...lassMemberImportTypeNodeParameter1_test.go | 47 +++++ ...lassMemberImportTypeNodeParameter2_test.go | 45 +++++ ...lassMemberImportTypeNodeParameter3_test.go | 49 +++++ ...lassMemberImportTypeNodeParameter4_test.go | 47 +++++ .../gen/completionsImportBaseUrl_test.go | 52 +++++ ...mpletionsImportDefaultExportCrash2_test.go | 77 +++++++ .../gen/completionsImportTypeKeyword_test.go | 50 +++++ .../completionsImport_augmentation_test.go | 60 ++++++ ...etionsImport_compilerOptionsModule_test.go | 65 ++++++ ...completionsImport_default_reExport_test.go | 64 ++++++ ...atePackages_scopedTypesAndNotTypes_test.go | 74 +++++++ ...port_duplicatePackages_scopedTypes_test.go | 74 +++++++ ...onsImport_duplicatePackages_scoped_test.go | 74 +++++++ ...duplicatePackages_typesAndNotTypes_test.go | 64 ++++++ ...ionsImport_duplicatePackages_types_test.go | 74 +++++++ ..._exportEqualsNamespace_noDuplicate_test.go | 52 +++++ ...pletionsImport_exportEquals_global_test.go | 50 +++++ ...ilteredByInvalidPackageJson_direct_test.go | 73 +++++++ ...lteredByPackageJson_@typesImplicit_test.go | 63 ++++++ ...t_filteredByPackageJson_@typesOnly_test.go | 63 ++++++ ...port_filteredByPackageJson_ambient_test.go | 153 ++++++++++++++ ...mport_filteredByPackageJson_direct_test.go | 65 ++++++ ...mport_filteredByPackageJson_nested_test.go | 89 +++++++++ ...eredByPackageJson_peerDependencies_test.go | 65 ++++++ .../completionsImport_mergedReExport_test.go | 85 ++++++++ ...ionsImport_named_didNotExistBefore_test.go | 63 ++++++ ...named_exportEqualsNamespace_merged_test.go | 53 +++++ ...mport_packageJsonImportsPreference_test.go | 77 +++++++ ...mport_preferUpdatingExistingImport_test.go | 52 +++++ ...onsImport_previousTokenIsSemicolon_test.go | 46 +++++ ...completionsImport_reExportDefault2_test.go | 56 ++++++ ...ompletionsImport_reexportTransient_test.go | 51 +++++ ...ionsImport_sortingModuleSpecifiers_test.go | 74 +++++++ .../tests/gen/completionsImport_tsx_test.go | 49 +++++ ...mpletionsImport_umdDefaultNoCrash1_test.go | 70 +++++++ ...onsImport_umdModules1_globalAccess_test.go | 49 +++++ ...nsImport_umdModules2_moduleExports_test.go | 54 +++++ ...mpletionsImport_umdModules3_script_test.go | 48 +++++ ...onsImport_uriStyleNodeCoreModules1_test.go | 78 ++++++++ ...onsImport_uriStyleNodeCoreModules2_test.go | 60 ++++++ ...Import_windowsPathsProjectRelative_test.go | 131 ++++++++++++ .../completionsRecommended_namespace_test.go | 92 +++++++++ .../completionsWithDeprecatedTag10_test.go | 45 +++++ ...rtSuggestionsCache_exportUndefined_test.go | 70 +++++++ ...uggestionsCache_invalidPackageJson_test.go | 58 ++++++ .../tests/gen/importTypeCompletions1_test.go | 50 +++++ .../tests/gen/importTypeCompletions3_test.go | 50 +++++ .../tests/gen/importTypeCompletions4_test.go | 51 +++++ .../tests/gen/importTypeCompletions5_test.go | 51 +++++ .../tests/gen/importTypeCompletions6_test.go | 51 +++++ .../tests/gen/importTypeCompletions7_test.go | 56 ++++++ .../tests/gen/importTypeCompletions8_test.go | 50 +++++ .../tests/gen/importTypeCompletions9_test.go | 50 +++++ .../tests/gen/jsFileImportNoTypes2_test.go | 84 ++++++++ internal/ls/completions.go | 46 ++--- 79 files changed, 5452 insertions(+), 52 deletions(-) create mode 100644 internal/fourslash/tests/gen/autoImportFileExcludePatterns3_test.go create mode 100644 internal/fourslash/tests/gen/autoImportPathsAliasesAndBarrels_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider6_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap1_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap3_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap4_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap5_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap6_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap7_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap8_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_exportMap9_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_globalTypingsCache_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_namespaceSameNameAsIntrinsic_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_wildcardExports1_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_wildcardExports2_test.go create mode 100644 internal/fourslash/tests/gen/autoImportProvider_wildcardExports3_test.go create mode 100644 internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go create mode 100644 internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go create mode 100644 internal/fourslash/tests/gen/completionForObjectProperty_test.go create mode 100644 internal/fourslash/tests/gen/completionPropertyShorthandForObjectLiteral5_test.go create mode 100644 internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter1_test.go create mode 100644 internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter2_test.go create mode 100644 internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter3_test.go create mode 100644 internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter4_test.go create mode 100644 internal/fourslash/tests/gen/completionsImportBaseUrl_test.go create mode 100644 internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go create mode 100644 internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_augmentation_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_reExport_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_duplicatePackages_typesAndNotTypes_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_exportEquals_global_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_packageJsonImportsPreference_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_preferUpdatingExistingImport_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_reExportDefault2_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_reexportTransient_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_tsx_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_umdModules1_globalAccess_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_umdModules3_script_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules2_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_windowsPathsProjectRelative_test.go create mode 100644 internal/fourslash/tests/gen/completionsRecommended_namespace_test.go create mode 100644 internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go create mode 100644 internal/fourslash/tests/gen/importSuggestionsCache_exportUndefined_test.go create mode 100644 internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions1_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions3_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions4_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions5_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions6_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions7_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions8_test.go create mode 100644 internal/fourslash/tests/gen/importTypeCompletions9_test.go create mode 100644 internal/fourslash/tests/gen/jsFileImportNoTypes2_test.go diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 534b7d69c7..40e63d7075 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -151,14 +151,17 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined { } const namespace = callExpression.expression.expression; const func = callExpression.expression.name; - if (!(ts.isIdentifier(namespace) || namespace.getText() === "verify.not") || !ts.isIdentifier(func)) { - console.error(`Expected identifiers for namespace and function, got ${namespace.getText()} and ${func.getText()}`); - return undefined; - } if (!ts.isIdentifier(namespace)) { switch (func.text) { case "quickInfoExists": return parseQuickInfoArgs("notQuickInfoExists", callExpression.arguments); + case "andApplyCodeAction": + // verify.completions({ ... }).andApplyCodeAction(...) + if (!(ts.isCallExpression(namespace) && namespace.expression.getText() === "verify.completions")) { + console.error(`Unrecognized fourslash statement: ${statement.getText()}`); + return undefined; + } + return parseVerifyCompletionsArgs(namespace.arguments, callExpression.arguments); } console.error(`Unrecognized fourslash statement: ${statement.getText()}`); return undefined; @@ -271,6 +274,13 @@ function parseEditStatement(funcName: string, args: readonly ts.Expression[]): E } } +function getGoMultiLineStringLiteral(text: string): string { + if (!text.includes("`") && !text.includes("\\")) { + return "`" + text + "`"; + } + return getGoStringLiteral(text); +} + function getGoStringLiteral(text: string): string { return `${JSON.stringify(text)}`; } @@ -362,13 +372,17 @@ function parseGoToArgs(args: readonly ts.Expression[], funcName: string): GoToCm } } -function parseVerifyCompletionsArgs(args: readonly ts.Expression[]): VerifyCompletionsCmd[] | undefined { +function parseVerifyCompletionsArgs(args: readonly ts.Expression[], codeActionArgs?: readonly ts.Expression[]): VerifyCompletionsCmd[] | undefined { const cmds = []; + const codeAction = codeActionArgs?.[0] && parseAndApplyCodeActionArg(codeActionArgs[0]); for (const arg of args) { - const result = parseVerifyCompletionArg(arg); + const result = parseVerifyCompletionArg(arg, codeAction); if (!result) { return undefined; } + if (codeActionArgs?.length) { + result.andApplyCodeActionArgs = parseAndApplyCodeActionArg(codeActionArgs[0]); + } cmds.push(result); } return cmds; @@ -397,7 +411,7 @@ const completionPlus = new Map([ ["completion.typeKeywordsPlus", "CompletionTypeKeywordsPlus"], ]); -function parseVerifyCompletionArg(arg: ts.Expression): VerifyCompletionsCmd | undefined { +function parseVerifyCompletionArg(arg: ts.Expression, codeActionArgs?: VerifyApplyCodeActionArgs): VerifyCompletionsCmd | undefined { let marker: string | undefined; let goArgs: VerifyCompletionsArgs | undefined; const obj = getObjectLiteralExpression(arg); @@ -478,7 +492,7 @@ function parseVerifyCompletionArg(arg: ts.Expression): VerifyCompletionsCmd | un } expected = `${funcName}(\n[]fourslash.CompletionsExpectedItem{`; for (const elem of items.elements) { - const result = parseExpectedCompletionItem(elem); + const result = parseExpectedCompletionItem(elem, codeActionArgs); if (!result) { return undefined; } @@ -589,7 +603,7 @@ function parseVerifyCompletionArg(arg: ts.Expression): VerifyCompletionsCmd | un }; } -function parseExpectedCompletionItem(expr: ts.Expression): string | undefined { +function parseExpectedCompletionItem(expr: ts.Expression, codeActionArgs?: VerifyApplyCodeActionArgs): string | undefined { if (completionConstants.has(expr.getText())) { return completionConstants.get(expr.getText())!; } @@ -600,6 +614,7 @@ function parseExpectedCompletionItem(expr: ts.Expression): string | undefined { if (strExpr = getObjectLiteralExpression(expr)) { let isDeprecated = false; // !!! let isOptional = false; + let sourceInit: ts.StringLiteralLike | undefined; let extensions: string[] = []; // !!! let itemProps: string[] = []; let name: string | undefined; @@ -708,6 +723,26 @@ function parseExpectedCompletionItem(expr: ts.Expression): string | undefined { } case "isFromUncheckedFile": break; // Ignored + case "hasAction": + itemProps.push("AdditionalTextEdits: fourslash.AnyTextEdits,"); + break; + case "source": + case "sourceDisplay": + if (sourceInit !== undefined) { + break; + } + if (sourceInit = getStringLiteralLike(init)) { + itemProps.push(`Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: ${getGoStringLiteral(sourceInit.text)}, + }, + })),`); + } + else { + console.error(`Expected string literal for source/sourceDisplay, got ${init.getText()}`); + return undefined; + } + break; case "commitCharacters": // !!! support these later break; @@ -732,6 +767,11 @@ function parseExpectedCompletionItem(expr: ts.Expression): string | undefined { if (!name) { return undefined; // Shouldn't happen } + if (codeActionArgs && codeActionArgs.name === name && codeActionArgs.source === sourceInit?.text) { + itemProps.push(`LabelDetails: &lsproto.CompletionItemLabelDetails{ + Description: PtrTo(${getGoStringLiteral(codeActionArgs.source)}), + },`); + } if (replacementSpanIdx) { itemProps.push(`TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ TextEdit: &lsproto.TextEdit{ @@ -754,6 +794,60 @@ function parseExpectedCompletionItem(expr: ts.Expression): string | undefined { return undefined; // Unsupported expression type } +function parseAndApplyCodeActionArg(arg: ts.Expression): VerifyApplyCodeActionArgs | undefined { + const obj = getObjectLiteralExpression(arg); + if (!obj) { + console.error(`Expected object literal for code action argument, got ${arg.getText()}`); + return undefined; + } + const nameProperty = obj.properties.find(prop => + ts.isPropertyAssignment(prop) && + ts.isIdentifier(prop.name) && + prop.name.text === "name" && + ts.isStringLiteralLike(prop.initializer) + ) as ts.PropertyAssignment | undefined; + if (!nameProperty) { + console.error(`Expected name property in code action argument, got ${obj.getText()}`); + return undefined; + } + const sourceProperty = obj.properties.find(prop => + ts.isPropertyAssignment(prop) && + ts.isIdentifier(prop.name) && + prop.name.text === "source" && + ts.isStringLiteralLike(prop.initializer) + ) as ts.PropertyAssignment | undefined; + if (!sourceProperty) { + console.error(`Expected source property in code action argument, got ${obj.getText()}`); + return undefined; + } + const descriptionProperty = obj.properties.find(prop => + ts.isPropertyAssignment(prop) && + ts.isIdentifier(prop.name) && + prop.name.text === "description" && + ts.isStringLiteralLike(prop.initializer) + ) as ts.PropertyAssignment | undefined; + if (!descriptionProperty) { + console.error(`Expected description property in code action argument, got ${obj.getText()}`); + return undefined; + } + const newFileContentProperty = obj.properties.find(prop => + ts.isPropertyAssignment(prop) && + ts.isIdentifier(prop.name) && + prop.name.text === "newFileContent" && + ts.isStringLiteralLike(prop.initializer) + ) as ts.PropertyAssignment | undefined; + if (!newFileContentProperty) { + console.error(`Expected newFileContent property in code action argument, got ${obj.getText()}`); + return undefined; + } + return { + name: (nameProperty.initializer as ts.StringLiteralLike).text, + source: (sourceProperty.initializer as ts.StringLiteralLike).text, + description: (descriptionProperty.initializer as ts.StringLiteralLike).text, + newFileContent: (newFileContentProperty.initializer as ts.StringLiteralLike).text, + }; +} + function parseBaselineFindAllReferencesArgs(args: readonly ts.Expression[]): [VerifyBaselineFindAllReferencesCmd] | undefined { const newArgs = []; for (const arg of args) { @@ -1287,6 +1381,7 @@ interface VerifyCompletionsCmd { marker: string; isNewIdentifierLocation?: true; args?: VerifyCompletionsArgs | "nil"; + andApplyCodeActionArgs?: VerifyApplyCodeActionArgs; } interface VerifyCompletionsArgs { @@ -1296,6 +1391,13 @@ interface VerifyCompletionsArgs { unsorted?: string; } +interface VerifyApplyCodeActionArgs { + name: string; + source: string; + description: string; + newFileContent: string; +} + interface VerifyBaselineFindAllReferencesCmd { kind: "verifyBaselineFindAllReferences"; markers: string[]; @@ -1371,7 +1473,7 @@ type Cmd = | VerifyBaselineRenameCmd | VerifyRenameInfoCmd; -function generateVerifyCompletions({ marker, args, isNewIdentifierLocation }: VerifyCompletionsCmd): string { +function generateVerifyCompletions({ marker, args, isNewIdentifierLocation, andApplyCodeActionArgs }: VerifyCompletionsCmd): string { let expectedList: string; if (args === "nil") { expectedList = "nil"; @@ -1395,7 +1497,17 @@ function generateVerifyCompletions({ marker, args, isNewIdentifierLocation }: Ve }, }`; } - return `f.VerifyCompletions(t, ${marker}, ${expectedList})`; + + const call = `f.VerifyCompletions(t, ${marker}, ${expectedList})`; + if (andApplyCodeActionArgs) { + return `${call}.AndApplyCodeAction(t, &fourslash.CompletionsExpectedCodeAction{ + Name: ${getGoStringLiteral(andApplyCodeActionArgs.name)}, + Source: ${getGoStringLiteral(andApplyCodeActionArgs.source)}, + Description: ${getGoStringLiteral(andApplyCodeActionArgs.description)}, + NewFileContent: ${getGoMultiLineStringLiteral(andApplyCodeActionArgs.newFileContent)}, + })`; + } + return call; } function generateBaselineFindAllReferences({ markers, ranges }: VerifyBaselineFindAllReferencesCmd): string { @@ -1497,7 +1609,7 @@ interface GoTest { } function generateGoTest(failingTests: Set, test: GoTest): string { - const testName = (test.name[0].toUpperCase() + test.name.substring(1)).replaceAll("-", "_"); + const testName = (test.name[0].toUpperCase() + test.name.substring(1)).replaceAll("-", "_").replaceAll(/[^a-zA-Z0-9_]/g, ""); const content = test.content; const commands = test.commands.map(cmd => generateCmd(cmd)).join("\n"); const imports = [`"github.com/microsoft/typescript-go/internal/fourslash"`]; diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 1db2b09ce7..83ff7cb4ad 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -3,6 +3,24 @@ TestAmbientShorthandGotoDefinition TestArgumentsAreAvailableAfterEditsAtEndOfFunction TestAugmentedTypesClass1 TestAugmentedTypesClass3Fourslash +TestAutoImportFileExcludePatterns3 +TestAutoImportPathsAliasesAndBarrels +TestAutoImportProvider6 +TestAutoImportProvider_exportMap1 +TestAutoImportProvider_exportMap2 +TestAutoImportProvider_exportMap3 +TestAutoImportProvider_exportMap4 +TestAutoImportProvider_exportMap5 +TestAutoImportProvider_exportMap6 +TestAutoImportProvider_exportMap7 +TestAutoImportProvider_exportMap8 +TestAutoImportProvider_exportMap9 +TestAutoImportProvider_globalTypingsCache +TestAutoImportProvider_namespaceSameNameAsIntrinsic +TestAutoImportProvider_wildcardExports1 +TestAutoImportProvider_wildcardExports2 +TestAutoImportProvider_wildcardExports3 +TestAutoImportTypeOnlyPreferred1 TestBestCommonTypeObjectLiterals TestBestCommonTypeObjectLiterals1 TestCodeCompletionEscaping @@ -20,6 +38,7 @@ TestCompletionEntryForUnionProperty TestCompletionEntryForUnionProperty2 TestCompletionForComputedStringProperties TestCompletionForMetaProperty +TestCompletionForObjectProperty TestCompletionForStringLiteral TestCompletionForStringLiteral4 TestCompletionForStringLiteralExport @@ -115,13 +134,49 @@ TestCompletionOfAwaitPromise6 TestCompletionOfAwaitPromise7 TestCompletionOfInterfaceAndVar TestCompletionPreferredSuggestions1 +TestCompletionPropertyShorthandForObjectLiteral5 TestCompletionWithConditionalOperatorMissingColon TestCompletionsAfterJSDoc TestCompletionsBeforeRestArg1 +TestCompletionsClassMemberImportTypeNodeParameter1 +TestCompletionsClassMemberImportTypeNodeParameter2 +TestCompletionsClassMemberImportTypeNodeParameter3 +TestCompletionsClassMemberImportTypeNodeParameter4 TestCompletionsElementAccessNumeric TestCompletionsExportImport TestCompletionsGenericTypeWithMultipleBases1 +TestCompletionsImportBaseUrl +TestCompletionsImportDefaultExportCrash2 TestCompletionsImportOrExportSpecifier +TestCompletionsImportTypeKeyword +TestCompletionsImport_augmentation +TestCompletionsImport_compilerOptionsModule +TestCompletionsImport_duplicatePackages_scoped +TestCompletionsImport_duplicatePackages_scopedTypes +TestCompletionsImport_duplicatePackages_scopedTypesAndNotTypes +TestCompletionsImport_duplicatePackages_types +TestCompletionsImport_exportEqualsNamespace_noDuplicate +TestCompletionsImport_exportEquals_global +TestCompletionsImport_filteredByInvalidPackageJson_direct +TestCompletionsImport_filteredByPackageJson_ambient +TestCompletionsImport_filteredByPackageJson_direct +TestCompletionsImport_filteredByPackageJson_nested +TestCompletionsImport_filteredByPackageJson_peerDependencies +TestCompletionsImport_filteredByPackageJson_typesImplicit +TestCompletionsImport_filteredByPackageJson_typesOnly +TestCompletionsImport_mergedReExport +TestCompletionsImport_named_didNotExistBefore +TestCompletionsImport_named_exportEqualsNamespace_merged +TestCompletionsImport_packageJsonImportsPreference +TestCompletionsImport_previousTokenIsSemicolon +TestCompletionsImport_reExportDefault2 +TestCompletionsImport_sortingModuleSpecifiers +TestCompletionsImport_tsx +TestCompletionsImport_umdDefaultNoCrash1 +TestCompletionsImport_umdModules2_moduleExports +TestCompletionsImport_uriStyleNodeCoreModules1 +TestCompletionsImport_uriStyleNodeCoreModules2 +TestCompletionsImport_windowsPathsProjectRelative TestCompletionsInExport TestCompletionsInExport_moduleBlock TestCompletionsInRequire @@ -153,6 +208,7 @@ TestCompletionsPaths_kinds TestCompletionsPaths_pathMapping TestCompletionsPaths_pathMapping_nonTrailingWildcard1 TestCompletionsPaths_pathMapping_parentDirectory +TestCompletionsRecommended_namespace TestCompletionsRecommended_union TestCompletionsRedeclareModuleAsGlobal TestCompletionsStringsWithTriggerCharacter @@ -160,6 +216,7 @@ TestCompletionsSymbolMembers TestCompletionsTriggerCharacter TestCompletionsTuple TestCompletionsUniqueSymbol1 +TestCompletionsWithDeprecatedTag10 TestConstEnumQuickInfoAndCompletionList TestConstQuickInfoAndCompletionList TestContextuallyTypedFunctionExpressionGeneric1 @@ -216,6 +273,16 @@ TestImportCompletions_importsMap2 TestImportCompletions_importsMap3 TestImportCompletions_importsMap4 TestImportCompletions_importsMap5 +TestImportSuggestionsCache_exportUndefined +TestImportSuggestionsCache_invalidPackageJson +TestImportTypeCompletions1 +TestImportTypeCompletions3 +TestImportTypeCompletions4 +TestImportTypeCompletions5 +TestImportTypeCompletions6 +TestImportTypeCompletions7 +TestImportTypeCompletions8 +TestImportTypeCompletions9 TestIndexerReturnTypes1 TestIndirectClassInstantiation TestInstanceTypesForGenericType1 @@ -246,6 +313,7 @@ TestJsDocPropertyDescription8 TestJsDocPropertyDescription9 TestJsDocServices TestJsDocTagsWithHyphen +TestJsFileImportNoTypes2 TestJsQuickInfoGenerallyAcceptableSize TestJsRequireQuickInfo TestJsdocCallbackTag diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index ddac550413..bcb496f9fc 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -503,19 +503,31 @@ type CompletionsExpectedItems struct { Unsorted []CompletionsExpectedItem } +type CompletionsExpectedCodeAction struct { + Name string + Source string + Description string + NewFileContent string +} + +type VerifyCompletionsResult struct { + AndApplyCodeAction func(t *testing.T, expectedAction *CompletionsExpectedCodeAction) +} + // string | *Marker | []string | []*Marker type MarkerInput = any // !!! user preferences param // !!! completion context param -func (f *FourslashTest) VerifyCompletions(t *testing.T, markerInput MarkerInput, expected *CompletionsExpectedList) { +func (f *FourslashTest) VerifyCompletions(t *testing.T, markerInput MarkerInput, expected *CompletionsExpectedList) VerifyCompletionsResult { + var list *lsproto.CompletionList switch marker := markerInput.(type) { case string: f.GoToMarker(t, marker) - f.verifyCompletionsWorker(t, expected) + list = f.verifyCompletionsWorker(t, expected) case *Marker: f.goToMarker(t, marker) - f.verifyCompletionsWorker(t, expected) + list = f.verifyCompletionsWorker(t, expected) case []string: for _, markerName := range marker { f.GoToMarker(t, markerName) @@ -527,13 +539,34 @@ func (f *FourslashTest) VerifyCompletions(t *testing.T, markerInput MarkerInput, f.verifyCompletionsWorker(t, expected) } case nil: - f.verifyCompletionsWorker(t, expected) + list = f.verifyCompletionsWorker(t, expected) default: t.Fatalf("Invalid marker input type: %T. Expected string, *Marker, []string, or []*Marker.", markerInput) } + + return VerifyCompletionsResult{ + AndApplyCodeAction: func(t *testing.T, expectedAction *CompletionsExpectedCodeAction) { + item := core.Find(list.Items, func(item *lsproto.CompletionItem) bool { + if item.Label != expectedAction.Name || item.Data == nil { + return false + } + data, ok := (*item.Data).(*ls.CompletionItemData) + if !ok || data.AutoImport == nil { + return false + } + return data.AutoImport.ModuleSpecifier == expectedAction.Source + }) + if item == nil { + t.Fatalf("Code action '%s' from source '%s' not found in completions.", expectedAction.Name, expectedAction.Source) + } + assert.Check(t, strings.Contains(*item.Detail, expectedAction.Description), "Completion item detail does not contain expected description.") + f.ApplyTextEdits(t, *item.AdditionalTextEdits) + assert.Equal(t, f.getScriptInfo(f.activeFilename).content, expectedAction.NewFileContent, fmt.Sprintf("File content after applying code action '%s' did not match expected content.", expectedAction.Name)) + }, + } } -func (f *FourslashTest) verifyCompletionsWorker(t *testing.T, expected *CompletionsExpectedList) { +func (f *FourslashTest) verifyCompletionsWorker(t *testing.T, expected *CompletionsExpectedList) *lsproto.CompletionList { prefix := f.getCurrentPositionPrefix() params := &lsproto.CompletionParams{ TextDocument: lsproto.TextDocumentIdentifier{ @@ -550,6 +583,7 @@ func (f *FourslashTest) verifyCompletionsWorker(t *testing.T, expected *Completi t.Fatalf(prefix+"Unexpected response type for completion request: %T", resMsg.AsResponse().Result) } f.verifyCompletionsResult(t, result.List, expected, prefix) + return result.List } func (f *FourslashTest) verifyCompletionsResult( @@ -712,20 +746,40 @@ func (f *FourslashTest) verifyCompletionsAreExactly(t *testing.T, prefix string, } } -var completionIgnoreOpts = cmp.FilterPath( - func(p cmp.Path) bool { - switch p.Last().String() { - case ".Kind", ".SortText", ".Data": - return true - default: +func ignorePaths(paths ...string) cmp.Option { + return cmp.FilterPath( + func(p cmp.Path) bool { + for _, path := range paths { + if p.Last().String() == path { + return true + } + } return false - } - }, - cmp.Ignore(), -) + }, + cmp.Ignore(), + ) +} + +var completionIgnoreOpts = ignorePaths(".Kind", ".SortText", ".Data") +var autoImportIgnoreOpts = ignorePaths(".Kind", ".SortText", ".Data", ".LabelDetails", ".Detail", ".AdditionalTextEdits") func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual *lsproto.CompletionItem, expected *lsproto.CompletionItem) { - if expected.Detail != nil || expected.Documentation != nil { + var actualAutoImportData, expectedAutoImportData *ls.AutoImportData + if actual.Data != nil { + if data, ok := (*actual.Data).(*ls.CompletionItemData); ok { + actualAutoImportData = data.AutoImport + } + } + if expected.Data != nil { + if data, ok := (*expected.Data).(*ls.CompletionItemData); ok { + expectedAutoImportData = data.AutoImport + } + } + if (actualAutoImportData == nil) != (expectedAutoImportData == nil) { + t.Fatal(prefix + "Mismatch in auto-import data presence") + } + + if expected.Detail != nil || expected.Documentation != nil || actualAutoImportData != nil { resMsg, result, resultOk := sendRequest(t, f, lsproto.CompletionItemResolveInfo, actual) if resMsg == nil { t.Fatal(prefix + "Expected non-nil response for completion item resolve, got nil") @@ -735,7 +789,21 @@ func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual } actual = result } - assertDeepEqual(t, actual, expected, prefix, completionIgnoreOpts) + + if actualAutoImportData != nil { + assertDeepEqual(t, actual, expected, prefix, autoImportIgnoreOpts) + if expected.AdditionalTextEdits == AnyTextEdits { + assert.Check(t, actual.AdditionalTextEdits != nil && len(*actual.AdditionalTextEdits) > 0, prefix+" Expected non-nil AdditionalTextEdits for auto-import completion item") + } + if expected.LabelDetails != nil { + assertDeepEqual(t, actual.LabelDetails, expected.LabelDetails, prefix+" LabelDetails mismatch") + } + + assert.Equal(t, actualAutoImportData.ModuleSpecifier, expectedAutoImportData.ModuleSpecifier, prefix+" ModuleSpecifier mismatch") + } else { + assertDeepEqual(t, actual, expected, prefix, completionIgnoreOpts) + } + if expected.Kind != nil { assertDeepEqual(t, actual.Kind, expected.Kind, prefix+" Kind mismatch") } @@ -1247,6 +1315,22 @@ func (f *FourslashTest) getSelection() core.TextRange { ) } +func (f *FourslashTest) ApplyTextEdits(t *testing.T, edits []*lsproto.TextEdit) { + script := f.getScriptInfo(f.activeFilename) + slices.SortFunc(edits, func(a, b *lsproto.TextEdit) int { + aStart := f.converters.LineAndCharacterToPosition(script, a.Range.Start) + bStart := f.converters.LineAndCharacterToPosition(script, b.Range.Start) + return int(aStart) - int(bStart) + }) + // Apply edits in reverse order to avoid affecting the positions of earlier edits. + for i := len(edits) - 1; i >= 0; i-- { + edit := edits[i] + start := int(f.converters.LineAndCharacterToPosition(script, edit.Range.Start)) + end := int(f.converters.LineAndCharacterToPosition(script, edit.Range.End)) + f.editScriptAndUpdateMarkers(t, f.activeFilename, start, end, edit.NewText) + } +} + func (f *FourslashTest) Replace(t *testing.T, start int, length int, text string) { f.editScriptAndUpdateMarkers(t, f.activeFilename, start, start+length, text) // f.checkPostEditInvariants() // !!! do we need this? @@ -1792,3 +1876,7 @@ func (f *FourslashTest) verifyBaselines(t *testing.T) { baseline.Run(t, getBaselineFileName(t, command), content.String(), getBaselineOptions(command)) } } + +type anyTextEdits *[]*lsproto.TextEdit + +var AnyTextEdits = anyTextEdits(nil) diff --git a/internal/fourslash/tests/gen/autoImportFileExcludePatterns3_test.go b/internal/fourslash/tests/gen/autoImportFileExcludePatterns3_test.go new file mode 100644 index 0000000000..e693dda53e --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportFileExcludePatterns3_test.go @@ -0,0 +1,71 @@ +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 TestAutoImportFileExcludePatterns3(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: /ambient1.d.ts +declare module "foo" { + export const x = 1; +} +// @Filename: /ambient2.d.ts +declare module "foo" { + export const y = 2; +} +// @Filename: /index.ts +/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "x", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "foo", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "y", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "foo", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobals, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportPathsAliasesAndBarrels_test.go b/internal/fourslash/tests/gen/autoImportPathsAliasesAndBarrels_test.go new file mode 100644 index 0000000000..3848049ba1 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportPathsAliasesAndBarrels_test.go @@ -0,0 +1,83 @@ +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 TestAutoImportPathsAliasesAndBarrels(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /tsconfig.json + { + "compilerOptions": { + "module": "commonjs", + "paths": { + "~/*": ["src/*"] + } + } +} +// @Filename: /src/dirA/index.ts + export * from "./thing1A"; + export * from "./thing2A"; +// @Filename: /src/dirA/thing1A.ts + export class Thing1A {} + Thing/**/ +// @Filename: /src/dirA/thing2A.ts + export class Thing2A {} +// @Filename: /src/dirB/index.ts + export * from "./thing1B"; + export * from "./thing2B"; +// @Filename: /src/dirB/thing1B.ts + export class Thing1B {} +// @Filename: /src/dirB/thing2B.ts + export class Thing2B {}` + 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: "Thing2A", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./thing2A", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "Thing1B", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "~/dirB", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "Thing2B", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "~/dirB", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider6_test.go b/internal/fourslash/tests/gen/autoImportProvider6_test.go new file mode 100644 index 0000000000..0aca378200 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider6_test.go @@ -0,0 +1,50 @@ +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 TestAutoImportProvider6(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ "compilerOptions": { "module": "commonjs", "lib": ["es2019"] } } +// @Filename: /home/src/workspaces/project/package.json +{ "dependencies": { "antd": "*", "react": "*" } } +// @Filename: /home/src/workspaces/project/node_modules/@types/react/index.d.ts +export declare function Component(): void; +// @Filename: /home/src/workspaces/project/node_modules/antd/index.d.ts +import "react"; +// @Filename: /home/src/workspaces/project/index.ts +Component/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Component", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/home/src/workspaces/project/node_modules/@types/react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap1_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap1_test.go new file mode 100644 index 0000000000..82b994d822 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap1_test.go @@ -0,0 +1,83 @@ +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 TestAutoImportProvider_exportMap1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "exports": { + ".": { + "types": "./lib/index.d.ts" + }, + "./lol": { + "types": "./lib/lol.d.ts" + } + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + &lsproto.CompletionItem{ + Label: "fooFromLol", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency/lol", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go new file mode 100644 index 0000000000..58dca8dc9c --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go @@ -0,0 +1,75 @@ +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 TestAutoImportProvider_exportMap2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "commonjs" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "types": "./lib/index.d.ts", + "exports": { + ".": { + "types": "./lib/index.d.ts" + }, + "./lol": { + "types": "./lib/lol.d.ts" + } + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap3_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap3_test.go new file mode 100644 index 0000000000..8f44b395be --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap3_test.go @@ -0,0 +1,69 @@ +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 TestAutoImportProvider_exportMap3(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "name": "dependency", + "version": "1.0.0", + "main": "./lib/index.js", + "exports": "./lib/lol.d.ts" +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromLol", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + Excludes: []string{ + "fooFromIndex", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap4_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap4_test.go new file mode 100644 index 0000000000..9df1a5a2fd --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap4_test.go @@ -0,0 +1,72 @@ +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 TestAutoImportProvider_exportMap4(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "exports": { + "types": "./lib/index.d.ts", + "require": "./lib/lol.js" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + Excludes: []string{ + "fooFromLol", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap5_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap5_test.go new file mode 100644 index 0000000000..7e92a21a2b --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap5_test.go @@ -0,0 +1,94 @@ +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 TestAutoImportProvider_exportMap5(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @types package lookup +// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "exports": { + ".": "./lib/index.js", + "./lol": "./lib/lol.js" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.js +export function fooFromIndex() {} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.js +export function fooFromLol() {} +// @Filename: /home/src/workspaces/project/node_modules/@types/dependency/package.json +{ + "type": "module", + "name": "@types/dependency", + "version": "1.0.0", + "exports": { + ".": "./lib/index.d.ts", + "./lol": "./lib/lol.d.ts" + } +} +// @Filename: /home/src/workspaces/project/node_modules/@types/dependency/lib/index.d.ts +export declare function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/@types/dependency/lib/lol.d.ts +export declare function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + &lsproto.CompletionItem{ + Label: "fooFromLol", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency/lol", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap6_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap6_test.go new file mode 100644 index 0000000000..47d78b34d8 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap6_test.go @@ -0,0 +1,101 @@ +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 TestAutoImportProvider_exportMap6(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @types package should be ignored because implementation package has types +// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + }, + "devDependencies": { + "@types/dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "exports": { + ".": "./lib/index.js", + "./lol": "./lib/lol.js" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.js +export function fooFromIndex() {} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export declare function fooFromIndex(): void +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.js +export function fooFromLol() {} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export declare function fooFromLol(): void +// @Filename: /home/src/workspaces/project/node_modules/@types/dependency/package.json +{ + "type": "module", + "name": "@types/dependency", + "version": "1.0.0", + "exports": { + ".": "./lib/index.d.ts", + "./lol": "./lib/lol.d.ts" + } +} +// @Filename: /home/src/workspaces/project/node_modules/@types/dependency/lib/index.d.ts +export declare function fooFromAtTypesIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/@types/dependency/lib/lol.d.ts +export declare function fooFromAtTypesLol(): void; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + &lsproto.CompletionItem{ + Label: "fooFromLol", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency/lol", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap7_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap7_test.go new file mode 100644 index 0000000000..7088378a8e --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap7_test.go @@ -0,0 +1,85 @@ +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 TestAutoImportProvider_exportMap7(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "exports": { + ".": { + "types": "./lib/index.d.ts" + }, + "./lol": { + "types": "./lib/lol.d.ts" + } + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/bar.ts +import { fooFromIndex } from "dependency"; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + &lsproto.CompletionItem{ + Label: "fooFromLol", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency/lol", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap8_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap8_test.go new file mode 100644 index 0000000000..c31f19f053 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap8_test.go @@ -0,0 +1,103 @@ +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 TestAutoImportProvider_exportMap8(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "exports": { + "./lol": { + "import": "./lib/index.js", + "require": "./lib/lol.js" + } + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/bar.ts +import { fooFromIndex } from "dependency"; +// @Filename: /home/src/workspaces/project/src/foo.cts +fooFrom/*cts*/ +// @Filename: /home/src/workspaces/project/src/foo.mts +fooFrom/*mts*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "cts") + f.VerifyCompletions(t, "cts", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromLol", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency/lol", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + Excludes: []string{ + "fooFromIndex", + }, + }, + }) + f.GoToMarker(t, "mts") + f.VerifyCompletions(t, "mts", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency/lol", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + Excludes: []string{ + "fooFromLol", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap9_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap9_test.go new file mode 100644 index 0000000000..dd90f2c0fa --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap9_test.go @@ -0,0 +1,73 @@ +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 TestAutoImportProvider_exportMap9(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "dependency": "^1.0.0" + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/package.json +{ + "type": "module", + "name": "dependency", + "version": "1.0.0", + "exports": { + "./lol": ["./lib/index.js", "./lib/lol.js"] + } +} +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/index.d.ts +export function fooFromIndex(): void; +// @Filename: /home/src/workspaces/project/node_modules/dependency/lib/lol.d.ts +export function fooFromLol(): void; +// @Filename: /home/src/workspaces/project/src/bar.ts +import { fooFromIndex } from "dependency"; +// @Filename: /home/src/workspaces/project/src/foo.ts +fooFrom/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooFromIndex", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dependency/lol", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + Excludes: []string{ + "fooFromLol", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_globalTypingsCache_test.go b/internal/fourslash/tests/gen/autoImportProvider_globalTypingsCache_test.go new file mode 100644 index 0000000000..e4c20f6b8c --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_globalTypingsCache_test.go @@ -0,0 +1,57 @@ +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 TestAutoImportProvider_globalTypingsCache(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/Library/Caches/typescript/node_modules/@types/react-router-dom/package.json + { "name": "@types/react-router-dom", "version": "16.8.4", "types": "index.d.ts" } +// @Filename: /home/src/Library/Caches/typescript/node_modules/@types/react-router-dom/index.d.ts + export class BrowserRouterFromDts {} +// @Filename: /home/src/workspaces/project/package.json + { "dependencies": { "react-router-dom": "*" } } +// @Filename: /home/src/workspaces/project/tsconfig.json + { "compilerOptions": { "module": "commonjs", "allowJs": true, "checkJs": true, "maxNodeModuleJsDepth": 2 }, "typeAcquisition": { "enable": true } } +// @Filename: /home/src/workspaces/project/node_modules/react-router-dom/package.json + { "name": "react-router-dom", "version": "16.8.4", "main": "index.js" } +// @Filename: /home/src/workspaces/project/node_modules/react-router-dom/index.js + import "./BrowserRouter"; + export {}; +// @Filename: /home/src/workspaces/project/node_modules/react-router-dom/BrowserRouter.js + export const BrowserRouterFromJs = () => null; +// @Filename: /home/src/workspaces/project/index.js +BrowserRouter/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsInJSPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "BrowserRouterFromDts", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "react-router-dom", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_namespaceSameNameAsIntrinsic_test.go b/internal/fourslash/tests/gen/autoImportProvider_namespaceSameNameAsIntrinsic_test.go new file mode 100644 index 0000000000..958cb934c0 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_namespaceSameNameAsIntrinsic_test.go @@ -0,0 +1,57 @@ +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 TestAutoImportProvider_namespaceSameNameAsIntrinsic(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/node_modules/fp-ts/package.json +{ "name": "fp-ts", "version": "0.10.4" } +// @Filename: /home/src/workspaces/project/node_modules/fp-ts/index.d.ts +export * as string from "./lib/string"; +// @Filename: /home/src/workspaces/project/node_modules/fp-ts/lib/string.d.ts +export declare const fromString: (s: string) => string; +export type SafeString = string; +// @Filename: /home/src/workspaces/project/package.json +{ "dependencies": { "fp-ts": "^0.10.4" } } +// @Filename: /home/src/workspaces/project/tsconfig.json +{ "compilerOptions": { "module": "commonjs" } } +// @Filename: /home/src/workspaces/project/index.ts +type A = { name: string/**/ }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "string", + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + }, + &lsproto.CompletionItem{ + Label: "string", + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "fp-ts", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_wildcardExports1_test.go b/internal/fourslash/tests/gen/autoImportProvider_wildcardExports1_test.go new file mode 100644 index 0000000000..4a12fc1dde --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_wildcardExports1_test.go @@ -0,0 +1,122 @@ +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 TestAutoImportProvider_wildcardExports1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ + "name": "pkg", + "version": "1.0.0", + "exports": { + "./*": "./a/*.js", + "./b/*.js": "./b/*.js", + "./c/*": "./c/*", + "./d/*": { + "import": "./d/*.mjs" + } + } +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/a/a1.d.ts +export const a1: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/b/b1.d.ts +export const b1: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/b/b2.d.mts +export const NOT_REACHABLE: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/c/c1.d.ts +export const c1: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/c/subfolder/c2.d.mts +export const c2: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/d/d1.d.mts +export const d1: number; +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "pkg": "1.0.0" + } +} +// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/main.ts +/**/` + 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: "a1", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "pkg/a1", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "b1", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "pkg/b/b1.js", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "c1", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "pkg/c/c1.js", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "c2", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "pkg/c/subfolder/c2.mjs", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "d1", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "pkg/d/d1", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "NOT_REACHABLE", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_wildcardExports2_test.go b/internal/fourslash/tests/gen/autoImportProvider_wildcardExports2_test.go new file mode 100644 index 0000000000..efaa6244a9 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_wildcardExports2_test.go @@ -0,0 +1,67 @@ +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 TestAutoImportProvider_wildcardExports2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ + "name": "pkg", + "version": "1.0.0", + "exports": { + "./core/*": { + "types": "./lib/core/*.d.ts", + "default": "./lib/core/*.js" + } + } +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/lib/core/test.d.ts +export function test(): void; +// @Filename: /home/src/workspaces/project/package.json +{ + "type": "module", + "dependencies": { + "pkg": "1.0.0" + } +} +// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "nodenext" + } +} +// @Filename: /home/src/workspaces/project/main.ts +/**/` + 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: "test", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "pkg/core/test", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportProvider_wildcardExports3_test.go b/internal/fourslash/tests/gen/autoImportProvider_wildcardExports3_test.go new file mode 100644 index 0000000000..ac0430073b --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_wildcardExports3_test.go @@ -0,0 +1,71 @@ +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 TestAutoImportProvider_wildcardExports3(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/packages/ui/package.json +{ + "name": "@repo/ui", + "version": "1.0.0", + "exports": { + "./*": "./src/*.tsx" + } +} +// @Filename: /home/src/workspaces/project/packages/ui/src/Card.tsx +export const Card = () => null; +// @Filename: /home/src/workspaces/project/apps/web/package.json +{ + "name": "web", + "version": "1.0.0", + "dependencies": { + "@repo/ui": "workspace:*" + } +} +// @Filename: /home/src/workspaces/project/apps/web/tsconfig.json +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "noEmit": true, + "jsx": "preserve" + }, + "include": ["app"] +} +// @Filename: /home/src/workspaces/project/apps/web/app/index.tsx +(); +// @link: /home/src/workspaces/project/packages/ui -> /home/src/workspaces/project/apps/web/node_modules/@repo/ui` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Card", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@repo/ui/Card", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go b/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go new file mode 100644 index 0000000000..1c4e6a85be --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go @@ -0,0 +1,59 @@ +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 TestAutoImportSameNameDefaultExported(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: /node_modules/antd/index.d.ts +declare function Table(): void; +export default Table; +// @Filename: /node_modules/rc-table/index.d.ts +declare function Table(): void; +export default Table; +// @Filename: /index.ts +Table/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Table", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "antd", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + &lsproto.CompletionItem{ + Label: "Table", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "rc-table", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go b/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go new file mode 100644 index 0000000000..e5e6dbeeec --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go @@ -0,0 +1,63 @@ +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 TestAutoImportTypeOnlyPreferred1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @verbatimModuleSyntax: true +// @module: esnext +// @moduleResolution: bundler +// @Filename: /ts.d.ts +declare namespace ts { + interface SourceFile { + text: string; + } + function createSourceFile(): SourceFile; +} +export = ts; +// @Filename: /types.ts +export interface VFS { + getSourceFile(path: string): ts/**/ +}` + 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: "ts", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./ts", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }).AndApplyCodeAction(t, &fourslash.CompletionsExpectedCodeAction{ + Name: "ts", + Source: "./ts", + Description: "Add import from \"./ts\"", + NewFileContent: `import type ts from "./ts"; + +export interface VFS { + getSourceFile(path: string): ts +}`, + }) +} diff --git a/internal/fourslash/tests/gen/completionForObjectProperty_test.go b/internal/fourslash/tests/gen/completionForObjectProperty_test.go new file mode 100644 index 0000000000..388df82e59 --- /dev/null +++ b/internal/fourslash/tests/gen/completionForObjectProperty_test.go @@ -0,0 +1,189 @@ +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 TestCompletionForObjectProperty(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export const foo = { bar: 'baz' }; +// @Filename: /b.ts +const test = foo/*1*/ +// @Filename: /c.ts +const test2 = {...foo/*2*/} +// @Filename: /d.ts +const test3 = [{...foo/*3*/}] +// @Filename: /e.ts +const test4 = { foo/*4*/ } +// @Filename: /f.ts +const test5 = { foo: /*5*/ } +// @Filename: /g.ts +const test6 = { unrelated: foo/*6*/ } +// @Filename: /i.ts +const test7: { foo/*7*/: "unrelated" } +// @Filename: /h.ts +const test8: { foo: string } = { foo/*8*/ }` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "5", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "6", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "7", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Excludes: []string{ + "foo", + }, + }, + }) + f.VerifyCompletions(t, "8", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + SortText: PtrTo(string(ls.SortTextLocationPriority)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionPropertyShorthandForObjectLiteral5_test.go b/internal/fourslash/tests/gen/completionPropertyShorthandForObjectLiteral5_test.go new file mode 100644 index 0000000000..ed5e08c7ff --- /dev/null +++ b/internal/fourslash/tests/gen/completionPropertyShorthandForObjectLiteral5_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/ls" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCompletionPropertyShorthandForObjectLiteral5(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @Filename: /a.ts +export const exportedConstant = 0; +// @Filename: /b.ts +const foo = 'foo' +const obj = { exp/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "exportedConstant", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter1_test.go b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter1_test.go new file mode 100644 index 0000000000..1a537ea7ce --- /dev/null +++ b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter1_test.go @@ -0,0 +1,47 @@ +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 TestCompletionsClassMemberImportTypeNodeParameter1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @Filename: /generation.d.ts +export type GenerationConfigType = { max_length?: number }; +// @FileName: /index.d.ts +export declare class PreTrainedModel { + _get_generation_config( + param: import("./generation.js").GenerationConfigType, + ): import("./generation.js").GenerationConfigType; +} + +export declare class BlenderbotSmallPreTrainedModel extends PreTrainedModel { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "_get_generation_config", + InsertText: PtrTo("_get_generation_config(param: import(\"./generation.js\").GenerationConfigType): import(\"./generation.js\").GenerationConfigType;"), + FilterText: PtrTo("_get_generation_config"), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter2_test.go b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter2_test.go new file mode 100644 index 0000000000..291c5f4023 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter2_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 TestCompletionsClassMemberImportTypeNodeParameter2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @FileName: /index.d.ts +export declare class Cls { + method( + param: import("./doesntexist.js").Foo, + ): import("./doesntexist.js").Foo; +} + +export declare class Derived extends Cls { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "method", + InsertText: PtrTo("method(param: import(\"./doesntexist.js\").Foo);"), + FilterText: PtrTo("method"), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter3_test.go b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter3_test.go new file mode 100644 index 0000000000..d3a0eb7fc7 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter3_test.go @@ -0,0 +1,49 @@ +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 TestCompletionsClassMemberImportTypeNodeParameter3(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @FileName: /other/foo.d.ts +export declare type Bar = { baz: string }; +// @FileName: /other/cls.d.ts +export declare class Cls { + method( + param: import("./foo.js").Bar, + ): import("./foo.js").Bar; +} +// @FileName: /index.d.ts +import { Cls } from "./other/cls.js"; + +export declare class Derived extends Cls { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "method", + InsertText: PtrTo("method(param: import(\"./other/foo.js\").Bar): import(\"./other/foo.js\").Bar;"), + FilterText: PtrTo("method"), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter4_test.go b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter4_test.go new file mode 100644 index 0000000000..52343b3055 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter4_test.go @@ -0,0 +1,47 @@ +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 TestCompletionsClassMemberImportTypeNodeParameter4(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @FileName: /other/cls.d.ts +export declare class Cls { + method( + param: import("./doesntexist.js").Foo, + ): import("./doesntexist.js").Foo; +} +// @FileName: /index.d.ts +import { Cls } from "./other/cls.js"; + +export declare class Derived extends Cls { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "method", + InsertText: PtrTo("method(param: import(\"./doesntexist.js\").Foo);"), + FilterText: PtrTo("method"), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImportBaseUrl_test.go b/internal/fourslash/tests/gen/completionsImportBaseUrl_test.go new file mode 100644 index 0000000000..e73fae4069 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImportBaseUrl_test.go @@ -0,0 +1,52 @@ +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 TestCompletionsImportBaseUrl(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /tsconfig.json +{ + "compilerOptions": { + "baseUrl": ".", + "module": "esnext" + } +} +// @Filename: /src/a.ts +export const foo = 0; +// @Filename: /src/b.ts +fo/**/` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/src/a", + }, + })), + Detail: PtrTo("const foo: 0"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go b/internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go new file mode 100644 index 0000000000..fd3d116e79 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go @@ -0,0 +1,77 @@ +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 TestCompletionsImportDefaultExportCrash2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @allowJs: true +// @Filename: /node_modules/dom7/index.d.ts +export interface Dom7Array { + length: number; + prop(propName: string): any; +} + +export interface Dom7 { + (): Dom7Array; + fn: any; +} + +declare const Dom7: Dom7; + +export { + Dom7 as $, +}; +// @Filename: /dom7.js +import * as methods from 'dom7'; +Object.keys(methods).forEach((methodName) => { + if (methodName === '$') return; + methods.$.fn[methodName] = methods[methodName]; +}); + +export default methods.$; +// @Filename: /swipe-back.js +/*1*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "$", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "dom7", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "Dom7", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./dom7", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go b/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go new file mode 100644 index 0000000000..473717309d --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go @@ -0,0 +1,50 @@ +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 TestCompletionsImportTypeKeyword(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @Filename: /os.d.ts +declare module "os" { + export function type(): string; +} +// @Filename: /index.ts +type/**/` + 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: "type", + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + }, + &lsproto.CompletionItem{ + Label: "type", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "os", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_augmentation_test.go b/internal/fourslash/tests/gen/completionsImport_augmentation_test.go new file mode 100644 index 0000000000..a43ca7fc41 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_augmentation_test.go @@ -0,0 +1,60 @@ +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 TestCompletionsImport_augmentation(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export const foo = 0; +// @Filename: /bar.ts +export {}; +declare module "./a" { + export const bar = 0; +} +// @Filename: /user.ts +/**/` + 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: "foo", + Detail: PtrTo("const foo: 0"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "bar", + Detail: PtrTo("const bar: 0"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go b/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go new file mode 100644 index 0000000000..d2da944d10 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go @@ -0,0 +1,65 @@ +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 TestCompletionsImport_compilerOptionsModule(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @module: commonjs +// @Filename: /node_modules/a/index.d.ts +export const foo = 0; +// @Filename: /b.js +const a = require("./a"); +fo/*b*/ +// @Filename: /c.js +const x = 0;/*c*/ +// @Filename: /c1.js +// @ts-check +const x = 0;/*ccheck*/ +// @Filename: /c2.ts +const x = 0;/*cts*/ +// @Filename: /d.js +const a = import("./a"); // Does not make this an external module +fo/*d*/ +// @Filename: /d1.js +// @ts-check +const a = import("./a"); // Does not make this an external module +fo/*dcheck*/ +// @Filename: /d2.ts +const a = import("./a"); // Does not make this an external module +fo/*dts*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, []string{"b", "c", "ccheck", "cts", "d", "dcheck", "dts"}, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/a/index", + }, + })), + Detail: PtrTo("const foo: 0"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_reExport_test.go b/internal/fourslash/tests/gen/completionsImport_default_reExport_test.go new file mode 100644 index 0000000000..52e55cdecb --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_reExport_test.go @@ -0,0 +1,64 @@ +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 TestCompletionsImport_default_reExport(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @allowJs: true +// @Filename: /file1.js +const a = 1; +export { + a as b +}; +export default a; +// @Filename: /file2.js +import * as foo from './file1'; +/**/ +export default foo.b;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsInJSPlus( + []fourslash.CompletionsExpectedItem{ + "foo", + &lsproto.CompletionItem{ + Label: "a", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./file1", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "b", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./file1", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go new file mode 100644 index 0000000000..18b1b6e73e --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go @@ -0,0 +1,74 @@ +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 TestCompletionsImport_duplicatePackages_scopedTypesAndNotTypes(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @esModuleInterop: true +// @Filename: /node_modules/@types/scope__react-dom/package.json +{ "name": "react-dom", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/scope__react-dom/index.d.ts +import * as React from "react"; +export function render(): void; +// @Filename: /node_modules/@types/scope__react/package.json +{ "name": "react", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/scope__react/index.d.ts +import "./other"; +export declare function useState(): void; +// @Filename: /node_modules/@types/scope__react/other.d.ts +export declare function useRef(): void; +// @Filename: /packages/a/node_modules/@scope/react/package.json +{ "name": "react", "version": "1.0.1", "types": "./index.d.ts" } +// @Filename: /packages/a/node_modules/@scope/react/index.d.ts +export declare function useState(): void; +// @Filename: /packages/a/index.ts +import "react-dom"; +import "react"; +// @Filename: /packages/a/foo.ts +/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "render", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@scope/react-dom", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "useState", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@scope/react", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go new file mode 100644 index 0000000000..0119e58b2f --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go @@ -0,0 +1,74 @@ +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 TestCompletionsImport_duplicatePackages_scopedTypes(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @esModuleInterop: true +// @Filename: /node_modules/@types/scope__react-dom/package.json +{ "name": "react-dom", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/scope__react-dom/index.d.ts +import * as React from "react"; +export function render(): void; +// @Filename: /node_modules/@types/scope__react/package.json +{ "name": "react", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/scope__react/index.d.ts +import "./other"; +export declare function useState(): void; +// @Filename: /node_modules/@types/scope__react/other.d.ts +export declare function useRef(): void; +// @Filename: /packages/a/node_modules/@types/scope__react/package.json +{ "name": "react", "version": "1.0.1", "types": "./index.d.ts" } +// @Filename: /packages/a/node_modules/@types/scope__react/index.d.ts +export declare function useState(): void; +// @Filename: /packages/a/index.ts +import "@scope/react-dom"; +import "@scope/react"; +// @Filename: /packages/a/foo.ts +/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "render", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@scope/react-dom", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "useState", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@scope/react", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go new file mode 100644 index 0000000000..78a52a020f --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go @@ -0,0 +1,74 @@ +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 TestCompletionsImport_duplicatePackages_scoped(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @esModuleInterop: true +// @Filename: /node_modules/@scope/react-dom/package.json +{ "name": "react-dom", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@scope/react-dom/index.d.ts +import * as React from "react"; +export function render(): void; +// @Filename: /node_modules/@scope/react/package.json +{ "name": "react", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@scope/react/index.d.ts +import "./other"; +export declare function useState(): void; +// @Filename: /node_modules/@scope/react/other.d.ts +export declare function useRef(): void; +// @Filename: /packages/a/node_modules/@scope/react/package.json +{ "name": "react", "version": "1.0.1", "types": "./index.d.ts" } +// @Filename: /packages/a/node_modules/@scope/react/index.d.ts +export declare function useState(): void; +// @Filename: /packages/a/index.ts +import "@scope/react-dom"; +import "@scope/react"; +// @Filename: /packages/a/foo.ts +/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "render", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@scope/react-dom", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "useState", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@scope/react", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_typesAndNotTypes_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_typesAndNotTypes_test.go new file mode 100644 index 0000000000..380ddb701d --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_typesAndNotTypes_test.go @@ -0,0 +1,64 @@ +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 TestCompletionsImport_duplicatePackages_typesAndNotTypes(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @esModuleInterop: true +// @Filename: /node_modules/@types/react-dom/package.json +{ "name": "react-dom", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/react-dom/index.d.ts +import * as React from "react"; +export function render(): void; +// @Filename: /node_modules/@types/react/package.json +{ "name": "react", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/react/index.d.ts +import "./other"; +export declare function useState(): void; +// @Filename: /node_modules/@types/react/other.d.ts +export declare function useRef(): void; +// @Filename: /packages/a/node_modules/react/package.json +{ "name": "react", "version": "1.0.1", "types": "./index.d.ts" } +// @Filename: /packages/a/node_modules/react/index.d.ts +export declare function useState(): void; +// @Filename: /packages/a/index.ts +import "react-dom"; +import "react"; +// @Filename: /packages/a/foo.ts +useState/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "useState", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "react", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go new file mode 100644 index 0000000000..a86a0ad038 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go @@ -0,0 +1,74 @@ +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 TestCompletionsImport_duplicatePackages_types(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @esModuleInterop: true +// @Filename: /node_modules/@types/react-dom/package.json +{ "name": "react-dom", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/react-dom/index.d.ts +import * as React from "react"; +export function render(): void; +// @Filename: /node_modules/@types/react/package.json +{ "name": "react", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /node_modules/@types/react/index.d.ts +import "./other"; +export declare function useState(): void; +// @Filename: /node_modules/@types/react/other.d.ts +export declare function useRef(): void; +// @Filename: /packages/a/node_modules/@types/react/package.json +{ "name": "react", "version": "1.0.1", "types": "./index.d.ts" } +// @Filename: /packages/a/node_modules/@types/react/index.d.ts +export declare function useState(): void; +// @Filename: /packages/a/index.ts +import "react-dom"; +import "react"; +// @Filename: /packages/a/foo.ts +/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "render", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "react-dom", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "useState", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "react", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go b/internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go new file mode 100644 index 0000000000..7b01bd95e9 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go @@ -0,0 +1,52 @@ +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 TestCompletionsImport_exportEqualsNamespace_noDuplicate(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /node_modules/a/index.d.ts +declare namespace core { + const foo: number; +} +declare module "a" { + export = core; +} +declare module "a/alias" { + export = core; +} +// @Filename: /user.ts +import * as a from "a"; +/**/foo;` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_exportEquals_global_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_global_test.go new file mode 100644 index 0000000000..9f4f618159 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_global_test.go @@ -0,0 +1,50 @@ +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 TestCompletionsImport_exportEquals_global(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: es6 +// @Filename: /console.d.ts + interface Console {} + declare var console: Console; + declare module "console" { + export = console; + } +// @Filename: /react-native.d.ts + import 'console'; + declare global { + interface Console {} + var console: Console; + } +// @Filename: /a.ts +conso/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "console", + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go new file mode 100644 index 0000000000..f3ea0e1041 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go @@ -0,0 +1,73 @@ +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 TestCompletionsImport_filteredByInvalidPackageJson_direct(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@noEmit: true +//@Filename: /package.json +{ + "mod" + "dependencies": { + "react": "*" + } +} +//@Filename: /node_modules/react/index.d.ts +export declare var React: any; +//@Filename: /node_modules/react/package.json +{ + "name": "react", + "types": "./index.d.ts" +} +//@Filename: /node_modules/fake-react/index.d.ts +export declare var ReactFake: any; +//@Filename: /node_modules/fake-react/package.json +{ + "name": "fake-react", + "types": "./index.d.ts" +} +//@Filename: /src/index.ts +const x = Re/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "React", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "ReactFake", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/fake-react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go new file mode 100644 index 0000000000..18d1fd34b0 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go @@ -0,0 +1,63 @@ +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 TestCompletionsImport_filteredByPackageJson_typesImplicit(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@noEmit: true +//@Filename: /package.json +{ + "dependencies": { + "react": "*" + } +} +//@Filename: /node_modules/@types/react/index.d.ts +export declare var React: any; +//@Filename: /node_modules/@types/react/package.json +{ + "name": "@types/react" +} +//@Filename: /node_modules/@types/fake-react/index.d.ts +export declare var ReactFake: any; +//@Filename: /node_modules/@types/fake-react/package.json +{ + "name": "@types/fake-react" +} +//@Filename: /src/index.ts +const x = Re/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "React", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/@types/react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "ReactFake", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go new file mode 100644 index 0000000000..9b6186bb92 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go @@ -0,0 +1,63 @@ +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 TestCompletionsImport_filteredByPackageJson_typesOnly(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@noEmit: true +//@Filename: /package.json +{ + "devDependencies": { + "@types/react": "*" + } +} +//@Filename: /node_modules/@types/react/index.d.ts +export declare var React: any; +//@Filename: /node_modules/@types/react/package.json +{ + "name": "@types/react" +} +//@Filename: /node_modules/@types/fake-react/index.d.ts +export declare var ReactFake: any; +//@Filename: /node_modules/@types/fake-react/package.json +{ + "name": "@types/fake-react" +} +//@Filename: /src/index.ts +const x = Re/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "React", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/@types/react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "ReactFake", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go new file mode 100644 index 0000000000..035f825c1b --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go @@ -0,0 +1,153 @@ +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 TestCompletionsImport_filteredByPackageJson_ambient(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@noEmit: true +//@Filename: /package.json +{ + "dependencies": { + "react-syntax-highlighter": "*", + "declared-by-foo": "*" + } +} +//@Filename: /node_modules/@types/foo/index.d.ts +declare module "foo" { + export const foo: any; +} +declare module "declared-by-foo" { + export const declaredBySomethingNotInPackageJson: any; +} +//@Filename: /node_modules/@types/foo/package.json +{ + "name": "@types/node" +} +//@Filename: /node_modules/@types/react-syntax-highlighter/index.d.ts +declare module "react-syntax-highlighter/sub" { + const agate: any; + export default agate; +} +declare module "something-else" { + export const somethingElse: any; +} +//@Filename: /node_modules/@types/react-syntax-highlighter/package.json +{ + "name": "@types/react-syntax-highlighter" +} +//@Filename: /src/ambient.ts +declare module "local" { + export const local: any'; +} +//@Filename: /src/index.ts +fo/*1*/ +aga/*2*/ +somethi/*3*/ +declaredBy/*4*/ +loca/*5*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobals, + }, + }) + f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "agate", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "react-syntax-highlighter/sub", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "somethingElse", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "something-else", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "declaredBySomethingNotInPackageJson", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "declared-by-foo", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "5", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "local", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "local", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go new file mode 100644 index 0000000000..6dbf39b3fc --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go @@ -0,0 +1,65 @@ +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 TestCompletionsImport_filteredByPackageJson_direct(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@noEmit: true +//@Filename: /package.json +{ + "dependencies": { + "react": "*" + } +} +//@Filename: /node_modules/react/index.d.ts +export declare var React: any; +//@Filename: /node_modules/react/package.json +{ + "name": "react", + "types": "./index.d.ts" +} +//@Filename: /node_modules/fake-react/index.d.ts +export declare var ReactFake: any; +//@Filename: /node_modules/fake-react/package.json +{ + "name": "fake-react", + "types": "./index.d.ts" +} +//@Filename: /src/index.ts +const x = Re/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "React", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "ReactFake", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go new file mode 100644 index 0000000000..a3a786ecae --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go @@ -0,0 +1,89 @@ +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 TestCompletionsImport_filteredByPackageJson_nested(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@noEmit: true +//@Filename: /package.json +{ + "dependencies": { + "react": "*" + } +} +//@Filename: /node_modules/react/index.d.ts +export declare var React: any; +//@Filename: /node_modules/react/package.json +{ + "name": "react", + "types": "./index.d.ts" +} +//@Filename: /dir/package.json +{ + "dependencies": { + "redux": "*" + } +} +//@Filename: /dir/node_modules/redux/package.json +{ + "name": "redux", + "types": "./index.d.ts" +} +//@Filename: /dir/node_modules/redux/index.d.ts +export declare var Redux: any; +//@Filename: /dir/index.ts +const x = Re/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "React", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Redux", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/dir/node_modules/redux/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go new file mode 100644 index 0000000000..da4da91923 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go @@ -0,0 +1,65 @@ +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 TestCompletionsImport_filteredByPackageJson_peerDependencies(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@noEmit: true +//@Filename: /package.json +{ + "peerDependencies": { + "react": "*" + } +} +//@Filename: /node_modules/react/index.d.ts +export declare var React: any; +//@Filename: /node_modules/react/package.json +{ + "name": "react", + "types": "./index.d.ts" +} +//@Filename: /node_modules/fake-react/index.d.ts +export declare var ReactFake: any; +//@Filename: /node_modules/fake-react/package.json +{ + "name": "fake-react", + "types": "./index.d.ts" +} +//@Filename: /src/index.ts +const x = Re/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "React", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/react/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "ReactFake", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go b/internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go new file mode 100644 index 0000000000..21f308404e --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go @@ -0,0 +1,85 @@ +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 TestCompletionsImport_mergedReExport(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ "compilerOptions": { "module": "commonjs" } } +// @Filename: /home/src/workspaces/project/package.json +{ "dependencies": { "@jest/types": "*", "ts-jest": "*" } } +// @Filename: /home/src/workspaces/project/node_modules/@jest/types/package.json +{ "name": "@jest/types" } +// @Filename: /home/src/workspaces/project/node_modules/@jest/types/index.d.ts +import type * as Config from "./Config"; +export type { Config }; +// @Filename: /home/src/workspaces/project/node_modules/@jest/types/Config.d.ts +export interface ConfigGlobals { + [K: string]: unknown; +} +// @Filename: /home/src/workspaces/project/node_modules/ts-jest/index.d.ts +export {}; +declare module "@jest/types" { + namespace Config { + interface ConfigGlobals { + 'ts-jest': any; + } + } +} +// @Filename: /home/src/workspaces/project/index.ts +C/**/` + 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: "Config", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/home/src/workspaces/project/node_modules/@jest/types/index", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.Insert(t, "o") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Config", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@jest/types", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go b/internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go new file mode 100644 index 0000000000..626a76378b --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go @@ -0,0 +1,63 @@ +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 TestCompletionsImport_named_didNotExistBefore(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @noLib: true +// @Filename: /a.ts +export function Test1() {} +export function Test2() {} +// @Filename: /b.ts +import { Test2 } from "./a"; +t/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Test2", + Detail: PtrTo("(alias) function Test2(): void\nimport Test2"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + }, + &lsproto.CompletionItem{ + Label: "Test1", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("function Test1(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + LabelDetails: &lsproto.CompletionItemLabelDetails{ + Description: PtrTo("/a"), + }, + }, + }, true), + }, + }).AndApplyCodeAction(t, &fourslash.CompletionsExpectedCodeAction{ + Name: "Test1", + Source: "/a", + Description: "Update import from \"./a\"", + NewFileContent: `import { Test1, Test2 } from "./a"; +t`, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go b/internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go new file mode 100644 index 0000000000..dac8721bd1 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go @@ -0,0 +1,53 @@ +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 TestCompletionsImport_named_exportEqualsNamespace_merged(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @Filename: /b.d.ts +declare namespace N { + export const foo: number; +} +declare module "n" { + export = N; +} +// @Filename: /c.d.ts +declare namespace N {} +// @Filename: /a.ts +fo/**/` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "n", + }, + })), + Detail: PtrTo("const N.foo: number"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_packageJsonImportsPreference_test.go b/internal/fourslash/tests/gen/completionsImport_packageJsonImportsPreference_test.go new file mode 100644 index 0000000000..9fa94c1dec --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_packageJsonImportsPreference_test.go @@ -0,0 +1,77 @@ +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 TestCompletionsImport_packageJsonImportsPreference(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: preserve +// @allowImportingTsExtensions: true +// @Filename: /project/package.json +{ + "name": "project", + "version": "1.0.0", + "imports": { + "#internal/*": "./src/internal/*.ts" + } +} +// @Filename: /project/src/internal/foo.ts +export const internalFoo = 0; +// @Filename: /project/src/other.ts +export * from "./internal/foo.ts"; +// @Filename: /project/src/main.ts +internalFoo/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "internalFoo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "#internal/foo", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "internalFoo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./other", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_preferUpdatingExistingImport_test.go b/internal/fourslash/tests/gen/completionsImport_preferUpdatingExistingImport_test.go new file mode 100644 index 0000000000..84f8381031 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_preferUpdatingExistingImport_test.go @@ -0,0 +1,52 @@ +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 TestCompletionsImport_preferUpdatingExistingImport(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: /deep/module/why/you/want/this/path.ts +export const x = 0; +export const y = 1; +// @Filename: /nice/reexport.ts +import { x, y } from "../deep/module/why/you/want/this/path"; +export { x, y }; +// @Filename: /index.ts +import { x } from "./deep/module/why/you/want/this/path"; + +y/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + "x", + &lsproto.CompletionItem{ + Label: "y", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./deep/module/why/you/want/this/path", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + AdditionalTextEdits: fourslash.AnyTextEdits, + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go b/internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go new file mode 100644 index 0000000000..642bb6d180 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go @@ -0,0 +1,46 @@ +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 TestCompletionsImport_previousTokenIsSemicolon(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export function foo() {} +// @Filename: /b.ts +import * as a from 'a'; +/**/` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("function foo(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_reExportDefault2_test.go b/internal/fourslash/tests/gen/completionsImport_reExportDefault2_test.go new file mode 100644 index 0000000000..4809f996c2 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_reExportDefault2_test.go @@ -0,0 +1,56 @@ +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 TestCompletionsImport_reExportDefault2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: preserve +// @checkJs: true +// @Filename: /node_modules/example/package.json +{ "name": "example", "version": "1.0.0", "main": "dist/index.js" } +// @Filename: /node_modules/example/dist/nested/module.d.ts +declare const defaultExport: () => void; +declare const namedExport: () => void; + +export default defaultExport; +export { namedExport }; +// @Filename: /node_modules/example/dist/index.d.ts +export { default, namedExport } from "./nested/module"; +// @Filename: /index.mjs +import { namedExport } from "example"; +defaultExp/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsInJSPlus( + []fourslash.CompletionsExpectedItem{ + "namedExport", + &lsproto.CompletionItem{ + Label: "defaultExport", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "example", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_reexportTransient_test.go b/internal/fourslash/tests/gen/completionsImport_reexportTransient_test.go new file mode 100644 index 0000000000..14e7c532c9 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_reexportTransient_test.go @@ -0,0 +1,51 @@ +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 TestCompletionsImport_reexportTransient(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @esModuleInterop: true +// @Filename: /transient.d.ts +declare const map: { [K in "one"]: number }; +export = map; +// @Filename: /r1.ts +export { one } from "./transient"; +// @Filename: /r2.ts +export { one } from "./r1"; +// @Filename: /index.ts +one/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "one", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./transient", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go b/internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go new file mode 100644 index 0000000000..6bd3aafdba --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go @@ -0,0 +1,74 @@ +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 TestCompletionsImport_sortingModuleSpecifiers(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: tsconfig.json +{ "compilerOptions": { "module": "commonjs" } } +// @Filename: path.d.ts +declare module "path/posix" { + export function normalize(p: string): string; +} +declare module "path/win32" { + export function normalize(p: string): string; +} +declare module "path" { + export function normalize(p: string): string; +} +// @Filename: main.ts +normalize/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "normalize", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "path", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "normalize", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "path/posix", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "normalize", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "path/win32", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_tsx_test.go b/internal/fourslash/tests/gen/completionsImport_tsx_test.go new file mode 100644 index 0000000000..bd6b5d4314 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_tsx_test.go @@ -0,0 +1,49 @@ +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 TestCompletionsImport_tsx(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @noLib: true +// @jsx: preserve +// @Filename: /a.tsx +export type Bar = 0; +export default function Foo() {}; +// @Filename: /b.tsx +;` + 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: "Foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "Bar", + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go b/internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go new file mode 100644 index 0000000000..375a34239c --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go @@ -0,0 +1,70 @@ +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 TestCompletionsImport_umdDefaultNoCrash1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: node +// @allowJs: true +// @checkJs: true +// @Filename: /node_modules/dottie/package.json +{ + "name": "dottie", + "main": "dottie.js" +} +// @Filename: /node_modules/dottie/dottie.js +(function (undefined) { + var root = this; + + var Dottie = function () {}; + + Dottie["default"] = function (object, path, value) {}; + + if (typeof module !== "undefined" && module.exports) { + exports = module.exports = Dottie; + } else { + root["Dottie"] = Dottie; + root["Dot"] = Dottie; + + if (typeof define === "function") { + define([], function () { + return Dottie; + }); + } + } +})(); +// @Filename: /src/index.js +/**/` + 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: "Dottie", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/dottie/dottie", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_umdModules1_globalAccess_test.go b/internal/fourslash/tests/gen/completionsImport_umdModules1_globalAccess_test.go new file mode 100644 index 0000000000..331af0b944 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_umdModules1_globalAccess_test.go @@ -0,0 +1,49 @@ +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 TestCompletionsImport_umdModules1_globalAccess(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: /package.json +{ "dependencies": { "@types/classnames": "*" } } +// @filename: /tsconfig.json +{ "compilerOptions": { "allowUmdGlobalAccess": true } } +// @filename: /node_modules/@types/classnames/package.json +{ "name": "@types/classnames", "types": "index.d.ts" } +// @filename: /node_modules/@types/classnames/index.d.ts +declare const classNames: () => string; +export = classNames; +export as namespace classNames; +// @filename: /SomeReactComponent.tsx +import * as React from 'react'; + +const el1 =
foo
;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "1") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "classNames", + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go b/internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go new file mode 100644 index 0000000000..ccd2b5d1ee --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go @@ -0,0 +1,54 @@ +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 TestCompletionsImport_umdModules2_moduleExports(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: /package.json +{ "dependencies": { "@types/classnames": "*" } } +// @filename: /tsconfig.json +{} +// @filename: /node_modules/@types/classnames/package.json +{ "name": "@types/classnames", "types": "index.d.ts" } +// @filename: /node_modules/@types/classnames/index.d.ts +declare const classNames: () => string; +export = classNames; +export as namespace classNames; +// @filename: /SomeReactComponent.tsx +import * as React from 'react'; + +const el1 =
foo
;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "1") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "classNames", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/@types/classnames/index", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_umdModules3_script_test.go b/internal/fourslash/tests/gen/completionsImport_umdModules3_script_test.go new file mode 100644 index 0000000000..f3781b3757 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_umdModules3_script_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 TestCompletionsImport_umdModules3_script(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: /package.json +{ "dependencies": { "@types/classnames": "*" } } +// @filename: /tsconfig.json +{ "compilerOptions": { "module": "es2015" }} +// @filename: /node_modules/@types/classnames/package.json +{ "name": "@types/classnames", "types": "index.d.ts" } +// @filename: /node_modules/@types/classnames/index.d.ts +declare const classNames: () => string; +export = classNames; +export as namespace classNames; +// @filename: /SomeReactComponent.tsx + +const el1 =
foo
` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "1") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "classNames", + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go b/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go new file mode 100644 index 0000000000..bc2bed098e --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go @@ -0,0 +1,78 @@ +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 TestCompletionsImport_uriStyleNodeCoreModules1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: /node_modules/@types/node/index.d.ts +declare module "fs" { function writeFile(): void } +declare module "fs/promises" { function writeFile(): Promise } +declare module "node:fs" { export * from "fs"; } +declare module "node:fs/promises" { export * from "fs/promises"; } +// @Filename: /index.ts +write/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "writeFile", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "fs", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "writeFile", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "node:fs", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "writeFile", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "fs/promises", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "writeFile", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "node:fs/promises", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules2_test.go b/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules2_test.go new file mode 100644 index 0000000000..5c295f65f2 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules2_test.go @@ -0,0 +1,60 @@ +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 TestCompletionsImport_uriStyleNodeCoreModules2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: /node_modules/@types/node/index.d.ts +declare module "fs" { function writeFile(): void } +declare module "fs/promises" { function writeFile(): Promise } +declare module "node:fs" { export * from "fs"; } +declare module "node:fs/promises" { export * from "fs/promises"; } +// @Filename: /other.ts +import "node:fs/promises"; +// @Filename: /index.ts +write/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "writeFile", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "node:fs", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "writeFile", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "node:fs/promises", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_windowsPathsProjectRelative_test.go b/internal/fourslash/tests/gen/completionsImport_windowsPathsProjectRelative_test.go new file mode 100644 index 0000000000..8533cb5bea --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_windowsPathsProjectRelative_test.go @@ -0,0 +1,131 @@ +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 TestCompletionsImport_windowsPathsProjectRelative(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: c:/project/tsconfig.json +{ + "compilerOptions": { + "paths": { + "~/noIndex/*": ["./src/noIndex/*"], + "~/withIndex": ["./src/withIndex/index.ts"] + } + } +} +// @Filename: c:/project/package.json +{} +// @Filename: c:/project/src/noIndex/a.ts +export const myFunctionA = () => {}; +// @Filename: c:/project/src/withIndex/b.ts +export const myFunctionB = () => {}; +// @Filename: c:/project/src/withIndex/index.ts +export * from './b'; +// @Filename: c:/project/src/reproduction/1.ts +myFunction/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "myFunctionA", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "~/noIndex/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "myFunctionB", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "~/withIndex", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "myFunctionA", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "../noIndex/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "myFunctionB", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "../withIndex", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "myFunctionA", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "../noIndex/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "myFunctionB", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "../withIndex", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsRecommended_namespace_test.go b/internal/fourslash/tests/gen/completionsRecommended_namespace_test.go new file mode 100644 index 0000000000..dbe73c56be --- /dev/null +++ b/internal/fourslash/tests/gen/completionsRecommended_namespace_test.go @@ -0,0 +1,92 @@ +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 TestCompletionsRecommended_namespace(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @noLib: true +// @Filename: /a.ts +export namespace Name { + export class C {} +} +export function f(c: Name.C) {} +f(new N/*a0*/); +f(new /*a1*/); +// @Filename: /b.ts +import { f } from "./a"; +f(new N/*b0*/); +f(new /*b1*/); +// @Filename: /c.ts +import * as alpha from "./a"; +alpha.f(new a/*c0*/); +alpha.f(new /*c1*/);` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, []string{"a0", "a1"}, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Name", + Detail: PtrTo("namespace Name"), + Kind: PtrTo(lsproto.CompletionItemKindModule), + Preselect: PtrTo(true), + }, + }, + }, + }) + f.VerifyCompletions(t, []string{"b0", "b1"}, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Name", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("namespace Name"), + Kind: PtrTo(lsproto.CompletionItemKindModule), + AdditionalTextEdits: fourslash.AnyTextEdits, + Preselect: PtrTo(true), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, []string{"c0", "c1"}, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "alpha", + Detail: PtrTo("import alpha"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + Preselect: PtrTo(true), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go b/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go new file mode 100644 index 0000000000..c7c0d62443 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_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/ls" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCompletionsWithDeprecatedTag10(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /foo.ts +/** @deprecated foo */ +export const foo = 0; +// @Filename: /index.ts +/**/` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/foo", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + Kind: PtrTo(lsproto.CompletionItemKindVariable), + SortText: PtrTo(string(ls.DeprecateSortText(ls.SortTextAutoImportSuggestions))), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importSuggestionsCache_exportUndefined_test.go b/internal/fourslash/tests/gen/importSuggestionsCache_exportUndefined_test.go new file mode 100644 index 0000000000..33022ac27d --- /dev/null +++ b/internal/fourslash/tests/gen/importSuggestionsCache_exportUndefined_test.go @@ -0,0 +1,70 @@ +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 TestImportSuggestionsCache_exportUndefined(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ "compilerOptions": { "module": "esnext" } } +// @Filename: /home/src/workspaces/project/undefined.ts +export = undefined; +// @Filename: /home/src/workspaces/project/undefinedAlias.ts +const x = undefined; +export = x; +// @Filename: /home/src/workspaces/project/index.ts + /**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "x", + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/home/src/workspaces/project/undefinedAlias", + }, + })), + }, + }, + }, + }) + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "x", + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/home/src/workspaces/project/undefinedAlias", + }, + })), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go b/internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go new file mode 100644 index 0000000000..539b9d756b --- /dev/null +++ b/internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go @@ -0,0 +1,58 @@ +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 TestImportSuggestionsCache_invalidPackageJson(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/jsconfig.json +{ + "compilerOptions": { + "module": "commonjs", + }, +} +// @Filename: /home/src/workspaces/project/node_modules/@types/node/index.d.ts +declare module 'fs' { + export function readFile(): void; +} +declare module 'util' { + export function promisify(): void; +} +// @Filename: /home/src/workspaces/project/package.json +{ "mod" } +// @Filename: /home/src/workspaces/project/a.js + +readF/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, nil, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "readFile", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "fs", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions1_test.go b/internal/fourslash/tests/gen/importTypeCompletions1_test.go new file mode 100644 index 0000000000..3e586eb516 --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions1_test.go @@ -0,0 +1,50 @@ +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 TestImportTypeCompletions1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: esnext +// @filename: /foo.ts +export interface Foo {} +// @filename: /bar.ts +[|import type F/**/|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/bar.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import type { Foo } from \"./foo\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions3_test.go b/internal/fourslash/tests/gen/importTypeCompletions3_test.go new file mode 100644 index 0000000000..64d207be07 --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions3_test.go @@ -0,0 +1,50 @@ +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 TestImportTypeCompletions3(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: esnext +// @filename: /foo.ts +export interface Foo {} +// @filename: /bar.ts +[|import type { F/**/ }|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/bar.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import type { Foo } from \"./foo\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions4_test.go b/internal/fourslash/tests/gen/importTypeCompletions4_test.go new file mode 100644 index 0000000000..ba2465a5e1 --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions4_test.go @@ -0,0 +1,51 @@ +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 TestImportTypeCompletions4(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @esModuleInterop: true +// @Filename: /foo.ts +interface Foo { }; +export = Foo; +// @Filename: /bar.ts + [|import type f/**/|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/bar.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import type Foo from \"./foo\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions5_test.go b/internal/fourslash/tests/gen/importTypeCompletions5_test.go new file mode 100644 index 0000000000..bfe7daff8d --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions5_test.go @@ -0,0 +1,51 @@ +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 TestImportTypeCompletions5(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @esModuleInterop: false +// @Filename: /foo.ts +interface Foo { }; +export = Foo; +// @Filename: /bar.ts + [|import type f/**/|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/bar.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import type Foo = require(\"./foo\");"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions6_test.go b/internal/fourslash/tests/gen/importTypeCompletions6_test.go new file mode 100644 index 0000000000..49d825be38 --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions6_test.go @@ -0,0 +1,51 @@ +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 TestImportTypeCompletions6(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @Filename: /foo.ts +export const foo = { }; +export interface Foo { }; +// @Filename: /bar.ts + [|import type * as f/**/|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/bar.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import type { Foo } from \"./foo\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions7_test.go b/internal/fourslash/tests/gen/importTypeCompletions7_test.go new file mode 100644 index 0000000000..e927da63ff --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions7_test.go @@ -0,0 +1,56 @@ +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 TestImportTypeCompletions7(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: es2020 +// @module: esnext +// @Filename: /foo.d.ts +declare namespace Foo {} +export = Foo; +// @Filename: /test.ts +[|import F/**/|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/test.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import * as Foo from \"./foo\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + &lsproto.CompletionItem{ + Label: "type", + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions8_test.go b/internal/fourslash/tests/gen/importTypeCompletions8_test.go new file mode 100644 index 0000000000..024b38ff05 --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions8_test.go @@ -0,0 +1,50 @@ +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 TestImportTypeCompletions8(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: esnext +// @filename: /foo.ts +export interface Foo {} +// @filename: /bar.ts +[|import { type F/**/ }|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/bar.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import { type Foo } from \"./foo\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/importTypeCompletions9_test.go b/internal/fourslash/tests/gen/importTypeCompletions9_test.go new file mode 100644 index 0000000000..d6460a2e54 --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions9_test.go @@ -0,0 +1,50 @@ +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 TestImportTypeCompletions9(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @target: esnext +// @filename: /foo.ts +export interface Foo {} +// @filename: /bar.ts +[|import { type /**/ }|]` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/bar.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + InsertText: PtrTo("import { type Foo } from \"./foo\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./foo", + }, + })), + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "Foo", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/jsFileImportNoTypes2_test.go b/internal/fourslash/tests/gen/jsFileImportNoTypes2_test.go new file mode 100644 index 0000000000..84c2d97611 --- /dev/null +++ b/internal/fourslash/tests/gen/jsFileImportNoTypes2_test.go @@ -0,0 +1,84 @@ +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 TestJsFileImportNoTypes2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: /default.ts +export default class TestDefaultClass {} +// @Filename: /defaultType.ts +export default interface TestDefaultInterface {} +// @Filename: /reExport/toReExport.ts +export class TestClassReExport {} +export interface TestInterfaceReExport {} +// @Filename: /reExport/index.ts +export { TestClassReExport, TestInterfaceReExport } from './toReExport'; +// @Filename: /exportList.ts +class TestClassExportList {}; +interface TestInterfaceExportList {}; +export { TestClassExportList, TestInterfaceExportList }; +// @Filename: /baseline.ts +export class TestClassBaseline {} +export interface TestInterfaceBaseline {} +// @Filename: /a.js +import /**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "TestClassBaseline", + InsertText: PtrTo("import { TestClassBaseline } from \"./baseline\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./baseline", + }, + })), + }, + &lsproto.CompletionItem{ + Label: "TestClassExportList", + InsertText: PtrTo("import { TestClassExportList } from \"./exportList\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./exportList", + }, + })), + }, + &lsproto.CompletionItem{ + Label: "TestClassReExport", + InsertText: PtrTo("import { TestClassReExport } from \"./reExport\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./reExport", + }, + })), + }, + &lsproto.CompletionItem{ + Label: "TestDefaultClass", + InsertText: PtrTo("import TestDefaultClass from \"./default\";"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./default", + }, + })), + }, + }, + }, + }) +} diff --git a/internal/ls/completions.go b/internal/ls/completions.go index 95934780dc..5697a74eaf 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -63,7 +63,7 @@ func ensureItemData(fileName string, pos int, list *lsproto.CompletionList) *lsp } for _, item := range list.Items { if item.Data == nil { - var data any = &itemData{ + var data any = &CompletionItemData{ FileName: fileName, Position: pos, Name: item.Label, @@ -246,7 +246,7 @@ func (origin *symbolOriginInfo) moduleSymbol() *ast.Symbol { } } -func (origin *symbolOriginInfo) toCompletionEntryData() *completionEntryData { +func (origin *symbolOriginInfo) toCompletionEntryData() *AutoImportData { debug.Assert(origin.kind&symbolOriginInfoKindExport != 0, fmt.Sprintf("completionEntryData is not generated for symbolOriginInfo of type %T", origin.data)) var ambientModuleName *string if origin.fileName == "" { @@ -258,7 +258,7 @@ func (origin *symbolOriginInfo) toCompletionEntryData() *completionEntryData { } data := origin.data.(*symbolOriginInfoExport) - return &completionEntryData{ + return &AutoImportData{ ExportName: data.exportName, ExportMapKey: data.exportMapKey, ModuleSpecifier: data.moduleSpecifier, @@ -2294,7 +2294,7 @@ func (l *LanguageService) createCompletionItem( } } - var autoImportData *completionEntryData + var autoImportData *AutoImportData if originIsExport(origin) { autoImportData = origin.toCompletionEntryData() hasAction = data.importStatementCompletion == nil @@ -3300,8 +3300,8 @@ func compareCompletionEntries(entryInSlice *lsproto.CompletionItem, entryToInser result = compareStrings(entryInSlice.Label, entryToInsert.Label) } if result == stringutil.ComparisonEqual && entryInSlice.Data != nil && entryToInsert.Data != nil { - sliceEntryData, ok1 := (*entryInSlice.Data).(*completionEntryData) - insertEntryData, ok2 := (*entryToInsert.Data).(*completionEntryData) + sliceEntryData, ok1 := (*entryInSlice.Data).(*AutoImportData) + insertEntryData, ok2 := (*entryToInsert.Data).(*AutoImportData) if ok1 && ok2 && sliceEntryData.ModuleSpecifier != "" && insertEntryData.ModuleSpecifier != "" { // Sort same-named auto-imports by module specifier result = compareNumberOfDirectorySeparators( @@ -4514,10 +4514,10 @@ func (l *LanguageService) createLSPCompletionItem( hasAction bool, preselect bool, source string, - autoImportEntryData *completionEntryData, + autoImportEntryData *AutoImportData, ) *lsproto.CompletionItem { kind := getCompletionsSymbolKind(elementKind) - var data any = &itemData{ + var data any = &CompletionItemData{ FileName: file.FileName(), Position: position, Source: source, @@ -4949,15 +4949,15 @@ func getArgumentInfoForCompletions(node *ast.Node, position int, file *ast.Sourc } } -type itemData struct { - FileName string `json:"fileName"` - Position int `json:"position"` - Source string `json:"source,omitempty"` - Name string `json:"name,omitempty"` - AutoImport *completionEntryData `json:"autoImport,omitempty"` +type CompletionItemData struct { + FileName string `json:"fileName"` + Position int `json:"position"` + Source string `json:"source,omitempty"` + Name string `json:"name,omitempty"` + AutoImport *AutoImportData `json:"autoImport,omitempty"` } -type completionEntryData struct { +type AutoImportData struct { /** * The name of the property or export in the module's symbol table. Differs from the completion name * in the case of InternalSymbolName.ExportEquals and InternalSymbolName.Default. @@ -4975,7 +4975,7 @@ type completionEntryData struct { IsPackageJsonImport core.Tristate `json:"isPackageJsonImport"` } -func (d *completionEntryData) toSymbolOriginExport(symbolName string, moduleSymbol *ast.Symbol, isDefaultExport bool) *symbolOriginInfoExport { +func (d *AutoImportData) toSymbolOriginExport(symbolName string, moduleSymbol *ast.Symbol, isDefaultExport bool) *symbolOriginInfoExport { return &symbolOriginInfoExport{ symbolName: symbolName, moduleSymbol: moduleSymbol, @@ -5012,7 +5012,7 @@ const ( func (l *LanguageService) ResolveCompletionItem( ctx context.Context, item *lsproto.CompletionItem, - data *itemData, + data *CompletionItemData, clientOptions *lsproto.CompletionClientCapabilities, preferences *UserPreferences, ) (*lsproto.CompletionItem, error) { @@ -5028,12 +5028,12 @@ func (l *LanguageService) ResolveCompletionItem( return l.getCompletionItemDetails(ctx, program, data.Position, file, item, data, clientOptions, preferences), nil } -func GetCompletionItemData(item *lsproto.CompletionItem) (*itemData, error) { +func GetCompletionItemData(item *lsproto.CompletionItem) (*CompletionItemData, error) { bytes, err := json.Marshal(item.Data) if err != nil { return nil, fmt.Errorf("failed to marshal completion item data: %w", err) } - var itemData itemData + var itemData CompletionItemData if err := json.Unmarshal(bytes, &itemData); err != nil { return nil, fmt.Errorf("failed to unmarshal completion item data: %w", err) } @@ -5046,7 +5046,7 @@ func (l *LanguageService) getCompletionItemDetails( position int, file *ast.SourceFile, item *lsproto.CompletionItem, - itemData *itemData, + itemData *CompletionItemData, clientOptions *lsproto.CompletionClientCapabilities, preferences *UserPreferences, ) *lsproto.CompletionItem { @@ -5145,7 +5145,7 @@ func (l *LanguageService) getSymbolCompletionFromItemData( ch *checker.Checker, file *ast.SourceFile, position int, - itemData *itemData, + itemData *CompletionItemData, clientOptions *lsproto.CompletionClientCapabilities, preferences *UserPreferences, ) detailsData { @@ -5219,7 +5219,7 @@ func (l *LanguageService) getSymbolCompletionFromItemData( return detailsData{} } -func (l *LanguageService) getAutoImportSymbolFromCompletionEntryData(ch *checker.Checker, name string, autoImportData *completionEntryData) *symbolDetails { +func (l *LanguageService) getAutoImportSymbolFromCompletionEntryData(ch *checker.Checker, name string, autoImportData *AutoImportData) *symbolDetails { containingProgram := l.GetProgram() // !!! isPackageJson ? packageJsonAutoimportProvider : program var moduleSymbol *ast.Symbol if autoImportData.AmbientModuleName != nil { @@ -5318,7 +5318,7 @@ func createCompletionDetailsForSymbol( } // !!! snippets -func (l *LanguageService) getCompletionItemActions(ctx context.Context, ch *checker.Checker, file *ast.SourceFile, position int, itemData *itemData, symbolDetails *symbolDetails, preferences *UserPreferences) []codeAction { +func (l *LanguageService) getCompletionItemActions(ctx context.Context, ch *checker.Checker, file *ast.SourceFile, position int, itemData *CompletionItemData, symbolDetails *symbolDetails, preferences *UserPreferences) []codeAction { if itemData.AutoImport != nil && itemData.AutoImport.ModuleSpecifier != "" && symbolDetails.previousToken != nil { // Import statement completion: 'import c|' if symbolDetails.contextToken != nil && l.getImportStatementCompletionInfo(symbolDetails.contextToken, file).replacementSpan != nil { From 432574cc9d1bd97e50c3ed5c7b7deb10e49b91ef Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 20 Oct 2025 08:55:05 -0700 Subject: [PATCH 02/17] Add support for applyCodeActionFromCompletion --- .../fourslash/_scripts/convertFourslash.mts | 174 ++++++++++++++++++ internal/fourslash/_scripts/failingTests.txt | 49 +++++ internal/fourslash/fourslash.go | 80 ++++++-- ...portCompletionAmbientMergedModule1_test.go | 78 ++++++++ ...CompletionExportEqualsWithDefault1_test.go | 102 ++++++++++ ...tCompletionExportListAugmentation1_test.go | 70 +++++++ ...tCompletionExportListAugmentation2_test.go | 80 ++++++++ ...tCompletionExportListAugmentation3_test.go | 69 +++++++ ...tCompletionExportListAugmentation4_test.go | 78 ++++++++ ...utoImportReExportFromAmbientModule_test.go | 76 ++++++++ .../autoImportSortCaseSensitivity2_test.go | 56 ++++++ .../gen/autoImportVerbatimTypeOnly1_test.go | 52 ++++++ .../gen/completionsImportFromJSXTag_test.go | 45 +++++ ...ionsImportModuleAugmentationWithJS_test.go | 47 +++++ .../completionsImportPathsConflict_test.go | 68 +++++++ .../completionsImportYieldExpression_test.go | 32 ++++ .../tests/gen/completionsImport_46332_test.go | 101 ++++++++++ .../gen/completionsImport_ambient_test.go | 76 ++++++++ ...ionsImport_defaultAndNamedConflict_test.go | 72 ++++++++ ...letionsImport_defaultFalsePositive_test.go | 58 ++++++ ...nsImport_default_addToNamedImports_test.go | 54 ++++++ ...mport_default_addToNamespaceImport_test.go | 53 ++++++ ...t_default_alreadyExistedWithRename_test.go | 54 ++++++ ...ompletionsImport_default_anonymous_test.go | 69 +++++++ ...nsImport_default_didNotExistBefore_test.go | 54 ++++++ ...rt_default_exportDefaultIdentifier_test.go | 56 ++++++ ...ort_default_fromMergedDeclarations_test.go | 60 ++++++ ...mpletionsImport_default_symbolName_test.go | 60 ++++++ ...sImport_details_withMisspelledName_test.go | 45 +++++ ...tionsImport_exportEquals_anonymous_test.go | 69 +++++++ .../completionsImport_exportEquals_test.go | 89 +++++++++ ...ompletionsImport_fromAmbientModule_test.go | 31 ++++ .../gen/completionsImport_importType_test.go | 83 +++++++++ ...sImport_jsxOpeningTagImportDefault_test.go | 61 ++++++ ...letionsImport_multipleWithSameName_test.go | 79 ++++++++ ...ionsImport_named_addToNamedImports_test.go | 54 ++++++ ...Import_named_exportEqualsNamespace_test.go | 57 ++++++ ...mport_named_fromMergedDeclarations_test.go | 60 ++++++ ...Import_named_namespaceImportExists_test.go | 53 ++++++ .../completionsImport_noSemicolons_test.go | 32 ++++ ...ionsImport_ofAlias_preferShortPath_test.go | 59 ++++++ .../gen/completionsImport_quoteStyle_test.go | 30 +++ .../completionsImport_reExportDefault_test.go | 58 ++++++ ...mpletionsImport_reExport_wrongName_test.go | 76 ++++++++ .../completionsImport_require_addNew_test.go | 54 ++++++ ...etionsImport_require_addToExisting_test.go | 57 ++++++ .../gen/completionsImport_require_test.go | 55 ++++++ .../gen/completionsImport_typeOnly_test.go | 31 ++++ ...etionsImport_weirdDefaultSynthesis_test.go | 31 ++++ .../completionsUniqueSymbol_import_test.go | 70 +++++++ .../importNameCodeFixDefaultExport6_test.go | 28 +++ .../importNameCodeFixExportAsDefault_test.go | 29 +++ .../gen/jsxTagNameCompletionClosed_test.go | 145 +++++++++++++++ .../gen/jsxTagNameCompletionUnclosed_test.go | 145 +++++++++++++++ ...agNameCompletionUnderElementClosed_test.go | 84 +++++++++ ...NameCompletionUnderElementUnclosed_test.go | 84 +++++++++ 56 files changed, 3661 insertions(+), 11 deletions(-) create mode 100644 internal/fourslash/tests/gen/autoImportCompletionAmbientMergedModule1_test.go create mode 100644 internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go create mode 100644 internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation1_test.go create mode 100644 internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation2_test.go create mode 100644 internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation3_test.go create mode 100644 internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation4_test.go create mode 100644 internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go create mode 100644 internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go create mode 100644 internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go create mode 100644 internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go create mode 100644 internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go create mode 100644 internal/fourslash/tests/gen/completionsImportPathsConflict_test.go create mode 100644 internal/fourslash/tests/gen/completionsImportYieldExpression_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_46332_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_ambient_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_anonymous_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_didNotExistBefore_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_exportDefaultIdentifier_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_exportEquals_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_fromAmbientModule_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_importType_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_multipleWithSameName_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_named_fromMergedDeclarations_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_named_namespaceImportExists_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_noSemicolons_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_ofAlias_preferShortPath_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_quoteStyle_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_reExportDefault_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_reExport_wrongName_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_require_addNew_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_require_addToExisting_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_require_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_typeOnly_test.go create mode 100644 internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go create mode 100644 internal/fourslash/tests/gen/completionsUniqueSymbol_import_test.go create mode 100644 internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go create mode 100644 internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go create mode 100644 internal/fourslash/tests/gen/jsxTagNameCompletionClosed_test.go create mode 100644 internal/fourslash/tests/gen/jsxTagNameCompletionUnclosed_test.go create mode 100644 internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementClosed_test.go create mode 100644 internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementUnclosed_test.go diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 40e63d7075..94001caab2 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -172,6 +172,9 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined { case "completions": // `verify.completions(...)` return parseVerifyCompletionsArgs(callExpression.arguments); + case "applyCodeActionFromCompletion": + // `verify.applyCodeActionFromCompletion(...)` + return parseVerifyApplyCodeActionFromCompletionArgs(callExpression.arguments); case "quickInfoAt": case "quickInfoExists": case "quickInfoIs": @@ -388,6 +391,154 @@ function parseVerifyCompletionsArgs(args: readonly ts.Expression[], codeActionAr return cmds; } +function parseVerifyApplyCodeActionFromCompletionArgs(args: readonly ts.Expression[]): VerifyApplyCodeActionFromCompletionCmd[] | undefined { + const cmds: VerifyApplyCodeActionFromCompletionCmd[] = []; + if (args.length !== 2) { + console.error(`Expected two arguments in verify.applyCodeActionFromCompletion, got ${args.map(arg => arg.getText()).join(", ")}`); + return undefined; + } + if (!ts.isStringLiteralLike(args[0]) && args[0].getText() !== "undefined") { + console.error(`Expected string literal or "undefined" in verify.applyCodeActionFromCompletion, got ${args[0].getText()}`); + return undefined; + } + const markerName = getStringLiteralLike(args[0])?.text; + const marker = markerName === undefined ? "nil" : `PtrTo(${getGoStringLiteral(markerName)})`; + const options = parseVerifyApplyCodeActionArgs(args[1]); + if (options === undefined) { + return undefined; + } + + cmds.push({ kind: "verifyApplyCodeActionFromCompletion", marker, options }); + return cmds; +} + +function parseVerifyApplyCodeActionArgs(arg: ts.Expression): string | undefined { + const obj = getObjectLiteralExpression(arg); + if (!obj) { + console.error(`Expected object literal for verify.applyCodeActionFromCompletion options, got ${arg.getText()}`); + return undefined; + } + let nameInit, sourceInit, descInit, dataInit; + const props: string[] = []; + for (const prop of obj.properties) { + if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) { + if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === "preferences") { + continue; // !!! parse once preferences are supported in fourslash + } + console.error(`Expected property assignment with identifier name in verify.applyCodeActionFromCompletion options, got ${prop.getText()}`); + return undefined; + } + const propName = prop.name.text; + const init = prop.initializer; + switch (propName) { + case "name": + nameInit = getStringLiteralLike(init); + if (!nameInit) { + console.error(`Expected string literal for name in verify.applyCodeActionFromCompletion options, got ${init.getText()}`); + return undefined; + } + props.push(`Name: ${getGoStringLiteral(nameInit.text)},`); + break; + case "source": + sourceInit = getStringLiteralLike(init); + if (!sourceInit) { + console.error(`Expected string literal for source in verify.applyCodeActionFromCompletion options, got ${init.getText()}`); + return undefined; + } + props.push(`Source: ${getGoStringLiteral(sourceInit.text)},`); + break; + case "data": + dataInit = getObjectLiteralExpression(init); + if (!dataInit) { + console.error(`Expected object literal for data in verify.applyCodeActionFromCompletion options, got ${init.getText()}`); + return undefined; + } + const dataProps: string[] = []; + for (const dataProp of dataInit.properties) { + if (!ts.isPropertyAssignment(dataProp) || !ts.isIdentifier(dataProp.name)) { + console.error(`Expected property assignment with identifier name in verify.applyCodeActionFromCompletion data, got ${dataProp.getText()}`); + return undefined; + } + const dataPropName = dataProp.name.text; + switch (dataPropName) { + case "moduleSpecifier": + const moduleSpecifierInit = getStringLiteralLike(dataProp.initializer); + if (!moduleSpecifierInit) { + console.error(`Expected string literal for moduleSpecifier in verify.applyCodeActionFromCompletion data, got ${dataProp.initializer.getText()}`); + return undefined; + } + dataProps.push(`ModuleSpecifier: ${getGoStringLiteral(moduleSpecifierInit.text)},`); + break; + case "exportName": + const exportNameInit = getStringLiteralLike(dataProp.initializer); + if (!exportNameInit) { + console.error(`Expected string literal for exportName in verify.applyCodeActionFromCompletion data, got ${dataProp.initializer.getText()}`); + return undefined; + } + dataProps.push(`ExportName: ${getGoStringLiteral(exportNameInit.text)},`); + break; + case "fileName": + const fileNameInit = getStringLiteralLike(dataProp.initializer); + if (!fileNameInit) { + console.error(`Expected string literal for fileName in verify.applyCodeActionFromCompletion data, got ${dataProp.initializer.getText()}`); + return undefined; + } + dataProps.push(`FileName: PtrTo(${getGoStringLiteral(fileNameInit.text)}),`); + break; + default: + console.error(`Unrecognized property in verify.applyCodeActionFromCompletion data: ${dataProp.getText()}`); + return undefined; + } + } + props.push(`AutoImportData: &ls.AutoImportData{\n${dataProps.join("\n")}\n},`); + break; + case "description": + descInit = getStringLiteralLike(init); + if (!descInit) { + console.error(`Expected string literal for description in verify.applyCodeActionFromCompletion options, got ${init.getText()}`); + return undefined; + } + props.push(`Description: ${getGoStringLiteral(descInit.text)},`); + break; + case "newFileContent": + const newFileContentInit = getStringLiteralLike(init); + if (!newFileContentInit) { + console.error(`Expected string literal for newFileContent in verify.applyCodeActionFromCompletion options, got ${init.getText()}`); + return undefined; + } + props.push(`NewFileContent: PtrTo(${getGoMultiLineStringLiteral(newFileContentInit.text)}),`); + break; + case "newRangeContent": + const newRangeContentInit = getStringLiteralLike(init); + if (!newRangeContentInit) { + console.error(`Expected string literal for newRangeContent in verify.applyCodeActionFromCompletion options, got ${init.getText()}`); + return undefined; + } + props.push(`NewRangeContent: PtrTo(${getGoMultiLineStringLiteral(newRangeContentInit.text)}),`); + break; + case "preferences": + // Few if any tests use non-default preferences + break; + default: + console.error(`Unrecognized property in verify.applyCodeActionFromCompletion options: ${prop.getText()}`); + return undefined; + } + } + if (!nameInit) { + console.error(`Expected name property in verify.applyCodeActionFromCompletion options`); + return undefined; + } + if (!sourceInit && !dataInit) { + console.error(`Expected source property in verify.applyCodeActionFromCompletion options`); + return undefined; + } + if (!descInit) { + console.error(`Expected description property in verify.applyCodeActionFromCompletion options`); + return undefined; + } + return `&fourslash.ApplyCodeActionFromCompletionOptions{\n${props.join("\n")}\n}`; +} + const completionConstants = new Map([ ["completion.globals", "CompletionGlobals"], ["completion.globalTypes", "CompletionGlobalTypes"], @@ -422,6 +573,9 @@ function parseVerifyCompletionArg(arg: ts.Expression, codeActionArgs?: VerifyApp let isNewIdentifierLocation: true | undefined; for (const prop of obj.properties) { if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) { + if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === "preferences") { + continue; // !!! parse once preferences are supported in fourslash + } console.error(`Expected property assignment with identifier name, got ${prop.getText()}`); return undefined; } @@ -732,6 +886,13 @@ function parseExpectedCompletionItem(expr: ts.Expression, codeActionArgs?: Verif break; } if (sourceInit = getStringLiteralLike(init)) { + if (propName === "source" && sourceInit.text.endsWith("/")) { + // source: "ClassMemberSnippet/" + itemProps.push(`Data: PtrTo(any(&ls.CompletionItemData{ + Source: ${getGoStringLiteral(sourceInit.text)}, + })),`); + break; + } itemProps.push(`Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ ModuleSpecifier: ${getGoStringLiteral(sourceInit.text)}, @@ -1398,6 +1559,12 @@ interface VerifyApplyCodeActionArgs { newFileContent: string; } +interface VerifyApplyCodeActionFromCompletionCmd { + kind: "verifyApplyCodeActionFromCompletion"; + marker: string; + options: string; +} + interface VerifyBaselineFindAllReferencesCmd { kind: "verifyBaselineFindAllReferences"; markers: string[]; @@ -1462,6 +1629,7 @@ interface VerifyRenameInfoCmd { type Cmd = | VerifyCompletionsCmd + | VerifyApplyCodeActionFromCompletionCmd | VerifyBaselineFindAllReferencesCmd | VerifyBaselineDocumentHighlightsCmd | VerifyBaselineGoToDefinitionCmd @@ -1510,6 +1678,10 @@ function generateVerifyCompletions({ marker, args, isNewIdentifierLocation, andA return call; } +function generateVerifyApplyCodeActionFromCompletion({ marker, options }: VerifyApplyCodeActionFromCompletionCmd): string { + return `f.VerifyApplyCodeActionFromCompletion(t, ${marker}, ${options})`; +} + function generateBaselineFindAllReferences({ markers, ranges }: VerifyBaselineFindAllReferencesCmd): string { if (ranges || markers.length === 0) { return `f.VerifyBaselineFindAllReferences(t)`; @@ -1568,6 +1740,8 @@ function generateCmd(cmd: Cmd): string { switch (cmd.kind) { case "verifyCompletions": return generateVerifyCompletions(cmd); + case "verifyApplyCodeActionFromCompletion": + return generateVerifyApplyCodeActionFromCompletion(cmd); case "verifyBaselineFindAllReferences": return generateBaselineFindAllReferences(cmd); case "verifyBaselineDocumentHighlights": diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 83ff7cb4ad..e7c89872cd 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -3,6 +3,12 @@ TestAmbientShorthandGotoDefinition TestArgumentsAreAvailableAfterEditsAtEndOfFunction TestAugmentedTypesClass1 TestAugmentedTypesClass3Fourslash +TestAutoImportCompletionAmbientMergedModule1 +TestAutoImportCompletionExportEqualsWithDefault1 +TestAutoImportCompletionExportListAugmentation1 +TestAutoImportCompletionExportListAugmentation2 +TestAutoImportCompletionExportListAugmentation3 +TestAutoImportCompletionExportListAugmentation4 TestAutoImportFileExcludePatterns3 TestAutoImportPathsAliasesAndBarrels TestAutoImportProvider6 @@ -20,7 +26,10 @@ TestAutoImportProvider_namespaceSameNameAsIntrinsic TestAutoImportProvider_wildcardExports1 TestAutoImportProvider_wildcardExports2 TestAutoImportProvider_wildcardExports3 +TestAutoImportReExportFromAmbientModule +TestAutoImportSortCaseSensitivity2 TestAutoImportTypeOnlyPreferred1 +TestAutoImportVerbatimTypeOnly1 TestBestCommonTypeObjectLiterals TestBestCommonTypeObjectLiterals1 TestCodeCompletionEscaping @@ -147,15 +156,34 @@ TestCompletionsExportImport TestCompletionsGenericTypeWithMultipleBases1 TestCompletionsImportBaseUrl TestCompletionsImportDefaultExportCrash2 +TestCompletionsImportFromJSXTag +TestCompletionsImportModuleAugmentationWithJS TestCompletionsImportOrExportSpecifier +TestCompletionsImportPathsConflict TestCompletionsImportTypeKeyword +TestCompletionsImportYieldExpression +TestCompletionsImport_46332 +TestCompletionsImport_ambient TestCompletionsImport_augmentation TestCompletionsImport_compilerOptionsModule +TestCompletionsImport_defaultAndNamedConflict +TestCompletionsImport_defaultFalsePositive +TestCompletionsImport_default_addToNamedImports +TestCompletionsImport_default_addToNamespaceImport +TestCompletionsImport_default_alreadyExistedWithRename +TestCompletionsImport_default_anonymous +TestCompletionsImport_default_didNotExistBefore +TestCompletionsImport_default_exportDefaultIdentifier +TestCompletionsImport_default_fromMergedDeclarations +TestCompletionsImport_default_symbolName +TestCompletionsImport_details_withMisspelledName TestCompletionsImport_duplicatePackages_scoped TestCompletionsImport_duplicatePackages_scopedTypes TestCompletionsImport_duplicatePackages_scopedTypesAndNotTypes TestCompletionsImport_duplicatePackages_types +TestCompletionsImport_exportEquals TestCompletionsImport_exportEqualsNamespace_noDuplicate +TestCompletionsImport_exportEquals_anonymous TestCompletionsImport_exportEquals_global TestCompletionsImport_filteredByInvalidPackageJson_direct TestCompletionsImport_filteredByPackageJson_ambient @@ -164,18 +192,36 @@ TestCompletionsImport_filteredByPackageJson_nested TestCompletionsImport_filteredByPackageJson_peerDependencies TestCompletionsImport_filteredByPackageJson_typesImplicit TestCompletionsImport_filteredByPackageJson_typesOnly +TestCompletionsImport_fromAmbientModule +TestCompletionsImport_importType +TestCompletionsImport_jsxOpeningTagImportDefault TestCompletionsImport_mergedReExport +TestCompletionsImport_multipleWithSameName +TestCompletionsImport_named_addToNamedImports TestCompletionsImport_named_didNotExistBefore +TestCompletionsImport_named_exportEqualsNamespace TestCompletionsImport_named_exportEqualsNamespace_merged +TestCompletionsImport_named_fromMergedDeclarations +TestCompletionsImport_named_namespaceImportExists +TestCompletionsImport_noSemicolons +TestCompletionsImport_ofAlias_preferShortPath TestCompletionsImport_packageJsonImportsPreference TestCompletionsImport_previousTokenIsSemicolon +TestCompletionsImport_quoteStyle +TestCompletionsImport_reExportDefault TestCompletionsImport_reExportDefault2 +TestCompletionsImport_reExport_wrongName +TestCompletionsImport_require +TestCompletionsImport_require_addNew +TestCompletionsImport_require_addToExisting TestCompletionsImport_sortingModuleSpecifiers TestCompletionsImport_tsx +TestCompletionsImport_typeOnly TestCompletionsImport_umdDefaultNoCrash1 TestCompletionsImport_umdModules2_moduleExports TestCompletionsImport_uriStyleNodeCoreModules1 TestCompletionsImport_uriStyleNodeCoreModules2 +TestCompletionsImport_weirdDefaultSynthesis TestCompletionsImport_windowsPathsProjectRelative TestCompletionsInExport TestCompletionsInExport_moduleBlock @@ -216,6 +262,7 @@ TestCompletionsSymbolMembers TestCompletionsTriggerCharacter TestCompletionsTuple TestCompletionsUniqueSymbol1 +TestCompletionsUniqueSymbol_import TestCompletionsWithDeprecatedTag10 TestConstEnumQuickInfoAndCompletionList TestConstQuickInfoAndCompletionList @@ -273,6 +320,8 @@ TestImportCompletions_importsMap2 TestImportCompletions_importsMap3 TestImportCompletions_importsMap4 TestImportCompletions_importsMap5 +TestImportNameCodeFixDefaultExport6 +TestImportNameCodeFixExportAsDefault TestImportSuggestionsCache_exportUndefined TestImportSuggestionsCache_invalidPackageJson TestImportTypeCompletions1 diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index bcb496f9fc..33187eed6e 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -560,13 +560,20 @@ func (f *FourslashTest) VerifyCompletions(t *testing.T, markerInput MarkerInput, t.Fatalf("Code action '%s' from source '%s' not found in completions.", expectedAction.Name, expectedAction.Source) } assert.Check(t, strings.Contains(*item.Detail, expectedAction.Description), "Completion item detail does not contain expected description.") - f.ApplyTextEdits(t, *item.AdditionalTextEdits) + f.applyTextEdits(t, *item.AdditionalTextEdits) assert.Equal(t, f.getScriptInfo(f.activeFilename).content, expectedAction.NewFileContent, fmt.Sprintf("File content after applying code action '%s' did not match expected content.", expectedAction.Name)) }, } } func (f *FourslashTest) verifyCompletionsWorker(t *testing.T, expected *CompletionsExpectedList) *lsproto.CompletionList { + prefix := f.getCurrentPositionPrefix() + list := f.getCompletions(t) + f.verifyCompletionsResult(t, list, expected, prefix) + return list +} + +func (f *FourslashTest) getCompletions(t *testing.T) *lsproto.CompletionList { prefix := f.getCurrentPositionPrefix() params := &lsproto.CompletionParams{ TextDocument: lsproto.TextDocumentIdentifier{ @@ -582,7 +589,6 @@ func (f *FourslashTest) verifyCompletionsWorker(t *testing.T, expected *Completi if !resultOk { t.Fatalf(prefix+"Unexpected response type for completion request: %T", resMsg.AsResponse().Result) } - f.verifyCompletionsResult(t, result.List, expected, prefix) return result.List } @@ -780,14 +786,7 @@ func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual } if expected.Detail != nil || expected.Documentation != nil || actualAutoImportData != nil { - resMsg, result, resultOk := sendRequest(t, f, lsproto.CompletionItemResolveInfo, actual) - if resMsg == nil { - t.Fatal(prefix + "Expected non-nil response for completion item resolve, got nil") - } - if !resultOk { - t.Fatalf(prefix+"Unexpected response type for completion item resolve: %T", resMsg.AsResponse().Result) - } - actual = result + actual = f.resolveCompletionItem(t, actual) } if actualAutoImportData != nil { @@ -810,6 +809,18 @@ func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual assertDeepEqual(t, actual.SortText, core.OrElse(expected.SortText, ptrTo(string(ls.SortTextLocationPriority))), prefix+" SortText mismatch") } +func (f *FourslashTest) resolveCompletionItem(t *testing.T, item *lsproto.CompletionItem) *lsproto.CompletionItem { + prefix := f.getCurrentPositionPrefix() + resMsg, result, resultOk := sendRequest(t, f, lsproto.CompletionItemResolveInfo, item) + if resMsg == nil { + t.Fatal(prefix + "Expected non-nil response for completion item resolve, got nil") + } + if !resultOk { + t.Fatalf(prefix+"Unexpected response type for completion item resolve: %T", resMsg.AsResponse().Result) + } + return result +} + func getExpectedLabel(t *testing.T, item CompletionsExpectedItem) string { switch item := item.(type) { case string: @@ -831,6 +842,53 @@ func assertDeepEqual(t *testing.T, actual any, expected any, prefix string, opts } } +type ApplyCodeActionFromCompletionOptions struct { + Name string + Source string + AutoImportData *ls.AutoImportData + Description string + NewFileContent *string + NewRangeContent *string +} + +func (f *FourslashTest) VerifyApplyCodeActionFromCompletion(t *testing.T, markerName *string, options *ApplyCodeActionFromCompletionOptions) { + f.GoToMarker(t, *markerName) + completionsList := f.getCompletions(t) + item := core.Find(completionsList.Items, func(item *lsproto.CompletionItem) bool { + if item.Label != options.Name || item.Data == nil { + return false + } + data, ok := (*item.Data).(*ls.CompletionItemData) + if !ok { + return false + } + if options.AutoImportData != nil { + return data.AutoImport != nil && data.AutoImport.ModuleSpecifier == options.AutoImportData.ModuleSpecifier && + (options.AutoImportData.ExportName == "" || data.AutoImport.ExportName == options.AutoImportData.ExportName) && + (options.AutoImportData.FileName == nil || data.AutoImport.FileName == options.AutoImportData.FileName) && + (options.AutoImportData.AmbientModuleName == nil || data.AutoImport.AmbientModuleName == options.AutoImportData.AmbientModuleName) && + (options.AutoImportData.IsPackageJsonImport == core.TSUnknown || data.AutoImport.IsPackageJsonImport == options.AutoImportData.IsPackageJsonImport) + } + if data.AutoImport == nil && data.Source != "" && data.Source == options.Source { + return true + } + if data.AutoImport != nil && data.AutoImport.ModuleSpecifier == options.Source { + return true + } + return false + }) + if item == nil { + t.Fatalf("Code action '%s' from source '%s' not found in completions.", options.Name, options.Source) + } + item = f.resolveCompletionItem(t, item) + assert.Check(t, strings.Contains(*item.Detail, options.Description), "Completion item detail does not contain expected description.") + if item.AdditionalTextEdits == nil { + t.Fatalf("Expected non-nil AdditionalTextEdits for code action completion item.") + } + f.applyTextEdits(t, *item.AdditionalTextEdits) + assert.Equal(t, f.getScriptInfo(f.activeFilename).content, options.NewFileContent, "File content after applying code action did not match expected content.") +} + func (f *FourslashTest) VerifyBaselineFindAllReferences( t *testing.T, markers ...string, @@ -1315,7 +1373,7 @@ func (f *FourslashTest) getSelection() core.TextRange { ) } -func (f *FourslashTest) ApplyTextEdits(t *testing.T, edits []*lsproto.TextEdit) { +func (f *FourslashTest) applyTextEdits(t *testing.T, edits []*lsproto.TextEdit) { script := f.getScriptInfo(f.activeFilename) slices.SortFunc(edits, func(a, b *lsproto.TextEdit) int { aStart := f.converters.LineAndCharacterToPosition(script, a.Range.Start) diff --git a/internal/fourslash/tests/gen/autoImportCompletionAmbientMergedModule1_test.go b/internal/fourslash/tests/gen/autoImportCompletionAmbientMergedModule1_test.go new file mode 100644 index 0000000000..273f99b13e --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportCompletionAmbientMergedModule1_test.go @@ -0,0 +1,78 @@ +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 TestAutoImportCompletionAmbientMergedModule1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// @module: commonjs +// @filename: /node_modules/@types/vscode/index.d.ts +declare module "vscode" { + export class Position { + readonly line: number; + readonly character: number; + } +} +// @filename: src/motion.ts +import { Position } from "vscode"; + +export abstract class MoveQuoteMatch { + public override async execActionWithCount( + position: Position, + ): Promise {} +} + +declare module "vscode" { + interface Position { + toString(): string; + } +} +// @filename: src/smartQuotes.ts +import { MoveQuoteMatch } from "./motion"; + +export class MoveInsideNextQuote extends MoveQuoteMatch {/*1*/ + keys = ["i", "n", "q"]; +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "execActionWithCount", + InsertText: PtrTo("public execActionWithCount(position: Position): Promise {\n}"), + FilterText: PtrTo("execActionWithCount"), + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + Source: "ClassMemberSnippet/", + })), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "execActionWithCount", + Source: "ClassMemberSnippet/", + Description: "Includes imports of types referenced by 'execActionWithCount'", + NewFileContent: PtrTo(`import { Position } from "vscode"; +import { MoveQuoteMatch } from "./motion"; + +export class MoveInsideNextQuote extends MoveQuoteMatch { + keys = ["i", "n", "q"]; +}`), + }) +} diff --git a/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go b/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go new file mode 100644 index 0000000000..5ed86f811c --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go @@ -0,0 +1,102 @@ +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 TestAutoImportCompletionExportEqualsWithDefault1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// @module: commonjs +// @filename: node.ts +import Container from "./container.js"; +import Document from "./document.js"; + +declare namespace Node { + class Node extends Node_ {} + + export { Node as default }; +} + +declare abstract class Node_ { + parent: Container | Document | undefined; +} + +declare class Node extends Node_ {} + +export = Node; +// @filename: document.ts +import Container from "./container.js"; + +declare namespace Document { + export { Document_ as default }; +} + +declare class Document_ extends Container {} + +declare class Document extends Document_ {} + +export = Document; +// @filename: container.ts +import Node from "./node.js"; + +declare namespace Container { + export { Container_ as default }; +} + +declare abstract class Container_ extends Node { + p/*1*/ +} + +declare class Container extends Container_ {} + +export = Container;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "parent", + InsertText: PtrTo("parent: Container_ | Document_ | undefined;"), + FilterText: PtrTo("parent"), + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + Source: "ClassMemberSnippet/", + })), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "parent", + Source: "ClassMemberSnippet/", + Description: "Includes imports of types referenced by 'parent'", + NewFileContent: PtrTo(`import Document_ from "./document.js"; +import Node from "./node.js"; + +declare namespace Container { + export { Container_ as default }; +} + +declare abstract class Container_ extends Node { + p +} + +declare class Container extends Container_ {} + +export = Container;`), + }) +} diff --git a/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation1_test.go b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation1_test.go new file mode 100644 index 0000000000..725856e637 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation1_test.go @@ -0,0 +1,70 @@ +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 TestAutoImportCompletionExportListAugmentation1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @Filename: /node_modules/@sapphire/pieces/index.d.ts +interface Container { + stores: unknown; +} + +declare class Piece { + container: Container; +} + +export { Piece, type Container }; +// @FileName: /augmentation.ts +declare module "@sapphire/pieces" { + interface Container { + client: unknown; + } + export { Container }; +} +// @Filename: /index.ts +import { Piece } from "@sapphire/pieces"; +class FullPiece extends Piece { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "container", + InsertText: PtrTo("container: Container;"), + FilterText: PtrTo("container"), + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + Source: "ClassMemberSnippet/", + })), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "container", + Source: "ClassMemberSnippet/", + Description: "Includes imports of types referenced by 'container'", + NewFileContent: PtrTo(`import { Container, Piece } from "@sapphire/pieces"; +class FullPiece extends Piece { + +}`), + }) +} diff --git a/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation2_test.go b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation2_test.go new file mode 100644 index 0000000000..34b6d1c7eb --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation2_test.go @@ -0,0 +1,80 @@ +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 TestAutoImportCompletionExportListAugmentation2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @Filename: /node_modules/@sapphire/pieces/index.d.ts +interface Container { + stores: unknown; +} + +declare class Piece { + get container(): Container; +} + +declare class AliasPiece extends Piece {} + +export { AliasPiece, type Container }; +// @Filename: /node_modules/@sapphire/framework/index.d.ts +import { AliasPiece } from "@sapphire/pieces"; + +declare class Command extends AliasPiece {} + +declare module "@sapphire/pieces" { + interface Container { + client: unknown; + } +} + +export { Command }; +// @Filename: /index.ts +import "@sapphire/pieces"; +import { Command } from "@sapphire/framework"; +class PingCommand extends Command { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "container", + InsertText: PtrTo("get container(): Container {\n}"), + FilterText: PtrTo("container"), + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + Source: "ClassMemberSnippet/", + })), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "container", + Source: "ClassMemberSnippet/", + Description: "Includes imports of types referenced by 'container'", + NewFileContent: PtrTo(`import "@sapphire/pieces"; +import { Command } from "@sapphire/framework"; +import { Container } from "@sapphire/pieces"; +class PingCommand extends Command { + +}`), + }) +} diff --git a/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation3_test.go b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation3_test.go new file mode 100644 index 0000000000..1877ab0244 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation3_test.go @@ -0,0 +1,69 @@ +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 TestAutoImportCompletionExportListAugmentation3(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @Filename: /node_modules/@sapphire/pieces/index.d.ts +export interface Container { + stores: unknown; +} + +declare class Piece { + container: Container; +} + +export { Piece }; +// @FileName: /augmentation.ts +declare module "@sapphire/pieces" { + interface Container { + client: unknown; + } +} +// @Filename: /index.ts +import { Piece } from "@sapphire/pieces"; +class FullPiece extends Piece { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "container", + InsertText: PtrTo("container: Container;"), + FilterText: PtrTo("container"), + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + Source: "ClassMemberSnippet/", + })), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "container", + Source: "ClassMemberSnippet/", + Description: "Includes imports of types referenced by 'container'", + NewFileContent: PtrTo(`import { Container, Piece } from "@sapphire/pieces"; +class FullPiece extends Piece { + +}`), + }) +} diff --git a/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation4_test.go b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation4_test.go new file mode 100644 index 0000000000..b64b116e1b --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation4_test.go @@ -0,0 +1,78 @@ +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 TestAutoImportCompletionExportListAugmentation4(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @Filename: /node_modules/@sapphire/pieces/index.d.ts +interface Container { + stores: unknown; +} + +declare class Piece { + get container(): Container; +} + +export { Piece as Alias, type Container }; +// @Filename: /node_modules/@sapphire/framework/index.d.ts +import { Alias } from "@sapphire/pieces"; + +declare class Command extends Alias {} + +declare module "@sapphire/pieces" { + interface Container { + client: unknown; + } +} + +export { Command as CommandAlias }; +// @Filename: /index.ts +import "@sapphire/pieces"; +import { CommandAlias } from "@sapphire/framework"; +class PingCommand extends CommandAlias { + /*1*/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &[]string{}, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "container", + InsertText: PtrTo("get container(): Container {\n}"), + FilterText: PtrTo("container"), + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + Source: "ClassMemberSnippet/", + })), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "container", + Source: "ClassMemberSnippet/", + Description: "Includes imports of types referenced by 'container'", + NewFileContent: PtrTo(`import "@sapphire/pieces"; +import { CommandAlias } from "@sapphire/framework"; +import { Container } from "@sapphire/pieces"; +class PingCommand extends CommandAlias { + +}`), + }) +} diff --git a/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go b/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go new file mode 100644 index 0000000000..bbcef82033 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go @@ -0,0 +1,76 @@ +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 TestAutoImportReExportFromAmbientModule(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "commonjs" + } +} +// @Filename: /home/src/workspaces/project/node_modules/@types/node/index.d.ts +declare module "fs" { + export function accessSync(path: string): void; +} +// @Filename: /home/src/workspaces/project/node_modules/@types/fs-extra/index.d.ts +export * from "fs"; +// @Filename: /home/src/workspaces/project/index.ts +access/**/` + 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: "accessSync", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "fs", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "accessSync", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "fs-extra", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "accessSync", + Source: "fs-extra", + Description: "Add import from \"fs-extra\"", + NewFileContent: PtrTo(`import { accessSync } from "fs-extra"; + +access`), + AutoImportData: &ls.AutoImportData{ + ExportName: "accessSync", + FileName: PtrTo("/home/src/workspaces/project/node_modules/@types/fs-extra/index.d.ts"), + ModuleSpecifier: "fs-extra", + }, + }) +} diff --git a/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go b/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go new file mode 100644 index 0000000000..aa6cd9798a --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go @@ -0,0 +1,56 @@ +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 TestAutoImportSortCaseSensitivity2(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export interface HasBar { bar: number } +export function hasBar(x: unknown): x is HasBar { return x && typeof x.bar === "number" } +export function foo() {} +export type __String = string; +// @Filename: /b.ts +import { __String, HasBar, hasBar } from "./a"; +f/**/;` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("function foo(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/a", + Description: "Update import from \"./a\"", + NewFileContent: PtrTo(`import { __String, foo, HasBar, hasBar } from "./a"; +f;`), + }) +} diff --git a/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go b/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go new file mode 100644 index 0000000000..dcb9290d69 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go @@ -0,0 +1,52 @@ +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/testutil" +) + +func TestAutoImportVerbatimTypeOnly1(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: node18 +// @verbatimModuleSyntax: true +// @Filename: /mod.ts +export const value = 0; +export class C { constructor(v: any) {} } +export interface I {} +// @Filename: /a.mts +const x: /**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "I", + Source: "./mod", + Description: "Add import from \"./mod.js\"", + AutoImportData: &ls.AutoImportData{ + ExportName: "I", + FileName: PtrTo("/mod.ts"), + ModuleSpecifier: "./mod.js", + }, + NewFileContent: PtrTo(`import type { I } from "./mod.js"; + +const x: `), + }) + f.Insert(t, "I = new C") + f.VerifyApplyCodeActionFromCompletion(t, nil, &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "C", + Source: "./mod", + Description: "Update import from \"./mod.js\"", + AutoImportData: &ls.AutoImportData{ + ExportName: "C", + FileName: PtrTo("/mod.ts"), + ModuleSpecifier: "./mod.js", + }, + NewFileContent: PtrTo(`import { C, type I } from "./mod.js"; + +const x: I = new C`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go b/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go new file mode 100644 index 0000000000..6c3463eb00 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImportFromJSXTag_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/testutil" +) + +func TestCompletionsImportFromJSXTag(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @jsx: react +// @Filename: /types.d.ts +declare namespace JSX { + interface IntrinsicElements { a } +} +// @Filename: /Box.tsx +export function Box(props: any) { return null; } +// @Filename: /App.tsx +export function App() { + return ( +
+ + ) +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "Box", + Source: "/Box", + Description: "Add import from \"./Box\"", + NewFileContent: PtrTo(`import { Box } from "./Box"; + +export function App() { + return ( +
+ + ) +}`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go b/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go new file mode 100644 index 0000000000..256c55dc16 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go @@ -0,0 +1,47 @@ +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 TestCompletionsImportModuleAugmentationWithJS(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @checkJs: true +// @noEmit: true +// @Filename: /test.js +class Abcde { + x +} + +module.exports = { + Abcde +}; +// @Filename: /index.ts +export {}; +declare module "./test" { + interface Abcde { b: string } +} + +Abcde/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "Abcde", + Source: "/test", + Description: "Add import from \"./test\"", + NewFileContent: PtrTo(`import { Abcde } from "./test"; + +export {}; +declare module "./test" { + interface Abcde { b: string } +} + +Abcde`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImportPathsConflict_test.go b/internal/fourslash/tests/gen/completionsImportPathsConflict_test.go new file mode 100644 index 0000000000..22b68c4e9e --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImportPathsConflict_test.go @@ -0,0 +1,68 @@ +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 TestCompletionsImportPathsConflict(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /tsconfig.json +{ + "compilerOptions": { + "module": "esnext", + "paths": { + "@reduxjs/toolkit": ["src/index.ts"], + "@internal/*": ["src/*"] + } + } +} +// @Filename: /src/index.ts +export { configureStore } from "./configureStore"; +// @Filename: /src/configureStore.ts +export function configureStore() {} +// @Filename: /src/tests/createAsyncThunk.typetest.ts +import {} from "@reduxjs/toolkit"; +/**/` + 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: "configureStore", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "@reduxjs/toolkit", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "configureStore", + Source: "@reduxjs/toolkit", + AutoImportData: &ls.AutoImportData{ + ExportName: "configureStore", + FileName: PtrTo("/src/configureStore.ts"), + ModuleSpecifier: "@reduxjs/toolkit", + }, + Description: "Update import from \"@reduxjs/toolkit\"", + NewFileContent: PtrTo(`import { configureStore } from "@reduxjs/toolkit"; +`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go b/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go new file mode 100644 index 0000000000..8576239728 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go @@ -0,0 +1,32 @@ +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 TestCompletionsImportYieldExpression(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export function a() {} +// @Filename: /b.ts +function *f() { + yield a/**/ +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "a", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { a } from "./a"; + +function *f() { + yield a +}`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_46332_test.go b/internal/fourslash/tests/gen/completionsImport_46332_test.go new file mode 100644 index 0000000000..9d60fe0808 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_46332_test.go @@ -0,0 +1,101 @@ +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 TestCompletionsImport_46332(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @moduleResolution: node +// @Filename: /node_modules/vue/package.json +{ + "name": "vue", + "types": "dist/vue.d.ts" +} +// @Filename: /node_modules/vue/dist/vue.d.ts +export * from "@vue/runtime-dom" +// @Filename: /node_modules/@vue/runtime-dom/package.json +{ + "name": "@vue/runtime-dom", + "types": "dist/runtime-dom.d.ts" +} +// @Filename: /node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts +export * from "@vue/runtime-core"; +export {} +declare module '@vue/reactivity' { + export interface RefUnwrapBailTypes { + runtimeDOMBailTypes: any + } +} +// @Filename: /node_modules/@vue/runtime-core/package.json +{ + "name": "@vue/runtime-core", + "types": "dist/runtime-core.d.ts" +} +// @Filename: /node_modules/@vue/runtime-core/dist/runtime-core.d.ts +import { ref } from '@vue/reactivity'; +export { ref }; +declare module '@vue/reactivity' { + export interface RefUnwrapBailTypes { + runtimeCoreBailTypes: any + } +} +// @Filename: /node_modules/@vue/reactivity/package.json +{ + "name": "@vue/reactivity", + "types": "dist/reactivity.d.ts" +} +// @Filename: /node_modules/@vue/reactivity/dist/reactivity.d.ts +export declare function ref(): T; +// @Filename: /package.json +{ + "dependencies": { + "vue": "*" + } +} +// @Filename: /index.ts +import {} from "vue"; +ref/**/` + 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: "ref", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "vue", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "ref", + Source: "vue", + Description: "Update import from \"vue\"", + AutoImportData: &ls.AutoImportData{ + ExportName: "ref", + FileName: PtrTo("/node_modules/vue/dist/vue.d.ts"), + }, + NewFileContent: PtrTo(`import { ref } from "vue"; +ref`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_ambient_test.go b/internal/fourslash/tests/gen/completionsImport_ambient_test.go new file mode 100644 index 0000000000..b65751ae7a --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_ambient_test.go @@ -0,0 +1,76 @@ +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 TestCompletionsImport_ambient(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: a.d.ts +declare namespace foo { class Bar {} } +declare module 'path1' { + import Bar = foo.Bar; + export default Bar; +} +declare module 'path2longer' { + import Bar = foo.Bar; + export {Bar}; +} + +// @Filename: b.ts +Ba/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + }, + &lsproto.CompletionItem{ + Label: "Bar", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "path1", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "Bar", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "path2longer", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "Bar", + Source: "path2longer", + Description: "Add import from \"path2longer\"", + NewFileContent: PtrTo(`import { Bar } from "path2longer"; + +Ba`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go new file mode 100644 index 0000000000..6e674f3371 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go @@ -0,0 +1,72 @@ +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 TestCompletionsImport_defaultAndNamedConflict(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @noLib: true +// @Filename: /someModule.ts +export const someModule = 0; +export default 1; +// @Filename: /index.ts +someMo/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "someModule", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/someModule", + }, + })), + Detail: PtrTo("(property) default: 1"), + Kind: PtrTo(lsproto.CompletionItemKindField), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "someModule", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/someModule", + }, + })), + Detail: PtrTo("const someModule: 0"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, true), + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "someModule", + Source: "/someModule", + AutoImportData: &ls.AutoImportData{ + ExportName: "default", + FileName: PtrTo("/someModule.ts"), + }, + Description: "Add import from \"./someModule\"", + NewFileContent: PtrTo(`import someModule from "./someModule"; + +someMo`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go b/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go new file mode 100644 index 0000000000..1ac87eb731 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go @@ -0,0 +1,58 @@ +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 TestCompletionsImport_defaultFalsePositive(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /node_modules/foo/index.ts +export default function f(): void; +// @Filename: /node_modules/bar/concat.d.ts +export const concat = 0; +// @Filename: /a.ts +export {}; +conca/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/a.ts") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "concat", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/bar/concat", + }, + })), + Detail: PtrTo("const concat: 0"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "concat", + Source: "/node_modules/bar/concat", + Description: "Add import from \"bar/concat\"", + NewFileContent: PtrTo(`import { concat } from "bar/concat"; + +export {}; +conca`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go b/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go new file mode 100644 index 0000000000..5c6c37b0de --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go @@ -0,0 +1,54 @@ +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 TestCompletionsImport_default_addToNamedImports(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export default function foo() {} +export const x = 0; +// @Filename: /b.ts +import { x } from "./a"; +f/**/;` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("function foo(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/a", + Description: "Update import from \"./a\"", + NewFileContent: PtrTo(`import foo, { x } from "./a"; +f;`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go b/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go new file mode 100644 index 0000000000..6b2e673417 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go @@ -0,0 +1,53 @@ +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 TestCompletionsImport_default_addToNamespaceImport(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export default function foo() {} +// @Filename: /b.ts +import * as a from "./a"; +f/**/;` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("function foo(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/a", + Description: "Update import from \"./a\"", + NewFileContent: PtrTo(`import foo, * as a from "./a"; +f;`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go b/internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go new file mode 100644 index 0000000000..407a46bc41 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go @@ -0,0 +1,54 @@ +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 TestCompletionsImport_default_alreadyExistedWithRename(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export default function foo() {} +// @Filename: /b.ts +import f_o_o from "./a"; +f/**/;` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("function foo(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import foo from "./a"; +import f_o_o from "./a"; +f;`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_anonymous_test.go b/internal/fourslash/tests/gen/completionsImport_default_anonymous_test.go new file mode 100644 index 0000000000..fce12a0932 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_anonymous_test.go @@ -0,0 +1,69 @@ +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 TestCompletionsImport_default_anonymous(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @noLib: true +// @Filename: /src/foo-bar.ts +export default 0; +// @Filename: /src/b.ts +def/*0*/ +fooB/*1*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "0") + f.VerifyCompletions(t, "0", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{}, true), + }, + }) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooBar", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/src/foo-bar", + }, + })), + Detail: PtrTo("(property) default: 0"), + Kind: PtrTo(lsproto.CompletionItemKindField), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "fooBar", + Source: "/src/foo-bar", + Description: "Add import from \"./foo-bar\"", + NewFileContent: PtrTo(`import fooBar from "./foo-bar" + +def +fooB`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_didNotExistBefore_test.go b/internal/fourslash/tests/gen/completionsImport_default_didNotExistBefore_test.go new file mode 100644 index 0000000000..26576cab49 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_didNotExistBefore_test.go @@ -0,0 +1,54 @@ +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 TestCompletionsImport_default_didNotExistBefore(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @Filename: /a.ts +export default function foo() {} +// @Filename: /b.ts +f/**/;` + 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: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("function foo(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import foo from "./a"; + +f;`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_exportDefaultIdentifier_test.go b/internal/fourslash/tests/gen/completionsImport_default_exportDefaultIdentifier_test.go new file mode 100644 index 0000000000..ae41e12f86 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_exportDefaultIdentifier_test.go @@ -0,0 +1,56 @@ +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 TestCompletionsImport_default_exportDefaultIdentifier(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @Filename: /a.ts +const foo = 0; +export default foo; +// @Filename: /b.ts +f/**/;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("(alias) const foo: 0\nexport default foo"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import foo from "./a"; + +f;`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go b/internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go new file mode 100644 index 0000000000..78fc7be2eb --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go @@ -0,0 +1,60 @@ +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 TestCompletionsImport_default_fromMergedDeclarations(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @Filename: /a.ts +declare module "m" { + export default class M {} +} +// @Filename: /b.ts +declare module "m" { + export default interface M {} +} +// @Filename: /c.ts +/**/` + 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: "M", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "m", + }, + })), + Detail: PtrTo("class M"), + Kind: PtrTo(lsproto.CompletionItemKindClass), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "M", + Source: "m", + Description: "Add import from \"m\"", + NewFileContent: PtrTo(`import M from "m"; + +`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go new file mode 100644 index 0000000000..8a96c34cf3 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go @@ -0,0 +1,60 @@ +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 TestCompletionsImport_default_symbolName(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: /node_modules/@types/range-parser/index.d.ts +declare function RangeParser(): string; +declare namespace RangeParser { + interface Options { + combine?: boolean; + } +} +export = RangeParser; +// @Filename: /b.ts +R/*0*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "0", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "RangeParser", + Kind: PtrTo(lsproto.CompletionItemKindFunction), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/node_modules/@types/range-parser/index", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + Detail: PtrTo("namespace RangeParser\nfunction RangeParser(): string"), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "RangeParser", + Source: "/node_modules/@types/range-parser/index", + Description: "Add import from \"range-parser\"", + NewFileContent: PtrTo(`import RangeParser = require("range-parser"); + +R`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go b/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go new file mode 100644 index 0000000000..6ed0bebc1a --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_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/ls" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCompletionsImport_details_withMisspelledName(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export const abc = 0; +// @Filename: /b.ts +acb/*1*/; +// @Filename: /c.ts +acb/*2*/;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "1") + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "abc", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { abc } from "./a"; + +acb;`), + }) + f.GoToMarker(t, "2") + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("2"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "abc", + Source: "/a", + AutoImportData: &ls.AutoImportData{ + ExportName: "abc", + FileName: PtrTo("/a.ts"), + }, + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { abc } from "./a"; + +acb;`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go new file mode 100644 index 0000000000..c849f51857 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go @@ -0,0 +1,69 @@ +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 TestCompletionsImport_exportEquals_anonymous(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @noLib: true +// @Filename: /src/foo-bar.ts +export = 0; +// @Filename: /src/b.ts +exp/*0*/ +fooB/*1*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "0") + f.VerifyCompletions(t, "0", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{}, true), + }, + }) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fooBar", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/src/foo-bar", + }, + })), + Detail: PtrTo("(property) export=: 0"), + Kind: PtrTo(lsproto.CompletionItemKindField), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, true), + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "fooBar", + Source: "/src/foo-bar", + Description: "Add import from \"./foo-bar\"", + NewFileContent: PtrTo(`import fooBar = require("./foo-bar") + +exp +fooB`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go new file mode 100644 index 0000000000..5d1bbd0d3b --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go @@ -0,0 +1,89 @@ +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 TestCompletionsImport_exportEquals(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @Filename: /a.d.ts +declare function a(): void; +declare namespace a { + export interface b {} +} +export = a; +// @Filename: /b.ts +a/*0*/; +let x: b/*1*/;` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "0", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "a", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "b", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "b", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { b } from "./a"; + +a; +let x: b;`), + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "a", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { b } from "./a"; +import a = require("./a"); + +a; +let x: b;`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_fromAmbientModule_test.go b/internal/fourslash/tests/gen/completionsImport_fromAmbientModule_test.go new file mode 100644 index 0000000000..db396101b7 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_fromAmbientModule_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/testutil" +) + +func TestCompletionsImport_fromAmbientModule(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @Filename: /a.ts +declare module "m" { + export const x: number; +} +// @Filename: /b.ts +/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "x", + Source: "m", + Description: "Add import from \"m\"", + NewFileContent: PtrTo(`import { x } from "m"; + +`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_importType_test.go b/internal/fourslash/tests/gen/completionsImport_importType_test.go new file mode 100644 index 0000000000..195afbd428 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_importType_test.go @@ -0,0 +1,83 @@ +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 TestCompletionsImport_importType(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: /a.js +export const x = 0; +export class C {} +/** @typedef {number} T */ +// @Filename: /b.js +export const m = 0; +/** @type {/*0*/} */ +/** @type {/*1*/} */` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, []string{"0", "1"}, &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "C", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("class C"), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "T", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + Detail: PtrTo("type T = number"), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "x", + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "C", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { C } from "./a"; + +export const m = 0; +/** @type {} */ +/** @type {} */`), + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "T", + Source: "/a", + Description: "Change 'T' to 'import(\"./a\").T'", + NewFileContent: PtrTo(`import { C } from "./a"; + +export const m = 0; +/** @type {} */ +/** @type {import("./a").} */`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go b/internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go new file mode 100644 index 0000000000..4e75441fad --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go @@ -0,0 +1,61 @@ +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 TestCompletionsImport_jsxOpeningTagImportDefault(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @jsx: react +// @Filename: /component.tsx +export default function (props: any) {} +// @Filename: /index.tsx +export function Index() { + return symbol; +// @Filename: /a.ts +const privateSym = Symbol(); +export const publicSym = Symbol(); +export interface I { + [privateSym]: number; + [publicSym]: number; + [defaultPublicSym]: number; + n: number; +} +export const i: I; +// @Filename: /user.ts +import { i } from "./a"; +i[|./**/|];` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Exact: []fourslash.CompletionsExpectedItem{ + "n", + &lsproto.CompletionItem{ + Label: "publicSym", + InsertText: PtrTo("[publicSym]"), + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a", + }, + })), + SortText: PtrTo(string(ls.SortTextGlobalsOrKeywords)), + AdditionalTextEdits: fourslash.AnyTextEdits, + TextEdit: &lsproto.TextEditOrInsertReplaceEdit{ + TextEdit: &lsproto.TextEdit{ + NewText: "publicSym", + Range: f.Ranges()[0].LSRange, + }, + }, + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "publicSym", + Source: "/a", + Description: "Update import from \"./a\"", + NewFileContent: PtrTo(`import { i, publicSym } from "./a"; +i.;`), + }) +} diff --git a/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go b/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go new file mode 100644 index 0000000000..8487cffab9 --- /dev/null +++ b/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go @@ -0,0 +1,28 @@ +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 TestImportNameCodeFixDefaultExport6(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /a.ts +export default Math.foo; +// @Filename: /index.ts +a/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "a", + Source: "/a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import a from "./a"; + +a`), + }) +} diff --git a/internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go b/internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go new file mode 100644 index 0000000000..bf900f540b --- /dev/null +++ b/internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go @@ -0,0 +1,29 @@ +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 TestImportNameCodeFixExportAsDefault(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /foo.ts +const foo = 'foo' +export { foo as default } +// @Filename: /index.ts + foo/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/foo", + Description: "Add import from \"./foo\"", + NewFileContent: PtrTo(`import foo from "./foo"; + +foo`), + }) +} diff --git a/internal/fourslash/tests/gen/jsxTagNameCompletionClosed_test.go b/internal/fourslash/tests/gen/jsxTagNameCompletionClosed_test.go new file mode 100644 index 0000000000..9358ac1196 --- /dev/null +++ b/internal/fourslash/tests/gen/jsxTagNameCompletionClosed_test.go @@ -0,0 +1,145 @@ +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 TestJsxTagNameCompletionClosed(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@Filename: file.tsx +interface NestedInterface { + Foo: NestedInterface; + (props: {}): any; +} + +declare const Foo: NestedInterface; + +function fn1() { + return + + +} +function fn2() { + return + + +} +function fn3() { + return + + +} +function fn4() { + return + + +} +function fn5() { + return + + +} +function fn6() { + return + + +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("const Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("const Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "5", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "6", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/jsxTagNameCompletionUnclosed_test.go b/internal/fourslash/tests/gen/jsxTagNameCompletionUnclosed_test.go new file mode 100644 index 0000000000..78ab4a048d --- /dev/null +++ b/internal/fourslash/tests/gen/jsxTagNameCompletionUnclosed_test.go @@ -0,0 +1,145 @@ +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 TestJsxTagNameCompletionUnclosed(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@Filename: file.tsx +interface NestedInterface { + Foo: NestedInterface; + (props: {}): any; +} + +declare const Foo: NestedInterface; + +function fn1() { + return + +} +function fn2() { + return + +} +function fn3() { + return + +} +function fn4() { + return + +} +function fn5() { + return + +} +function fn6() { + return + +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("const Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("const Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "5", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) + f.VerifyCompletions(t, "6", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "Foo", + Detail: PtrTo("(property) NestedInterface.Foo: NestedInterface"), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementClosed_test.go b/internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementClosed_test.go new file mode 100644 index 0000000000..8e509858f3 --- /dev/null +++ b/internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementClosed_test.go @@ -0,0 +1,84 @@ +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 TestJsxTagNameCompletionUnderElementClosed(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@Filename: file.tsx +declare namespace JSX { + interface IntrinsicElements { + button: any; + div: any; + } +} +function fn() { + return <> + + ; +} +function fn2() { + return <> + preceding junk + ; +} +function fn3() { + return <> + + ; +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "button", + Detail: PtrTo("(property) JSX.IntrinsicElements.button: any"), + }, + }, + }, + }) + f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "button", + Detail: PtrTo("(property) JSX.IntrinsicElements.button: any"), + }, + }, + }, + }) + f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "button", + Detail: PtrTo("(property) JSX.IntrinsicElements.button: any"), + }, + }, + }, + }) +} diff --git a/internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementUnclosed_test.go b/internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementUnclosed_test.go new file mode 100644 index 0000000000..568c195177 --- /dev/null +++ b/internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementUnclosed_test.go @@ -0,0 +1,84 @@ +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 TestJsxTagNameCompletionUnderElementUnclosed(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `//@Filename: file.tsx +declare namespace JSX { + interface IntrinsicElements { + button: any; + div: any; + } +} +function fn() { + return <> + ; +} +function fn2() { + return <> + preceding junk ; +} +function fn3() { + return <> + ; +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "button", + Detail: PtrTo("(property) JSX.IntrinsicElements.button: any"), + }, + }, + }, + }) + f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "button", + Detail: PtrTo("(property) JSX.IntrinsicElements.button: any"), + }, + }, + }, + }) + f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "button", + Detail: PtrTo("(property) JSX.IntrinsicElements.button: any"), + }, + }, + }, + }) +} From ba5a65e0c7400b1ffbe2fd351873d95a61e6a8d6 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 20 Oct 2025 09:23:49 -0700 Subject: [PATCH 03/17] Pull in fourslash test updates --- internal/fourslash/_scripts/failingTests.txt | 5 +---- ...oImportCompletionExportEqualsWithDefault1_test.go | 2 ++ .../fourslash/tests/gen/autoImportProvider6_test.go | 4 ++-- .../tests/gen/autoImportProvider_exportMap2_test.go | 1 + .../gen/autoImportSameNameDefaultExported_test.go | 2 +- .../tests/gen/autoImportSortCaseSensitivity2_test.go | 4 ++-- .../tests/gen/completionForObjectProperty_test.go | 12 ++++++------ .../tests/gen/completionsImportFromJSXTag_test.go | 2 +- ...completionsImportModuleAugmentationWithJS_test.go | 2 +- .../gen/completionsImportYieldExpression_test.go | 2 +- .../tests/gen/completionsImport_46332_test.go | 2 +- .../tests/gen/completionsImport_augmentation_test.go | 4 ++-- .../completionsImport_compilerOptionsModule_test.go | 2 +- ...completionsImport_defaultAndNamedConflict_test.go | 6 +++--- .../completionsImport_defaultFalsePositive_test.go | 4 ++-- ...mpletionsImport_default_addToNamedImports_test.go | 4 ++-- ...etionsImport_default_addToNamespaceImport_test.go | 4 ++-- ...nsImport_default_alreadyExistedWithRename_test.go | 4 ++-- .../gen/completionsImport_default_symbolName_test.go | 6 ++++-- ...pletionsImport_details_withMisspelledName_test.go | 9 +++++---- .../completionsImport_exportEquals_anonymous_test.go | 7 +++++-- .../tests/gen/completionsImport_exportEquals_test.go | 10 ++++++---- ...mport_filteredByInvalidPackageJson_direct_test.go | 4 ++-- ...port_filteredByPackageJson_@typesImplicit_test.go | 2 +- ...nsImport_filteredByPackageJson_@typesOnly_test.go | 2 +- ...etionsImport_filteredByPackageJson_direct_test.go | 2 +- ...etionsImport_filteredByPackageJson_nested_test.go | 4 ++-- ...rt_filteredByPackageJson_peerDependencies_test.go | 2 +- .../tests/gen/completionsImport_importType_test.go | 8 ++++---- ...pletionsImport_jsxOpeningTagImportDefault_test.go | 4 ++-- .../gen/completionsImport_mergedReExport_test.go | 2 +- ...completionsImport_named_addToNamedImports_test.go | 4 ++-- ...completionsImport_named_didNotExistBefore_test.go | 6 +++--- ...letionsImport_named_namespaceImportExists_test.go | 4 ++-- .../tests/gen/completionsImport_noSemicolons_test.go | 2 +- ...completionsImport_ofAlias_preferShortPath_test.go | 2 +- ...ompletionsImport_previousTokenIsSemicolon_test.go | 4 ++-- .../gen/completionsImport_reExportDefault_test.go | 2 +- .../gen/completionsImport_reExport_wrongName_test.go | 10 +++++----- .../gen/completionsImport_require_addNew_test.go | 4 ++-- .../completionsImport_require_addToExisting_test.go | 4 ++-- .../tests/gen/completionsImport_require_test.go | 4 ++-- .../tests/gen/completionsImport_tsx_test.go | 4 ++-- .../tests/gen/completionsImport_typeOnly_test.go | 3 ++- .../gen/completionsImport_umdDefaultNoCrash1_test.go | 4 ++-- ...mpletionsImport_umdModules2_moduleExports_test.go | 4 ++-- .../completionsImport_weirdDefaultSynthesis_test.go | 7 +++++-- .../gen/completionsRecommended_namespace_test.go | 2 +- .../tests/gen/completionsWithDeprecatedTag10_test.go | 2 +- .../gen/importNameCodeFixDefaultExport6_test.go | 2 +- .../gen/importNameCodeFixExportAsDefault_test.go | 2 +- .../tests/gen/importTypeCompletions5_test.go | 3 ++- 52 files changed, 110 insertions(+), 97 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index e7c89872cd..b7baf607c6 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -11,7 +11,6 @@ TestAutoImportCompletionExportListAugmentation3 TestAutoImportCompletionExportListAugmentation4 TestAutoImportFileExcludePatterns3 TestAutoImportPathsAliasesAndBarrels -TestAutoImportProvider6 TestAutoImportProvider_exportMap1 TestAutoImportProvider_exportMap2 TestAutoImportProvider_exportMap3 @@ -27,6 +26,7 @@ TestAutoImportProvider_wildcardExports1 TestAutoImportProvider_wildcardExports2 TestAutoImportProvider_wildcardExports3 TestAutoImportReExportFromAmbientModule +TestAutoImportSameNameDefaultExported TestAutoImportSortCaseSensitivity2 TestAutoImportTypeOnlyPreferred1 TestAutoImportVerbatimTypeOnly1 @@ -206,7 +206,6 @@ TestCompletionsImport_named_namespaceImportExists TestCompletionsImport_noSemicolons TestCompletionsImport_ofAlias_preferShortPath TestCompletionsImport_packageJsonImportsPreference -TestCompletionsImport_previousTokenIsSemicolon TestCompletionsImport_quoteStyle TestCompletionsImport_reExportDefault TestCompletionsImport_reExportDefault2 @@ -215,10 +214,8 @@ TestCompletionsImport_require TestCompletionsImport_require_addNew TestCompletionsImport_require_addToExisting TestCompletionsImport_sortingModuleSpecifiers -TestCompletionsImport_tsx TestCompletionsImport_typeOnly TestCompletionsImport_umdDefaultNoCrash1 -TestCompletionsImport_umdModules2_moduleExports TestCompletionsImport_uriStyleNodeCoreModules1 TestCompletionsImport_uriStyleNodeCoreModules2 TestCompletionsImport_weirdDefaultSynthesis diff --git a/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go b/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go index 5ed86f811c..e5036d3293 100644 --- a/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go +++ b/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go @@ -16,6 +16,8 @@ func TestAutoImportCompletionExportEqualsWithDefault1(t *testing.T) { defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @strict: true // @module: commonjs +// @esModuleInterop: false +// @allowSyntheticDefaultImports: false // @filename: node.ts import Container from "./container.js"; import Document from "./document.js"; diff --git a/internal/fourslash/tests/gen/autoImportProvider6_test.go b/internal/fourslash/tests/gen/autoImportProvider6_test.go index 0aca378200..eeb92339c0 100644 --- a/internal/fourslash/tests/gen/autoImportProvider6_test.go +++ b/internal/fourslash/tests/gen/autoImportProvider6_test.go @@ -12,7 +12,7 @@ import ( func TestAutoImportProvider6(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /home/src/workspaces/project/tsconfig.json { "compilerOptions": { "module": "commonjs", "lib": ["es2019"] } } @@ -39,7 +39,7 @@ Component/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/home/src/workspaces/project/node_modules/@types/react/index", + ModuleSpecifier: "react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go b/internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go index 58dca8dc9c..57eb4b8e9a 100644 --- a/internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap2_test.go @@ -18,6 +18,7 @@ func TestAutoImportProvider_exportMap2(t *testing.T) { { "compilerOptions": { "module": "commonjs" + "moduleResolution": "node10", } } // @Filename: /home/src/workspaces/project/package.json diff --git a/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go b/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go index 1c4e6a85be..36855f75c7 100644 --- a/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go +++ b/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go @@ -12,7 +12,7 @@ import ( func TestAutoImportSameNameDefaultExported(t *testing.T) { t.Parallel() - + t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @Filename: /node_modules/antd/index.d.ts diff --git a/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go b/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go index aa6cd9798a..247f36c968 100644 --- a/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go +++ b/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go @@ -35,7 +35,7 @@ f/**/;` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function foo(): void"), @@ -48,7 +48,7 @@ f/**/;` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Update import from \"./a\"", NewFileContent: PtrTo(`import { __String, foo, HasBar, hasBar } from "./a"; f;`), diff --git a/internal/fourslash/tests/gen/completionForObjectProperty_test.go b/internal/fourslash/tests/gen/completionForObjectProperty_test.go index 388df82e59..3ccb4b9527 100644 --- a/internal/fourslash/tests/gen/completionForObjectProperty_test.go +++ b/internal/fourslash/tests/gen/completionForObjectProperty_test.go @@ -45,7 +45,7 @@ const test8: { foo: string } = { foo/*8*/ }` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -66,7 +66,7 @@ const test8: { foo: string } = { foo/*8*/ }` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -87,7 +87,7 @@ const test8: { foo: string } = { foo/*8*/ }` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -108,7 +108,7 @@ const test8: { foo: string } = { foo/*8*/ }` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -129,7 +129,7 @@ const test8: { foo: string } = { foo/*8*/ }` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -150,7 +150,7 @@ const test8: { foo: string } = { foo/*8*/ }` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, diff --git a/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go b/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go index 6c3463eb00..535ec04f82 100644 --- a/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go +++ b/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go @@ -30,7 +30,7 @@ export function App() { f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "Box", - Source: "/Box", + Source: "./Box", Description: "Add import from \"./Box\"", NewFileContent: PtrTo(`import { Box } from "./Box"; diff --git a/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go b/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go index 256c55dc16..20e3032d3b 100644 --- a/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go +++ b/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go @@ -33,7 +33,7 @@ Abcde/**/` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "Abcde", - Source: "/test", + Source: "./test", Description: "Add import from \"./test\"", NewFileContent: PtrTo(`import { Abcde } from "./test"; diff --git a/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go b/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go index 8576239728..287bb937c4 100644 --- a/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go +++ b/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go @@ -21,7 +21,7 @@ function *f() { f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "a", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { a } from "./a"; diff --git a/internal/fourslash/tests/gen/completionsImport_46332_test.go b/internal/fourslash/tests/gen/completionsImport_46332_test.go index 9d60fe0808..7444e6d911 100644 --- a/internal/fourslash/tests/gen/completionsImport_46332_test.go +++ b/internal/fourslash/tests/gen/completionsImport_46332_test.go @@ -15,7 +15,7 @@ func TestCompletionsImport_46332(t *testing.T) { t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: esnext -// @moduleResolution: node +// @moduleResolution: bundler // @Filename: /node_modules/vue/package.json { "name": "vue", diff --git a/internal/fourslash/tests/gen/completionsImport_augmentation_test.go b/internal/fourslash/tests/gen/completionsImport_augmentation_test.go index a43ca7fc41..b3c2f3b1b5 100644 --- a/internal/fourslash/tests/gen/completionsImport_augmentation_test.go +++ b/internal/fourslash/tests/gen/completionsImport_augmentation_test.go @@ -37,7 +37,7 @@ declare module "./a" { Detail: PtrTo("const foo: 0"), Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -48,7 +48,7 @@ declare module "./a" { Detail: PtrTo("const bar: 0"), Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, diff --git a/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go b/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go index d2da944d10..7d130aa585 100644 --- a/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go +++ b/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go @@ -51,7 +51,7 @@ fo/*dts*/` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/a/index", + ModuleSpecifier: "a", }, })), Detail: PtrTo("const foo: 0"), diff --git a/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go index 6e674f3371..02f289f9d3 100644 --- a/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go +++ b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go @@ -34,7 +34,7 @@ someMo/**/` Label: "someModule", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/someModule", + ModuleSpecifier: "./someModule", }, })), Detail: PtrTo("(property) default: 1"), @@ -46,7 +46,7 @@ someMo/**/` Label: "someModule", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/someModule", + ModuleSpecifier: "./someModule", }, })), Detail: PtrTo("const someModule: 0"), @@ -59,7 +59,7 @@ someMo/**/` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "someModule", - Source: "/someModule", + Source: "./someModule", AutoImportData: &ls.AutoImportData{ ExportName: "default", FileName: PtrTo("/someModule.ts"), diff --git a/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go b/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go index 1ac87eb731..197f9a17b6 100644 --- a/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go +++ b/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go @@ -35,7 +35,7 @@ conca/**/` Label: "concat", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/bar/concat", + ModuleSpecifier: "bar/concat", }, })), Detail: PtrTo("const concat: 0"), @@ -48,7 +48,7 @@ conca/**/` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "concat", - Source: "/node_modules/bar/concat", + Source: "bar/concat", Description: "Add import from \"bar/concat\"", NewFileContent: PtrTo(`import { concat } from "bar/concat"; diff --git a/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go b/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go index 5c6c37b0de..b522e96693 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go @@ -33,7 +33,7 @@ f/**/;` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function foo(): void"), @@ -46,7 +46,7 @@ f/**/;` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Update import from \"./a\"", NewFileContent: PtrTo(`import foo, { x } from "./a"; f;`), diff --git a/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go b/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go index 6b2e673417..49d1215d71 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go @@ -32,7 +32,7 @@ f/**/;` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function foo(): void"), @@ -45,7 +45,7 @@ f/**/;` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Update import from \"./a\"", NewFileContent: PtrTo(`import foo, * as a from "./a"; f;`), diff --git a/internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go b/internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go index 407a46bc41..4ffdba061b 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_alreadyExistedWithRename_test.go @@ -32,7 +32,7 @@ f/**/;` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function foo(): void"), @@ -45,7 +45,7 @@ f/**/;` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import foo from "./a"; import f_o_o from "./a"; diff --git a/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go index 8a96c34cf3..4145b4d095 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go @@ -15,6 +15,8 @@ func TestCompletionsImport_default_symbolName(t *testing.T) { t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs +// @esModuleInterop: false +// @allowSyntheticDefaultImports: false // @Filename: /node_modules/@types/range-parser/index.d.ts declare function RangeParser(): string; declare namespace RangeParser { @@ -39,7 +41,7 @@ R/*0*/` Kind: PtrTo(lsproto.CompletionItemKindFunction), Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/@types/range-parser/index", + ModuleSpecifier: "range-parser", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -51,7 +53,7 @@ R/*0*/` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "RangeParser", - Source: "/node_modules/@types/range-parser/index", + Source: "range-parser", Description: "Add import from \"range-parser\"", NewFileContent: PtrTo(`import RangeParser = require("range-parser"); diff --git a/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go b/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go index 6ed0bebc1a..730e2ccbfe 100644 --- a/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go +++ b/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go @@ -23,7 +23,7 @@ acb/*2*/;` f.GoToMarker(t, "1") f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "abc", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { abc } from "./a"; @@ -32,10 +32,11 @@ acb;`), f.GoToMarker(t, "2") f.VerifyApplyCodeActionFromCompletion(t, PtrTo("2"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "abc", - Source: "/a", + Source: "./a", AutoImportData: &ls.AutoImportData{ - ExportName: "abc", - FileName: PtrTo("/a.ts"), + ExportName: "abc", + FileName: PtrTo("/a.ts"), + ModuleSpecifier: "./a", }, Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { abc } from "./a"; diff --git a/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go index c849f51857..f3b7805d04 100644 --- a/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go @@ -15,6 +15,9 @@ func TestCompletionsImport_exportEquals_anonymous(t *testing.T) { t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @noLib: true +// @module: commonjs +// @esModuleInterop: false +// @allowSyntheticDefaultImports: false // @Filename: /src/foo-bar.ts export = 0; // @Filename: /src/b.ts @@ -46,7 +49,7 @@ fooB/*1*/` Label: "fooBar", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/src/foo-bar", + ModuleSpecifier: "./foo-bar", }, })), Detail: PtrTo("(property) export=: 0"), @@ -59,7 +62,7 @@ fooB/*1*/` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "fooBar", - Source: "/src/foo-bar", + Source: "./foo-bar", Description: "Add import from \"./foo-bar\"", NewFileContent: PtrTo(`import fooBar = require("./foo-bar") diff --git a/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go index 5d1bbd0d3b..071fb88853 100644 --- a/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go @@ -15,6 +15,8 @@ func TestCompletionsImport_exportEquals(t *testing.T) { t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs +// @esModuleInterop: false +// @allowSyntheticDefaultImports: false // @Filename: /a.d.ts declare function a(): void; declare namespace a { @@ -37,7 +39,7 @@ let x: b/*1*/;` Label: "a", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -58,7 +60,7 @@ let x: b/*1*/;` Label: "b", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -69,7 +71,7 @@ let x: b/*1*/;` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "b", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { b } from "./a"; @@ -78,7 +80,7 @@ let x: b;`), }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "a", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { b } from "./a"; import a = require("./a"); diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go index f3ea0e1041..7d7f135186 100644 --- a/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go +++ b/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go @@ -52,7 +52,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/react/index", + ModuleSpecifier: "react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), @@ -62,7 +62,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/fake-react/index", + ModuleSpecifier: "fake-react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go index 18d1fd34b0..bd53aa7be8 100644 --- a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesImplicit_test.go @@ -49,7 +49,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/@types/react/index", + ModuleSpecifier: "react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go index 9b6186bb92..27ccbf38d8 100644 --- a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_@typesOnly_test.go @@ -49,7 +49,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/@types/react/index", + ModuleSpecifier: "react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go index 6dbf39b3fc..52dee82f49 100644 --- a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_direct_test.go @@ -51,7 +51,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/react/index", + ModuleSpecifier: "react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go index a3a786ecae..f2116414aa 100644 --- a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_nested_test.go @@ -57,7 +57,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/react/index", + ModuleSpecifier: "react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), @@ -78,7 +78,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/dir/node_modules/redux/index", + ModuleSpecifier: "redux", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go index da4da91923..8997b6e93a 100644 --- a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_peerDependencies_test.go @@ -51,7 +51,7 @@ const x = Re/**/` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/react/index", + ModuleSpecifier: "react", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_importType_test.go b/internal/fourslash/tests/gen/completionsImport_importType_test.go index 195afbd428..28c24d84d2 100644 --- a/internal/fourslash/tests/gen/completionsImport_importType_test.go +++ b/internal/fourslash/tests/gen/completionsImport_importType_test.go @@ -36,7 +36,7 @@ export const m = 0; Label: "C", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("class C"), @@ -47,7 +47,7 @@ export const m = 0; Label: "T", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("type T = number"), @@ -62,7 +62,7 @@ export const m = 0; }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo("0"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "C", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { C } from "./a"; @@ -72,7 +72,7 @@ export const m = 0; }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo("1"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "T", - Source: "/a", + Source: "./a", Description: "Change 'T' to 'import(\"./a\").T'", NewFileContent: PtrTo(`import { C } from "./a"; diff --git a/internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go b/internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go index 4e75441fad..1dc2706366 100644 --- a/internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go +++ b/internal/fourslash/tests/gen/completionsImport_jsxOpeningTagImportDefault_test.go @@ -36,7 +36,7 @@ export function Index() { Label: "Component", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/component", + ModuleSpecifier: "./component", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, @@ -50,7 +50,7 @@ export function Index() { }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "Component", - Source: "/component", + Source: "./component", Description: "Add import from \"./component\"", NewFileContent: PtrTo(`import Component from "./component"; diff --git a/internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go b/internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go index 21f308404e..7b62f55d6c 100644 --- a/internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go +++ b/internal/fourslash/tests/gen/completionsImport_mergedReExport_test.go @@ -51,7 +51,7 @@ C/**/` Label: "Config", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/home/src/workspaces/project/node_modules/@jest/types/index", + ModuleSpecifier: "@jest/types", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, diff --git a/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go b/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go index 1bdc989954..1ebc60f7f1 100644 --- a/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go +++ b/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go @@ -33,7 +33,7 @@ f/**/;` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function foo(): void"), @@ -46,7 +46,7 @@ f/**/;` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Update import from \"./a\"", NewFileContent: PtrTo(`import { foo, x } from "./a"; f;`), diff --git a/internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go b/internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go index 626a76378b..73b4255412 100644 --- a/internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go +++ b/internal/fourslash/tests/gen/completionsImport_named_didNotExistBefore_test.go @@ -40,7 +40,7 @@ t/**/` Label: "Test1", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function Test1(): void"), @@ -48,14 +48,14 @@ t/**/` AdditionalTextEdits: fourslash.AnyTextEdits, SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), LabelDetails: &lsproto.CompletionItemLabelDetails{ - Description: PtrTo("/a"), + Description: PtrTo("./a"), }, }, }, true), }, }).AndApplyCodeAction(t, &fourslash.CompletionsExpectedCodeAction{ Name: "Test1", - Source: "/a", + Source: "./a", Description: "Update import from \"./a\"", NewFileContent: `import { Test1, Test2 } from "./a"; t`, diff --git a/internal/fourslash/tests/gen/completionsImport_named_namespaceImportExists_test.go b/internal/fourslash/tests/gen/completionsImport_named_namespaceImportExists_test.go index a8b3079242..a8eb3a70da 100644 --- a/internal/fourslash/tests/gen/completionsImport_named_namespaceImportExists_test.go +++ b/internal/fourslash/tests/gen/completionsImport_named_namespaceImportExists_test.go @@ -32,7 +32,7 @@ f/**/;` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function foo(): void"), @@ -45,7 +45,7 @@ f/**/;` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Change 'foo' to 'a.foo'", NewFileContent: PtrTo(`import * as a from "./a"; a.f;`), diff --git a/internal/fourslash/tests/gen/completionsImport_noSemicolons_test.go b/internal/fourslash/tests/gen/completionsImport_noSemicolons_test.go index a1698b4ea4..b9036b1292 100644 --- a/internal/fourslash/tests/gen/completionsImport_noSemicolons_test.go +++ b/internal/fourslash/tests/gen/completionsImport_noSemicolons_test.go @@ -21,7 +21,7 @@ const z = fo/**/` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { foo } from "./a" diff --git a/internal/fourslash/tests/gen/completionsImport_ofAlias_preferShortPath_test.go b/internal/fourslash/tests/gen/completionsImport_ofAlias_preferShortPath_test.go index 25a40b43cf..3c6b93f2c4 100644 --- a/internal/fourslash/tests/gen/completionsImport_ofAlias_preferShortPath_test.go +++ b/internal/fourslash/tests/gen/completionsImport_ofAlias_preferShortPath_test.go @@ -14,7 +14,7 @@ func TestCompletionsImport_ofAlias_preferShortPath(t *testing.T) { t.Parallel() t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") - const content = `// @moduleResolution: node + const content = `// @moduleResolution: node10 // @module: commonJs // @noLib: true // @Filename: /foo/index.ts diff --git a/internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go b/internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go index 642bb6d180..084836b20b 100644 --- a/internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go +++ b/internal/fourslash/tests/gen/completionsImport_previousTokenIsSemicolon_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_previousTokenIsSemicolon(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export function foo() {} @@ -32,7 +32,7 @@ import * as a from 'a'; Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("function foo(): void"), diff --git a/internal/fourslash/tests/gen/completionsImport_reExportDefault_test.go b/internal/fourslash/tests/gen/completionsImport_reExportDefault_test.go index ed6acd2d99..f6e4129652 100644 --- a/internal/fourslash/tests/gen/completionsImport_reExportDefault_test.go +++ b/internal/fourslash/tests/gen/completionsImport_reExportDefault_test.go @@ -15,7 +15,7 @@ func TestCompletionsImport_reExportDefault(t *testing.T) { t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: esnext -// @moduleResolution: node +// @moduleResolution: node10 // @Filename: /a/b/impl.ts export default function foo() {} // @Filename: /a/index.ts diff --git a/internal/fourslash/tests/gen/completionsImport_reExport_wrongName_test.go b/internal/fourslash/tests/gen/completionsImport_reExport_wrongName_test.go index 04244cfb96..4651f917c1 100644 --- a/internal/fourslash/tests/gen/completionsImport_reExport_wrongName_test.go +++ b/internal/fourslash/tests/gen/completionsImport_reExport_wrongName_test.go @@ -14,7 +14,7 @@ func TestCompletionsImport_reExport_wrongName(t *testing.T) { t.Parallel() t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") - const content = `// @moduleResolution: node + const content = `// @moduleResolution: bundler // @Filename: /a.ts export const x = 0; // @Filename: /index.ts @@ -35,7 +35,7 @@ export { x as y } from "./a"; Label: "x", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("const x: 0"), @@ -46,7 +46,7 @@ export { x as y } from "./a"; Label: "y", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/index", + ModuleSpecifier: ".", }, })), Detail: PtrTo("(alias) const y: 0\nexport y"), @@ -58,7 +58,7 @@ export { x as y } from "./a"; }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "x", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import { x } from "./a"; @@ -66,7 +66,7 @@ export { x as y } from "./a"; }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "y", - Source: "/index", + Source: ".", Description: "Add import from \".\"", NewFileContent: PtrTo(`import { y } from "."; import { x } from "./a"; diff --git a/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go b/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go index 6756881e43..8ec12de0ba 100644 --- a/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go +++ b/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go @@ -33,7 +33,7 @@ x/**/` Label: "x", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("(alias) const x: 0\nimport x"), @@ -45,7 +45,7 @@ x/**/` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "x", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`const { x } = require("./a"); diff --git a/internal/fourslash/tests/gen/completionsImport_require_addToExisting_test.go b/internal/fourslash/tests/gen/completionsImport_require_addToExisting_test.go index d2fc4257e0..e0ee34df82 100644 --- a/internal/fourslash/tests/gen/completionsImport_require_addToExisting_test.go +++ b/internal/fourslash/tests/gen/completionsImport_require_addToExisting_test.go @@ -36,7 +36,7 @@ x/**/` Label: "x", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("(alias) const x: 0\nimport x"), @@ -48,7 +48,7 @@ x/**/` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "x", - Source: "/a", + Source: "./a", Description: "Update import from \"./a\"", NewFileContent: PtrTo(`const { f, x } = require("./a"); diff --git a/internal/fourslash/tests/gen/completionsImport_require_test.go b/internal/fourslash/tests/gen/completionsImport_require_test.go index 9696b05d3b..4829099b64 100644 --- a/internal/fourslash/tests/gen/completionsImport_require_test.go +++ b/internal/fourslash/tests/gen/completionsImport_require_test.go @@ -33,7 +33,7 @@ fo/*b*/` Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("const foo: 0"), @@ -46,7 +46,7 @@ fo/*b*/` }) f.VerifyApplyCodeActionFromCompletion(t, PtrTo("b"), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import * as s from "something"; import { foo } from "./a"; diff --git a/internal/fourslash/tests/gen/completionsImport_tsx_test.go b/internal/fourslash/tests/gen/completionsImport_tsx_test.go index bd6b5d4314..4f8e7c38b5 100644 --- a/internal/fourslash/tests/gen/completionsImport_tsx_test.go +++ b/internal/fourslash/tests/gen/completionsImport_tsx_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_tsx(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @noLib: true // @jsx: preserve @@ -34,7 +34,7 @@ export default function Foo() {}; Label: "Foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, diff --git a/internal/fourslash/tests/gen/completionsImport_typeOnly_test.go b/internal/fourslash/tests/gen/completionsImport_typeOnly_test.go index abad22d066..27d374d54e 100644 --- a/internal/fourslash/tests/gen/completionsImport_typeOnly_test.go +++ b/internal/fourslash/tests/gen/completionsImport_typeOnly_test.go @@ -13,6 +13,7 @@ func TestCompletionsImport_typeOnly(t *testing.T) { t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @target: esnext +// @moduleResolution: bundler // @Filename: /a.ts export class A {} export class B {} @@ -23,7 +24,7 @@ const b: B/**/` f.GoToFile(t, "/b.ts") f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "B", - Source: "/a", + Source: "./a", Description: "Update import from \"./a\"", NewFileContent: PtrTo(`import type { A, B } from './a'; const b: B`), diff --git a/internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go b/internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go index 375a34239c..f76355c039 100644 --- a/internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go +++ b/internal/fourslash/tests/gen/completionsImport_umdDefaultNoCrash1_test.go @@ -14,7 +14,7 @@ func TestCompletionsImport_umdDefaultNoCrash1(t *testing.T) { t.Parallel() t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") - const content = `// @moduleResolution: node + const content = `// @moduleResolution: bundler // @allowJs: true // @checkJs: true // @Filename: /node_modules/dottie/package.json @@ -59,7 +59,7 @@ func TestCompletionsImport_umdDefaultNoCrash1(t *testing.T) { AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/dottie/dottie", + ModuleSpecifier: "dottie", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go b/internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go index ccd2b5d1ee..a1dfd2d6d8 100644 --- a/internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go +++ b/internal/fourslash/tests/gen/completionsImport_umdModules2_moduleExports_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_umdModules2_moduleExports(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @filename: /package.json { "dependencies": { "@types/classnames": "*" } } @@ -43,7 +43,7 @@ const el1 =
foo
;` AdditionalTextEdits: fourslash.AnyTextEdits, Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/node_modules/@types/classnames/index", + ModuleSpecifier: "classnames", }, })), SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), diff --git a/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go b/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go index e2875263f3..463ea288be 100644 --- a/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go +++ b/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go @@ -12,7 +12,10 @@ func TestCompletionsImport_weirdDefaultSynthesis(t *testing.T) { t.Parallel() t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") - const content = `// @Filename: /collection.ts + const content = `// @module: commonjs +// @esModuleInterop: false +// @allowSyntheticDefaultImports: false +// @Filename: /collection.ts class Collection { public static readonly default: typeof Collection = Collection; } @@ -22,7 +25,7 @@ Colle/**/` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "Collection", - Source: "/collection", + Source: "./collection", Description: "Add import from \"./collection\"", NewFileContent: PtrTo(`import Collection = require("./collection"); diff --git a/internal/fourslash/tests/gen/completionsRecommended_namespace_test.go b/internal/fourslash/tests/gen/completionsRecommended_namespace_test.go index dbe73c56be..f81d6b2f98 100644 --- a/internal/fourslash/tests/gen/completionsRecommended_namespace_test.go +++ b/internal/fourslash/tests/gen/completionsRecommended_namespace_test.go @@ -60,7 +60,7 @@ alpha.f(new /*c1*/);` Label: "Name", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/a", + ModuleSpecifier: "./a", }, })), Detail: PtrTo("namespace Name"), diff --git a/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go b/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go index c7c0d62443..104b77761c 100644 --- a/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go +++ b/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go @@ -32,7 +32,7 @@ export const foo = 0; Label: "foo", Data: PtrTo(any(&ls.CompletionItemData{ AutoImport: &ls.AutoImportData{ - ModuleSpecifier: "/foo", + ModuleSpecifier: "./foo", }, })), AdditionalTextEdits: fourslash.AnyTextEdits, diff --git a/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go b/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go index 8487cffab9..27cb234cac 100644 --- a/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go +++ b/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go @@ -19,7 +19,7 @@ a/**/` f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "a", - Source: "/a", + Source: "./a", Description: "Add import from \"./a\"", NewFileContent: PtrTo(`import a from "./a"; diff --git a/internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go b/internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go index bf900f540b..d5b712b078 100644 --- a/internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go +++ b/internal/fourslash/tests/gen/importNameCodeFixExportAsDefault_test.go @@ -20,7 +20,7 @@ export { foo as default } f := fourslash.NewFourslash(t, nil /*capabilities*/, content) f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ Name: "foo", - Source: "/foo", + Source: "./foo", Description: "Add import from \"./foo\"", NewFileContent: PtrTo(`import foo from "./foo"; diff --git a/internal/fourslash/tests/gen/importTypeCompletions5_test.go b/internal/fourslash/tests/gen/importTypeCompletions5_test.go index bfe7daff8d..543d69aa3f 100644 --- a/internal/fourslash/tests/gen/importTypeCompletions5_test.go +++ b/internal/fourslash/tests/gen/importTypeCompletions5_test.go @@ -14,7 +14,8 @@ func TestImportTypeCompletions5(t *testing.T) { t.Parallel() t.Skip() defer testutil.RecoverAndFail(t, "Panic on fourslash test") - const content = `// @esModuleInterop: false + const content = `// @allowSyntheticDefaultImports: false +// @esModuleInterop: false // @Filename: /foo.ts interface Foo { }; export = Foo; From c46c95aff77643824adfef1942d4bf1396be6ce6 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 20 Oct 2025 13:29:50 -0700 Subject: [PATCH 04/17] Make auto-import order deterministic --- internal/fourslash/_scripts/failingTests.txt | 1 - internal/fourslash/fourslash.go | 33 +++++++++++++------ .../autoImportSameNameDefaultExported_test.go | 2 +- internal/ls/autoimports.go | 19 ++++++----- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index b7baf607c6..90d090cdd2 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -26,7 +26,6 @@ TestAutoImportProvider_wildcardExports1 TestAutoImportProvider_wildcardExports2 TestAutoImportProvider_wildcardExports3 TestAutoImportReExportFromAmbientModule -TestAutoImportSameNameDefaultExported TestAutoImportSortCaseSensitivity2 TestAutoImportTypeOnlyPreferred1 TestAutoImportVerbatimTypeOnly1 diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 33187eed6e..a5ea2f5a01 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -673,9 +673,9 @@ func (f *FourslashTest) verifyCompletionsItems(t *testing.T, prefix string, actu } return } - nameToActualItem := make(map[string]*lsproto.CompletionItem) + nameToActualItems := make(map[string][]*lsproto.CompletionItem) for _, item := range actual { - nameToActualItem[item.Label] = item + nameToActualItems[item.Label] = append(nameToActualItems[item.Label], item) } if expected.Unsorted != nil { if expected.Includes != nil { @@ -687,24 +687,30 @@ func (f *FourslashTest) verifyCompletionsItems(t *testing.T, prefix string, actu for _, item := range expected.Unsorted { switch item := item.(type) { case string: - _, ok := nameToActualItem[item] + _, ok := nameToActualItems[item] if !ok { t.Fatalf("%sLabel '%s' not found in actual items. Actual items: %s", prefix, item, cmp.Diff(actual, nil)) } - delete(nameToActualItem, item) + delete(nameToActualItems, item) case *lsproto.CompletionItem: - actualItem, ok := nameToActualItem[item.Label] + actualItems, ok := nameToActualItems[item.Label] if !ok { t.Fatalf("%sLabel '%s' not found in actual items. Actual items: %s", prefix, item.Label, cmp.Diff(actual, nil)) } - delete(nameToActualItem, item.Label) + actualItem := actualItems[0] + actualItems = actualItems[1:] + if len(actualItems) == 0 { + delete(nameToActualItems, item.Label) + } else { + nameToActualItems[item.Label] = actualItems + } f.verifyCompletionItem(t, prefix+"Includes completion item mismatch for label "+item.Label+": ", actualItem, item) default: t.Fatalf("%sExpected completion item to be a string or *lsproto.CompletionItem, got %T", prefix, item) } } if len(expected.Unsorted) != len(actual) { - unmatched := slices.Collect(maps.Keys(nameToActualItem)) + unmatched := slices.Collect(maps.Keys(nameToActualItems)) t.Fatalf("%sAdditional completions found but not included in 'unsorted': %s", prefix, strings.Join(unmatched, "\n")) } return @@ -713,15 +719,22 @@ func (f *FourslashTest) verifyCompletionsItems(t *testing.T, prefix string, actu for _, item := range expected.Includes { switch item := item.(type) { case string: - _, ok := nameToActualItem[item] + _, ok := nameToActualItems[item] if !ok { t.Fatalf("%sLabel '%s' not found in actual items. Actual items: %s", prefix, item, cmp.Diff(actual, nil)) } case *lsproto.CompletionItem: - actualItem, ok := nameToActualItem[item.Label] + actualItems, ok := nameToActualItems[item.Label] if !ok { t.Fatalf("%sLabel '%s' not found in actual items. Actual items: %s", prefix, item.Label, cmp.Diff(actual, nil)) } + actualItem := actualItems[0] + actualItems = actualItems[1:] + if len(actualItems) == 0 { + delete(nameToActualItems, item.Label) + } else { + nameToActualItems[item.Label] = actualItems + } f.verifyCompletionItem(t, prefix+"Includes completion item mismatch for label "+item.Label+": ", actualItem, item) default: t.Fatalf("%sExpected completion item to be a string or *lsproto.CompletionItem, got %T", prefix, item) @@ -729,7 +742,7 @@ func (f *FourslashTest) verifyCompletionsItems(t *testing.T, prefix string, actu } } for _, exclude := range expected.Excludes { - if _, ok := nameToActualItem[exclude]; ok { + if _, ok := nameToActualItems[exclude]; ok { t.Fatalf("%sLabel '%s' should not be in actual items but was found. Actual items: %s", prefix, exclude, cmp.Diff(actual, nil)) } } diff --git a/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go b/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go index 36855f75c7..1c4e6a85be 100644 --- a/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go +++ b/internal/fourslash/tests/gen/autoImportSameNameDefaultExported_test.go @@ -12,7 +12,7 @@ import ( func TestAutoImportSameNameDefaultExported(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @Filename: /node_modules/antd/index.d.ts diff --git a/internal/ls/autoimports.go b/internal/ls/autoimports.go index cf89e08fab..4f3005db98 100644 --- a/internal/ls/autoimports.go +++ b/internal/ls/autoimports.go @@ -69,7 +69,7 @@ type CachedSymbolExportInfo struct { } type exportInfoMap struct { - exportInfo collections.MultiMap[ExportInfoMapKey, CachedSymbolExportInfo] + exportInfo collections.OrderedMap[ExportInfoMapKey, []*CachedSymbolExportInfo] symbols map[int]symbolExportEntry exportInfoId int usableByFileName tspath.Path @@ -83,7 +83,7 @@ type exportInfoMap struct { func (e *exportInfoMap) clear() { e.symbols = map[int]symbolExportEntry{} - e.exportInfo = collections.MultiMap[ExportInfoMapKey, CachedSymbolExportInfo]{} + e.exportInfo = collections.OrderedMap[ExportInfoMapKey, []*CachedSymbolExportInfo]{} e.usableByFileName = "" } @@ -91,7 +91,7 @@ func (e *exportInfoMap) get(importingFile tspath.Path, ch *checker.Checker, key if e.usableByFileName != importingFile { return nil } - return core.Map(e.exportInfo.Get(key), func(info CachedSymbolExportInfo) *SymbolExportInfo { return e.rehydrateCachedInfo(ch, info) }) + return core.Map(e.exportInfo.GetOrZero(key), func(info *CachedSymbolExportInfo) *SymbolExportInfo { return e.rehydrateCachedInfo(ch, info) }) } func (e *exportInfoMap) add( @@ -193,7 +193,9 @@ func (e *exportInfoMap) add( if moduleFile != nil { moduleFileName = moduleFile.FileName() } - e.exportInfo.Add(newExportInfoMapKey(symbolName, symbol, moduleKey, ch), CachedSymbolExportInfo{ + key := newExportInfoMapKey(symbolName, symbol, moduleKey, ch) + infos := e.exportInfo.GetOrZero(key) + infos = append(infos, &CachedSymbolExportInfo{ id: id, symbolTableKey: symbolTableKey, symbolName: symbolName, @@ -209,6 +211,7 @@ func (e *exportInfoMap) add( targetFlags: target.Flags, isFromPackageJson: isFromPackageJson, }) + e.exportInfo.Set(key, infos) } func (e *exportInfoMap) search( @@ -221,13 +224,13 @@ func (e *exportInfoMap) search( if importingFile != e.usableByFileName { return nil } - for key, info := range e.exportInfo.M { + for key, info := range e.exportInfo.Entries() { symbolName, ambientModuleName := key.SymbolName, key.AmbientModuleName if preferCapitalized && info[0].capitalizedSymbolName != "" { symbolName = info[0].capitalizedSymbolName } if matches(symbolName, info[0].targetFlags) { - rehydrated := core.Map(info, func(info CachedSymbolExportInfo) *SymbolExportInfo { + rehydrated := core.Map(info, func(info *CachedSymbolExportInfo) *SymbolExportInfo { return e.rehydrateCachedInfo(ch, info) }) filtered := core.FilterIndex(rehydrated, func(r *SymbolExportInfo, i int, _ []*SymbolExportInfo) bool { @@ -254,7 +257,7 @@ func (e *exportInfoMap) isNotShadowedByDeeperNodeModulesPackage(info *SymbolExpo return !ok || strings.HasPrefix(info.moduleFileName, packageDeepestNodeModulesPath) } -func (e *exportInfoMap) rehydrateCachedInfo(ch *checker.Checker, info CachedSymbolExportInfo) *SymbolExportInfo { +func (e *exportInfoMap) rehydrateCachedInfo(ch *checker.Checker, info *CachedSymbolExportInfo) *SymbolExportInfo { if info.symbol != nil && info.moduleSymbol != nil { return &SymbolExportInfo{ symbol: info.symbol, @@ -400,7 +403,7 @@ func NewExportInfoMap(globalsTypingCacheLocation string) *exportInfoMap { return &exportInfoMap{ packages: map[string]string{}, symbols: map[int]symbolExportEntry{}, - exportInfo: collections.MultiMap[ExportInfoMapKey, CachedSymbolExportInfo]{}, + exportInfo: collections.OrderedMap[ExportInfoMapKey, []*CachedSymbolExportInfo]{}, globalTypingsCacheLocation: globalsTypingCacheLocation, } } From 746441b53f0097bc713393aee04a781d9fe64e4c Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 20 Oct 2025 16:57:27 -0700 Subject: [PATCH 05/17] Fix first batch of bugs --- .../fourslash/_scripts/convertFourslash.mts | 2 +- internal/fourslash/_scripts/failingTests.txt | 16 ------- internal/fourslash/fourslash.go | 10 ++-- ...utoImportReExportFromAmbientModule_test.go | 4 +- .../gen/autoImportTypeOnlyPreferred1_test.go | 2 +- .../gen/autoImportVerbatimTypeOnly1_test.go | 4 +- .../gen/completionsImportFromJSXTag_test.go | 2 +- ...ionsImportModuleAugmentationWithJS_test.go | 2 +- .../completionsImportPathsConflict_test.go | 4 +- .../gen/completionsImportTypeKeyword_test.go | 2 +- .../completionsImportYieldExpression_test.go | 2 +- .../tests/gen/completionsImport_46332_test.go | 2 +- .../gen/completionsImport_ambient_test.go | 2 +- ...ionsImport_defaultAndNamedConflict_test.go | 2 +- ...nsImport_default_addToNamedImports_test.go | 2 +- ...mport_default_addToNamespaceImport_test.go | 2 +- ...mpletionsImport_default_symbolName_test.go | 2 +- ...sImport_details_withMisspelledName_test.go | 2 +- .../completionsImport_exportEquals_test.go | 2 +- ...named_exportEqualsNamespace_merged_test.go | 2 +- .../gen/completionsImport_require_test.go | 2 +- ...etionsImport_weirdDefaultSynthesis_test.go | 2 +- .../importNameCodeFixDefaultExport6_test.go | 2 +- internal/ls/autoimports.go | 2 +- internal/ls/autoimportsexportinfo.go | 3 +- internal/ls/changetrackerimpl.go | 4 +- internal/ls/completions.go | 48 +++++++++---------- 27 files changed, 59 insertions(+), 72 deletions(-) diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 94001caab2..72a6d879a6 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -483,7 +483,7 @@ function parseVerifyApplyCodeActionArgs(arg: ts.Expression): string | undefined console.error(`Expected string literal for fileName in verify.applyCodeActionFromCompletion data, got ${dataProp.initializer.getText()}`); return undefined; } - dataProps.push(`FileName: PtrTo(${getGoStringLiteral(fileNameInit.text)}),`); + dataProps.push(`FileName: ${getGoStringLiteral(fileNameInit.text)},`); break; default: console.error(`Unrecognized property in verify.applyCodeActionFromCompletion data: ${dataProp.getText()}`); diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 90d090cdd2..3abe76449c 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -25,9 +25,7 @@ TestAutoImportProvider_namespaceSameNameAsIntrinsic TestAutoImportProvider_wildcardExports1 TestAutoImportProvider_wildcardExports2 TestAutoImportProvider_wildcardExports3 -TestAutoImportReExportFromAmbientModule TestAutoImportSortCaseSensitivity2 -TestAutoImportTypeOnlyPreferred1 TestAutoImportVerbatimTypeOnly1 TestBestCommonTypeObjectLiterals TestBestCommonTypeObjectLiterals1 @@ -155,32 +153,22 @@ TestCompletionsExportImport TestCompletionsGenericTypeWithMultipleBases1 TestCompletionsImportBaseUrl TestCompletionsImportDefaultExportCrash2 -TestCompletionsImportFromJSXTag -TestCompletionsImportModuleAugmentationWithJS TestCompletionsImportOrExportSpecifier -TestCompletionsImportPathsConflict -TestCompletionsImportTypeKeyword -TestCompletionsImportYieldExpression TestCompletionsImport_46332 -TestCompletionsImport_ambient TestCompletionsImport_augmentation TestCompletionsImport_compilerOptionsModule TestCompletionsImport_defaultAndNamedConflict TestCompletionsImport_defaultFalsePositive -TestCompletionsImport_default_addToNamedImports -TestCompletionsImport_default_addToNamespaceImport TestCompletionsImport_default_alreadyExistedWithRename TestCompletionsImport_default_anonymous TestCompletionsImport_default_didNotExistBefore TestCompletionsImport_default_exportDefaultIdentifier TestCompletionsImport_default_fromMergedDeclarations -TestCompletionsImport_default_symbolName TestCompletionsImport_details_withMisspelledName TestCompletionsImport_duplicatePackages_scoped TestCompletionsImport_duplicatePackages_scopedTypes TestCompletionsImport_duplicatePackages_scopedTypesAndNotTypes TestCompletionsImport_duplicatePackages_types -TestCompletionsImport_exportEquals TestCompletionsImport_exportEqualsNamespace_noDuplicate TestCompletionsImport_exportEquals_anonymous TestCompletionsImport_exportEquals_global @@ -199,7 +187,6 @@ TestCompletionsImport_multipleWithSameName TestCompletionsImport_named_addToNamedImports TestCompletionsImport_named_didNotExistBefore TestCompletionsImport_named_exportEqualsNamespace -TestCompletionsImport_named_exportEqualsNamespace_merged TestCompletionsImport_named_fromMergedDeclarations TestCompletionsImport_named_namespaceImportExists TestCompletionsImport_noSemicolons @@ -209,7 +196,6 @@ TestCompletionsImport_quoteStyle TestCompletionsImport_reExportDefault TestCompletionsImport_reExportDefault2 TestCompletionsImport_reExport_wrongName -TestCompletionsImport_require TestCompletionsImport_require_addNew TestCompletionsImport_require_addToExisting TestCompletionsImport_sortingModuleSpecifiers @@ -217,7 +203,6 @@ TestCompletionsImport_typeOnly TestCompletionsImport_umdDefaultNoCrash1 TestCompletionsImport_uriStyleNodeCoreModules1 TestCompletionsImport_uriStyleNodeCoreModules2 -TestCompletionsImport_weirdDefaultSynthesis TestCompletionsImport_windowsPathsProjectRelative TestCompletionsInExport TestCompletionsInExport_moduleBlock @@ -316,7 +301,6 @@ TestImportCompletions_importsMap2 TestImportCompletions_importsMap3 TestImportCompletions_importsMap4 TestImportCompletions_importsMap5 -TestImportNameCodeFixDefaultExport6 TestImportNameCodeFixExportAsDefault TestImportSuggestionsCache_exportUndefined TestImportSuggestionsCache_invalidPackageJson diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index a5ea2f5a01..17b9ad1a47 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -829,7 +829,7 @@ func (f *FourslashTest) resolveCompletionItem(t *testing.T, item *lsproto.Comple t.Fatal(prefix + "Expected non-nil response for completion item resolve, got nil") } if !resultOk { - t.Fatalf(prefix+"Unexpected response type for completion item resolve: %T", resMsg.AsResponse().Result) + t.Fatalf(prefix+"Unexpected response type for completion item resolve: %T, Error: %v", resMsg.AsResponse().Result, resMsg.AsResponse().Error) } return result } @@ -878,7 +878,7 @@ func (f *FourslashTest) VerifyApplyCodeActionFromCompletion(t *testing.T, marker if options.AutoImportData != nil { return data.AutoImport != nil && data.AutoImport.ModuleSpecifier == options.AutoImportData.ModuleSpecifier && (options.AutoImportData.ExportName == "" || data.AutoImport.ExportName == options.AutoImportData.ExportName) && - (options.AutoImportData.FileName == nil || data.AutoImport.FileName == options.AutoImportData.FileName) && + (data.AutoImport.FileName == options.AutoImportData.FileName) && (options.AutoImportData.AmbientModuleName == nil || data.AutoImport.AmbientModuleName == options.AutoImportData.AmbientModuleName) && (options.AutoImportData.IsPackageJsonImport == core.TSUnknown || data.AutoImport.IsPackageJsonImport == options.AutoImportData.IsPackageJsonImport) } @@ -899,7 +899,11 @@ func (f *FourslashTest) VerifyApplyCodeActionFromCompletion(t *testing.T, marker t.Fatalf("Expected non-nil AdditionalTextEdits for code action completion item.") } f.applyTextEdits(t, *item.AdditionalTextEdits) - assert.Equal(t, f.getScriptInfo(f.activeFilename).content, options.NewFileContent, "File content after applying code action did not match expected content.") + if options.NewFileContent != nil { + assert.Equal(t, f.getScriptInfo(f.activeFilename).content, *options.NewFileContent, "File content after applying code action did not match expected content.") + } else if options.NewRangeContent != nil { + t.Fatal("!!! TODO") + } } func (f *FourslashTest) VerifyBaselineFindAllReferences( diff --git a/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go b/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go index bbcef82033..a685a1a371 100644 --- a/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go +++ b/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go @@ -12,7 +12,7 @@ import ( func TestAutoImportReExportFromAmbientModule(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /home/src/workspaces/project/tsconfig.json { @@ -69,7 +69,7 @@ access/**/` access`), AutoImportData: &ls.AutoImportData{ ExportName: "accessSync", - FileName: PtrTo("/home/src/workspaces/project/node_modules/@types/fs-extra/index.d.ts"), + FileName: "/home/src/workspaces/project/node_modules/@types/fs-extra/index.d.ts", ModuleSpecifier: "fs-extra", }, }) diff --git a/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go b/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go index e5e6dbeeec..3a89a0273c 100644 --- a/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go +++ b/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go @@ -12,7 +12,7 @@ import ( func TestAutoImportTypeOnlyPreferred1(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @verbatimModuleSyntax: true // @module: esnext diff --git a/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go b/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go index dcb9290d69..6d8622d386 100644 --- a/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go +++ b/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go @@ -28,7 +28,7 @@ const x: /**/` Description: "Add import from \"./mod.js\"", AutoImportData: &ls.AutoImportData{ ExportName: "I", - FileName: PtrTo("/mod.ts"), + FileName: "/mod.ts", ModuleSpecifier: "./mod.js", }, NewFileContent: PtrTo(`import type { I } from "./mod.js"; @@ -42,7 +42,7 @@ const x: `), Description: "Update import from \"./mod.js\"", AutoImportData: &ls.AutoImportData{ ExportName: "C", - FileName: PtrTo("/mod.ts"), + FileName: "/mod.ts", ModuleSpecifier: "./mod.js", }, NewFileContent: PtrTo(`import { C, type I } from "./mod.js"; diff --git a/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go b/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go index 535ec04f82..c0488b300a 100644 --- a/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go +++ b/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go @@ -10,7 +10,7 @@ import ( func TestCompletionsImportFromJSXTag(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @jsx: react // @Filename: /types.d.ts diff --git a/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go b/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go index 20e3032d3b..39ec087d07 100644 --- a/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go +++ b/internal/fourslash/tests/gen/completionsImportModuleAugmentationWithJS_test.go @@ -10,7 +10,7 @@ import ( func TestCompletionsImportModuleAugmentationWithJS(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/completionsImportPathsConflict_test.go b/internal/fourslash/tests/gen/completionsImportPathsConflict_test.go index 22b68c4e9e..da67a8a511 100644 --- a/internal/fourslash/tests/gen/completionsImportPathsConflict_test.go +++ b/internal/fourslash/tests/gen/completionsImportPathsConflict_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImportPathsConflict(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /tsconfig.json { @@ -58,7 +58,7 @@ import {} from "@reduxjs/toolkit"; Source: "@reduxjs/toolkit", AutoImportData: &ls.AutoImportData{ ExportName: "configureStore", - FileName: PtrTo("/src/configureStore.ts"), + FileName: "/src/configureStore.ts", ModuleSpecifier: "@reduxjs/toolkit", }, Description: "Update import from \"@reduxjs/toolkit\"", diff --git a/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go b/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go index 473717309d..42b83f978e 100644 --- a/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go +++ b/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImportTypeKeyword(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: node18 // @Filename: /os.d.ts diff --git a/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go b/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go index 287bb937c4..f0c76cee39 100644 --- a/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go +++ b/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go @@ -10,7 +10,7 @@ import ( func TestCompletionsImportYieldExpression(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export function a() {} diff --git a/internal/fourslash/tests/gen/completionsImport_46332_test.go b/internal/fourslash/tests/gen/completionsImport_46332_test.go index 7444e6d911..6b1e822f47 100644 --- a/internal/fourslash/tests/gen/completionsImport_46332_test.go +++ b/internal/fourslash/tests/gen/completionsImport_46332_test.go @@ -93,7 +93,7 @@ ref/**/` Description: "Update import from \"vue\"", AutoImportData: &ls.AutoImportData{ ExportName: "ref", - FileName: PtrTo("/node_modules/vue/dist/vue.d.ts"), + FileName: "/node_modules/vue/dist/vue.d.ts", }, NewFileContent: PtrTo(`import { ref } from "vue"; ref`), diff --git a/internal/fourslash/tests/gen/completionsImport_ambient_test.go b/internal/fourslash/tests/gen/completionsImport_ambient_test.go index b65751ae7a..611fdb9572 100644 --- a/internal/fourslash/tests/gen/completionsImport_ambient_test.go +++ b/internal/fourslash/tests/gen/completionsImport_ambient_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_ambient(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @Filename: a.d.ts diff --git a/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go index 02f289f9d3..b395553b5a 100644 --- a/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go +++ b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go @@ -62,7 +62,7 @@ someMo/**/` Source: "./someModule", AutoImportData: &ls.AutoImportData{ ExportName: "default", - FileName: PtrTo("/someModule.ts"), + FileName: "/someModule.ts", }, Description: "Add import from \"./someModule\"", NewFileContent: PtrTo(`import someModule from "./someModule"; diff --git a/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go b/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go index b522e96693..d98caac868 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_addToNamedImports_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_default_addToNamedImports(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export default function foo() {} diff --git a/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go b/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go index 49d1215d71..23d8638a44 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_addToNamespaceImport_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_default_addToNamespaceImport(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export default function foo() {} diff --git a/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go index 4145b4d095..bae20c6a6d 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_default_symbolName(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @esModuleInterop: false diff --git a/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go b/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go index 730e2ccbfe..f0201764ec 100644 --- a/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go +++ b/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_test.go @@ -35,7 +35,7 @@ acb;`), Source: "./a", AutoImportData: &ls.AutoImportData{ ExportName: "abc", - FileName: PtrTo("/a.ts"), + FileName: "/a.ts", ModuleSpecifier: "./a", }, Description: "Add import from \"./a\"", diff --git a/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go index 071fb88853..5a1ef9edd0 100644 --- a/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_exportEquals(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @esModuleInterop: false diff --git a/internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go b/internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go index dac8721bd1..5c403f6d48 100644 --- a/internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go +++ b/internal/fourslash/tests/gen/completionsImport_named_exportEqualsNamespace_merged_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_named_exportEqualsNamespace_merged(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: esnext // @Filename: /b.d.ts diff --git a/internal/fourslash/tests/gen/completionsImport_require_test.go b/internal/fourslash/tests/gen/completionsImport_require_test.go index 4829099b64..aab622f2ef 100644 --- a/internal/fourslash/tests/gen/completionsImport_require_test.go +++ b/internal/fourslash/tests/gen/completionsImport_require_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_require(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @allowJs: true // @Filename: /a.ts diff --git a/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go b/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go index 463ea288be..5514308ba0 100644 --- a/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go +++ b/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go @@ -10,7 +10,7 @@ import ( func TestCompletionsImport_weirdDefaultSynthesis(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @esModuleInterop: false diff --git a/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go b/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go index 27cb234cac..43b6d1076a 100644 --- a/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go +++ b/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go @@ -10,7 +10,7 @@ import ( func TestImportNameCodeFixDefaultExport6(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export default Math.foo; diff --git a/internal/ls/autoimports.go b/internal/ls/autoimports.go index 4f3005db98..1183007adc 100644 --- a/internal/ls/autoimports.go +++ b/internal/ls/autoimports.go @@ -724,7 +724,7 @@ func (l *LanguageService) createPackageJsonImportFilter(fromFile *ast.SourceFile } allowsImportingAmbientModule := func(moduleSymbol *ast.Symbol, moduleSpecifierResolutionHost modulespecifiers.ModuleSpecifierGenerationHost) bool { - if len(packageJsons) > 0 || moduleSymbol.ValueDeclaration == nil { + if len(packageJsons) == 0 || moduleSymbol.ValueDeclaration == nil { return true } diff --git a/internal/ls/autoimportsexportinfo.go b/internal/ls/autoimportsexportinfo.go index 65de5e82ad..a68767e964 100644 --- a/internal/ls/autoimportsexportinfo.go +++ b/internal/ls/autoimportsexportinfo.go @@ -8,6 +8,7 @@ import ( "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/scanner" + "github.com/microsoft/typescript-go/internal/stringutil" ) func (l *LanguageService) getExportInfos( @@ -31,7 +32,7 @@ func (l *LanguageService) getExportInfos( if moduleCount = moduleCount + 1; moduleCount%100 == 0 && ctx.Err() != nil { return } - if moduleFile == nil && moduleSymbol.Name != exportMapKey.AmbientModuleName { + if moduleFile == nil && stringutil.StripQuotes(moduleSymbol.Name) != exportMapKey.AmbientModuleName { return } seenExports := collections.Set[string]{} diff --git a/internal/ls/changetrackerimpl.go b/internal/ls/changetrackerimpl.go index e8f3d13e69..b36c1ea982 100644 --- a/internal/ls/changetrackerimpl.go +++ b/internal/ls/changetrackerimpl.go @@ -84,7 +84,7 @@ func (ct *changeTracker) computeNewText(change *trackerEdit, targetSourceFile *a if !(change.options.indentation != nil && *change.options.indentation != 0 || format.GetLineStartPositionForPosition(pos, targetSourceFile) == pos) { noIndent = strings.TrimLeftFunc(text, unicode.IsSpace) } - return change.options.prefix + noIndent // !!! +((!options.suffix || endsWith(noIndent, options.suffix)) ? "" : options.suffix); + return change.options.prefix + noIndent + core.IfElse(strings.HasSuffix(noIndent, change.options.suffix), "", change.options.suffix) } /** Note: this may mutate `nodeIn`. */ @@ -121,7 +121,6 @@ func getFormatCodeSettingsForWriting(options *format.FormatCodeSettings, sourceF return options } -/** Note: output node may be mutated input node. */ func (ct *changeTracker) getNonformattedText(node *ast.Node, sourceFile *ast.SourceFile) (string, *ast.Node) { nodeIn := node eofToken := ct.Factory.NewToken(ast.KindEndOfFile) @@ -146,6 +145,7 @@ func (ct *changeTracker) getNonformattedText(node *ast.Node, sourceFile *ast.Sou ).Write(nodeIn, sourceFile, writer, nil) text := writer.String() + text = strings.TrimSuffix(text, ct.newLine) // Newline artifact from printing a SourceFile instead of a node nodeOut := writer.AssignPositionsToNode(nodeIn, ct.NodeFactory) var sourceFileLike *ast.Node diff --git a/internal/ls/completions.go b/internal/ls/completions.go index 5697a74eaf..0df2347e8f 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -87,7 +87,7 @@ type completionDataData struct { location *ast.Node keywordFilters KeywordCompletionFilters literals []literalValue - symbolToOriginInfoMap map[ast.SymbolId]*symbolOriginInfo + symbolToOriginInfoMap map[int]*symbolOriginInfo symbolToSortTextMap map[ast.SymbolId]sortText recommendedCompletion *ast.Symbol previousToken *ast.Node @@ -263,7 +263,7 @@ func (origin *symbolOriginInfo) toCompletionEntryData() *AutoImportData { ExportMapKey: data.exportMapKey, ModuleSpecifier: data.moduleSpecifier, AmbientModuleName: ambientModuleName, - FileName: strPtrTo(origin.fileName), + FileName: origin.fileName, IsPackageJsonImport: isPackageJsonImport, } } @@ -711,7 +711,8 @@ func (l *LanguageService) getCompletionData( hasUnresolvedAutoImports := false // This also gets mutated in nested-functions after the return var symbols []*ast.Symbol - symbolToOriginInfoMap := map[ast.SymbolId]*symbolOriginInfo{} + // Keys are indexes of `symbols`. + symbolToOriginInfoMap := map[int]*symbolOriginInfo{} symbolToSortTextMap := map[ast.SymbolId]sortText{} var seenPropertySymbols collections.Set[ast.SymbolId] importSpecifierResolver := &importSpecifierResolverForCompletions{SourceFile: file, UserPreferences: preferences, l: l} @@ -725,9 +726,9 @@ func (l *LanguageService) getCompletionData( addSymbolOriginInfo := func(symbol *ast.Symbol, insertQuestionDot bool, insertAwait bool) { symbolId := ast.GetSymbolId(symbol) if insertAwait && seenPropertySymbols.AddIfAbsent(symbolId) { - symbolToOriginInfoMap[symbolId] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindPromise, insertQuestionDot)} + symbolToOriginInfoMap[len(symbols)] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindPromise, insertQuestionDot)} } else if insertQuestionDot { - symbolToOriginInfoMap[symbolId] = &symbolOriginInfo{kind: symbolOriginInfoKindNullable} + symbolToOriginInfoMap[len(symbols)] = &symbolOriginInfo{kind: symbolOriginInfoKindNullable} } } @@ -772,7 +773,7 @@ func (l *LanguageService) getCompletionData( if moduleSymbol == nil || !checker.IsExternalModuleSymbol(moduleSymbol) || typeChecker.TryGetMemberInModuleExportsAndProperties(firstAccessibleSymbol.Name, moduleSymbol) != firstAccessibleSymbol { - symbolToOriginInfoMap[firstAccessibleSymbolId] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindSymbolMemberNoExport, insertQuestionDot)} + symbolToOriginInfoMap[len(symbols)-1] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindSymbolMemberNoExport, insertQuestionDot)} } else { var fileName string if tspath.IsExternalModuleNameRelative(stringutil.StripQuotes(moduleSymbol.Name)) { @@ -793,7 +794,7 @@ func (l *LanguageService) getCompletionData( ) if result != nil { - symbolToOriginInfoMap[ast.GetSymbolId(symbol)] = &symbolOriginInfo{ + symbolToOriginInfoMap[len(symbols)-1] = &symbolOriginInfo{ kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindSymbolMemberExport, insertQuestionDot), isDefaultExport: false, fileName: fileName, @@ -1262,7 +1263,7 @@ func (l *LanguageService) getCompletionData( moduleSpecifier: moduleSpecifier, }, } - symbolToOriginInfoMap[symbolId] = originInfo + symbolToOriginInfoMap[len(symbols)] = originInfo symbolToSortTextMap[symbolId] = core.IfElse(importStatementCompletion != nil, SortTextLocationPriority, SortTextAutoImportSuggestions) symbols = append(symbols, symbol) return nil @@ -1530,17 +1531,16 @@ func (l *LanguageService) getCompletionData( symbols = append(symbols, filterClassMembersList(baseSymbols, decl.Members(), classElementModifierFlags, file, position)...) - for _, symbol := range symbols { + for index, symbol := range symbols { declaration := symbol.ValueDeclaration if declaration != nil && ast.IsClassElement(declaration) && declaration.Name() != nil && ast.IsComputedPropertyName(declaration.Name()) { - symbolId := ast.GetSymbolId(symbol) origin := &symbolOriginInfo{ kind: symbolOriginInfoKindComputedPropertyName, data: &symbolOriginInfoComputedPropertyName{symbolName: typeChecker.SymbolToString(symbol)}, } - symbolToOriginInfoMap[symbolId] = origin + symbolToOriginInfoMap[index] = origin } } } @@ -1647,7 +1647,7 @@ func (l *LanguageService) getCompletionData( symbols = append(symbols, typeChecker.GetSymbolsInScope(scopeNode, symbolMeanings)...) core.CheckEachDefined(symbols, "getSymbolsInScope() should all be defined") - for _, symbol := range symbols { + for index, symbol := range symbols { symbolId := ast.GetSymbolId(symbol) if !typeChecker.IsArgumentsSymbol(symbol) && !core.Some(symbol.Declarations, func(decl *ast.Declaration) bool { @@ -1662,7 +1662,7 @@ func (l *LanguageService) getCompletionData( kind: symbolOriginInfoKindTypeOnlyAlias, data: &symbolOriginInfoTypeOnlyAlias{declaration: typeOnlyAliasDeclaration}, } - symbolToOriginInfoMap[symbolId] = origin + symbolToOriginInfoMap[index] = origin } } } @@ -1677,7 +1677,7 @@ func (l *LanguageService) getCompletionData( for _, symbol := range getPropertiesForCompletion(thisType, typeChecker) { symbolId := ast.GetSymbolId(symbol) symbols = append(symbols, symbol) - symbolToOriginInfoMap[symbolId] = &symbolOriginInfo{kind: symbolOriginInfoKindThisType} + symbolToOriginInfoMap[len(symbols)-1] = &symbolOriginInfo{kind: symbolOriginInfoKindThisType} symbolToSortTextMap[symbolId] = SortTextSuggestedClassMembers } } @@ -1957,9 +1957,8 @@ func (l *LanguageService) getCompletionEntriesFromSymbols( // true otherwise. Based on the order we add things we will always see locals first, then globals, then module exports. // So adding a completion for a local will prevent us from adding completions for external module exports sharing the same name. uniques := make(uniqueNamesMap) - for _, symbol := range data.symbols { - symbolId := ast.GetSymbolId(symbol) - origin := data.symbolToOriginInfoMap[symbolId] + for index, symbol := range data.symbols { + origin := data.symbolToOriginInfoMap[index] name, needsConvertPropertyAccess := getCompletionEntryDisplayNameForSymbol( symbol, origin, @@ -4967,7 +4966,7 @@ type AutoImportData struct { ModuleSpecifier string `json:"moduleSpecifier"` /** The file name declaring the export's module symbol, if it was an external module */ - FileName *string `json:"fileName"` + FileName string `json:"fileName"` /** The module name (with quotes stripped) of the export's module symbol, if it was an ambient module */ AmbientModuleName *string `json:"ambientModuleName"` @@ -5194,9 +5193,8 @@ func (l *LanguageService) getSymbolCompletionFromItemData( // We don't need to perform character checks here because we're only comparing the // name against 'entryName' (which is known to be good), not building a new // completion entry. - for _, symbol := range data.symbols { - symbolId := ast.GetSymbolId(symbol) - origin := data.symbolToOriginInfoMap[symbolId] + for index, symbol := range data.symbols { + origin := data.symbolToOriginInfoMap[index] displayName, _ := getCompletionEntryDisplayNameForSymbol(symbol, origin, data.completionKind, data.isJsxIdentifierExpected) if displayName == itemData.Name && (itemData.Source == string(completionSourceClassMemberSnippet) && symbol.Flags&ast.SymbolFlagsClassMember != 0 || @@ -5224,10 +5222,10 @@ func (l *LanguageService) getAutoImportSymbolFromCompletionEntryData(ch *checker var moduleSymbol *ast.Symbol if autoImportData.AmbientModuleName != nil { moduleSymbol = ch.TryFindAmbientModule(*autoImportData.AmbientModuleName) - } else if autoImportData.FileName != nil { - moduleSymbolSourceFile := containingProgram.GetSourceFile(*autoImportData.FileName) + } else if autoImportData.FileName != "" { + moduleSymbolSourceFile := containingProgram.GetSourceFile(autoImportData.FileName) if moduleSymbolSourceFile == nil { - panic("module sourceFile not found: " + *autoImportData.FileName) + panic("module sourceFile not found: " + autoImportData.FileName) } moduleSymbol = ch.GetMergedSymbol(moduleSymbolSourceFile.Symbol) } @@ -5253,7 +5251,7 @@ func (l *LanguageService) getAutoImportSymbolFromCompletionEntryData(ch *checker } origin := &symbolOriginInfo{ kind: symbolOriginInfoKindExport, - fileName: *autoImportData.FileName, + fileName: autoImportData.FileName, isFromPackageJson: autoImportData.IsPackageJsonImport.IsTrue(), isDefaultExport: isDefaultExport, data: autoImportData.toSymbolOriginExport(name, moduleSymbol, isDefaultExport), From 94c8de9e29527f8dd8794b4dcbabb1f7c286e80f Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 09:28:07 -0700 Subject: [PATCH 06/17] Fix another small batch --- internal/fourslash/_scripts/failingTests.txt | 3 --- ..._exportEqualsNamespace_noDuplicate_test.go | 2 +- ...ionsImport_sortingModuleSpecifiers_test.go | 2 +- ...onsImport_uriStyleNodeCoreModules1_test.go | 2 +- internal/ls/autoimports.go | 3 ++- internal/ls/completions.go | 23 +++++++++++-------- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 3abe76449c..3a7e4fa15d 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -169,7 +169,6 @@ TestCompletionsImport_duplicatePackages_scoped TestCompletionsImport_duplicatePackages_scopedTypes TestCompletionsImport_duplicatePackages_scopedTypesAndNotTypes TestCompletionsImport_duplicatePackages_types -TestCompletionsImport_exportEqualsNamespace_noDuplicate TestCompletionsImport_exportEquals_anonymous TestCompletionsImport_exportEquals_global TestCompletionsImport_filteredByInvalidPackageJson_direct @@ -198,10 +197,8 @@ TestCompletionsImport_reExportDefault2 TestCompletionsImport_reExport_wrongName TestCompletionsImport_require_addNew TestCompletionsImport_require_addToExisting -TestCompletionsImport_sortingModuleSpecifiers TestCompletionsImport_typeOnly TestCompletionsImport_umdDefaultNoCrash1 -TestCompletionsImport_uriStyleNodeCoreModules1 TestCompletionsImport_uriStyleNodeCoreModules2 TestCompletionsImport_windowsPathsProjectRelative TestCompletionsInExport diff --git a/internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go b/internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go index 7b01bd95e9..df2677b55e 100644 --- a/internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go +++ b/internal/fourslash/tests/gen/completionsImport_exportEqualsNamespace_noDuplicate_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_exportEqualsNamespace_noDuplicate(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /node_modules/a/index.d.ts declare namespace core { diff --git a/internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go b/internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go index 6bd3aafdba..625ab87cce 100644 --- a/internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go +++ b/internal/fourslash/tests/gen/completionsImport_sortingModuleSpecifiers_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_sortingModuleSpecifiers(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: tsconfig.json { "compilerOptions": { "module": "commonjs" } } diff --git a/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go b/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go index bc2bed098e..993593f4d2 100644 --- a/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go +++ b/internal/fourslash/tests/gen/completionsImport_uriStyleNodeCoreModules1_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_uriStyleNodeCoreModules1(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @Filename: /node_modules/@types/node/index.d.ts diff --git a/internal/ls/autoimports.go b/internal/ls/autoimports.go index 1183007adc..5af673bb3e 100644 --- a/internal/ls/autoimports.go +++ b/internal/ls/autoimports.go @@ -164,7 +164,8 @@ func (e *exportInfoMap) add( } moduleName := stringutil.StripQuotes(moduleSymbol.Name) - id := e.exportInfoId + 1 + e.exportInfoId++ + id := e.exportInfoId target := ch.SkipAlias(symbol) if flagMatch != nil && !flagMatch(target.Flags) { diff --git a/internal/ls/completions.go b/internal/ls/completions.go index 0df2347e8f..27e66f8357 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -3288,10 +3288,7 @@ func getCompletionsSymbolKind(kind ScriptElementKind) lsproto.CompletionItemKind // Editors will use the `sortText` and then fall back to `name` for sorting, but leave ties in response order. // So, it's important that we sort those ties in the order we want them displayed if it matters. We don't // strictly need to sort by name or SortText here since clients are going to do it anyway, but we have to -// do the work of comparing them so we can sort those ties appropriately; plus, it makes the order returned -// by the language service consistent with what TS Server does and what editors typically do. This also makes -// completions tests make more sense. We used to sort only alphabetically and only in the server layer, but -// this made tests really weird, since most fourslash tests don't use the server. +// do the work of comparing them so we can sort those ties appropriately. func compareCompletionEntries(entryInSlice *lsproto.CompletionItem, entryToInsert *lsproto.CompletionItem) int { compareStrings := stringutil.CompareStringsCaseInsensitiveThenSensitive result := compareStrings(*entryInSlice.SortText, *entryToInsert.SortText) @@ -3299,14 +3296,22 @@ func compareCompletionEntries(entryInSlice *lsproto.CompletionItem, entryToInser result = compareStrings(entryInSlice.Label, entryToInsert.Label) } if result == stringutil.ComparisonEqual && entryInSlice.Data != nil && entryToInsert.Data != nil { - sliceEntryData, ok1 := (*entryInSlice.Data).(*AutoImportData) - insertEntryData, ok2 := (*entryToInsert.Data).(*AutoImportData) - if ok1 && ok2 && sliceEntryData.ModuleSpecifier != "" && insertEntryData.ModuleSpecifier != "" { + sliceEntryData, ok1 := (*entryInSlice.Data).(*CompletionItemData) + insertEntryData, ok2 := (*entryToInsert.Data).(*CompletionItemData) + if ok1 && ok2 && + sliceEntryData.AutoImport != nil && sliceEntryData.AutoImport.ModuleSpecifier != "" && + insertEntryData.AutoImport != nil && insertEntryData.AutoImport.ModuleSpecifier != "" { // Sort same-named auto-imports by module specifier result = compareNumberOfDirectorySeparators( - sliceEntryData.ModuleSpecifier, - insertEntryData.ModuleSpecifier, + sliceEntryData.AutoImport.ModuleSpecifier, + insertEntryData.AutoImport.ModuleSpecifier, ) + if result == stringutil.ComparisonEqual { + result = compareStrings( + sliceEntryData.AutoImport.ModuleSpecifier, + insertEntryData.AutoImport.ModuleSpecifier, + ) + } } } if result == stringutil.ComparisonEqual { From d6b8d7765c9c4eeb7ba8793592421a7531b19be0 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 09:45:00 -0700 Subject: [PATCH 07/17] Fix #1890 --- internal/fourslash/_scripts/failingTests.txt | 8 -------- .../tests/gen/completionsImport_augmentation_test.go | 2 +- ...mpletionsImport_default_fromMergedDeclarations_test.go | 2 +- ...mport_duplicatePackages_scopedTypesAndNotTypes_test.go | 2 +- ...ompletionsImport_duplicatePackages_scopedTypes_test.go | 2 +- .../completionsImport_duplicatePackages_scoped_test.go | 2 +- .../gen/completionsImport_duplicatePackages_types_test.go | 2 +- .../tests/gen/completionsImport_fromAmbientModule_test.go | 2 +- ...completionsImport_named_fromMergedDeclarations_test.go | 2 +- internal/ls/changetracker.go | 2 +- 10 files changed, 9 insertions(+), 17 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 3a7e4fa15d..4bfb255317 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -155,7 +155,6 @@ TestCompletionsImportBaseUrl TestCompletionsImportDefaultExportCrash2 TestCompletionsImportOrExportSpecifier TestCompletionsImport_46332 -TestCompletionsImport_augmentation TestCompletionsImport_compilerOptionsModule TestCompletionsImport_defaultAndNamedConflict TestCompletionsImport_defaultFalsePositive @@ -163,12 +162,7 @@ TestCompletionsImport_default_alreadyExistedWithRename TestCompletionsImport_default_anonymous TestCompletionsImport_default_didNotExistBefore TestCompletionsImport_default_exportDefaultIdentifier -TestCompletionsImport_default_fromMergedDeclarations TestCompletionsImport_details_withMisspelledName -TestCompletionsImport_duplicatePackages_scoped -TestCompletionsImport_duplicatePackages_scopedTypes -TestCompletionsImport_duplicatePackages_scopedTypesAndNotTypes -TestCompletionsImport_duplicatePackages_types TestCompletionsImport_exportEquals_anonymous TestCompletionsImport_exportEquals_global TestCompletionsImport_filteredByInvalidPackageJson_direct @@ -178,7 +172,6 @@ TestCompletionsImport_filteredByPackageJson_nested TestCompletionsImport_filteredByPackageJson_peerDependencies TestCompletionsImport_filteredByPackageJson_typesImplicit TestCompletionsImport_filteredByPackageJson_typesOnly -TestCompletionsImport_fromAmbientModule TestCompletionsImport_importType TestCompletionsImport_jsxOpeningTagImportDefault TestCompletionsImport_mergedReExport @@ -186,7 +179,6 @@ TestCompletionsImport_multipleWithSameName TestCompletionsImport_named_addToNamedImports TestCompletionsImport_named_didNotExistBefore TestCompletionsImport_named_exportEqualsNamespace -TestCompletionsImport_named_fromMergedDeclarations TestCompletionsImport_named_namespaceImportExists TestCompletionsImport_noSemicolons TestCompletionsImport_ofAlias_preferShortPath diff --git a/internal/fourslash/tests/gen/completionsImport_augmentation_test.go b/internal/fourslash/tests/gen/completionsImport_augmentation_test.go index b3c2f3b1b5..2c7cdce25b 100644 --- a/internal/fourslash/tests/gen/completionsImport_augmentation_test.go +++ b/internal/fourslash/tests/gen/completionsImport_augmentation_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_augmentation(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export const foo = 0; diff --git a/internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go b/internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go index 78fc7be2eb..5123c8e3cd 100644 --- a/internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go +++ b/internal/fourslash/tests/gen/completionsImport_default_fromMergedDeclarations_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_default_fromMergedDeclarations(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: esnext // @Filename: /a.ts diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go index 18b1b6e73e..650cff95f6 100644 --- a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypesAndNotTypes_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_duplicatePackages_scopedTypesAndNotTypes(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @esModuleInterop: true diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go index 0119e58b2f..ef1bbfc4b9 100644 --- a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scopedTypes_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_duplicatePackages_scopedTypes(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @esModuleInterop: true diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go index 78a52a020f..7bdc35017a 100644 --- a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_scoped_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_duplicatePackages_scoped(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @esModuleInterop: true diff --git a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go index a86a0ad038..6653f114ec 100644 --- a/internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go +++ b/internal/fourslash/tests/gen/completionsImport_duplicatePackages_types_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_duplicatePackages_types(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: commonjs // @esModuleInterop: true diff --git a/internal/fourslash/tests/gen/completionsImport_fromAmbientModule_test.go b/internal/fourslash/tests/gen/completionsImport_fromAmbientModule_test.go index db396101b7..e070b3e47f 100644 --- a/internal/fourslash/tests/gen/completionsImport_fromAmbientModule_test.go +++ b/internal/fourslash/tests/gen/completionsImport_fromAmbientModule_test.go @@ -10,7 +10,7 @@ import ( func TestCompletionsImport_fromAmbientModule(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: esnext // @Filename: /a.ts diff --git a/internal/fourslash/tests/gen/completionsImport_named_fromMergedDeclarations_test.go b/internal/fourslash/tests/gen/completionsImport_named_fromMergedDeclarations_test.go index 824e643e2b..7a216a296a 100644 --- a/internal/fourslash/tests/gen/completionsImport_named_fromMergedDeclarations_test.go +++ b/internal/fourslash/tests/gen/completionsImport_named_fromMergedDeclarations_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_named_fromMergedDeclarations(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: esnext // @Filename: /a.ts diff --git a/internal/ls/changetracker.go b/internal/ls/changetracker.go index 34397aa546..188aecd1f8 100644 --- a/internal/ls/changetracker.go +++ b/internal/ls/changetracker.go @@ -288,7 +288,7 @@ func (ct *changeTracker) insertAtTopOfFile(sourceFile *ast.SourceFile, insert [] if pos != 0 { options.prefix = ct.newLine } - if !stringutil.IsLineBreak(rune(sourceFile.Text()[pos])) { + if len(sourceFile.Text()) == 0 || !stringutil.IsLineBreak(rune(sourceFile.Text()[pos])) { options.suffix = ct.newLine } if blankLineBetween { From b53c471f245033ce740a5aab3ce823cf3bac9dfd Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 09:55:33 -0700 Subject: [PATCH 08/17] Implement missing JS functionality --- internal/fourslash/_scripts/failingTests.txt | 4 - ...mpletionsImportDefaultExportCrash2_test.go | 2 +- ...etionsImport_compilerOptionsModule_test.go | 2 +- .../completionsImport_require_addNew_test.go | 2 +- ...uggestionsCache_invalidPackageJson_test.go | 2 +- internal/ls/autoimports.go | 85 ++++++++++++++++++- 6 files changed, 87 insertions(+), 10 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 4bfb255317..9e739d2117 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -152,10 +152,8 @@ TestCompletionsElementAccessNumeric TestCompletionsExportImport TestCompletionsGenericTypeWithMultipleBases1 TestCompletionsImportBaseUrl -TestCompletionsImportDefaultExportCrash2 TestCompletionsImportOrExportSpecifier TestCompletionsImport_46332 -TestCompletionsImport_compilerOptionsModule TestCompletionsImport_defaultAndNamedConflict TestCompletionsImport_defaultFalsePositive TestCompletionsImport_default_alreadyExistedWithRename @@ -187,7 +185,6 @@ TestCompletionsImport_quoteStyle TestCompletionsImport_reExportDefault TestCompletionsImport_reExportDefault2 TestCompletionsImport_reExport_wrongName -TestCompletionsImport_require_addNew TestCompletionsImport_require_addToExisting TestCompletionsImport_typeOnly TestCompletionsImport_umdDefaultNoCrash1 @@ -292,7 +289,6 @@ TestImportCompletions_importsMap4 TestImportCompletions_importsMap5 TestImportNameCodeFixExportAsDefault TestImportSuggestionsCache_exportUndefined -TestImportSuggestionsCache_invalidPackageJson TestImportTypeCompletions1 TestImportTypeCompletions3 TestImportTypeCompletions4 diff --git a/internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go b/internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go index fd3d116e79..f300628828 100644 --- a/internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go +++ b/internal/fourslash/tests/gen/completionsImportDefaultExportCrash2_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImportDefaultExportCrash2(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: node18 // @allowJs: true diff --git a/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go b/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go index 7d130aa585..62a31af0ac 100644 --- a/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go +++ b/internal/fourslash/tests/gen/completionsImport_compilerOptionsModule_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_compilerOptionsModule(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @allowJs: true // @module: commonjs diff --git a/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go b/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go index 8ec12de0ba..5f38f4b5b1 100644 --- a/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go +++ b/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_require_addNew(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @allowJs: true // @Filename: /a.js diff --git a/internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go b/internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go index 539b9d756b..7ca5b026fc 100644 --- a/internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go +++ b/internal/fourslash/tests/gen/importSuggestionsCache_invalidPackageJson_test.go @@ -12,7 +12,7 @@ import ( func TestImportSuggestionsCache_invalidPackageJson(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /home/src/workspaces/project/jsconfig.json { diff --git a/internal/ls/autoimports.go b/internal/ls/autoimports.go index 5af673bb3e..0a9f7a1b5a 100644 --- a/internal/ls/autoimports.go +++ b/internal/ls/autoimports.go @@ -1446,8 +1446,7 @@ func (l *LanguageService) codeActionForFixWorker( } if fix.useRequire { - // !!! require - // declarations = getNewRequires(fixAddNew.moduleSpecifier, quotePreference, defaultImport, namedImports, namespaceLikeImport, l.GetProgram().Options(), preferences) + declarations = changeTracker.getNewRequires(fix.moduleSpecifier, defaultImport, namedImports, namespaceLikeImport, l.GetProgram().Options(), preferences) } else { declarations = changeTracker.getNewImports(fix.moduleSpecifier, defaultImport, namedImports, namespaceLikeImport, l.GetProgram().Options(), preferences) } @@ -1478,6 +1477,88 @@ func (l *LanguageService) codeActionForFixWorker( return nil } +func (c *changeTracker) getNewRequires( + moduleSpecifier string, + defaultImport *Import, + namedImports []*Import, + namespaceLikeImport *Import, + compilerOptions *core.CompilerOptions, + preferences *UserPreferences, +) []*ast.Statement { + quotedModuleSpecifier := c.NodeFactory.NewStringLiteral(moduleSpecifier) + var statements []*ast.Statement + + // const { default: foo, bar, etc } = require('./mod'); + if defaultImport != nil || len(namedImports) > 0 { + bindingElements := []*ast.Node{} + for _, namedImport := range namedImports { + var propertyName *ast.Node + if namedImport.propertyName != "" { + propertyName = c.NodeFactory.NewIdentifier(namedImport.propertyName) + } + bindingElements = append(bindingElements, c.NodeFactory.NewBindingElement( + /*dotDotDotToken*/ nil, + propertyName, + c.NodeFactory.NewIdentifier(namedImport.name), + /*initializer*/ nil, + )) + } + if defaultImport != nil { + bindingElements = append([]*ast.Node{ + c.NodeFactory.NewBindingElement( + /*dotDotDotToken*/ nil, + c.NodeFactory.NewIdentifier("default"), + c.NodeFactory.NewIdentifier(defaultImport.name), + /*initializer*/ nil, + ), + }, bindingElements...) + } + declaration := c.createConstEqualsRequireDeclaration( + c.NodeFactory.NewBindingPattern( + ast.KindObjectBindingPattern, + c.NodeFactory.NewNodeList(bindingElements), + ), + quotedModuleSpecifier, + ) + statements = append(statements, declaration) + } + + // const foo = require('./mod'); + if namespaceLikeImport != nil { + declaration := c.createConstEqualsRequireDeclaration( + c.NodeFactory.NewIdentifier(namespaceLikeImport.name), + quotedModuleSpecifier, + ) + statements = append(statements, declaration) + } + + debug.AssertIsDefined(statements) + return statements +} + +func (c *changeTracker) createConstEqualsRequireDeclaration(name *ast.Node, quotedModuleSpecifier *ast.Node) *ast.Statement { + return c.NodeFactory.NewVariableStatement( + /*modifiers*/ nil, + c.NodeFactory.NewVariableDeclarationList( + ast.NodeFlagsConst, + c.NodeFactory.NewNodeList([]*ast.Node{ + c.NodeFactory.NewVariableDeclaration( + name, + /*exclamationToken*/ nil, + /*type*/ nil, + c.NodeFactory.NewCallExpression( + c.NodeFactory.NewIdentifier("require"), + /*questionDotToken*/ nil, + /*typeArguments*/ nil, + c.NodeFactory.NewNodeList([]*ast.Node{quotedModuleSpecifier}), + ast.NodeFlagsNone, + ), + ), + }), + ), + ) +} + func getModuleSpecifierText(promotedDeclaration *ast.ImportDeclaration) string { if promotedDeclaration.Kind == ast.KindImportEqualsDeclaration { importEqualsDeclaration := promotedDeclaration.AsImportEqualsDeclaration() From c9af8fce9d9176a0390db47116231efd1650f0d9 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 12:03:54 -0700 Subject: [PATCH 09/17] Fix package.json filter --- internal/fourslash/_scripts/failingTests.txt | 3 -- internal/fourslash/fourslash.go | 7 ++- .../completionInNamedImportLocation_test.go | 2 +- ...port_filteredByPackageJson_ambient_test.go | 2 +- .../tests/gen/quickInfoOnNarrowedType_test.go | 2 +- internal/ls/autoimports.go | 50 +++++++------------ internal/module/resolver.go | 5 +- internal/packagejson/cache.go | 1 + internal/packagejson/packagejson.go | 27 ++++++++++ 9 files changed, 58 insertions(+), 41 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 9e739d2117..d3d55711c1 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -90,7 +90,6 @@ TestCompletionImportModuleSpecifierEndingUnsupportedExtension TestCompletionInChecks1 TestCompletionInFunctionLikeBody_includesPrimitiveTypes TestCompletionInJsDoc -TestCompletionInNamedImportLocation TestCompletionInUncheckedJSFile TestCompletionListBuilderLocations_VariableDeclarations TestCompletionListForDerivedType1 @@ -164,7 +163,6 @@ TestCompletionsImport_details_withMisspelledName TestCompletionsImport_exportEquals_anonymous TestCompletionsImport_exportEquals_global TestCompletionsImport_filteredByInvalidPackageJson_direct -TestCompletionsImport_filteredByPackageJson_ambient TestCompletionsImport_filteredByPackageJson_direct TestCompletionsImport_filteredByPackageJson_nested TestCompletionsImport_filteredByPackageJson_peerDependencies @@ -469,7 +467,6 @@ TestQuickInfoOnGenericWithConstraints1 TestQuickInfoOnInternalAliases TestQuickInfoOnJsxNamespacedNameWithDoc1 TestQuickInfoOnMethodOfImportEquals -TestQuickInfoOnNarrowedType TestQuickInfoOnNarrowedTypeInModule TestQuickInfoOnNewKeyword01 TestQuickInfoOnObjectLiteralWithAccessors diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 17b9ad1a47..d6d3452995 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -779,8 +779,8 @@ func ignorePaths(paths ...string) cmp.Option { ) } -var completionIgnoreOpts = ignorePaths(".Kind", ".SortText", ".Data") -var autoImportIgnoreOpts = ignorePaths(".Kind", ".SortText", ".Data", ".LabelDetails", ".Detail", ".AdditionalTextEdits") +var completionIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data") +var autoImportIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data", ".LabelDetails", ".Detail", ".AdditionalTextEdits") func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual *lsproto.CompletionItem, expected *lsproto.CompletionItem) { var actualAutoImportData, expectedAutoImportData *ls.AutoImportData @@ -816,6 +816,9 @@ func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual assertDeepEqual(t, actual, expected, prefix, completionIgnoreOpts) } + if expected.FilterText != nil { + assertDeepEqual(t, actual.FilterText, expected.FilterText, prefix+" FilterText mismatch") + } if expected.Kind != nil { assertDeepEqual(t, actual.Kind, expected.Kind, prefix+" Kind mismatch") } diff --git a/internal/fourslash/tests/gen/completionInNamedImportLocation_test.go b/internal/fourslash/tests/gen/completionInNamedImportLocation_test.go index 70e23f84fa..dd636cca8b 100644 --- a/internal/fourslash/tests/gen/completionInNamedImportLocation_test.go +++ b/internal/fourslash/tests/gen/completionInNamedImportLocation_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionInNamedImportLocation(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: file.ts export var x = 10; diff --git a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go index 035f825c1b..69fd73678f 100644 --- a/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go +++ b/internal/fourslash/tests/gen/completionsImport_filteredByPackageJson_ambient_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_filteredByPackageJson_ambient(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `//@noEmit: true //@Filename: /package.json diff --git a/internal/fourslash/tests/gen/quickInfoOnNarrowedType_test.go b/internal/fourslash/tests/gen/quickInfoOnNarrowedType_test.go index f917e01054..203d4dc986 100644 --- a/internal/fourslash/tests/gen/quickInfoOnNarrowedType_test.go +++ b/internal/fourslash/tests/gen/quickInfoOnNarrowedType_test.go @@ -11,7 +11,7 @@ import ( func TestQuickInfoOnNarrowedType(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @strictNullChecks: true function foo(strOrNum: string | number) { diff --git a/internal/ls/autoimports.go b/internal/ls/autoimports.go index 0a9f7a1b5a..2a20436d0c 100644 --- a/internal/ls/autoimports.go +++ b/internal/ls/autoimports.go @@ -17,6 +17,7 @@ import ( "github.com/microsoft/typescript-go/internal/lsp/lsproto" "github.com/microsoft/typescript-go/internal/module" "github.com/microsoft/typescript-go/internal/modulespecifiers" + "github.com/microsoft/typescript-go/internal/packagejson" "github.com/microsoft/typescript-go/internal/stringutil" "github.com/microsoft/typescript-go/internal/tspath" ) @@ -344,32 +345,6 @@ type packageJsonFilterResult struct { importable bool packageName string } -type projectPackageJsonInfo struct { - fileName string - parseable bool - dependencies map[string]string - devDependencies map[string]string - peerDependencies map[string]string - optionalDependencies map[string]string -} - -func (info *projectPackageJsonInfo) has(dependencyName string) bool { - if _, ok := info.dependencies[dependencyName]; ok { - return true - } - if _, ok := info.devDependencies[dependencyName]; ok { - return true - } - - if _, ok := info.peerDependencies[dependencyName]; ok { - return true - } - if _, ok := info.optionalDependencies[dependencyName]; ok { - return true - } - - return false -} func (l *LanguageService) getImportCompletionAction( ctx context.Context, @@ -657,10 +632,23 @@ func (l *LanguageService) getImportFixes( } func (l *LanguageService) createPackageJsonImportFilter(fromFile *ast.SourceFile, preferences UserPreferences) *packageJsonImportFilter { - packageJsons := []*projectPackageJsonInfo{} - // packageJsons := ( - // (host.getPackageJsonsVisibleToFile && host.getPackageJsonsVisibleToFile(fromFile.fileName)) || getPackageJsonsVisibleToFile(fromFile.fileName, host) - // ).filter(p => p.parseable); + // !!! The program package.json cache may not have every relevant package.json. + // This should eventually be integrated with the session. + var packageJsons []*packagejson.PackageJson + dir := tspath.GetDirectoryPath(fromFile.FileName()) + for { + packageJsonDir := l.GetProgram().GetNearestAncestorDirectoryWithPackageJson(dir) + if packageJsonDir == "" { + break + } + if packageJson := l.GetProgram().GetPackageJsonInfo(tspath.CombinePaths(packageJsonDir, "package.json")).GetContents(); packageJson != nil && packageJson.Parseable { + packageJsons = append(packageJsons, packageJson) + } + dir = tspath.GetDirectoryPath(packageJsonDir) + if dir == packageJsonDir { + break + } + } var usesNodeCoreModules *bool ambientModuleCache := map[*ast.Symbol]bool{} @@ -678,7 +666,7 @@ func (l *LanguageService) createPackageJsonImportFilter(fromFile *ast.SourceFile moduleSpecifierIsCoveredByPackageJson := func(specifier string) bool { packageName := getNodeModuleRootSpecifier(specifier) for _, packageJson := range packageJsons { - if packageJson.has(packageName) || packageJson.has(module.GetTypesPackageName(packageName)) { + if packageJson.HasDependency(packageName) || packageJson.HasDependency(module.GetTypesPackageName(packageName)) { return true } } diff --git a/internal/module/resolver.go b/internal/module/resolver.go index e88a468cc0..7f83beb76d 100644 --- a/internal/module/resolver.go +++ b/internal/module/resolver.go @@ -1675,7 +1675,7 @@ func (r *resolutionState) getPackageJsonInfo(packageDirectory string, onlyRecord if directoryExists && r.resolver.host.FS().FileExists(packageJsonPath) { // Ignore error contents, _ := r.resolver.host.FS().ReadFile(packageJsonPath) - packageJsonContent, _ := packagejson.Parse([]byte(contents)) + packageJsonContent, err := packagejson.Parse([]byte(contents)) if r.tracer != nil { r.tracer.write(diagnostics.Found_package_json_at_0.Format(packageJsonPath)) } @@ -1683,7 +1683,8 @@ func (r *resolutionState) getPackageJsonInfo(packageDirectory string, onlyRecord PackageDirectory: packageDirectory, DirectoryExists: true, Contents: &packagejson.PackageJson{ - Fields: packageJsonContent, + Fields: packageJsonContent, + Parseable: err == nil, }, } result = r.resolver.packageJsonInfoCache.Set(packageJsonPath, result) diff --git a/internal/packagejson/cache.go b/internal/packagejson/cache.go index 7b72a4e3e9..ecff10e365 100644 --- a/internal/packagejson/cache.go +++ b/internal/packagejson/cache.go @@ -14,6 +14,7 @@ var typeScriptVersion = semver.MustParse(core.Version()) type PackageJson struct { Fields + Parseable bool versionPaths VersionPaths versionTraces []string once sync.Once diff --git a/internal/packagejson/packagejson.go b/internal/packagejson/packagejson.go index 5db60cebab..7ada92993e 100644 --- a/internal/packagejson/packagejson.go +++ b/internal/packagejson/packagejson.go @@ -28,6 +28,33 @@ type DependencyFields struct { OptionalDependencies Expected[map[string]string] `json:"optionalDependencies"` } +// HasDependency returns true if the package.json has a dependency with the given name +// under any of the dependency fields (dependencies, devDependencies, peerDependencies, +// optionalDependencies). +func (df *DependencyFields) HasDependency(name string) bool { + if deps, ok := df.Dependencies.GetValue(); ok { + if _, ok := deps[name]; ok { + return true + } + } + if devDeps, ok := df.DevDependencies.GetValue(); ok { + if _, ok := devDeps[name]; ok { + return true + } + } + if peerDeps, ok := df.PeerDependencies.GetValue(); ok { + if _, ok := peerDeps[name]; ok { + return true + } + } + if optDeps, ok := df.OptionalDependencies.GetValue(); ok { + if _, ok := optDeps[name]; ok { + return true + } + } + return false +} + type Fields struct { HeaderFields PathFields From b5da1b39a76bdaf62e367bcb153a21acd0273610 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 13:36:33 -0700 Subject: [PATCH 10/17] Fix another batch including module specifier bug --- internal/fourslash/_scripts/failingTests.txt | 3 - internal/fourslash/fourslash.go | 6 +- .../tests/gen/completionsImport_46332_test.go | 2 +- ...ionsImport_defaultAndNamedConflict_test.go | 2 +- ...letionsImport_defaultFalsePositive_test.go | 2 +- internal/modulespecifiers/specifiers.go | 8 +- ...arationErrorNotEmittedForNonEmittedFile.js | 85 ++---------------- ...onErrorNotEmittedForNonEmittedFile.js.diff | 87 ++----------------- ...arationsIndirectGeneratedAliasReference.js | 28 +----- ...onsIndirectGeneratedAliasReference.js.diff | 32 ------- .../nodeModuleReexportFromDottedPath.js | 29 +------ .../nodeModuleReexportFromDottedPath.js.diff | 34 -------- 12 files changed, 24 insertions(+), 294 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index d3d55711c1..1724656391 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -152,9 +152,6 @@ TestCompletionsExportImport TestCompletionsGenericTypeWithMultipleBases1 TestCompletionsImportBaseUrl TestCompletionsImportOrExportSpecifier -TestCompletionsImport_46332 -TestCompletionsImport_defaultAndNamedConflict -TestCompletionsImport_defaultFalsePositive TestCompletionsImport_default_alreadyExistedWithRename TestCompletionsImport_default_anonymous TestCompletionsImport_default_didNotExistBefore diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index d6d3452995..f2e03a6fca 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -879,11 +879,11 @@ func (f *FourslashTest) VerifyApplyCodeActionFromCompletion(t *testing.T, marker return false } if options.AutoImportData != nil { - return data.AutoImport != nil && data.AutoImport.ModuleSpecifier == options.AutoImportData.ModuleSpecifier && + return data.AutoImport != nil && ((data.AutoImport.FileName == options.AutoImportData.FileName) && + (options.AutoImportData.ModuleSpecifier == "" || data.AutoImport.ModuleSpecifier == options.AutoImportData.ModuleSpecifier) && (options.AutoImportData.ExportName == "" || data.AutoImport.ExportName == options.AutoImportData.ExportName) && - (data.AutoImport.FileName == options.AutoImportData.FileName) && (options.AutoImportData.AmbientModuleName == nil || data.AutoImport.AmbientModuleName == options.AutoImportData.AmbientModuleName) && - (options.AutoImportData.IsPackageJsonImport == core.TSUnknown || data.AutoImport.IsPackageJsonImport == options.AutoImportData.IsPackageJsonImport) + (options.AutoImportData.IsPackageJsonImport == core.TSUnknown || data.AutoImport.IsPackageJsonImport == options.AutoImportData.IsPackageJsonImport)) } if data.AutoImport == nil && data.Source != "" && data.Source == options.Source { return true diff --git a/internal/fourslash/tests/gen/completionsImport_46332_test.go b/internal/fourslash/tests/gen/completionsImport_46332_test.go index 6b1e822f47..bee727e2cc 100644 --- a/internal/fourslash/tests/gen/completionsImport_46332_test.go +++ b/internal/fourslash/tests/gen/completionsImport_46332_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_46332(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @module: esnext // @moduleResolution: bundler diff --git a/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go index b395553b5a..f60bf9f376 100644 --- a/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go +++ b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_defaultAndNamedConflict(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @noLib: true // @Filename: /someModule.ts diff --git a/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go b/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go index 197f9a17b6..38d4aef0f8 100644 --- a/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go +++ b/internal/fourslash/tests/gen/completionsImport_defaultFalsePositive_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_defaultFalsePositive(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /node_modules/foo/index.ts export default function f(): void; diff --git a/internal/modulespecifiers/specifiers.go b/internal/modulespecifiers/specifiers.go index 1f8e26b040..fd040fc14e 100644 --- a/internal/modulespecifiers/specifiers.go +++ b/internal/modulespecifiers/specifiers.go @@ -793,6 +793,8 @@ func tryDirectoryWithPackageJson( fileName := moduleFileToTry[parts.PackageRootIndex+1:] if fileName == "index.d.ts" || fileName == "index.js" || fileName == "index.ts" || fileName == "index.tsx" { return pkgJsonDirAttemptResult{moduleFileToTry: moduleFileToTry, packageRootPath: packageRootPath} + } else { + return pkgJsonDirAttemptResult{moduleFileToTry: moduleFileToTry} } } @@ -801,11 +803,7 @@ func tryDirectoryWithPackageJson( importMode = host.GetDefaultResolutionModeForFile(importingSourceFile) } - var packageJsonContent *packagejson.PackageJson - if packageJson != nil { - packageJsonContent = packageJson.GetContents() - } - + packageJsonContent := packageJson.GetContents() if options.GetResolvePackageJsonImports() { // The package name that we found in node_modules could be different from the package // name in the package.json content via url/filepath dependency specifiers. We need to diff --git a/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js b/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js index 3079c4ba18..45192f5a18 100644 --- a/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js +++ b/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js @@ -68,87 +68,14 @@ exports.publicProcedure = trpc.procedure; //// [index.d.ts] -export declare const middleware: >(fn: import("@trpc/server").MiddlewareFunction<{ - _config: import("@trpc/server").RootConfig<{ - errorShape: import("@trpc/server").ErrorFormatterShape; +export declare const middleware: >(fn: import("@trpc/server/middleware").MiddlewareFunction<{ + _config: import("@trpc/server/internals/config").RootConfig<{ + errorShape: import("@trpc/server/internals/utils").ErrorFormatterShape; }>; -}, TNewParams>) => import("@trpc/server").MiddlewareBuilder<{ - _config: import("@trpc/server").RootConfig<{ - errorShape: import("@trpc/server").ErrorFormatterShape; +}, TNewParams>) => import("@trpc/server/middleware").MiddlewareBuilder<{ + _config: import("@trpc/server/internals/config").RootConfig<{ + errorShape: import("@trpc/server/internals/utils").ErrorFormatterShape; }>; }, TNewParams>; export declare const router: {}; export declare const publicProcedure: {}; - - -//// [DtsFileErrors] - - -index.d.ts(1,102): error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareFunction'. -index.d.ts(5,43): error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareBuilder'. - - -==== node_modules/@trpc/server/internals/config.d.ts (0 errors) ==== - export interface RootConfig { - prop: T; - } -==== node_modules/@trpc/server/internals/utils.d.ts (0 errors) ==== - export interface ErrorFormatterShape { - prop: T; - } - export type PickFirstDefined = undefined extends TType - ? undefined extends TPick - ? never - : TPick - : TType; - export interface ErrorFormatter { - prop: [T, U]; - } - export interface DefaultErrorShape { - prop: T; - } -==== node_modules/@trpc/server/middleware.d.ts (0 errors) ==== - export interface MiddlewareFunction { - prop: [T, U]; - } - export interface MiddlewareBuilder { - prop: [T, U]; - } -==== node_modules/@trpc/server/index.d.ts (0 errors) ==== - import { RootConfig } from './internals/config'; - import { ErrorFormatterShape, PickFirstDefined, ErrorFormatter, DefaultErrorShape } from './internals/utils'; - declare class TRPCBuilder { - create>(): { - procedure: {}; - middleware: >(fn: import("./middleware").MiddlewareFunction<{ - _config: RootConfig<{ - errorShape: ErrorFormatterShape>>; - }>; - }, TNewParams>) => import("./middleware").MiddlewareBuilder<{ - _config: RootConfig<{ - errorShape: ErrorFormatterShape>>; - }>; - }, TNewParams>; - router: {}; - }; - } - - export declare const initTRPC: TRPCBuilder; - export {}; -==== index.d.ts (2 errors) ==== - export declare const middleware: >(fn: import("@trpc/server").MiddlewareFunction<{ - ~~~~~~~~~~~~~~~~~~ -!!! error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareFunction'. - _config: import("@trpc/server").RootConfig<{ - errorShape: import("@trpc/server").ErrorFormatterShape; - }>; - }, TNewParams>) => import("@trpc/server").MiddlewareBuilder<{ - ~~~~~~~~~~~~~~~~~ -!!! error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareBuilder'. - _config: import("@trpc/server").RootConfig<{ - errorShape: import("@trpc/server").ErrorFormatterShape; - }>; - }, TNewParams>; - export declare const router: {}; - export declare const publicProcedure: {}; - \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js.diff b/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js.diff index acd616e574..d4735170cf 100644 --- a/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js.diff +++ b/testdata/baselines/reference/submodule/compiler/declarationEmitIsolatedDeclarationErrorNotEmittedForNonEmittedFile.js.diff @@ -13,87 +13,14 @@ + + +//// [index.d.ts] -+export declare const middleware: >(fn: import("@trpc/server").MiddlewareFunction<{ -+ _config: import("@trpc/server").RootConfig<{ -+ errorShape: import("@trpc/server").ErrorFormatterShape; ++export declare const middleware: >(fn: import("@trpc/server/middleware").MiddlewareFunction<{ ++ _config: import("@trpc/server/internals/config").RootConfig<{ ++ errorShape: import("@trpc/server/internals/utils").ErrorFormatterShape; + }>; -+}, TNewParams>) => import("@trpc/server").MiddlewareBuilder<{ -+ _config: import("@trpc/server").RootConfig<{ -+ errorShape: import("@trpc/server").ErrorFormatterShape; ++}, TNewParams>) => import("@trpc/server/middleware").MiddlewareBuilder<{ ++ _config: import("@trpc/server/internals/config").RootConfig<{ ++ errorShape: import("@trpc/server/internals/utils").ErrorFormatterShape; + }>; +}, TNewParams>; +export declare const router: {}; -+export declare const publicProcedure: {}; -+ -+ -+//// [DtsFileErrors] -+ -+ -+index.d.ts(1,102): error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareFunction'. -+index.d.ts(5,43): error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareBuilder'. -+ -+ -+==== node_modules/@trpc/server/internals/config.d.ts (0 errors) ==== -+ export interface RootConfig { -+ prop: T; -+ } -+==== node_modules/@trpc/server/internals/utils.d.ts (0 errors) ==== -+ export interface ErrorFormatterShape { -+ prop: T; -+ } -+ export type PickFirstDefined = undefined extends TType -+ ? undefined extends TPick -+ ? never -+ : TPick -+ : TType; -+ export interface ErrorFormatter { -+ prop: [T, U]; -+ } -+ export interface DefaultErrorShape { -+ prop: T; -+ } -+==== node_modules/@trpc/server/middleware.d.ts (0 errors) ==== -+ export interface MiddlewareFunction { -+ prop: [T, U]; -+ } -+ export interface MiddlewareBuilder { -+ prop: [T, U]; -+ } -+==== node_modules/@trpc/server/index.d.ts (0 errors) ==== -+ import { RootConfig } from './internals/config'; -+ import { ErrorFormatterShape, PickFirstDefined, ErrorFormatter, DefaultErrorShape } from './internals/utils'; -+ declare class TRPCBuilder { -+ create>(): { -+ procedure: {}; -+ middleware: >(fn: import("./middleware").MiddlewareFunction<{ -+ _config: RootConfig<{ -+ errorShape: ErrorFormatterShape>>; -+ }>; -+ }, TNewParams>) => import("./middleware").MiddlewareBuilder<{ -+ _config: RootConfig<{ -+ errorShape: ErrorFormatterShape>>; -+ }>; -+ }, TNewParams>; -+ router: {}; -+ }; -+ } -+ -+ export declare const initTRPC: TRPCBuilder; -+ export {}; -+==== index.d.ts (2 errors) ==== -+ export declare const middleware: >(fn: import("@trpc/server").MiddlewareFunction<{ -+ ~~~~~~~~~~~~~~~~~~ -+!!! error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareFunction'. -+ _config: import("@trpc/server").RootConfig<{ -+ errorShape: import("@trpc/server").ErrorFormatterShape; -+ }>; -+ }, TNewParams>) => import("@trpc/server").MiddlewareBuilder<{ -+ ~~~~~~~~~~~~~~~~~ -+!!! error TS2694: Namespace '"node_modules/@trpc/server/index"' has no exported member 'MiddlewareBuilder'. -+ _config: import("@trpc/server").RootConfig<{ -+ errorShape: import("@trpc/server").ErrorFormatterShape; -+ }>; -+ }, TNewParams>; -+ export declare const router: {}; -+ export declare const publicProcedure: {}; -+ \ No newline at end of file ++export declare const publicProcedure: {}; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js b/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js index 916a7548c9..37a14c819a 100644 --- a/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js +++ b/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js @@ -29,30 +29,4 @@ exports.MyComp = Ctor.extends({ foo: "bar" }); //// [index.d.ts] import * as ns from "mod"; -export declare const MyComp: import("mod").ExtendedCtor; - - -//// [DtsFileErrors] - - -index.d.ts(2,44): error TS2694: Namespace '"node_modules/mod/index"' has no exported member 'ExtendedCtor'. - - -==== node_modules/mod/ctor.d.ts (0 errors) ==== - export interface Ctor { - x: number; - } - export type ExtendedCtor = {x: number, ext: T}; - export interface CtorConstructor { - extends(x: T): ExtendedCtor; - } - export const Ctor: CtorConstructor; -==== node_modules/mod/index.d.ts (0 errors) ==== - import { Ctor } from "./ctor"; - export default Ctor; -==== index.d.ts (1 errors) ==== - import * as ns from "mod"; - export declare const MyComp: import("mod").ExtendedCtor; - ~~~~~~~~~~~~ -!!! error TS2694: Namespace '"node_modules/mod/index"' has no exported member 'ExtendedCtor'. - \ No newline at end of file +export declare const MyComp: import("mod/ctor").ExtendedCtor; diff --git a/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js.diff b/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js.diff index c460ba5131..0d1946d9ee 100644 --- a/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js.diff +++ b/testdata/baselines/reference/submodule/compiler/declarationsIndirectGeneratedAliasReference.js.diff @@ -8,35 +8,3 @@ +const ns = require("mod"); const Ctor = ns.default; exports.MyComp = Ctor.extends({ foo: "bar" }); - - - //// [index.d.ts] - import * as ns from "mod"; --export declare const MyComp: import("mod/ctor").ExtendedCtor; -+export declare const MyComp: import("mod").ExtendedCtor; -+ -+ -+//// [DtsFileErrors] -+ -+ -+index.d.ts(2,44): error TS2694: Namespace '"node_modules/mod/index"' has no exported member 'ExtendedCtor'. -+ -+ -+==== node_modules/mod/ctor.d.ts (0 errors) ==== -+ export interface Ctor { -+ x: number; -+ } -+ export type ExtendedCtor = {x: number, ext: T}; -+ export interface CtorConstructor { -+ extends(x: T): ExtendedCtor; -+ } -+ export const Ctor: CtorConstructor; -+==== node_modules/mod/index.d.ts (0 errors) ==== -+ import { Ctor } from "./ctor"; -+ export default Ctor; -+==== index.d.ts (1 errors) ==== -+ import * as ns from "mod"; -+ export declare const MyComp: import("mod").ExtendedCtor; -+ ~~~~~~~~~~~~ -+!!! error TS2694: Namespace '"node_modules/mod/index"' has no exported member 'ExtendedCtor'. -+ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js b/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js index 8e6036fddd..4959a62228 100644 --- a/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js +++ b/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js @@ -29,32 +29,5 @@ exports.default = new EnhancedPrisma(); //// [index.d.ts] import { PrismaClient } from "@prisma/client"; -declare const _default: PrismaClient; +declare const _default: PrismaClient; export default _default; - - -//// [DtsFileErrors] - - -/index.d.ts(2,45): error TS2307: Cannot find module '.prisma' or its corresponding type declarations. - - -==== /node_modules/.prisma/client/index.d.ts (0 errors) ==== - export interface PrismaClientOptions { - rejectOnNotFound?: any; - } - - export class PrismaClient { - private fetcher; - } - -==== /node_modules/@prisma/client/index.d.ts (0 errors) ==== - export * from ".prisma/client"; - -==== /index.d.ts (1 errors) ==== - import { PrismaClient } from "@prisma/client"; - declare const _default: PrismaClient; - ~~~~~~~~~ -!!! error TS2307: Cannot find module '.prisma' or its corresponding type declarations. - export default _default; - \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js.diff b/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js.diff index ce61505671..24451f8b04 100644 --- a/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js.diff +++ b/testdata/baselines/reference/submodule/compiler/nodeModuleReexportFromDottedPath.js.diff @@ -8,37 +8,3 @@ +const client_1 = require("@prisma/client"); const EnhancedPrisma = enhancePrisma(client_1.PrismaClient); exports.default = new EnhancedPrisma(); - - - //// [index.d.ts] - import { PrismaClient } from "@prisma/client"; --declare const _default: PrismaClient; -+declare const _default: PrismaClient; - export default _default; -+ -+ -+//// [DtsFileErrors] -+ -+ -+/index.d.ts(2,45): error TS2307: Cannot find module '.prisma' or its corresponding type declarations. -+ -+ -+==== /node_modules/.prisma/client/index.d.ts (0 errors) ==== -+ export interface PrismaClientOptions { -+ rejectOnNotFound?: any; -+ } -+ -+ export class PrismaClient { -+ private fetcher; -+ } -+ -+==== /node_modules/@prisma/client/index.d.ts (0 errors) ==== -+ export * from ".prisma/client"; -+ -+==== /index.d.ts (1 errors) ==== -+ import { PrismaClient } from "@prisma/client"; -+ declare const _default: PrismaClient; -+ ~~~~~~~~~ -+!!! error TS2307: Cannot find module '.prisma' or its corresponding type declarations. -+ export default _default; -+ \ No newline at end of file From 0ef2bb3a0a4dc9cc12a2f405dc1d49a85936d2ea Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 16:19:06 -0700 Subject: [PATCH 11/17] Fix named import insertion --- internal/fourslash/_scripts/failingTests.txt | 1 - ...ionsImport_named_addToNamedImports_test.go | 2 +- internal/ls/autoimportfixes.go | 108 ++++--- internal/ls/changetracker.go | 50 +++ internal/ls/organizeimports.go | 285 ++++++++++++++++++ internal/stringutil/compare.go | 20 ++ 6 files changed, 417 insertions(+), 49 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 1724656391..75d734bad3 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -169,7 +169,6 @@ TestCompletionsImport_importType TestCompletionsImport_jsxOpeningTagImportDefault TestCompletionsImport_mergedReExport TestCompletionsImport_multipleWithSameName -TestCompletionsImport_named_addToNamedImports TestCompletionsImport_named_didNotExistBefore TestCompletionsImport_named_exportEqualsNamespace TestCompletionsImport_named_namespaceImportExists diff --git a/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go b/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go index 1ebc60f7f1..faeeb7855d 100644 --- a/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go +++ b/internal/fourslash/tests/gen/completionsImport_named_addToNamedImports_test.go @@ -12,7 +12,7 @@ import ( func TestCompletionsImport_named_addToNamedImports(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export function foo() {} diff --git a/internal/ls/autoimportfixes.go b/internal/ls/autoimportfixes.go index 4aa8104bb1..0fb1864455 100644 --- a/internal/ls/autoimportfixes.go +++ b/internal/ls/autoimportfixes.go @@ -1,10 +1,13 @@ package ls import ( + "slices" + "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/astnav" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/debug" + "github.com/microsoft/typescript-go/internal/stringutil" ) type Import struct { @@ -81,8 +84,7 @@ func (ct *changeTracker) doAddExistingFix( } if len(namedImports) > 0 { - // !!! OrganizeImports not yet implemented - // specifierComparer, isSorted := OrganizeImports.getNamedImportSpecifierComparerWithDetection(importClause.Parent, preferences, sourceFile); + specifierComparer, isSorted := getNamedImportSpecifierComparerWithDetection(importClause.Parent, preferences, sourceFile) newSpecifiers := core.Map(namedImports, func(namedImport *Import) *ast.Node { var identifier *ast.Node if namedImport.propertyName != "" { @@ -93,7 +95,8 @@ func (ct *changeTracker) doAddExistingFix( identifier, ct.NodeFactory.NewIdentifier(namedImport.name), ) - }) // !!! sort with specifierComparer + }) + slices.SortFunc(newSpecifiers, specifierComparer) // !!! remove imports not implemented // if (removeExistingImportSpecifiers) { @@ -108,30 +111,41 @@ func (ct *changeTracker) doAddExistingFix( // append(core.Filter(existingSpecifiers, func (s *ast.ImportSpecifier) bool {return !removeExistingImportSpecifiers.Has(s)}), newSpecifiers...), // !!! sort with specifierComparer // ), // ); - // } else if (len(existingSpecifiers) > 0 && isSorted != false) { - // !!! OrganizeImports not implemented - // The sorting preference computed earlier may or may not have validated that these particular - // import specifiers are sorted. If they aren't, `getImportSpecifierInsertionIndex` will return - // nonsense. So if there are existing specifiers, even if we know the sorting preference, we - // need to ensure that the existing specifiers are sorted according to the preference in order - // to do a sorted insertion. - // changed to check if existing specifiers are sorted - // if we're promoting the clause from type-only, we need to transform the existing imports before attempting to insert the new named imports - // transformedExistingSpecifiers := existingSpecifiers - // if promoteFromTypeOnly && existingSpecifiers { - // transformedExistingSpecifiers = ct.NodeFactory.updateNamedImports( - // importClause.NamedBindings.AsNamedImports(), - // core.SameMap(existingSpecifiers, func(e *ast.ImportSpecifier) *ast.ImportSpecifier { - // return ct.NodeFactory.updateImportSpecifier(e, /*isTypeOnly*/ true, e.propertyName, e.name) - // }), - // ).elements - // } - // for _, spec := range newSpecifiers { - // insertionIndex := OrganizeImports.getImportSpecifierInsertionIndex(transformedExistingSpecifiers, spec, specifierComparer); - // ct.insertImportSpecifierAtIndex(sourceFile, spec, importClause.namedBindings as NamedImports, insertionIndex); - // } - // } else - if len(existingSpecifiers) > 0 { + // + if len(existingSpecifiers) > 0 && isSorted != core.TSFalse { + // The sorting preference computed earlier may or may not have validated that these particular + // import specifiers are sorted. If they aren't, `getImportSpecifierInsertionIndex` will return + // nonsense. So if there are existing specifiers, even if we know the sorting preference, we + // need to ensure that the existing specifiers are sorted according to the preference in order + // to do a sorted insertion. + // if we're promoting the clause from type-only, we need to transform the existing imports before attempting to insert the new named imports + // transformedExistingSpecifiers := existingSpecifiers + // if promoteFromTypeOnly && existingSpecifiers { + // transformedExistingSpecifiers = ct.NodeFactory.updateNamedImports( + // importClause.NamedBindings.AsNamedImports(), + // core.SameMap(existingSpecifiers, func(e *ast.ImportSpecifier) *ast.ImportSpecifier { + // return ct.NodeFactory.updateImportSpecifier(e, /*isTypeOnly*/ true, e.propertyName, e.name) + // }), + // ).elements + // } + for _, spec := range newSpecifiers { + insertionIndex := getImportSpecifierInsertionIndex(existingSpecifiers, spec, specifierComparer) + ct.insertImportSpecifierAtIndex(sourceFile, spec, importClause.NamedBindings, insertionIndex) + } + } else if len(existingSpecifiers) > 0 && isSorted.IsTrue() { + // Existing specifiers are sorted, so insert each new specifier at the correct position + for _, spec := range newSpecifiers { + insertionIndex := getImportSpecifierInsertionIndex(existingSpecifiers, spec, specifierComparer) + if insertionIndex >= len(existingSpecifiers) { + // Insert at the end + ct.insertNodeInListAfter(sourceFile, existingSpecifiers[len(existingSpecifiers)-1], spec.AsNode(), existingSpecifiers) + } else { + // Insert before the element at insertionIndex + ct.insertNodeInListAfter(sourceFile, existingSpecifiers[insertionIndex], spec.AsNode(), existingSpecifiers) + } + } + } else if len(existingSpecifiers) > 0 { + // Existing specifiers may not be sorted, append to the end for _, spec := range newSpecifiers { ct.insertNodeInListAfter(sourceFile, existingSpecifiers[len(existingSpecifiers)-1], spec.AsNode(), existingSpecifiers) } @@ -202,10 +216,11 @@ func (ct *changeTracker) insertImports(sourceFile *ast.SourceFile, imports []*as } else { existingImportStatements = core.Filter(sourceFile.Statements.Nodes, ast.IsAnyImportSyntax) } - // !!! OrganizeImports - // { comparer, isSorted } := OrganizeImports.getOrganizeImportsStringComparerWithDetection(existingImportStatements, preferences); - // sortedNewImports := isArray(imports) ? toSorted(imports, (a, b) => OrganizeImports.compareImportsOrRequireStatements(a, b, comparer)) : [imports]; - sortedNewImports := imports + comparer, isSorted := getOrganizeImportsStringComparerWithDetection(existingImportStatements, preferences) + sortedNewImports := slices.Clone(imports) + slices.SortFunc(sortedNewImports, func(a, b *ast.Statement) int { + return compareImportsOrRequireStatements(a, b, comparer) + }) // !!! FutureSourceFile // if !isFullSourceFile(sourceFile) { // for _, newImport := range sortedNewImports { @@ -216,22 +231,21 @@ func (ct *changeTracker) insertImports(sourceFile *ast.SourceFile, imports []*as // return; // } - // if len(existingImportStatements) > 0 && isSorted { - // for _, newImport := range sortedNewImports { - // insertionIndex := OrganizeImports.getImportDeclarationInsertionIndex(existingImportStatements, newImport, comparer) - // if insertionIndex == 0 { - // // If the first import is top-of-file, insert after the leading comment which is likely the header. - // options := existingImportStatements[0] == sourceFile.statements[0] ? { leadingTriviaOption: textchanges.LeadingTriviaOption.Exclude } : {}; - // ct.insertNodeBefore(sourceFile, existingImportStatements[0], newImport, /*blankLineBetween*/ false, options); - // } else { - // prevImport := existingImportStatements[insertionIndex - 1] - // ct.insertNodeAfter(sourceFile, prevImport, newImport); - // } - // } - // return - // } - - if len(existingImportStatements) > 0 { + if len(existingImportStatements) > 0 && isSorted { + // Existing imports are sorted, insert each new import at the correct position + for _, newImport := range sortedNewImports { + insertionIndex := getImportDeclarationInsertIndex(existingImportStatements, newImport, func(a, b *ast.Statement) stringutil.Comparison { + return compareImportsOrRequireStatements(a, b, comparer) + }) + if insertionIndex == 0 { + // If the first import is top-of-file, insert after the leading comment which is likely the header + ct.insertNodeAt(sourceFile, core.TextPos(astnav.GetStartOfNode(existingImportStatements[0], sourceFile, false)), newImport.AsNode(), changeNodeOptions{}) + } else { + prevImport := existingImportStatements[insertionIndex-1] + ct.insertNodeAfter(sourceFile, prevImport.AsNode(), newImport.AsNode()) + } + } + } else if len(existingImportStatements) > 0 { ct.insertNodesAfter(sourceFile, existingImportStatements[len(existingImportStatements)-1], sortedNewImports) } else { ct.insertAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween) diff --git a/internal/ls/changetracker.go b/internal/ls/changetracker.go index 188aecd1f8..ebe9838080 100644 --- a/internal/ls/changetracker.go +++ b/internal/ls/changetracker.go @@ -165,6 +165,12 @@ func (ct *changeTracker) insertNodesAfter(sourceFile *ast.SourceFile, after *ast ct.insertNodesAt(sourceFile, endPosition, newNodes, ct.getInsertNodeAfterOptions(sourceFile, after)) } +func (ct *changeTracker) insertNodeBefore(sourceFile *ast.SourceFile, before *ast.Node, newNode *ast.Node, blankLineBetween bool) { + // TODO: use getAdjustedStartPosition when implemented + pos := astnav.GetStartOfNode(before, sourceFile, false) + ct.insertNodeAt(sourceFile, core.TextPos(pos), newNode, ct.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween)) +} + func (ct *changeTracker) endPosForInsertNodeAfter(sourceFile *ast.SourceFile, after *ast.Node, newNode *ast.Node) core.TextPos { if (needSemicolonBetween(after, newNode)) && (rune(sourceFile.Text()[after.End()-1]) != ';') { // check if previous statement ends with semicolon @@ -278,6 +284,21 @@ func (ct *changeTracker) insertNodeInListAfter(sourceFile *ast.SourceFile, after ) } +// insertImportSpecifierAtIndex inserts a new import specifier at the specified index in a NamedImports list +func (ct *changeTracker) insertImportSpecifierAtIndex(sourceFile *ast.SourceFile, newSpecifier *ast.Node, namedImports *ast.Node, index int) { + namedImportsNode := namedImports.AsNamedImports() + elements := namedImportsNode.Elements.Nodes + + if index > 0 && len(elements) > index { + ct.insertNodeInListAfter(sourceFile, elements[index-1], newSpecifier, elements) + } else { + // Insert before the first element + firstElement := elements[0] + multiline := printer.GetLinesBetweenPositions(sourceFile, firstElement.Pos(), namedImports.Parent.Parent.Pos()) != 0 + ct.insertNodeBefore(sourceFile, firstElement, newSpecifier, multiline) + } +} + func (ct *changeTracker) insertAtTopOfFile(sourceFile *ast.SourceFile, insert []*ast.Statement, blankLineBetween bool) { if len(insert) == 0 { return @@ -334,3 +355,32 @@ func (ct *changeTracker) getInsertNodeAfterOptions(sourceFile *ast.SourceFile, n return options } + +func (ct *changeTracker) getOptionsForInsertNodeBefore(before *ast.Node, inserted *ast.Node, blankLineBetween bool) changeNodeOptions { + if ast.IsStatement(before) || ast.IsClassOrTypeElement(before) { + if blankLineBetween { + return changeNodeOptions{suffix: ct.newLine + ct.newLine} + } + return changeNodeOptions{suffix: ct.newLine} + } else if before.Kind == ast.KindVariableDeclaration { + // insert `x = 1, ` into `const x = 1, y = 2; + return changeNodeOptions{suffix: ", "} + } else if before.Kind == ast.KindParameter { + if inserted.Kind == ast.KindParameter { + return changeNodeOptions{suffix: ", "} + } + return changeNodeOptions{} + } else if (before.Kind == ast.KindStringLiteral && before.Parent != nil && before.Parent.Kind == ast.KindImportDeclaration) || before.Kind == ast.KindNamedImports { + return changeNodeOptions{suffix: ", "} + } else if before.Kind == ast.KindImportSpecifier { + suffix := "," + if blankLineBetween { + suffix += ct.newLine + } else { + suffix += " " + } + return changeNodeOptions{suffix: suffix} + } + // We haven't handled this kind of node yet -- add it + panic("unimplemented node type " + before.Kind.String() + " in changeTracker.getOptionsForInsertNodeBefore") +} diff --git a/internal/ls/organizeimports.go b/internal/ls/organizeimports.go index 8cdeddab5d..0c7c01eddd 100644 --- a/internal/ls/organizeimports.go +++ b/internal/ls/organizeimports.go @@ -8,6 +8,7 @@ import ( "github.com/microsoft/typescript-go/internal/compiler" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/modulespecifiers" + "github.com/microsoft/typescript-go/internal/stringutil" "github.com/microsoft/typescript-go/internal/tspath" ) @@ -126,3 +127,287 @@ func isIndexFileName(fileName string) bool { } return fileName == "index" } + +func getOrganizeImportsOrdinalStringComparer(ignoreCase bool) func(a, b string) stringutil.Comparison { + if ignoreCase { + return stringutil.CompareStringsCaseInsensitiveEslintCompatible + } + return stringutil.CompareStringsCaseSensitive +} + +// getModuleSpecifierExpression returns the module specifier expression from an import/require statement +func getModuleSpecifierExpression(declaration *ast.Statement) *ast.Expression { + switch declaration.Kind { + case ast.KindImportEqualsDeclaration: + importEquals := declaration.AsImportEqualsDeclaration() + if importEquals.ModuleReference.Kind == ast.KindExternalModuleReference { + return importEquals.ModuleReference.AsExternalModuleReference().Expression + } + return nil + case ast.KindImportDeclaration: + return declaration.AsImportDeclaration().ModuleSpecifier + case ast.KindVariableStatement: + // For require statements: const x = require('...') + variableStatement := declaration.AsVariableStatement() + declarations := variableStatement.DeclarationList.AsVariableDeclarationList().Declarations.Nodes + if len(declarations) > 0 { + decl := declarations[0] + initializer := decl.Initializer() + if initializer != nil && initializer.Kind == ast.KindCallExpression { + callExpr := initializer.AsCallExpression() + if len(callExpr.Arguments.Nodes) > 0 { + return callExpr.Arguments.Nodes[0] + } + } + } + return nil + default: + return nil + } +} + +func getExternalModuleName(specifier *ast.Expression) string { + if specifier != nil && ast.IsStringLiteralLike(specifier.AsNode()) { + return specifier.Text() + } + return "" +} + +// compareModuleSpecifiersWorker compares two module specifiers +func compareModuleSpecifiersWorker(m1 *ast.Expression, m2 *ast.Expression, comparer func(a, b string) stringutil.Comparison) stringutil.Comparison { + name1 := getExternalModuleName(m1) + name2 := getExternalModuleName(m2) + if cmp := compareBooleans(name1 == "", name2 == ""); cmp != 0 { + return cmp + } + if cmp := compareBooleans(tspath.IsExternalModuleNameRelative(name1), tspath.IsExternalModuleNameRelative(name2)); cmp != 0 { + return cmp + } + return comparer(name1, name2) +} + +// compareImportKind returns comparison order based on import kind +func compareImportKind(s1 *ast.Statement, s2 *ast.Statement) stringutil.Comparison { + return cmp.Compare(getImportKindOrder(s1), getImportKindOrder(s2)) +} + +// getImportKindOrder returns the sort order for different import kinds: +// 1. Side-effect imports +// 2. Type-only imports +// 3. Namespace imports +// 4. Default imports +// 5. Named imports +// 6. ImportEqualsDeclarations +// 7. Require variable statements +func getImportKindOrder(s1 *ast.Statement) int { + switch s1.Kind { + case ast.KindImportDeclaration: + importDecl := s1.AsImportDeclaration() + if importDecl.ImportClause == nil { + return 0 // Side-effect import + } + importClause := importDecl.ImportClause.AsImportClause() + if importClause.IsTypeOnly() { + return 1 // Type-only import + } + if importClause.NamedBindings != nil && importClause.NamedBindings.Kind == ast.KindNamespaceImport { + return 2 // Namespace import + } + if importClause.Name() != nil { + return 3 // Default import + } + return 4 // Named imports + case ast.KindImportEqualsDeclaration: + return 5 + case ast.KindVariableStatement: + return 6 // Require statement + default: + return 7 + } +} + +// compareImportsOrRequireStatements compares two import or require statements for sorting +func compareImportsOrRequireStatements(s1 *ast.Statement, s2 *ast.Statement, comparer func(a, b string) stringutil.Comparison) stringutil.Comparison { + if cmp := compareModuleSpecifiersWorker(getModuleSpecifierExpression(s1), getModuleSpecifierExpression(s2), comparer); cmp != stringutil.ComparisonEqual { + return cmp + } + return compareImportKind(s1, s2) +} + +// compareImportOrExportSpecifiers compares two import or export specifiers +func compareImportOrExportSpecifiers(s1 *ast.Node, s2 *ast.Node, comparer func(a, b string) stringutil.Comparison, preferences *UserPreferences) stringutil.Comparison { + typeOrder := OrganizeImportsTypeOrderLast + if preferences != nil { + typeOrder = preferences.OrganizeImportsTypeOrder + } + + s1Name := s1.Name().Text() + s2Name := s2.Name().Text() + + switch typeOrder { + case OrganizeImportsTypeOrderFirst: + if cmp := compareBooleans(s2.IsTypeOnly(), s1.IsTypeOnly()); cmp != 0 { + return cmp + } + return comparer(s1Name, s2Name) + case OrganizeImportsTypeOrderInline: + return comparer(s1Name, s2Name) + default: // OrganizeImportsTypeOrderLast + if cmp := compareBooleans(s1.IsTypeOnly(), s2.IsTypeOnly()); cmp != 0 { + return cmp + } + return comparer(s1Name, s2Name) + } +} + +// getNamedImportSpecifierComparer returns a comparer function for import/export specifiers +func getNamedImportSpecifierComparer(preferences *UserPreferences, comparer func(a, b string) stringutil.Comparison) func(s1, s2 *ast.Node) stringutil.Comparison { + if comparer == nil { + ignoreCase := false + if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { + ignoreCase = preferences.OrganizeImportsIgnoreCase.IsTrue() + } + comparer = getOrganizeImportsOrdinalStringComparer(ignoreCase) + } + return func(s1, s2 *ast.Node) stringutil.Comparison { + return compareImportOrExportSpecifiers(s1, s2, comparer, preferences) + } +} + +// getImportSpecifierInsertionIndex finds the insertion index for a new import specifier +func getImportSpecifierInsertionIndex(sortedImports []*ast.Node, newImport *ast.Node, comparer func(s1, s2 *ast.Node) stringutil.Comparison) int { + if len(sortedImports) == 0 { + return 0 + } + + low := 0 + high := len(sortedImports) - 1 + + for low <= high { + middle := low + ((high - low) >> 1) + midKey := sortedImports[middle] + switch comparer(midKey, newImport) { + case stringutil.ComparisonLessThan: + low = middle + 1 + case stringutil.ComparisonEqual: + return middle + case stringutil.ComparisonGreaterThan: + high = middle - 1 + } + } + + return low +} + +// getOrganizeImportsStringComparerWithDetection detects the string comparer to use based on existing imports +func getOrganizeImportsStringComparerWithDetection(originalImportDecls []*ast.Statement, preferences *UserPreferences) (comparer func(a, b string) stringutil.Comparison, isSorted bool) { + // Get the list of comparers to test based on preferences + var comparersToTest []func(a, b string) stringutil.Comparison + if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { + // If case sensitivity is explicitly specified, only test that one + comparersToTest = []func(a, b string) stringutil.Comparison{ + getOrganizeImportsOrdinalStringComparer(preferences.OrganizeImportsIgnoreCase.IsTrue()), + } + } else { + // Otherwise, test both case-insensitive and case-sensitive + comparersToTest = []func(a, b string) stringutil.Comparison{ + getOrganizeImportsOrdinalStringComparer(true), // case-insensitive first (higher priority) + getOrganizeImportsOrdinalStringComparer(false), // case-sensitive second + } + } + + result := detectModuleSpecifierCaseBySort([][]*ast.Statement{originalImportDecls}, comparersToTest) + return result.comparer, result.isSorted +} + +type caseSensitivityDetectionResult struct { + comparer func(a, b string) stringutil.Comparison + isSorted bool +} + +func detectModuleSpecifierCaseBySort(importDeclsByGroup [][]*ast.Statement, comparersToTest []func(a, b string) stringutil.Comparison) caseSensitivityDetectionResult { + moduleSpecifiersByGroup := make([][]string, 0, len(importDeclsByGroup)) + for _, importGroup := range importDeclsByGroup { + moduleNames := make([]string, 0, len(importGroup)) + for _, decl := range importGroup { + if expr := getModuleSpecifierExpression(decl); expr != nil { + moduleNames = append(moduleNames, getExternalModuleName(expr)) + } else { + moduleNames = append(moduleNames, "") + } + } + moduleSpecifiersByGroup = append(moduleSpecifiersByGroup, moduleNames) + } + return detectCaseSensitivityBySort(moduleSpecifiersByGroup, comparersToTest) +} + +func detectCaseSensitivityBySort(originalGroups [][]string, comparersToTest []func(a, b string) stringutil.Comparison) caseSensitivityDetectionResult { + var bestComparer func(a, b string) stringutil.Comparison + bestDiff := int(^uint(0) >> 1) // max int + + for _, curComparer := range comparersToTest { + diffOfCurrentComparer := 0 + + for _, listToSort := range originalGroups { + if len(listToSort) <= 1 { + continue + } + diff := measureSortedness(listToSort, curComparer) + diffOfCurrentComparer += diff + } + + if diffOfCurrentComparer < bestDiff { + bestDiff = diffOfCurrentComparer + bestComparer = curComparer + } + } + + if bestComparer == nil && len(comparersToTest) > 0 { + bestComparer = comparersToTest[0] + } + + return caseSensitivityDetectionResult{ + comparer: bestComparer, + isSorted: bestDiff == 0, + } +} + +func measureSortedness[T any](arr []T, comparer func(a, b T) stringutil.Comparison) int { + i := 0 + for j := range len(arr) - 1 { + if comparer(arr[j], arr[j+1]) > 0 { + i++ + } + } + return i +} + +// getNamedImportSpecifierComparerWithDetection detects the appropriate comparer for named imports +func getNamedImportSpecifierComparerWithDetection(importDecl *ast.Node, preferences *UserPreferences, sourceFile *ast.SourceFile) (specifierComparer func(s1, s2 *ast.Node) stringutil.Comparison, isSorted core.Tristate) { + // Get the list of comparers to test based on preferences + var comparersToTest []func(a, b string) stringutil.Comparison + if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { + // If case sensitivity is explicitly specified, only test that one + comparersToTest = []func(a, b string) stringutil.Comparison{ + getOrganizeImportsOrdinalStringComparer(preferences.OrganizeImportsIgnoreCase.IsTrue()), + } + } else { + // Otherwise, test both + comparersToTest = []func(a, b string) stringutil.Comparison{ + getOrganizeImportsOrdinalStringComparer(true), // case-insensitive first + getOrganizeImportsOrdinalStringComparer(false), // case-sensitive second + } + } + + specifierComparer = getNamedImportSpecifierComparer(preferences, comparersToTest[0]) + + // Try to detect from the current import declaration + if (preferences == nil || preferences.OrganizeImportsIgnoreCase.IsUnknown() || preferences.OrganizeImportsTypeOrder == OrganizeImportsTypeOrderLast) && + importDecl.Kind == ast.KindImportDeclaration { + // For now, just return the default comparer + // Full detection logic would require porting detectNamedImportOrganizationBySort + return specifierComparer, core.TSUnknown + } + + return specifierComparer, core.TSUnknown +} diff --git a/internal/stringutil/compare.go b/internal/stringutil/compare.go index 832e1dbcf1..0fb1cd3975 100644 --- a/internal/stringutil/compare.go +++ b/internal/stringutil/compare.go @@ -98,3 +98,23 @@ func CompareStringsCaseInsensitiveThenSensitive(a, b string) Comparison { } return CompareStringsCaseSensitive(a, b) } + +// CompareStringsCaseInsensitiveEslintCompatible performs a case-insensitive comparison +// using toLowerCase() instead of toUpperCase() for ESLint compatibility. +// +// `CompareStringsCaseInsensitive` transforms letters to uppercase for unicode reasons, +// while eslint's `sort-imports` rule transforms letters to lowercase. Which one you choose +// affects the relative order of letters and ASCII characters 91-96, of which `_` is a +// valid character in an identifier. So if we used `CompareStringsCaseInsensitive` for +// import sorting, TypeScript and eslint would disagree about the correct case-insensitive +// sort order for `__String` and `Foo`. Since eslint's whole job is to create consistency +// by enforcing nitpicky details like this, it makes way more sense for us to just adopt +// their convention so users can have auto-imports without making eslint angry. +func CompareStringsCaseInsensitiveEslintCompatible(a, b string) Comparison { + if a == b { + return ComparisonEqual + } + a = strings.ToLower(a) + b = strings.ToLower(b) + return strings.Compare(a, b) +} From d4b6e75a97599a76e0e1b53a1f2f91ed61544601 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 16:40:09 -0700 Subject: [PATCH 12/17] Fix existing tests, update baselines --- internal/fourslash/fourslash.go | 2 +- internal/ls/changetracker.go | 4 ++-- internal/ls/completions.go | 4 ++-- internal/lsp/server.go | 2 +- .../fourslash/autoImports/autoImportCompletion2.baseline.md | 2 +- .../fourslash/autoImports/autoImportCompletion3.baseline.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index f2e03a6fca..642171b544 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -1720,7 +1720,7 @@ func (f *FourslashTest) BaselineAutoImportsCompletions(t *testing.T, markerNames t.Fatalf(prefix+"Nil response received for resolve completion", f.lastKnownMarkerName) } if !resultOk { - t.Fatalf(prefix+"Unexpected response type for resolve completion: %T", resMsg.AsResponse().Result) + t.Fatalf(prefix+"Unexpected response type for resolve completion: %T, Error: %v", resMsg.AsResponse().Result, resMsg.AsResponse().Error) } if details == nil || details.AdditionalTextEdits == nil || len(*details.AdditionalTextEdits) == 0 { t.Fatalf(prefix+"Entry %s from %s returned no code changes from completion details request", item.Label, item.Detail) diff --git a/internal/ls/changetracker.go b/internal/ls/changetracker.go index ebe9838080..12134b1a0d 100644 --- a/internal/ls/changetracker.go +++ b/internal/ls/changetracker.go @@ -219,10 +219,10 @@ func (ct *changeTracker) insertNodeInListAfter(sourceFile *ast.SourceFile, after // ###b, // c, nextNode := containingList[index+1] - startPos := scanner.SkipTriviaEx(sourceFile.Text(), nextNode.Pos(), &scanner.SkipTriviaOptions{StopAfterLineBreak: true, StopAtComments: false}) + startPos := scanner.SkipTriviaEx(sourceFile.Text(), nextNode.Pos(), &scanner.SkipTriviaOptions{StopAfterLineBreak: false, StopAtComments: true}) // write separator and leading trivia of the next element as suffix - suffix := scanner.TokenToString(nextToken.Kind) + sourceFile.Text()[nextNode.End():startPos] + suffix := scanner.TokenToString(nextToken.Kind) + sourceFile.Text()[nextToken.End():startPos] ct.insertNodeAt(sourceFile, core.TextPos(startPos), newNode, changeNodeOptions{suffix: suffix}) } return diff --git a/internal/ls/completions.go b/internal/ls/completions.go index 27e66f8357..65db54b937 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -726,9 +726,9 @@ func (l *LanguageService) getCompletionData( addSymbolOriginInfo := func(symbol *ast.Symbol, insertQuestionDot bool, insertAwait bool) { symbolId := ast.GetSymbolId(symbol) if insertAwait && seenPropertySymbols.AddIfAbsent(symbolId) { - symbolToOriginInfoMap[len(symbols)] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindPromise, insertQuestionDot)} + symbolToOriginInfoMap[len(symbols)-1] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindPromise, insertQuestionDot)} } else if insertQuestionDot { - symbolToOriginInfoMap[len(symbols)] = &symbolOriginInfo{kind: symbolOriginInfoKindNullable} + symbolToOriginInfoMap[len(symbols)-1] = &symbolOriginInfo{kind: symbolOriginInfoKindNullable} } } diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 2265ebb344..9e5f95442e 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -800,7 +800,7 @@ func (s *Server) handleCompletionItemResolve(ctx context.Context, params *lsprot if err != nil { return nil, err } - defer s.recover(reqMsg) + // defer s.recover(reqMsg) return languageService.ResolveCompletionItem( ctx, params, diff --git a/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion2.baseline.md b/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion2.baseline.md index 1fff3fc8ff..a679c95fee 100644 --- a/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion2.baseline.md +++ b/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion2.baseline.md @@ -6,7 +6,7 @@ someVar; a/**/ ``````ts -import {someVar,anotherVar} from "./a.ts"; +import {anotherVar, someVar} from "./a.ts"; someVar; a diff --git a/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion3.baseline.md b/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion3.baseline.md index e565df0c68..b70487e0b7 100644 --- a/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion3.baseline.md +++ b/testdata/baselines/reference/fourslash/autoImports/autoImportCompletion3.baseline.md @@ -6,7 +6,7 @@ someVar; b/**/ ``````ts -import { aa, someVar,bb } from "./a.ts"; +import { aa, bb, someVar } from "./a.ts"; someVar; b From e3fcacb34a7082d4ab457ef92c5ad11a94261954 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 16:48:26 -0700 Subject: [PATCH 13/17] Use getAdjustedStartPosition --- internal/fourslash/_scripts/failingTests.txt | 1 - .../tests/gen/autoImportSortCaseSensitivity2_test.go | 2 +- internal/ls/changetracker.go | 4 +--- internal/lsp/server.go | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 75d734bad3..422c31bae0 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -25,7 +25,6 @@ TestAutoImportProvider_namespaceSameNameAsIntrinsic TestAutoImportProvider_wildcardExports1 TestAutoImportProvider_wildcardExports2 TestAutoImportProvider_wildcardExports3 -TestAutoImportSortCaseSensitivity2 TestAutoImportVerbatimTypeOnly1 TestBestCommonTypeObjectLiterals TestBestCommonTypeObjectLiterals1 diff --git a/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go b/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go index 247f36c968..ff585d978d 100644 --- a/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go +++ b/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go @@ -12,7 +12,7 @@ import ( func TestAutoImportSortCaseSensitivity2(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @Filename: /a.ts export interface HasBar { bar: number } diff --git a/internal/ls/changetracker.go b/internal/ls/changetracker.go index 12134b1a0d..db7cfb3fec 100644 --- a/internal/ls/changetracker.go +++ b/internal/ls/changetracker.go @@ -166,9 +166,7 @@ func (ct *changeTracker) insertNodesAfter(sourceFile *ast.SourceFile, after *ast } func (ct *changeTracker) insertNodeBefore(sourceFile *ast.SourceFile, before *ast.Node, newNode *ast.Node, blankLineBetween bool) { - // TODO: use getAdjustedStartPosition when implemented - pos := astnav.GetStartOfNode(before, sourceFile, false) - ct.insertNodeAt(sourceFile, core.TextPos(pos), newNode, ct.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween)) + ct.insertNodeAt(sourceFile, core.TextPos(ct.getAdjustedStartPosition(sourceFile, before, leadingTriviaOptionNone, false)), newNode, ct.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween)) } func (ct *changeTracker) endPosForInsertNodeAfter(sourceFile *ast.SourceFile, after *ast.Node, newNode *ast.Node) core.TextPos { diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 9e5f95442e..2265ebb344 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -800,7 +800,7 @@ func (s *Server) handleCompletionItemResolve(ctx context.Context, params *lsprot if err != nil { return nil, err } - // defer s.recover(reqMsg) + defer s.recover(reqMsg) return languageService.ResolveCompletionItem( ctx, params, From 4929e6ce01c537daf28e72edc2d2cc56b13b0657 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 21 Oct 2025 16:50:41 -0700 Subject: [PATCH 14/17] Format --- internal/fourslash/fourslash.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 642171b544..00f39aac1e 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -779,8 +779,10 @@ func ignorePaths(paths ...string) cmp.Option { ) } -var completionIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data") -var autoImportIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data", ".LabelDetails", ".Detail", ".AdditionalTextEdits") +var ( + completionIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data") + autoImportIgnoreOpts = ignorePaths(".Kind", ".SortText", ".FilterText", ".Data", ".LabelDetails", ".Detail", ".AdditionalTextEdits") +) func (f *FourslashTest) verifyCompletionItem(t *testing.T, prefix string, actual *lsproto.CompletionItem, expected *lsproto.CompletionItem) { var actualAutoImportData, expectedAutoImportData *ls.AutoImportData From 937bba175bc936bf0ff9eb6a274471ed3e020918 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 22 Oct 2025 09:17:34 -0700 Subject: [PATCH 15/17] Fix AI slop --- internal/ls/organizeimports.go | 71 +++++++++++++--------------------- 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/internal/ls/organizeimports.go b/internal/ls/organizeimports.go index 0c7c01eddd..e5972f3b2c 100644 --- a/internal/ls/organizeimports.go +++ b/internal/ls/organizeimports.go @@ -2,6 +2,7 @@ package ls import ( "cmp" + "math" "strings" "github.com/microsoft/typescript-go/internal/ast" @@ -128,7 +129,7 @@ func isIndexFileName(fileName string) bool { return fileName == "index" } -func getOrganizeImportsOrdinalStringComparer(ignoreCase bool) func(a, b string) stringutil.Comparison { +func getOrganizeImportsOrdinalStringComparer(ignoreCase bool) func(a, b string) int { if ignoreCase { return stringutil.CompareStringsCaseInsensitiveEslintCompatible } @@ -174,7 +175,7 @@ func getExternalModuleName(specifier *ast.Expression) string { } // compareModuleSpecifiersWorker compares two module specifiers -func compareModuleSpecifiersWorker(m1 *ast.Expression, m2 *ast.Expression, comparer func(a, b string) stringutil.Comparison) stringutil.Comparison { +func compareModuleSpecifiersWorker(m1 *ast.Expression, m2 *ast.Expression, comparer func(a, b string) int) int { name1 := getExternalModuleName(m1) name2 := getExternalModuleName(m2) if cmp := compareBooleans(name1 == "", name2 == ""); cmp != 0 { @@ -187,7 +188,7 @@ func compareModuleSpecifiersWorker(m1 *ast.Expression, m2 *ast.Expression, compa } // compareImportKind returns comparison order based on import kind -func compareImportKind(s1 *ast.Statement, s2 *ast.Statement) stringutil.Comparison { +func compareImportKind(s1 *ast.Statement, s2 *ast.Statement) int { return cmp.Compare(getImportKindOrder(s1), getImportKindOrder(s2)) } @@ -227,15 +228,15 @@ func getImportKindOrder(s1 *ast.Statement) int { } // compareImportsOrRequireStatements compares two import or require statements for sorting -func compareImportsOrRequireStatements(s1 *ast.Statement, s2 *ast.Statement, comparer func(a, b string) stringutil.Comparison) stringutil.Comparison { - if cmp := compareModuleSpecifiersWorker(getModuleSpecifierExpression(s1), getModuleSpecifierExpression(s2), comparer); cmp != stringutil.ComparisonEqual { +func compareImportsOrRequireStatements(s1 *ast.Statement, s2 *ast.Statement, comparer func(a, b string) int) int { + if cmp := compareModuleSpecifiersWorker(getModuleSpecifierExpression(s1), getModuleSpecifierExpression(s2), comparer); cmp != 0 { return cmp } return compareImportKind(s1, s2) } // compareImportOrExportSpecifiers compares two import or export specifiers -func compareImportOrExportSpecifiers(s1 *ast.Node, s2 *ast.Node, comparer func(a, b string) stringutil.Comparison, preferences *UserPreferences) stringutil.Comparison { +func compareImportOrExportSpecifiers(s1 *ast.Node, s2 *ast.Node, comparer func(a, b string) int, preferences *UserPreferences) int { typeOrder := OrganizeImportsTypeOrderLast if preferences != nil { typeOrder = preferences.OrganizeImportsTypeOrder @@ -261,7 +262,7 @@ func compareImportOrExportSpecifiers(s1 *ast.Node, s2 *ast.Node, comparer func(a } // getNamedImportSpecifierComparer returns a comparer function for import/export specifiers -func getNamedImportSpecifierComparer(preferences *UserPreferences, comparer func(a, b string) stringutil.Comparison) func(s1, s2 *ast.Node) stringutil.Comparison { +func getNamedImportSpecifierComparer(preferences *UserPreferences, comparer func(a, b string) int) func(s1, s2 *ast.Node) int { if comparer == nil { ignoreCase := false if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { @@ -269,48 +270,30 @@ func getNamedImportSpecifierComparer(preferences *UserPreferences, comparer func } comparer = getOrganizeImportsOrdinalStringComparer(ignoreCase) } - return func(s1, s2 *ast.Node) stringutil.Comparison { + return func(s1, s2 *ast.Node) int { return compareImportOrExportSpecifiers(s1, s2, comparer, preferences) } } // getImportSpecifierInsertionIndex finds the insertion index for a new import specifier -func getImportSpecifierInsertionIndex(sortedImports []*ast.Node, newImport *ast.Node, comparer func(s1, s2 *ast.Node) stringutil.Comparison) int { - if len(sortedImports) == 0 { - return 0 - } - - low := 0 - high := len(sortedImports) - 1 - - for low <= high { - middle := low + ((high - low) >> 1) - midKey := sortedImports[middle] - switch comparer(midKey, newImport) { - case stringutil.ComparisonLessThan: - low = middle + 1 - case stringutil.ComparisonEqual: - return middle - case stringutil.ComparisonGreaterThan: - high = middle - 1 - } - } - - return low +func getImportSpecifierInsertionIndex(sortedImports []*ast.Node, newImport *ast.Node, comparer func(s1, s2 *ast.Node) int) int { + return core.FirstResult(core.BinarySearchUniqueFunc(sortedImports, func(mid int, value *ast.Node) int { + return comparer(value, newImport) + })) } // getOrganizeImportsStringComparerWithDetection detects the string comparer to use based on existing imports -func getOrganizeImportsStringComparerWithDetection(originalImportDecls []*ast.Statement, preferences *UserPreferences) (comparer func(a, b string) stringutil.Comparison, isSorted bool) { +func getOrganizeImportsStringComparerWithDetection(originalImportDecls []*ast.Statement, preferences *UserPreferences) (comparer func(a, b string) int, isSorted bool) { // Get the list of comparers to test based on preferences - var comparersToTest []func(a, b string) stringutil.Comparison + var comparersToTest []func(a, b string) int if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { // If case sensitivity is explicitly specified, only test that one - comparersToTest = []func(a, b string) stringutil.Comparison{ + comparersToTest = []func(a, b string) int{ getOrganizeImportsOrdinalStringComparer(preferences.OrganizeImportsIgnoreCase.IsTrue()), } } else { // Otherwise, test both case-insensitive and case-sensitive - comparersToTest = []func(a, b string) stringutil.Comparison{ + comparersToTest = []func(a, b string) int{ getOrganizeImportsOrdinalStringComparer(true), // case-insensitive first (higher priority) getOrganizeImportsOrdinalStringComparer(false), // case-sensitive second } @@ -321,11 +304,11 @@ func getOrganizeImportsStringComparerWithDetection(originalImportDecls []*ast.St } type caseSensitivityDetectionResult struct { - comparer func(a, b string) stringutil.Comparison + comparer func(a, b string) int isSorted bool } -func detectModuleSpecifierCaseBySort(importDeclsByGroup [][]*ast.Statement, comparersToTest []func(a, b string) stringutil.Comparison) caseSensitivityDetectionResult { +func detectModuleSpecifierCaseBySort(importDeclsByGroup [][]*ast.Statement, comparersToTest []func(a, b string) int) caseSensitivityDetectionResult { moduleSpecifiersByGroup := make([][]string, 0, len(importDeclsByGroup)) for _, importGroup := range importDeclsByGroup { moduleNames := make([]string, 0, len(importGroup)) @@ -341,9 +324,9 @@ func detectModuleSpecifierCaseBySort(importDeclsByGroup [][]*ast.Statement, comp return detectCaseSensitivityBySort(moduleSpecifiersByGroup, comparersToTest) } -func detectCaseSensitivityBySort(originalGroups [][]string, comparersToTest []func(a, b string) stringutil.Comparison) caseSensitivityDetectionResult { - var bestComparer func(a, b string) stringutil.Comparison - bestDiff := int(^uint(0) >> 1) // max int +func detectCaseSensitivityBySort(originalGroups [][]string, comparersToTest []func(a, b string) int) caseSensitivityDetectionResult { + var bestComparer func(a, b string) int + bestDiff := math.MaxInt for _, curComparer := range comparersToTest { diffOfCurrentComparer := 0 @@ -372,7 +355,7 @@ func detectCaseSensitivityBySort(originalGroups [][]string, comparersToTest []fu } } -func measureSortedness[T any](arr []T, comparer func(a, b T) stringutil.Comparison) int { +func measureSortedness[T any](arr []T, comparer func(a, b T) int) int { i := 0 for j := range len(arr) - 1 { if comparer(arr[j], arr[j+1]) > 0 { @@ -383,17 +366,17 @@ func measureSortedness[T any](arr []T, comparer func(a, b T) stringutil.Comparis } // getNamedImportSpecifierComparerWithDetection detects the appropriate comparer for named imports -func getNamedImportSpecifierComparerWithDetection(importDecl *ast.Node, preferences *UserPreferences, sourceFile *ast.SourceFile) (specifierComparer func(s1, s2 *ast.Node) stringutil.Comparison, isSorted core.Tristate) { +func getNamedImportSpecifierComparerWithDetection(importDecl *ast.Node, preferences *UserPreferences, sourceFile *ast.SourceFile) (specifierComparer func(s1, s2 *ast.Node) int, isSorted core.Tristate) { // Get the list of comparers to test based on preferences - var comparersToTest []func(a, b string) stringutil.Comparison + var comparersToTest []func(a, b string) int if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { // If case sensitivity is explicitly specified, only test that one - comparersToTest = []func(a, b string) stringutil.Comparison{ + comparersToTest = []func(a, b string) int{ getOrganizeImportsOrdinalStringComparer(preferences.OrganizeImportsIgnoreCase.IsTrue()), } } else { // Otherwise, test both - comparersToTest = []func(a, b string) stringutil.Comparison{ + comparersToTest = []func(a, b string) int{ getOrganizeImportsOrdinalStringComparer(true), // case-insensitive first getOrganizeImportsOrdinalStringComparer(false), // case-sensitive second } From d6eaabce258c5d1a9fad157d4f6a45a80d6c9b6f Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 22 Oct 2025 10:53:21 -0700 Subject: [PATCH 16/17] More AI slop --- internal/ls/organizeimports.go | 51 +++++++++++++--------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/internal/ls/organizeimports.go b/internal/ls/organizeimports.go index e5972f3b2c..cca55b8f46 100644 --- a/internal/ls/organizeimports.go +++ b/internal/ls/organizeimports.go @@ -13,6 +13,13 @@ import ( "github.com/microsoft/typescript-go/internal/tspath" ) +var caseInsensitiveOrganizeImportsComparer = []func(a, b string) int{getOrganizeImportsOrdinalStringComparer(true)} +var caseSensitiveOrganizeImportsComparer = []func(a, b string) int{getOrganizeImportsOrdinalStringComparer(false)} +var organizeImportsComparers = []func(a, b string) int{ + caseInsensitiveOrganizeImportsComparer[0], + caseSensitiveOrganizeImportsComparer[0], +} + // statement = anyImportOrRequireStatement func getImportDeclarationInsertIndex(sortedImports []*ast.Statement, newImport *ast.Statement, comparer func(a, b *ast.Statement) int) int { // !!! @@ -284,23 +291,21 @@ func getImportSpecifierInsertionIndex(sortedImports []*ast.Node, newImport *ast. // getOrganizeImportsStringComparerWithDetection detects the string comparer to use based on existing imports func getOrganizeImportsStringComparerWithDetection(originalImportDecls []*ast.Statement, preferences *UserPreferences) (comparer func(a, b string) int, isSorted bool) { - // Get the list of comparers to test based on preferences - var comparersToTest []func(a, b string) int - if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { - // If case sensitivity is explicitly specified, only test that one - comparersToTest = []func(a, b string) int{ - getOrganizeImportsOrdinalStringComparer(preferences.OrganizeImportsIgnoreCase.IsTrue()), - } - } else { - // Otherwise, test both case-insensitive and case-sensitive - comparersToTest = []func(a, b string) int{ - getOrganizeImportsOrdinalStringComparer(true), // case-insensitive first (higher priority) - getOrganizeImportsOrdinalStringComparer(false), // case-sensitive second + result := detectModuleSpecifierCaseBySort([][]*ast.Statement{originalImportDecls}, getComparers(preferences)) + return result.comparer, result.isSorted +} + +func getComparers(preferences *UserPreferences) []func(a string, b string) int { + if preferences != nil { + switch preferences.OrganizeImportsIgnoreCase { + case core.TSTrue: + return caseInsensitiveOrganizeImportsComparer + case core.TSFalse: + return caseSensitiveOrganizeImportsComparer } } - result := detectModuleSpecifierCaseBySort([][]*ast.Statement{originalImportDecls}, comparersToTest) - return result.comparer, result.isSorted + return organizeImportsComparers } type caseSensitivityDetectionResult struct { @@ -367,23 +372,7 @@ func measureSortedness[T any](arr []T, comparer func(a, b T) int) int { // getNamedImportSpecifierComparerWithDetection detects the appropriate comparer for named imports func getNamedImportSpecifierComparerWithDetection(importDecl *ast.Node, preferences *UserPreferences, sourceFile *ast.SourceFile) (specifierComparer func(s1, s2 *ast.Node) int, isSorted core.Tristate) { - // Get the list of comparers to test based on preferences - var comparersToTest []func(a, b string) int - if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { - // If case sensitivity is explicitly specified, only test that one - comparersToTest = []func(a, b string) int{ - getOrganizeImportsOrdinalStringComparer(preferences.OrganizeImportsIgnoreCase.IsTrue()), - } - } else { - // Otherwise, test both - comparersToTest = []func(a, b string) int{ - getOrganizeImportsOrdinalStringComparer(true), // case-insensitive first - getOrganizeImportsOrdinalStringComparer(false), // case-sensitive second - } - } - - specifierComparer = getNamedImportSpecifierComparer(preferences, comparersToTest[0]) - + specifierComparer = getNamedImportSpecifierComparer(preferences, getComparers(preferences)[0]) // Try to detect from the current import declaration if (preferences == nil || preferences.OrganizeImportsIgnoreCase.IsUnknown() || preferences.OrganizeImportsTypeOrder == OrganizeImportsTypeOrderLast) && importDecl.Kind == ast.KindImportDeclaration { From d2e5f2cb7bf2601bd48db1f6427e281ba3c02ddc Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 22 Oct 2025 11:24:49 -0700 Subject: [PATCH 17/17] Format --- internal/ls/organizeimports.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/internal/ls/organizeimports.go b/internal/ls/organizeimports.go index cca55b8f46..b5cfaf68a6 100644 --- a/internal/ls/organizeimports.go +++ b/internal/ls/organizeimports.go @@ -13,12 +13,14 @@ import ( "github.com/microsoft/typescript-go/internal/tspath" ) -var caseInsensitiveOrganizeImportsComparer = []func(a, b string) int{getOrganizeImportsOrdinalStringComparer(true)} -var caseSensitiveOrganizeImportsComparer = []func(a, b string) int{getOrganizeImportsOrdinalStringComparer(false)} -var organizeImportsComparers = []func(a, b string) int{ - caseInsensitiveOrganizeImportsComparer[0], - caseSensitiveOrganizeImportsComparer[0], -} +var ( + caseInsensitiveOrganizeImportsComparer = []func(a, b string) int{getOrganizeImportsOrdinalStringComparer(true)} + caseSensitiveOrganizeImportsComparer = []func(a, b string) int{getOrganizeImportsOrdinalStringComparer(false)} + organizeImportsComparers = []func(a, b string) int{ + caseInsensitiveOrganizeImportsComparer[0], + caseSensitiveOrganizeImportsComparer[0], + } +) // statement = anyImportOrRequireStatement func getImportDeclarationInsertIndex(sortedImports []*ast.Statement, newImport *ast.Statement, comparer func(a, b *ast.Statement) int) int {