Skip to content

Commit 872853f

Browse files
JeanMecheleonsenft
authored andcommitted
docs(docs-infra): Show function args
With this change non-overloaded functions also show the params + return type in a dedicated block.
1 parent b7255f9 commit 872853f

10 files changed

Lines changed: 98 additions & 54 deletions

File tree

adev/shared-docs/pipeline/api-gen/rendering/entities/renderables.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
ParameterEntry,
2222
PipeEntry,
2323
TypeAliasEntry,
24-
EntryType,
2524
} from '../entities.mjs';
2625

2726
import {CliCommand, CliOption} from '../cli-entities.mjs';
@@ -105,6 +104,7 @@ export type FunctionEntryRenderable = FunctionEntry &
105104
export type FunctionSignatureMetadataRenderable = FunctionSignatureMetadata &
106105
DocEntryRenderable & {
107106
params: ParameterEntryRenderable[];
107+
htmlReturnDescription?: string;
108108
};
109109

110110
/** Documentation entity for a block augmented with transformed content for rendering. */

adev/shared-docs/pipeline/api-gen/rendering/templates/class-method-info.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,17 @@ import {RawHtml} from './raw-html';
2323
export function ClassMethodInfo(props: {
2424
entry: FunctionSignatureMetadataRenderable;
2525
hideUsageNotes?: boolean;
26+
hideDescription?: boolean;
2627
}) {
2728
const entry = props.entry;
2829

2930
return (
3031
<div
3132
className={`${REFERENCE_MEMBER_CARD_ITEM} ${entry.deprecated ? 'docs-reference-card-item-deprecated' : ''}`}
3233
>
33-
<RawHtml value={entry.htmlDescription} className={'docs-function-definition'} />
34+
{!props.hideDescription && (
35+
<RawHtml value={entry.htmlDescription} className={'docs-function-definition'} />
36+
)}
3437
{/* In case when method is overloaded we need to indicate which overload is deprecated */}
3538
{entry.deprecated ? (
3639
<div>
@@ -45,6 +48,9 @@ export function ClassMethodInfo(props: {
4548
<div className={'docs-return-type'}>
4649
<span className={PARAM_KEYWORD_CLASS_NAME}>@returns</span>
4750
<CodeSymbol code={entry.returnType} />
51+
{entry.htmlReturnDescription && (
52+
<RawHtml value={entry.htmlReturnDescription} className="docs-parameter-description" />
53+
)}
4854
</div>
4955
{entry.htmlUsageNotes && !props.hideUsageNotes ? (
5056
<div className={'docs-usage-notes'}>

adev/shared-docs/pipeline/api-gen/rendering/templates/function-reference.tsx

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,55 +32,68 @@ import {SectionUsageNotes} from './section-usage-notes';
3232
export const signatureCard = (
3333
name: string,
3434
signature: FunctionSignatureMetadataRenderable,
35-
opts: {id: string; printSignaturesAsHeader: boolean; hideUsageNotes?: boolean},
35+
opts: {
36+
id: string;
37+
printSignaturesAsHeader: boolean;
38+
hideUsageNotes?: boolean;
39+
hideHeader?: boolean;
40+
hideDescription?: boolean;
41+
},
3642
) => {
3743
return (
3844
<div id={opts.id} class={REFERENCE_MEMBER_CARD}>
39-
<header class={REFERENCE_MEMBER_CARD_HEADER}>
40-
{opts.printSignaturesAsHeader ? (
41-
<HighlightTypeScript
42-
code={printInitializerFunctionSignatureLine(
43-
name,
44-
signature,
45-
// Always omit types in signature headers, to keep them short.
46-
true,
47-
)}
48-
/>
49-
) : (
50-
<>
51-
<h3>{name}</h3>
52-
<div>
53-
<CodeSymbol code={signature.returnType} />
54-
</div>
55-
</>
56-
)}
57-
</header>
45+
{!opts.hideHeader && (
46+
<header class={REFERENCE_MEMBER_CARD_HEADER}>
47+
{opts.printSignaturesAsHeader ? (
48+
<HighlightTypeScript
49+
code={printInitializerFunctionSignatureLine(
50+
name,
51+
signature,
52+
// Always omit types in signature headers, to keep them short.
53+
true,
54+
)}
55+
/>
56+
) : (
57+
<>
58+
<h3>{name}</h3>
59+
<div>
60+
<CodeSymbol code={signature.returnType} />
61+
</div>
62+
</>
63+
)}
64+
</header>
65+
)}
5866
<div class={REFERENCE_MEMBER_CARD_BODY}>
59-
<ClassMethodInfo entry={signature} hideUsageNotes={opts.hideUsageNotes} />
67+
<ClassMethodInfo
68+
entry={signature}
69+
hideUsageNotes={opts.hideUsageNotes}
70+
hideDescription={opts.hideDescription}
71+
/>
6072
</div>
6173
</div>
6274
);
6375
};
6476

6577
/** Component to render a function API reference document. */
6678
export function FunctionReference(entry: FunctionEntryRenderable) {
67-
// Use signatures as header if there are multiple signatures.
6879
const printSignaturesAsHeader = entry.signatures.length > 1;
80+
const hideSignatureCardDescription = !printSignaturesAsHeader;
6981

7082
return (
7183
<div className={API_REFERENCE_CONTAINER}>
7284
<HeaderApi entry={entry} />
7385
<DeprecationWarning entry={entry} />
7486
<SectionApi entry={entry} />
7587
<div className={REFERENCE_MEMBERS}>
76-
{entry.signatures.length > 1 &&
77-
entry.signatures.map((s, i) =>
78-
signatureCard(s.name, getFunctionMetadataRenderable(s, entry.moduleName, entry.repo), {
79-
id: `${s.name}_${i}`,
80-
printSignaturesAsHeader,
81-
hideUsageNotes: true,
82-
}),
83-
)}
88+
{entry.signatures.map((s, i) =>
89+
signatureCard(s.name, getFunctionMetadataRenderable(s, entry.moduleName, entry.repo), {
90+
id: `${s.name}_${i}`,
91+
printSignaturesAsHeader,
92+
hideHeader: !printSignaturesAsHeader,
93+
hideUsageNotes: hideSignatureCardDescription,
94+
hideDescription: hideSignatureCardDescription,
95+
}),
96+
)}
8497
</div>
8598

8699
<SectionDescription entry={entry} />

adev/shared-docs/pipeline/api-gen/rendering/templates/parameter.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
import {h} from 'preact';
1010
import {ParameterEntryRenderable} from '../entities/renderables.mjs';
11-
import {RawHtml} from './raw-html';
1211
import {PARAM_GROUP_CLASS_NAME} from '../styling/css-classes.mjs';
1312
import {CodeSymbol} from './code-symbols';
13+
import {RawHtml} from './raw-html';
1414

1515
/** Component to render a function or method parameter reference doc fragment. */
1616
export function Parameter(props: {param: ParameterEntryRenderable}) {
@@ -21,7 +21,9 @@ export function Parameter(props: {param: ParameterEntryRenderable}) {
2121
{/*TODO: isOptional, isRestParam*/}
2222
<span class="docs-param-keyword">@param</span>
2323
<span class="docs-param-name">{param.name}</span>
24-
<CodeSymbol code={param.type} />
24+
<span class="docs-param-type">
25+
<CodeSymbol code={param.type} />
26+
</span>
2527
<RawHtml value={param.htmlDescription} className="docs-parameter-description" />
2628
</div>
2729
);

adev/shared-docs/pipeline/api-gen/rendering/test/fake-entries.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@
463463
"isRestParam": false
464464
}
465465
],
466+
"returnDescription": "A reference that can be used to unregister callbacks registered by this call.",
466467
"rawComment": "/**\n * Register callbacks to be invoked the next time the application finishes rendering, during the\n * specified phases. The available phases are:\n * - `earlyRead`\n * Use this phase to **read** from the DOM before a subsequent `write` callback, for example to\n * perform custom layout that the browser doesn't natively support. Prefer the `read` phase if\n * reading can wait until after the write phase. **Never** write to the DOM in this phase.\n * - `write`\n * Use this phase to **write** to the DOM. **Never** read from the DOM in this phase.\n * - `mixedReadWrite`\n * Use this phase to read from and write to the DOM simultaneously. **Never** use this phase if\n * it is possible to divide the work among the other phases instead.\n * - `read`\n * Use this phase to **read** from the DOM. **Never** write to the DOM in this phase.\n *\n * <div class=\"docs-alert docs-alert-critical\">\n *\n * You should prefer using the `read` and `write` phases over the `earlyRead` and `mixedReadWrite`\n * phases when possible, to avoid performance degradation.\n *\n * </div>\n *\n * Note that:\n * - Callbacks run in the following phase order *once, after the next render*:\n * 1. `earlyRead`\n * 2. `write`\n * 3. `mixedReadWrite`\n * 4. `read`\n * - Callbacks in the same phase run in the order they are registered.\n * - Callbacks run on browser platforms only, they will not run on the server.\n *\n * The first phase callback to run as part of this spec will receive no parameters. Each\n * subsequent phase callback in this spec will receive the return value of the previously run\n * phase callback as a parameter. This can be used to coordinate work across multiple phases.\n *\n * Angular is unable to verify or enforce that phases are used correctly, and instead\n * relies on each developer to follow the guidelines documented for each value and\n * carefully choose the appropriate one, refactoring their code if necessary. By doing\n * so, Angular is better able to minimize the performance degradation associated with\n * manual DOM access, ensuring the best experience for the end users of your application\n * or library.\n *\n * <div class=\"docs-alert docs-alert-important\">\n *\n * Components are not guaranteed to be [hydrated](guide/hydration) before the callback runs.\n * You must use caution when directly reading or writing the DOM and layout.\n *\n * </div>\n *\n * @param spec The callback functions to register\n * @param options Options to control the behavior of the callback\n *\n * @usageNotes\n *\n * Use `afterNextRender` to read or write the DOM once,\n * for example to initialize a non-Angular library.\n *\n * ### Example\n * ```angular-ts\n * @Component({\n * selector: 'my-chart-cmp',\n * template: `<div #chart>{{ ... }}</div>`,\n * })\n * export class MyChartCmp {\n * @ViewChild('chart') chartRef: ElementRef;\n * chart: MyChart|null;\n *\n * constructor() {\n * afterNextRender({\n * write: () => {\n * this.chart = new MyChart(this.chartRef.nativeElement);\n * }\n * });\n * }\n * }\n * ```\n *\n * @developerPreview\n */",
467468
"returnType": "AfterRenderRef"
468469
},
@@ -497,6 +498,7 @@
497498
"isRestParam": false
498499
}
499500
],
501+
"returnDescription": "A reference that can be used to unregister the callback registered by this call.",
500502
"rawComment": "/**\n * Register a callback to be invoked the next time the application finishes rendering, during the\n * `mixedReadWrite` phase.\n *\n * <div class=\"docs-alert docs-alert-critical\">\n *\n * You should prefer specifying an explicit phase for the callback instead, or you risk significant\n * performance degradation.\n *\n * </div>\n *\n * Note that the callback will run\n * - in the order it was registered\n * - on browser platforms only\n * - during the `mixedReadWrite` phase\n *\n * <div class=\"docs-alert docs-alert-important\">\n *\n * Components are not guaranteed to be [hydrated](guide/hydration) before the callback runs.\n * You must use caution when directly reading or writing the DOM and layout.\n *\n * </div>\n *\n * @param callback A callback function to register\n * @param options Options to control the behavior of the callback\n *\n * @usageNotes\n *\n * Use `afterNextRender` to read or write the DOM once,\n * for example to initialize a non-Angular library.\n *\n * ### Example\n * ```angular-ts\n * @Component({\n * selector: 'my-chart-cmp',\n * template: `<div #chart>{{ ... }}</div>`,\n * })\n * export class MyChartCmp {\n * @ViewChild('chart') chartRef: ElementRef;\n * chart: MyChart|null;\n *\n * constructor() {\n * afterNextRender({\n * write: () => {\n * this.chart = new MyChart(this.chartRef.nativeElement);\n * }\n * });\n * }\n * }\n * ```\n *\n * @publicApi 20.0\n */",
501503
"returnType": "AfterRenderRef"
502504
}

adev/shared-docs/pipeline/api-gen/rendering/transforms/function-transforms.mts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
setEntryFlags,
2121
} from './jsdoc-transforms.mjs';
2222
import {addModuleName} from './module-name.mjs';
23-
import {addRenderableFunctionParams} from './params-transforms.mjs';
23+
import {addHtmlReturnDescription, addRenderableFunctionParams} from './params-transforms.mjs';
2424
import {addRepo} from './repo.mjs';
2525

2626
/** Given an unprocessed function entry, get the fully renderable function entry. */
@@ -50,11 +50,13 @@ export function getFunctionMetadataRenderable(
5050
repo: string,
5151
): FunctionSignatureMetadataRenderable {
5252
return addHtmlAdditionalLinks(
53-
addRenderableFunctionParams(
54-
addHtmlUsageNotes(
55-
setEntryFlags(
56-
addHtmlJsDocTagComments(
57-
addHtmlDescription(addRepo(addModuleName(entry, moduleName), repo)),
53+
addHtmlReturnDescription(
54+
addRenderableFunctionParams(
55+
addHtmlUsageNotes(
56+
setEntryFlags(
57+
addHtmlJsDocTagComments(
58+
addHtmlDescription(addRepo(addModuleName(entry, moduleName), repo)),
59+
),
5860
),
5961
),
6062
),

adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export function addHtmlUsageNotes<T extends HasJsDocTags>(entry: T): T & HasHtml
112112
}
113113

114114
/** Given a markdown JsDoc text, gets the rendered HTML. */
115-
function getHtmlForJsDocText(text: string): string {
115+
export function getHtmlForJsDocText(text: string): string {
116116
const mdToParse = convertLinks(wrapExampleHtmlElementsWithCode(text));
117117
const parsed = parseMarkdown(mdToParse, {
118118
apiEntries: getSymbolsAsApiEntries(),

adev/shared-docs/pipeline/api-gen/rendering/transforms/params-transforms.mts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {HasModuleName, HasParams, HasRenderableParams} from '../entities/traits.mjs';
10-
import {addHtmlDescription} from './jsdoc-transforms.mjs';
10+
import {addHtmlDescription, getHtmlForJsDocText} from './jsdoc-transforms.mjs';
1111
import {addModuleName} from './module-name.mjs';
1212

1313
export function addRenderableFunctionParams<T extends HasParams & HasModuleName>(
@@ -22,3 +22,13 @@ export function addRenderableFunctionParams<T extends HasParams & HasModuleName>
2222
params,
2323
};
2424
}
25+
26+
/** Converts `returnDescription` to `htmlReturnDescription` for rendering. */
27+
export function addHtmlReturnDescription<
28+
T extends {returnDescription?: string; moduleName: string},
29+
>(entry: T): T & {htmlReturnDescription?: string} {
30+
const htmlReturnDescription = entry.returnDescription
31+
? getHtmlForJsDocText(entry.returnDescription)
32+
: undefined;
33+
return {...entry, htmlReturnDescription};
34+
}

adev/shared-docs/styles/_reference.scss

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@
340340
}
341341
}
342342

343+
.docs-param-type {
344+
display: inline-block;
345+
margin-inline-end: 0.5rem;
346+
}
347+
343348
.docs-parameter-description {
344349
p:first-child {
345350
margin-block-start: 0;
@@ -357,7 +362,7 @@
357362
padding-block: 1rem;
358363

359364
// & does not follow a function definition
360-
&:not(.docs-function-definition + .docs-return-type) {
365+
&:not(.docs-function-definition + .docs-return-type):not(:first-child) {
361366
border-block-start: 1px solid var(--senary-contrast);
362367
}
363368
}

packages/compiler-cli/src/ngtsc/docs/src/function_extractor.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,21 @@ function filterSignatureDeclarations(signatures: readonly ts.Signature[]) {
162162
}
163163

164164
export function extractCallSignatures(name: string, typeChecker: ts.TypeChecker, type: ts.Type) {
165-
return filterSignatureDeclarations(type.getCallSignatures()).map(({decl, signature}) => ({
166-
name,
167-
entryType: EntryType.Function,
168-
description: extractJsDocDescription(decl),
169-
generics: extractGenerics(decl),
170-
isNewType: false,
171-
jsdocTags: extractJsDocTags(decl),
172-
params: extractAllParams(decl.parameters, typeChecker),
173-
rawComment: extractRawJsDoc(decl),
174-
returnType: extractReturnType(signature, typeChecker),
175-
}));
165+
return filterSignatureDeclarations(type.getCallSignatures()).map(({decl, signature}) => {
166+
const jsdocTags = extractJsDocTags(decl);
167+
return {
168+
name,
169+
entryType: EntryType.Function,
170+
description: extractJsDocDescription(decl),
171+
generics: extractGenerics(decl),
172+
isNewType: false,
173+
jsdocTags,
174+
params: extractAllParams(decl.parameters, typeChecker),
175+
rawComment: extractRawJsDoc(decl),
176+
returnType: extractReturnType(signature, typeChecker),
177+
returnDescription: jsdocTags.find((tag) => tag.name === 'returns')?.comment,
178+
};
179+
});
176180
}
177181

178182
function extractReturnType(signature: ts.Signature, typeChecker: ts.TypeChecker): string {

0 commit comments

Comments
 (0)