Skip to content

Commit ca94f7e

Browse files
committed
Include TOC & index on object type aliases
Resolves #2817
1 parent 503bc98 commit ca94f7e

File tree

24 files changed

+401
-192
lines changed

24 files changed

+401
-192
lines changed

.config/typedoc.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,8 @@
7676
"@types/markdown-it": {
7777
"MarkdownIt": "https://markdown-it.github.io/markdown-it/#MarkdownIt"
7878
}
79-
}
79+
},
80+
81+
// Saves a couple seconds when generating docs
82+
"skipErrorChecking": true
8083
}

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ title: Changelog
1616
- Function-like variable exports will now only be automatically converted as function types if
1717
they are initialized with a function expression. TypeDoc can be instructed to convert them as functions
1818
with the `@function` tag, #2881.
19+
- Object literal type alias types will now be converted in a way which causes them to be rendered more similarly
20+
to how interfaces are rendered, #2817.
1921

2022
### API Breaking Changes
2123

src/lib/converter/plugins/MergeModuleWithPlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ export class MergeModuleWithPlugin extends ConverterComponent {
7272
this.application.logger.verbose(
7373
`Merging ${refl.getFullName()} into ${target.getFullName()}`,
7474
);
75-
project.mergeModules(refl, target);
75+
project.mergeReflections(refl, target);
7676
}
7777
}

src/lib/converter/symbols.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,10 @@ export function convertSymbol(
186186
): void {
187187
// #1795, defer conversion of symbols named `default` so that if a function
188188
// is default exported and also exported with a name, the name takes precedence
189-
if ((exportSymbol?.name ?? symbol.name) === "default") {
189+
if (
190+
(exportSymbol?.name ?? symbol.name) === "default" &&
191+
context.scope.kindOf(ReflectionKind.ExportContainer)
192+
) {
190193
context.converter.deferConversion(() => {
191194
_convertSymbolNow(context, symbol, exportSymbol);
192195
});
@@ -357,6 +360,7 @@ function convertTypeAlias(
357360
symbol,
358361
exportSymbol,
359362
);
363+
context.finalizeDeclarationReflection(reflection);
360364

361365
if (reflection.comment?.hasModifier("@useDeclaredType")) {
362366
reflection.comment.removeModifier("@useDeclaredType");
@@ -373,12 +377,19 @@ function convertTypeAlias(
373377

374378
if (reflection.type.type === "union") {
375379
attachUnionComments(context, declaration, reflection.type);
380+
} else if (reflection.type.type === "reflection" && reflection.type.declaration.children) {
381+
// #2817 lift properties of object literal types up to the reflection level.
382+
const typeDecl = reflection.type.declaration;
383+
reflection.project.mergeReflections(typeDecl, reflection);
384+
delete reflection.type;
385+
386+
// When created any signatures will be created with __type as their
387+
// name, rename them so that they have the alias's name as their name
388+
for (const sig of reflection.signatures || []) {
389+
sig.name = reflection.name;
390+
}
376391
}
377392

378-
context.finalizeDeclarationReflection(reflection);
379-
380-
// Do this after finalization so that the CommentPlugin can get @typeParam tags
381-
// from the parent comment. Ugly, but works for now. Should be cleaned up eventually.
382393
reflection.typeParameters = declaration.typeParameters?.map((param) =>
383394
createTypeParamReflection(param, context.withScope(reflection))
384395
);

src/lib/models/ContainerReflection.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Reflection, type TraverseCallback, TraverseProperty } from "./Reflection.js";
22
import { ReflectionCategory } from "./ReflectionCategory.js";
33
import { ReflectionGroup } from "./ReflectionGroup.js";
4-
import type { ReflectionKind } from "./kind.js";
4+
import { ReflectionKind } from "./kind.js";
55
import type { Deserializer, JSONOutput, Serializer } from "#serialization";
66
import type { DocumentReflection } from "./DocumentReflection.js";
77
import type { DeclarationReflection } from "./DeclarationReflection.js";
8-
import { removeIfPresent } from "#utils";
8+
import { assertNever, removeIfPresent } from "#utils";
99

1010
/**
1111
* @category Reflections
@@ -59,17 +59,39 @@ export abstract class ContainerReflection extends Reflection {
5959
return (this.children || []).filter((child) => child.kindOf(kind));
6060
}
6161

62-
addChild(child: DeclarationReflection | DocumentReflection) {
62+
addChild(child: Reflection) {
6363
if (child.isDeclaration()) {
6464
this.children ||= [];
6565
this.children.push(child);
66-
} else {
66+
67+
this.childrenIncludingDocuments ||= [];
68+
this.childrenIncludingDocuments.push(child);
69+
} else if (child.isDocument()) {
6770
this.documents ||= [];
6871
this.documents.push(child);
69-
}
7072

71-
this.childrenIncludingDocuments ||= [];
72-
this.childrenIncludingDocuments.push(child);
73+
this.childrenIncludingDocuments ||= [];
74+
this.childrenIncludingDocuments.push(child);
75+
} else if (this.isDeclaration() && child.isSignature()) {
76+
switch (child.kind) {
77+
case ReflectionKind.CallSignature:
78+
case ReflectionKind.ConstructorSignature:
79+
this.signatures ||= [];
80+
this.signatures.push(child);
81+
break;
82+
case ReflectionKind.IndexSignature:
83+
this.indexSignatures ||= [];
84+
this.indexSignatures.push(child);
85+
break;
86+
case ReflectionKind.GetSignature:
87+
case ReflectionKind.SetSignature:
88+
throw new Error("Unsupported child type: " + ReflectionKind[child.kind]);
89+
default:
90+
assertNever(child.kind);
91+
}
92+
} else {
93+
throw new Error("Unsupported child type: " + ReflectionKind[child.kind]);
94+
}
7395
}
7496

7597
removeChild(child: DeclarationReflection | DocumentReflection) {

src/lib/models/ProjectReflection.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ export class ProjectReflection extends ContainerReflection {
223223
}
224224

225225
/** @internal */
226-
mergeModules(
226+
mergeReflections(
227227
source: DeclarationReflection,
228228
target: DeclarationReflection | ProjectReflection,
229229
) {
@@ -234,9 +234,7 @@ export class ProjectReflection extends ContainerReflection {
234234
const newChildren = this.reflectionChildren.get(target.id);
235235

236236
for (const childId of oldChildrenIds) {
237-
const childRefl = this.getReflectionById(childId) as
238-
| DocumentReflection
239-
| DeclarationReflection;
237+
const childRefl = this.getReflectionById(childId);
240238

241239
// To avoid conflicting with some plugins which do this surgery somewhat incorrectly
242240
// (typedoc-plugin-merge-modules and likely others I'm not aware of) only move children

src/lib/output/formatter.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,19 @@ export class FormattedCodeBuilder {
836836
return simpleElement(<span class="tsd-signature-symbol">{"{}"}</span>);
837837
}
838838

839+
typeAlias(item: DeclarationReflection) {
840+
return nodes(
841+
simpleElement(<span class="tsd-signature-keyword">type</span>),
842+
space(),
843+
simpleElement(<span class={getKindClass(item)}>{item.name}</span>),
844+
this.typeParameters(item),
845+
space(),
846+
simpleElement(<span class="tsd-signature-symbol">{"="}</span>),
847+
space(),
848+
this.reflection(item, { topLevelLinks: true }),
849+
);
850+
}
851+
839852
interface(item: DeclarationReflection) {
840853
return nodes(
841854
simpleElement(<span class="tsd-signature-keyword">interface</span>),

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,14 @@ export function reflectionPreview(context: DefaultThemeRenderContext, props: Ref
1818

1919
return <div class="tsd-signature">{generator.toElement()}</div>;
2020
}
21+
22+
if (props.kindOf(ReflectionKind.TypeAlias) && props.children) {
23+
const builder = new FormattedCodeBuilder(context.router, context.model);
24+
const tree = builder.typeAlias(props);
25+
const generator = new FormattedCodeGenerator(context.options.getValue("typePrintWidth"));
26+
generator.forceWrap(builder.forceWrap); // Ensure elements are added to new lines.
27+
generator.node(tree, Wrap.Enable);
28+
29+
return <div class="tsd-signature">{generator.toElement()}</div>;
30+
}
2131
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,7 @@ function renderIndexSignature(context: DefaultThemeRenderContext, index: Signatu
323323
{context.type(item.type)}
324324
</>
325325
))}
326-
<span class="tsd-signature-symbol">{"]: "}</span>
327-
{context.type(index.type)}
326+
<span class="tsd-signature-symbol">]:</span> {context.type(index.type)}
328327
</h5>
329328
{context.commentSummary(index)}
330329
{context.commentTags(index)}

src/lib/output/themes/default/templates/reflection.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import { i18n, JSX } from "#utils";
1212
export function reflectionTemplate(context: DefaultThemeRenderContext, props: PageEvent<ContainerReflection>) {
1313
if (
1414
props.model.kindOf(ReflectionKind.TypeAlias | ReflectionKind.Variable) &&
15-
props.model instanceof DeclarationReflection
15+
props.model instanceof DeclarationReflection &&
16+
props.model.type
1617
) {
1718
return context.memberDeclaration(props.model);
1819
}
@@ -87,8 +88,7 @@ function renderIndexSignature(context: DefaultThemeRenderContext, index: Signatu
8788
<span class={getKindClass(item)}>{item.name}</span>: {context.type(item.type)}
8889
</>
8990
))}
90-
<span class="tsd-signature-symbol">]:</span>
91-
{context.type(index.type)}
91+
<span class="tsd-signature-symbol">]:</span> {context.type(index.type)}
9292
</div>
9393
{context.commentSummary(index)}
9494
{context.commentTags(index)}

src/test/behavior.c2.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { filterMap } from "#utils";
1212
import { CommentStyle } from "../lib/utils/options/declaration.js";
1313
import { TestLogger } from "./TestLogger.js";
14-
import { getComment, getSigComment, query, querySig } from "./utils.js";
14+
import { getComment, getSigComment, query, querySig, reflToTree } from "./utils.js";
1515
import { getConverter2App, getConverter2Project } from "./programs.js";
1616

1717
type NameTree = { [name: string]: NameTree | undefined };
@@ -1402,4 +1402,19 @@ describe("Behavior Tests", () => {
14021402
// Previously, would find TypeDoc's root readme
14031403
equal(project.readme, undefined);
14041404
});
1405+
1406+
it("Supports @document tags", () => {
1407+
const project = convert("documentTag");
1408+
1409+
equal(reflToTree(project), {
1410+
HasDescriptor: "Interface",
1411+
});
1412+
1413+
const refl = query(project, "HasDescriptor");
1414+
equal(refl.documents?.length, 1);
1415+
1416+
equal(refl.documents[0].content, [
1417+
{ kind: "text", text: "External doc!" },
1418+
]);
1419+
});
14051420
});

src/test/converter.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ import {
1414
ReflectionGroup,
1515
resetReflectionID,
1616
Serializer,
17+
type SomeReflection,
1718
SourceReference,
1819
} from "../index.js";
19-
import type { ModelToObject, SomeReflection } from "../lib/serialization/schema.js";
20+
import type { ModelToObject } from "../lib/serialization/schema.js";
2021
import { getExpandedEntryPointsForPaths, normalizePath } from "../lib/utils/index.js";
2122
import { getConverterApp, getConverterBase, getConverterProgram } from "./programs.js";
2223
import { FileRegistry } from "../lib/models/FileRegistry.js";
@@ -76,8 +77,11 @@ comparisonSerializer.addSerializer<SomeReflection>({
7677
supports(x) {
7778
return x instanceof Reflection;
7879
},
79-
toObject(_refl, obj) {
80+
toObject(refl, obj: any) {
8081
delete obj["id"];
82+
if (refl.isDeclaration()) {
83+
obj["childrenIncludingDocuments"] = refl.childrenIncludingDocuments?.map(id => id.getFullName());
84+
}
8185
return obj;
8286
},
8387
});

src/test/converter/comment/comment.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/**
2-
* This is a module doc comment with legacy behavior.
2+
* Module doc comment with document.
3+
*
4+
* @document document.md
5+
* @packageDocumentation
36
*/
4-
/** dummy comment */
57
import "./comment2";
68

79
/**
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
External doc included with `@document` tag!

0 commit comments

Comments
 (0)