diff --git a/_extension/package.json b/_extension/package.json index 3a654bc4648..95ddbbf5b66 100644 --- a/_extension/package.json +++ b/_extension/package.json @@ -113,6 +113,12 @@ "enablement": "typescript.native-preview.serverRunning", "category": "TypeScript Native Preview" }, + { + "command": "typescript.native-preview.goToSourceDefinition", + "title": "Go to Source Definition", + "enablement": "typescript.native-preview.serverRunning", + "category": "TypeScript Native Preview" + }, { "title": "Show References of CodeLens", "command": "typescript.native-preview.codeLens.showLocations", @@ -154,7 +160,22 @@ "enablement": "typescript.native-preview.serverRunning", "category": "Developer: TypeScript Native Preview" } - ] + ], + "menus": { + "commandPalette": [ + { + "command": "typescript.native-preview.goToSourceDefinition", + "when": "typescript.native-preview.serverRunning && tsSupportsSourceDefinition" + } + ], + "editor/context": [ + { + "command": "typescript.native-preview.goToSourceDefinition", + "when": "typescript.native-preview.serverRunning && tsSupportsSourceDefinition && (resourceLangId == typescript || resourceLangId == typescriptreact || resourceLangId == javascript || resourceLangId == javascriptreact)", + "group": "navigation@1.41" + } + ] + } }, "main": "./dist/extension.bundle.js", "files": [ diff --git a/_extension/src/client.ts b/_extension/src/client.ts index 9ca8e361e09..040790f04ba 100644 --- a/_extension/src/client.ts +++ b/_extension/src/client.ts @@ -20,6 +20,7 @@ import { configurationMiddleware, sendNotificationMiddleware, } from "./configurationMiddleware"; +import { registerSourceDefinitionFeature } from "./languageFeatures/sourceDefinition"; import { registerTagClosingFeature } from "./languageFeatures/tagClosing"; import * as tr from "./telemetryReporting"; import { @@ -205,6 +206,7 @@ export class Client implements vscode.Disposable { this.disposables.push( serverTelemetryListener, + registerSourceDefinitionFeature(this.client), registerTagClosingFeature("typescript", this.documentSelector, this.client), registerTagClosingFeature("javascript", this.documentSelector, this.client), ); diff --git a/_extension/src/languageFeatures/sourceDefinition.ts b/_extension/src/languageFeatures/sourceDefinition.ts new file mode 100644 index 00000000000..daafbfa1d00 --- /dev/null +++ b/_extension/src/languageFeatures/sourceDefinition.ts @@ -0,0 +1,84 @@ +import * as vscode from "vscode"; +import { + LanguageClient, + Location, + LocationLink, +} from "vscode-languageclient/node"; + +const sourceDefinitionMethod = "custom/textDocument/sourceDefinition"; +const sourceDefinitionCommand = "typescript.native-preview.goToSourceDefinition"; +const sourceDefinitionContext = "tsSupportsSourceDefinition"; + +type SourceDefinitionResponse = Location | Location[] | LocationLink[] | null; + +export function registerSourceDefinitionFeature(client: LanguageClient): vscode.Disposable { + const capabilities = client.initializeResult?.capabilities as { customSourceDefinitionProvider?: boolean; } | undefined; + const enabled = !!capabilities?.customSourceDefinitionProvider; + void vscode.commands.executeCommand("setContext", sourceDefinitionContext, enabled); + + if (!enabled) { + return new vscode.Disposable(() => { + void vscode.commands.executeCommand("setContext", sourceDefinitionContext, false); + }); + } + + const disposable = vscode.commands.registerCommand(sourceDefinitionCommand, async () => { + const activeEditor = vscode.window.activeTextEditor; + if (!activeEditor) { + vscode.window.showErrorMessage("Go to Source Definition failed. No editor is active."); + return; + } + + const { document } = activeEditor; + if (!["javascript", "javascriptreact", "typescript", "typescriptreact"].includes(document.languageId)) { + vscode.window.showErrorMessage("Go to Source Definition failed. Unsupported file type."); + return; + } + + const position = activeEditor.selection.active; + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + title: "Finding source definitions", + }, async (_, token) => { + let response: SourceDefinitionResponse; + try { + response = await client.sendRequest( + sourceDefinitionMethod, + client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), + token, + ); + } + catch { + return; + } + + if (token.isCancellationRequested) { + return; + } + + const p2c = client.protocol2CodeConverter; + const items = !response ? [] : Array.isArray(response) ? response : [response]; + const locations = items.map(item => + LocationLink.is(item) + ? p2c.asLocation({ uri: item.targetUri, range: item.targetSelectionRange }) + : p2c.asLocation(item) + ); + + await vscode.commands.executeCommand( + "editor.action.goToLocations", + document.uri, + position, + locations, + "goto", + "No source definitions found.", + ); + }); + }); + + return vscode.Disposable.from( + disposable, + new vscode.Disposable(() => { + void vscode.commands.executeCommand("setContext", sourceDefinitionContext, false); + }), + ); +} diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index 9b40f4862a8..b8e399f57f9 100755 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -253,6 +253,7 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] { case "baselineGetDefinitionAtPosition": case "baselineGoToType": case "baselineGoToImplementation": + case "baselineGoToSourceDefinition": // Both `baselineGoToDefinition` and `baselineGetDefinitionAtPosition` take the same // arguments, but differ in that... // - `verify.baselineGoToDefinition(...)` called getDefinitionAndBoundSpan @@ -1289,14 +1290,14 @@ function parseBaselineDocumentHighlightsArgs(args: readonly ts.Expression[]): [V } function parseBaselineGoToDefinitionArgs( - funcName: "baselineGoToDefinition" | "baselineGoToType" | "baselineGetDefinitionAtPosition" | "baselineGoToImplementation", + funcName: "baselineGoToDefinition" | "baselineGoToType" | "baselineGetDefinitionAtPosition" | "baselineGoToImplementation" | "baselineGoToSourceDefinition", args: readonly ts.Expression[], ): [VerifyBaselineGoToDefinitionCmd] { let boundSpan: true | undefined; if (funcName === "baselineGoToDefinition") { boundSpan = true; } - let kind: "verifyBaselineGoToDefinition" | "verifyBaselineGoToType" | "verifyBaselineGoToImplementation"; + let kind: "verifyBaselineGoToDefinition" | "verifyBaselineGoToType" | "verifyBaselineGoToImplementation" | "verifyBaselineGoToSourceDefinition"; switch (funcName) { case "baselineGoToDefinition": case "baselineGetDefinitionAtPosition": @@ -1308,6 +1309,9 @@ function parseBaselineGoToDefinitionArgs( case "baselineGoToImplementation": kind = "verifyBaselineGoToImplementation"; break; + case "baselineGoToSourceDefinition": + kind = "verifyBaselineGoToSourceDefinition"; + break; } const newArgs = []; for (const arg of args) { @@ -2986,7 +2990,7 @@ interface VerifyBaselineFindAllReferencesCmd { } interface VerifyBaselineGoToDefinitionCmd { - kind: "verifyBaselineGoToDefinition" | "verifyBaselineGoToType" | "verifyBaselineGoToImplementation"; + kind: "verifyBaselineGoToDefinition" | "verifyBaselineGoToType" | "verifyBaselineGoToImplementation" | "verifyBaselineGoToSourceDefinition"; markers: string[]; boundSpan?: true; ranges?: boolean; @@ -3310,6 +3314,11 @@ function generateBaselineGoToDefinition({ markers, ranges, kind, boundSpan }: Ve return `f.VerifyBaselineGoToImplementation(t)`; } return `f.VerifyBaselineGoToImplementation(t, ${markers.join(", ")})`; + case "verifyBaselineGoToSourceDefinition": + if (ranges || markers.length === 0) { + return `f.VerifyBaselineGoToSourceDefinition(t)`; + } + return `f.VerifyBaselineGoToSourceDefinition(t, ${markers.join(", ")})`; } } @@ -3502,6 +3511,7 @@ function generateCmd(cmd: Cmd): string { case "verifyBaselineGoToDefinition": case "verifyBaselineGoToType": case "verifyBaselineGoToImplementation": + case "verifyBaselineGoToSourceDefinition": return generateBaselineGoToDefinition(cmd); case "verifyBaselineQuickInfo": // Quick Info -> Hover diff --git a/internal/fourslash/_scripts/unparsedTests.txt b/internal/fourslash/_scripts/unparsedTests.txt index 3d7ba11aa41..5213974a4f6 100644 --- a/internal/fourslash/_scripts/unparsedTests.txt +++ b/internal/fourslash/_scripts/unparsedTests.txt @@ -1737,23 +1737,6 @@ getMatchingBracesAdjacentBraces.ts parse error: "Unrecognized fourslash statemen getMatchingBracesNegativeCases.ts parse error: "Unrecognized fourslash statement: test.ranges().forEach(...)" getNameOrDottedNameSpan.ts parse error: "Unrecognized fourslash statement: verify.nameOrDottedNameSpanTextIs(...)" globalCompletionListInsideObjectLiterals.ts parse error: "Expected string literal or object literal for expected completion item, got exact.filter(name => name !== 'p1')" -goToSource1_localJsBesideDts.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource10_mapFromAtTypes3.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource11_propertyOfAlias.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource12_callbackParam.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource13_nodenext.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource14_unresolvedRequireDestructuring.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource15_bundler.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource16_callbackParamDifferentFile.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource17_AddsFileToProject.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource18_reusedFromDifferentFolder.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource2_nodeModulesWithTypes.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource3_nodeModulesAtTypes.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource5_sameAsGoToDef1.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource6_sameAsGoToDef2.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource7_conditionallyMinified.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource8_mapFromAtTypes.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" -goToSource9_mapFromAtTypes2.ts parse error: "Unrecognized fourslash statement: verify.baselineGoToSourceDefinition(...)" identationAfterInterfaceCall.ts parse error: "Unrecognized verify content function: indentationIs" impliedNodeFormat.ts parse error: "Expected a single string literal argument in edit.paste, got `\\n\"${\"a\".repeat(256)}\";`" importDeclPaste0.ts parse error: "Unrecognized edit function: disableFormatting" diff --git a/internal/fourslash/baselineutil.go b/internal/fourslash/baselineutil.go index 1a550c89d84..a830e2ed9d0 100644 --- a/internal/fourslash/baselineutil.go +++ b/internal/fourslash/baselineutil.go @@ -28,6 +28,7 @@ const ( findAllReferencesCmd baselineCommand = "findAllReferences" goToDefinitionCmd baselineCommand = "goToDefinition" goToImplementationCmd baselineCommand = "goToImplementation" + goToSourceDefinitionCmd baselineCommand = "goToSourceDefinition" goToTypeDefinitionCmd baselineCommand = "goToType" inlayHintsCmd baselineCommand = "Inlay Hints" nonSuggestionDiagnosticsCmd baselineCommand = "Syntax and Semantic Diagnostics" @@ -274,7 +275,7 @@ func (f *FourslashTest) getBaselineOptions(command baselineCommand, testPath str return strings.Join(fixedLines, "\n") }, } - case goToDefinitionCmd, goToTypeDefinitionCmd, goToImplementationCmd: + case goToDefinitionCmd, goToTypeDefinitionCmd, goToImplementationCmd, goToSourceDefinitionCmd: return baseline.Options{ Subfolder: subfolder, IsSubmodule: true, @@ -515,7 +516,9 @@ type baselineFourslashLocationsOptions struct { endMarkerSuffix func(span documentSpan) *string getLocationData func(span documentSpan) string - additionalSpan *documentSpan + additionalSpan *documentSpan + preserveResultOrder bool + orderedFiles []lsproto.DocumentUri } func locationToSpan(loc lsproto.Location) documentSpan { @@ -534,6 +537,9 @@ func (f *FourslashTest) getBaselineForLocationsWithFileContents(locations []lspr func (f *FourslashTest) getBaselineForSpansWithFileContents(spans []documentSpan, options baselineFourslashLocationsOptions) string { spansByFile := collections.GroupBy(spans, func(span documentSpan) lsproto.DocumentUri { return span.uri }) + if options.preserveResultOrder { + options.orderedFiles = uniqueFilesInSpanOrder(spans) + } return f.getBaselineForGroupedSpansWithFileContents( spansByFile, options, @@ -549,25 +555,16 @@ func (f *FourslashTest) getBaselineForGroupedSpansWithFileContents(groupedRanges spanToContextId := map[documentSpan]int{} baselineEntries := []string{} - walkDirFn := func(path string, d vfs.DirEntry, e error) error { - if e != nil { - return e - } - - if !d.Type().IsRegular() { - return nil - } - + addFileEntry := func(path string) { fileName := lsconv.FileNameToDocumentURI(path) ranges := groupedRanges.Get(fileName) if len(ranges) == 0 { - return nil + return } content, ok := f.textOfFile(path) if !ok { - // !!! error? - return nil + return } if options.marker != nil && options.marker.FileName() == path { @@ -579,17 +576,34 @@ func (f *FourslashTest) getBaselineForGroupedSpansWithFileContents(groupedRanges } baselineEntries = append(baselineEntries, f.getBaselineContentForFile(path, content, ranges, spanToContextId, options)) - return nil } + walkDirFn := func(path string, d vfs.DirEntry, e error) error { + if e != nil { + return e + } + + if !d.Type().IsRegular() { + return nil + } - err := f.vfs.WalkDir("/", walkDirFn) - if err != nil && !errors.Is(err, fs.ErrNotExist) { - panic("walkdir error during fourslash baseline: " + err.Error()) + addFileEntry(path) + return nil } - err = f.vfs.WalkDir("bundled:///", walkDirFn) - if err != nil && !errors.Is(err, fs.ErrNotExist) { - panic("walkdir error during fourslash baseline: " + err.Error()) + if options.preserveResultOrder { + for _, uri := range options.orderedFiles { + addFileEntry(uri.FileName()) + } + } else { + err := f.vfs.WalkDir("/", walkDirFn) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + panic("walkdir error during fourslash baseline: " + err.Error()) + } + + err = f.vfs.WalkDir("bundled:///", walkDirFn) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + panic("walkdir error during fourslash baseline: " + err.Error()) + } } // In Strada, there is a bug where we only ever add additional spans to baselines if we haven't @@ -620,6 +634,22 @@ func (f *FourslashTest) getBaselineForGroupedSpansWithFileContents(groupedRanges return strings.Join(baselineEntries, "\n\n") } +func uniqueFilesInSpanOrder(spans []documentSpan) []lsproto.DocumentUri { + if len(spans) == 0 { + return nil + } + seen := map[lsproto.DocumentUri]struct{}{} + result := make([]lsproto.DocumentUri, 0, len(spans)) + for _, span := range spans { + if _, ok := seen[span.uri]; ok { + continue + } + seen[span.uri] = struct{}{} + result = append(result, span.uri) + } + return result +} + func (f *FourslashTest) textOfFile(fileName string) (string, bool) { if _, ok := f.openFiles[fileName]; ok { return f.getScriptInfo(fileName).content, true diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 0df43d4daad..f0c182b3b6e 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -1879,9 +1879,10 @@ func (f *FourslashTest) verifyBaselineDefinitions( } f.addResultToBaseline(t, definitionCommand, f.getBaselineForSpansWithFileContents(resultAsSpans, baselineFourslashLocationsOptions{ - marker: markerOrRange, - markerName: definitionMarker, - additionalSpan: additionalSpan, + marker: markerOrRange, + markerName: definitionMarker, + additionalSpan: additionalSpan, + preserveResultOrder: definitionCommand == goToSourceDefinitionCmd, })) } } @@ -1909,6 +1910,33 @@ func (f *FourslashTest) VerifyBaselineGoToTypeDefinition( ) } +func (f *FourslashTest) VerifyBaselineGoToSourceDefinition( + t *testing.T, + markers ...string, +) { + f.verifyBaselineDefinitions( + t, + goToSourceDefinitionCmd, + "/*GOTO SOURCE DEF*/", /*definitionMarker*/ + func(t *testing.T, f *FourslashTest, fileName string, position lsproto.Position) lsproto.LocationOrLocationsOrDefinitionLinksOrNull { + params := &lsproto.TextDocumentPositionParams{ + TextDocument: lsproto.TextDocumentIdentifier{ + Uri: lsconv.FileNameToDocumentURI(f.activeFilename), + }, + Position: f.currentCaretPosition, + } + + result := sendRequest(t, f, lsproto.CustomTextDocumentSourceDefinitionInfo, params) + if result == nil { + return lsproto.LocationOrLocationsOrDefinitionLinksOrNull{} + } + return *result + }, + false, /*includeOriginalSelectionRange*/ + markers..., + ) +} + func (f *FourslashTest) VerifyBaselineWorkspaceSymbol(t *testing.T, query string) { t.Helper() result := sendRequest(t, f, lsproto.WorkspaceSymbolInfo, &lsproto.WorkspaceSymbolParams{Query: query}) diff --git a/internal/fourslash/tests/gen/goToSource10_mapFromAtTypes3_test.go b/internal/fourslash/tests/gen/goToSource10_mapFromAtTypes3_test.go new file mode 100644 index 00000000000..fd1b70217cd --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource10_mapFromAtTypes3_test.go @@ -0,0 +1,81 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource10_mapFromAtTypes3" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource10_mapFromAtTypes3(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/lodash/package.json +{ "name": "lodash", "version": "4.17.15", "main": "./lodash.js" } +// @Filename: /home/src/workspaces/project/node_modules/lodash/lodash.js +;(function() { + /** + * Adds two numbers. + * + * @static + * @memberOf _ + * @since 3.4.0 + * @category Math + * @param {number} augend The first number in an addition. + * @param {number} addend The second number in an addition. + * @returns {number} Returns the total. + * @example + * + * _.add(6, 4); + * // => 10 + */ + var [|/*variable*/add|] = createMathOperation(function(augend, addend) { + return augend + addend; + }, 0); + + function lodash(value) {} + lodash.[|/*property*/add|] = add; + + /** Detect free variable ` + "`" + `global` + "`" + ` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + /** Detect free variable ` + "`" + `self` + "`" + `. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + /** Detect free variable ` + "`" + `exports` + "`" + `. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;//// + /** Detect free variable ` + "`" + `module` + "`" + `. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + if (freeModule) { + // Export for Node.js. + (freeModule.exports = _)._ = _; + // Export for CommonJS support. + freeExports._ = _; + } + else { + // Export to the global object. + root._ = _; + } +}.call(this)); +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/package.json +{ "name": "@types/lodash", "version": "4.14.97", "types": "index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/index.d.ts +export = _; +export as namespace _; +declare const _: _.LoDashStatic; +declare namespace _ { + interface LoDashStatic {} +} +// @Filename: /home/src/workspaces/project/index.ts +import { [|/*start*/add|] } from 'lodash';` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource11_propertyOfAlias_test.go b/internal/fourslash/tests/gen/goToSource11_propertyOfAlias_test.go new file mode 100644 index 00000000000..8a0dc2d3b8e --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource11_propertyOfAlias_test.go @@ -0,0 +1,30 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource11_propertyOfAlias" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource11_propertyOfAlias(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/a.js +export const a = { /*end*/a: 'a' }; +// @Filename: /home/src/workspaces/project/a.d.ts +export declare const a: { a: string }; +// @Filename: /home/src/workspaces/project/b.ts +import { a } from './a'; +a.[|a/*start*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource12_callbackParam_test.go b/internal/fourslash/tests/gen/goToSource12_callbackParam_test.go new file mode 100644 index 00000000000..590ea7418c0 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource12_callbackParam_test.go @@ -0,0 +1,45 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource12_callbackParam" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource12_callbackParam(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/package.json +{ + "name": "@types/yargs", + "version": "1.0.0", + "types": "./index.d.ts" +} +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/index.d.ts +export interface Yargs { positional(): Yargs; } +export declare function command(command: string, cb: (yargs: Yargs) => void): void; +// @Filename: /home/src/workspaces/project/node_modules/yargs/package.json +{ + "name": "yargs", + "version": "1.0.0", + "main": "index.js" +} +// @Filename: /home/src/workspaces/project/node_modules/yargs/index.js +export function command(cmd, cb) { cb({ /*end*/positional: "This is obviously not even close to realistic" }); } +// @Filename: /home/src/workspaces/project/index.ts +import { command } from "yargs"; +command("foo", yargs => { + yargs.[|/*start*/positional|](); +});` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource13_nodenext_test.go b/internal/fourslash/tests/gen/goToSource13_nodenext_test.go new file mode 100644 index 00000000000..93118fb18ae --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource13_nodenext_test.go @@ -0,0 +1,49 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource13_nodenext" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource13_nodenext(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/node_modules/left-pad/package.json +{ + "name": "left-pad", + "version": "1.3.0", + "description": "String left pad", + "main": "index.js", + "types": "index.d.ts" +} +// @Filename: /home/src/workspaces/project/node_modules/left-pad/index.d.ts +declare function leftPad(str: string|number, len: number, ch?: string|number): string; +declare namespace leftPad { } +export = leftPad; +// @Filename: /home/src/workspaces/project/node_modules/left-pad/index.js +module.exports = leftPad; +function /*end*/leftPad(str, len, ch) {} +// @Filename: /home/src/workspaces/project/tsconfig.json +{ + "compilerOptions": { + "module": "node16", + "lib": ["es5"], + "strict": true, + "outDir": "./out", + + } +} +// @Filename: /home/src/workspaces/project/index.mts +import leftPad = require("left-pad"); +/*start*/leftPad("", 4);` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource14_unresolvedRequireDestructuring_test.go b/internal/fourslash/tests/gen/goToSource14_unresolvedRequireDestructuring_test.go new file mode 100644 index 00000000000..7b967b81909 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource14_unresolvedRequireDestructuring_test.go @@ -0,0 +1,25 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource14_unresolvedRequireDestructuring" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource14_unresolvedRequireDestructuring(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @allowJs: true +// @Filename: /home/src/workspaces/project/index.js +const { blah/**/ } = require("unresolved");` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "") +} diff --git a/internal/fourslash/tests/gen/goToSource15_bundler_test.go b/internal/fourslash/tests/gen/goToSource15_bundler_test.go new file mode 100644 index 00000000000..b3293cabab5 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource15_bundler_test.go @@ -0,0 +1,46 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource15_bundler" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource15_bundler(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/tsconfig.json +{ "compilerOptions": { "module": "esnext", "moduleResolution": "bundler", "lib": ["es5"] } } +// @Filename: /home/src/workspaces/project/node_modules/react/package.json +{ "name": "react", "version": "16.8.6", "main": "index.js" } +// @Filename: /home/src/workspaces/project/node_modules/react/index.js +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/react.production.min.js'); +} else { + module.exports = require('./cjs/react.development.js'); +} +// @Filename: /home/src/workspaces/project/node_modules/react/cjs/react.production.min.js +'use strict';exports./*production*/useState=function(a){};exports.version='16.8.6'; +// @Filename: /home/src/workspaces/project/node_modules/react/cjs/react.development.js +'use strict'; +if (process.env.NODE_ENV !== 'production') { + (function() { + function useState(initialState) {} + exports./*development*/useState = useState; + exports.version = '16.8.6'; + }()); +} +// @Filename: /home/src/workspaces/project/index.ts +import { [|/*start*/useState|] } from 'react';` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource16_callbackParamDifferentFile_test.go b/internal/fourslash/tests/gen/goToSource16_callbackParamDifferentFile_test.go new file mode 100644 index 00000000000..3c3a267cd58 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource16_callbackParamDifferentFile_test.go @@ -0,0 +1,50 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource16_callbackParamDifferentFile" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource16_callbackParamDifferentFile(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/package.json +{ + "name": "@types/yargs", + "version": "1.0.0", + "types": "./index.d.ts" +} +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/callback.d.ts +export declare class Yargs { positional(): Yargs; } +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/index.d.ts +import { Yargs } from "./callback"; +export declare function command(command: string, cb: (yargs: Yargs) => void): void; +// @Filename: /home/src/workspaces/project/node_modules/yargs/package.json +{ + "name": "yargs", + "version": "1.0.0", + "main": "index.js" +} +// @Filename: /home/src/workspaces/project/node_modules/yargs/callback.js +export class Yargs { positional() { } } +// @Filename: /home/src/workspaces/project/node_modules/yargs/index.js +import { Yargs } from "./callback"; +export function command(cmd, cb) { cb(Yargs) } +// @Filename: /home/src/workspaces/project/index.ts +import { command } from "yargs"; +command("foo", yargs => { + yargs.[|/*start*/positional|](); +});` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource17_AddsFileToProject_test.go b/internal/fourslash/tests/gen/goToSource17_AddsFileToProject_test.go new file mode 100644 index 00000000000..9cbb21c4d95 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource17_AddsFileToProject_test.go @@ -0,0 +1,50 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource17_AddsFileToProject" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource17_AddsFileToProject(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/package.json +{ + "name": "@types/yargs", + "version": "1.0.0", + "types": "./index.d.ts" +} +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/callback.d.ts +export declare class Yargs { positional(): Yargs; } +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/index.d.ts +import { Yargs } from "./callback"; +export declare function command(command: string, cb: (yargs: Yargs) => void): void; +// @Filename: /home/src/workspaces/project/node_modules/yargs/package.json +{ + "name": "yargs", + "version": "1.0.0", + "main": "index.js" +} +// @Filename: /home/src/workspaces/project/node_modules/yargs/callback.js +export class Yargs { positional() { } } +// @Filename: /home/src/workspaces/project/node_modules/yargs/index.js +// Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage +export function command(cmd, cb) { cb(Yargs) } +// @Filename: /home/src/workspaces/project/index.ts +import { command } from "yargs"; +command("foo", yargs => { + yargs.[|/*start*/positional|](); +});` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource18_reusedFromDifferentFolder_test.go b/internal/fourslash/tests/gen/goToSource18_reusedFromDifferentFolder_test.go new file mode 100644 index 00000000000..ff099b014c5 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource18_reusedFromDifferentFolder_test.go @@ -0,0 +1,53 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource18_reusedFromDifferentFolder" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource18_reusedFromDifferentFolder(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/package.json +{ + "name": "@types/yargs", + "version": "1.0.0", + "types": "./index.d.ts" +} +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/callback.d.ts +export declare class Yargs { positional(): Yargs; } +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/index.d.ts +import { Yargs } from "./callback"; +export declare function command(command: string, cb: (yargs: Yargs) => void): void; +// @Filename: /home/src/workspaces/project/node_modules/yargs/package.json +{ + "name": "yargs", + "version": "1.0.0", + "main": "index.js" +} +// @Filename: /home/src/workspaces/project/node_modules/yargs/callback.js +export class Yargs { positional() { } } +// @Filename: /home/src/workspaces/project/node_modules/yargs/index.js +// Specifically didnt have ./callback import to ensure that resolving module sepcifier adds the file to project at later stage +export function command(cmd, cb) { cb(Yargs) } +// @Filename: /home/src/workspaces/project/folder/random.ts +import { Yargs } from "yargs/callback"; +// @Filename: /home/src/workspaces/project/some/index.ts +import { random } from "../folder/random"; +import { command } from "yargs"; +command("foo", yargs => { + yargs.[|/*start*/positional|](); +});` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource1_localJsBesideDts_test.go b/internal/fourslash/tests/gen/goToSource1_localJsBesideDts_test.go new file mode 100644 index 00000000000..4c1ed88cc3f --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource1_localJsBesideDts_test.go @@ -0,0 +1,29 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource1_localJsBesideDts" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource1_localJsBesideDts(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @Filename: /home/src/workspaces/project/a.js +export const /*end*/a = "a"; +// @Filename: /home/src/workspaces/project/a.d.ts +export declare const a: string; +// @Filename: /home/src/workspaces/project/index.ts +import { a } from [|"./a"/*moduleSpecifier*/|]; +[|a/*identifier*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "identifier", "moduleSpecifier") +} diff --git a/internal/fourslash/tests/gen/goToSource2_nodeModulesWithTypes_test.go b/internal/fourslash/tests/gen/goToSource2_nodeModulesWithTypes_test.go new file mode 100644 index 00000000000..4edf75a72c0 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource2_nodeModulesWithTypes_test.go @@ -0,0 +1,32 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource2_nodeModulesWithTypes" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource2_nodeModulesWithTypes(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/foo/package.json +{ "name": "foo", "version": "1.0.0", "main": "./lib/main.js", "types": "./types/main.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/foo/lib/main.js +export const /*end*/a = "a"; +// @Filename: /home/src/workspaces/project/node_modules/foo/types/main.d.ts +export declare const a: string; +// @Filename: /home/src/workspaces/project/index.ts +import { a } from "foo"; +[|a/*start*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource3_nodeModulesAtTypes_test.go b/internal/fourslash/tests/gen/goToSource3_nodeModulesAtTypes_test.go new file mode 100644 index 00000000000..9f9b7fe6df6 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource3_nodeModulesAtTypes_test.go @@ -0,0 +1,34 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource3_nodeModulesAtTypes" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource3_nodeModulesAtTypes(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/foo/package.json +{ "name": "foo", "version": "1.0.0", "main": "./lib/main.js" } +// @Filename: /home/src/workspaces/project/node_modules/foo/lib/main.js +export const /*end*/a = "a"; +// @Filename: /home/src/workspaces/project/node_modules/@types/foo/package.json +{ "name": "@types/foo", "version": "1.0.0", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/@types/foo/index.d.ts +export declare const a: string; +// @Filename: /home/src/workspaces/project/index.ts +import { a } from "foo"; +[|a/*start*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource5_sameAsGoToDef1_test.go b/internal/fourslash/tests/gen/goToSource5_sameAsGoToDef1_test.go new file mode 100644 index 00000000000..157721027e0 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource5_sameAsGoToDef1_test.go @@ -0,0 +1,32 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource5_sameAsGoToDef1" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource5_sameAsGoToDef1(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @Filename: /home/src/workspaces/project/a.ts +export const /*end*/a = 'a'; +// @Filename: /home/src/workspaces/project/a.d.ts +export declare const a: string; +// @Filename: /home/src/workspaces/project/a.js +export const a = 'a'; +// @Filename: /home/src/workspaces/project/b.ts +import { a } from './a'; +[|a/*start*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") + f.VerifyBaselineGoToDefinition(t, true, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource6_sameAsGoToDef2_test.go b/internal/fourslash/tests/gen/goToSource6_sameAsGoToDef2_test.go new file mode 100644 index 00000000000..d3d26177c18 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource6_sameAsGoToDef2_test.go @@ -0,0 +1,37 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource6_sameAsGoToDef2" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource6_sameAsGoToDef2(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @Filename: /home/src/workspaces/project/node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3", "typesVersions": { "*": { "*": ["./types/*"] } } } +// @Filename: /home/src/workspaces/project/node_modules/foo/src/a.ts +export const /*end*/a = 'a'; +// @Filename: /home/src/workspaces/project/node_modules/foo/types/a.d.ts +export declare const a: string; +//# sourceMappingURL=a.d.ts.map +// @Filename: /home/src/workspaces/project/node_modules/foo/types/a.d.ts.map +{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["../src/a.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,OAAO,CAAC;;AACvB,wBAAsB"} +// @Filename: /home/src/workspaces/project/node_modules/foo/dist/a.js +export const a = 'a'; +// @Filename: /home/src/workspaces/project/b.ts +import { a } from 'foo/a'; +[|a/*start*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") + f.VerifyBaselineGoToDefinition(t, true, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource7_conditionallyMinified_test.go b/internal/fourslash/tests/gen/goToSource7_conditionallyMinified_test.go new file mode 100644 index 00000000000..99d0c5aa2cd --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource7_conditionallyMinified_test.go @@ -0,0 +1,46 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource7_conditionallyMinified" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource7_conditionallyMinified(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/react/package.json +{ "name": "react", "version": "16.8.6", "main": "index.js" } +// @Filename: /home/src/workspaces/project/node_modules/react/index.js +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/react.production.min.js'); +} else { + module.exports = require('./cjs/react.development.js'); +} +// @Filename: /home/src/workspaces/project/node_modules/react/cjs/react.production.min.js +'use strict';exports./*production*/useState=function(a){};exports.version='16.8.6'; +// @Filename: /home/src/workspaces/project/node_modules/react/cjs/react.development.js +'use strict'; +if (process.env.NODE_ENV !== 'production') { + (function() { + function useState(initialState) {} + exports./*development*/useState = useState; + exports.version = '16.8.6'; + }()); +} +// @Filename: /home/src/workspaces/project/index.ts +import { [|/*start*/useState|] } from 'react';` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource8_mapFromAtTypes_test.go b/internal/fourslash/tests/gen/goToSource8_mapFromAtTypes_test.go new file mode 100644 index 00000000000..27f3b64ddcb --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource8_mapFromAtTypes_test.go @@ -0,0 +1,89 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource8_mapFromAtTypes" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource8_mapFromAtTypes(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/lodash/package.json +{ "name": "lodash", "version": "4.17.15", "main": "./lodash.js" } +// @Filename: /home/src/workspaces/project/node_modules/lodash/lodash.js +;(function() { + /** + * Adds two numbers. + * + * @static + * @memberOf _ + * @since 3.4.0 + * @category Math + * @param {number} augend The first number in an addition. + * @param {number} addend The second number in an addition. + * @returns {number} Returns the total. + * @example + * + * _.add(6, 4); + * // => 10 + */ + var [|/*variable*/add|] = createMathOperation(function(augend, addend) { + return augend + addend; + }, 0); + + function lodash(value) {} + lodash.[|/*property*/add|] = add; + + /** Detect free variable ` + "`" + `global` + "`" + ` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + /** Detect free variable ` + "`" + `self` + "`" + `. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + /** Detect free variable ` + "`" + `exports` + "`" + `. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;//// + /** Detect free variable ` + "`" + `module` + "`" + `. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + if (freeModule) { + // Export for Node.js. + (freeModule.exports = _)._ = _; + // Export for CommonJS support. + freeExports._ = _; + } + else { + // Export to the global object. + root._ = _; + } +}.call(this)); +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/package.json +{ "name": "@types/lodash", "version": "4.14.97", "types": "index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/index.d.ts +/// +export = _; +export as namespace _; +declare const _: _.LoDashStatic; +declare namespace _ { + interface LoDashStatic {} +} +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/common/math.d.ts +import _ = require("../index"); +declare module "../index" { + interface LoDashStatic { + add(augend: number, addend: number): number; + } +} +// @Filename: /home/src/workspaces/project/index.ts +import { [|/*start*/add|] } from 'lodash';` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/gen/goToSource9_mapFromAtTypes2_test.go b/internal/fourslash/tests/gen/goToSource9_mapFromAtTypes2_test.go new file mode 100644 index 00000000000..f710ce11932 --- /dev/null +++ b/internal/fourslash/tests/gen/goToSource9_mapFromAtTypes2_test.go @@ -0,0 +1,90 @@ +// Code generated by convertFourslash; DO NOT EDIT. +// To modify this test, run "npm run makemanual goToSource9_mapFromAtTypes2" + +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSource9_mapFromAtTypes2(t *testing.T) { + fourslash.SkipIfFailing(t) + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @lib: es5 +// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/lodash/package.json +{ "name": "lodash", "version": "4.17.15", "main": "./lodash.js" } +// @Filename: /home/src/workspaces/project/node_modules/lodash/lodash.js +;(function() { + /** + * Adds two numbers. + * + * @static + * @memberOf _ + * @since 3.4.0 + * @category Math + * @param {number} augend The first number in an addition. + * @param {number} addend The second number in an addition. + * @returns {number} Returns the total. + * @example + * + * _.add(6, 4); + * // => 10 + */ + var [|/*variable*/add|] = createMathOperation(function(augend, addend) { + return augend + addend; + }, 0); + + function lodash(value) {} + lodash.[|/*property*/add|] = add; + + /** Detect free variable ` + "`" + `global` + "`" + ` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + /** Detect free variable ` + "`" + `self` + "`" + `. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + /** Detect free variable ` + "`" + `exports` + "`" + `. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;//// + /** Detect free variable ` + "`" + `module` + "`" + `. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + if (freeModule) { + // Export for Node.js. + (freeModule.exports = _)._ = _; + // Export for CommonJS support. + freeExports._ = _; + } + else { + // Export to the global object. + root._ = _; + } +}.call(this)); +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/package.json +{ "name": "@types/lodash", "version": "4.14.97", "types": "index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/index.d.ts +/// +export = _; +export as namespace _; +declare const _: _.LoDashStatic; +declare namespace _ { + interface LoDashStatic {} +} +// @Filename: /home/src/workspaces/project/node_modules/@types/lodash/common/math.d.ts +import _ = require("../index"); +declare module "../index" { + interface LoDashStatic { + add(augend: number, addend: number): number; + } +} +// @Filename: /home/src/workspaces/project/index.ts +import [|/*defaultImport*/_|], { [|/*unresolvableNamedImport*/foo|] } from [|/*moduleSpecifier*/'lodash'|]; +_.[|/*propertyAccess*/add|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.MarkTestAsStradaServer() + f.VerifyBaselineGoToSourceDefinition(t, "defaultImport", "unresolvableNamedImport", "moduleSpecifier") +} diff --git a/internal/fourslash/tests/goToDefinitionPreferSourceDefinition_test.go b/internal/fourslash/tests/goToDefinitionPreferSourceDefinition_test.go new file mode 100644 index 00000000000..5ed7b08a02f --- /dev/null +++ b/internal/fourslash/tests/goToDefinitionPreferSourceDefinition_test.go @@ -0,0 +1,57 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/ls/lsutil" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToDefinitionPreferSourceDefinition(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/a.js +export const /*sourceTarget*/a = "a"; +// @Filename: /home/src/workspaces/project/a.d.ts +export declare const /*dtsTarget*/a: string; +// @Filename: /home/src/workspaces/project/index.ts +import { a } from "./a"; +a/*start*/` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + + // 1. Regular go-to-definition: goes to the .d.ts file + f.VerifyBaselineGoToDefinition(t, false /*includeOriginalSelectionRange*/, "start") + + // 2. Go-to-source-definition: goes to the .js file + f.VerifyBaselineGoToSourceDefinition(t, "start") + + // 3. Go-to-definition with preferGoToSourceDefinition: goes to the .js file, same as source definition + f.Configure(t, &lsutil.UserPreferences{PreferGoToSourceDefinition: true}) + f.VerifyBaselineGoToDefinition(t, false /*includeOriginalSelectionRange*/, "start") +} + +func TestGoToDefinitionPreferSourceDefinitionFallback(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export interface Config { + enabled: boolean; +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +exports.makeConfig = () => ({ enabled: true }); +// @Filename: /home/src/workspaces/project/index.ts +import type { Config } from "pkg"; +let value: /*start*/Config;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + + // With preferGoToSourceDefinition, when no source .js definition exists for a type-only symbol, + // go-to-definition should fall back to the .d.ts definition. + f.Configure(t, &lsutil.UserPreferences{PreferGoToSourceDefinition: true}) + f.VerifyBaselineGoToDefinition(t, false /*includeOriginalSelectionRange*/, "start") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionAliasedImportUsage_test.go b/internal/fourslash/tests/goToSourceDefinitionAliasedImportUsage_test.go new file mode 100644 index 00000000000..aa35634b0ea --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionAliasedImportUsage_test.go @@ -0,0 +1,55 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceAliasedImportAtUsageSite(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When the cursor is on a usage of an aliased import (not on the import + // specifier itself), the module specifier is discovered via + // findImportForName, and the original export name is passed as + // additionalNames so that the .js file is searched for the correct + // declaration. Without additionalNames, only the alias name would be + // searched, which does not exist in the .js file. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function unrelated(): void; +export declare function original(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function unrelated() {} +export function /*target*/original() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import { original as renamed } from "pkg"; +renamed/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourceAliasedImportAtUsageSiteNamespaceImport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When an aliased namespace import (import * as ns) is used at a property + // access site (ns.foo), the root identifier's import is discovered and the + // module specifier is used to resolve the property in the .js file. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function helper(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*target*/helper() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import * as ns from "pkg"; +ns./*usage*/helper();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionAliasedImportWithPrecedingExports_test.go b/internal/fourslash/tests/goToSourceDefinitionAliasedImportWithPrecedingExports_test.go new file mode 100644 index 00000000000..501806bada7 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionAliasedImportWithPrecedingExports_test.go @@ -0,0 +1,53 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceAliasedImportWithPrecedingExports(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When importing { original as alias }, the module specifier path resolves + // the alias text (not the original name). If the target function is NOT the + // first export in the .js file, the entry-declaration fallback will point to + // the wrong declaration. The fix should resolve to the original export name. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function unrelated(): void; +export declare function original(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function unrelated() {} +export function /*target*/original() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import { original as /*aliasedImport*/renamed } from "pkg"; +renamed();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "aliasedImport") +} + +func TestGoToSourceReExportAliasWithPrecedingExports(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Re-export with alias: export { original as alias } from "pkg" + // should navigate to the original export, not the first statement. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function unrelated(): void; +export declare function original(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function unrelated() {} +export function /*target*/original() { return "ok"; } +// @Filename: /home/src/workspaces/project/reexport.ts +export { original as /*reExportAlias*/renamed } from "pkg";` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "reExportAlias") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionDefaultExport_test.go b/internal/fourslash/tests/goToSourceDefinitionDefaultExport_test.go new file mode 100644 index 00000000000..c81aa1d0d74 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionDefaultExport_test.go @@ -0,0 +1,153 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceNamedAndDefaultExport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // findDeclarationNodesByName correctly finds both named exports and + // default-exported classes/functions via the AST visitor. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export default class Widget {} +export declare function helper(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export default class /*targetWidget*/Widget {} +export function /*targetHelper*/helper() {} +// @Filename: /home/src/workspaces/project/index.ts +import /*importDefault*/Widget, { /*importHelper*/helper } from "pkg"; +Widget; +helper();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importDefault", "importHelper") +} + +func TestGoToSourceDefaultImportNotFirstStatement(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Default import navigates to the actual export default declaration, + // not the first statement of the file, when the default export is not first. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare const version: string; +export default class Widget {} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const version = "1.0"; +export default class /*targetWidget*/Widget {} +// @Filename: /home/src/workspaces/project/index.ts +import /*importDefault*/Widget from "pkg"; +Widget;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importDefault") +} + +func TestGoToSourceUnnamedDefaultExport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export default function(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export default /*targetDefault*/function() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import /*importDefault*/myFunc from "pkg"; +myFunc/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importDefault", "usage") +} + +func TestGoToSourceEmptyNamesEntryFallback(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // getCandidateSourceDeclarationNames returns empty names, + // so mapDeclarationToSourceDefinitions falls through to entry declarations. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +declare const _default: { run(): void }; +export default _default; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export default { run() {} }; +// @Filename: /home/src/workspaces/project/index.ts +import /*defaultImport*/pkg from "pkg"; +pkg.run();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "defaultImport") +} + +func TestGoToSourceExportAssignmentDefault(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // ExportAssignment/default path in findDeclarationNodesByName + // and getCandidateSourceDeclarationNames. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +declare const _default: { run(): void }; +export default _default; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +/*target*/export default { run() {} }; +// @Filename: /home/src/workspaces/project/index.ts +import pkg from "pkg"; +pkg/*usage*/;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourceExportAssignment(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // findDeclarationNodesByName finds export assignment (export = ...) + // when searching for "default". + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/legacy/package.json +{ "name": "legacy", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/legacy/index.d.ts +declare function legacyFn(): string; +export = legacyFn; +// @Filename: /home/src/workspaces/project/node_modules/legacy/index.js +function /*targetFn*/legacyFn() { return "ok"; } +module.exports = legacyFn; +// @Filename: /home/src/workspaces/project/index.ts +import /*importName*/legacyFn from "legacy"; +legacyFn();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName") +} + +func TestGoToSourceExportAssignmentExpression(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export default function createThing(): { value: number }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export default function createThing() { return { value: 42 }; } +// @Filename: /home/src/workspaces/project/index.ts +import /*defaultName*/createThing from "pkg"; +createThing/*callDefault*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "defaultName", "callDefault") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionDefaultUsageSite_test.go b/internal/fourslash/tests/goToSourceDefinitionDefaultUsageSite_test.go new file mode 100644 index 00000000000..44acf0d8a02 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionDefaultUsageSite_test.go @@ -0,0 +1,56 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceDefaultImportUsageSiteChecker(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When the cursor is on a usage of a default import (not on the import + // clause itself), the checker path is taken. getCandidateSourceDeclarationNames + // must include "default" from the resolved declaration's export-default + // modifier, since isDefaultImportName returns false at the usage site. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export default class Widget { + render(): void; +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export default class /*targetWidget*/Widget { + /*targetRender*/render() {} +} +// @Filename: /home/src/workspaces/project/index.ts +import Widget from "pkg"; +const w = new Widget/*constructUsage*/("test"); +w./*methodUsage*/render();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "constructUsage", "methodUsage") +} + +func TestGoToSourceDefaultImportReExportUsage(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Default import re-exported and then used at a call site. The checker + // must resolve the alias chain, and the source definition should reach + // the original implementation file. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export default function greet(name: string): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export default function /*targetGreet*/greet(name) { return "Hello, " + name; } +// @Filename: /home/src/workspaces/project/index.ts +import greet from "pkg"; +greet/*callUsage*/("world");` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "callUsage") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionEmptyAndMissing_test.go b/internal/fourslash/tests/goToSourceDefinitionEmptyAndMissing_test.go new file mode 100644 index 00000000000..8e3dc5f1161 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionEmptyAndMissing_test.go @@ -0,0 +1,48 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceDefinitionEmptyJsFile(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When the resolved .js file is empty (0 statements), source definition + // navigates to the SourceFile node itself. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function foo(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +// @Filename: /home/src/workspaces/project/index.ts +import { foo } from /*specifier*/"pkg"; +foo();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "specifier") +} + +func TestGoToSourceDefaultImportNoDefaultInJs(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When a default import resolves to a .js file that has no default export, + // source definition falls back to the first statement of the file. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export default function create(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +/*targetEntry*/function internalCreate() { return {}; } +module.exports = { create: internalCreate }; +// @Filename: /home/src/workspaces/project/index.ts +import /*importDefault*/create from "pkg"; +create();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importDefault") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionImportVariants_test.go b/internal/fourslash/tests/goToSourceDefinitionImportVariants_test.go new file mode 100644 index 00000000000..d69da575b5c --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionImportVariants_test.go @@ -0,0 +1,52 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceRequireCall(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // findContainingModuleSpecifier handles require() calls. + const content = `// @moduleResolution: bundler +// @allowJs: true +// @checkJs: true +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function helper(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +exports./*target*/helper = function() { return "ok"; }; +// @Filename: /home/src/workspaces/project/index.js +const { /*importName*/helper } = require("pkg"); +helper/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName", "usage") +} + +func TestGoToSourceDynamicImport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // findContainingModuleSpecifier handles dynamic import() calls. + const content = `// @moduleResolution: bundler +// @target: esnext +// @module: esnext +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function dynHelper(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*target*/dynHelper() { return "dynamic"; } +// @Filename: /home/src/workspaces/project/index.ts +async function main() { + const mod = await import("pkg"); + mod./*usage*/dynHelper(); +}` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionImports_test.go b/internal/fourslash/tests/goToSourceDefinitionImports_test.go new file mode 100644 index 00000000000..c5bc359e03c --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionImports_test.go @@ -0,0 +1,278 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceAliasedImportExport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare const foo: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +exports./*target*/foo = 1; +// @Filename: /home/src/workspaces/project/index.ts +import { foo as /*importAlias*/bar } from "pkg"; +bar; +// @Filename: /home/src/workspaces/project/reexport.ts +export { foo as /*reExportAlias*/bar } from "pkg";` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importAlias", "reExportAlias") +} + +func TestGoToSourceAliasedImportSpecifier(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // import { original as alias } uses the propertyName branch. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function original(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*target*/original() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import { original as /*aliasedImport*/renamed } from "pkg"; +renamed();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "aliasedImport") +} + +func TestGoToSourceCallThroughImport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When calling an imported function, the checker returns both the import specifier + // (in the current file) and the call signature target (from .d.ts → mapped to .js). + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare class Widget { + constructor(name: string); + render(): void; +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export class /*targetWidget*/Widget { + constructor(name) { this.name = name; } + /*targetRender*/render() {} +} +// @Filename: /home/src/workspaces/project/index.ts +import { Widget } from "pkg"; +const w = new /*constructorCall*/Widget("test"); +w./*methodCall*/render();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "constructorCall", "methodCall") +} + +func TestGoToSourceCallbackParam(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/package.json +{ + "name": "@types/yargs", + "version": "1.0.0", + "types": "./index.d.ts" +} +// @Filename: /home/src/workspaces/project/node_modules/@types/yargs/index.d.ts +export interface Yargs { positional(): Yargs; } +export declare function command(command: string, cb: (yargs: Yargs) => void): void; +// @Filename: /home/src/workspaces/project/node_modules/yargs/package.json +{ + "name": "yargs", + "version": "1.0.0", + "main": "index.js" +} +// @Filename: /home/src/workspaces/project/node_modules/yargs/index.js +export function command(cmd, cb) { cb({ /*end*/positional: "This is obviously not even close to realistic" }); } +// @Filename: /home/src/workspaces/project/index.ts +import { command } from "yargs"; +command("foo", yargs => { + yargs.[|/*start*/positional|](); +});` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} + +func TestGoToSourceReExportNames(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function foo(): string; +export declare function bar(): number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*targetFoo*/foo() { return "ok"; } +export function /*targetBar*/bar() { return 42; } +// @Filename: /home/src/workspaces/project/reexport.ts +export { /*reExportFoo*/foo, /*reExportBar*/bar } from "pkg"; +// @Filename: /home/src/workspaces/project/index.ts +import { foo, bar } from [|"pkg"/*moduleSpecifier*/|];` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "reExportFoo", "reExportBar", "moduleSpecifier") +} + +func TestGoToSourceReExportModuleSpecifier(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function alpha(): string; +export declare function beta(): number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*targetAlpha*/alpha() { return "a"; } +export function /*targetBeta*/beta() { return 2; } +// @Filename: /home/src/workspaces/project/reexport.ts +export { alpha, beta } from [|"pkg"/*reExportSpecifier*/|];` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "reExportSpecifier") +} + +func TestGoToSourceReExportedImplementation(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts", "type": "module" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export { foo } from "./foo"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export { foo } from "./foo.js"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/foo.d.ts +export declare function foo(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/foo.js +export function /*target*/foo() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/foo } from "pkg"; +foo/*start*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName", "start") +} + +func TestGoToSourceImportFilteredByExternalDeclaration(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function helper(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*target*/helper() {} +// @Filename: /home/src/workspaces/project/index.ts +import { helper } from "pkg"; +helper/*usage*/(); +export { helper as /*reExport*/myHelper } from "pkg";` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage", "reExport") +} + +func TestGoToSourceDtsReExport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // The .d.ts declaration itself re-exports from another module, + // so findContainingModuleSpecifier(declaration) finds that specifier. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.d.ts +export declare function helper(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.js +export function /*target*/helper() {} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export { helper } from "./impl"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export { helper } from "./impl.js"; +// @Filename: /home/src/workspaces/project/index.ts +import { helper } from "pkg"; +helper/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourceBarrelReExportChain(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // index.js re-exports from impl.js, causing getForwardedImplementationFiles + // to follow the chain. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.js +export function /*target*/doWork() { return 42; } +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.d.ts +export declare function doWork(): number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export { doWork } from "./impl"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export { doWork } from "./impl.js"; +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/doWork } from "pkg"; +doWork/*callSite*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName", "callSite") +} + +func TestGoToSourceCJSReExportViaDefineProperty(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function greet(name: string): string; +export declare enum TargetPopulation { + Team = "team", + Public = "public", +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TargetPopulation = exports.greet = void 0; +var impl_1 = require("./impl"); +Object.defineProperty(exports, "greet", { enumerable: true, get: function () { return impl_1.greet; } }); +var types_1 = require("./types"); +Object.defineProperty(exports, "TargetPopulation", { enumerable: true, get: function () { return types_1.TargetPopulation; } }); +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.js +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.greet = void 0; +function /*greetImpl*/greet(name) { return "Hello, " + name; } +exports.greet = greet; +// @Filename: /home/src/workspaces/project/node_modules/pkg/types.js +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TargetPopulation = void 0; +var /*targetPopulationImpl*/TargetPopulation; +(function (TargetPopulation) { + TargetPopulation["Team"] = "team"; + TargetPopulation["Public"] = "public"; +})(TargetPopulation || (exports.TargetPopulation = TargetPopulation = {})); +// @Filename: /home/src/workspaces/project/index.ts +import { /*namedImport*/greet, /*enumImport*/TargetPopulation } from "pkg"; +greet/*call*/("world"); +TargetPopulation/*enumAccess*/.Team;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "namedImport", "enumImport", "call", "enumAccess") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionMergedDeclarations_test.go b/internal/fourslash/tests/goToSourceDefinitionMergedDeclarations_test.go new file mode 100644 index 00000000000..db27f415a21 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionMergedDeclarations_test.go @@ -0,0 +1,36 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceMergedDeclarationDedup(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When a symbol has merged declarations (class + namespace), source + // definition deduplicates them and navigates to the single source class. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare class /*dtsClass*/Util { + run(): void; +} +export declare namespace Util { + export const version: string; +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export class /*targetUtil*/Util { + run() {} +} +Util.version = "1.0"; +// @Filename: /home/src/workspaces/project/index.ts +import { /*importUtil*/Util } from "pkg"; +const u: /*typeRef*/Util = new Util();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importUtil", "typeRef") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionNestedNodeModules_test.go b/internal/fourslash/tests/goToSourceDefinitionNestedNodeModules_test.go new file mode 100644 index 00000000000..be6191f1610 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionNestedNodeModules_test.go @@ -0,0 +1,36 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceNestedNodeModules(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When a .d.ts file is inside nested node_modules (more than one /node_modules/ + // segment), the findImplementationFileFromDtsFileName should bail out rather + // than trying to resolve, since the package name extraction may be incorrect. + // The module specifier path should still work though. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/outer/package.json +{ "name": "outer", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/outer/index.d.ts +export { inner } from "./node_modules/inner/index"; +// @Filename: /home/src/workspaces/project/node_modules/outer/index.js +export { inner } from "./node_modules/inner/index.js"; +// @Filename: /home/src/workspaces/project/node_modules/outer/node_modules/inner/package.json +{ "name": "inner", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/outer/node_modules/inner/index.d.ts +export declare function inner(): string; +// @Filename: /home/src/workspaces/project/node_modules/outer/node_modules/inner/index.js +export function /*target*/inner() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/inner } from "outer"; +inner/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName", "usage") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionNestedScope_test.go b/internal/fourslash/tests/goToSourceDefinitionNestedScope_test.go new file mode 100644 index 00000000000..8f2442e4896 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionNestedScope_test.go @@ -0,0 +1,58 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceNestedScopeShadowing(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // findDeclarationNodesByName should only match top-level/exported declarations, + // not nested locals that happen to share the same name. Here "helper" is + // exported at the top level, but there's also a local "helper" variable inside + // a function body. We should navigate to the exported function, not the local. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function helper(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*targetHelper*/helper() { return "ok"; } +function unrelated() { + const helper = "shadow"; + return helper; +} +// @Filename: /home/src/workspaces/project/index.ts +import { /*importHelper*/helper } from "pkg"; +helper/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importHelper", "usage") +} + +func TestGoToSourceNestedClassShadowing(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // A class "Widget" is exported at the top level, and there's also a local + // class "Widget" inside a function. We should only navigate to the exported one. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare class Widget {} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export class /*targetWidget*/Widget {} +function factory() { + class Widget { constructor() { this.local = true; } } + return new Widget(); +} +// @Filename: /home/src/workspaces/project/index.ts +import { /*importWidget*/Widget } from "pkg"; +new Widget();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importWidget") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionNonNodeModulesDts_test.go b/internal/fourslash/tests/goToSourceDefinitionNonNodeModulesDts_test.go new file mode 100644 index 00000000000..f64caef19b1 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionNonNodeModulesDts_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceFindImplementationNonNodeModules(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When a .d.ts file is not in node_modules and has no sibling .js, + // source definition falls back to the standard definition provider + // and navigates to the .d.ts declaration. + const content = `// @moduleResolution: bundler +// @declaration: true +// @Filename: /home/src/workspaces/project/lib/helper.d.ts +export declare function helper(): string; +// @Filename: /home/src/workspaces/project/index.ts +import { /*usage*/helper } from "./lib/helper"; +helper();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionPackageResolution_test.go b/internal/fourslash/tests/goToSourceDefinitionPackageResolution_test.go new file mode 100644 index 00000000000..3bcd7553f77 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionPackageResolution_test.go @@ -0,0 +1,109 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceAtTypesPackage(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // NoDts resolver can't resolve "foo" to any .js (only @types/foo has .d.ts), + // so findImplementationFileFromDtsFileName maps @types/foo → foo and finds the .js. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/foo/package.json +{ "name": "@types/foo", "version": "1.0.0" } +// @Filename: /home/src/workspaces/project/node_modules/@types/foo/index.d.ts +export declare function bar(): string; +// @Filename: /home/src/workspaces/project/node_modules/foo/package.json +{ "name": "foo", "version": "1.0.0", "main": "./index.js" } +// @Filename: /home/src/workspaces/project/node_modules/foo/index.js +export function /*target*/bar() { return "hello"; } +// @Filename: /home/src/workspaces/project/index.ts +import { bar } from "foo"; +bar/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourcePackageIndexDts(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When the .d.ts is index.d.ts, tryPackageRootFirst is true, + // so package root resolution is tried before subpath. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./lib/index.js", "types": "./lib/index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/lib/index.d.ts +export declare function greet(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/lib/index.js +export function /*target*/greet() { return "hi"; } +// @Filename: /home/src/workspaces/project/index.ts +import { greet } from "pkg"; +greet/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourcePackageRootThenSubpath(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // tryPackageRootFirst is true (index.d.ts), root resolution fails because + // there's no main entry, but subpath resolution ("pkg/index") succeeds. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function work(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*target*/work() {} +// @Filename: /home/src/workspaces/project/index.ts +import { work } from "pkg"; +work/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourcePackageRootFallsBackToSubpath(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // tryPackageRootFirst is true (index.d.ts), root resolution fails, + // falls back to subpath. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function work(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*target*/work() {} +// @Filename: /home/src/workspaces/project/index.ts +import { work } from "pkg"; +work/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourceSubpathNotIndex(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Subpath resolution succeeds when the d.ts is NOT index.d.ts. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "types": "./lib/utils.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/lib/utils.d.ts +export declare function util(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/lib/utils.js +export function /*target*/util() {} +// @Filename: /home/src/workspaces/project/index.ts +import { util } from "pkg"; +util/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionProperties_test.go b/internal/fourslash/tests/goToSourceDefinitionProperties_test.go new file mode 100644 index 00000000000..e26ce9283bb --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionProperties_test.go @@ -0,0 +1,116 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceAccessExpressionProperty(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare const obj: { greet(name: string): string; count: number; }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const /*targetObj*/obj = { /*targetGreet*/greet(name) { return name; }, /*targetCount*/count: 42 }; +// @Filename: /home/src/workspaces/project/index.ts +import { obj } from "pkg"; +obj./*propAccess*/greet("world"); +obj./*propAccess2*/count;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "propAccess", "propAccess2") +} + +func TestGoToSourcePropertyOfAlias(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/a.js +export const a = { /*end*/a: 'a' }; +// @Filename: /home/src/workspaces/project/a.d.ts +export declare const a: { a: string }; +// @Filename: /home/src/workspaces/project/b.ts +import { a } from './a'; +a.[|a/*start*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} + +func TestGoToSourceIndexSignatureProperty(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When accessing a property defined via index signature, getDeclarationsFromLocation + // returns empty, so the GetPropertyOfType fallback is used. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare const config: { readonly [key: string]: string; name: string }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const config = { /*targetName*/name: "test" }; +// @Filename: /home/src/workspaces/project/index.ts +import { config } from "pkg"; +config./*propAccess*/name;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "propAccess") +} + +func TestGoToSourceMappedTypeProperty(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // getDeclarationsFromLocation returns empty for a property that exists only + // via a mapped type (no explicit declaration), so GetPropertyOfType fallback is used. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +type Keys = "a" | "b"; +export declare const obj: { [K in Keys]: number }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const obj = { a: 1, /*target*/b: 2 }; +// @Filename: /home/src/workspaces/project/index.ts +import { obj } from "pkg"; +obj./*propAccess*/b;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "propAccess") +} + +func TestGoToSourceCommonJSAliasPrefersDeclaration(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare enum TargetPopulation { + Team = "team", + Internal = "internal", + Insiders = "insider", + Public = "public", +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TargetPopulation = void 0; +var TargetPopulation; +(function (TargetPopulation) { + TargetPopulation["Team"] = "team"; + TargetPopulation["Internal"] = "internal"; + TargetPopulation["Insiders"] = "insider"; + TargetPopulation["Public"] = "public"; +})(TargetPopulation || (exports.TargetPopulation = TargetPopulation = {})); +// @Filename: /home/src/workspaces/project/index.ts +import * as tas from "pkg"; +tas./*start*/TargetPopulation.Public;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionPropertyAccessNoDecl_test.go b/internal/fourslash/tests/goToSourceDefinitionPropertyAccessNoDecl_test.go new file mode 100644 index 00000000000..56146310616 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionPropertyAccessNoDecl_test.go @@ -0,0 +1,75 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourcePropertyAccessNoDeclaration(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When a property exists only via a mapped type in the .d.ts, the checker + // returns no declarations. The source definition resolver should still + // navigate to the property in the .js file by finding the module specifier + // from the parent expression's import declaration. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +type Keys = "alpha" | "beta"; +export declare const config: { [K in Keys]: string }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const config = { /*targetAlpha*/alpha: "a", /*targetBeta*/beta: "b" }; +// @Filename: /home/src/workspaces/project/index.ts +import { config } from "pkg"; +config./*accessAlpha*/alpha; +config./*accessBeta*/beta;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "accessAlpha", "accessBeta") +} + +func TestGoToSourcePropertyAccessDeepChain(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Deep property access chain: import * as ns; ns.obj.prop + // where the intermediate object has no declaration but the root + // identifier can be traced back to its import. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare const nested: { inner: { value: number } }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const nested = { inner: { /*targetValue*/value: 42 } }; +// @Filename: /home/src/workspaces/project/index.ts +import { nested } from "pkg"; +nested.inner./*accessValue*/value;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "accessValue") +} + +func TestGoToSourcePropertyAccessNamespaceImport(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // import * as ns from "pkg"; ns.thing — where "thing" has no declarations + // from the checker (e.g. module augmentation or dynamic). + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +type Keys = "x" | "y"; +export declare const coords: { [K in Keys]: number }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const coords = { /*targetX*/x: 10, /*targetY*/y: 20 }; +// @Filename: /home/src/workspaces/project/index.ts +import { coords } from "pkg"; +coords./*accessX*/x; +coords./*accessY*/y;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "accessX", "accessY") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionPropertyAccess_test.go b/internal/fourslash/tests/goToSourceDefinitionPropertyAccess_test.go new file mode 100644 index 00000000000..d8290935ac9 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionPropertyAccess_test.go @@ -0,0 +1,55 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceMappedTypePropertyWithMatch(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When accessing a property that only exists via a mapped type, the checker + // returns no declarations. The property access fallback (GetPropertyOfType) + // should find the property if it's in the .js implementation file. + // This test differs from the existing goToSourceMappedTypeProperty by having + // a named explicit property in the .d.ts alongside the mapped type. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare const obj: { a: number; b: number }; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export const obj = { /*targetA*/a: 1, /*targetB*/b: 2 }; +// @Filename: /home/src/workspaces/project/index.ts +import { obj } from "pkg"; +obj./*propA*/a; +obj./*propB*/b;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "propA", "propB") +} + +func TestGoToSourceNamespaceImportProperty(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // import * as ns from "pkg"; ns.prop — should navigate to the property + // in the .js file. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function helper(): void; +export declare const value: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*targetHelper*/helper() {} +export const /*targetValue*/value = 42; +// @Filename: /home/src/workspaces/project/index.ts +import * as pkg from "pkg"; +pkg./*helperAccess*/helper(); +pkg./*valueAccess*/value;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "helperAccess", "valueAccess") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionReExportChain_test.go b/internal/fourslash/tests/goToSourceDefinitionReExportChain_test.go new file mode 100644 index 00000000000..916a3e9e5a7 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionReExportChain_test.go @@ -0,0 +1,30 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceForwardedReExportChain(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When an implementation file re-exports from another file, source + // definition follows the re-export chain to the actual implementation. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function helper(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export { helper } from './impl.js'; +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.js +export function /*targetHelper*/helper() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import { /*importHelper*/helper } from "pkg"; +helper();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importHelper") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionScopedPackage_test.go b/internal/fourslash/tests/goToSourceDefinitionScopedPackage_test.go new file mode 100644 index 00000000000..51595aadd73 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionScopedPackage_test.go @@ -0,0 +1,49 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceScopedPackage(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Scoped packages (@scope/pkg) exercise UnmangleScopedPackageName + // in findImplementationFileFromDtsFileName. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@myscope/mylib/package.json +{ "name": "@myscope/mylib", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/@myscope/mylib/index.d.ts +export declare function scopedHelper(): string; +// @Filename: /home/src/workspaces/project/node_modules/@myscope/mylib/index.js +export function /*target*/scopedHelper() { return "scoped"; } +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/scopedHelper } from "@myscope/mylib"; +scopedHelper/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName", "usage") +} + +func TestGoToSourceScopedAtTypesPackage(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // @types/@scope/pkg should map to @scope/pkg implementation. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/myns__mylib/package.json +{ "name": "@types/myns__mylib", "version": "1.0.0" } +// @Filename: /home/src/workspaces/project/node_modules/@types/myns__mylib/index.d.ts +export declare function nsHelper(): number; +// @Filename: /home/src/workspaces/project/node_modules/@myns/mylib/package.json +{ "name": "@myns/mylib", "version": "1.0.0", "main": "./index.js" } +// @Filename: /home/src/workspaces/project/node_modules/@myns/mylib/index.js +export function /*target*/nsHelper() { return 42; } +// @Filename: /home/src/workspaces/project/index.ts +import { nsHelper } from "@myns/mylib"; +nsHelper/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionTripleSlashUnresolved_test.go b/internal/fourslash/tests/goToSourceDefinitionTripleSlashUnresolved_test.go new file mode 100644 index 00000000000..36b07785feb --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionTripleSlashUnresolved_test.go @@ -0,0 +1,21 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceDefinitionUnresolvedTripleSlash(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When the cursor is on a triple-slash reference directive that doesn't + // resolve to a file, source definition returns empty results. + const content = `// @Filename: /home/src/workspaces/project/index.ts +/// +export {};` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "marker") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionTripleSlash_test.go b/internal/fourslash/tests/goToSourceDefinitionTripleSlash_test.go new file mode 100644 index 00000000000..14ed7574d0e --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionTripleSlash_test.go @@ -0,0 +1,56 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceReferenceTypesToJS(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // /// resolves to @types/foo/index.d.ts. + // Source definition should find the corresponding foo/index.js. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/@types/foo/package.json +{ "name": "@types/foo", "version": "1.0.0" } +// @Filename: /home/src/workspaces/project/node_modules/@types/foo/index.d.ts +export declare function bar(): string; +// @Filename: /home/src/workspaces/project/node_modules/foo/package.json +{ "name": "foo", "version": "1.0.0", "main": "./index.js" } +// @Filename: /home/src/workspaces/project/node_modules/foo/index.js +export function /*target*/bar() { return "hello"; } +// @Filename: /home/src/workspaces/project/index.ts +/// +import { bar } from "foo"; +bar();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "refTypes") +} + +func TestGoToSourceReferencePathToDts(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // /// where a sibling .js file exists. + // Source definition should navigate to the .js implementation. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +/// +export declare function main(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/lib.d.ts +export declare function helper(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/lib.js +export function /*target*/helper() { return "ok"; } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function main() {} +// @Filename: /home/src/workspaces/project/index.ts +/// +declare function helper(): string;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "refPath") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionTypeOnlySymbol_test.go b/internal/fourslash/tests/goToSourceDefinitionTypeOnlySymbol_test.go new file mode 100644 index 00000000000..d32a0bd60a0 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionTypeOnlySymbol_test.go @@ -0,0 +1,81 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceDefinitionTypeOnlyImportFallsBackToDeclaration(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When source definition is invoked on a type-only symbol (e.g. an + // interface) imported via a non-type-only import, the .js file has no + // corresponding declaration. Source definition should fall back to the + // .d.ts declaration rather than jumping to the first line of the .js file. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export interface /*targetDecl*/Config { + name: string; + value: number; +} +export declare function create(config: Config): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function create(config) { return config; } +// @Filename: /home/src/workspaces/project/index.ts +import { /*importConfig*/Config, create } from "pkg"; +const c: Config = { name: "test", value: 1 }; +create(c);` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importConfig") +} + +func TestGoToSourceDefinitionTypeOnlyUsageFallsBackToDeclaration(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When source definition is invoked at a usage site of a type-only symbol, + // the checker path finds the .d.ts declarations but mapDeclarationToSource + // finds nothing in the .js file. The result should fall back to regular + // definition (the .d.ts declaration). + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export interface /*targetDecl*/Config { + name: string; +} +export declare function create(config: Config): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function create(config) { return config; } +// @Filename: /home/src/workspaces/project/index.ts +import { Config, create } from "pkg"; +const c: /*usageSite*/Config = { name: "test" }; +create(c);` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usageSite") +} + +func TestGoToSourceDefinitionValueImportStillWorks(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Value imports (functions, classes, variables) should still navigate + // to the .js implementation, not regress to .d.ts. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function /*dtsCreate*/create(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*targetCreate*/create() {} +// @Filename: /home/src/workspaces/project/index.ts +import { /*importCreate*/create } from "pkg"; +create();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importCreate") +} diff --git a/internal/fourslash/tests/goToSourceDefinitionTypes_test.go b/internal/fourslash/tests/goToSourceDefinitionTypes_test.go new file mode 100644 index 00000000000..4a43a4c5042 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinitionTypes_test.go @@ -0,0 +1,82 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceFallbacksToDefinitionForInterface(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export interface /*target*/Config { + enabled: boolean; +} +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +exports.makeConfig = () => ({ enabled: true }); +// @Filename: /home/src/workspaces/project/index.ts +import type { /*importName*/Config } from "pkg"; +let value: /*typeRef*/Config;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName", "typeRef") +} + +func TestGoToSourceTypeOnlySymbolFallback(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When a type-only symbol (type alias) is imported with a regular import and used + // in a value position, source definition should fall back to regular definition + // (the .d.ts declaration) since there's no concrete JS implementation. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/types.d.ts +export interface Config { enabled: boolean; } +// @Filename: /home/src/workspaces/project/node_modules/pkg/types.js +// no runtime content for Config interface +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export { Config } from "./types"; +export declare function makeConfig(): Config; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export { Config } from "./types.js"; +export function makeConfig() { return { enabled: true }; } +// @Filename: /home/src/workspaces/project/index.ts +import { Config, makeConfig } from "pkg"; +let c: /*typeRef*/Config; +makeConfig/*callRef*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "typeRef", "callRef") +} + +func TestGoToSourceForwardedNonConcreteMerge(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Forwarded declarations are non-concrete, so they merge with the initial + // non-concrete declarations. The barrel index.js re-exports from types.js + // which only has type re-exports. + const content = `// @moduleResolution: bundler +// @allowJs: true +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export { Config } from "./types"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/types.d.ts +export interface Config { enabled: boolean; } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export { Config } from "./types.js"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/types.js +// Config is a type, no runtime value +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/Config } from "pkg"; +let c: Config;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName") +} diff --git a/internal/fourslash/tests/goToSourceDefinition_test.go b/internal/fourslash/tests/goToSourceDefinition_test.go new file mode 100644 index 00000000000..e1fd38effc7 --- /dev/null +++ b/internal/fourslash/tests/goToSourceDefinition_test.go @@ -0,0 +1,213 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestGoToSourceNodeModulesWithTypes(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/foo/package.json +{ "name": "foo", "version": "1.0.0", "main": "./lib/main.js", "types": "./types/main.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/foo/lib/main.js +export const /*end*/a = "a"; +// @Filename: /home/src/workspaces/project/node_modules/foo/types/main.d.ts +export declare const a: string; +// @Filename: /home/src/workspaces/project/index.ts +import { a } from "foo"; +[|a/*start*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "start") +} + +func TestGoToSourceLocalJsBesideDts(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /home/src/workspaces/project/a.js +export const /*end*/a = "a"; +// @Filename: /home/src/workspaces/project/a.d.ts +export declare const a: string; +// @Filename: /home/src/workspaces/project/index.ts +import { a } from [|"./a"/*moduleSpecifier*/|]; +[|a/*identifier*/|]` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "identifier", "moduleSpecifier") +} + +func TestGoToSourceNonDeclarationFile(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Declaration is in a .ts file (not .d.ts), + // so mapDeclarationToSourceDefinitions returns it as-is. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/utils.ts +export function /*target*/helper() { return 1; } +// @Filename: /home/src/workspaces/project/index.ts +import { helper } from "./utils"; +helper/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourceNoImplementationFile(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // No implementation file can be resolved (types-only package with no .js). + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function typesOnly(): void; +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/typesOnly } from "pkg"; +typesOnly/*callSite*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName", "callSite") +} + +func TestGoToSourceDeclarationMapSourceMap(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // .d.ts has a sourcemap pointing back to the original .ts source. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./dist/index.js", "types": "./dist/index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/src/index.ts +export function /*target*/greet() { return "hi"; } +// @Filename: /home/src/workspaces/project/node_modules/pkg/dist/index.d.ts +export declare function greet(): string; +//# sourceMappingURL=index.d.ts.map +// @Filename: /home/src/workspaces/project/node_modules/pkg/dist/index.d.ts.map +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,WAAY"} +// @Filename: /home/src/workspaces/project/node_modules/pkg/dist/index.js +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.greet = greet; +function greet() { return "hi"; } +// @Filename: /home/src/workspaces/project/index.ts +import { greet } from "pkg"; +greet/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourceDeclarationMapFallback(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // findClosestDeclarationNode walks up parents and finds no declaration, + // returns entry node. This happens when source map points to a position + // that's not inside any declaration. + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./dist/index.js", "types": "./dist/index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/src/index.ts +/*target*/console.log("side effect"); +export function greet() { return "hi"; } +// @Filename: /home/src/workspaces/project/node_modules/pkg/dist/index.d.ts +export declare function greet(): string; +//# sourceMappingURL=index.d.ts.map +// @Filename: /home/src/workspaces/project/node_modules/pkg/dist/index.d.ts.map +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAC6B"} +// @Filename: /home/src/workspaces/project/node_modules/pkg/dist/index.js +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.greet = greet; +console.log("side effect"); +function greet() { return "hi"; } +// @Filename: /home/src/workspaces/project/index.ts +import { greet } from "pkg"; +greet/*usage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "usage") +} + +func TestGoToSourceNamedExportsSpecifier(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @moduleResolution: bundler +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function foo(): string; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +export function /*target*/foo() { return "ok"; } +// @Filename: /home/src/workspaces/project/index.ts +import { foo } from "pkg"; +const result = foo/*valueUsage*/();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "valueUsage") +} + +func TestGoToSourceTripleSlashReference(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // Cursor on a /// directive pointing to a .js file. + const content = `// @allowJs: true +// @Filename: /home/src/workspaces/project/helper.js +/*target*/function helper() { return 1; } +// @Filename: /home/src/workspaces/project/index.ts +/// +declare function helper(): number; +helper();` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "refPath") +} + +func TestGoToSourceFallbackToModuleSpecifier(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // When the specific name can't be found in the .js implementation file + // (because the JS uses a different export pattern), the fallback returns + // the entry declaration of the .js file. + const content = `// @moduleResolution: bundler +// @allowJs: true +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./index.js", "types": "./index.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.d.ts +export declare function internalHelper(): void; +// @Filename: /home/src/workspaces/project/node_modules/pkg/index.js +/*entryPoint*/Object.defineProperty(exports, "internalHelper", { value: function() {} }); +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/internalHelper } from "pkg";` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName") +} + +func TestGoToSourceFilterPreferredFallbackAll(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + // filterPreferredSourceDeclarations returns all declarations when none are + // property-like and none are concrete. This happens with re-export specifiers + // matching the name in the .js file. + const content = `// @moduleResolution: bundler +// @allowJs: true +// @Filename: /home/src/workspaces/project/node_modules/pkg/package.json +{ "name": "pkg", "main": "./barrel.js", "types": "./barrel.d.ts" } +// @Filename: /home/src/workspaces/project/node_modules/pkg/barrel.d.ts +export { value } from "./impl"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.d.ts +export declare const value: number; +// @Filename: /home/src/workspaces/project/node_modules/pkg/barrel.js +export { value } from "./impl.js"; +// @Filename: /home/src/workspaces/project/node_modules/pkg/impl.js +export const /*target*/value = 42; +// @Filename: /home/src/workspaces/project/index.ts +import { /*importName*/value } from "pkg"; +console.log(value);` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineGoToSourceDefinition(t, "importName") +} diff --git a/internal/ls/definition.go b/internal/ls/definition.go index ace5c5c5ca9..4820a411a3e 100644 --- a/internal/ls/definition.go +++ b/internal/ls/definition.go @@ -18,6 +18,17 @@ func (l *LanguageService) ProvideDefinition( ctx context.Context, documentURI lsproto.DocumentUri, position lsproto.Position, +) (lsproto.DefinitionResponse, error) { + if l.UserPreferences().PreferGoToSourceDefinition { + return l.ProvideSourceDefinition(ctx, documentURI, position) + } + return l.provideDefinitionWorker(ctx, documentURI, position) +} + +func (l *LanguageService) provideDefinitionWorker( + ctx context.Context, + documentURI lsproto.DocumentUri, + position lsproto.Position, ) (lsproto.DefinitionResponse, error) { caps := lsproto.GetClientCapabilities(ctx) clientSupportsLink := caps.TextDocument.Definition.LinkSupport @@ -161,7 +172,12 @@ func (l *LanguageService) createDefinitionLocations( file := ast.GetSourceFileOfNode(decl) fileName := file.FileName() name := core.OrElse(ast.GetNameOfDeclaration(decl), decl) - nameRange := createRangeFromNode(name, file) + var nameRange core.TextRange + if name.Kind == ast.KindEmptyStatement { + nameRange = core.NewTextRange(name.Pos(), name.Pos()) + } else { + nameRange = createRangeFromNode(name, file) + } if locationRanges.AddIfAbsent(fileRange{fileName, nameRange}) { contextNode := core.OrElse(getContextNode(decl), decl) contextRange := core.OrElse(toContextRange(&nameRange, file, contextNode), &nameRange) diff --git a/internal/ls/lsutil/userpreferences.go b/internal/ls/lsutil/userpreferences.go index fb0d5af28b3..6b00fefb60f 100644 --- a/internal/ls/lsutil/userpreferences.go +++ b/internal/ls/lsutil/userpreferences.go @@ -144,6 +144,10 @@ type UserPreferences struct { CodeLens CodeLensUserPreferences + // ------- Definition ------- + + PreferGoToSourceDefinition bool + // ------- Symbols ------- ExcludeLibrarySymbolsInNavTo bool @@ -713,6 +717,8 @@ func (p *UserPreferences) Set(name string, value any) bool { p.InlayHints.IncludeInlayFunctionLikeReturnTypeHints = parseBoolWithDefault(value, false) case "includeinlayenummembervaluehints": p.InlayHints.IncludeInlayEnumMemberValueHints = parseBoolWithDefault(value, false) + case "prefergotosourcedefinition": + p.PreferGoToSourceDefinition = parseBoolWithDefault(value, false) case "excludelibrarysymbolsinnavto": p.ExcludeLibrarySymbolsInNavTo = parseBoolWithDefault(value, false) case "disablesuggestions": diff --git a/internal/ls/sourcedefinition.go b/internal/ls/sourcedefinition.go new file mode 100644 index 00000000000..48503ebc276 --- /dev/null +++ b/internal/ls/sourcedefinition.go @@ -0,0 +1,708 @@ +package ls + +import ( + "context" + "math" + "slices" + "strings" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/astnav" + "github.com/microsoft/typescript-go/internal/binder" + "github.com/microsoft/typescript-go/internal/checker" + "github.com/microsoft/typescript-go/internal/collections" + "github.com/microsoft/typescript-go/internal/compiler" + "github.com/microsoft/typescript-go/internal/core" + "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/parser" + "github.com/microsoft/typescript-go/internal/tspath" + "github.com/microsoft/typescript-go/internal/vfs" +) + +func (l *LanguageService) ProvideSourceDefinition( + ctx context.Context, + documentURI lsproto.DocumentUri, + position lsproto.Position, +) (lsproto.DefinitionResponse, error) { + caps := lsproto.GetClientCapabilities(ctx) + clientSupportsLink := caps.TextDocument.Definition.LinkSupport + + program, file := l.getProgramAndFile(documentURI) + pos := int(l.converters.LineAndCharacterToPosition(file, position)) + resolver := l.newSourceDefResolver(program, file.FileName()) + node := astnav.GetTouchingPropertyName(file, pos) + + if node.Kind == ast.KindSourceFile { + // Triple-slash directives are comments, not AST nodes, so + // GetTouchingPropertyName returns the SourceFile node. + if declarations, ref := resolver.resolveTripleSlashReference(file, pos, program); len(declarations) != 0 { + originSelectionRange := l.createLspRangeFromBounds(ref.Pos(), ref.End(), file) + return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, declarations, nil /*reference*/), nil + } + return lsproto.LocationOrLocationsOrDefinitionLinksOrNull{}, nil + } + + originSelectionRange := l.createLspRangeFromNode(node, file) + + // If the cursor is directly on a module specifier string, resolve to the + // implementation file's entry point. + containingModuleSpecifier := findContainingModuleSpecifier(node) + if node == containingModuleSpecifier { + specifierMode := program.GetModeForUsageLocation(file, containingModuleSpecifier) + if implementationFile := resolver.resolveImplementation(containingModuleSpecifier.Text(), specifierMode); implementationFile != "" { + if sourceFile := resolver.getOrParseSourceFile(implementationFile); sourceFile != nil { + return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, getSourceDefinitionEntryDeclarations(sourceFile), nil), nil + } + } + return l.provideDefinitionWorker(ctx, documentURI, position) + } + + // Phase 1: Syntactic fast path — when the cursor is inside an + // import/require/export, forward-resolve the module specifier to an + // implementation file and search it directly. This avoids acquiring + // the type checker entirely when the fast path succeeds. + var resolvedImplFile string + if containingModuleSpecifier != nil { + specifierMode := program.GetModeForUsageLocation(file, containingModuleSpecifier) + resolvedImplFile = resolver.resolveImplementation(containingModuleSpecifier.Text(), specifierMode) + } + + if resolvedImplFile != "" { + names := getCandidateSourceDeclarationNames(node, nil) + moduleResults := resolver.searchImplementationFile(node, resolvedImplFile, names) + if len(moduleResults) != 0 { + if !ast.IsPartOfTypeNode(node) && !ast.IsPartOfTypeOnlyImportOrExportDeclaration(node) || hasConcreteSourceDeclarations(moduleResults) { + return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, uniqueDeclarationNodes(moduleResults), nil), nil + } + } + } + + // Phase 2: Type checker path — acquire the checker for the original file + // and use its declarations and module specifier to map to source + // implementations. This is the only point where the checker is used; + // after this, only the NoDts module resolver and file parsing are needed. + checkerDeclarations, moduleSpecifier := getSourceDefCheckerInfo(ctx, program, file, node) + + // Phase 3: Map checker results to source definitions. + declarations := resolver.resolveFromCheckerInfo(node, resolvedImplFile, checkerDeclarations, moduleSpecifier) + if len(declarations) == 0 { + // If we resolved an implementation file from an import/export but + // couldn't find specific declarations, fall back to the file entry + // point rather than the standard definition provider — unless the + // checker found declarations that are all type-only (e.g. interfaces), + // in which case the .d.ts definition is more appropriate. + if containingModuleSpecifier != nil && resolvedImplFile != "" && !hasConcreteSourceDeclarations(checkerDeclarations) { + if sourceFile := resolver.getOrParseSourceFile(resolvedImplFile); sourceFile != nil { + return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, getSourceDefinitionEntryDeclarations(sourceFile), nil), nil + } + } + return l.provideDefinitionWorker(ctx, documentURI, position) + } + return l.createDefinitionLocations(originSelectionRange, clientSupportsLink, declarations, nil /*reference*/), nil +} + +// sourceDefResolver resolves source definitions by mapping .d.ts declarations +// to their implementation files (.js/.ts). It uses the NoDts module resolver +// and file parsing for resolution, but never acquires the type checker or +// the original program; all checker-dependent work is done before results +// are passed in. +type sourceDefResolver struct { + ls *LanguageService + fs vfs.FS + options *core.CompilerOptions + getSourceFile func(string) *ast.SourceFile + resolveFrom string + resolver *module.Resolver + parsedFiles map[string]*ast.SourceFile +} + +func (l *LanguageService) newSourceDefResolver( + program *compiler.Program, + resolveFrom string, +) *sourceDefResolver { + options := program.Options() + noDtsOptions := options.Clone() + noDtsOptions.NoDtsResolution = core.TSTrue + return &sourceDefResolver{ + ls: l, + fs: program.Host().FS(), + options: options, + getSourceFile: program.GetSourceFile, + resolveFrom: resolveFrom, + resolver: module.NewResolver(program.Host(), noDtsOptions, program.GetGlobalTypingsCacheLocation(), ""), + } +} + +// resolveFromCheckerInfo maps type-checker declarations to source +// implementations. It uses only the NoDts module resolver and file parsing; +// the type checker and original request file are not needed. +func (r *sourceDefResolver) resolveFromCheckerInfo( + node *ast.Node, + resolvedImplFile string, + checkerDeclarations []*ast.Node, + moduleSpecifier string, +) []*ast.Node { + // If we don't yet have a forward-resolved implementation file, try to + // recover a module specifier from the checker (e.g. from the import that + // brought the symbol into scope, or from the root of an access expression). + if resolvedImplFile == "" && moduleSpecifier != "" { + resolvedImplFile = r.resolveImplementation(moduleSpecifier, r.inferImpliedNodeFormat(r.resolveFrom)) + } + + // For property access where the checker found no declarations (e.g. + // mapped types), search the implementation file for the property name. + if len(checkerDeclarations) == 0 && resolvedImplFile != "" { + names := getCandidateSourceDeclarationNames(node, nil) + if results := r.searchImplementationFile(node, resolvedImplFile, names); results != nil { + return uniqueDeclarationNodes(results) + } + } + + var declarations []*ast.Node + for _, declaration := range checkerDeclarations { + declarations = append(declarations, r.mapDeclarationToSource(node, declaration, resolvedImplFile)...) + } + declarations = uniqueDeclarationNodes(declarations) + if hasConcreteSourceDeclarations(declarations) { + return declarations + } + return nil +} + +// getSourceDefCheckerInfo acquires the type checker for the given file and +// returns the definition declarations for node along with the module specifier +// of the import that brought the symbol into scope (empty if not applicable). +func getSourceDefCheckerInfo( + ctx context.Context, + program *compiler.Program, + file *ast.SourceFile, + node *ast.Node, +) ([]*ast.Node, string) { + c, done := program.GetTypeCheckerForFile(ctx, file) + defer done() + + declarations := getDeclarationsFromLocation(c, node) + isPropertyName := node.Parent != nil && ast.IsAccessExpression(node.Parent) && node.Parent.Name() == node + if len(declarations) == 0 && isPropertyName { + if left := node.Parent.Expression(); left != nil { + if prop := c.GetPropertyOfType(c.GetTypeAtLocation(left), node.Text()); prop != nil { + declarations = prop.Declarations + } + } + } + if calledDeclaration := tryGetSignatureDeclaration(c, node); calledDeclaration != nil { + nonFunctionDeclarations := core.Filter(declarations, func(node *ast.Node) bool { return !ast.IsFunctionLike(node) }) + declarations = append(nonFunctionDeclarations, calledDeclaration) + } + + // Extract module specifier from the import that brought this symbol into + // scope. For property access (obj.prop), walk up the access chain to the + // root expression's symbol. + var moduleSpecifier string + resolveNode := node + if isPropertyName { + expr := node.Parent.Expression() + for expr != nil && ast.IsAccessExpression(expr) { + expr = expr.Expression() + } + if expr != nil { + resolveNode = expr + } + } + if sym := c.GetSymbolAtLocation(resolveNode); sym != nil { + for _, d := range sym.Declarations { + if !ast.IsImportSpecifier(d) && !ast.IsImportClause(d) && !ast.IsNamespaceImport(d) && !ast.IsImportEqualsDeclaration(d) { + continue + } + if spec := checker.TryGetModuleSpecifierFromDeclaration(d); spec != nil { + moduleSpecifier = spec.Text() + break + } + } + } + + return declarations, moduleSpecifier +} + +// resolveTripleSlashReference handles /// directives. +// For path references to .js files, it returns the entry declarations directly. +// For path references to .d.ts files or type references, it uses the NoDts +// resolver to find the corresponding implementation file. +func (r *sourceDefResolver) resolveTripleSlashReference(file *ast.SourceFile, pos int, program *compiler.Program) ([]*ast.Node, *ast.FileReference) { + ref := getReferenceAtPosition(file, pos, program) + if ref == nil || ref.file == nil { + return nil, nil + } + + // If the referenced file is already an implementation file, return it directly. + if !ref.file.IsDeclarationFile { + return getSourceDefinitionEntryDeclarations(ref.file), ref.reference + } + + // The referenced file is a .d.ts. Try to find the implementation file + // using the NoDts module resolver via findImplementationFileFromDtsFileName. + dtsFileName := ref.file.FileName() + preferredMode := r.inferImpliedNodeFormat(dtsFileName) + implementationFile := r.findImplementationFileFromDtsFileName(dtsFileName, preferredMode) + if implementationFile == "" { + return nil, nil + } + + sourceFile := r.getOrParseSourceFile(implementationFile) + if sourceFile == nil { + return nil, nil + } + return getSourceDefinitionEntryDeclarations(sourceFile), ref.reference +} + +// searchImplementationFile searches an implementation file for declarations +// matching the given names. Returns nil when no declarations matched; callers +// fall through to the checker path or to the standard definition provider. +func (r *sourceDefResolver) searchImplementationFile( + originalNode *ast.Node, + implementationFile string, + names []string, +) []*ast.Node { + if implementationFile == "" { + return nil + } + sourceFile := r.getOrParseSourceFile(implementationFile) + if sourceFile == nil { + return nil + } + if isDefaultImportName(originalNode) { + // For default imports, only search for "default" declarations to avoid + // matching unrelated declarations with the same identifier name. + defaultDeclarations := r.findDeclarationsInFile(implementationFile, []string{"default"}, &collections.Set[string]{}) + if len(defaultDeclarations) != 0 { + return filterPreferredSourceDeclarations(originalNode, defaultDeclarations) + } + return getSourceDefinitionEntryDeclarations(sourceFile) + } + declarations := r.findDeclarationsInFile(implementationFile, names, &collections.Set[string]{}) + if len(declarations) != 0 { + return filterPreferredSourceDeclarations(originalNode, declarations) + } + return nil +} + +func isDefaultImportName(node *ast.Node) bool { + if node == nil || node.Parent == nil || !ast.IsImportClause(node.Parent) || node.Parent.Name() != node || node.Parent.Parent == nil { + return false + } + return ast.IsDefaultImport(node.Parent.Parent) +} + +func getSourceDefinitionEntryNode(sourceFile *ast.SourceFile) *ast.Node { + if len(sourceFile.Statements.Nodes) != 0 { + return sourceFile.Statements.Nodes[0].AsNode() + } + return sourceFile.AsNode() +} + +func getSourceDefinitionEntryDeclarations(sourceFile *ast.SourceFile) []*ast.Node { + return []*ast.Node{getSourceDefinitionEntryNode(sourceFile)} +} + +func (r *sourceDefResolver) mapDeclarationToSource( + originalNode *ast.Node, + declaration *ast.Node, + resolvedImplFile string, +) []*ast.Node { + file, startPos := getFileAndStartPosFromDeclaration(declaration) + fileName := file.FileName() + + if mapped := r.ls.tryGetSourcePosition(fileName, startPos); mapped != nil { + if sourceFile := r.getOrParseSourceFile(mapped.FileName); sourceFile != nil { + return []*ast.Node{findClosestDeclarationNode(sourceFile, mapped.Pos)} + } + } + + if !tspath.IsDeclarationFileName(fileName) { + return []*ast.Node{declaration} + } + + implementationFile := resolvedImplFile + if implementationFile == "" { + // Reverse-resolve .d.ts path to implementation file. This path is only + // reached for declarations with no associated module specifier (e.g. + // globals, ambient declarations, or when forward resolution failed). + dtsFileName := ast.GetSourceFileOfNode(declaration).FileName() + preferredMode := r.inferImpliedNodeFormat(dtsFileName) + implementationFile = r.findImplementationFileFromDtsFileName(dtsFileName, preferredMode) + } + + return r.searchImplementationFile(originalNode, implementationFile, getCandidateSourceDeclarationNames(originalNode, declaration)) +} + +func (r *sourceDefResolver) findImplementationFileFromDtsFileName( + dtsFileName string, + preferredMode core.ResolutionMode, +) string { + if jsExt := module.TryGetJSExtensionForFile(dtsFileName, r.options); jsExt != "" { + candidate := tspath.ChangeExtension(dtsFileName, jsExt) + if r.fs.FileExists(candidate) { + return candidate + } + } + + parts := modulespecifiers.GetNodeModulePathParts(dtsFileName) + if parts == nil { + return "" + } + + // Ensure the file only contains one /node_modules/ segment. If there's more + // than one, the package name extraction may be incorrect, so bail out. + if strings.LastIndex(dtsFileName, "/node_modules/") != parts.TopLevelNodeModulesIndex { + return "" + } + + packageNamePathPart := dtsFileName[parts.TopLevelPackageNameIndex+1 : parts.PackageRootIndex] + packageName := module.GetPackageNameFromTypesPackageName(module.UnmangleScopedPackageName(packageNamePathPart)) + if packageName == "" { + return "" + } + + pathToFileInPackage := dtsFileName[parts.PackageRootIndex+1:] + + // Try resolving as a package subpath first (e.g. "pkg/dist/utils"), then + // fall back to the bare package name (e.g. "pkg"). This covers both main + // entrypoints and deep imports without needing to inspect package.json + // entrypoints. + if pathToFileInPackage != "" { + specifier := packageName + "/" + tspath.RemoveFileExtension(pathToFileInPackage) + if implementationFile := r.resolveImplementation(specifier, preferredMode); implementationFile != "" { + return implementationFile + } + } + return r.resolveImplementation(packageName, preferredMode) +} + +func (r *sourceDefResolver) resolveImplementation( + moduleName string, + preferredMode core.ResolutionMode, +) string { + return r.resolveImplementationFrom(moduleName, r.resolveFrom, preferredMode) +} + +func (r *sourceDefResolver) resolveImplementationFrom( + moduleName string, + resolveFromFile string, + preferredMode core.ResolutionMode, +) string { + modes := []core.ResolutionMode{preferredMode} + if preferredMode != core.ModuleKindESNext { + modes = append(modes, core.ModuleKindESNext) + } + if preferredMode != core.ModuleKindCommonJS { + modes = append(modes, core.ModuleKindCommonJS) + } + + for _, mode := range modes { + resolved, _ := r.resolver.ResolveModuleName(moduleName, resolveFromFile, mode, nil) + if resolved != nil && resolved.IsResolved() && !tspath.IsDeclarationFileName(resolved.ResolvedFileName) { + return resolved.ResolvedFileName + } + } + return "" +} + +func (r *sourceDefResolver) getOrParseSourceFile(fileName string) *ast.SourceFile { + if sourceFile := r.getSourceFile(fileName); sourceFile != nil { + return sourceFile + } + if sourceFile, ok := r.parsedFiles[fileName]; ok { + return sourceFile + } + var sourceFile *ast.SourceFile + if text, ok := r.ls.ReadFile(fileName); ok { + sourceFile = parser.ParseSourceFile( + ast.SourceFileParseOptions{FileName: fileName, Path: r.ls.toPath(fileName)}, + text, + core.GetScriptKindFromFileName(fileName), + ) + binder.BindSourceFile(sourceFile) + } + if r.parsedFiles == nil { + r.parsedFiles = map[string]*ast.SourceFile{} + } + r.parsedFiles[fileName] = sourceFile + return sourceFile +} + +// inferImpliedNodeFormat determines the module format for a source file that may not be +// in the program, using the file extension and nearest package.json "type" field. +func (r *sourceDefResolver) inferImpliedNodeFormat(fileName string) core.ResolutionMode { + var packageJsonType string + if scope := r.resolver.GetPackageScopeForPath(tspath.GetDirectoryPath(fileName)); scope.Exists() { + if value, ok := scope.Contents.Type.GetValue(); ok { + packageJsonType = value + } + } + return ast.GetImpliedNodeFormatForFile(fileName, packageJsonType) +} + +func findContainingModuleSpecifier(node *ast.Node) *ast.Node { + for current := node; current != nil; current = current.Parent { + if ast.IsAnyImportOrReExport(current) || ast.IsRequireCall(current, true /*requireStringLiteralLikeArgument*/) || ast.IsImportCall(current) { + if moduleSpecifier := ast.GetExternalModuleName(current); moduleSpecifier != nil && ast.IsStringLiteralLike(moduleSpecifier) { + return moduleSpecifier + } + } + } + return nil +} + +func (r *sourceDefResolver) findDeclarationsInFile( + fileName string, + names []string, + seen *collections.Set[string], +) []*ast.Node { + if fileName == "" || len(names) == 0 { + return nil + } + if !seen.AddIfAbsent(fileName) { + return nil + } + + sourceFile := r.getOrParseSourceFile(fileName) + if sourceFile == nil { + return nil + } + + declarations := findDeclarationNodesByName(sourceFile, names) + if len(declarations) != 0 && hasConcreteSourceDeclarations(declarations) { + return declarations + } + + var forwarded []*ast.Node + for _, forwardedFile := range r.getForwardedImplementationFiles(sourceFile) { + forwarded = append(forwarded, r.findDeclarationsInFile(forwardedFile, names, seen)...) + } + if len(forwarded) != 0 { + if hasConcreteSourceDeclarations(forwarded) { + return uniqueDeclarationNodes(forwarded) + } + return uniqueDeclarationNodes(append(slices.Clip(declarations), forwarded...)) + } + return declarations +} + +func (r *sourceDefResolver) getForwardedImplementationFiles(sourceFile *ast.SourceFile) []string { + preferredMode := r.inferImpliedNodeFormat(sourceFile.FileName()) + + var files []string + for _, imp := range sourceFile.Imports() { + moduleName := imp.Text() + if implementationFile := r.resolveImplementationFrom(moduleName, sourceFile.FileName(), preferredMode); implementationFile != "" { + files = append(files, implementationFile) + } + } + return core.Deduplicate(files) +} + +func getCandidateSourceDeclarationNames(originalNode *ast.Node, declaration *ast.Node) []string { + var names []string + if declaration != nil { + if name := ast.GetNameOfDeclaration(declaration); name != nil { + if text := ast.GetTextOfPropertyName(name); text != "" { + names = append(names, text) + } + } + if declaration.Kind == ast.KindExportAssignment { + names = append(names, "default") + } + if (ast.IsFunctionDeclaration(declaration) || ast.IsClassDeclaration(declaration)) && declaration.ModifierFlags()&ast.ModifierFlagsExportDefault == ast.ModifierFlagsExportDefault { + names = append(names, "default") + } + if ast.IsImportSpecifier(declaration) || ast.IsExportSpecifier(declaration) { + if propName := declaration.PropertyName(); propName != nil { + names = append(names, propName.Text()) + } + } + } + if originalNode != nil { + if ast.IsIdentifier(originalNode) || ast.IsPrivateIdentifier(originalNode) { + names = append(names, originalNode.Text()) + } + if isDefaultImportName(originalNode) { + names = append(names, "default") + } + if originalNode.Parent != nil { + if ast.IsImportSpecifier(originalNode.Parent) || ast.IsExportSpecifier(originalNode.Parent) { + if propName := originalNode.Parent.PropertyName(); propName != nil { + names = append(names, propName.Text()) + } + } + } + } + return names +} + +func findDeclarationNodesByName(sourceFile *ast.SourceFile, names []string) []*ast.Node { + names = core.Deduplicate(core.Filter(names, func(name string) bool { return name != "" })) + if len(names) == 0 { + return nil + } + + var wanted collections.Set[string] + wantDefault := false + for _, name := range names { + if name == "default" { + wantDefault = true + continue + } + wanted.Add(name) + } + + type candidate struct { + node *ast.Node + depth int + } + var candidates []candidate + minDepth := math.MaxInt + + var visit ast.Visitor + visit = func(node *ast.Node) bool { + matched := false + if name := ast.GetNameOfDeclaration(node); name != nil { + if text := ast.GetTextOfPropertyName(name); text != "" { + if wanted.Has(text) { + matched = true + } + } + } + if wantDefault && node.Kind == ast.KindExportAssignment { + matched = true + } + if wantDefault && (ast.IsFunctionDeclaration(node) || ast.IsClassDeclaration(node)) && node.ModifierFlags()&ast.ModifierFlagsExportDefault == ast.ModifierFlagsExportDefault { + matched = true + } + if matched { + depth := getContainerDepth(node) + candidates = append(candidates, candidate{node: node, depth: depth}) + if depth < minDepth { + minDepth = depth + } + } + return node.ForEachChild(visit) + } + sourceFile.AsNode().ForEachChild(visit) + + // Only keep declarations at the shallowest depth, like getTopMostDeclarationNamesInFile. + var declarations []*ast.Node + for _, c := range candidates { + if c.depth == minDepth { + declarations = append(declarations, c.node) + } + } + return uniqueDeclarationNodes(declarations) +} + +// getContainerDepth counts the number of container nodes above a declaration, +// matching the behavior of getDepth in getTopMostDeclarationNamesInFile. +func getContainerDepth(node *ast.Node) int { + depth := 0 + current := node + for current != nil { + current = getContainerNode(current) + depth++ + } + return depth +} + +func filterPreferredSourceDeclarations(originalNode *ast.Node, declarations []*ast.Node) []*ast.Node { + if len(declarations) <= 1 || originalNode == nil { + return declarations + } + if preferred := getPropertyLikeSourceDeclarations(originalNode, declarations); len(preferred) != 0 { + return preferred + } + if preferred := core.Filter(declarations, isConcreteSourceDeclaration); len(preferred) != 0 { + return preferred + } + return declarations +} + +func getPropertyLikeSourceDeclarations(originalNode *ast.Node, declarations []*ast.Node) []*ast.Node { + if originalNode.Parent == nil || !ast.IsAccessExpression(originalNode.Parent) || originalNode.Parent.Name() != originalNode { + return nil + } + return core.Filter(declarations, func(node *ast.Node) bool { + switch node.Kind { + case ast.KindPropertyAssignment, + ast.KindShorthandPropertyAssignment, + ast.KindPropertyDeclaration, + ast.KindPropertySignature, + ast.KindMethodDeclaration, + ast.KindMethodSignature, + ast.KindGetAccessor, + ast.KindSetAccessor, + ast.KindEnumMember: + return true + default: + return false + } + }) +} + +func hasConcreteSourceDeclarations(declarations []*ast.Node) bool { + return slices.ContainsFunc(declarations, isConcreteSourceDeclaration) +} + +func isConcreteSourceDeclaration(node *ast.Node) bool { + if !ast.IsDeclaration(node) || node.Kind == ast.KindExportAssignment || node.Kind == ast.KindJSExportAssignment { + return false + } + if (ast.IsBinaryExpression(node) || ast.IsCallExpression(node)) && ast.GetAssignmentDeclarationKind(node) != ast.JSDeclarationKindNone { + return false + } + switch node.Kind { + case ast.KindParameter, + ast.KindTypeParameter, + ast.KindBindingElement, + ast.KindImportClause, + ast.KindImportSpecifier, + ast.KindNamespaceImport, + ast.KindExportSpecifier, + ast.KindPropertyAccessExpression, + ast.KindElementAccessExpression, + ast.KindCommonJSExport: + return false + default: + return true + } +} + +func uniqueDeclarationNodes(nodes []*ast.Node) []*ast.Node { + type declarationKey struct { + fileName string + loc core.TextRange + } + var seen collections.Set[declarationKey] + result := make([]*ast.Node, 0, len(nodes)) + for _, node := range nodes { + if node == nil { + continue + } + fileName := ast.GetSourceFileOfNode(node).FileName() + key := declarationKey{fileName: fileName, loc: node.Loc} + if !seen.AddIfAbsent(key) { + continue + } + result = append(result, node) + } + return result +} + +func findClosestDeclarationNode(sourceFile *ast.SourceFile, pos int) *ast.Node { + node := astnav.GetTouchingPropertyName(sourceFile, pos) + for current := node; current != nil; current = current.Parent { + if ast.IsDeclaration(current) || current.Kind == ast.KindExportAssignment { + return current + } + } + return getSourceDefinitionEntryNode(sourceFile) +} diff --git a/internal/lsp/lsproto/_generate/generate.mts b/internal/lsp/lsproto/_generate/generate.mts index d6623fdb169..9a8733ac5b3 100755 --- a/internal/lsp/lsproto/_generate/generate.mts +++ b/internal/lsp/lsproto/_generate/generate.mts @@ -408,6 +408,14 @@ const customRequests: Request[] = [ messageDirection: "clientToServer", documentation: "Returns project information (e.g. the tsconfig.json path) for a given text document.", }, + { + method: "custom/textDocument/sourceDefinition", + typeName: "CustomTextDocumentSourceDefinitionRequest", + params: { kind: "reference", name: "TextDocumentPositionParams" }, + result: { kind: "reference", name: "LocationOrLocationsOrDefinitionLinksOrNull" }, + messageDirection: "clientToServer", + documentation: "Request to get source definitions for a position.", + }, ]; const customTypeAliases: TypeAlias[] = [ @@ -492,6 +500,16 @@ function patchAndPreprocessModel() { } for (const structure of model.structures) { + // Patch ServerCapabilities to add custom tsgo capability flags + if (structure.name === "ServerCapabilities") { + structure.properties.push({ + name: "customSourceDefinitionProvider", + type: { kind: "base", name: "boolean" }, + optional: true, + documentation: "The server provides source definition support via custom/textDocument/sourceDefinition.", + }); + } + for (const prop of structure.properties) { // Replace initializationOptions type with custom InitializationOptions if (prop.name === "initializationOptions" && prop.type.kind === "reference" && prop.type.name === "LSPAny") { diff --git a/internal/lsp/lsproto/lsp_generated.go b/internal/lsp/lsproto/lsp_generated.go index 176c8cf292d..9fe931f9ffb 100644 --- a/internal/lsp/lsproto/lsp_generated.go +++ b/internal/lsp/lsproto/lsp_generated.go @@ -17140,6 +17140,9 @@ type ServerCapabilities struct { // Workspace specific server capabilities. Workspace *WorkspaceOptions `json:"workspace,omitzero"` + + // The server provides source definition support via custom/textDocument/sourceDefinition. + CustomSourceDefinitionProvider *bool `json:"customSourceDefinitionProvider,omitzero"` } var _ json.UnmarshalerFrom = (*ServerCapabilities)(nil) @@ -17396,6 +17399,13 @@ func (s *ServerCapabilities) UnmarshalJSONFrom(dec *json.Decoder) error { if err := json.UnmarshalDecode(dec, &s.Workspace); err != nil { return err } + case `"customSourceDefinitionProvider"`: + if dec.PeekKind() == 'n' { + return errNull("customSourceDefinitionProvider") + } + if err := json.UnmarshalDecode(dec, &s.CustomSourceDefinitionProvider); err != nil { + return err + } default: if err := dec.SkipValue(); err != nil { return err @@ -30203,6 +30213,8 @@ func unmarshalParams(method Method, data []byte) (any, error) { return unmarshalPtrTo[InitializeAPISessionParams](data) case MethodCustomProjectInfo: return unmarshalPtrTo[ProjectInfoParams](data) + case MethodCustomTextDocumentSourceDefinition: + return unmarshalPtrTo[TextDocumentPositionParams](data) case MethodWorkspaceDidChangeWorkspaceFolders: return unmarshalPtrTo[DidChangeWorkspaceFoldersParams](data) case MethodWindowWorkDoneProgressCancel: @@ -30408,6 +30420,8 @@ func unmarshalResult(method Method, data []byte) (any, error) { return unmarshalValue[CustomInitializeAPISessionResponse](data) case MethodCustomProjectInfo: return unmarshalValue[CustomProjectInfoResponse](data) + case MethodCustomTextDocumentSourceDefinition: + return unmarshalValue[CustomTextDocumentSourceDefinitionResponse](data) default: return unmarshalAny(data) } @@ -30728,6 +30742,8 @@ const ( MethodCustomInitializeAPISession Method = "custom/initializeAPISession" // Returns project information (e.g. the tsconfig.json path) for a given text document. MethodCustomProjectInfo Method = "custom/projectInfo" + // Request to get source definitions for a position. + MethodCustomTextDocumentSourceDefinition Method = "custom/textDocument/sourceDefinition" // The `workspace/didChangeWorkspaceFolders` notification is sent from the client to the server when the workspace // folder configuration changes. MethodWorkspaceDidChangeWorkspaceFolders Method = "workspace/didChangeWorkspaceFolders" @@ -31273,6 +31289,12 @@ type CustomProjectInfoResponse = *ProjectInfoResult // Type mapping info for `custom/projectInfo` var CustomProjectInfoInfo = RequestInfo[*ProjectInfoParams, CustomProjectInfoResponse]{Method: MethodCustomProjectInfo} +// Response type for `custom/textDocument/sourceDefinition` +type CustomTextDocumentSourceDefinitionResponse = *LocationOrLocationsOrDefinitionLinksOrNull + +// Type mapping info for `custom/textDocument/sourceDefinition` +var CustomTextDocumentSourceDefinitionInfo = RequestInfo[*TextDocumentPositionParams, CustomTextDocumentSourceDefinitionResponse]{Method: MethodCustomTextDocumentSourceDefinition} + // Type mapping info for `workspace/didChangeWorkspaceFolders` var WorkspaceDidChangeWorkspaceFoldersInfo = NotificationInfo[*DidChangeWorkspaceFoldersParams]{Method: MethodWorkspaceDidChangeWorkspaceFolders} diff --git a/internal/lsp/server.go b/internal/lsp/server.go index c51b2ad6fa8..2afeb298be4 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -677,6 +677,7 @@ var handlers = sync.OnceValue(func() handlerMap { registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentDiagnosticInfo, (*Server).handleDocumentDiagnostic) registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentHoverInfo, (*Server).handleHover) registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentDefinitionInfo, (*Server).handleDefinition) + registerLanguageServiceDocumentRequestHandler(handlers, lsproto.CustomTextDocumentSourceDefinitionInfo, (*Server).handleSourceDefinition) registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentTypeDefinitionInfo, (*Server).handleTypeDefinition) registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentSignatureHelpInfo, (*Server).handleSignatureHelp) registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentFormattingInfo, (*Server).handleDocumentFormat) @@ -1059,6 +1060,7 @@ func (s *Server) handleInitialize(ctx context.Context, params *lsproto.Initializ CallHierarchyProvider: &lsproto.BooleanOrCallHierarchyOptionsOrCallHierarchyRegistrationOptions{ Boolean: new(true), }, + CustomSourceDefinitionProvider: new(true), }, } @@ -1251,6 +1253,14 @@ func (s *Server) handleDefinition(ctx context.Context, ls *ls.LanguageService, p return ls.ProvideDefinition(ctx, params.TextDocument.Uri, params.Position) } +func (s *Server) handleSourceDefinition(ctx context.Context, ls *ls.LanguageService, params *lsproto.TextDocumentPositionParams) (lsproto.CustomTextDocumentSourceDefinitionResponse, error) { + resp, err := ls.ProvideSourceDefinition(ctx, params.TextDocument.Uri, params.Position) + if err != nil { + return nil, err + } + return &resp, nil +} + func (s *Server) handleTypeDefinition(ctx context.Context, ls *ls.LanguageService, params *lsproto.TypeDefinitionParams) (lsproto.TypeDefinitionResponse, error) { return ls.ProvideTypeDefinition(ctx, params.TextDocument.Uri, params.Position) } diff --git a/testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionPreferSourceDefinition.baseline.jsonc b/testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionPreferSourceDefinition.baseline.jsonc new file mode 100644 index 00000000000..baef142cffb --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionPreferSourceDefinition.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToDefinition === +// === /home/src/workspaces/project/a.d.ts === +// <|export declare const [|a|]: string;|> + +// === /home/src/workspaces/project/index.ts === +// import { a } from "./a"; +// a/*GOTO DEF*/ + + + +// === goToDefinition === +// === /home/src/workspaces/project/a.js === +// <|export const [|a|] = "a";|> + +// === /home/src/workspaces/project/index.ts === +// import { a } from "./a"; +// a/*GOTO DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionPreferSourceDefinitionFallback.baseline.jsonc b/testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionPreferSourceDefinitionFallback.baseline.jsonc new file mode 100644 index 00000000000..396b5986c88 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionPreferSourceDefinitionFallback.baseline.jsonc @@ -0,0 +1,9 @@ +// === goToDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|export interface [|Config|] { +// enabled: boolean; +// }|> + +// === /home/src/workspaces/project/index.ts === +// import type { Config } from "pkg"; +// let value: /*GOTO DEF*/Config; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToDefinitionPreferSourceDefinition.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToDefinitionPreferSourceDefinition.baseline.jsonc new file mode 100644 index 00000000000..9b9c6cfdc7e --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToDefinitionPreferSourceDefinition.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.js === +// <|export const [|a|] = "a";|> + +// === /home/src/workspaces/project/index.ts === +// import { a } from "./a"; +// a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAccessExpressionProperty.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAccessExpressionProperty.baseline.jsonc new file mode 100644 index 00000000000..031a0cdc19b --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAccessExpressionProperty.baseline.jsonc @@ -0,0 +1,19 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const obj = { <|[|greet|](name) { return name; }|>, count: 42 }; + +// === /home/src/workspaces/project/index.ts === +// import { obj } from "pkg"; +// obj./*GOTO SOURCE DEF*/greet("world"); +// obj.count; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const obj = { greet(name) { return name; }, <|[|count|]: 42|> }; + +// === /home/src/workspaces/project/index.ts === +// import { obj } from "pkg"; +// obj.greet("world"); +// obj./*GOTO SOURCE DEF*/count; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportAtUsageSite.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportAtUsageSite.baseline.jsonc new file mode 100644 index 00000000000..bb0de46ae59 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportAtUsageSite.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export function unrelated() {} +// <|export function [|original|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { original as renamed } from "pkg"; +// renamed/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportAtUsageSiteNamespaceImport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportAtUsageSiteNamespaceImport.baseline.jsonc new file mode 100644 index 00000000000..18b03d11635 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportAtUsageSiteNamespaceImport.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|helper|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import * as ns from "pkg"; +// ns./*GOTO SOURCE DEF*/helper(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportExport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportExport.baseline.jsonc new file mode 100644 index 00000000000..2a795cd6b84 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportExport.baseline.jsonc @@ -0,0 +1,16 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|exports.[|foo|] = 1|>; + +// === /home/src/workspaces/project/index.ts === +// import { foo as /*GOTO SOURCE DEF*/bar } from "pkg"; +// bar; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|exports.[|foo|] = 1|>; + +// === /home/src/workspaces/project/reexport.ts === +// export { foo as /*GOTO SOURCE DEF*/bar } from "pkg"; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportSpecifier.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportSpecifier.baseline.jsonc new file mode 100644 index 00000000000..fbeff92532d --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportSpecifier.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|original|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { original as /*GOTO SOURCE DEF*/renamed } from "pkg"; +// renamed(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportWithPrecedingExports.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportWithPrecedingExports.baseline.jsonc new file mode 100644 index 00000000000..2c4d67b8036 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAliasedImportWithPrecedingExports.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export function unrelated() {} +// <|export function [|original|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { original as /*GOTO SOURCE DEF*/renamed } from "pkg"; +// renamed(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAtTypesPackage.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAtTypesPackage.baseline.jsonc new file mode 100644 index 00000000000..d6e1dff0f95 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceAtTypesPackage.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/foo/index.js === +// <|export function [|bar|]() { return "hello"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { bar } from "foo"; +// bar/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceBarrelReExportChain.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceBarrelReExportChain.baseline.jsonc new file mode 100644 index 00000000000..3219656334c --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceBarrelReExportChain.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/impl.js === +// <|export function [|doWork|]() { return 42; }|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/doWork } from "pkg"; +// doWork(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/impl.js === +// <|export function [|doWork|]() { return 42; }|> + +// === /home/src/workspaces/project/index.ts === +// import { doWork } from "pkg"; +// doWork/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCJSReExportViaDefineProperty.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCJSReExportViaDefineProperty.baseline.jsonc new file mode 100644 index 00000000000..a0a4aac831f --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCJSReExportViaDefineProperty.baseline.jsonc @@ -0,0 +1,63 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/impl.js === +// "use strict"; +// Object.defineProperty(exports, "__esModule", { value: true }); +// exports.greet = void 0; +// <|function [|greet|](name) { return "Hello, " + name; }|> +// exports.greet = greet; + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/greet, TargetPopulation } from "pkg"; +// greet("world"); +// TargetPopulation.Team; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/types.js === +// "use strict"; +// Object.defineProperty(exports, "__esModule", { value: true }); +// exports.TargetPopulation = void 0; +// <|var [|TargetPopulation|];|> +// (function (TargetPopulation) { +// TargetPopulation["Team"] = "team"; +// TargetPopulation["Public"] = "public"; +// })(TargetPopulation || (exports.TargetPopulation = TargetPopulation = {})); + +// === /home/src/workspaces/project/index.ts === +// import { greet, /*GOTO SOURCE DEF*/TargetPopulation } from "pkg"; +// greet("world"); +// TargetPopulation.Team; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/impl.js === +// "use strict"; +// Object.defineProperty(exports, "__esModule", { value: true }); +// exports.greet = void 0; +// <|function [|greet|](name) { return "Hello, " + name; }|> +// exports.greet = greet; + +// === /home/src/workspaces/project/index.ts === +// import { greet, TargetPopulation } from "pkg"; +// greet/*GOTO SOURCE DEF*/("world"); +// TargetPopulation.Team; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/types.js === +// "use strict"; +// Object.defineProperty(exports, "__esModule", { value: true }); +// exports.TargetPopulation = void 0; +// <|var [|TargetPopulation|];|> +// (function (TargetPopulation) { +// TargetPopulation["Team"] = "team"; +// TargetPopulation["Public"] = "public"; +// })(TargetPopulation || (exports.TargetPopulation = TargetPopulation = {})); + +// === /home/src/workspaces/project/index.ts === +// import { greet, TargetPopulation } from "pkg"; +// greet("world"); +// TargetPopulation/*GOTO SOURCE DEF*/.Team; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCallThroughImport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCallThroughImport.baseline.jsonc new file mode 100644 index 00000000000..59a38ee5359 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCallThroughImport.baseline.jsonc @@ -0,0 +1,25 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export class [|Widget|] { +// constructor(name) { this.name = name; } +// render() {} +// }|> + +// === /home/src/workspaces/project/index.ts === +// import { Widget } from "pkg"; +// const w = new /*GOTO SOURCE DEF*/Widget("test"); +// w.render(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export class Widget { +// constructor(name) { this.name = name; } +// <|[|render|]() {}|> +// } + +// === /home/src/workspaces/project/index.ts === +// import { Widget } from "pkg"; +// const w = new Widget("test"); +// w./*GOTO SOURCE DEF*/render(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCallbackParam.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCallbackParam.baseline.jsonc new file mode 100644 index 00000000000..825462ff139 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCallbackParam.baseline.jsonc @@ -0,0 +1,9 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/yargs/index.js === +// export function command(cmd, cb) { cb({ <|[|positional|]: "This is obviously not even close to realistic"|> }); } + +// === /home/src/workspaces/project/index.ts === +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCommonJSAliasPrefersDeclaration.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCommonJSAliasPrefersDeclaration.baseline.jsonc new file mode 100644 index 00000000000..af3f6fb1611 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceCommonJSAliasPrefersDeclaration.baseline.jsonc @@ -0,0 +1,14 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// "use strict"; +// Object.defineProperty(exports, "__esModule", { value: true }); +// exports.TargetPopulation = void 0; +// <|var [|TargetPopulation|];|> +// (function (TargetPopulation) { +// TargetPopulation["Team"] = "team"; +// TargetPopulation["Internal"] = "internal"; +// --- (line: 8) skipped --- + +// === /home/src/workspaces/project/index.ts === +// import * as tas from "pkg"; +// tas./*GOTO SOURCE DEF*/TargetPopulation.Public; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDeclarationMapFallback.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDeclarationMapFallback.baseline.jsonc new file mode 100644 index 00000000000..0ec90b27611 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDeclarationMapFallback.baseline.jsonc @@ -0,0 +1,11 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/dist/index.js === +// "use strict"; +// Object.defineProperty(exports, "__esModule", { value: true }); +// exports.greet = greet; +// console.log("side effect"); +// <|function [|greet|]() { return "hi"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { greet } from "pkg"; +// greet/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDeclarationMapSourceMap.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDeclarationMapSourceMap.baseline.jsonc new file mode 100644 index 00000000000..e074eb02bda --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDeclarationMapSourceMap.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/src/index.ts === +// <|export function [|greet|]() { return "hi"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { greet } from "pkg"; +// greet/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportNoDefaultInJs.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportNoDefaultInJs.baseline.jsonc new file mode 100644 index 00000000000..111f01a10ff --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportNoDefaultInJs.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|function [|internalCreate|]() { return {}; }|> +// module.exports = { create: internalCreate }; + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/create from "pkg"; +// create(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportNotFirstStatement.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportNotFirstStatement.baseline.jsonc new file mode 100644 index 00000000000..f4dbe16a0aa --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportNotFirstStatement.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const version = "1.0"; +// <|export default class [|Widget|] {}|> + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/Widget from "pkg"; +// Widget; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportReExportUsage.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportReExportUsage.baseline.jsonc new file mode 100644 index 00000000000..42ee20796ba --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportReExportUsage.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export default function [|greet|](name) { return "Hello, " + name; }|> + +// === /home/src/workspaces/project/index.ts === +// import greet from "pkg"; +// greet/*GOTO SOURCE DEF*/("world"); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportUsageSiteChecker.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportUsageSiteChecker.baseline.jsonc new file mode 100644 index 00000000000..5418695fdd4 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefaultImportUsageSiteChecker.baseline.jsonc @@ -0,0 +1,23 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export default class [|Widget|] { +// render() {} +// }|> + +// === /home/src/workspaces/project/index.ts === +// import Widget from "pkg"; +// const w = new Widget/*GOTO SOURCE DEF*/("test"); +// w.render(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export default class Widget { +// <|[|render|]() {}|> +// } + +// === /home/src/workspaces/project/index.ts === +// import Widget from "pkg"; +// const w = new Widget("test"); +// w./*GOTO SOURCE DEF*/render(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionEmptyJsFile.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionEmptyJsFile.baseline.jsonc new file mode 100644 index 00000000000..4bfe3b59aca --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionEmptyJsFile.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// [||] + +// === /home/src/workspaces/project/index.ts === +// import { foo } from /*GOTO SOURCE DEF*/"pkg"; +// foo(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionTypeOnlyImportFallsBackToDeclaration.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionTypeOnlyImportFallsBackToDeclaration.baseline.jsonc new file mode 100644 index 00000000000..59f0eeb1604 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionTypeOnlyImportFallsBackToDeclaration.baseline.jsonc @@ -0,0 +1,12 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|export interface [|Config|] { +// name: string; +// value: number; +// }|> +// export declare function create(config: Config): void; + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/Config, create } from "pkg"; +// const c: Config = { name: "test", value: 1 }; +// create(c); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionTypeOnlyUsageFallsBackToDeclaration.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionTypeOnlyUsageFallsBackToDeclaration.baseline.jsonc new file mode 100644 index 00000000000..ab5a0605032 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionTypeOnlyUsageFallsBackToDeclaration.baseline.jsonc @@ -0,0 +1,11 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|export interface [|Config|] { +// name: string; +// }|> +// export declare function create(config: Config): void; + +// === /home/src/workspaces/project/index.ts === +// import { Config, create } from "pkg"; +// const c: /*GOTO SOURCE DEF*/Config = { name: "test" }; +// create(c); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionUnresolvedTripleSlash.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionUnresolvedTripleSlash.baseline.jsonc new file mode 100644 index 00000000000..0d4e56f1c7a --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionUnresolvedTripleSlash.baseline.jsonc @@ -0,0 +1,4 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/index.ts === +// /// +// export {}; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionValueImportStillWorks.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionValueImportStillWorks.baseline.jsonc new file mode 100644 index 00000000000..6c713aa9c13 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDefinitionValueImportStillWorks.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|create|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/create } from "pkg"; +// create(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDtsReExport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDtsReExport.baseline.jsonc new file mode 100644 index 00000000000..855680a2758 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDtsReExport.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/impl.js === +// <|export function [|helper|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import { helper } from "pkg"; +// helper/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDynamicImport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDynamicImport.baseline.jsonc new file mode 100644 index 00000000000..8f8edfa7252 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceDynamicImport.baseline.jsonc @@ -0,0 +1,9 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|dynHelper|]() { return "dynamic"; }|> + +// === /home/src/workspaces/project/index.ts === +// async function main() { +// const mod = await import("pkg"); +// mod./*GOTO SOURCE DEF*/dynHelper(); +// } \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceEmptyNamesEntryFallback.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceEmptyNamesEntryFallback.baseline.jsonc new file mode 100644 index 00000000000..12c7e01f89d --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceEmptyNamesEntryFallback.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// [|export default { run() {} };|] + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/pkg from "pkg"; +// pkg.run(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignment.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignment.baseline.jsonc new file mode 100644 index 00000000000..fb4cfc43112 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignment.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/legacy/index.js === +// <|function [|legacyFn|]() { return "ok"; }|> +// module.exports = legacyFn; + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/legacyFn from "legacy"; +// legacyFn(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignmentDefault.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignmentDefault.baseline.jsonc new file mode 100644 index 00000000000..91e7c86ccc9 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignmentDefault.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|declare const [|_default|]: { run(): void };|> +// export default _default; + +// === /home/src/workspaces/project/index.ts === +// import pkg from "pkg"; +// pkg/*GOTO SOURCE DEF*/; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignmentExpression.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignmentExpression.baseline.jsonc new file mode 100644 index 00000000000..16e9f782d93 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceExportAssignmentExpression.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export default function [|createThing|]() { return { value: 42 }; }|> + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/createThing from "pkg"; +// createThing(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export default function [|createThing|]() { return { value: 42 }; }|> + +// === /home/src/workspaces/project/index.ts === +// import createThing from "pkg"; +// createThing/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFallbackToModuleSpecifier.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFallbackToModuleSpecifier.baseline.jsonc new file mode 100644 index 00000000000..1581dc498ff --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFallbackToModuleSpecifier.baseline.jsonc @@ -0,0 +1,6 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|Object.defineProperty(exports, [|"internalHelper"|], { value: function() {} })|>; + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/internalHelper } from "pkg"; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFallbacksToDefinitionForInterface.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFallbacksToDefinitionForInterface.baseline.jsonc new file mode 100644 index 00000000000..8e1fd8a2039 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFallbacksToDefinitionForInterface.baseline.jsonc @@ -0,0 +1,21 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|export interface [|Config|] { +// enabled: boolean; +// }|> + +// === /home/src/workspaces/project/index.ts === +// import type { /*GOTO SOURCE DEF*/Config } from "pkg"; +// let value: Config; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|export interface [|Config|] { +// enabled: boolean; +// }|> + +// === /home/src/workspaces/project/index.ts === +// import type { Config } from "pkg"; +// let value: /*GOTO SOURCE DEF*/Config; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFilterPreferredFallbackAll.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFilterPreferredFallbackAll.baseline.jsonc new file mode 100644 index 00000000000..8fb83035cc4 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFilterPreferredFallbackAll.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/impl.js === +// <|export const [|value|] = 42;|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/value } from "pkg"; +// console.log(value); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFindImplementationNonNodeModules.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFindImplementationNonNodeModules.baseline.jsonc new file mode 100644 index 00000000000..d334e25aedd --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceFindImplementationNonNodeModules.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/lib/helper.d.ts === +// <|export declare function [|helper|](): string;|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/helper } from "./lib/helper"; +// helper(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceForwardedNonConcreteMerge.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceForwardedNonConcreteMerge.baseline.jsonc new file mode 100644 index 00000000000..8a1d723b194 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceForwardedNonConcreteMerge.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export { [|Config|] } from "./types.js";|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/Config } from "pkg"; +// let c: Config; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceForwardedReExportChain.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceForwardedReExportChain.baseline.jsonc new file mode 100644 index 00000000000..d6062c67f1b --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceForwardedReExportChain.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/impl.js === +// <|export function [|helper|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/helper } from "pkg"; +// helper(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceImportFilteredByExternalDeclaration.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceImportFilteredByExternalDeclaration.baseline.jsonc new file mode 100644 index 00000000000..2fdfb4dd767 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceImportFilteredByExternalDeclaration.baseline.jsonc @@ -0,0 +1,19 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|helper|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import { helper } from "pkg"; +// helper/*GOTO SOURCE DEF*/(); +// export { helper as myHelper } from "pkg"; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|helper|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import { helper } from "pkg"; +// helper(); +// export { helper as /*GOTO SOURCE DEF*/myHelper } from "pkg"; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceIndexSignatureProperty.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceIndexSignatureProperty.baseline.jsonc new file mode 100644 index 00000000000..8e19b715054 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceIndexSignatureProperty.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const config = { <|[|name|]: "test"|> }; + +// === /home/src/workspaces/project/index.ts === +// import { config } from "pkg"; +// config./*GOTO SOURCE DEF*/name; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceLocalJsBesideDts.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceLocalJsBesideDts.baseline.jsonc new file mode 100644 index 00000000000..b6d79847503 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceLocalJsBesideDts.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.js === +// <|export const [|a|] = "a";|> + +// === /home/src/workspaces/project/index.ts === +// import { a } from "./a"; +// a/*GOTO SOURCE DEF*/ + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.js === +// [|export const a = "a";|] + +// === /home/src/workspaces/project/index.ts === +// import { a } from "./a"/*GOTO SOURCE DEF*/; +// a \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMappedTypeProperty.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMappedTypeProperty.baseline.jsonc new file mode 100644 index 00000000000..9e88be22596 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMappedTypeProperty.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const obj = { a: 1, <|[|b|]: 2|> }; + +// === /home/src/workspaces/project/index.ts === +// import { obj } from "pkg"; +// obj./*GOTO SOURCE DEF*/b; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMappedTypePropertyWithMatch.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMappedTypePropertyWithMatch.baseline.jsonc new file mode 100644 index 00000000000..5bdf280977a --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMappedTypePropertyWithMatch.baseline.jsonc @@ -0,0 +1,19 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const obj = { <|[|a|]: 1|>, b: 2 }; + +// === /home/src/workspaces/project/index.ts === +// import { obj } from "pkg"; +// obj./*GOTO SOURCE DEF*/a; +// obj.b; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const obj = { a: 1, <|[|b|]: 2|> }; + +// === /home/src/workspaces/project/index.ts === +// import { obj } from "pkg"; +// obj.a; +// obj./*GOTO SOURCE DEF*/b; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMergedDeclarationDedup.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMergedDeclarationDedup.baseline.jsonc new file mode 100644 index 00000000000..0166e9cbe83 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceMergedDeclarationDedup.baseline.jsonc @@ -0,0 +1,23 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export class [|Util|] { +// run() {} +// }|> +// Util.version = "1.0"; + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/Util } from "pkg"; +// const u: Util = new Util(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export class [|Util|] { +// run() {} +// }|> +// Util.version = "1.0"; + +// === /home/src/workspaces/project/index.ts === +// import { Util } from "pkg"; +// const u: /*GOTO SOURCE DEF*/Util = new Util(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamedAndDefaultExport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamedAndDefaultExport.baseline.jsonc new file mode 100644 index 00000000000..1eecd913571 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamedAndDefaultExport.baseline.jsonc @@ -0,0 +1,21 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export default class [|Widget|] {}|> +// export function helper() {} + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/Widget, { helper } from "pkg"; +// Widget; +// helper(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export default class Widget {} +// <|export function [|helper|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import Widget, { /*GOTO SOURCE DEF*/helper } from "pkg"; +// Widget; +// helper(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamedExportsSpecifier.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamedExportsSpecifier.baseline.jsonc new file mode 100644 index 00000000000..10f86cad152 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamedExportsSpecifier.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|foo|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { foo } from "pkg"; +// const result = foo/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamespaceImportProperty.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamespaceImportProperty.baseline.jsonc new file mode 100644 index 00000000000..2ffaab0299a --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNamespaceImportProperty.baseline.jsonc @@ -0,0 +1,21 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|helper|]() {}|> +// export const value = 42; + +// === /home/src/workspaces/project/index.ts === +// import * as pkg from "pkg"; +// pkg./*GOTO SOURCE DEF*/helper(); +// pkg.value; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export function helper() {} +// <|export const [|value|] = 42;|> + +// === /home/src/workspaces/project/index.ts === +// import * as pkg from "pkg"; +// pkg.helper(); +// pkg./*GOTO SOURCE DEF*/value; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedClassShadowing.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedClassShadowing.baseline.jsonc new file mode 100644 index 00000000000..af0e12965c9 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedClassShadowing.baseline.jsonc @@ -0,0 +1,11 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export class [|Widget|] {}|> +// function factory() { +// class Widget { constructor() { this.local = true; } } +// return new Widget(); +// } + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/Widget } from "pkg"; +// new Widget(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedNodeModules.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedNodeModules.baseline.jsonc new file mode 100644 index 00000000000..d94e6c31e3b --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedNodeModules.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/outer/node_modules/inner/index.js === +// <|export function [|inner|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/inner } from "outer"; +// inner(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/outer/node_modules/inner/index.js === +// <|export function [|inner|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { inner } from "outer"; +// inner/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedScopeShadowing.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedScopeShadowing.baseline.jsonc new file mode 100644 index 00000000000..2ab5deb1c0c --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNestedScopeShadowing.baseline.jsonc @@ -0,0 +1,25 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|helper|]() { return "ok"; }|> +// function unrelated() { +// const helper = "shadow"; +// return helper; +// } + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/helper } from "pkg"; +// helper(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|helper|]() { return "ok"; }|> +// function unrelated() { +// const helper = "shadow"; +// return helper; +// } + +// === /home/src/workspaces/project/index.ts === +// import { helper } from "pkg"; +// helper/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNoImplementationFile.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNoImplementationFile.baseline.jsonc new file mode 100644 index 00000000000..8907adf248d --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNoImplementationFile.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|export declare function [|typesOnly|](): void;|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/typesOnly } from "pkg"; +// typesOnly(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.d.ts === +// <|export declare function [|typesOnly|](): void;|> + +// === /home/src/workspaces/project/index.ts === +// import { typesOnly } from "pkg"; +// typesOnly/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNodeModulesWithTypes.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNodeModulesWithTypes.baseline.jsonc new file mode 100644 index 00000000000..13ccd51adb0 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNodeModulesWithTypes.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/foo/lib/main.js === +// <|export const [|a|] = "a";|> + +// === /home/src/workspaces/project/index.ts === +// import { a } from "foo"; +// a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNonDeclarationFile.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNonDeclarationFile.baseline.jsonc new file mode 100644 index 00000000000..f678745f0d5 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceNonDeclarationFile.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/utils.ts === +// <|export function [|helper|]() { return 1; }|> + +// === /home/src/workspaces/project/index.ts === +// import { helper } from "./utils"; +// helper/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageIndexDts.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageIndexDts.baseline.jsonc new file mode 100644 index 00000000000..cf8a70b3df6 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageIndexDts.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/lib/index.js === +// <|export function [|greet|]() { return "hi"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { greet } from "pkg"; +// greet/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageRootFallsBackToSubpath.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageRootFallsBackToSubpath.baseline.jsonc new file mode 100644 index 00000000000..cf54176e81c --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageRootFallsBackToSubpath.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|work|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import { work } from "pkg"; +// work/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageRootThenSubpath.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageRootThenSubpath.baseline.jsonc new file mode 100644 index 00000000000..cf54176e81c --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePackageRootThenSubpath.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|work|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import { work } from "pkg"; +// work/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessDeepChain.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessDeepChain.baseline.jsonc new file mode 100644 index 00000000000..850da1e3ae0 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessDeepChain.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const nested = { inner: { <|[|value|]: 42|> } }; + +// === /home/src/workspaces/project/index.ts === +// import { nested } from "pkg"; +// nested.inner./*GOTO SOURCE DEF*/value; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessNamespaceImport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessNamespaceImport.baseline.jsonc new file mode 100644 index 00000000000..1556700ee3a --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessNamespaceImport.baseline.jsonc @@ -0,0 +1,19 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const coords = { <|[|x|]: 10|>, y: 20 }; + +// === /home/src/workspaces/project/index.ts === +// import { coords } from "pkg"; +// coords./*GOTO SOURCE DEF*/x; +// coords.y; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const coords = { x: 10, <|[|y|]: 20|> }; + +// === /home/src/workspaces/project/index.ts === +// import { coords } from "pkg"; +// coords.x; +// coords./*GOTO SOURCE DEF*/y; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessNoDeclaration.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessNoDeclaration.baseline.jsonc new file mode 100644 index 00000000000..af9e7741e0b --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyAccessNoDeclaration.baseline.jsonc @@ -0,0 +1,19 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const config = { <|[|alpha|]: "a"|>, beta: "b" }; + +// === /home/src/workspaces/project/index.ts === +// import { config } from "pkg"; +// config./*GOTO SOURCE DEF*/alpha; +// config.beta; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export const config = { alpha: "a", <|[|beta|]: "b"|> }; + +// === /home/src/workspaces/project/index.ts === +// import { config } from "pkg"; +// config.alpha; +// config./*GOTO SOURCE DEF*/beta; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyOfAlias.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyOfAlias.baseline.jsonc new file mode 100644 index 00000000000..df677fa98d6 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourcePropertyOfAlias.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.js === +// export const a = { <|[|a|]: 'a'|> }; + +// === /home/src/workspaces/project/b.ts === +// import { a } from './a'; +// a.a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportAliasWithPrecedingExports.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportAliasWithPrecedingExports.baseline.jsonc new file mode 100644 index 00000000000..1b20f21d1a1 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportAliasWithPrecedingExports.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export function unrelated() {} +// <|export function [|original|]() { return "ok"; }|> + +// === /home/src/workspaces/project/reexport.ts === +// export { original as /*GOTO SOURCE DEF*/renamed } from "pkg"; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportModuleSpecifier.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportModuleSpecifier.baseline.jsonc new file mode 100644 index 00000000000..5d02592b135 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportModuleSpecifier.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|alpha|]() { return "a"; }|> +// export function beta() { return 2; } + +// === /home/src/workspaces/project/reexport.ts === +// export { alpha, beta } from "pkg"/*GOTO SOURCE DEF*/; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportNames.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportNames.baseline.jsonc new file mode 100644 index 00000000000..e0663cda3fd --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportNames.baseline.jsonc @@ -0,0 +1,27 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|foo|]() { return "ok"; }|> +// export function bar() { return 42; } + +// === /home/src/workspaces/project/reexport.ts === +// export { /*GOTO SOURCE DEF*/foo, bar } from "pkg"; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export function foo() { return "ok"; } +// <|export function [|bar|]() { return 42; }|> + +// === /home/src/workspaces/project/reexport.ts === +// export { foo, /*GOTO SOURCE DEF*/bar } from "pkg"; + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// <|export function [|foo|]() { return "ok"; }|> +// export function bar() { return 42; } + +// === /home/src/workspaces/project/index.ts === +// import { foo, bar } from "pkg"/*GOTO SOURCE DEF*/; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportedImplementation.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportedImplementation.baseline.jsonc new file mode 100644 index 00000000000..c3222089fb9 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReExportedImplementation.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/foo.js === +// <|export function [|foo|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/foo } from "pkg"; +// foo(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/foo.js === +// <|export function [|foo|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { foo } from "pkg"; +// foo/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReferencePathToDts.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReferencePathToDts.baseline.jsonc new file mode 100644 index 00000000000..6e736e51ada --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReferencePathToDts.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/lib.js === +// <|export function [|helper|]() { return "ok"; }|> + +// === /home/src/workspaces/project/index.ts === +// /// +// declare function helper(): string; \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReferenceTypesToJS.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReferenceTypesToJS.baseline.jsonc new file mode 100644 index 00000000000..a43173156a0 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceReferenceTypesToJS.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/foo/index.js === +// <|export function [|bar|]() { return "hello"; }|> + +// === /home/src/workspaces/project/index.ts === +// /// +// import { bar } from "foo"; +// bar(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceRequireCall.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceRequireCall.baseline.jsonc new file mode 100644 index 00000000000..8abd32bc132 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceRequireCall.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// exports.[|helper|] = <|function() { return "ok"; }|>; + +// === /home/src/workspaces/project/index.js === +// const { /*GOTO SOURCE DEF*/helper } = require("pkg"); +// helper(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// exports.[|helper|] = <|function() { return "ok"; }|>; + +// === /home/src/workspaces/project/index.js === +// const { helper } = require("pkg"); +// helper/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceScopedAtTypesPackage.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceScopedAtTypesPackage.baseline.jsonc new file mode 100644 index 00000000000..3ab55d01d23 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceScopedAtTypesPackage.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/@myns/mylib/index.js === +// <|export function [|nsHelper|]() { return 42; }|> + +// === /home/src/workspaces/project/index.ts === +// import { nsHelper } from "@myns/mylib"; +// nsHelper/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceScopedPackage.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceScopedPackage.baseline.jsonc new file mode 100644 index 00000000000..7655bbfa30a --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceScopedPackage.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/@myscope/mylib/index.js === +// <|export function [|scopedHelper|]() { return "scoped"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/scopedHelper } from "@myscope/mylib"; +// scopedHelper(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/@myscope/mylib/index.js === +// <|export function [|scopedHelper|]() { return "scoped"; }|> + +// === /home/src/workspaces/project/index.ts === +// import { scopedHelper } from "@myscope/mylib"; +// scopedHelper/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceSubpathNotIndex.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceSubpathNotIndex.baseline.jsonc new file mode 100644 index 00000000000..c6817131dc7 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceSubpathNotIndex.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/lib/utils.js === +// <|export function [|util|]() {}|> + +// === /home/src/workspaces/project/index.ts === +// import { util } from "pkg"; +// util/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceTripleSlashReference.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceTripleSlashReference.baseline.jsonc new file mode 100644 index 00000000000..bcce8931c03 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceTripleSlashReference.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/helper.js === +// <|function [|helper|]() { return 1; }|> + +// === /home/src/workspaces/project/index.ts === +// /// +// declare function helper(): number; +// helper(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceTypeOnlySymbolFallback.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceTypeOnlySymbolFallback.baseline.jsonc new file mode 100644 index 00000000000..cb25ae86207 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceTypeOnlySymbolFallback.baseline.jsonc @@ -0,0 +1,20 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/types.d.ts === +// <|export interface [|Config|] { enabled: boolean; }|> + +// === /home/src/workspaces/project/index.ts === +// import { Config, makeConfig } from "pkg"; +// let c: /*GOTO SOURCE DEF*/Config; +// makeConfig(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// export { Config } from "./types.js"; +// <|export function [|makeConfig|]() { return { enabled: true }; }|> + +// === /home/src/workspaces/project/index.ts === +// import { Config, makeConfig } from "pkg"; +// let c: Config; +// makeConfig/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceUnnamedDefaultExport.baseline.jsonc b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceUnnamedDefaultExport.baseline.jsonc new file mode 100644 index 00000000000..cd10ff82682 --- /dev/null +++ b/testdata/baselines/reference/fourslash/goToSourceDefinition/goToSourceUnnamedDefaultExport.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// [|export default function() { return "ok"; }|] + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/myFunc from "pkg"; +// myFunc(); + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/pkg/index.js === +// [|export default function() { return "ok"; }|] + +// === /home/src/workspaces/project/index.ts === +// import myFunc from "pkg"; +// myFunc/*GOTO SOURCE DEF*/(); \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/state/codeLensAcrossProjects.baseline b/testdata/baselines/reference/fourslash/state/codeLensAcrossProjects.baseline index e6b2b00583e..3ca982e9f95 100644 --- a/testdata/baselines/reference/fourslash/state/codeLensAcrossProjects.baseline +++ b/testdata/baselines/reference/fourslash/state/codeLensAcrossProjects.baseline @@ -206,6 +206,7 @@ Config File Names:: "ImplementationsCodeLensShowOnInterfaceMethods": true, "ImplementationsCodeLensShowOnAllClassMethods": true }, + "PreferGoToSourceDefinition": false, "ExcludeLibrarySymbolsInNavTo": false, "DisableSuggestions": false, "DisableLineTextInReferences": false, @@ -683,6 +684,7 @@ Config:: "ImplementationsCodeLensShowOnInterfaceMethods": false, "ImplementationsCodeLensShowOnAllClassMethods": false }, + "PreferGoToSourceDefinition": false, "ExcludeLibrarySymbolsInNavTo": true, "DisableSuggestions": false, "DisableLineTextInReferences": true, diff --git a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToSource5_sameAsGoToDef1.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToSource5_sameAsGoToDef1.baseline.jsonc new file mode 100644 index 00000000000..d1db116af47 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToSource5_sameAsGoToDef1.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToDefinition === +// === /home/src/workspaces/project/a.ts === +// export const [|a|] = 'a'; + +// === /home/src/workspaces/project/b.ts === +// import { a } from './a'; +// [|a|]/*GOTO DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc new file mode 100644 index 00000000000..7adeb02e00b --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToDefinition === +// === /home/src/workspaces/project/node_modules/foo/src/a.ts === +// export const [|a |]= 'a'; + +// === /home/src/workspaces/project/b.ts === +// import { a } from 'foo/a'; +// [|a|]/*GOTO DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource10_mapFromAtTypes3.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource10_mapFromAtTypes3.baseline.jsonc new file mode 100644 index 00000000000..7a7f69bd46c --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource10_mapFromAtTypes3.baseline.jsonc @@ -0,0 +1,14 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/lodash/lodash.js === +// --- (line: 13) skipped --- +// * _.add(6, 4); +// * // => 10 +// */ +// var [|add|] = createMathOperation(function(augend, addend) { +// return augend + addend; +// }, 0); +// +// --- (line: 21) skipped --- + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/add } from 'lodash'; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource10_mapFromAtTypes3.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource10_mapFromAtTypes3.baseline.jsonc.diff new file mode 100644 index 00000000000..77e4698668a --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource10_mapFromAtTypes3.baseline.jsonc.diff @@ -0,0 +1,16 @@ +--- old.goToSource10_mapFromAtTypes3.baseline.jsonc ++++ new.goToSource10_mapFromAtTypes3.baseline.jsonc +@@= skipped -7, +7 lines =@@ + // return augend + addend; + // }, 0); + // +-// function lodash(value) {} +-// lodash.[|add|] = add; +-// +-// /** Detect free variable `global` from Node.js. */ +-// var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; +-// --- (line: 26) skipped --- ++// --- (line: 21) skipped --- + + // === /home/src/workspaces/project/index.ts === + // import { /*GOTO SOURCE DEF*/add } from 'lodash'; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource11_propertyOfAlias.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource11_propertyOfAlias.baseline.jsonc new file mode 100644 index 00000000000..8e6fbdb2272 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource11_propertyOfAlias.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.js === +// export const a = { [|a|]: 'a' }; + +// === /home/src/workspaces/project/b.ts === +// import { a } from './a'; +// a.a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource12_callbackParam.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource12_callbackParam.baseline.jsonc new file mode 100644 index 00000000000..06ee0e0b4d2 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource12_callbackParam.baseline.jsonc @@ -0,0 +1,9 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/yargs/index.js === +// export function command(cmd, cb) { cb({ [|positional|]: "This is obviously not even close to realistic" }); } + +// === /home/src/workspaces/project/index.ts === +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource13_nodenext.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource13_nodenext.baseline.jsonc new file mode 100644 index 00000000000..de71cf21ac0 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource13_nodenext.baseline.jsonc @@ -0,0 +1,8 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/left-pad/index.js === +// module.exports = leftPad; +// function [|leftPad|](str, len, ch) {} + +// === /home/src/workspaces/project/index.mts === +// import leftPad = require("left-pad"); +// /*GOTO SOURCE DEF*/leftPad("", 4); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource14_unresolvedRequireDestructuring.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource14_unresolvedRequireDestructuring.baseline.jsonc new file mode 100644 index 00000000000..62dfdb48deb --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource14_unresolvedRequireDestructuring.baseline.jsonc @@ -0,0 +1,3 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/index.js === +// const { blah/*GOTO SOURCE DEF*/ } = require("unresolved"); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource15_bundler.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource15_bundler.baseline.jsonc new file mode 100644 index 00000000000..caa06831c71 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource15_bundler.baseline.jsonc @@ -0,0 +1,16 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/react/cjs/react.production.min.js === +// 'use strict';exports.[|useState|]=function(a){};exports.version='16.8.6'; + +// === /home/src/workspaces/project/node_modules/react/cjs/react.development.js === +// 'use strict'; +// if (process.env.NODE_ENV !== 'production') { +// (function() { +// function [|useState|](initialState) {} +// exports.useState = useState; +// exports.version = '16.8.6'; +// }()); +// } + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/useState } from 'react'; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource15_bundler.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource15_bundler.baseline.jsonc.diff new file mode 100644 index 00000000000..b046a2cbc59 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource15_bundler.baseline.jsonc.diff @@ -0,0 +1,13 @@ +--- old.goToSource15_bundler.baseline.jsonc ++++ new.goToSource15_bundler.baseline.jsonc +@@= skipped -5, +5 lines =@@ + // 'use strict'; + // if (process.env.NODE_ENV !== 'production') { + // (function() { +-// function useState(initialState) {} +-// exports.[|useState|] = useState; ++// function [|useState|](initialState) {} ++// exports.useState = useState; + // exports.version = '16.8.6'; + // }()); + // } \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource16_callbackParamDifferentFile.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource16_callbackParamDifferentFile.baseline.jsonc new file mode 100644 index 00000000000..9fa27de70d4 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource16_callbackParamDifferentFile.baseline.jsonc @@ -0,0 +1,9 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/yargs/callback.js === +// export class Yargs { [|positional|]() { } } + +// === /home/src/workspaces/project/index.ts === +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource17_AddsFileToProject.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource17_AddsFileToProject.baseline.jsonc new file mode 100644 index 00000000000..9fa27de70d4 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource17_AddsFileToProject.baseline.jsonc @@ -0,0 +1,9 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/yargs/callback.js === +// export class Yargs { [|positional|]() { } } + +// === /home/src/workspaces/project/index.ts === +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource18_reusedFromDifferentFolder.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource18_reusedFromDifferentFolder.baseline.jsonc new file mode 100644 index 00000000000..b1039210f9b --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource18_reusedFromDifferentFolder.baseline.jsonc @@ -0,0 +1,10 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/yargs/callback.js === +// export class Yargs { [|positional|]() { } } + +// === /home/src/workspaces/project/some/index.ts === +// import { random } from "../folder/random"; +// import { command } from "yargs"; +// command("foo", yargs => { +// yargs./*GOTO SOURCE DEF*/positional(); +// }); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource1_localJsBesideDts.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource1_localJsBesideDts.baseline.jsonc new file mode 100644 index 00000000000..f368222ffed --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource1_localJsBesideDts.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.js === +// export const [|a|] = "a"; + +// === /home/src/workspaces/project/index.ts === +// import { a } from "./a"; +// a/*GOTO SOURCE DEF*/ + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.js === +// [|export const a = "a";|] + +// === /home/src/workspaces/project/index.ts === +// import { a } from "./a"/*GOTO SOURCE DEF*/; +// a \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource2_nodeModulesWithTypes.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource2_nodeModulesWithTypes.baseline.jsonc new file mode 100644 index 00000000000..f3486d73d27 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource2_nodeModulesWithTypes.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/foo/lib/main.js === +// export const [|a|] = "a"; + +// === /home/src/workspaces/project/index.ts === +// import { a } from "foo"; +// a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource3_nodeModulesAtTypes.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource3_nodeModulesAtTypes.baseline.jsonc new file mode 100644 index 00000000000..f3486d73d27 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource3_nodeModulesAtTypes.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/foo/lib/main.js === +// export const [|a|] = "a"; + +// === /home/src/workspaces/project/index.ts === +// import { a } from "foo"; +// a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource5_sameAsGoToDef1.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource5_sameAsGoToDef1.baseline.jsonc new file mode 100644 index 00000000000..5f5f218e35d --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource5_sameAsGoToDef1.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/a.ts === +// export const [|a|] = 'a'; + +// === /home/src/workspaces/project/b.ts === +// import { a } from './a'; +// a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc new file mode 100644 index 00000000000..73a0704a04e --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc @@ -0,0 +1,7 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/foo/src/a.ts === +// export const [|a|] = 'a'; + +// === /home/src/workspaces/project/b.ts === +// import { a } from 'foo/a'; +// a/*GOTO SOURCE DEF*/ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc.diff new file mode 100644 index 00000000000..e49e2579793 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource6_sameAsGoToDef2.baseline.jsonc.diff @@ -0,0 +1,10 @@ +--- old.goToSource6_sameAsGoToDef2.baseline.jsonc ++++ new.goToSource6_sameAsGoToDef2.baseline.jsonc +@@= skipped -0, +0 lines =@@ + // === goToSourceDefinition === + // === /home/src/workspaces/project/node_modules/foo/src/a.ts === +-// export const [|a |]= 'a'; ++// export const [|a|] = 'a'; + + // === /home/src/workspaces/project/b.ts === + // import { a } from 'foo/a'; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource7_conditionallyMinified.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource7_conditionallyMinified.baseline.jsonc new file mode 100644 index 00000000000..caa06831c71 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource7_conditionallyMinified.baseline.jsonc @@ -0,0 +1,16 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/react/cjs/react.production.min.js === +// 'use strict';exports.[|useState|]=function(a){};exports.version='16.8.6'; + +// === /home/src/workspaces/project/node_modules/react/cjs/react.development.js === +// 'use strict'; +// if (process.env.NODE_ENV !== 'production') { +// (function() { +// function [|useState|](initialState) {} +// exports.useState = useState; +// exports.version = '16.8.6'; +// }()); +// } + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/useState } from 'react'; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource7_conditionallyMinified.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource7_conditionallyMinified.baseline.jsonc.diff new file mode 100644 index 00000000000..4a2d0e4811b --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource7_conditionallyMinified.baseline.jsonc.diff @@ -0,0 +1,13 @@ +--- old.goToSource7_conditionallyMinified.baseline.jsonc ++++ new.goToSource7_conditionallyMinified.baseline.jsonc +@@= skipped -5, +5 lines =@@ + // 'use strict'; + // if (process.env.NODE_ENV !== 'production') { + // (function() { +-// function useState(initialState) {} +-// exports.[|useState|] = useState; ++// function [|useState|](initialState) {} ++// exports.useState = useState; + // exports.version = '16.8.6'; + // }()); + // } \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource8_mapFromAtTypes.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource8_mapFromAtTypes.baseline.jsonc new file mode 100644 index 00000000000..7a7f69bd46c --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource8_mapFromAtTypes.baseline.jsonc @@ -0,0 +1,14 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/lodash/lodash.js === +// --- (line: 13) skipped --- +// * _.add(6, 4); +// * // => 10 +// */ +// var [|add|] = createMathOperation(function(augend, addend) { +// return augend + addend; +// }, 0); +// +// --- (line: 21) skipped --- + +// === /home/src/workspaces/project/index.ts === +// import { /*GOTO SOURCE DEF*/add } from 'lodash'; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource8_mapFromAtTypes.baseline.jsonc.diff b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource8_mapFromAtTypes.baseline.jsonc.diff new file mode 100644 index 00000000000..acf4d6ec92a --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource8_mapFromAtTypes.baseline.jsonc.diff @@ -0,0 +1,16 @@ +--- old.goToSource8_mapFromAtTypes.baseline.jsonc ++++ new.goToSource8_mapFromAtTypes.baseline.jsonc +@@= skipped -7, +7 lines =@@ + // return augend + addend; + // }, 0); + // +-// function lodash(value) {} +-// lodash.[|add|] = add; +-// +-// /** Detect free variable `global` from Node.js. */ +-// var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; +-// --- (line: 26) skipped --- ++// --- (line: 21) skipped --- + + // === /home/src/workspaces/project/index.ts === + // import { /*GOTO SOURCE DEF*/add } from 'lodash'; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource9_mapFromAtTypes2.baseline.jsonc b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource9_mapFromAtTypes2.baseline.jsonc new file mode 100644 index 00000000000..55182a137b5 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/goToSourceDefinition/goToSource9_mapFromAtTypes2.baseline.jsonc @@ -0,0 +1,39 @@ +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/lodash/lodash.js === +// [||];(function() { +// /** +// * Adds two numbers. +// * +// --- (line: 5) skipped --- + +// === /home/src/workspaces/project/index.ts === +// import /*GOTO SOURCE DEF*/_, { foo } from 'lodash'; +// _.add + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/lodash/lodash.js === +// [||];(function() { +// /** +// * Adds two numbers. +// * +// --- (line: 5) skipped --- + +// === /home/src/workspaces/project/index.ts === +// import _, { /*GOTO SOURCE DEF*/foo } from 'lodash'; +// _.add + + + +// === goToSourceDefinition === +// === /home/src/workspaces/project/node_modules/lodash/lodash.js === +// [||];(function() { +// /** +// * Adds two numbers. +// * +// --- (line: 5) skipped --- + +// === /home/src/workspaces/project/index.ts === +// import _, { foo } from /*GOTO SOURCE DEF*/'lodash'; +// _.add \ No newline at end of file