forked from nodejs/doc-kit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate.mjs
More file actions
138 lines (113 loc) · 3.94 KB
/
generate.mjs
File metadata and controls
138 lines (113 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
'use strict';
import { readFile, cp } from 'node:fs/promises';
import { basename, join } from 'node:path';
import buildContent from './utils/buildContent.mjs';
import { replaceTemplateValues } from './utils/replaceTemplateValues.mjs';
import tableOfContents from './utils/tableOfContents.mjs';
import getConfig from '../../utils/configuration/index.mjs';
import { writeFile } from '../../utils/file.mjs';
import { groupNodesByModule } from '../../utils/generators.mjs';
import { minifyHTML } from '../../utils/html-minifier.mjs';
import { getRemarkRehypeWithShiki as remark } from '../../utils/remark.mjs';
/**
* Creates a heading object with the given name.
* @param {string} name - The name of the heading
* @returns {HeadingMetadataEntry} The heading object
*/
const getHeading = name => ({ depth: 1, data: { name } });
/**
* Process a chunk of items in a worker thread.
* Builds HTML template objects - FS operations happen in generate().
*
* Each item is pre-grouped {head, nodes, headNodes} - no need to
* recompute groupNodesByModule for every chunk.
*
* @type {import('./types').Generator['processChunk']}
*/
export async function processChunk(slicedInput, itemIndices, navigation) {
const results = [];
for (const idx of itemIndices) {
const { head, nodes, headNodes } = slicedInput[idx];
const nav = navigation.replace(
`class="nav-${head.api}"`,
`class="nav-${head.api} active"`
);
const toc = String(
remark().processSync(
tableOfContents(nodes, {
maxDepth: 5,
parser: tableOfContents.parseToCNode,
})
)
);
const content = buildContent(headNodes, nodes);
const apiAsHeading = head.api.charAt(0).toUpperCase() + head.api.slice(1);
const template = {
api: head.api,
path: head.path,
added: head.introduced_in ?? '',
section: head.heading.data.name || apiAsHeading,
toc,
nav,
content,
};
results.push(template);
}
return results;
}
/**
* Generates the legacy version of the API docs in HTML
*
* @type {import('./types').Generator['generate']}
*/
export async function* generate(input, worker) {
const config = getConfig('legacy-html');
const apiTemplate = await readFile(config.templatePath, 'utf-8');
const groupedModules = groupNodesByModule(input);
const headNodes = input
.filter(node => node.heading.depth === 1)
.toSorted((a, b) => a.heading.data.name.localeCompare(b.heading.data.name));
const indexOfFiles = config.index
? config.index.map(({ api, section }) => ({
api,
heading: getHeading(section),
}))
: headNodes;
const navigation = String(
remark().processSync(
tableOfContents(indexOfFiles, {
maxDepth: 1,
parser: tableOfContents.parseNavigationNode,
})
)
);
if (config.output) {
for (const path of config.additionalPathsToCopy) {
// Define the output folder for API docs assets
const assetsFolder = join(config.output, basename(path));
// Copy all files from assets folder to output
await cp(path, assetsFolder, { recursive: true });
}
}
// Create sliced input: each item contains head + its module's entries + headNodes reference
// This avoids sending all ~4900 entries to every worker and recomputing groupings
const entries = headNodes.map(head => ({
head,
nodes: groupedModules.get(head.api),
headNodes,
}));
// Stream chunks as they complete - HTML files are written immediately
for await (const chunkResult of worker.stream(entries, navigation)) {
// Write files for this chunk in the generate method (main thread)
if (config.output) {
for (const template of chunkResult) {
let result = replaceTemplateValues(apiTemplate, template, config);
if (config.minify) {
result = await minifyHTML(result);
}
await writeFile(join(config.output, `${template.api}.html`), result);
}
}
yield chunkResult;
}
}