Skip to content

Commit a792315

Browse files
JeanMecheamishne
authored andcommitted
docs(docs-infra): prevent heading from linking symbols
1 parent 61614f6 commit a792315

6 files changed

Lines changed: 35 additions & 27 deletions

File tree

adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {Tokens, Token, RendererThis, TokenizerThis} from 'marked';
10-
import {loadWorkspaceRelativeFile, anchorTarget} from '../../helpers.mjs';
11-
import {setInsideLink} from '../../transformations/link.mjs';
9+
import {RendererThis, Token, TokenizerThis, Tokens} from 'marked';
10+
import {anchorTarget, loadWorkspaceRelativeFile} from '../../helpers.mjs';
11+
import {AdevDocsRenderer} from '../../renderer.mjs';
1212

1313
interface DocsCardToken extends Tokens.Generic {
1414
type: 'docs-card';
@@ -67,11 +67,13 @@ export const docsCardExtension = {
6767
return undefined;
6868
},
6969
renderer(this: RendererThis, token: DocsCardToken) {
70-
return token.imgSrc ? getCardWithSvgIllustration(this, token) : getStandardCard(this, token);
70+
return token.imgSrc
71+
? getCardWithSvgIllustration(this, token)
72+
: getStandardCard(this.parser.renderer as AdevDocsRenderer, token);
7173
},
7274
};
7375

74-
function getStandardCard(renderer: RendererThis, token: DocsCardToken) {
76+
function getStandardCard(renderer: AdevDocsRenderer, token: DocsCardToken) {
7577
if (token.iconImgSrc && token.href) {
7678
// We can assume that all icons are svg files since they are custom.
7779
// We need to read svg content, instead of renering svg with `img`,
@@ -110,13 +112,11 @@ function getStandardCard(renderer: RendererThis, token: DocsCardToken) {
110112
`;
111113
}
112114

113-
function parseWithoutCreatingLinks(renderer: RendererThis, token: DocsCardToken) {
114-
setInsideLink(true);
115-
try {
116-
return renderer.parser.parse(token.tokens);
117-
} finally {
118-
setInsideLink(false);
119-
}
115+
function parseWithoutCreatingLinks(renderer: AdevDocsRenderer, token: DocsCardToken) {
116+
renderer.context.disableAutoLinking = true;
117+
const parsed = renderer.parser.parse(token.tokens);
118+
renderer.context.disableAutoLinking = false;
119+
return parsed;
120120
}
121121

122122
function getCardWithSvgIllustration(renderer: RendererThis, token: DocsCardToken) {

adev/shared-docs/pipeline/shared/marked/renderer.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface RendererContext {
3131
apiEntries?: Record<string, {moduleName: string; aliases?: string[]}>;
3232
highlighter: HighlighterGeneric<any, any>;
3333
headerIds: Map<string, number>;
34+
/** In the case we want to disable auto-linking because anchor blocks might be incompatible where some code blocks are being rendered */
35+
disableAutoLinking: boolean;
3436
}
3537

3638
/**

adev/shared-docs/pipeline/shared/marked/test/heading/heading.spec.mts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {parseMarkdown} from '../../parse.mjs';
10-
import {resolve} from 'node:path';
119
import {readFile} from 'fs/promises';
1210
import {JSDOM} from 'jsdom';
11+
import {resolve} from 'node:path';
12+
import {parseMarkdown} from '../../parse.mjs';
1313
import {rendererContext} from '../renderer-context.mjs';
1414

1515
describe('markdown to html', () => {
@@ -118,4 +118,17 @@ describe('markdown to html', () => {
118118

119119
expect(h2.firstElementChild!.innerHTML).toBe('Query for the <code>&lt;h1&gt;</code>');
120120
});
121+
122+
it('shoud now link symbols in headings', () => {
123+
const markdownDocument = JSDOM.fragment(
124+
parseMarkdown('## Hello **NEW** `Router` ', rendererContext),
125+
);
126+
const h2 = markdownDocument.querySelector('h2')!;
127+
128+
// The anchor element should be to only child, no nested anchor
129+
expect(h2.children.length).toBe(1);
130+
131+
// We ensure that we still style the heading content
132+
expect(markdownDocument.querySelector('strong')).toBeDefined();
133+
});
121134
});

adev/shared-docs/pipeline/shared/marked/test/renderer-context.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const rendererContext: RendererContext = {
2525
Router: {moduleName: 'angular/router'},
2626
},
2727
headerIds: new Map<string, number>(),
28+
disableAutoLinking: false,
2829
};
2930

3031
export async function setHighlighter() {

adev/shared-docs/pipeline/shared/marked/transformations/heading.mts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ export function headingRender(
1313
this: AdevDocsRenderer,
1414
{depth, tokens, text: headingText, raw}: Tokens.Heading,
1515
): string {
16-
const parsedText = this?.parser.parseInline(tokens);
16+
this.context.disableAutoLinking = true;
17+
const parsedText = this?.parser.parseInline(tokens, this);
18+
this.context.disableAutoLinking = false;
1719
if (depth === 1) {
1820
return `
1921
<header class="docs-header">

adev/shared-docs/pipeline/shared/marked/transformations/link.mts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,10 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import {Tokens} from 'marked';
910
import {anchorTarget} from '../helpers.mjs';
10-
import {Renderer, Tokens} from 'marked';
1111
import {AdevDocsRenderer} from '../renderer.mjs';
1212

13-
/**
14-
* Tracks whether the current renderer is inside a link.
15-
*
16-
* This is necessary because nested links are invalid HTML and can cause rendering issues.
17-
*/
18-
let insideLink = false;
19-
export function setInsideLink(value: boolean) {
20-
insideLink = value;
21-
}
22-
2313
export function linkRender(this: AdevDocsRenderer, {href, title, tokens}: Tokens.Link) {
2414
// We have render-time check that we don't create absolute links (which are rendered as external links)
2515
// in our guides
@@ -40,7 +30,7 @@ export function linkRender(this: AdevDocsRenderer, {href, title, tokens}: Tokens
4030
);
4131
}
4232

43-
if (insideLink) {
33+
if (this.context.disableAutoLinking) {
4434
return this.parser.parseInline(tokens);
4535
}
4636

0 commit comments

Comments
 (0)