• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Build all.html by combining the generated toc and apicontent from each
2// of the generated html files.
3
4import fs from 'fs';
5
6const source = new URL('../../out/doc/api/', import.meta.url);
7
8// Get a list of generated API documents.
9const htmlFiles = fs.readdirSync(source, 'utf8')
10  .filter((name) => name.includes('.html') && name !== 'all.html');
11
12// Read the table of contents.
13const toc = fs.readFileSync(new URL('./index.html', source), 'utf8');
14
15// Extract (and concatenate) the toc and apicontent from each document.
16let contents = '';
17let apicontent = '';
18
19// Identify files that should be skipped. As files are processed, they
20// are added to this list to prevent dupes.
21const seen = {
22  'all.html': true,
23  'index.html': true
24};
25
26for (const link of toc.match(/<a.*?>/g)) {
27  const href = /href="(.*?)"/.exec(link)[1];
28  if (!htmlFiles.includes(href) || seen[href]) continue;
29  const data = fs.readFileSync(new URL(`./${href}`, source), 'utf8');
30
31  // Split the doc.
32  const match = /(<\/ul>\s*)?<\/\w+>\s*<\w+ id="apicontent">/.exec(data);
33
34  contents += data.slice(0, match.index)
35    .replace(/[\s\S]*?id="toc"[^>]*>\s*<\w+>.*?<\/\w+>\s*(<ul>\s*)?/, '');
36
37  apicontent += '<section>' + data.slice(match.index + match[0].length)
38    .replace(/<!-- API END -->[\s\S]*/, '</section>')
39    .replace(/<a href="(\w[^#"]*)#/g, (match, href) => {
40      return htmlFiles.includes(href) ? '<a href="#' : match;
41    })
42    .trim() + '\n';
43
44  // Mark source as seen.
45  seen[href] = true;
46}
47
48// Replace various mentions of index with all.
49let all = toc.replace(/index\.html/g, 'all.html')
50  .replace('<a href="all.html">', '<a href="index.html">')
51  .replace('index.json', 'all.json')
52  .replace('api-section-index', 'api-section-all')
53  .replace('data-id="index"', 'data-id="all"')
54  .replace(/<li class="edit_on_github">.*?<\/li>/, '');
55
56// Clean up the title.
57all = all.replace(/<title>.*?\| /, '<title>');
58
59// Insert the combined table of contents.
60const tocStart = /<!-- TOC -->/.exec(all);
61all = all.slice(0, tocStart.index + tocStart[0].length) +
62  '<details id="toc" open><summary>Table of contents</summary>\n' +
63  '<ul>\n' + contents + '</ul>\n' +
64  '</details>\n' +
65  all.slice(tocStart.index + tocStart[0].length);
66
67// Replace apicontent with the concatenated set of apicontents from each source.
68const apiStart = /<\w+ id="apicontent">\s*/.exec(all);
69const apiEnd = all.lastIndexOf('<!-- API END -->');
70all = all.slice(0, apiStart.index + apiStart[0].length) +
71  apicontent +
72  all.slice(apiEnd);
73
74// Write results.
75fs.writeFileSync(new URL('./all.html', source), all, 'utf8');
76
77// Validate all hrefs have a target.
78const ids = new Set();
79const idRe = / id="([^"]+)"/g;
80let match;
81while (match = idRe.exec(all)) {
82  ids.add(match[1]);
83}
84
85const hrefRe = / href="#([^"]+)"/g;
86while (match = hrefRe.exec(all)) {
87  if (!ids.has(match[1])) throw new Error(`link not found: ${match[1]}`);
88}
89