Skip to content

Commit 1c31c0d

Browse files
hawkgsmmalerba
authored andcommitted
docs(docs-infra): API doc content rendering fixes (#60116)
The PR introduces a few doc content rendering fixes: - Fix highlighted section heading styles (regression from #59965). - Convert JSDoc links within 'Usage Notes' sections to HTML and render them. - Add IDs to doc content headings. This, by itself, makes these headings available in the page ToC. PR Close #60116
1 parent 3f01166 commit 1c31c0d

9 files changed

Lines changed: 52 additions & 37 deletions

File tree

adev/shared-docs/pipeline/api-gen/rendering/marked/renderer.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import {Renderer, Tokens} from 'marked';
1010
import {codeToHtml} from '../shiki/shiki';
11+
import {SECTION_HEADING, SECTION_SUB_HEADING} from '../styling/css-classes';
1112

1213
/**
1314
* Custom renderer for marked that will be used to transform markdown files to HTML
@@ -55,21 +56,39 @@ export const renderer: Partial<Renderer> = {
5556
<div class="docs-table docs-scroll-track-transparent">
5657
<table>
5758
<thead>
58-
${this.tablerow({
59-
text: header.map((cell) => this.tablecell(cell)).join(''),
60-
})}
59+
${this.tablerow({text: header.map((cell) => this.tablecell(cell)).join('')})}
6160
</thead>
6261
<tbody>
6362
${rows
64-
.map((row) =>
65-
this.tablerow({
66-
text: row.map((cell) => this.tablecell(cell)).join(''),
67-
}),
68-
)
63+
.map((row) => this.tablerow({text: row.map((cell) => this.tablecell(cell)).join('')}))
6964
.join('')}
7065
</tbody>
7166
</table>
7267
</div>
7368
`;
7469
},
70+
71+
heading(this: Renderer, {text, depth, tokens}: Tokens.Heading) {
72+
const id = text
73+
.toLowerCase()
74+
.replaceAll(' ', '-')
75+
.replace(/[^a-z0-9-]/g, '');
76+
77+
// Since we have a code transformer `addApiLinksToHtml` which adds anchors
78+
// to code blocks of known symbols, we add an additional `data-skip-anchor`
79+
// attribute that prevents the transformation. This is needed since nested
80+
// anchor tags are illegal and break the HTML.
81+
const textRenderer = new Renderer();
82+
textRenderer.codespan = ({text}) => `<code data-skip-anchor>${text}</code>`;
83+
const parsedText = this.parser.parseInline(tokens, textRenderer);
84+
85+
// The template matches templates/section-heading.tsx
86+
return `
87+
<h${depth} id="${id}" class="${SECTION_HEADING} ${SECTION_SUB_HEADING}">
88+
<a href="#${id}" aria-label="Link to ${text} section" tabIndex="-1">
89+
${parsedText}
90+
</a>
91+
</h${depth}>
92+
`;
93+
},
7594
};

adev/shared-docs/pipeline/api-gen/rendering/styling/css-classes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ export const HEADER_ENTRY_LABEL = 'docs-api-item-label';
2727

2828
export const SECTION_CONTAINER = 'docs-reference-section';
2929
export const SECTION_HEADING = 'docs-reference-section-heading';
30+
export const SECTION_SUB_HEADING = 'docs-reference-section-heading--sub';

adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,10 +476,11 @@ function appendPrefixAndSuffix(entry: DocEntry, codeTocData: CodeTableOfContents
476476
*/
477477
export function addApiLinksToHtml(htmlString: string): string {
478478
const result = htmlString.replace(
479-
// This regex looks for span/code blocks not wrapped by an anchor block.
479+
// This regex looks for span/code blocks not wrapped by an anchor block
480+
// or the tag doesn't contain `data-skip-anchor` attribute.
480481
// Their content are then replaced with a link if the symbol is known
481-
// The captured content ==> vvvvvvvv
482-
/(?<!<a[^>]*>)(<(?:(?:span)|(?:code))[^>]*>\s*)([^<]*?)(\s*<\/(?:span|code)>)/g,
482+
// The captured content ==> vvvvvvvv
483+
/(?<!<a[^>]*>)(<(?:(?:span)|(?:code))(?!\sdata-skip-anchor)[^>]*>\s*)([^<]*?)(\s*<\/(?:span|code)>)/g,
483484
(type: string, span1: string, potentialSymbolName: string, span2: string) => {
484485
let [symbol, subSymbol] = potentialSymbolName.split(/(?:#|\.)/) as [string, string?];
485486

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

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,10 @@ export function addHtmlDescription<T extends HasDescription & HasModuleName>(
5858

5959
const description = !!entry.description ? entry.description : jsDocDescription;
6060
const shortTextMatch = description.match(firstParagraphRule);
61-
const htmlDescription = getHtmlForJsDocText(description, entry).trim();
62-
const shortHtmlDescription = getHtmlForJsDocText(
63-
shortTextMatch ? shortTextMatch[0] : '',
64-
entry,
65-
).trim();
66-
return {
67-
...entry,
68-
htmlDescription,
69-
shortHtmlDescription,
70-
};
61+
const htmlDescription = getHtmlForJsDocText(description).trim();
62+
const shortHtmlDescription = getHtmlForJsDocText(shortTextMatch ? shortTextMatch[0] : '').trim();
63+
64+
return {...entry, htmlDescription, shortHtmlDescription};
7165
}
7266

7367
/**
@@ -81,7 +75,7 @@ export function addHtmlJsDocTagComments<T extends HasJsDocTags & HasModuleName>(
8175
...entry,
8276
jsdocTags: entry.jsdocTags.map((tag) => ({
8377
...tag,
84-
htmlComment: getHtmlForJsDocText(tag.comment, entry),
78+
htmlComment: getHtmlForJsDocText(tag.comment),
8579
})),
8680
};
8781
}
@@ -100,20 +94,16 @@ export function addHtmlUsageNotes<T extends HasJsDocTags>(entry: T): T & HasHtml
10094
const usageNotesTag = entry.jsdocTags.find(
10195
({name}) => name === JS_DOC_USAGE_NOTES_TAG || name === JS_DOC_REMARKS_TAG,
10296
);
103-
const htmlUsageNotes = usageNotesTag
104-
? (marked.parse(wrapExampleHtmlElementsWithCode(usageNotesTag.comment)) as string)
105-
: '';
106-
107-
const transformedHtml = addApiLinksToHtml(htmlUsageNotes);
97+
const htmlUsageNotes = usageNotesTag ? getHtmlForJsDocText(usageNotesTag.comment) : '';
10898

10999
return {
110100
...entry,
111-
htmlUsageNotes: transformedHtml,
101+
htmlUsageNotes,
112102
};
113103
}
114104

115105
/** Given a markdown JsDoc text, gets the rendered HTML. */
116-
function getHtmlForJsDocText<T extends HasModuleName>(text: string, entry: T): string {
106+
function getHtmlForJsDocText(text: string): string {
117107
const parsed = marked.parse(convertLinks(wrapExampleHtmlElementsWithCode(text))) as string;
118108
return addApiLinksToHtml(parsed);
119109
}
@@ -126,7 +116,7 @@ export function setEntryFlags<T extends HasJsDocTags & HasModuleName>(
126116
...entry,
127117
isDeprecated: isDeprecatedEntry(entry),
128118
deprecationMessage: deprecationMessage
129-
? getHtmlForJsDocText(deprecationMessage, entry)
119+
? getHtmlForJsDocText(deprecationMessage)
130120
: deprecationMessage,
131121
isDeveloperPreview: isDeveloperPreview(entry),
132122
isExperimental: isExperimental(entry),

adev/shared-docs/styles/_reference.scss

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@
6666
.docs-reference-section-heading {
6767
padding-block-start: 3rem;
6868

69-
a {
69+
&--sub {
70+
padding-block-start: 1rem;
71+
}
72+
73+
& > a {
7074
@include anchor.docs-anchor();
7175
color: inherit;
7276
}
@@ -98,7 +102,7 @@
98102
z-index: 0;
99103
}
100104

101-
&.highlighted {
105+
&.docs-highlighted-card {
102106
box-shadow: 10px 4px 40px 0 rgba(0, 0, 0, 0.01);
103107

104108
&::before {

adev/shared-docs/styles/_typography.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
}
8080

8181
p > a,
82+
p > em > a,
8283
td > a,
8384
div > a:not(.docs-card),
8485
code > a,
@@ -93,6 +94,7 @@
9394
}
9495

9596
p > a,
97+
p > em > a,
9698
.docs-list a,
9799
.docs-card a {
98100
margin-block: 0;

adev/src/app/features/references/api-reference-details-page/api-reference-details-page.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {DOCUMENT} from '@angular/common';
1414
import {ReferenceScrollHandler} from '../services/reference-scroll-handler.service';
1515
import {API_SECTION_CLASS_NAME} from '../constants/api-reference-prerender.constants';
1616

17-
const HIGHLIGHTED_CARD_CLASS = 'highlighted';
17+
const HIGHLIGHTED_CARD_CLASS = 'docs-highlighted-card';
1818

1919
@Component({
2020
selector: 'adev-reference-page',

packages/core/src/application/application_ref.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ export function optionsReducer<T extends Object>(dst: T, objs: T | T[]): T {
188188
* A reference to an Angular application running on a page.
189189
*
190190
* @usageNotes
191-
* {@a is-stable-examples}
192191
* ### isStable examples and caveats
193192
*
194193
* Note two important points about `isStable`, demonstrated in the examples below:

packages/upgrade/static/src/upgrade_module.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {NgAdapterInjector} from './util';
3636
* {@link UpgradeModule#upgrading-an-angular-1-service Upgrading an AngularJS service} below.
3737
* 4. Creation of an AngularJS service that wraps and exposes an Angular injectable
3838
* so that it can be injected into an AngularJS context. See `downgradeInjectable`.
39-
* 3. Bootstrapping of a hybrid Angular application which contains both of the frameworks
39+
* 5. Bootstrapping of a hybrid Angular application which contains both of the frameworks
4040
* coexisting in a single application.
4141
*
4242
* @usageNotes
@@ -102,7 +102,7 @@ import {NgAdapterInjector} from './util';
102102
*
103103
* ### Examples
104104
*
105-
* Import the `UpgradeModule` into your top level {@link NgModule Angular `NgModule`}.
105+
* Import the `UpgradeModule` into your top level Angular {@link NgModule NgModule}.
106106
*
107107
* {@example upgrade/static/ts/full/module.ts region='ng2-module'}
108108
*
@@ -116,7 +116,6 @@ import {NgAdapterInjector} from './util';
116116
*
117117
* {@example upgrade/static/ts/full/module.ts region='bootstrap-ng2'}
118118
*
119-
* {@a upgrading-an-angular-1-service}
120119
* ### Upgrading an AngularJS service
121120
*
122121
* There is no specific API for upgrading an AngularJS service. Instead you should just follow the

0 commit comments

Comments
 (0)