Skip to content

Commit 71c39f7

Browse files
committed
chore: more code refactors and cleanups
1 parent 147a349 commit 71c39f7

File tree

10 files changed

+172
-110
lines changed

10 files changed

+172
-110
lines changed

package-lock.json

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

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"test": "node --test",
99
"test:watch": "node --test --watch",
1010
"test:coverage": "node --experimental-test-coverage --test",
11-
"prepare": "husky"
11+
"prepare": "husky",
12+
"run": "node bin/cli.mjs",
13+
"watch": "node --watch bin/cli.mjs"
1214
},
1315
"bin": {
1416
"api-docs-tooling": "./bin/cli.mjs"
@@ -28,6 +30,7 @@
2830
"commander": "^12.1.0",
2931
"github-slugger": "^2.0.0",
3032
"glob": "^11.0.0",
33+
"hastscript": "^9.0.0",
3134
"html-minifier-terser": "^7.2.0",
3235
"rehype-stringify": "^10.0.0",
3336
"remark": "^15.0.1",

shiki.config.mjs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
import { u as createTree } from 'unist-builder';
3+
import { h as createElement } from 'hastscript';
44

55
import { getWasmInstance } from '@shikijs/core/wasm-inlined';
66

@@ -21,11 +21,11 @@ import shikiNordTheme from 'shiki/themes/nord.mjs';
2121

2222
// Creates a static button element which is used for the "copy" button
2323
// within codeboxes for copying the code to the clipboard
24-
const copyButtonElement = createTree('element', {
25-
tagName: 'button',
26-
properties: { class: 'copy-button' },
27-
children: [createTree('text', 'copy')],
28-
});
24+
const copyButtonElement = createElement(
25+
'button',
26+
{ class: 'copy-button' },
27+
createElement('text', 'copy')
28+
);
2929

3030
/**
3131
* @TODO: Use `shiki.config.mjs` from nodejs/nodejs.org

src/generators/legacy-html/assets/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ tt,
668668
}
669669

670670
.api_stability code {
671-
background-color: rgb(0 0 0 / 10%);
671+
background-color: rgb(0 0 0 / 10%) !important;
672672
}
673673

674674
a code {
Lines changed: 81 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,109 @@
11
'use strict';
22

3+
import { h as createElement } from 'hastscript';
34
import { u as createTree } from 'unist-builder';
45

5-
import {
6-
DOC_API_STABILITY_SECTION_REF_URL,
7-
DOC_NODE_BLOB_BASE_URL,
8-
} from '../../../constants.mjs';
9-
10-
// The regular expression to match the Stability Index prefix
11-
const STABILITY_INDEX_PREFIX_REGEX = /Stability: ([0-5])/;
6+
import { DOC_NODE_BLOB_BASE_URL } from '../../../constants.mjs';
127

138
/**
149
* Builds a Markdown heading for a given node
1510
*
1611
* @param {ApiDocMetadataEntry} node The node to build the Markdown heading for
12+
* @returns {import('unist').Parent} The HTML AST tree of the heading content
1713
*/
18-
const buildNodeHeading = node => {
14+
const buildHeadingElement = node => {
1915
const [, headingId] = node.slug.split('#');
2016

21-
// Creates the anchor element for the heading (floats on the right side)
22-
const anchor = `<span><a class="mark" href="#${headingId}" id="${headingId}">#</a></span>`;
17+
// Creates the element that references the link to the heading
18+
const headingLinkElement = createElement(
19+
'span',
20+
createElement('a.mark#headingId', { href: `#${headingId}` }, '#')
21+
);
2322

24-
// The extra `\n` (new lines) are done to ensure that remark parses Markdown within HTML
25-
// as it would normally do, as it would not parse it if it were in the same line
26-
return `<h${node.heading.depth + 1}>\n\n${node.heading.text} ${anchor}\n\n</h${node.heading.depth + 1}>`;
23+
// Creates the heading element with the heading text and the link to the heading
24+
return createElement(`h${node.heading.depth + 1}`, [
25+
node.heading.text,
26+
headingLinkElement,
27+
]);
2728
};
2829

2930
/**
3031
* Builds a Markdown Stability Index
3132
*
3233
* @param {ApiDocMetadataEntry} node The node to build the Markdown Stability Index for
3334
* @param {import('remark').remark} remark The Remark instance to be used to process
35+
* @returns {import('unist').Parent} The AST tree of the Stability Index content
3436
*/
35-
const buildStabilityIndex = (node, remark) => {
36-
// Iterates through the Stability Indexes to build the content
37-
return node.stability.children.reduce((acc, stabilityNode) => {
38-
// Transforms the Stability Index AST nodes into a HTML string
39-
let stabilityIndex = remark.stringify(remark.runSync(stabilityNode));
40-
41-
// If the current node being processed is not the documentation node, we
42-
// define a link to the Stability Index section in the documentation
43-
// as they are originally referenced within the `documentation` node.
44-
if (node.api !== 'documentation') {
45-
stabilityIndex = stabilityIndex.replace(
46-
STABILITY_INDEX_PREFIX_REGEX,
47-
match => `<a href="${DOC_API_STABILITY_SECTION_REF_URL}">${match}</a>`
48-
);
49-
}
50-
51-
// Wraps the inner content with an HTML div to apply the CSS styles
52-
acc += `<div class="api_stability api_stability_${stabilityNode.data.index}">${stabilityIndex}</div>`;
53-
54-
return acc;
55-
}, '');
37+
const buildStabilityIndexes = (node, remark) => {
38+
// Iterates over each stability index to create a `div` element with the stability index class
39+
const parsedStabilityIndexes = node.stability.children.map(stabilityNode =>
40+
createElement(
41+
// Creates the `div` element with the class `api_stability` and the stability index class
42+
`div.api_stability.api_stability_${stabilityNode.data.index}`,
43+
// Processed the Markdown nodes into HTML nodes
44+
remark.runSync(stabilityNode).children
45+
)
46+
);
47+
48+
// Creates a tree to surround the Stability Indexes
49+
return createTree('root', parsedStabilityIndexes);
5650
};
5751

5852
/**
5953
* Builds the Metadata Properties into content
6054
*
6155
* @param {ApiDocMetadataEntry} node The node to build to build the properties from
56+
* @returns {import('unist').Parent} The HTML AST tree of the properties content
6257
*/
63-
const buildProperties = node => {
64-
let metadataSection = '<div class="api_metadata">';
58+
const buildMetadataElement = node => {
59+
const metadataElement = createElement('div.api_metadata');
6560

6661
// We use a `span` element to display the source link as a clickable link to the source within Node.js
6762
if (node.sourceLink && node.sourceLink.length) {
68-
metadataSection +=
69-
`<span><b>Source Code:</b>&nbsp;` +
70-
`<a href="${DOC_NODE_BLOB_BASE_URL}${node.sourceLink}">${node.sourceLink}` +
71-
`</a></span>`;
63+
// Creates the source link URL with the base URL and the source link
64+
const sourceLink = `${DOC_NODE_BLOB_BASE_URL}${node.sourceLink}`;
65+
66+
// Creates the source link element with the source link and the source link text
67+
const sourceLinkElement = createElement('span', [
68+
createElement('b', 'Source Code: '),
69+
createElement('a', { href: sourceLink }, node.sourceLink),
70+
]);
71+
72+
// Appends the source link element to the metadata element
73+
metadataElement.children.push(sourceLinkElement);
7274
}
7375

7476
// If there are changes, we create a `details` element with a `table` element to display the changes
7577
// Differently from the old API docs, on this version we always enforce a table to display the changes
7678
if (node.changes && node.changes.length) {
77-
const mapChangesIntoTable = node.changes.map(
78-
({ version, description }) =>
79-
// We use double `\n` to ensure that the Markdown is correctly parsed
80-
`<tr><td>${version.join(', ')}</td><td>\n\n${description}\n\n</td></tr>`
79+
// Maps the changes into a `tr` element with the version and the description
80+
const mappedHistoryEntries = node.changes.map(({ version, description }) =>
81+
createElement('tr', [
82+
createElement('td', version.join(', ')),
83+
createElement('td', description),
84+
])
8185
);
8286

83-
metadataSection +=
84-
`<details class="changelog"><summary>History</summary><table>` +
85-
`<thead><tr><th>Version</th><th>Changes</th></tr></thead>` +
86-
`<tbody>${mapChangesIntoTable.reverse().join('\n')}</tbody></table></details>`;
87+
// Creates the history details element with a summary and a table with the changes
88+
const historyDetailsElement = createElement('details.changelog', [
89+
createElement('summary', 'History'),
90+
createElement('table', [
91+
createElement('thead', [
92+
createElement('tr', [
93+
createElement('th', 'Version'),
94+
createElement('th', 'Changes'),
95+
]),
96+
]),
97+
createElement('tbody', mappedHistoryEntries),
98+
]),
99+
]);
100+
101+
// Appends the history details element to the metadata element
102+
metadataElement.children.push(historyDetailsElement);
87103
}
88104

89-
metadataSection += '</div>';
90-
91-
return metadataSection;
92-
};
93-
94-
/**
95-
* Builds the aggregated Markdown metadata content for a given node
96-
*
97-
* @param {ApiDocMetadataEntry} node Builds the content of a given node
98-
* @param {import('remark').remark} remark The Remark instance to be used to process
99-
*/
100-
const buildMetadata = (node, remark) => {
101-
const heading = buildNodeHeading(node);
102-
const stabilityIndeex = buildStabilityIndex(node, remark);
103-
const properties = buildProperties(node);
104-
105-
// Concatenates all the strings and parses with remark into an AST tree
106-
return remark.parse(`${heading}${stabilityIndeex}${properties}`);
105+
// Parses and processes the mixed Markdonw/HTML content into an HTML AST tree
106+
return metadataElement;
107107
};
108108

109109
/**
@@ -116,23 +116,23 @@ export default (nodes, remark) => {
116116
'root',
117117
// Parses the metadata pieces of each node and the content
118118
nodes.map(node => {
119-
// Parses the metadata into AST, since it they are strings
120-
const parsedMetadata = buildMetadata(node, remark);
121-
122-
// aggregate the two AST trees to then be parsed by runSync
123-
return createTree('root', [parsedMetadata, node.content]);
119+
const headingElement = buildHeadingElement(node);
120+
const metadataElement = buildMetadataElement(node);
121+
const stabilityIndexes = buildStabilityIndexes(node, remark);
122+
123+
// Processes the Markdown AST tree into an HTML AST tree
124+
const processedContent = remark.runSync(node.content);
125+
126+
// Concatenates all the strings and parses with remark into an AST tree
127+
return createElement('section', [
128+
headingElement,
129+
metadataElement,
130+
...stabilityIndexes.children,
131+
...processedContent.children,
132+
]);
124133
})
125134
);
126135

127-
// Processes the nodes to ensure that the Markdown is correctly parsed
128-
const processedNodes = remark.runSync(parsedNodes);
129-
130-
// We transform the outer `div` elements into `section` elements
131-
// This is done to ensure that each section is an actual section in the HTML
132-
processedNodes.children.forEach(node => {
133-
node.tagName = node.tagName === 'div' ? 'section' : node.tagName;
134-
});
135-
136136
// Stringifies the processed nodes to return the final Markdown content
137-
return remark.stringify(processedNodes);
137+
return remark.stringify(parsedNodes);
138138
};

src/loader.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ const createLoader = () => {
2727
);
2828

2929
return resolvedFiles.map(async filePath => {
30-
const fileBuffer = await readFile(filePath);
30+
const fileContents = await readFile(filePath, 'utf-8');
3131

32-
return new VFile({ path: filePath, value: fileBuffer });
32+
return new VFile({ path: filePath, value: fileContents });
3333
});
3434
};
3535

src/parser.mjs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { SKIP, visit } from 'unist-util-visit';
99
import createMetadata from './metadata.mjs';
1010
import createQueries from './queries.mjs';
1111

12-
import { transformTypeToReferenceLink } from './utils/parser.mjs';
1312
import { getRemark } from './utils/remark.mjs';
1413
import { createNodeSlugger } from './utils/slugger.mjs';
1514

@@ -27,6 +26,8 @@ const createParser = () => {
2726
addYAMLMetadata,
2827
addHeadingMetadata,
2928
addStabilityIndexMetadata,
29+
updateTypesToMarkdownLinks,
30+
updateStailityPrefixToMarkdownLinks,
3031
} = createQueries();
3132

3233
/**
@@ -47,22 +48,18 @@ const createParser = () => {
4748
*/
4849
const metadataCollection = [];
4950

51+
// Creates a new Slugger instance for the current API doc file
52+
const nodeSlugger = createNodeSlugger();
53+
5054
// We allow the API doc VFile to be a Promise of a VFile also,
5155
// hence we want to ensure that it first resolves before we pass it to the parser
5256
const resolvedApiDoc = await Promise.resolve(apiDoc);
5357

5458
// Normalizes all the types in the API doc file to be reference links
55-
// which needs to be done before the actual processing is done
56-
// since we're replacing raw text within the Markdown
57-
// @TODO: This could be moved to another place responsible for handling
58-
// text substitutions at the beginning of the parsing process (as dependencies)
59-
resolvedApiDoc.value = String(resolvedApiDoc.value).replaceAll(
60-
createQueries.QUERIES.normalizeTypes,
61-
transformTypeToReferenceLink
62-
);
59+
updateTypesToMarkdownLinks(resolvedApiDoc);
6360

64-
// Creates a new Slugger instance for the current API doc file
65-
const nodeSlugger = createNodeSlugger();
61+
// Normalizes all the Stability Index prefixes with Markdown links
62+
updateStailityPrefixToMarkdownLinks(resolvedApiDoc);
6663

6764
// Parses the API doc into an AST tree using `unified` and `remark`
6865
const apiDocTree = remarkProcessor.parse(resolvedApiDoc);

0 commit comments

Comments
 (0)