diff --git a/tsc/internal/parser/reparser.go b/tsc/internal/parser/reparser.go index bdebd40ade98d..7e548a1a068f2 100644 --- a/tsc/internal/parser/reparser.go +++ b/tsc/internal/parser/reparser.go @@ -134,6 +134,8 @@ func (p *Parser) reparseUnhosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Nod p.addDeepCloneReparse(importTag.Attributes), ) p.finishReparsedNode(importDeclaration, tag) + p.jsdocInfos = append(p.jsdocInfos, JSDocInfo{parent: importDeclaration, jsDocs: []*ast.Node{jsDoc}}) + importDeclaration.Flags |= ast.NodeFlagsHasJSDoc p.reparseList = append(p.reparseList, importDeclaration) case ast.KindJSDocOverloadTag: // Create overload signatures only for function, method, and constructor declarations outside object literals diff --git a/tsc/internal/printer/emitcontext.go b/tsc/internal/printer/emitcontext.go index ee483873f0d58..d187f90446767 100644 --- a/tsc/internal/printer/emitcontext.go +++ b/tsc/internal/printer/emitcontext.go @@ -25,6 +25,8 @@ type EmitContext struct { varScopeStack core.Stack[*varScope] letScopeStack core.Stack[*varScope] emitHelpers collections.OrderedSet[*EmitHelper] + // Comments owned by a node they do not textually precede, keyed by the comment's start position. + claimedComments map[int]*ast.Node } type environmentFlags int @@ -523,6 +525,7 @@ type emitNodeFlags uint32 const ( hasCommentRange emitNodeFlags = 1 << iota hasSourceMapRange + claimsComment ) type SnippetKind int @@ -619,6 +622,51 @@ func (c *EmitContext) AssignCommentRange(to *ast.Node, from *ast.Node) { c.SetCommentRange(to, c.CommentRange(from)) } +// Gives the comment at loc to node, which need not be the node the comment textually precedes. A +// claimed comment is emitted by its owner and skipped by every other node whose leading comment scan +// runs across it, and the owner in turn emits no leading comment other than the one it claimed. This +// lets a declaration reparsed out of a JSDoc tag keep the comment that declared it instead of +// leaving it in front of the following statement. scanFrom is where the printer starts looking for +// leading comments and must sit before the line the comment starts on, since comment scans only +// collect after a line break. +// +// node is nil when the declaration the comment documents is elided from the output, which leaves the +// comment with no one to emit it - it documents something the output does not contain. A claim by an +// emitted node supersedes one made for an elided declaration from the same comment; otherwise the +// first claim wins. +func (c *EmitContext) ClaimComment(node *ast.Node, scanFrom int, loc core.TextRange) { + if owner, claimed := c.claimedComments[loc.Pos()]; claimed && (owner != nil || node == nil) { + return + } + if c.claimedComments == nil { + c.claimedComments = make(map[int]*ast.Node) + } + c.claimedComments[loc.Pos()] = node + if node == nil { + return + } + c.SetCommentRange(node, core.NewTextRange(scanFrom, loc.End())) + c.emitNodes.Get(node).flags |= claimsComment +} + +// Reports whether node was given a comment to emit by ClaimComment. +func (c *EmitContext) ClaimsComment(node *ast.Node) bool { + if node == nil { + return false + } + emitNode := c.emitNodes.TryGet(node) + return emitNode != nil && emitNode.flags&claimsComment != 0 +} + +// Reports whether node emits the comment starting at pos as one of its leading comments. node is nil +// when comments are emitted outside of any node. +func (c *EmitContext) EmitsLeadingComment(node *ast.Node, pos int) bool { + if owner, claimed := c.claimedComments[pos]; claimed { + return owner != nil && owner == node + } + return !c.ClaimsComment(node) +} + // Gets the range to use for a node when emitting source maps. func (c *EmitContext) SourceMapRange(node *ast.Node) core.TextRange { if emitNode := c.emitNodes.TryGet(node); emitNode != nil && emitNode.flags&hasSourceMapRange != 0 { diff --git a/tsc/internal/printer/printer.go b/tsc/internal/printer/printer.go index 31547cde51d64..5fca5fab4d531 100644 --- a/tsc/internal/printer/printer.go +++ b/tsc/internal/printer/printer.go @@ -5435,7 +5435,7 @@ func (p *Printer) emitLeadingCommentsOfNode(node *ast.Node, emitFlags EmitFlags, // Emit leading comments if the position is not synthesized and the node // has not opted out from emitting leading comments. if !skipLeadingComments { - p.emitLeadingComments(pos, node.Kind == ast.KindNotEmittedStatement /*elided*/) + p.emitLeadingCommentsWorker(pos, node, node.Kind == ast.KindNotEmittedStatement /*elided*/) } if !skipLeadingComments || (pos >= 0 && (emitFlags&EFNoLeadingComments) != 0) { @@ -5533,6 +5533,12 @@ func (p *Printer) writeSynthesizedComment(comment SynthesizedComment) { } func (p *Printer) emitLeadingComments(pos int, elided bool) bool { + return p.emitLeadingCommentsWorker(pos, nil /*node*/, elided) +} + +// node decides ownership of comments claimed by way of EmitContext.ClaimComment, and is nil when +// comments are emitted outside of any node. +func (p *Printer) emitLeadingCommentsWorker(pos int, node *ast.Node, elided bool) bool { // Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments if p.commentsDisabled || p.currentSourceFile == nil || ast.PositionIsSynthesized(pos) || pos == p.containerPos { return false @@ -5557,8 +5563,11 @@ func (p *Printer) emitLeadingComments(pos int, elided bool) bool { return false } - // skip detached comments - if p.detachedCommentsInfo.Len() > 0 { + // skip detached comments - a node claiming a comment has to keep scanning across them, since the + // comment it claims may be one the detached pass left behind for it, and the node the comments + // were detached from still needs to consume them + claimsComment := p.emitContext.ClaimsComment(node) + if p.detachedCommentsInfo.Len() > 0 && !claimsComment { if info := p.detachedCommentsInfo.Peek(); info.nodePos == pos { pos = p.detachedCommentsInfo.Pop().detachedCommentEndPos } @@ -5566,6 +5575,9 @@ func (p *Printer) emitLeadingComments(pos int, elided bool) bool { var comments []ast.CommentRange for comment := range scanner.GetLeadingCommentRanges(p.emitContext.Factory.AsNodeFactory(), p.currentSourceFile.Text(), pos) { + if !p.emitContext.EmitsLeadingComment(node, comment.Pos()) { + continue + } if p.shouldWriteComment(comment) && p.shouldEmitCommentIfTripleSlash(comment, tripleSlash) { comments = append(comments, comment) } @@ -5576,7 +5588,13 @@ func (p *Printer) emitLeadingComments(pos int, elided bool) bool { } // Leading comments are emitted as /*leading comment1*/space/*leading comment*/space - return p.emitComments(comments, commentSeparatorAfter) + hasWrittenComment := p.emitComments(comments, commentSeparatorAfter) + if hasWrittenComment && claimsComment && !p.writer.IsAtStartOfLine() { + // A claimed comment no longer precedes the text it did in the source, so it cannot borrow + // that text's line break. + p.writeLine() + } + return hasWrittenComment } func (p *Printer) shouldEmitCommentIfTripleSlash(comment ast.CommentRange, tripleSlash core.Tristate) bool { @@ -5722,6 +5740,13 @@ func (p *Printer) emitDetachedComments(textRange core.TextRange) (result detache } } + if !p.emitContext.EmitsLeadingComment(nil /*node*/, comment.Pos()) { + // A claimed comment is emitted by its owner, which comes after this point in the + // output. Detaching the rest of the run would print it ahead of the owner and put + // the comments out of source order. + break + } + detachedComments = append(detachedComments, comment) lastComment = comment } diff --git a/tsc/internal/transformers/declarations/transform.go b/tsc/internal/transformers/declarations/transform.go index 32fa0201a9ef5..9c03a789dd127 100644 --- a/tsc/internal/transformers/declarations/transform.go +++ b/tsc/internal/transformers/declarations/transform.go @@ -458,9 +458,104 @@ func (tx *DeclarationTransformer) transformAndReplaceLatePaintedStatements(state } } + // Claim over the statements as they went in, not over `results`, so that a comment whose + // declaration was just elided is claimed by nothing rather than left for the next statement. + tx.claimReparsedJSDocComments(statements.Nodes) return tx.Factory().NewNodeList(results) } +// Tags that reparse into a top-level declaration the containing JSDoc comment can be claimed for. +func declaresOwnDeclaration(tag *ast.Node) bool { + switch tag.Kind { + case ast.KindJSDocTypedefTag, ast.KindJSDocCallbackTag, ast.KindJSDocImportTag: + return true + } + return false +} + +// Tags whose meaning belongs to a node other than the declarations reparsed out of the containing +// comment: those the parser applies to the comment's host - see reparseHosted - plus `@overload`, +// which is emitted as a signature of its own. `@template` is the exception, since alongside a +// `@typedef` or `@callback` it declares type parameters of the type being declared and leaves the +// host none, per gatherTypeParameters. +func documentsAnotherNode(tag *ast.Node, declaresType bool) bool { + switch tag.Kind { + case ast.KindJSDocTypeTag, ast.KindJSDocSatisfiesTag, ast.KindJSDocParameterTag, ast.KindJSDocThisTag, + ast.KindJSDocReturnTag, ast.KindJSDocReadonlyTag, ast.KindJSDocPrivateTag, ast.KindJSDocPublicTag, + ast.KindJSDocProtectedTag, ast.KindJSDocOverrideTag, ast.KindJSDocImplementsTag, + ast.KindJSDocAugmentsTag, ast.KindJSDocOverloadTag: + return true + case ast.KindJSDocTemplateTag: + return !declaresType + } + return false +} + +// A JSDoc comment documents the declarations reparsed out of it, rather than the statement it is +// attached to, when it produces such a declaration and carries nothing that documents anything else. +// Whatever remains - the description, `@see`, `@example` and the like - describes what the comment +// declares. +func documentsOnlyReparsedDeclarations(jsdoc *ast.Node) bool { + tags := jsdoc.AsJSDoc().Tags + if tags == nil || !core.Some(tags.Nodes, declaresOwnDeclaration) { + return false + } + declaresType := core.Some(tags.Nodes, func(tag *ast.Node) bool { + return ast.IsJSDocTypedefTag(tag) || ast.IsJSDocCallbackTag(tag) + }) + return !core.Some(tags.Nodes, func(tag *ast.Node) bool { return documentsAnotherNode(tag, declaresType) }) +} + +// A JSDoc node starts at the full start of the node it documents rather than at its own `/**`, so +// recover the range of the comment itself. +func (tx *DeclarationTransformer) commentRangeOfJSDoc(jsdoc *ast.Node, file *ast.SourceFile) (core.TextRange, bool) { + for comment := range scanner.GetLeadingCommentRanges(tx.EmitContext().Factory.AsNodeFactory(), file.Text(), jsdoc.Pos()) { + if comment.End() == jsdoc.End() { + return comment.TextRange, true + } + } + return core.TextRange{}, false +} + +// The node a statement takes in the output, or nil when it is elided. +func (tx *DeclarationTransformer) emittedForm(statement *ast.Node) *ast.Node { + if !ast.IsLateVisibilityPaintedStatement(statement) { + return statement + } + replacement, replaced := tx.lateStatementReplacementMap[ast.GetNodeId(tx.EmitContext().MostOriginal(statement))] + if !replaced { + return statement + } + if replacement != nil && replacement.Kind == ast.KindSyntaxList { + return core.FirstOrNil(replacement.AsSyntaxList().Children) + } + return replacement +} + +// Declarations reparsed from JSDoc (`@typedef`, `@callback`, `@import`) take the text range of the +// tag they came from, which sits inside the comment. The printer therefore finds no leading comment +// for them and hands the comment to the following statement instead, documenting the wrong +// declaration. Claim each such comment for the first declaration reparsed out of it. +func (tx *DeclarationTransformer) claimReparsedJSDocComments(statements []*ast.Node) { + file := tx.state.currentSourceFile + if file == nil || !ast.IsSourceFileJS(file) { + return + } + for _, statement := range statements { + original := tx.EmitContext().MostOriginal(statement) + if original.Flags&ast.NodeFlagsReparsed == 0 { + continue + } + jsdoc := core.FirstOrNil(original.EagerJSDoc(file)) + if jsdoc == nil || !documentsOnlyReparsedDeclarations(jsdoc) { + continue + } + if loc, ok := tx.commentRangeOfJSDoc(jsdoc, file); ok { + tx.EmitContext().ClaimComment(tx.emittedForm(statement), jsdoc.Pos(), loc) + } + } +} + func (tx *DeclarationTransformer) getReferencedFiles(outputFilePath string) (results []*ast.FileReference) { // Handle path rewrites for triple slash ref comments for _, pair := range tx.rawReferencedFiles { diff --git a/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging5.js b/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging5.js index 4f0f0afc8a7d3..fe4d7d1c7db0e 100644 --- a/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging5.js +++ b/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging5.js @@ -29,14 +29,14 @@ let v1 = { x: "test" }; //// [a.d.ts] -/** - * @typedef {{x: string}} Foo - */ declare const _exports: { a: number; b: string; }; export = _exports; +/** + * @typedef {{x: string}} Foo + */ export type Foo = { x: string; }; diff --git a/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging6.js b/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging6.js index 40f8911c5ffc4..fedf752ed885c 100644 --- a/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging6.js +++ b/tsc/testdata/baselines/reference/compiler/exportAssignmentMerging6.js @@ -33,12 +33,12 @@ let v1 = { x: "test" }; //// [a.d.ts] -export type Foo = { - x: string; -}; /** * @typedef {{x: string}} Foo */ +export type Foo = { + x: string; +}; export declare const x = 1; //// [b.d.ts] export {}; diff --git a/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitDoesNotRenameImport.js b/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitDoesNotRenameImport.js index 5f0cf191f367c..caaf932650352 100644 --- a/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitDoesNotRenameImport.js +++ b/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitDoesNotRenameImport.js @@ -45,13 +45,13 @@ declare class Test { export default Test; //// [index.d.ts] import Test from './test/Test.js'; -export type Options = { - test?: typeof import("./Test.js").default; -}; /** * @typedef {Object} Options * @property {typeof import("./Test.js").default} [test] */ +export type Options = { + test?: typeof import("./Test.js").default; +}; declare class X extends Test { test: import("./Test.js").default | undefined; /** diff --git a/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitExportAssignedFunctionWithExtraTypedefsMembers.js b/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitExportAssignedFunctionWithExtraTypedefsMembers.js index 10157988ac1cf..6c991faf611f4 100644 --- a/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitExportAssignedFunctionWithExtraTypedefsMembers.js +++ b/tsc/testdata/baselines/reference/compiler/jsDeclarationEmitExportAssignedFunctionWithExtraTypedefsMembers.js @@ -25,15 +25,15 @@ module.exports = function loader(options) { }; //// [index.d.ts] -/** - * @typedef Options - * @property {string} opt - */ export = loader; /** * @param {Options} options */ declare function loader(options: Options): void; +/** + * @typedef Options + * @property {string} opt + */ export type Options = { opt: string; }; diff --git a/tsc/testdata/baselines/reference/compiler/jsDeclarationsInheritedTypes.js b/tsc/testdata/baselines/reference/compiler/jsDeclarationsInheritedTypes.js index 94d864452f5c6..31ad8e03dcd11 100644 --- a/tsc/testdata/baselines/reference/compiler/jsDeclarationsInheritedTypes.js +++ b/tsc/testdata/baselines/reference/compiler/jsDeclarationsInheritedTypes.js @@ -43,13 +43,13 @@ class C3 extends C1 { type A = { a: string; }; -type B = { - b: number; -}; /** * @typedef B * @property {number} b */ +type B = { + b: number; +}; declare class C1 { /** * @type {A} diff --git a/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport1.js b/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport1.js index eac66bbf52af0..82b29e1ee3741 100644 --- a/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport1.js +++ b/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport1.js @@ -12,10 +12,10 @@ function f1() {} //// [x.d.ts] -type Foo = (x: string) => number; /** * @callback Foo * @param {string} x * @returns {number} */ +type Foo = (x: string) => number; declare function f1(): void; diff --git a/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport2.js b/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport2.js index 8a894ce57d28e..b3048ca6f49ea 100644 --- a/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport2.js +++ b/tsc/testdata/baselines/reference/compiler/jsDocCallbackExport2.js @@ -12,10 +12,10 @@ export function f1() {} //// [x.d.ts] -export type Foo = (x: string) => number; /** * @callback Foo * @param {string} x * @returns {number} */ +export type Foo = (x: string) => number; export declare function f1(): void; diff --git a/tsc/testdata/baselines/reference/compiler/jsTypedefMergedWithModuleExportProperty.js b/tsc/testdata/baselines/reference/compiler/jsTypedefMergedWithModuleExportProperty.js index 9708ba8ee6f56..ebb6528f12645 100644 --- a/tsc/testdata/baselines/reference/compiler/jsTypedefMergedWithModuleExportProperty.js +++ b/tsc/testdata/baselines/reference/compiler/jsTypedefMergedWithModuleExportProperty.js @@ -36,13 +36,13 @@ declare namespace ModuleGraphConnection { const _exported: typeof T; export { _exported as T }; } -export type T = typeof T; /** @typedef {typeof T} T */ +export type T = typeof T; declare const T: unique symbol; //// [repro.d.ts] export = Repro; -/** @typedef {import('./local-lib/ModuleGraphConnection')} ImportedType */ /** @type {ImportedType} */ declare class Repro { } +/** @typedef {import('./local-lib/ModuleGraphConnection')} ImportedType */ export type ImportedType = import('./local-lib/ModuleGraphConnection'); diff --git a/tsc/testdata/baselines/reference/compiler/jsdocMultilineUnion.js b/tsc/testdata/baselines/reference/compiler/jsdocMultilineUnion.js index 8aad70d67947f..cdb8bf288f6a0 100644 --- a/tsc/testdata/baselines/reference/compiler/jsdocMultilineUnion.js +++ b/tsc/testdata/baselines/reference/compiler/jsdocMultilineUnion.js @@ -14,7 +14,6 @@ //// [a.d.ts] -type T = ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n")[]; /** * @typedef {("a"|"b"|"c"| * "d"|"e"|"f"|"g"| @@ -23,3 +22,4 @@ type T = ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" * "k"|"l"| * "m"|"n")[]} T */ +type T = ("a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n")[]; diff --git a/tsc/testdata/baselines/reference/compiler/jsdocNonIdentifierPropertiesAndParams.js b/tsc/testdata/baselines/reference/compiler/jsdocNonIdentifierPropertiesAndParams.js index c1b67a05e60bd..30f5a58ec4998 100644 --- a/tsc/testdata/baselines/reference/compiler/jsdocNonIdentifierPropertiesAndParams.js +++ b/tsc/testdata/baselines/reference/compiler/jsdocNonIdentifierPropertiesAndParams.js @@ -51,9 +51,9 @@ export type ButtonProps = { * @returns {ButtonProps} */ export declare function Button(props: ButtonProps): ButtonProps; -export type ButtonPropsCallback = (props_like?: ButtonProps) => ButtonProps; /** * @callback ButtonPropsCallback * @param {ButtonProps} [props-like] * @returns {ButtonProps} */ +export type ButtonPropsCallback = (props_like?: ButtonProps) => ButtonProps; diff --git a/tsc/testdata/baselines/reference/compiler/reuseTypeAnnotationImportTypeInGlobalThisTypeArgument.js b/tsc/testdata/baselines/reference/compiler/reuseTypeAnnotationImportTypeInGlobalThisTypeArgument.js index 41f5b45f14933..a07ff1306075c 100644 --- a/tsc/testdata/baselines/reference/compiler/reuseTypeAnnotationImportTypeInGlobalThisTypeArgument.js +++ b/tsc/testdata/baselines/reference/compiler/reuseTypeAnnotationImportTypeInGlobalThisTypeArgument.js @@ -34,11 +34,11 @@ export const blah = handleParamGovernance({}); //// [types.d.ts] export {}; -export type ParamStateRecord = Record; /** * @typedef {Record} ParamStateRecord a Record containing * keyword pairs with descriptions of parameters under governance. */ +export type ParamStateRecord = Record; //// [index.d.ts] export declare const blah: { publicMixin: { diff --git a/tsc/testdata/baselines/reference/compiler/typedefHoisting.js b/tsc/testdata/baselines/reference/compiler/typedefHoisting.js index 6803d6b512432..6a0abf6821f81 100644 --- a/tsc/testdata/baselines/reference/compiler/typedefHoisting.js +++ b/tsc/testdata/baselines/reference/compiler/typedefHoisting.js @@ -19,15 +19,15 @@ export {} //// [y.d.ts] -export type Bar = string; /** @typedef {string} Bar */ +export type Bar = string; export {}; //// [x.d.ts] +/** @import {Bar} from "./y" */ import type { Bar } from "./y"; +/** @typedef {Bar[]} Bars */ type Bars = Bar[]; declare class C { - /** @import {Bar} from "./y" */ - /** @typedef {Bar[]} Bars */ /** @type {Bars} */ foo: Bars; bar(/** @type {Bar} */ x: Bar): string; diff --git a/tsc/testdata/baselines/reference/conformance/callbackOnConstructor.js b/tsc/testdata/baselines/reference/conformance/callbackOnConstructor.js index 4c9906e3cd709..29251540bfb0a 100644 --- a/tsc/testdata/baselines/reference/conformance/callbackOnConstructor.js +++ b/tsc/testdata/baselines/reference/conformance/callbackOnConstructor.js @@ -32,13 +32,13 @@ var ooscope2 = s => s.length > 0; //// [callbackOnConstructor.d.ts] +/** + * @callback ValueGetter_2 + * @param {string} name + * @returns {boolean|number|string|undefined} + */ export type ValueGetter_2 = (name: string) => boolean | number | string | undefined; export declare class Preferences { assignability: string; - /** - * @callback ValueGetter_2 - * @param {string} name - * @returns {boolean|number|string|undefined} - */ constructor(); } diff --git a/tsc/testdata/baselines/reference/conformance/checkJsdocSatisfiesTag15.js b/tsc/testdata/baselines/reference/conformance/checkJsdocSatisfiesTag15.js index e53c5236eb5a7..aaa77030248ac 100644 --- a/tsc/testdata/baselines/reference/conformance/checkJsdocSatisfiesTag15.js +++ b/tsc/testdata/baselines/reference/conformance/checkJsdocSatisfiesTag15.js @@ -85,8 +85,8 @@ export function fn7(uuid) { } //// [a.d.ts] /** @satisfies {(uuid: string) => void} */ export declare const fn1: (uuid: string) => void; -export type Foo = Parameters; /** @typedef {Parameters} Foo */ +export type Foo = Parameters; /** @type Foo */ export declare const v1: Foo; /** @type Foo */ diff --git a/tsc/testdata/baselines/reference/conformance/importDeferJsdoc.js b/tsc/testdata/baselines/reference/conformance/importDeferJsdoc.js index 13607f52d3319..dc7f8bc6a7a81 100644 --- a/tsc/testdata/baselines/reference/conformance/importDeferJsdoc.js +++ b/tsc/testdata/baselines/reference/conformance/importDeferJsdoc.js @@ -19,9 +19,6 @@ let a = 2; //// [types.d.ts] export type X = 1; //// [foo.d.ts] -/** - * @import defer * as ns from "./types" - */ /** * @type { ns.X } */ diff --git a/tsc/testdata/baselines/reference/conformance/importTag15(module=es2015).js b/tsc/testdata/baselines/reference/conformance/importTag15(module=es2015).js index 2ade94c80ebc1..8d502927e436b 100644 --- a/tsc/testdata/baselines/reference/conformance/importTag15(module=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/importTag15(module=es2015).js @@ -18,7 +18,6 @@ export interface I { } //// [1.d.ts] /** @import { I } from './0' with { type: "json" } */ -/** @import * as foo from './0' with { type: "json" } */ import type { I } from './0' with { type: "json" }; /** @param {I} a */ declare function f(a: I): void; diff --git a/tsc/testdata/baselines/reference/conformance/importTag15(module=esnext).js b/tsc/testdata/baselines/reference/conformance/importTag15(module=esnext).js index 2ade94c80ebc1..8d502927e436b 100644 --- a/tsc/testdata/baselines/reference/conformance/importTag15(module=esnext).js +++ b/tsc/testdata/baselines/reference/conformance/importTag15(module=esnext).js @@ -18,7 +18,6 @@ export interface I { } //// [1.d.ts] /** @import { I } from './0' with { type: "json" } */ -/** @import * as foo from './0' with { type: "json" } */ import type { I } from './0' with { type: "json" }; /** @param {I} a */ declare function f(a: I): void; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassImplementsGenericsSerialization(target=es2015).js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassImplementsGenericsSerialization(target=es2015).js index a162e36a7e401..e2149d92f9605 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassImplementsGenericsSerialization(target=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassImplementsGenericsSerialization(target=es2015).js @@ -65,8 +65,8 @@ export declare class Encoder implements IEncoder { */ encode(value: T): Uint8Array; } -export type IEncoder = import('./interface').Encoder; /** * @template T * @typedef {import('./interface').Encoder} IEncoder */ +export type IEncoder = import('./interface').Encoder; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassStatic(target=es2015).js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassStatic(target=es2015).js index f71f4d003992d..5d5e8f3dc0973 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassStatic(target=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsClassStatic(target=es2015).js @@ -62,14 +62,14 @@ declare const Strings: { a: string; b: string; }; +/** + * @typedef {Object} HandlerOptions + * @property {String} name + * Should be able to export a type alias at the same time. + */ export type HandlerOptions = { /** * Should be able to export a type alias at the same time. */ name: string; }; -/** - * @typedef {Object} HandlerOptions - * @property {String} name - * Should be able to export a type alias at the same time. - */ diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefault(target=es2015).js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefault(target=es2015).js index e875e57bd88e1..d5eb67a582caa 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefault(target=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefault(target=es2015).js @@ -122,13 +122,13 @@ export default Bar; //// [index5.d.ts] declare const _default = 12; export default _default; -export type default = string | number; /** * @typedef {string | number} default */ +export type default = string | number; //// [index6.d.ts] export default function func(): void; -export type default = string | number; /** * @typedef {string | number} default */ +export type default = string | number; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefaultsErr(target=es2015).js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefaultsErr(target=es2015).js index 062db66cf59ab..3cb662fdade65 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefaultsErr(target=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsDefaultsErr(target=es2015).js @@ -70,21 +70,21 @@ declare class Cls { static y: string; } export default Cls; -export type default = string | number; /** * @typedef {string | number} default */ +export type default = string | number; //// [index2.d.ts] export default class C { } -export type default = string | number; /** * @typedef {string | number} default */ +export type default = string | number; //// [index3.d.ts] declare const x = 12; export { x as default }; -export type default = string | number; /** * @typedef {string | number} default */ +export type default = string | number; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionClassesCjsExportAssignment(target=es2015).js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionClassesCjsExportAssignment(target=es2015).js index eaaac056b90b7..5d75d478e31b6 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionClassesCjsExportAssignment(target=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionClassesCjsExportAssignment(target=es2015).js @@ -147,6 +147,7 @@ export = Timer; */ declare function Timer(timeout: number): void; //// [context.d.ts] +export = Context; /** * Imports * @@ -154,18 +155,9 @@ declare function Timer(timeout: number): void; * @typedef {import("./hook")} Hook * @typedef {import("./hook").HookHandler} HookHandler */ -export = Context; export type Timer = import("./timer"); export type Hook = import("./hook"); export type HookHandler = import("./hook").HookHandler; -export type Input = { - timer: Timer; - hook: Hook; -}; -export type State = { - timer: Timer; - hook: Hook; -}; /** * Input type definition * @@ -173,6 +165,10 @@ export type State = { * @prop {Timer} timer * @prop {Hook} hook */ +export type Input = { + timer: Timer; + hook: Hook; +}; /** * State type definition * @@ -180,6 +176,10 @@ export type State = { * @prop {Timer} timer * @prop {Hook} hook */ +export type State = { + timer: Timer; + hook: Hook; +}; /** * New `Context` * @@ -199,10 +199,10 @@ declare namespace Context { } //// [hook.d.ts] export = Hook; -export type HookHandler = (arg: import("./context")) => void; /** * @typedef {(arg: import("./context")) => void} HookHandler */ +export type HookHandler = (arg: import("./context")) => void; /** * @param {HookHandler} handle */ diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionPrototypeStatic(target=es2015).js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionPrototypeStatic(target=es2015).js index 81f31ee4100a9..465221d1fe410 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionPrototypeStatic(target=es2015).js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsFunctionPrototypeStatic(target=es2015).js @@ -37,10 +37,10 @@ declare namespace MyClass { var staticMethod: () => void; var staticProperty: number; } -export type DoneCB = (failures: number) => any; /** * Callback to be invoked when test execution is complete. * * @callback DoneCB * @param {number} failures - Number of failures that occurred. */ +export type DoneCB = (failures: number) => any; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespace.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespace.js index 4d58c2fd590c8..60efc5acc5c2d 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespace.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespace.js @@ -61,9 +61,15 @@ export {testFn, testFnTypes}; */ declare const myTypes: Record; export declare namespace myTypes { + /** @typedef {string|RegExp|Array} myTypes.typeA */ export type typeA = string | RegExp | Array; } export declare namespace myTypes { + /** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ export type typeB = { /** * - Prop 1. @@ -76,15 +82,9 @@ export declare namespace myTypes { }; } export declare namespace myTypes { + /** @typedef {myTypes.typeB|Function} myTypes.typeC */ export type typeC = myTypes.typeB | Function; } -/** @typedef {string|RegExp|Array} myTypes.typeA */ -/** - * @typedef myTypes.typeB - * @property {myTypes.typeA} prop1 - Prop 1. - * @property {string} prop2 - Prop 2. - */ -/** @typedef {myTypes.typeB|Function} myTypes.typeC */ export { myTypes }; //// [file2.d.ts] import { myTypes } from './file.js'; @@ -95,9 +95,9 @@ import { myTypes } from './file.js'; */ declare const testFnTypes: Record; export declare namespace testFnTypes { + /** @typedef {boolean|myTypes.typeC} testFnTypes.input */ export type input = boolean | myTypes.typeC; } -/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ /** * @function testFn * @description A test function. diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js index 1899566abe4ff..b63dd96e5104b 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js @@ -62,9 +62,15 @@ export { myTypes }; */ declare const myTypes: Record; export declare namespace myTypes { + /** @typedef {string|RegExp|Array} myTypes.typeA */ export type typeA = string | RegExp | Array; } export declare namespace myTypes { + /** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ export type typeB = { /** * - Prop 1. @@ -77,6 +83,7 @@ export declare namespace myTypes { }; } export declare namespace myTypes { + /** @typedef {myTypes.typeB|Function} myTypes.typeC */ export type typeC = myTypes.typeB | Function; } //// [file2.d.ts] @@ -93,9 +100,9 @@ import { myTypes } from './file.js'; */ declare const testFnTypes: Record; export declare namespace testFnTypes { + /** @typedef {boolean|myTypes.typeC} testFnTypes.input */ export type input = boolean | myTypes.typeC; } -/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ /** * @function testFn * @description A test function. diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportNamespacedType.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportNamespacedType.js index 94d7aaee6e878..ffe3506ee605c 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportNamespacedType.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsImportNamespacedType.js @@ -14,9 +14,9 @@ export var dummy = 1 //// [mod1.d.ts] export declare namespace Dotted { + /** @typedef {number} Dotted.Name */ export type Name = number; } -/** @typedef {number} Dotted.Name */ export declare var dummy: number; //// [file.d.ts] export {}; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsParameterTagReusesInputNodeInEmit1.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsParameterTagReusesInputNodeInEmit1.js index 61c74727f7018..874b247c70887 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsParameterTagReusesInputNodeInEmit1.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsParameterTagReusesInputNodeInEmit1.js @@ -71,13 +71,13 @@ declare namespace BaseFactory { export { Base }; } //// [file.d.ts] -type BaseFactory = import('./base'); -type BaseFactoryFactory = (factory: import('./base')) => any; /** @typedef {import('./base')} BaseFactory */ +type BaseFactory = import('./base'); /** * @callback BaseFactoryFactory * @param {import('./base')} factory */ +type BaseFactoryFactory = (factory: import('./base')) => any; /** @enum {import('./base')} */ declare const couldntThinkOfAny: {}; /** diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypeAliases.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypeAliases.js index 174bb02fd7dbd..31a895531fe66 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypeAliases.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypeAliases.js @@ -106,15 +106,10 @@ class LocalThing { //// [index.d.ts] export {}; -export type PropName = string | number | symbol; -export type NumberToStringCb = (a: number) => string; -export type MixinName = T & { - name: string; -}; -export type Identity = (x: T) => T; /** * @typedef {string | number | symbol} PropName */ +export type PropName = string | number | symbol; /** * Callback * @@ -122,10 +117,14 @@ export type Identity = (x: T) => T; * @param {number} a * @returns {string} */ +export type NumberToStringCb = (a: number) => string; /** * @template T * @typedef {T & {name: string}} MixinName */ +export type MixinName = T & { + name: string; +}; /** * Identity function * @@ -134,18 +133,19 @@ export type Identity = (x: T) => T; * @param {T} x * @returns {T} */ +export type Identity = (x: T) => T; //// [mixed.d.ts] declare const _exports: { doTheThing: typeof doTheThing; ExportedThing: typeof ExportedThing; }; export = _exports; -export type SomeType = { - x: string; -} | number | LocalThing | ExportedThing; /** * @typedef {{x: string} | number | LocalThing | ExportedThing} SomeType */ +export type SomeType = { + x: string; +} | number | LocalThing | ExportedThing; /** * @param {number} x * @returns {SomeType} diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefAndImportTypes.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefAndImportTypes.js index 11faffb1309d6..2b81c60a347a9 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefAndImportTypes.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefAndImportTypes.js @@ -67,10 +67,10 @@ module.exports = { //// [conn.d.ts] +export = Conn; /** * @typedef {string | number} Whatever */ -export = Conn; export type Whatever = string | number; declare class Conn { constructor(); @@ -78,13 +78,13 @@ declare class Conn { method(): void; } //// [usage.d.ts] -/** - * @typedef {import("./conn")} Conn - */ declare const _exports: { Wrap: typeof Wrap; }; export = _exports; +/** + * @typedef {import("./conn")} Conn + */ export type Conn = import("./conn"); declare class Wrap { connItem: number; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.js new file mode 100644 index 0000000000000..9cc63f2e0e111 --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.js @@ -0,0 +1,432 @@ +//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsTypedefCommentPlacement.ts] //// + +//// [typedef.js] +export function noop() {} + +/** + * A point in 2D space. + * @typedef {Object} Point + * @property {number} x + * @property {number} y + */ + +/** + * @param {Point} p + */ +export function dist(p) { + return p.x; +} + +//// [callback.js] +export function noop() {} + +/** + * Compares two numbers. + * @callback Comparator + * @param {number} a + * @param {number} b + * @returns {number} + */ + +/** + * @param {number[]} arr + * @param {Comparator} cmp + */ +export function sortWith(arr, cmp) { + return arr.slice().sort(cmp); +} + +//// [shared.js] +export function noop() {} + +/** + * Two aliases from one comment. + * @typedef {number} A + * @typedef {string} B + */ + +export function f() {} + +//// [hosted.js] +export function noop() {} + +/** + * Documents g, not N. + * @typedef {number} N + * @param {N} x + */ +export function g(x) { + return x; +} + +//// [trailing.js] +export function noop() {} + +/** + * Nothing follows this one. + * @typedef {Object} Trailing + * @property {number} x + */ + +//// [imported.js] +export function noop() {} + +/** + * Imports and defines in one comment. + * @import {Point} from "./typedef.js" + * @typedef {Point[]} Path + */ + +export function h() {} + +//// [preceded.js] +export function noop() {} + +// not a JSDoc comment +/** + * @typedef {number} Q + */ + +export function i() {} + +//// [generic.js] +export function noop() {} + +/** + * A named mixin. + * @template T + * @typedef {T & {name: string}} MixinName + */ + +/** + * Identity. + * @template T + * @callback Identity + * @param {T} x + * @returns {T} + */ + +export function j() {} + +//// [templateOnHost.js] +export function noop() {} + +/** + * Documents k, not a type. + * @template T + * @param {T} x + */ +export function k(x) { return x; } + +//// [standaloneImport.js] +export function noop() {} + +/** + * Brings Point into scope. + * @import {Point} from "./typedef.js" + */ + +/** @type {Point} */ +export const p = { x: 0, y: 0 }; + +//// [overload.js] +export function noop() {} + +/** + * Takes a string. + * @overload + * @param {string} x + * @returns {string} + */ + +/** + * @param {any} x + */ +export function l(x) { return x; } + +//// [documentationTags.js] +export function noop() {} + +/** + * Prose describing S. + * @typedef {number} S + * @see noop + * @example + * const s = 1; + */ + +export function m() {} + +//// [elidedImport.js] +export function noop() {} + +/** + * Nothing in the output uses this import. + * @import {Point} from "./typedef.js" + */ + +export function n() {} + + +//// [typedef.js] +export function noop() { } +/** + * A point in 2D space. + * @typedef {Object} Point + * @property {number} x + * @property {number} y + */ +/** + * @param {Point} p + */ +export function dist(p) { + return p.x; +} +//// [callback.js] +export function noop() { } +/** + * Compares two numbers. + * @callback Comparator + * @param {number} a + * @param {number} b + * @returns {number} + */ +/** + * @param {number[]} arr + * @param {Comparator} cmp + */ +export function sortWith(arr, cmp) { + return arr.slice().sort(cmp); +} +//// [shared.js] +export function noop() { } +/** + * Two aliases from one comment. + * @typedef {number} A + * @typedef {string} B + */ +export function f() { } +//// [hosted.js] +export function noop() { } +/** + * Documents g, not N. + * @typedef {number} N + * @param {N} x + */ +export function g(x) { + return x; +} +//// [trailing.js] +export function noop() { } +/** + * Nothing follows this one. + * @typedef {Object} Trailing + * @property {number} x + */ +//// [imported.js] +export function noop() { } +/** + * Imports and defines in one comment. + * @import {Point} from "./typedef.js" + * @typedef {Point[]} Path + */ +export function h() { } +//// [preceded.js] +export function noop() { } +// not a JSDoc comment +/** + * @typedef {number} Q + */ +export function i() { } +//// [generic.js] +export function noop() { } +/** + * A named mixin. + * @template T + * @typedef {T & {name: string}} MixinName + */ +/** + * Identity. + * @template T + * @callback Identity + * @param {T} x + * @returns {T} + */ +export function j() { } +//// [templateOnHost.js] +export function noop() { } +/** + * Documents k, not a type. + * @template T + * @param {T} x + */ +export function k(x) { return x; } +//// [standaloneImport.js] +export function noop() { } +/** + * Brings Point into scope. + * @import {Point} from "./typedef.js" + */ +/** @type {Point} */ +export const p = { x: 0, y: 0 }; +//// [overload.js] +export function noop() { } +/** + * Takes a string. + * @overload + * @param {string} x + * @returns {string} + */ +/** + * @param {any} x + */ +export function l(x) { return x; } +//// [documentationTags.js] +export function noop() { } +/** + * Prose describing S. + * @typedef {number} S + * @see noop + * @example + * const s = 1; + */ +export function m() { } +//// [elidedImport.js] +export function noop() { } +/** + * Nothing in the output uses this import. + * @import {Point} from "./typedef.js" + */ +export function n() { } + + +//// [typedef.d.ts] +export declare function noop(): void; +/** + * A point in 2D space. + * @typedef {Object} Point + * @property {number} x + * @property {number} y + */ +export type Point = { + x: number; + y: number; +}; +/** + * @param {Point} p + */ +export declare function dist(p: Point): number; +//// [callback.d.ts] +export declare function noop(): void; +/** + * Compares two numbers. + * @callback Comparator + * @param {number} a + * @param {number} b + * @returns {number} + */ +export type Comparator = (a: number, b: number) => number; +/** + * @param {number[]} arr + * @param {Comparator} cmp + */ +export declare function sortWith(arr: number[], cmp: Comparator): number[]; +//// [shared.d.ts] +export declare function noop(): void; +/** + * Two aliases from one comment. + * @typedef {number} A + * @typedef {string} B + */ +export type A = number; +export type B = string; +export declare function f(): void; +//// [hosted.d.ts] +export declare function noop(): void; +export type N = number; +/** + * Documents g, not N. + * @typedef {number} N + * @param {N} x + */ +export declare function g(x: N): number; +//// [trailing.d.ts] +export declare function noop(): void; +/** + * Nothing follows this one. + * @typedef {Object} Trailing + * @property {number} x + */ +export type Trailing = { + x: number; +}; +//// [imported.d.ts] +export declare function noop(): void; +/** + * Imports and defines in one comment. + * @import {Point} from "./typedef.js" + * @typedef {Point[]} Path + */ +import type { Point } from "./typedef.js"; +export type Path = Point[]; +export declare function h(): void; +//// [preceded.d.ts] +export declare function noop(): void; +/** + * @typedef {number} Q + */ +export type Q = number; +export declare function i(): void; +//// [generic.d.ts] +export declare function noop(): void; +/** + * A named mixin. + * @template T + * @typedef {T & {name: string}} MixinName + */ +export type MixinName = T & { + name: string; +}; +/** + * Identity. + * @template T + * @callback Identity + * @param {T} x + * @returns {T} + */ +export type Identity = (x: T) => T; +export declare function j(): void; +//// [templateOnHost.d.ts] +export declare function noop(): void; +/** + * Documents k, not a type. + * @template T + * @param {T} x + */ +export declare function k(x: T): T; +//// [standaloneImport.d.ts] +export declare function noop(): void; +/** + * Brings Point into scope. + * @import {Point} from "./typedef.js" + */ +import type { Point } from "./typedef.js"; +/** @type {Point} */ +export declare const p: Point; +//// [overload.d.ts] +export declare function noop(): void; +export declare function l(x: string): string; +//// [documentationTags.d.ts] +export declare function noop(): void; +/** + * Prose describing S. + * @typedef {number} S + * @see noop + * @example + * const s = 1; + */ +export type S = number; +export declare function m(): void; +//// [elidedImport.d.ts] +export declare function noop(): void; +export declare function n(): void; diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.symbols b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.symbols new file mode 100644 index 0000000000000..bfa218b64a58c --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.symbols @@ -0,0 +1,217 @@ +//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsTypedefCommentPlacement.ts] //// + +=== typedef.js === +export function noop() {} +>noop : Symbol(noop, Decl(typedef.js, 0, 0)) + +/** + * A point in 2D space. + * @typedef {Object} Point + * @property {number} x + * @property {number} y + */ + +/** + * @param {Point} p + */ +export function dist(p) { +>dist : Symbol(dist, Decl(typedef.js, 0, 25)) +>p : Symbol(p, Decl(typedef.js, 12, 21)) + + return p.x; +>p.x : Symbol(x, Decl(typedef.js, 5, 3)) +>p : Symbol(p, Decl(typedef.js, 12, 21)) +>x : Symbol(x, Decl(typedef.js, 5, 3)) +} + +=== callback.js === +export function noop() {} +>noop : Symbol(noop, Decl(callback.js, 0, 0)) + +/** + * Compares two numbers. + * @callback Comparator + * @param {number} a + * @param {number} b + * @returns {number} + */ + +/** + * @param {number[]} arr + * @param {Comparator} cmp + */ +export function sortWith(arr, cmp) { +>sortWith : Symbol(sortWith, Decl(callback.js, 0, 25)) +>arr : Symbol(arr, Decl(callback.js, 14, 25)) +>cmp : Symbol(cmp, Decl(callback.js, 14, 29)) + + return arr.slice().sort(cmp); +>arr.slice().sort : Symbol(Array.sort, Decl(lib.es5.d.ts, --, --)) +>arr.slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) +>arr : Symbol(arr, Decl(callback.js, 14, 25)) +>slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) +>sort : Symbol(Array.sort, Decl(lib.es5.d.ts, --, --)) +>cmp : Symbol(cmp, Decl(callback.js, 14, 29)) +} + +=== shared.js === +export function noop() {} +>noop : Symbol(noop, Decl(shared.js, 0, 0)) + +/** + * Two aliases from one comment. + * @typedef {number} A + * @typedef {string} B + */ + +export function f() {} +>f : Symbol(f, Decl(shared.js, 0, 25)) + +=== hosted.js === +export function noop() {} +>noop : Symbol(noop, Decl(hosted.js, 0, 0)) + +/** + * Documents g, not N. + * @typedef {number} N + * @param {N} x + */ +export function g(x) { +>g : Symbol(g, Decl(hosted.js, 0, 25)) +>x : Symbol(x, Decl(hosted.js, 7, 18)) + + return x; +>x : Symbol(x, Decl(hosted.js, 7, 18)) +} + +=== trailing.js === +export function noop() {} +>noop : Symbol(noop, Decl(trailing.js, 0, 0)) + +/** + * Nothing follows this one. + * @typedef {Object} Trailing + * @property {number} x + */ + +=== imported.js === +export function noop() {} +>noop : Symbol(noop, Decl(imported.js, 0, 0)) + +/** + * Imports and defines in one comment. + * @import {Point} from "./typedef.js" + * @typedef {Point[]} Path + */ + +export function h() {} +>h : Symbol(h, Decl(imported.js, 0, 25)) + +=== preceded.js === +export function noop() {} +>noop : Symbol(noop, Decl(preceded.js, 0, 0)) + +// not a JSDoc comment +/** + * @typedef {number} Q + */ + +export function i() {} +>i : Symbol(i, Decl(preceded.js, 0, 25)) + +=== generic.js === +export function noop() {} +>noop : Symbol(noop, Decl(generic.js, 0, 0)) + +/** + * A named mixin. + * @template T + * @typedef {T & {name: string}} MixinName + */ + +/** + * Identity. + * @template T + * @callback Identity + * @param {T} x + * @returns {T} + */ + +export function j() {} +>j : Symbol(j, Decl(generic.js, 0, 25)) + +=== templateOnHost.js === +export function noop() {} +>noop : Symbol(noop, Decl(templateOnHost.js, 0, 0)) + +/** + * Documents k, not a type. + * @template T + * @param {T} x + */ +export function k(x) { return x; } +>k : Symbol(k, Decl(templateOnHost.js, 0, 25)) +>x : Symbol(x, Decl(templateOnHost.js, 7, 18)) +>x : Symbol(x, Decl(templateOnHost.js, 7, 18)) + +=== standaloneImport.js === +export function noop() {} +>noop : Symbol(noop, Decl(standaloneImport.js, 0, 0)) + +/** + * Brings Point into scope. + * @import {Point} from "./typedef.js" + */ + +/** @type {Point} */ +export const p = { x: 0, y: 0 }; +>p : Symbol(p, Decl(standaloneImport.js, 8, 12)) +>x : Symbol(x, Decl(standaloneImport.js, 8, 18)) +>y : Symbol(y, Decl(standaloneImport.js, 8, 24)) + +=== overload.js === +export function noop() {} +>noop : Symbol(noop, Decl(overload.js, 0, 0)) + +/** + * Takes a string. + * @overload + * @param {string} x + * @returns {string} + */ + +/** + * @param {any} x + */ +export function l(x) { return x; } +>l : Symbol(l, Decl(overload.js, 4, 4), Decl(overload.js, 0, 25)) +>x : Symbol(x, Decl(overload.js, 12, 18)) +>x : Symbol(x, Decl(overload.js, 12, 18)) + +=== documentationTags.js === +export function noop() {} +>noop : Symbol(noop, Decl(documentationTags.js, 0, 0)) + +/** + * Prose describing S. + * @typedef {number} S + * @see noop + * @example + * const s = 1; + */ + +export function m() {} +>m : Symbol(m, Decl(documentationTags.js, 0, 25)) + +=== elidedImport.js === +export function noop() {} +>noop : Symbol(noop, Decl(elidedImport.js, 0, 0)) + +/** + * Nothing in the output uses this import. + * @import {Point} from "./typedef.js" + */ + +export function n() {} +>n : Symbol(n, Decl(elidedImport.js, 0, 25)) + diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.types b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.types new file mode 100644 index 0000000000000..94421060806af --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefCommentPlacement.types @@ -0,0 +1,222 @@ +//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsTypedefCommentPlacement.ts] //// + +=== typedef.js === +export function noop() {} +>noop : () => void + +/** + * A point in 2D space. + * @typedef {Object} Point + * @property {number} x + * @property {number} y + */ + +/** + * @param {Point} p + */ +export function dist(p) { +>dist : (p: Point) => number +>p : Point + + return p.x; +>p.x : number +>p : Point +>x : number +} + +=== callback.js === +export function noop() {} +>noop : () => void + +/** + * Compares two numbers. + * @callback Comparator + * @param {number} a + * @param {number} b + * @returns {number} + */ + +/** + * @param {number[]} arr + * @param {Comparator} cmp + */ +export function sortWith(arr, cmp) { +>sortWith : (arr: number[], cmp: Comparator) => number[] +>arr : number[] +>cmp : Comparator + + return arr.slice().sort(cmp); +>arr.slice().sort(cmp) : number[] +>arr.slice().sort : (compareFn?: ((a: number, b: number) => number) | undefined) => number[] +>arr.slice() : number[] +>arr.slice : (start?: number, end?: number) => number[] +>arr : number[] +>slice : (start?: number, end?: number) => number[] +>sort : (compareFn?: ((a: number, b: number) => number) | undefined) => number[] +>cmp : Comparator +} + +=== shared.js === +export function noop() {} +>noop : () => void + +/** + * Two aliases from one comment. + * @typedef {number} A + * @typedef {string} B + */ + +export function f() {} +>f : () => void + +=== hosted.js === +export function noop() {} +>noop : () => void + +/** + * Documents g, not N. + * @typedef {number} N + * @param {N} x + */ +export function g(x) { +>g : (x: N) => number +>x : number + + return x; +>x : number +} + +=== trailing.js === +export function noop() {} +>noop : () => void + +/** + * Nothing follows this one. + * @typedef {Object} Trailing + * @property {number} x + */ + +=== imported.js === +export function noop() {} +>noop : () => void + +/** + * Imports and defines in one comment. + * @import {Point} from "./typedef.js" + * @typedef {Point[]} Path + */ + +export function h() {} +>h : () => void + +=== preceded.js === +export function noop() {} +>noop : () => void + +// not a JSDoc comment +/** + * @typedef {number} Q + */ + +export function i() {} +>i : () => void + +=== generic.js === +export function noop() {} +>noop : () => void + +/** + * A named mixin. + * @template T + * @typedef {T & {name: string}} MixinName + */ + +/** + * Identity. + * @template T + * @callback Identity + * @param {T} x + * @returns {T} + */ + +export function j() {} +>j : () => void + +=== templateOnHost.js === +export function noop() {} +>noop : () => void + +/** + * Documents k, not a type. + * @template T + * @param {T} x + */ +export function k(x) { return x; } +>k : (x: T) => T +>x : T +>x : T + +=== standaloneImport.js === +export function noop() {} +>noop : () => void + +/** + * Brings Point into scope. + * @import {Point} from "./typedef.js" + */ + +/** @type {Point} */ +export const p = { x: 0, y: 0 }; +>p : Point +>{ x: 0, y: 0 } : { x: number; y: number; } +>x : number +>0 : 0 +>y : number +>0 : 0 + +=== overload.js === +export function noop() {} +>noop : () => void + +/** + * Takes a string. + * @overload + * @param {string} x + * @returns {string} + */ + +/** + * @param {any} x + */ +export function l(x) { return x; } +>l : (x: string) => string +>x : any +>x : any + +=== documentationTags.js === +export function noop() {} +>noop : () => void + +/** + * Prose describing S. + * @typedef {number} S + * @see noop + * @example + * const s = 1; + */ + +export function m() {} +>m : () => void + +=== elidedImport.js === +export function noop() {} +>noop : () => void + +/** + * Nothing in the output uses this import. + * @import {Point} from "./typedef.js" + */ + +export function n() {} +>n : () => void + diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefDescriptionsPreserved.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefDescriptionsPreserved.js index 2e76c81fde174..7616893d5b700 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefDescriptionsPreserved.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefDescriptionsPreserved.js @@ -53,6 +53,14 @@ type FooOptions = { */ baz: string; }; +/** + * Multiline + * Options + * for Foo <------------ + * @typedef {Object} BarOptions + * @property {boolean} bar - Marvin K Mooney + * @property {string} baz - Sylvester McMonkey McBean + */ type BarOptions = { /** * - Marvin K Mooney @@ -63,11 +71,3 @@ type BarOptions = { */ baz: string; }; -/** - * Multiline - * Options - * for Foo <------------ - * @typedef {Object} BarOptions - * @property {boolean} bar - Marvin K Mooney - * @property {string} baz - Sylvester McMonkey McBean - */ diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefPropertyAndExportAssignment.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefPropertyAndExportAssignment.js index 8999557336040..6d353f2155bb5 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefPropertyAndExportAssignment.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsTypedefPropertyAndExportAssignment.js @@ -104,7 +104,6 @@ module.exports = MainThreadTasks; //// [module.d.ts] -/** @typedef {'parseHTML'|'styleLayout'} TaskGroupIds */ declare const _exports: { taskGroups: { parseHTML: { @@ -119,7 +118,14 @@ declare const _exports: { taskNameToGroup: Record; }; export = _exports; +/** @typedef {'parseHTML'|'styleLayout'} TaskGroupIds */ export type TaskGroupIds = 'parseHTML' | 'styleLayout'; +/** + * @typedef TaskGroup + * @property {TaskGroupIds} id + * @property {string} label + * @property {string[]} traceEventNames + */ export type TaskGroup = { id: TaskGroupIds; label: string; @@ -127,23 +133,23 @@ export type TaskGroup = { }; //// [index.d.ts] export = MainThreadTasks; +/** @typedef {import('./module.js').TaskGroup} TaskGroup */ export type TaskGroup = import('./module.js').TaskGroup; +/** + * @typedef TaskNode + * @prop {TaskNode[]} children + * @prop {TaskNode|undefined} parent + * @prop {TaskGroup} group + */ export type TaskNode = { children: TaskNode[]; parent: TaskNode | undefined; group: TaskGroup; }; +/** @typedef {{timers: Map}} PriorTaskData */ export type PriorTaskData = { timers: Map; }; -/** @typedef {import('./module.js').TaskGroup} TaskGroup */ -/** - * @typedef TaskNode - * @prop {TaskNode[]} children - * @prop {TaskNode|undefined} parent - * @prop {TaskGroup} group - */ -/** @typedef {{timers: Map}} PriorTaskData */ declare class MainThreadTasks { /** * @param {TaskGroup} x diff --git a/tsc/testdata/baselines/reference/conformance/jsDeclarationsUniqueSymbolUsage.js b/tsc/testdata/baselines/reference/conformance/jsDeclarationsUniqueSymbolUsage.js index 35f951bdfd045..b3db55e388b29 100644 --- a/tsc/testdata/baselines/reference/conformance/jsDeclarationsUniqueSymbolUsage.js +++ b/tsc/testdata/baselines/reference/conformance/jsDeclarationsUniqueSymbolUsage.js @@ -20,12 +20,12 @@ export function b(value) { //// [a.d.ts] export declare const kSymbol: unique symbol; -export type WithSymbol = { - [kSymbol]: true; -}; /** * @typedef {{[kSymbol]: true}} WithSymbol */ +export type WithSymbol = { + [kSymbol]: true; +}; //// [b.d.ts] /** * @returns {import('./a').WithSymbol} diff --git a/tsc/testdata/baselines/reference/conformance/jsdocTemplateTagDefault.js b/tsc/testdata/baselines/reference/conformance/jsdocTemplateTagDefault.js index 449020ebe88d0..4ff0cb25c8ac9 100644 --- a/tsc/testdata/baselines/reference/conformance/jsdocTemplateTagDefault.js +++ b/tsc/testdata/baselines/reference/conformance/jsdocTemplateTagDefault.js @@ -138,34 +138,34 @@ type A = [T]; /** @type {A} */ declare const aDefault2: A; /** @type {A} */ declare const aString: A; /** @type {A} */ declare const aNumber: A; -type B = [T, U]; -type C = [T]; -type D = [T]; -type E = [T, U]; -type G = [T, U]; /** * @template T * @template [U=T] - ok: default can reference earlier type parameter * @typedef {[T, U]} B */ +type B = [T, U]; /** * @template {string | number} [T] - error: default requires an `=type` * @typedef {[T]} C */ +type C = [T]; /** * @template {string | number} [T=] - error: default requires a `type` * @typedef {[T]} D */ +type D = [T]; /** * @template {string | number} [T=string] * @template U - error: Required type parameters cannot follow optional type parameters * @typedef {[T, U]} E */ +type E = [T, U]; /** * @template [T=U] - error: Type parameter defaults can only reference previously declared type parameters. * @template [U=T] * @typedef {[T, U]} G */ +type G = [T, U]; /** * @template T * @template [U=T] - ok: default can reference earlier type parameter diff --git a/tsc/testdata/baselines/reference/conformance/linkTagEmit1.js b/tsc/testdata/baselines/reference/conformance/linkTagEmit1.js index b03dba9647d9e..09da3929d9913 100644 --- a/tsc/testdata/baselines/reference/conformance/linkTagEmit1.js +++ b/tsc/testdata/baselines/reference/conformance/linkTagEmit1.js @@ -49,12 +49,12 @@ var see3 = true; //// [linkTagEmit1.d.ts] /** @typedef {number} N */ +type N = number; /** * @typedef {Object} D1 * @property {1} e Just link to {@link NS.R} this time * @property {1} m Wyatt Earp loved {@link N integers} I bet. */ -type N = number; type D1 = { /** * Just link to {@link NS.R} this time @@ -65,13 +65,13 @@ type D1 = { */ m: 1; }; -type Z = number; /** @typedef {number} Z @see N {@link N} */ +type Z = number; /** * @param {number} integer {@link Z} */ declare function computeCommonSourceDirectoryOfFilenames(integer: number): number; /** {@link https://hvad} */ declare var see3: boolean; -type Attempt = number; /** @typedef {number} Attempt {@link https://wat} {@linkcode I think lingcod is better} {@linkplain or lutefisk}*/ +type Attempt = number; diff --git a/tsc/testdata/baselines/reference/conformance/recursiveTypeReferences2.js b/tsc/testdata/baselines/reference/conformance/recursiveTypeReferences2.js index cb238bde424b5..f62c131c959e5 100644 --- a/tsc/testdata/baselines/reference/conformance/recursiveTypeReferences2.js +++ b/tsc/testdata/baselines/reference/conformance/recursiveTypeReferences2.js @@ -57,24 +57,13 @@ const p = {}; //// [bug39372.d.ts] /** @typedef {ReadonlyArray} JsonArray */ -/** @typedef {{ readonly [key: string]: Json }} JsonRecord */ -/** @typedef {boolean | number | string | null | JsonRecord | JsonArray | readonly []} Json */ type JsonArray = ReadonlyArray; +/** @typedef {{ readonly [key: string]: Json }} JsonRecord */ type JsonRecord = { readonly [key: string]: Json; }; +/** @typedef {boolean | number | string | null | JsonRecord | JsonArray | readonly []} Json */ type Json = boolean | number | string | null | JsonRecord | JsonArray | readonly []; -type XMLObject = { - $A: { [K in keyof T]?: XMLObject[]; }; - $O: { [K in keyof T]?: { - $$?: Record; - } & (T[K] extends string ? { - $: string; - } : XMLObject); }; - $$?: Record; -} & { - [K in keyof T]?: (T[K] extends string ? string : XMLObject); -}; /** * @template T * @typedef {{ @@ -93,6 +82,17 @@ type XMLObject = { : XMLObject ) }} XMLObject */ +type XMLObject = { + $A: { [K in keyof T]?: XMLObject[]; }; + $O: { [K in keyof T]?: { + $$?: Record; + } & (T[K] extends string ? { + $: string; + } : XMLObject); }; + $$?: Record; +} & { + [K in keyof T]?: (T[K] extends string ? string : XMLObject); +}; /** @type {XMLObject<{foo:string}>} */ declare const p: XMLObject<{ foo: string; diff --git a/tsc/testdata/baselines/reference/conformance/templateInsideCallback.js b/tsc/testdata/baselines/reference/conformance/templateInsideCallback.js index dc6fe5579e022..06756655abeb9 100644 --- a/tsc/testdata/baselines/reference/conformance/templateInsideCallback.js +++ b/tsc/testdata/baselines/reference/conformance/templateInsideCallback.js @@ -113,28 +113,35 @@ function flatMap(array, iterable = identity) { //// [templateInsideCallback.d.ts] -type Oops = { - a: T; - b: T; -}; -type Call = (x: T) => T; /** * @typedef Oops * @template T * @property {T} a * @property {T} b */ +type Oops = { + a: T; + b: T; +}; /** * @callback Call * @template T * @param {T} x * @returns {T} */ +type Call = (x: T) => T; /** * @template T * @type {Call} */ declare const identity: Call; +/** + * @typedef Nested + * @property {Object} oh + * @property {number} oh.no + * @template T + * @property {string} oh.noooooo + */ type Nested = { oh: { no: number; diff --git a/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect1.js b/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect1.js index 835bca08c60c4..623d05d000c9e 100644 --- a/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect1.js +++ b/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect1.js @@ -24,14 +24,14 @@ var c; //// [typedefModuleExportsIndirect1.d.ts] export = dummy; +/** @typedef {{ a: 1, m: 1 }} C */ export type C = { a: 1; m: 1; }; -/** @typedef {{ a: 1, m: 1 }} C */ declare const dummy = 0; //// [use.d.ts] -type C = import('./typedefModuleExportsIndirect1').C; /** @typedef {import('./typedefModuleExportsIndirect1').C} C */ +type C = import('./typedefModuleExportsIndirect1').C; /** @type {C} */ declare var c: C; diff --git a/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect2.js b/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect2.js index 66fdb1e30a5f8..df5a8eafc88cf 100644 --- a/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect2.js +++ b/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect2.js @@ -24,14 +24,14 @@ var c; //// [typedefModuleExportsIndirect2.d.ts] export = f; +/** @typedef {{ a: 1, m: 1 }} C */ export type C = { a: 1; m: 1; }; -/** @typedef {{ a: 1, m: 1 }} C */ declare const f: () => void; //// [use.d.ts] -type C = import('./typedefModuleExportsIndirect2').C; /** @typedef {import('./typedefModuleExportsIndirect2').C} C */ +type C = import('./typedefModuleExportsIndirect2').C; /** @type {C} */ declare var c: C; diff --git a/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect3.js b/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect3.js index 5d7dae4e723b9..269952d4573dc 100644 --- a/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect3.js +++ b/tsc/testdata/baselines/reference/conformance/typedefModuleExportsIndirect3.js @@ -24,14 +24,14 @@ var c; //// [typedefModuleExportsIndirect3.d.ts] export = o; +/** @typedef {{ a: 1, m: 1 }} C */ export type C = { a: 1; m: 1; }; -/** @typedef {{ a: 1, m: 1 }} C */ declare const o: {}; //// [use.d.ts] -type C = import('./typedefModuleExportsIndirect3').C; /** @typedef {import('./typedefModuleExportsIndirect3').C} C */ +type C = import('./typedefModuleExportsIndirect3').C; /** @type {C} */ declare var c: C; diff --git a/tsc/testdata/baselines/reference/conformance/typedefOnSemicolonClassElement.js b/tsc/testdata/baselines/reference/conformance/typedefOnSemicolonClassElement.js index 5bfd2f8f0c529..22c1ed2c07fc9 100644 --- a/tsc/testdata/baselines/reference/conformance/typedefOnSemicolonClassElement.js +++ b/tsc/testdata/baselines/reference/conformance/typedefOnSemicolonClassElement.js @@ -21,6 +21,7 @@ export class Preferences { //// [typedefOnSemicolonClassElement.d.ts] +/** @typedef {string} A */ export type A = string; export declare class Preferences { /** @type {A} */ diff --git a/tsc/testdata/baselines/reference/conformance/typedefOnStatements.js b/tsc/testdata/baselines/reference/conformance/typedefOnStatements.js index 60373b4f8996f..dcf0e627fb57f 100644 --- a/tsc/testdata/baselines/reference/conformance/typedefOnStatements.js +++ b/tsc/testdata/baselines/reference/conformance/typedefOnStatements.js @@ -159,54 +159,71 @@ function proof(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) { //// [typedefOnStatements.d.ts] +/** @typedef {{a: string}} A */ type A = { a: string; }; +/** @typedef {{ b: string }} B */ type B = { b: string; }; +/** @typedef {{ c: string }} C */ type C = { c: string; }; +/** @typedef {{ d: string }} D */ type D = { d: string; }; +/** @typedef {{ e: string }} E */ type E = { e: string; }; +/** @typedef {{ f: string }} F */ type F = { f: string; }; +/** @typedef {{ g: string }} G */ type G = { g: string; }; +/** @typedef {{ h: string }} H */ type H = { h: string; }; +/** @typedef {{ i: string }} I */ type I = { i: string; }; +/** @typedef {{ j: string }} J */ type J = { j: string; }; +/** @typedef {{ k: string }} K */ type K = { k: string; }; +/** @typedef {{ l: string }} L */ type L = { l: string; }; +/** @typedef {{ m: string }} M */ type M = { m: string; }; +/** @typedef {{ n: string }} N */ type N = { n: string; }; +/** @typedef {{ o: string }} O */ type O = { o: string; }; +/** @typedef {{ p: string }} P */ type P = { p: string; }; +/** @typedef {{ q: string }} Q */ type Q = { q: string; }; diff --git a/tsc/testdata/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-and-emits-them-correctly.js b/tsc/testdata/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-and-emits-them-correctly.js index fec3153558361..d0a7161e4784e 100644 --- a/tsc/testdata/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-and-emits-them-correctly.js +++ b/tsc/testdata/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-and-emits-them-correctly.js @@ -153,12 +153,12 @@ interface Symbol { } declare const console: { log(msg: any): void; }; //// [/home/src/workspaces/lib/common/nominal.d.ts] *new* +declare const _exports: {}; +export = _exports; /** * @template T, Name * @typedef {T & {[Symbol.species]: Name}} Nominal */ -declare const _exports: {}; -export = _exports; export type Nominal = T & {}; //// [/home/src/workspaces/lib/common/nominal.js] *new* @@ -170,7 +170,7 @@ export type Nominal = T & {}; module.exports = {}; //// [/home/src/workspaces/lib/common/tsconfig.tsbuildinfo] *new* -{"version":"FakeTSVersion","root":[2],"fileNames":["lib.es2025.full.d.ts","../../solution/common/nominal.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"a19075dfba5b2d593b761ed8d8cd526f-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nmodule.exports = {};","signature":"81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n","impliedNodeFormat":1}],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"semanticDiagnosticsPerFile":[[2,[{"pos":51,"end":58,"code":2339,"category":1,"messageKey":"Property_0_does_not_exist_on_type_1_2339","messageArgs":["species","SymbolConstructor"]}]]],"latestChangedDtsFile":"./nominal.d.ts"} +{"version":"FakeTSVersion","root":[2],"fileNames":["lib.es2025.full.d.ts","../../solution/common/nominal.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"a19075dfba5b2d593b761ed8d8cd526f-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nmodule.exports = {};","signature":"77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n","impliedNodeFormat":1}],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"semanticDiagnosticsPerFile":[[2,[{"pos":51,"end":58,"code":2339,"category":1,"messageKey":"Property_0_does_not_exist_on_type_1_2339","messageArgs":["species","SymbolConstructor"]}]]],"latestChangedDtsFile":"./nominal.d.ts"} //// [/home/src/workspaces/lib/common/tsconfig.tsbuildinfo.readable.baseline.txt] *new* { "version": "FakeTSVersion", @@ -202,11 +202,11 @@ module.exports = {}; { "fileName": "../../solution/common/nominal.js", "version": "a19075dfba5b2d593b761ed8d8cd526f-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nmodule.exports = {};", - "signature": "81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n", + "signature": "77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n", "impliedNodeFormat": "CommonJS", "original": { "version": "a19075dfba5b2d593b761ed8d8cd526f-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nmodule.exports = {};", - "signature": "81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n", + "signature": "77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n", "impliedNodeFormat": 1 } } @@ -265,7 +265,7 @@ export function getVar() { } //// [/home/src/workspaces/lib/sub-project-2/tsconfig.tsbuildinfo] *new* -{"version":"FakeTSVersion","root":[4],"fileNames":["lib.es2025.full.d.ts","../common/nominal.d.ts","../sub-project/index.d.ts","../../solution/sub-project-2/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n","225285a996cc5c4120877a377890d79e-import { Nominal } from '../common/nominal';\nexport type MyNominal = Nominal;\n/**\n * @typedef {Nominal} MyNominal\n */ \n",{"version":"db2a90e082fd17d65127bda69975a727-import { MyNominal } from '../sub-project/index';\n\nconst variable = {\n key: /** @type {MyNominal} */('value'),\n};\n\n/**\n * @return {keyof typeof variable}\n */\nexport function getVar() {\n return 'key';\n}","signature":"0620ca4a9fe7036c93bd1594ffccf8eb-import { MyNominal } from '../sub-project/index';\ndeclare const variable: {\n key: MyNominal;\n};\n/**\n * @return {keyof typeof variable}\n */\nexport declare function getVar(): keyof typeof variable;\nexport {};\n","impliedNodeFormat":1}],"fileIdsList":[[2],[3]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1],[4,2]],"semanticDiagnosticsPerFile":[[4,[{"pos":9,"end":18,"code":18042,"category":1,"messageKey":"_0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation_18042","messageArgs":["MyNominal","import(\"../sub-project/index\").MyNominal"]}]]],"latestChangedDtsFile":"./index.d.ts"} +{"version":"FakeTSVersion","root":[4],"fileNames":["lib.es2025.full.d.ts","../common/nominal.d.ts","../sub-project/index.d.ts","../../solution/sub-project-2/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n","5fa17a470c0fbdd3d822f5e7ff2044b0-import { Nominal } from '../common/nominal';\n/**\n * @typedef {Nominal} MyNominal\n */ \nexport type MyNominal = Nominal;\n",{"version":"db2a90e082fd17d65127bda69975a727-import { MyNominal } from '../sub-project/index';\n\nconst variable = {\n key: /** @type {MyNominal} */('value'),\n};\n\n/**\n * @return {keyof typeof variable}\n */\nexport function getVar() {\n return 'key';\n}","signature":"0620ca4a9fe7036c93bd1594ffccf8eb-import { MyNominal } from '../sub-project/index';\ndeclare const variable: {\n key: MyNominal;\n};\n/**\n * @return {keyof typeof variable}\n */\nexport declare function getVar(): keyof typeof variable;\nexport {};\n","impliedNodeFormat":1}],"fileIdsList":[[2],[3]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1],[4,2]],"semanticDiagnosticsPerFile":[[4,[{"pos":9,"end":18,"code":18042,"category":1,"messageKey":"_0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation_18042","messageArgs":["MyNominal","import(\"../sub-project/index\").MyNominal"]}]]],"latestChangedDtsFile":"./index.d.ts"} //// [/home/src/workspaces/lib/sub-project-2/tsconfig.tsbuildinfo.readable.baseline.txt] *new* { "version": "FakeTSVersion", @@ -298,14 +298,14 @@ export function getVar() { }, { "fileName": "../common/nominal.d.ts", - "version": "81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n", - "signature": "81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n", + "version": "77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n", + "signature": "77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n", "impliedNodeFormat": "CommonJS" }, { "fileName": "../sub-project/index.d.ts", - "version": "225285a996cc5c4120877a377890d79e-import { Nominal } from '../common/nominal';\nexport type MyNominal = Nominal;\n/**\n * @typedef {Nominal} MyNominal\n */ \n", - "signature": "225285a996cc5c4120877a377890d79e-import { Nominal } from '../common/nominal';\nexport type MyNominal = Nominal;\n/**\n * @typedef {Nominal} MyNominal\n */ \n", + "version": "5fa17a470c0fbdd3d822f5e7ff2044b0-import { Nominal } from '../common/nominal';\n/**\n * @typedef {Nominal} MyNominal\n */ \nexport type MyNominal = Nominal;\n", + "signature": "5fa17a470c0fbdd3d822f5e7ff2044b0-import { Nominal } from '../common/nominal';\n/**\n * @typedef {Nominal} MyNominal\n */ \nexport type MyNominal = Nominal;\n", "impliedNodeFormat": "CommonJS" }, { @@ -368,10 +368,10 @@ export function getVar() { } //// [/home/src/workspaces/lib/sub-project/index.d.ts] *new* import { Nominal } from '../common/nominal'; -export type MyNominal = Nominal; /** * @typedef {Nominal} MyNominal */ +export type MyNominal = Nominal; //// [/home/src/workspaces/lib/sub-project/index.js] *new* import { Nominal } from '../common/nominal'; @@ -380,7 +380,7 @@ import { Nominal } from '../common/nominal'; */ //// [/home/src/workspaces/lib/sub-project/tsconfig.tsbuildinfo] *new* -{"version":"FakeTSVersion","root":[3],"fileNames":["lib.es2025.full.d.ts","../common/nominal.d.ts","../../solution/sub-project/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n",{"version":"00b7836eaf1e026f7764b7be6efcc8f5-import { Nominal } from '../common/nominal';\n\n/**\n * @typedef {Nominal} MyNominal\n */","signature":"225285a996cc5c4120877a377890d79e-import { Nominal } from '../common/nominal';\nexport type MyNominal = Nominal;\n/**\n * @typedef {Nominal} MyNominal\n */ \n","impliedNodeFormat":1}],"fileIdsList":[[2]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1]],"semanticDiagnosticsPerFile":[[3,[{"pos":9,"end":16,"code":18042,"category":1,"messageKey":"_0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation_18042","messageArgs":["Nominal","import(\"../common/nominal\").Nominal"]}]]],"latestChangedDtsFile":"./index.d.ts"} +{"version":"FakeTSVersion","root":[3],"fileNames":["lib.es2025.full.d.ts","../common/nominal.d.ts","../../solution/sub-project/index.js"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n",{"version":"00b7836eaf1e026f7764b7be6efcc8f5-import { Nominal } from '../common/nominal';\n\n/**\n * @typedef {Nominal} MyNominal\n */","signature":"5fa17a470c0fbdd3d822f5e7ff2044b0-import { Nominal } from '../common/nominal';\n/**\n * @typedef {Nominal} MyNominal\n */ \nexport type MyNominal = Nominal;\n","impliedNodeFormat":1}],"fileIdsList":[[2]],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"outDir":"..","rootDir":"../../solution","skipLibCheck":true},"referencedMap":[[3,1]],"semanticDiagnosticsPerFile":[[3,[{"pos":9,"end":16,"code":18042,"category":1,"messageKey":"_0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation_18042","messageArgs":["Nominal","import(\"../common/nominal\").Nominal"]}]]],"latestChangedDtsFile":"./index.d.ts"} //// [/home/src/workspaces/lib/sub-project/tsconfig.tsbuildinfo.readable.baseline.txt] *new* { "version": "FakeTSVersion", @@ -412,18 +412,18 @@ import { Nominal } from '../common/nominal'; }, { "fileName": "../common/nominal.d.ts", - "version": "81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n", - "signature": "81ac3a6e47fc4be420cd544e175d838d-/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\ndeclare const _exports: {};\nexport = _exports;\nexport type Nominal = T & {};\n", + "version": "77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n", + "signature": "77e32cd27288eae696416a61327db719-declare const _exports: {};\nexport = _exports;\n/**\n * @template T, Name\n * @typedef {T & {[Symbol.species]: Name}} Nominal\n */\nexport type Nominal = T & {};\n", "impliedNodeFormat": "CommonJS" }, { "fileName": "../../solution/sub-project/index.js", "version": "00b7836eaf1e026f7764b7be6efcc8f5-import { Nominal } from '../common/nominal';\n\n/**\n * @typedef {Nominal} MyNominal\n */", - "signature": "225285a996cc5c4120877a377890d79e-import { Nominal } from '../common/nominal';\nexport type MyNominal = Nominal;\n/**\n * @typedef {Nominal} MyNominal\n */ \n", + "signature": "5fa17a470c0fbdd3d822f5e7ff2044b0-import { Nominal } from '../common/nominal';\n/**\n * @typedef {Nominal} MyNominal\n */ \nexport type MyNominal = Nominal;\n", "impliedNodeFormat": "CommonJS", "original": { "version": "00b7836eaf1e026f7764b7be6efcc8f5-import { Nominal } from '../common/nominal';\n\n/**\n * @typedef {Nominal} MyNominal\n */", - "signature": "225285a996cc5c4120877a377890d79e-import { Nominal } from '../common/nominal';\nexport type MyNominal = Nominal;\n/**\n * @typedef {Nominal} MyNominal\n */ \n", + "signature": "5fa17a470c0fbdd3d822f5e7ff2044b0-import { Nominal } from '../common/nominal';\n/**\n * @typedef {Nominal} MyNominal\n */ \nexport type MyNominal = Nominal;\n", "impliedNodeFormat": 1 } } diff --git a/tsc/testdata/tests/cases/conformance/jsdoc/declarations/jsDeclarationsTypedefCommentPlacement.ts b/tsc/testdata/tests/cases/conformance/jsdoc/declarations/jsDeclarationsTypedefCommentPlacement.ts new file mode 100644 index 0000000000000..e9d394dd1363e --- /dev/null +++ b/tsc/testdata/tests/cases/conformance/jsdoc/declarations/jsDeclarationsTypedefCommentPlacement.ts @@ -0,0 +1,184 @@ +// @target: es2015 +// @allowJs: true +// @checkJs: true +// @outDir: ./out +// @declaration: true +// @filename: typedef.js + +export function noop() {} + +/** + * A point in 2D space. + * @typedef {Object} Point + * @property {number} x + * @property {number} y + */ + +/** + * @param {Point} p + */ +export function dist(p) { + return p.x; +} + +// @filename: callback.js + +export function noop() {} + +/** + * Compares two numbers. + * @callback Comparator + * @param {number} a + * @param {number} b + * @returns {number} + */ + +/** + * @param {number[]} arr + * @param {Comparator} cmp + */ +export function sortWith(arr, cmp) { + return arr.slice().sort(cmp); +} + +// @filename: shared.js + +export function noop() {} + +/** + * Two aliases from one comment. + * @typedef {number} A + * @typedef {string} B + */ + +export function f() {} + +// @filename: hosted.js + +export function noop() {} + +/** + * Documents g, not N. + * @typedef {number} N + * @param {N} x + */ +export function g(x) { + return x; +} + +// @filename: trailing.js + +export function noop() {} + +/** + * Nothing follows this one. + * @typedef {Object} Trailing + * @property {number} x + */ + +// @filename: imported.js + +export function noop() {} + +/** + * Imports and defines in one comment. + * @import {Point} from "./typedef.js" + * @typedef {Point[]} Path + */ + +export function h() {} + +// @filename: preceded.js + +export function noop() {} + +// not a JSDoc comment +/** + * @typedef {number} Q + */ + +export function i() {} + +// @filename: generic.js + +export function noop() {} + +/** + * A named mixin. + * @template T + * @typedef {T & {name: string}} MixinName + */ + +/** + * Identity. + * @template T + * @callback Identity + * @param {T} x + * @returns {T} + */ + +export function j() {} + +// @filename: templateOnHost.js + +export function noop() {} + +/** + * Documents k, not a type. + * @template T + * @param {T} x + */ +export function k(x) { return x; } + +// @filename: standaloneImport.js + +export function noop() {} + +/** + * Brings Point into scope. + * @import {Point} from "./typedef.js" + */ + +/** @type {Point} */ +export const p = { x: 0, y: 0 }; + +// @filename: overload.js + +export function noop() {} + +/** + * Takes a string. + * @overload + * @param {string} x + * @returns {string} + */ + +/** + * @param {any} x + */ +export function l(x) { return x; } + +// @filename: documentationTags.js + +export function noop() {} + +/** + * Prose describing S. + * @typedef {number} S + * @see noop + * @example + * const s = 1; + */ + +export function m() {} + +// @filename: elidedImport.js + +export function noop() {} + +/** + * Nothing in the output uses this import. + * @import {Point} from "./typedef.js" + */ + +export function n() {}