Skip to content

Commit c1bf00b

Browse files
committed
Add support for an @expand tag.
Closes #2303
1 parent 6e76611 commit c1bf00b

File tree

5 files changed

+89
-45
lines changed

5 files changed

+89
-45
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
- Removed the `hideParameterTypesInTitle` option, this was originally added as a workaround for many signatures overflowing
66
the available horizontal space in rendered pages. TypeDoc now has logic to wrap types/signatures smartly, so this option is
77
no longer necessary.
8+
- Add support for an `@expand` tag which can be placed on type aliases and interfaces.
9+
When a type with `@expand` is referenced and TypeDoc has a place to include additional details about the type,
10+
the properties of the type will be included in the page where `@expand` is found. Note that use of this tag can
11+
_significantly_ increase the size of your generated documentation if it is applied to commonly used types as
12+
it will result in inlining the comments for those types everywhere they are referenced, #2303.
13+
14+
TODO:
15+
16+
- Add an option for controlling print width.
17+
- Add an option for non-rendered tags, add `@expand` to it by default.
18+
- Finish cleaning up formatter TODO comments, tests
19+
- Write docs for `@expand`
820

921
# Unreleased
1022

src/lib/models/comments/comment.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,18 @@ export type CommentDisplayPart =
2424
* that TypeDoc knows to skip it when parsing relative links and inline tags.
2525
**/
2626
| { kind: "code"; text: string }
27-
/**
28-
* Represents an inline tag like `{@link Foo}`
29-
*/
3027
| InlineTagDisplayPart
31-
/**
32-
* Represents a reference to a path relative to where the comment resides.
33-
* This is used to detect and copy relative image links.
34-
* Use {@link FileRegistry} to determine what path on disc this refers to.
35-
*/
3628
| RelativeLinkDisplayPart;
3729

3830
/**
31+
* Represents an inline tag like `{@link Foo}`
32+
*
3933
* The `@link`, `@linkcode`, and `@linkplain` tags may have a `target`
4034
* property set indicating which reflection/url they link to. They may also
4135
* have a `tsLinkText` property which includes the part of the `text` which
4236
* TypeScript thinks should be displayed as the link text.
4337
* @category Comments
38+
* @expand
4439
*/
4540
export interface InlineTagDisplayPart {
4641
kind: "inline-tag";
@@ -51,9 +46,16 @@ export interface InlineTagDisplayPart {
5146
}
5247

5348
/**
49+
* Represents a reference to a path relative to where the comment resides.
50+
* This is used to detect and copy relative image links.
51+
*
52+
* Use {@link FileRegistry} to determine what path on disc this refers to.
53+
*
5454
* This is used for relative links within comments/documents.
5555
* It is used to mark pieces of text which need to be replaced
5656
* to make links work properly.
57+
* @category Comments
58+
* @expand
5759
*/
5860
export interface RelativeLinkDisplayPart {
5961
kind: "relative-link";

src/lib/output/themes/default/partials/typeDetails.tsx

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
import type { DeclarationReflection, SignatureReflection } from "../../../../models/index.js";
2-
import type { SomeType, TypeVisitor } from "../../../../models/types.js";
1+
import {
2+
type Reflection,
3+
ReflectionKind,
4+
type DeclarationReflection,
5+
type SignatureReflection,
6+
} from "../../../../models/index.js";
7+
import type { ReferenceType, SomeType, TypeVisitor } from "../../../../models/types.js";
38
import { JSX, Raw } from "../../../../utils/index.js";
49
import { classNames, getKindClass } from "../../lib.js";
510
import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext.js";
@@ -17,6 +22,9 @@ const isUsefulVisitor: Partial<TypeVisitor<boolean>> = {
1722
reflection(type) {
1823
return renderingChildIsUseful(type.declaration);
1924
},
25+
reference(type) {
26+
return shouldExpandReference(type);
27+
},
2028
};
2129

2230
function renderingTypeDetailsIsUseful(type: SomeType) {
@@ -35,6 +43,15 @@ export function typeDeclaration(context: DefaultThemeRenderContext, type: SomeTy
3543
return null;
3644
}
3745

46+
const expanded = new Set<Reflection>();
47+
function shouldExpandReference(reference: ReferenceType) {
48+
const target = reference.reflection;
49+
if (!target?.kindOf(ReflectionKind.TypeAlias | ReflectionKind.Interface)) return false;
50+
if (!target.comment?.hasModifier("@expand")) return false;
51+
52+
return expanded.has(target) === false;
53+
}
54+
3855
export function typeDetails(context: DefaultThemeRenderContext, type: SomeType): JSX.Children {
3956
return type.visit<JSX.Children>({
4057
array(type) {
@@ -58,42 +75,18 @@ export function typeDetails(context: DefaultThemeRenderContext, type: SomeType):
5875
},
5976
reflection(type) {
6077
const declaration = type.declaration;
61-
62-
return (
63-
<ul class="tsd-parameters">
64-
{declaration.signatures && (
65-
<li class="tsd-parameter-signature">
66-
<ul
67-
class={classNames(
68-
{ "tsd-signatures": true },
69-
context.getReflectionClasses(declaration),
70-
)}
71-
>
72-
{declaration.signatures.map((item) => (
73-
<>
74-
<li class="tsd-signature" id={item.anchor}>
75-
{context.memberSignatureTitle(item, {
76-
hideName: true,
77-
})}
78-
</li>
79-
<li class="tsd-description">
80-
{context.memberSignatureBody(item, {
81-
hideSources: true,
82-
})}
83-
</li>
84-
</>
85-
))}
86-
</ul>
87-
</li>
88-
)}
89-
{declaration.indexSignatures?.map((index) => renderIndexSignature(context, index))}
90-
{declaration.children?.map((child) => renderChild(context, child))}
91-
</ul>
92-
);
78+
return declarationDetails(context, declaration);
9379
},
94-
reference() {
95-
// TODO: Check for @expand
96-
return null;
80+
reference(reference) {
81+
if (shouldExpandReference(reference)) {
82+
const target = reference.reflection as DeclarationReflection;
83+
84+
// Ensure we don't go into an infinite loop here
85+
expanded.add(target);
86+
const details = target.type ? typeDetails(context, target.type) : declarationDetails(context, target);
87+
expanded.delete(target);
88+
return details;
89+
}
9790
},
9891
// tuple??
9992
});
@@ -105,6 +98,38 @@ export function typeDetailsIfUseful(context: DefaultThemeRenderContext, type: So
10598
}
10699
}
107100

101+
function declarationDetails(context: DefaultThemeRenderContext, declaration: DeclarationReflection): JSX.Children {
102+
return (
103+
<>
104+
{context.commentSummary(declaration)}
105+
<ul class="tsd-parameters">
106+
{declaration.signatures && (
107+
<li class="tsd-parameter-signature">
108+
<ul class={classNames({ "tsd-signatures": true }, context.getReflectionClasses(declaration))}>
109+
{declaration.signatures.map((item) => (
110+
<>
111+
<li class="tsd-signature" id={item.anchor}>
112+
{context.memberSignatureTitle(item, {
113+
hideName: true,
114+
})}
115+
</li>
116+
<li class="tsd-description">
117+
{context.memberSignatureBody(item, {
118+
hideSources: true,
119+
})}
120+
</li>
121+
</>
122+
))}
123+
</ul>
124+
</li>
125+
)}
126+
{declaration.indexSignatures?.map((index) => renderIndexSignature(context, index))}
127+
{declaration.children?.map((child) => renderChild(context, child))}
128+
</ul>
129+
</>
130+
);
131+
}
132+
108133
function renderChild(context: DefaultThemeRenderContext, child: DeclarationReflection) {
109134
if (child.signatures) {
110135
return (

src/lib/utils/options/tsdoc-defaults.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export const modifierTags = [
6464
"@class",
6565
"@enum",
6666
"@event",
67+
"@expand",
6768
"@hidden",
6869
"@hideCategories",
6970
"@hideconstructor",

tsdoc.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@
8888
"tagName": "@event",
8989
"syntaxKind": "modifier"
9090
},
91+
{
92+
"tagName": "@expand",
93+
"syntaxKind": "modifier"
94+
},
9195
{
9296
"tagName": "@template",
9397
"syntaxKind": "block",

0 commit comments

Comments
 (0)