Skip to content

Commit 1393844

Browse files
committed
build: update markdown pipeline
The pipeline for rendering Markdown was 13 major versions behind. These changes update to the latest version and account for breakages.
1 parent 9f8e699 commit 1393844

File tree

6 files changed

+55
-43
lines changed

6 files changed

+55
-43
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@
9595
"@types/glob": "^8.0.0",
9696
"@types/jasmine": "^5.0.0",
9797
"@types/luxon": "^3.0.0",
98-
"@types/marked": "^2.0.0",
9998
"@types/minimatch": "^5.1.2",
10099
"@types/node": "^22.14.1",
101100
"@types/selenium-webdriver": "^3.0.17",
@@ -124,7 +123,7 @@
124123
"karma-parallel": "^0.3.1",
125124
"karma-sourcemap-loader": "^0.4.0",
126125
"magic-string": "0.30.17",
127-
"marked": "^2.0.0",
126+
"marked": "^15.0.12",
128127
"minimatch": "^3.0.4",
129128
"node-fetch": "^2.6.0",
130129
"parse5": "^7.1.2",
@@ -141,6 +140,7 @@
141140
"semver": "^7.3.5",
142141
"send": "^0.19.0",
143142
"shelljs": "^0.10.0",
143+
"slugify": "^1.6.6",
144144
"source-map-support": "^0.5.21",
145145
"stylelint": "^14.14.0",
146146
"terser": "^5.10.0",

pnpm-lock.yaml

Lines changed: 15 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/highlight-files/highlight-code-block.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import highlightJs from 'highlight.js';
44
* Transforms a given code block into its corresponding HTML output. We do this using
55
* highlight.js because it allows us to show colored code blocks in our documentation.
66
*/
7-
export function highlightCodeBlock(code: string, language: string) {
7+
export function highlightCodeBlock(code: string, language?: string) {
88
if (language) {
99
return highlightJs.highlight(code, {
1010
language: language.toLowerCase() === 'ts' ? 'typescript' : language,

tools/markdown-to-html/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ ts_project(
1313
),
1414
tsconfig = "//tools:tsconfig",
1515
deps = [
16-
"//:node_modules/@types/marked",
1716
"//:node_modules/marked",
17+
"//:node_modules/slugify",
1818
"//tools/highlight-files:sources",
1919
],
2020
)

tools/markdown-to-html/docs-marked-renderer.ts

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import {Renderer, Slugger} from 'marked';
1+
import {Renderer, Tokens} from 'marked';
22
import {basename, extname} from 'path';
3+
import slugify from 'slugify';
4+
import {highlightCodeBlock} from '../highlight-files/highlight-code-block';
35

46
/** Regular expression that matches example comments. */
57
const exampleCommentRegex = /<!--\s*example\(\s*([^)]+)\)\s*-->/g;
@@ -18,46 +20,53 @@ export class DocsMarkdownRenderer extends Renderer {
1820
/** Set of fragment links discovered in the currently rendered file. */
1921
private _referencedFragments = new Set<string>();
2022

21-
/**
22-
* Slugger provided by the `marked` package. Can be used to create unique
23-
* ids for headings.
24-
*/
25-
private _slugger = new Slugger();
23+
/** IDs that have been generated during Markdown parsing. */
24+
private _seenIds = new Set<string>();
2625

2726
/**
2827
* Transforms a markdown heading into the corresponding HTML output. In our case, we
2928
* want to create a header-link for each H2, H3, and H4 heading. This allows users to jump to
3029
* specific parts of the docs.
3130
*/
32-
heading(label: string, level: number, raw: string) {
33-
if (level === 2 || level === 3 || level === 4 || level === 5 || level === 6) {
34-
const headingId = this._slugger.slug(raw);
31+
heading(tag: Tokens.Heading) {
32+
const depth = tag.depth;
33+
const content = this.parser.parseInline(tag.tokens);
34+
35+
if (depth === 2 || depth === 3 || depth === 4 || depth === 5 || depth === 6) {
36+
const headingId = slugify(tag.text, {lower: true, strict: true});
37+
38+
this._seenIds.add(headingId);
3539
return `
36-
<h${level} id="${headingId}" class="docs-header-link">
40+
<h${depth} id="${headingId}" class="docs-header-link">
3741
<span header-link="${headingId}"></span>
38-
${label}
39-
</h${level}>
42+
${content}
43+
</h${depth}>
4044
`;
4145
}
4246

43-
return `<h${level}>${label}</h${level}>`;
47+
return `<h${depth}>${content}</h${depth}>`;
4448
}
4549

4650
/** Transforms markdown links into the corresponding HTML output. */
47-
link(href: string, title: string, text: string) {
51+
link(link: Tokens.Link) {
52+
const {href} = link;
53+
4854
// We only want to fix up markdown links that are relative and do not refer to guides already.
4955
// Otherwise we always map the link to the "guide/" path.
5056
// TODO(devversion): remove this logic and just disallow relative paths.
5157
if (!href.startsWith('http') && !href.startsWith('#') && !href.includes('guide/')) {
52-
return super.link(`guide/${basename(href, extname(href))}`, title, text);
58+
return super.link({
59+
...link,
60+
href: `guide/${basename(href, extname(href))}`,
61+
});
5362
}
5463

5564
// Keep track of all fragments discovered in a file.
5665
if (href.startsWith('#')) {
5766
this._referencedFragments.add(href.slice(1));
5867
}
5968

60-
return super.link(href, title, text);
69+
return super.link(link);
6170
}
6271

6372
/**
@@ -82,8 +91,8 @@ export class DocsMarkdownRenderer extends Renderer {
8291
* turns into
8392
* `<div material-docs-example="name"></div>`
8493
*/
85-
html(html: string) {
86-
html = html.replace(exampleCommentRegex, (_match: string, content: string) => {
94+
html(content: Tokens.HTML | Tokens.Tag) {
95+
return content.raw.replace(exampleCommentRegex, (_match: string, content: string) => {
8796
let replacement: string;
8897

8998
// using [\s\S]* because .* does not match line breaks
@@ -102,8 +111,11 @@ export class DocsMarkdownRenderer extends Renderer {
102111

103112
return `${exampleStartMarker}${replacement}${exampleEndMarker}`;
104113
});
114+
}
105115

106-
return super.html(html);
116+
code(block: Tokens.Code): string {
117+
const langClass = block.lang ? ` class="language-${block.lang}"` : '';
118+
return `<pre><code${langClass}>${highlightCodeBlock(block.text, block.lang)}</code></pre>`;
107119
}
108120

109121
/**
@@ -116,7 +128,7 @@ export class DocsMarkdownRenderer extends Renderer {
116128
// Collect any fragment links that do not resolve to existing fragments in the
117129
// rendered file. We want to error for broken fragment links.
118130
this._referencedFragments.forEach(id => {
119-
if (this._slugger.seen[id] === undefined) {
131+
if (!this._seenIds.has(id)) {
120132
failures.push(`Found link to "${id}". This heading does not exist.`);
121133
}
122134
});
@@ -127,7 +139,7 @@ export class DocsMarkdownRenderer extends Renderer {
127139
process.exit(1);
128140
}
129141

130-
this._slugger.seen = {};
142+
this._seenIds.clear();
131143
this._referencedFragments.clear();
132144

133145
const markdownOpen = '<div class="docs-markdown">';

tools/markdown-to-html/transform-markdown.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@
44
*/
55

66
import {readFileSync, writeFileSync} from 'fs';
7-
import marked from 'marked';
7+
import {marked} from 'marked';
88
import {join} from 'path';
9-
import {highlightCodeBlock} from '../highlight-files/highlight-code-block';
109
import {DocsMarkdownRenderer} from './docs-marked-renderer';
1110

1211
// Custom markdown renderer for transforming markdown files for the docs.
1312
const markdownRenderer = new DocsMarkdownRenderer();
1413

1514
// Setup our custom docs renderer by default.
16-
marked.setOptions({renderer: markdownRenderer, highlight: highlightCodeBlock});
15+
marked.setOptions({renderer: markdownRenderer});
1716

1817
if (require.main === module) {
1918
// The script expects the bazel-bin path as first argument. All remaining arguments will be
@@ -25,7 +24,7 @@ if (require.main === module) {
2524
inputFiles.forEach(inputPath => {
2625
const outputPath = join(bazelBinPath, `${inputPath}.html`);
2726
const htmlOutput = markdownRenderer.finalizeOutput(
28-
marked(readFileSync(inputPath, 'utf8')),
27+
marked.parse(readFileSync(inputPath, 'utf8'), {async: false}),
2928
inputPath,
3029
);
3130

0 commit comments

Comments
 (0)