diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 534b7d69c7..72a6d879a6 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; @@ -169,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": @@ -271,6 +277,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,18 +375,170 @@ 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; } +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: ${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"], @@ -397,7 +562,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); @@ -408,6 +573,9 @@ function parseVerifyCompletionArg(arg: ts.Expression): VerifyCompletionsCmd | un 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; } @@ -478,7 +646,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 +757,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 +768,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 +877,33 @@ 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)) { + 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)}, + }, + })),`); + } + else { + console.error(`Expected string literal for source/sourceDisplay, got ${init.getText()}`); + return undefined; + } + break; case "commitCharacters": // !!! support these later break; @@ -732,6 +928,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 +955,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 +1542,7 @@ interface VerifyCompletionsCmd { marker: string; isNewIdentifierLocation?: true; args?: VerifyCompletionsArgs | "nil"; + andApplyCodeActionArgs?: VerifyApplyCodeActionArgs; } interface VerifyCompletionsArgs { @@ -1296,6 +1552,19 @@ interface VerifyCompletionsArgs { unsorted?: string; } +interface VerifyApplyCodeActionArgs { + name: string; + source: string; + description: string; + newFileContent: string; +} + +interface VerifyApplyCodeActionFromCompletionCmd { + kind: "verifyApplyCodeActionFromCompletion"; + marker: string; + options: string; +} + interface VerifyBaselineFindAllReferencesCmd { kind: "verifyBaselineFindAllReferences"; markers: string[]; @@ -1360,6 +1629,7 @@ interface VerifyRenameInfoCmd { type Cmd = | VerifyCompletionsCmd + | VerifyApplyCodeActionFromCompletionCmd | VerifyBaselineFindAllReferencesCmd | VerifyBaselineDocumentHighlightsCmd | VerifyBaselineGoToDefinitionCmd @@ -1371,7 +1641,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 +1665,21 @@ 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 generateVerifyApplyCodeActionFromCompletion({ marker, options }: VerifyApplyCodeActionFromCompletionCmd): string { + return `f.VerifyApplyCodeActionFromCompletion(t, ${marker}, ${options})`; } function generateBaselineFindAllReferences({ markers, ranges }: VerifyBaselineFindAllReferencesCmd): string { @@ -1456,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": @@ -1497,7 +1783,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..422c31bae0 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -3,6 +3,29 @@ TestAmbientShorthandGotoDefinition TestArgumentsAreAvailableAfterEditsAtEndOfFunction TestAugmentedTypesClass1 TestAugmentedTypesClass3Fourslash +TestAutoImportCompletionAmbientMergedModule1 +TestAutoImportCompletionExportEqualsWithDefault1 +TestAutoImportCompletionExportListAugmentation1 +TestAutoImportCompletionExportListAugmentation2 +TestAutoImportCompletionExportListAugmentation3 +TestAutoImportCompletionExportListAugmentation4 +TestAutoImportFileExcludePatterns3 +TestAutoImportPathsAliasesAndBarrels +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 +TestAutoImportVerbatimTypeOnly1 TestBestCommonTypeObjectLiterals TestBestCommonTypeObjectLiterals1 TestCodeCompletionEscaping @@ -20,6 +43,7 @@ TestCompletionEntryForUnionProperty TestCompletionEntryForUnionProperty2 TestCompletionForComputedStringProperties TestCompletionForMetaProperty +TestCompletionForObjectProperty TestCompletionForStringLiteral TestCompletionForStringLiteral4 TestCompletionForStringLiteralExport @@ -65,7 +89,6 @@ TestCompletionImportModuleSpecifierEndingUnsupportedExtension TestCompletionInChecks1 TestCompletionInFunctionLikeBody_includesPrimitiveTypes TestCompletionInJsDoc -TestCompletionInNamedImportLocation TestCompletionInUncheckedJSFile TestCompletionListBuilderLocations_VariableDeclarations TestCompletionListForDerivedType1 @@ -115,13 +138,51 @@ TestCompletionOfAwaitPromise6 TestCompletionOfAwaitPromise7 TestCompletionOfInterfaceAndVar TestCompletionPreferredSuggestions1 +TestCompletionPropertyShorthandForObjectLiteral5 TestCompletionWithConditionalOperatorMissingColon TestCompletionsAfterJSDoc TestCompletionsBeforeRestArg1 +TestCompletionsClassMemberImportTypeNodeParameter1 +TestCompletionsClassMemberImportTypeNodeParameter2 +TestCompletionsClassMemberImportTypeNodeParameter3 +TestCompletionsClassMemberImportTypeNodeParameter4 TestCompletionsElementAccessNumeric TestCompletionsExportImport TestCompletionsGenericTypeWithMultipleBases1 +TestCompletionsImportBaseUrl TestCompletionsImportOrExportSpecifier +TestCompletionsImport_default_alreadyExistedWithRename +TestCompletionsImport_default_anonymous +TestCompletionsImport_default_didNotExistBefore +TestCompletionsImport_default_exportDefaultIdentifier +TestCompletionsImport_details_withMisspelledName +TestCompletionsImport_exportEquals_anonymous +TestCompletionsImport_exportEquals_global +TestCompletionsImport_filteredByInvalidPackageJson_direct +TestCompletionsImport_filteredByPackageJson_direct +TestCompletionsImport_filteredByPackageJson_nested +TestCompletionsImport_filteredByPackageJson_peerDependencies +TestCompletionsImport_filteredByPackageJson_typesImplicit +TestCompletionsImport_filteredByPackageJson_typesOnly +TestCompletionsImport_importType +TestCompletionsImport_jsxOpeningTagImportDefault +TestCompletionsImport_mergedReExport +TestCompletionsImport_multipleWithSameName +TestCompletionsImport_named_didNotExistBefore +TestCompletionsImport_named_exportEqualsNamespace +TestCompletionsImport_named_namespaceImportExists +TestCompletionsImport_noSemicolons +TestCompletionsImport_ofAlias_preferShortPath +TestCompletionsImport_packageJsonImportsPreference +TestCompletionsImport_quoteStyle +TestCompletionsImport_reExportDefault +TestCompletionsImport_reExportDefault2 +TestCompletionsImport_reExport_wrongName +TestCompletionsImport_require_addToExisting +TestCompletionsImport_typeOnly +TestCompletionsImport_umdDefaultNoCrash1 +TestCompletionsImport_uriStyleNodeCoreModules2 +TestCompletionsImport_windowsPathsProjectRelative TestCompletionsInExport TestCompletionsInExport_moduleBlock TestCompletionsInRequire @@ -153,6 +214,7 @@ TestCompletionsPaths_kinds TestCompletionsPaths_pathMapping TestCompletionsPaths_pathMapping_nonTrailingWildcard1 TestCompletionsPaths_pathMapping_parentDirectory +TestCompletionsRecommended_namespace TestCompletionsRecommended_union TestCompletionsRedeclareModuleAsGlobal TestCompletionsStringsWithTriggerCharacter @@ -160,6 +222,8 @@ TestCompletionsSymbolMembers TestCompletionsTriggerCharacter TestCompletionsTuple TestCompletionsUniqueSymbol1 +TestCompletionsUniqueSymbol_import +TestCompletionsWithDeprecatedTag10 TestConstEnumQuickInfoAndCompletionList TestConstQuickInfoAndCompletionList TestContextuallyTypedFunctionExpressionGeneric1 @@ -216,6 +280,16 @@ TestImportCompletions_importsMap2 TestImportCompletions_importsMap3 TestImportCompletions_importsMap4 TestImportCompletions_importsMap5 +TestImportNameCodeFixExportAsDefault +TestImportSuggestionsCache_exportUndefined +TestImportTypeCompletions1 +TestImportTypeCompletions3 +TestImportTypeCompletions4 +TestImportTypeCompletions5 +TestImportTypeCompletions6 +TestImportTypeCompletions7 +TestImportTypeCompletions8 +TestImportTypeCompletions9 TestIndexerReturnTypes1 TestIndirectClassInstantiation TestInstanceTypesForGenericType1 @@ -246,6 +320,7 @@ TestJsDocPropertyDescription8 TestJsDocPropertyDescription9 TestJsDocServices TestJsDocTagsWithHyphen +TestJsFileImportNoTypes2 TestJsQuickInfoGenerallyAcceptableSize TestJsRequireQuickInfo TestJsdocCallbackTag @@ -387,7 +462,6 @@ TestQuickInfoOnGenericWithConstraints1 TestQuickInfoOnInternalAliases TestQuickInfoOnJsxNamespacedNameWithDoc1 TestQuickInfoOnMethodOfImportEquals -TestQuickInfoOnNarrowedType TestQuickInfoOnNarrowedTypeInModule TestQuickInfoOnNewKeyword01 TestQuickInfoOnObjectLiteralWithAccessors diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index ddac550413..00f39aac1e 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,41 @@ 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() + 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{ @@ -549,7 +589,7 @@ 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 } func (f *FourslashTest) verifyCompletionsResult( @@ -633,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 { @@ -647,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 @@ -673,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) @@ -689,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)) } } @@ -712,36 +765,80 @@ 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", ".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) { - if expected.Detail != nil || expected.Documentation != 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") + var actualAutoImportData, expectedAutoImportData *ls.AutoImportData + if actual.Data != nil { + if data, ok := (*actual.Data).(*ls.CompletionItemData); ok { + actualAutoImportData = data.AutoImport } - if !resultOk { - t.Fatalf(prefix+"Unexpected response type for completion item resolve: %T", resMsg.AsResponse().Result) + } + 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 { + actual = f.resolveCompletionItem(t, actual) + } + + 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") } - actual = result + 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.FilterText != nil { + assertDeepEqual(t, actual.FilterText, expected.FilterText, prefix+" FilterText mismatch") } - assertDeepEqual(t, actual, expected, prefix, completionIgnoreOpts) if expected.Kind != nil { assertDeepEqual(t, actual.Kind, expected.Kind, prefix+" Kind mismatch") } 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, Error: %v", resMsg.AsResponse().Result, resMsg.AsResponse().Error) + } + return result +} + func getExpectedLabel(t *testing.T, item CompletionsExpectedItem) string { switch item := item.(type) { case string: @@ -763,6 +860,57 @@ 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.FileName == options.AutoImportData.FileName) && + (options.AutoImportData.ModuleSpecifier == "" || data.AutoImport.ModuleSpecifier == options.AutoImportData.ModuleSpecifier) && + (options.AutoImportData.ExportName == "" || data.AutoImport.ExportName == options.AutoImportData.ExportName) && + (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) + 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( t *testing.T, markers ...string, @@ -1247,6 +1395,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? @@ -1558,7 +1722,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) @@ -1792,3 +1956,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/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..e5036d3293 --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go @@ -0,0 +1,104 @@ +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 +// @esModuleInterop: false +// @allowSyntheticDefaultImports: false +// @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/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..eeb92339c0 --- /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() + + 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: "react", + }, + })), + 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..57eb4b8e9a --- /dev/null +++ b/internal/fourslash/tests/gen/autoImportProvider_exportMap2_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 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" + "moduleResolution": "node10", + } +} +// @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/autoImportReExportFromAmbientModule_test.go b/internal/fourslash/tests/gen/autoImportReExportFromAmbientModule_test.go new file mode 100644 index 0000000000..a685a1a371 --- /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() + + 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: "/home/src/workspaces/project/node_modules/@types/fs-extra/index.d.ts", + ModuleSpecifier: "fs-extra", + }, + }) +} 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/autoImportSortCaseSensitivity2_test.go b/internal/fourslash/tests/gen/autoImportSortCaseSensitivity2_test.go new file mode 100644 index 0000000000..ff585d978d --- /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() + + 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/autoImportTypeOnlyPreferred1_test.go b/internal/fourslash/tests/gen/autoImportTypeOnlyPreferred1_test.go new file mode 100644 index 0000000000..3a89a0273c --- /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() + + 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/autoImportVerbatimTypeOnly1_test.go b/internal/fourslash/tests/gen/autoImportVerbatimTypeOnly1_test.go new file mode 100644 index 0000000000..6d8622d386 --- /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: "/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: "/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/completionForObjectProperty_test.go b/internal/fourslash/tests/gen/completionForObjectProperty_test.go new file mode 100644 index 0000000000..3ccb4b9527 --- /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/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/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..f300628828 --- /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() + + 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/completionsImportFromJSXTag_test.go b/internal/fourslash/tests/gen/completionsImportFromJSXTag_test.go new file mode 100644 index 0000000000..c0488b300a --- /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() + + 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..39ec087d07 --- /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() + + 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..da67a8a511 --- /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() + + 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: "/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/completionsImportTypeKeyword_test.go b/internal/fourslash/tests/gen/completionsImportTypeKeyword_test.go new file mode 100644 index 0000000000..42b83f978e --- /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() + + 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/completionsImportYieldExpression_test.go b/internal/fourslash/tests/gen/completionsImportYieldExpression_test.go new file mode 100644 index 0000000000..f0c76cee39 --- /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() + + 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..bee727e2cc --- /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() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @moduleResolution: bundler +// @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: "/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..611fdb9572 --- /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() + + 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_augmentation_test.go b/internal/fourslash/tests/gen/completionsImport_augmentation_test.go new file mode 100644 index 0000000000..2c7cdce25b --- /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() + + 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..62a31af0ac --- /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() + + 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: "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/completionsImport_defaultAndNamedConflict_test.go b/internal/fourslash/tests/gen/completionsImport_defaultAndNamedConflict_test.go new file mode 100644 index 0000000000..f60bf9f376 --- /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() + + 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: "/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..38d4aef0f8 --- /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() + + 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: "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: "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..d98caac868 --- /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() + + 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..23d8638a44 --- /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() + + 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..4ffdba061b --- /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..5123c8e3cd --- /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() + + 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_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_default_symbolName_test.go b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go new file mode 100644 index 0000000000..bae20c6a6d --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_default_symbolName_test.go @@ -0,0 +1,62 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + . "github.com/microsoft/typescript-go/internal/fourslash/tests/util" + "github.com/microsoft/typescript-go/internal/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() + + 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 { + 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: "range-parser", + }, + })), + 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: "range-parser", + 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..f0201764ec --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_details_withMisspelledName_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/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: "/a.ts", + ModuleSpecifier: "./a", + }, + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { abc } from "./a"; + +acb;`), + }) +} 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..650cff95f6 --- /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() + + 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..ef1bbfc4b9 --- /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() + + 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..7bdc35017a --- /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() + + 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..6653f114ec --- /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() + + 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..df2677b55e --- /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() + + 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_anonymous_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_test.go new file mode 100644 index 0000000000..f3b7805d04 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_anonymous_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_exportEquals_anonymous(t *testing.T) { + t.Parallel() + 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 +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: "./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: "./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_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_exportEquals_test.go b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go new file mode 100644 index 0000000000..5a1ef9edd0 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_exportEquals_test.go @@ -0,0 +1,91 @@ +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() + + 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 { + 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_filteredByInvalidPackageJson_direct_test.go b/internal/fourslash/tests/gen/completionsImport_filteredByInvalidPackageJson_direct_test.go new file mode 100644 index 0000000000..7d7f135186 --- /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: "react", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "ReactFake", + AdditionalTextEdits: fourslash.AnyTextEdits, + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + 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 new file mode 100644 index 0000000000..bd53aa7be8 --- /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: "react", + }, + })), + 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..27ccbf38d8 --- /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: "react", + }, + })), + 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..69fd73678f --- /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() + + 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..52dee82f49 --- /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: "react", + }, + })), + 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..f2116414aa --- /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: "react", + }, + })), + 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: "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 new file mode 100644 index 0000000000..8997b6e93a --- /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: "react", + }, + })), + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + Excludes: []string{ + "ReactFake", + }, + }, + }) +} 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..e070b3e47f --- /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() + + 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..28c24d84d2 --- /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..1dc2706366 --- /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 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_reExportDefault_test.go b/internal/fourslash/tests/gen/completionsImport_reExportDefault_test.go new file mode 100644 index 0000000000..f6e4129652 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_reExportDefault_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_reExportDefault(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: esnext +// @moduleResolution: node10 +// @Filename: /a/b/impl.ts +export default function foo() {} +// @Filename: /a/index.ts +export { default as foo } from "./b/impl"; +// @Filename: /use.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{ + Exact: CompletionGlobalsPlus( + []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "foo", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "/a/b/impl", + }, + })), + Detail: PtrTo("function foo(): void"), + Kind: PtrTo(lsproto.CompletionItemKindFunction), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, false), + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "/a/b/impl", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { foo } from "./a"; + +fo`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_reExport_wrongName_test.go b/internal/fourslash/tests/gen/completionsImport_reExport_wrongName_test.go new file mode 100644 index 0000000000..4651f917c1 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_reExport_wrongName_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_reExport_wrongName(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /a.ts +export const x = 0; +// @Filename: /index.ts +export { x as y } from "./a"; +// @Filename: /c.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{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "x", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./a", + }, + })), + Detail: PtrTo("const x: 0"), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + &lsproto.CompletionItem{ + Label: "y", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: ".", + }, + })), + Detail: PtrTo("(alias) const y: 0\nexport y"), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "x", + Source: "./a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import { x } from "./a"; + +`), + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "y", + Source: ".", + Description: "Add import from \".\"", + NewFileContent: PtrTo(`import { y } from "."; +import { x } from "./a"; + +`), + }) +} 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_require_addNew_test.go b/internal/fourslash/tests/gen/completionsImport_require_addNew_test.go new file mode 100644 index 0000000000..5f38f4b5b1 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_require_addNew_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_require_addNew(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: /a.js +const x = 0; +module.exports = { x }; +// @Filename: /b.js +x/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "x", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./a", + }, + })), + Detail: PtrTo("(alias) const x: 0\nimport x"), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "x", + Source: "./a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`const { x } = require("./a"); + +x`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_require_addToExisting_test.go b/internal/fourslash/tests/gen/completionsImport_require_addToExisting_test.go new file mode 100644 index 0000000000..e0ee34df82 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_require_addToExisting_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 TestCompletionsImport_require_addToExisting(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: /a.js +const x = 0; +function f() {} +module.exports = { x, f }; +// @Filename: /b.js +const { f } = require("./a"); + +x/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "x", + Data: PtrTo(any(&ls.CompletionItemData{ + AutoImport: &ls.AutoImportData{ + ModuleSpecifier: "./a", + }, + })), + Detail: PtrTo("(alias) const x: 0\nimport x"), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "x", + Source: "./a", + Description: "Update import from \"./a\"", + NewFileContent: PtrTo(`const { f, x } = require("./a"); + +x`), + }) +} diff --git a/internal/fourslash/tests/gen/completionsImport_require_test.go b/internal/fourslash/tests/gen/completionsImport_require_test.go new file mode 100644 index 0000000000..aab622f2ef --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_require_test.go @@ -0,0 +1,55 @@ +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_require(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowJs: true +// @Filename: /a.ts +export const foo = 0; +// @Filename: /b.js +import * as s from "something"; +fo/*b*/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyCompletions(t, "b", &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("const foo: 0"), + Kind: PtrTo(lsproto.CompletionItemKindVariable), + AdditionalTextEdits: fourslash.AnyTextEdits, + SortText: PtrTo(string(ls.SortTextAutoImportSuggestions)), + }, + }, + }, + }) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo("b"), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "foo", + Source: "./a", + Description: "Add import from \"./a\"", + NewFileContent: PtrTo(`import * as s from "something"; +import { foo } from "./a"; +fo`), + }) +} 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..625ab87cce --- /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() + + 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..4f8e7c38b5 --- /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() + + 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_typeOnly_test.go b/internal/fourslash/tests/gen/completionsImport_typeOnly_test.go new file mode 100644 index 0000000000..27d374d54e --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_typeOnly_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 TestCompletionsImport_typeOnly(t *testing.T) { + t.Parallel() + 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 {} +// @Filename: /b.ts +import type { A } from './a'; +const b: B/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToFile(t, "/b.ts") + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "B", + 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 new file mode 100644 index 0000000000..f76355c039 --- /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: bundler +// @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: "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..a1dfd2d6d8 --- /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() + + 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: "classnames", + }, + })), + 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..993593f4d2 --- /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() + + 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_weirdDefaultSynthesis_test.go b/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go new file mode 100644 index 0000000000..5514308ba0 --- /dev/null +++ b/internal/fourslash/tests/gen/completionsImport_weirdDefaultSynthesis_test.go @@ -0,0 +1,34 @@ +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_weirdDefaultSynthesis(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @module: commonjs +// @esModuleInterop: false +// @allowSyntheticDefaultImports: false +// @Filename: /collection.ts +class Collection { + public static readonly default: typeof Collection = Collection; +} +export = Collection as typeof Collection & { default: typeof Collection }; +// @Filename: /index.ts +Colle/**/` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.VerifyApplyCodeActionFromCompletion(t, PtrTo(""), &fourslash.ApplyCodeActionFromCompletionOptions{ + Name: "Collection", + Source: "./collection", + Description: "Add import from \"./collection\"", + NewFileContent: PtrTo(`import Collection = require("./collection"); + +Colle`), + }) +} 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..f81d6b2f98 --- /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/completionsUniqueSymbol_import_test.go b/internal/fourslash/tests/gen/completionsUniqueSymbol_import_test.go new file mode 100644 index 0000000000..acdd1674ab --- /dev/null +++ b/internal/fourslash/tests/gen/completionsUniqueSymbol_import_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 TestCompletionsUniqueSymbol_import(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @noLib: true +// @Filename: /globals.d.ts +declare const Symbol: () => 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/completionsWithDeprecatedTag10_test.go b/internal/fourslash/tests/gen/completionsWithDeprecatedTag10_test.go new file mode 100644 index 0000000000..104b77761c --- /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/importNameCodeFixDefaultExport6_test.go b/internal/fourslash/tests/gen/importNameCodeFixDefaultExport6_test.go new file mode 100644 index 0000000000..43b6d1076a --- /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() + + 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..d5b712b078 --- /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/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..7ca5b026fc --- /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() + + 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..543d69aa3f --- /dev/null +++ b/internal/fourslash/tests/gen/importTypeCompletions5_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 TestImportTypeCompletions5(t *testing.T) { + t.Parallel() + t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @allowSyntheticDefaultImports: false +// @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/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"), + }, + }, + }, + }) +} 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/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/autoimports.go b/internal/ls/autoimports.go index cf89e08fab..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" ) @@ -69,7 +70,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 +84,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 +92,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( @@ -164,7 +165,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) { @@ -193,7 +195,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 +213,7 @@ func (e *exportInfoMap) add( targetFlags: target.Flags, isFromPackageJson: isFromPackageJson, }) + e.exportInfo.Set(key, infos) } func (e *exportInfoMap) search( @@ -221,13 +226,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 +259,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, @@ -340,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, @@ -400,7 +379,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, } } @@ -653,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{} @@ -674,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 } } @@ -721,7 +713,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 } @@ -1442,8 +1434,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) } @@ -1474,6 +1465,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() 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/changetracker.go b/internal/ls/changetracker.go index 34397aa546..db7cfb3fec 100644 --- a/internal/ls/changetracker.go +++ b/internal/ls/changetracker.go @@ -165,6 +165,10 @@ 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) { + 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 { if (needSemicolonBetween(after, newNode)) && (rune(sourceFile.Text()[after.End()-1]) != ';') { // check if previous statement ends with semicolon @@ -213,10 +217,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 @@ -278,6 +282,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 @@ -288,7 +307,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 { @@ -334,3 +353,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/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 95934780dc..65db54b937 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, @@ -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 @@ -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,12 +258,12 @@ func (origin *symbolOriginInfo) toCompletionEntryData() *completionEntryData { } data := origin.data.(*symbolOriginInfoExport) - return &completionEntryData{ + return &AutoImportData{ ExportName: data.exportName, 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)-1] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindPromise, insertQuestionDot)} } else if insertQuestionDot { - symbolToOriginInfoMap[symbolId] = &symbolOriginInfo{kind: symbolOriginInfoKindNullable} + symbolToOriginInfoMap[len(symbols)-1] = &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, @@ -2294,7 +2293,7 @@ func (l *LanguageService) createCompletionItem( } } - var autoImportData *completionEntryData + var autoImportData *AutoImportData if originIsExport(origin) { autoImportData = origin.toCompletionEntryData() hasAction = data.importStatementCompletion == nil @@ -3289,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) @@ -3300,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).(*completionEntryData) - insertEntryData, ok2 := (*entryToInsert.Data).(*completionEntryData) - 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 { @@ -4514,10 +4518,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 +4953,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. @@ -4967,7 +4971,7 @@ type completionEntryData 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"` @@ -4975,7 +4979,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 +5016,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 +5032,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 +5050,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 +5149,7 @@ func (l *LanguageService) getSymbolCompletionFromItemData( ch *checker.Checker, file *ast.SourceFile, position int, - itemData *itemData, + itemData *CompletionItemData, clientOptions *lsproto.CompletionClientCapabilities, preferences *UserPreferences, ) detailsData { @@ -5194,9 +5198,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 || @@ -5219,15 +5222,15 @@ 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 { 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 +5256,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), @@ -5318,7 +5321,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 { diff --git a/internal/ls/organizeimports.go b/internal/ls/organizeimports.go index 8cdeddab5d..b5cfaf68a6 100644 --- a/internal/ls/organizeimports.go +++ b/internal/ls/organizeimports.go @@ -2,15 +2,26 @@ package ls import ( "cmp" + "math" "strings" "github.com/microsoft/typescript-go/internal/ast" "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" ) +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 { // !!! @@ -126,3 +137,251 @@ func isIndexFileName(fileName string) bool { } return fileName == "index" } + +func getOrganizeImportsOrdinalStringComparer(ignoreCase bool) func(a, b string) int { + 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) int) int { + 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) int { + 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) 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) int, preferences *UserPreferences) int { + 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) int) func(s1, s2 *ast.Node) int { + if comparer == nil { + ignoreCase := false + if preferences != nil && !preferences.OrganizeImportsIgnoreCase.IsUnknown() { + ignoreCase = preferences.OrganizeImportsIgnoreCase.IsTrue() + } + comparer = getOrganizeImportsOrdinalStringComparer(ignoreCase) + } + 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) 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) int, isSorted bool) { + 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 + } + } + + return organizeImportsComparers +} + +type caseSensitivityDetectionResult struct { + comparer func(a, b string) int + isSorted bool +} + +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)) + 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) int) caseSensitivityDetectionResult { + var bestComparer func(a, b string) int + bestDiff := math.MaxInt + + 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) int) 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) int, isSorted core.Tristate) { + 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 { + // 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/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/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/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 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) +} 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 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