Files
rea/src/domain/javascript/htmlArtifactReferences.ts
T
Rudy Mizrahi Celekli 1154f2f03c fix(javascript): reconstruct HTML script loads accurately (#1042)
* fix: parse HTML script references with HTML semantics

Signed-off-by: Rudy Celekli <47457359+rudycelekli@users.noreply.github.com>

* test(javascript): cover exact HTML script resource identity

---------

Signed-off-by: Rudy Celekli <47457359+rudycelekli@users.noreply.github.com>
Co-authored-by: N0zoM1z0 <1705004398@qq.com>
2026-10-08 13:24:24 +08:00

56 lines
1.8 KiB
TypeScript

import {
defaultTreeAdapter,
parse,
type DefaultTreeAdapterTypes,
} from "parse5";
interface HtmlScriptReference {
readonly scriptPath: string;
readonly startOffset: number;
readonly endOffset: number;
}
/** Extract inert HTML script references and the first document base href. */
export const htmlArtifactReferences = (
text: string,
): {
readonly baseHref: string | null;
readonly scripts: readonly HtmlScriptReference[];
} => {
const pending: DefaultTreeAdapterTypes.Node[] = [
parse(text, { sourceCodeLocationInfo: true }),
];
const scripts: HtmlScriptReference[] = [];
let baseHref: string | null = null;
while (pending.length > 0) {
const node = pending.pop();
if (node === undefined) continue;
if (
defaultTreeAdapter.isElementNode(node) &&
node.namespaceURI === "http://www.w3.org/1999/xhtml"
) {
if (node.tagName === "base" && baseHref === null) {
const href = node.attrs.find(({ name }) => name === "href");
if (href !== undefined) baseHref = href.value;
}
if (node.tagName === "script") {
const src = node.attrs.find(({ name }) => name === "src");
const location = node.sourceCodeLocation?.startTag;
if (src !== undefined && src.value !== "" && location !== undefined) {
scripts.push({
scriptPath: src.value,
startOffset: location.startOffset,
endOffset: location.endOffset,
});
}
}
}
// Template content belongs to a separate inert document fragment. Only
// traverse the actual document children, without recursion on deep input.
if ("childNodes" in node) {
for (const child of node.childNodes.toReversed()) pending.push(child);
}
}
return { baseHref, scripts };
};