scan only the fetched script tail in canonicalHtml and deduplicate hrefs in linksOf
Signed-off-by: dawn <90008@klbr.net>
12123456567891081112131412151614171819172021222023242526272823242529303132333435362837383940414243324445464748// the bits of a rendered page the renderer reads or rewrites
// kit's universal fetch inlines each read as a <script data-sveltekit-fetched> in the// order the promises resolved. sorting them makes the html a function of the page's reads,// not of which loopback fetch came back firstconst FETCHED_MARKER = '<script type="application/json" data-sveltekit-fetched';const FETCHED = /<script type="application\/json" data-sveltekit-fetched data-url="([^"]*)"[^>]*>[\s\S]*?<\/script>/g;
// kit inlines each read the page made in the order the reads finished, which follows// concurrency. sorted, the same reads give the same bytes, so an unchanged page is unchangedexport const canonicalHtml = (html) => { const start = html.indexOf(FETCHED_MARKER); if (start === -1 || html.indexOf(FETCHED_MARKER, start + FETCHED_MARKER.length) === -1) return html; const tail = html.slice(start); const blocks = [...html.matchAll(FETCHED)]; const blocks = [...tail.matchAll(FETCHED)]; if (blocks.length < 2) return html; const sorted = blocks.map((m) => m[0]).sort(); let at = 0; let rebuilt = ""; let rebuilt = html.slice(0, start); blocks.forEach((m, i) => { rebuilt += html.slice(at, m.index) + sorted[i]; rebuilt += tail.slice(at, m.index) + sorted[i]; at = m.index + m[0].length; }); return rebuilt + html.slice(at); return rebuilt + tail.slice(at);};
// same-repo links a page shows, as decoded pathnames routeOf acceptsconst HREF = /href="([^"#?]+)/g;
// same-repo routes linked from rendered html, decoded the way routeOf and the filesystem// see themexport const linksOf = (html, origin, routeOf) => { const found = new Set(); for (const [, raw] of html.matchAll(/href="([^"#?]+)/g)) { const href = raw.replaceAll("&", "&"); if (!href.startsWith("/")) continue; const seen = new Set(); for (const [, raw] of html.matchAll(HREF)) { if (seen.has(raw)) continue; seen.add(raw); if (!raw.startsWith("/")) continue; const href = raw.includes("&") ? raw.replaceAll("&", "&") : raw; let pathname; try { pathname = decodeURI(new URL(href, origin).pathname); pathname = href.startsWith("//") || href.includes("/.") || href.includes("\\") ? decodeURI(new URL(href, origin).pathname) : decodeURI(href); } catch { continue; } pathname = pathname.replace(/\/$/, "") || "/"; if (pathname.length > 1 && pathname.endsWith("/")) pathname = pathname.replace(/\/+$/, "") || "/"; if (routeOf(pathname) !== null) found.add(pathname); } return found;};