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