diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index d392785d4181f..9705a2c911b84 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -7054,7 +7054,7 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { } if ast.IsImportSpecifier(node) { targetSymbol := c.resolveAliasWithDeprecationCheck(symbol, node) - if c.isDeprecatedSymbol(targetSymbol) && targetSymbol.Declarations() != nil { + if targetSymbol != symbol && c.isDeprecatedSymbol(targetSymbol) && targetSymbol.Declarations() != nil { c.addDeprecatedSuggestion(node, targetSymbol.Declarations(), targetSymbol.Name()) } } diff --git a/tsc/internal/checker/services.go b/tsc/internal/checker/services.go index 90f3f2f901844..52376f4ae3da1 100644 --- a/tsc/internal/checker/services.go +++ b/tsc/internal/checker/services.go @@ -399,6 +399,10 @@ func (c *Checker) SkipAlias(symbol *ast.Symbol) *ast.Symbol { return symbol } +func (c *Checker) GetDeclarationOfAliasSymbol(symbol *ast.Symbol) *ast.Node { + return c.getDeclarationOfAliasSymbol(symbol) +} + func (c *Checker) GetRootSymbols(symbol *ast.Symbol) []*ast.Symbol { roots := c.getImmediateRootSymbols(symbol) if len(roots) == 0 { diff --git a/tsc/internal/fourslash/tests/hoverAliasChainJSDoc_test.go b/tsc/internal/fourslash/tests/hoverAliasChainJSDoc_test.go new file mode 100644 index 0000000000000..bea1275b35023 --- /dev/null +++ b/tsc/internal/fourslash/tests/hoverAliasChainJSDoc_test.go @@ -0,0 +1,156 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + . "github.com/microsoft/TypeScript/tsc/internal/fourslash/tests/util" + "github.com/microsoft/TypeScript/tsc/internal/lsp/lsproto" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestHoverAliasChainJSDoc(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /lib.ts +/** + * Doc on impl + */ +export function foo() {} +// @Filename: /main.ts +import * as lib from "./lib.js"; + +/** + * Doc on export import alias + */ +export import bar = lib.foo +// @Filename: /use.ts +import { + /** + * Doc on import alias + */ + /*specifier*/bar +} from "./main.js" + +/*call*/bar() +/*reference*/bar` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + const documentation = "Doc on import alias\nDoc on export import alias\nDoc on impl" + f.VerifyQuickInfoAt(t, "call", "(alias) function foo(): void", documentation) + f.VerifyQuickInfoAt(t, "reference", "(alias) function foo(): void", documentation) + f.VerifyQuickInfoAt(t, "specifier", "(alias) function foo(): void", documentation) +} + +func TestHoverAliasChainJSDocShapes(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @Filename: /lib.ts +/** + * Doc on impl + */ +export function foo() {} +// @Filename: /main.ts +import * as lib from "./lib.js"; + +/** + * Doc on export import alias + */ +export import bar = lib.foo +// @Filename: /namespaceImport.ts +import * as m from "./main.js"; +m./*namespaceImportCall*/bar(); +m./*namespaceImport*/bar; +// @Filename: /uncommentedReexport.ts +export { foo } from "./lib.js"; +// @Filename: /middleHop.ts +import { + /** Doc on import alias */ + foo +} from "./uncommentedReexport.js"; +/*middleHopCall*/foo(); +/*middleHop*/foo; +// @Filename: /impl.ts +/** on impl */ +export function f() {} +/** on impl */ +export default function d() {} +// @Filename: /reexport.ts +export { /** on re-export */ f as g } from "./impl.js"; +// @Filename: /useReexport.ts +import { g } from "./reexport.js"; +/*reexportCall*/g(); +/*reexport*/g; +// @Filename: /useDefault.ts +/** before import */ +import d from "./impl.js"; +/*defaultImportCall*/d(); +/*defaultImport*/d; +// @Filename: /namespaces.ts +declare namespace a { + /** on the declaration */ + export function fn(): void; + /** on the declaration */ + export interface S {} + /** Same */ + export function same(): void; + /** on the declaration */ + export function tagged(): void; +} +declare namespace b { + /** on the alias */ + export import fn = a.fn; + export namespace S {} + /** on the alias */ + export import S = a.S; + /** Same */ + export import same = a.same; + /** @deprecated on the alias */ + export import tagged = a.tagged; +} +b./*importEqualsCall*/fn(); +b./*importEquals*/fn; +let s: b./*merged*/S; +b./*sameTextCall*/same(); +b./*sameText*/same; +b./*tagOnlyCall*/tagged(); +b./*tagOnly*/tagged; +// @Filename: /useDeprecated.ts +import { /** @deprecated */ dep } from "./deprecated.js"; +[|dep|]; +// @Filename: /deprecated.ts +export function dep() {}` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineHover(t) + f.VerifyCompletions(t, "importEquals", &fourslash.CompletionsExpectedList{ + IsIncomplete: false, + ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{ + CommitCharacters: &DefaultCommitCharacters, + EditRange: Ignored, + }, + Items: &fourslash.CompletionsExpectedItems{ + Includes: []fourslash.CompletionsExpectedItem{ + &lsproto.CompletionItem{ + Label: "fn", + Detail: new("(alias) function a.fn(): void"), + Documentation: &lsproto.StringOrMarkupContent{ + MarkupContent: &lsproto.MarkupContent{ + Kind: lsproto.MarkupKindMarkdown, + Value: "on the alias\non the declaration", + }, + }, + }, + }, + }, + }) + f.GoToFile(t, "/useDeprecated.ts") + f.VerifySuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: new(int32(6385))}, + Message: lsproto.StringOrMarkupContent{String: new("'dep' is deprecated.")}, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, + Range: f.Ranges()[0].LSRange, + }, + }) +} diff --git a/tsc/internal/ls/hover.go b/tsc/internal/ls/hover.go index a6a326a003df4..ab0c5f47e5930 100644 --- a/tsc/internal/ls/hover.go +++ b/tsc/internal/ls/hover.go @@ -205,55 +205,102 @@ func (l *LanguageService) documentationLocationMapper(feature spanmap.Feature) d } } -// getDocumentationForSymbol tries each documentation source in turn (call-signature documentation, -// declaration JSDoc, root-symbol JSDoc, alias target JSDoc) and returns the first non-empty result, -// formatted for contentFormat. commentOnly restricts the result to the JSDoc summary, excluding the -// @tag section. +// getDocumentationForSymbol assembles the documentation shown for symbol at node. Every alias on +// the way from symbol to the implementation contributes the JSDoc written on its own declaration, +// outermost first, and the implementation contributes the first of: the resolved call or construct +// signature's declaration, the root symbols, declaration (the one quick info picked), the alias +// target's declaration. Descriptions are joined with a newline, then the tag sections follow in the +// same order, with exact duplicates dropped from both. node only decides which implementation +// declaration is picked, so a reference and a call to the same alias show the same lines. commentOnly +// leaves the tag sections out. func getDocumentationForSymbol(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, node *ast.Node, declaration *ast.Node, contentFormat lsproto.MarkupKind, commentOnly bool) string { - documentation := documentationFromSignature(getMappedLocation, c, symbol, getCallOrNewExpression(node), node, contentFormat, commentOnly) - if documentation != "" { - return documentation + var parts documentationParts + for _, aliasDeclaration := range aliasChainDeclarations(c, symbol) { + parts.add(getDocumentationPartsFromDeclaration(getMappedLocation, c, symbol, aliasDeclaration, node, contentFormat)) + } + description, tags := documentationFromSignature(getMappedLocation, c, symbol, getCallOrNewExpression(node), node, contentFormat) + if description == "" && tags == "" { + description, tags = documentationFromRootSymbols(getMappedLocation, c, symbol, node, contentFormat) + } + if description == "" && tags == "" { + description, tags = getDocumentationPartsFromDeclaration(getMappedLocation, c, symbol, declaration, node, contentFormat) } + if description == "" && tags == "" { + description, tags = documentationFromAlias(getMappedLocation, c, symbol, node, contentFormat) + } + parts.add(description, tags) + return parts.join(commentOnly) +} - documentation = documentationFromRootSymbols(getMappedLocation, c, symbol, node, contentFormat, commentOnly) - if documentation != "" { - return documentation +// documentationParts collects the descriptions and tag sections of several declarations, keeping +// each distinct one once in the order it was added. +type documentationParts struct { + descriptions []string + tags []string +} + +func (p *documentationParts) add(description string, tags string) { + if description != "" { + p.descriptions = core.AppendIfUnique(p.descriptions, description) + } + if tags != "" { + p.tags = core.AppendIfUnique(p.tags, tags) } +} - documentation = getDocumentationFromDeclaration(getMappedLocation, c, symbol, declaration, node, contentFormat, commentOnly) - if documentation != "" { +func (p *documentationParts) join(commentOnly bool) string { + documentation := strings.Join(p.descriptions, "\n") + if commentOnly { return documentation } + return documentation + strings.Join(p.tags, "") +} - return documentationFromAlias(getMappedLocation, c, symbol, node, contentFormat, commentOnly) +// aliasChainDeclarations returns the alias declaration of symbol and of each alias it resolves +// through, outermost first, up to the first symbol that is not an alias. +func aliasChainDeclarations(c *checker.Checker, symbol *ast.Symbol) []*ast.Node { + var declarations []*ast.Node + var visited collections.Set[*ast.Symbol] + for symbol != nil && symbol.Flags()&ast.SymbolFlagsAlias != 0 && visited.AddIfAbsent(symbol) { + declaration := c.GetDeclarationOfAliasSymbol(symbol) + if declaration == nil { + break + } + declarations = append(declarations, declaration) + symbol = c.GetImmediateAliasedSymbol(symbol) + if symbol == c.GetUnknownSymbol() { + break + } + } + return declarations } -func documentationFromSignature(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, node *ast.Node, location *ast.Node, contentFormat lsproto.MarkupKind, commentOnly bool) string { +func documentationFromSignature(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, node *ast.Node, location *ast.Node, contentFormat lsproto.MarkupKind) (string, string) { if node == nil { - return "" + return "", "" } signature := c.GetResolvedSignature(node) if signature == nil { - return "" + return "", "" } declaration := signature.Declaration() if declaration == nil { - return "" + return "", "" } if ast.IsCallSignatureDeclaration(declaration) || ast.IsConstructSignatureDeclaration(declaration) { - return getDocumentationFromDeclaration(getMappedLocation, c, symbol, declaration, location, contentFormat, commentOnly) + return getDocumentationPartsFromDeclaration(getMappedLocation, c, symbol, declaration, location, contentFormat) } - return "" + return "", "" } -func documentationFromAlias(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, node *ast.Node, contentFormat lsproto.MarkupKind, commentOnly bool) string { +func documentationFromAlias(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, node *ast.Node, contentFormat lsproto.MarkupKind) (string, string) { if symbol == nil || symbol.Flags()&ast.SymbolFlagsAlias == 0 { - return "" + return "", "" } aliasedSymbol := c.GetAliasedSymbol(symbol) if aliasedSymbol == nil || aliasedSymbol == c.GetUnknownSymbol() { - return "" + return "", "" } candidates := []*ast.Symbol{aliasedSymbol} @@ -267,25 +314,25 @@ func documentationFromAlias(getMappedLocation documentationLocationMapper, c *ch continue } - if documentation := getDocumentationFromDeclaration(getMappedLocation, c, candidate, aliasedDeclaration, node, contentFormat, commentOnly); documentation != "" { - return documentation + if description, tags := getDocumentationPartsFromDeclaration(getMappedLocation, c, candidate, aliasedDeclaration, node, contentFormat); description != "" || tags != "" { + return description, tags } } - return "" + return "", "" } -func documentationFromRootSymbols(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, node *ast.Node, contentFormat lsproto.MarkupKind, commentOnly bool) string { +func documentationFromRootSymbols(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, node *ast.Node, contentFormat lsproto.MarkupKind) (string, string) { if symbol == nil { - return "" + return "", "" } rootSymbols := c.GetRootSymbols(symbol) if len(rootSymbols) <= 1 { - return "" + return "", "" } - var docs []string + var parts documentationParts for _, rootSymbol := range rootSymbols { if rootSymbol == nil { continue @@ -295,23 +342,31 @@ func documentationFromRootSymbols(getMappedLocation documentationLocationMapper, declarations = []*ast.Node{rootSymbol.ValueDeclaration()} } for _, declaration := range declarations { - if documentation := getDocumentationFromDeclaration(getMappedLocation, c, rootSymbol, declaration, node, contentFormat, commentOnly); documentation != "" { - docs = core.AppendIfUnique(docs, documentation) - } + parts.add(getDocumentationPartsFromDeclaration(getMappedLocation, c, rootSymbol, declaration, node, contentFormat)) } } - return strings.Join(docs, "\n") + return strings.Join(parts.descriptions, "\n"), strings.Join(parts.tags, "") } func getDocumentationFromDeclaration(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, declaration *ast.Node, location *ast.Node, contentFormat lsproto.MarkupKind, commentOnly bool) string { + description, tags := getDocumentationPartsFromDeclaration(getMappedLocation, c, symbol, declaration, location, contentFormat) + if commentOnly { + return description + } + return description + tags +} + +// getDocumentationPartsFromDeclaration renders the JSDoc on declaration as its description and its +// tag section, each empty when there is none. +func getDocumentationPartsFromDeclaration(getMappedLocation documentationLocationMapper, c *checker.Checker, symbol *ast.Symbol, declaration *ast.Node, location *ast.Node, contentFormat lsproto.MarkupKind) (string, string) { if declaration == nil { - return "" + return "", "" } isMarkdown := contentFormat == lsproto.MarkupKindMarkdown - var b strings.Builder + var description, b strings.Builder if jsdoc := getJSDocOrTag(c, declaration, &collections.Set[*ast.Symbol]{}); jsdoc != nil && !(declaration.Flags&ast.NodeFlagsReparsed == 0 && containsTypedefTag(jsdoc)) { - writeComments(getMappedLocation, &b, c, jsdoc.Comments(), isMarkdown) - if jsdoc.Kind == ast.KindJSDoc && !commentOnly { + writeComments(getMappedLocation, &description, c, jsdoc.Comments(), isMarkdown) + if jsdoc.Kind == ast.KindJSDoc { if tags := jsdoc.AsJSDoc().Tags; tags != nil { for _, tag := range tags.Nodes { if tag.Kind == ast.KindJSDocTypeTag || tag.Kind == ast.KindJSDocTypedefTag || tag.Kind == ast.KindJSDocCallbackTag { @@ -390,7 +445,7 @@ func getDocumentationFromDeclaration(getMappedLocation documentationLocationMapp } } } - return b.String() + return description.String(), b.String() } func formatQuickInfo(quickInfo string) string { diff --git a/tsc/internal/parser/parser.go b/tsc/internal/parser/parser.go index c670d64ad21c2..5aa73c1e817a4 100644 --- a/tsc/internal/parser/parser.go +++ b/tsc/internal/parser/parser.go @@ -2466,6 +2466,7 @@ func (p *Parser) parseNamedImports() *ast.Node { func (p *Parser) parseImportSpecifier() *ast.Node { pos := p.nodePos() + jsdoc := p.jsdocScannerInfo() isTypeOnly, propertyName, name := p.parseImportOrExportSpecifier(ast.KindImportSpecifier) var identifierName *ast.Node if name.Kind == ast.KindIdentifier { @@ -2475,7 +2476,9 @@ func (p *Parser) parseImportSpecifier() *ast.Node { identifierName = p.newIdentifier("") p.finishNode(identifierName, name.Pos()) } - result := p.checkJSSyntax(p.finishNode(p.factory.NewImportSpecifier(isTypeOnly, propertyName, identifierName), pos)) + result := p.finishNode(p.factory.NewImportSpecifier(isTypeOnly, propertyName, identifierName), pos) + p.withJSDoc(result, jsdoc) + p.checkJSSyntax(result) return result } diff --git a/tsc/internal/parser/parser_test.go b/tsc/internal/parser/parser_test.go index ffa96713eb444..2d0201e7a0010 100644 --- a/tsc/internal/parser/parser_test.go +++ b/tsc/internal/parser/parser_test.go @@ -460,6 +460,41 @@ const value = 0;` } } +func TestImportSpecifierJSDoc(t *testing.T) { + t.Parallel() + sourceText := `import { /** a */ a, + /** b */ b } from "m"` + tests := []struct { + fileName tspath.RootedFilePath + pathKey tspath.PathKey + scriptKind core.ScriptKind + }{ + {fileName: "/index.ts", pathKey: "/index.ts", scriptKind: core.ScriptKindTS}, + {fileName: "/index.js", pathKey: "/index.js", scriptKind: core.ScriptKindJS}, + } + for _, test := range tests { + t.Run(string(test.fileName), func(t *testing.T) { + t.Parallel() + opts := ast.SourceFileParseOptions{ + FileName: test.fileName, + PathKey: test.pathKey, + } + file := parser.ParseSourceFile(opts, sourceText, test.scriptKind) + importDeclaration := file.Statements.Nodes[0] + assert.Assert(t, ast.IsImportDeclaration(importDeclaration)) + assert.Equal(t, len(importDeclaration.JSDoc(file)), 0) + + specifiers := importDeclaration.AsImportDeclaration().ImportClause.AsImportClause().NamedBindings.AsNamedImports().Elements.Nodes + assert.Equal(t, len(specifiers), 2) + for i, expected := range []string{"a", "b"} { + jsDocs := specifiers[i].JSDoc(file) + assert.Equal(t, len(jsDocs), 1) + assert.Equal(t, scanner.GetTextOfJSDocComment(jsDocs[0].AsJSDoc().Comment), expected) + } + }) + } +} + func TestJSDocTypeSourcePropagatesToConstructedReparse(t *testing.T) { t.Parallel() sourceText := `/** diff --git a/tsc/internal/parser/utilities.go b/tsc/internal/parser/utilities.go index 48a4ecf7ed3cb..87aba361f7c7d 100644 --- a/tsc/internal/parser/utilities.go +++ b/tsc/internal/parser/utilities.go @@ -27,7 +27,7 @@ func tokenIsIdentifierOrKeywordOrGreaterThan(token ast.Kind) bool { func GetJSDocCommentRanges(f *ast.NodeFactory, commentRanges []ast.CommentRange, node *ast.Node, text string) []ast.CommentRange { switch node.Kind { - case ast.KindParameter, ast.KindTypeParameter, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindParenthesizedExpression, ast.KindVariableDeclaration, ast.KindExportSpecifier: + case ast.KindParameter, ast.KindTypeParameter, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindParenthesizedExpression, ast.KindVariableDeclaration, ast.KindImportSpecifier, ast.KindExportSpecifier: for commentRange := range scanner.GetTrailingCommentRanges(f, text, node.Pos()) { commentRanges = append(commentRanges, commentRange) } diff --git a/tsc/testdata/baselines/reference/fourslash/quickInfo/hoverAliasChainJSDocShapes.baseline b/tsc/testdata/baselines/reference/fourslash/quickInfo/hoverAliasChainJSDocShapes.baseline new file mode 100644 index 0000000000000..aab779921497d --- /dev/null +++ b/tsc/testdata/baselines/reference/fourslash/quickInfo/hoverAliasChainJSDocShapes.baseline @@ -0,0 +1,584 @@ +// === QuickInfo === +=== /middleHop.ts === +// import { +// /** Doc on import alias */ +// foo +// } from "./uncommentedReexport.js"; +// foo(); +// ^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function foo(): void +// | ``` +// | Doc on import alias +// | Doc on impl +// | ---------------------------------------------------------------------- +// foo; +// ^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function foo(): void +// | ``` +// | Doc on import alias +// | Doc on impl +// | ---------------------------------------------------------------------- +=== /namespaceImport.ts === +// import * as m from "./main.js"; +// m.bar(); +// ^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function foo(): void +// | ``` +// | Doc on export import alias +// | Doc on impl +// | ---------------------------------------------------------------------- +// m.bar; +// ^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function foo(): void +// | ``` +// | Doc on export import alias +// | Doc on impl +// | ---------------------------------------------------------------------- + + +=== /namespaces.ts === +// declare namespace a { +// /** on the declaration */ +// export function fn(): void; +// /** on the declaration */ +// export interface S {} +// /** Same */ +// export function same(): void; +// /** on the declaration */ +// export function tagged(): void; +// } +// declare namespace b { +// /** on the alias */ +// export import fn = a.fn; +// export namespace S {} +// /** on the alias */ +// export import S = a.S; +// /** Same */ +// export import same = a.same; +// /** @deprecated on the alias */ +// export import tagged = a.tagged; +// } +// b.fn(); +// ^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function a.fn(): void +// | ``` +// | on the alias +// | on the declaration +// | ---------------------------------------------------------------------- +// b.fn; +// ^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function a.fn(): void +// | ``` +// | on the alias +// | on the declaration +// | ---------------------------------------------------------------------- +// let s: b.S; +// ^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) interface a.S +// | ``` +// | on the alias +// | on the declaration +// | ---------------------------------------------------------------------- +// b.same(); +// ^^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function a.same(): void +// | ``` +// | Same +// | ---------------------------------------------------------------------- +// b.same; +// ^^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function a.same(): void +// | ``` +// | Same +// | ---------------------------------------------------------------------- +// b.tagged(); +// ^^^^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function a.tagged(): void +// | ``` +// | on the declaration +// | +// | *@deprecated* — on the alias +// | ---------------------------------------------------------------------- +// b.tagged; +// ^^^^^^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function a.tagged(): void +// | ``` +// | on the declaration +// | +// | *@deprecated* — on the alias +// | ---------------------------------------------------------------------- + + +=== /useDefault.ts === +// /** before import */ +// import d from "./impl.js"; +// d(); +// ^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function d(): void +// | ``` +// | on impl +// | ---------------------------------------------------------------------- +// d; +// ^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function d(): void +// | ``` +// | on impl +// | ---------------------------------------------------------------------- + + +=== /useReexport.ts === +// import { g } from "./reexport.js"; +// g(); +// ^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function f(): void +// | ``` +// | on re-export +// | on impl +// | ---------------------------------------------------------------------- +// g; +// ^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (alias) function f(): void +// | ``` +// | on re-export +// | on impl +// | ---------------------------------------------------------------------- + + +[ + { + "marker": { + "Position": 34, + "LSPosition": { + "line": 1, + "character": 2 + }, + "Name": "namespaceImportCall", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function foo(): void\n```\nDoc on export import alias\nDoc on impl" + }, + "range": { + "start": { + "line": 1, + "character": 2 + }, + "end": { + "line": 1, + "character": 5 + } + } + } + }, + { + "marker": { + "Position": 43, + "LSPosition": { + "line": 2, + "character": 2 + }, + "Name": "namespaceImport", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function foo(): void\n```\nDoc on export import alias\nDoc on impl" + }, + "range": { + "start": { + "line": 2, + "character": 2 + }, + "end": { + "line": 2, + "character": 5 + } + } + } + }, + { + "marker": { + "Position": 83, + "LSPosition": { + "line": 4, + "character": 0 + }, + "Name": "middleHopCall", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function foo(): void\n```\nDoc on import alias\nDoc on impl" + }, + "range": { + "start": { + "line": 4, + "character": 0 + }, + "end": { + "line": 4, + "character": 3 + } + } + } + }, + { + "marker": { + "Position": 90, + "LSPosition": { + "line": 5, + "character": 0 + }, + "Name": "middleHop", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function foo(): void\n```\nDoc on import alias\nDoc on impl" + }, + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 3 + } + } + } + }, + { + "marker": { + "Position": 35, + "LSPosition": { + "line": 1, + "character": 0 + }, + "Name": "reexportCall", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function f(): void\n```\non re-export\non impl" + }, + "range": { + "start": { + "line": 1, + "character": 0 + }, + "end": { + "line": 1, + "character": 1 + } + } + } + }, + { + "marker": { + "Position": 40, + "LSPosition": { + "line": 2, + "character": 0 + }, + "Name": "reexport", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function f(): void\n```\non re-export\non impl" + }, + "range": { + "start": { + "line": 2, + "character": 0 + }, + "end": { + "line": 2, + "character": 1 + } + } + } + }, + { + "marker": { + "Position": 48, + "LSPosition": { + "line": 2, + "character": 0 + }, + "Name": "defaultImportCall", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function d(): void\n```\non impl" + }, + "range": { + "start": { + "line": 2, + "character": 0 + }, + "end": { + "line": 2, + "character": 1 + } + } + } + }, + { + "marker": { + "Position": 53, + "LSPosition": { + "line": 3, + "character": 0 + }, + "Name": "defaultImport", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function d(): void\n```\non impl" + }, + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 3, + "character": 1 + } + } + } + }, + { + "marker": { + "Position": 536, + "LSPosition": { + "line": 21, + "character": 2 + }, + "Name": "importEqualsCall", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function a.fn(): void\n```\non the alias\non the declaration" + }, + "range": { + "start": { + "line": 21, + "character": 2 + }, + "end": { + "line": 21, + "character": 4 + } + } + } + }, + { + "marker": { + "Position": 544, + "LSPosition": { + "line": 22, + "character": 2 + }, + "Name": "importEquals", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function a.fn(): void\n```\non the alias\non the declaration" + }, + "range": { + "start": { + "line": 22, + "character": 2 + }, + "end": { + "line": 22, + "character": 4 + } + } + } + }, + { + "marker": { + "Position": 557, + "LSPosition": { + "line": 23, + "character": 9 + }, + "Name": "merged", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) interface a.S\n```\non the alias\non the declaration" + }, + "range": { + "start": { + "line": 23, + "character": 9 + }, + "end": { + "line": 23, + "character": 10 + } + }, + "canIncreaseVerbosity": true + } + }, + { + "marker": { + "Position": 562, + "LSPosition": { + "line": 24, + "character": 2 + }, + "Name": "sameTextCall", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function a.same(): void\n```\nSame" + }, + "range": { + "start": { + "line": 24, + "character": 2 + }, + "end": { + "line": 24, + "character": 6 + } + } + } + }, + { + "marker": { + "Position": 572, + "LSPosition": { + "line": 25, + "character": 2 + }, + "Name": "sameText", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function a.same(): void\n```\nSame" + }, + "range": { + "start": { + "line": 25, + "character": 2 + }, + "end": { + "line": 25, + "character": 6 + } + } + } + }, + { + "marker": { + "Position": 580, + "LSPosition": { + "line": 26, + "character": 2 + }, + "Name": "tagOnlyCall", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function a.tagged(): void\n```\non the declaration\n\n*@deprecated* — on the alias" + }, + "range": { + "start": { + "line": 26, + "character": 2 + }, + "end": { + "line": 26, + "character": 8 + } + } + } + }, + { + "marker": { + "Position": 592, + "LSPosition": { + "line": 27, + "character": 2 + }, + "Name": "tagOnly", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(alias) function a.tagged(): void\n```\non the declaration\n\n*@deprecated* — on the alias" + }, + "range": { + "start": { + "line": 27, + "character": 2 + }, + "end": { + "line": 27, + "character": 8 + } + } + } + } +] \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/fourslash/quickInfo/quickInfoAlias.baseline b/tsc/testdata/baselines/reference/fourslash/quickInfo/quickInfoAlias.baseline index d7147de14dac8..2d5c9a4a20fe2 100644 --- a/tsc/testdata/baselines/reference/fourslash/quickInfo/quickInfoAlias.baseline +++ b/tsc/testdata/baselines/reference/fourslash/quickInfo/quickInfoAlias.baseline @@ -29,8 +29,11 @@ // | ```typescript // | (alias) const x: 0 // | ``` +// | Doc 3 // | Doc // | +// | *@tag* — Tag text 3 +// | // | *@tag* — Tag text // | ---------------------------------------------------------------------- @@ -76,7 +79,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```typescript\n(alias) const x: 0\n```\nDoc\n\n*@tag* — Tag text" + "value": "```typescript\n(alias) const x: 0\n```\nDoc 3\nDoc\n\n*@tag* — Tag text 3\n\n*@tag* — Tag text" }, "range": { "start": { diff --git a/tsc/testdata/baselines/reference/fourslash/vSQuickInfo/quickInfoAliasVS.baseline b/tsc/testdata/baselines/reference/fourslash/vSQuickInfo/quickInfoAliasVS.baseline index 656d7e854cb99..9fba95bdc0eed 100644 --- a/tsc/testdata/baselines/reference/fourslash/vSQuickInfo/quickInfoAliasVS.baseline +++ b/tsc/testdata/baselines/reference/fourslash/vSQuickInfo/quickInfoAliasVS.baseline @@ -45,7 +45,7 @@ // | [punctuation] ": " // | [string] "0" // | ClassifiedTextElement -// | [text] "Doc" +// | [text] "Doc 3\nDoc" // | ---------------------------------------------------------------------- @@ -160,7 +160,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```typescript\n(alias) const x: 0\n```\nDoc\n\n*@tag* — Tag text" + "value": "```typescript\n(alias) const x: 0\n```\nDoc 3\nDoc\n\n*@tag* — Tag text 3\n\n*@tag* — Tag text" }, "range": { "start": { @@ -233,7 +233,7 @@ "Runs": [ { "ClassificationTypeName": "text", - "Text": "Doc", + "Text": "Doc 3\nDoc", "_vs_type": "ClassifiedTextRun" } ],