diff --git a/_tools/generate-pages.js b/_tools/generate-pages.js index 09ac71e3..f3c47b6a 100644 --- a/_tools/generate-pages.js +++ b/_tools/generate-pages.js @@ -1,5 +1,7 @@ const fs = require("fs/promises"); const html = require('escape-html-template-tag'); +const {safe} = html; +const {JSDOM} = require("jsdom"); const { expandCrawlResult } = require('reffy/src/lib/util'); @@ -8,6 +10,8 @@ const aliasIndex = new Map(); const linksIndex = new Map(); const letters = new Map(); +let results; + const typeInfo = { "grammar": { human: "grammar", @@ -195,6 +199,33 @@ function sortByArea([relatedTerm1, relatedTermId1], [relatedTerm2, relatedTermId return typeInfo[type1].area.localeCompare(typeInfo[type2].area) || type1.localeCompare(type2) || relatedTerm1.localeCompare(relatedTerm2); } +function findDfn(link) { + console.log("searching for " + link + " in " + results.length + " specs"); + for (const spec of results) { + const dfn = spec.dfns?.find(d => d.href === link); + if (dfn) return {dfn, spec}; + } +} + +function substituteProseLinks(html) { + // TODO: how reliably can we assume that the html can be put inside a
? + const frag = JSDOM.fragment("
" + html + "
"); + frag.querySelectorAll('a[href^="https://"]').forEach(link => { + const dfnData = findDfn(link.href); + if (dfnData) { + const {dfn, spec} = dfnData; + const term = cleanTerm(dfn.linkingText[0], dfn.type); + const termId = generateTermId(dfn, spec); + console.log(link.href, term, termId); + const dfnLink = getLink(term, termId); + if (dfnLink) { + link.href = dfnLink; + } + } + }); + return frag.firstChild.innerHTML; +} + function getScopingTermId(type, _for, displayTerm, dfns) { function returnIfFound(candidates, matches) { if (matches.length === 1) { @@ -413,10 +444,23 @@ ${content}`); } +function generateTermId(dfn, spec) { + if (dfn.for.length === 0) { + if (typeInfo[dfn.type]?.exclusiveNamespace) { + return `@@${dfn.type}`; + } else { + return `${spec.series.shortname}%%${dfn.type}`; + } + } else { + // by convention, we use the first 'for' by alphabetical order + return `${dfn.for.sort()[0]}@${dfn.type}`; + } +} + (async function() { const jsonIndex = await fs.readFile("./webref/ed/index.json", "utf-8"); const index = JSON.parse(jsonIndex); - const {results} = await expandCrawlResult(index, './webref/ed/', ['dfns', 'links']); + results = (await expandCrawlResult(index, './webref/ed/', ['dfns', 'links'])).results; for (const spec of results) { for (const dfn of (spec.dfns || [])) { if (dfn.access === "private") continue; @@ -425,22 +469,14 @@ ${content}`); const term = cleanTerm(dfn.linkingText[0], dfn.type); const displayTerm = dfn.linkingText[0].replace(/^"/, '').replace(/"$/, ''); const termEntry = termIndex.get(term) ?? {}; - let termId; + const termId = generateTermId(dfn, spec); let prefixes = []; - if (dfn.for.length === 0) { - if (typeInfo[dfn.type]?.exclusiveNamespace) { - termId = `@@${dfn.type}`; - } else { - termId = `${spec.series.shortname}%%${dfn.type}`; - } - } else { + if (dfn.for.length) { if (dfn.type === "constructor" && term !== 'constructor()') { prefixes = ['new ']; } else if (['method', 'const', 'attribute', 'dict-member'].includes(dfn.type)) { prefixes = dfn.for.map(_for => `${_for}.`); } - // by convention, we use the first 'for' by alphabetical order - termId = `${dfn.for.sort()[0]}@${dfn.type}`; } const subtermEntry = termEntry[termId] ?? {shortname: spec.series.shortname, type: dfn.type, _for: dfn.for, dfns: [], prefixes: [], refs: [], related: [], displayTerm, sortTerm: `${displayTerm}-${prefixes[0] ?? ''}`}; subtermEntry.dfns.push({...dfn, spec: spec.shortTitle}); @@ -510,16 +546,29 @@ ${content}`);

Color key: WebIDL CSS Markup HTTP

${letters.get(entry).sort((a,b) => a.toLowerCase().localeCompare(b.toLowerCase())).map(term => { + return html`${Object.keys(termIndex.get(term)).sort((a,b) => termIndex.get(term)[a].sortTerm.localeCompare(termIndex.get(term)[b].sortTerm)) .map(termId => { const {displayTerm, type, _for, dfns, prefixes, refs, related} = termIndex.get(term)[termId]; + let definitionContent = ``; + const withProse = dfns.some(d => d.htmlProse && d.access === "public"); + if (!withProse) { + definitionContent = html.join(dfns.map(dfn => { + return html`${dfn.spec} `; + }), ', '); + } else if (dfns.length === 1) { + const dfn = dfns[0]; + definitionContent = html`${dfn.spec}: ${safe(substituteProseLinks(dfn.htmlProse))}`; + } else { + definitionContent = html`