import { expect, it } from "vitest"; import { HTML_INLINE_SCRIPT_LOCATION_LIMIT, htmlArtifactReferences, } from "./htmlArtifactReferences.js"; it.each([ ['', []], ['', []], [``, []], ["", ["actual.js"]], ['', ["actual.js"]], ['', ["actual.js"]], ["", ["actual.js"]], ['', ["actual.js"]], ['', ["actual.js"]], ['', []], ['', ["actual.js"]], ['', []], ['', []], ['', []], [``, []], [ '', [], ], ['', []], [ '', ["actual.js"], ], ['', ["actual.js"]], ['', ["actual.js"]], ['', ["actual.js"]], ['', ["actual.js"]], ['', ["actual.js"]], ['', ["actual.js"]], ['', ["actual.js"]], ])("extracts document references from %s", (text, expected) => { expect( htmlArtifactReferences(text).scripts.map(({ scriptPath }) => scriptPath), ).toEqual(expected); }); it("retains exact opening-tag coordinates rather than the script body", () => { const opening = ''; const prefix = "\n\n"; const text = `${prefix}${opening}ignored body`; expect(htmlArtifactReferences(text)).toEqual({ baseHref: null, inlineScripts: [], inlineScriptCount: 0, scripts: [ { scriptPath: "actual.js", scriptType: "classic", location: { start: { line: 3, column: 0 }, end: { line: 4, column: ' title=">" src=actual.js>'.length }, }, }, ], }); }); it.each([ ['', "actual/"], ['', "actual/"], ['', ""], ['', "actual/"], ['', "actual/"], ])("selects the first real base href from %s", (text, expected) => { expect(htmlArtifactReferences(text).baseHref).toBe(expected); }); it("traverses deep valid document content without recursive stack growth", () => { const depth = 12_000; const text = `${"
".repeat(depth)}${"
".repeat(depth)}`; expect( htmlArtifactReferences(text).scripts.map(({ scriptPath }) => scriptPath), ).toEqual(["actual.js"]); }); it.each([ ["", ["classic"]], ['', ["classic"]], ['', ["classic"]], ['', ["classic"]], ['', ["classic"]], ['', ["classic"]], ['', ["module"]], // Only the JavaScript MIME check strips whitespace; `module` must match. ['', []], ['', []], ["", ["classic"]], // A src attribute, even an empty one, means the browser ignores the body. ['', []], ['', []], ["", []], ['', []], ['', []], ['', []], ['', []], ['', []], ['', []], ["", []], ["", []], ["", ["classic"]], ])("classifies inline JavaScript in %s", (text, expected) => { expect( htmlArtifactReferences(text).inlineScripts.map( ({ scriptType }) => scriptType, ), ).toEqual(expected); }); it.each([ ['src="ignored.js"', "classic"], ['language="vbscript"', "classic"], ['xlink:type="simple"', "classic"], ['type=" Text/JavaScript "', "classic"], ['type="MODULE"', "module"], ['type=" module "', null], ['type="application/json"', null], ['type="text/javascript; charset=utf-8"', null], ['href="external.js"', null], ['href=""', null], ['xlink:href="external.js"', null], ] as const)("classifies SVG inline bodies using %s", (attributes, expected) => { const result = htmlArtifactReferences( ``, ); expect(result.inlineScripts.map(({ scriptType }) => scriptType)).toEqual( expected === null ? [] : [expected], ); expect(result.inlineScriptCount).toBe(expected === null ? 0 : 1); }); it.each([ ['href="external.js"', ["external.js"]], ['xlink:href="external.js"', ["external.js"]], ['href="first.js" xlink:href="second.js"', ["first.js"]], ['xlink:href="second.js" href="first.js"', ["first.js"]], ['href="" xlink:href="ignored.js"', []], ['other:href="ignored.js"', []], ['src="ignored.js"', []], ])("extracts SVG script URL from %s", (attributes, paths) => { const result = htmlArtifactReferences( ``, ); expect(result.scripts.map(({ scriptPath }) => scriptPath)).toEqual(paths); expect(result.inlineScriptCount).toBe(0); }); it("shares precise body coordinates and location limits across HTML and SVG", () => { const prefix = '\n`).inlineScripts, ).toEqual([ { scriptType: "classic", location: { start: { line: 2, column: 30 }, end: { line: 4, column: 0 } }, }, ]); const repeated = "".repeat(60); const result = htmlArtifactReferences(repeated); expect(result.inlineScriptCount).toBe(120); expect(result.inlineScripts).toHaveLength(HTML_INLINE_SCRIPT_LOCATION_LIMIT); expect( htmlArtifactReferences("") .inlineScriptCount, ).toBe(0); }); it("retains exact inline script body coordinates, including unclosed scripts", () => { const prefix = "\n

after

`; expect(htmlArtifactReferences(closed).inlineScripts).toEqual([ { scriptType: "classic", location: { start: { line: 2, column: 8 }, end: { line: 4, column: 0 } }, }, ]); const unclosed = `${prefix}${body}`; expect(htmlArtifactReferences(unclosed).inlineScripts).toEqual([ { scriptType: "classic", location: { start: { line: 2, column: 8 }, end: { line: 4, column: 0 } }, }, ]); }); it("counts every inline body but retains bounded locations", () => { const count = 150_000; const text = "".repeat(count); const { inlineScripts, inlineScriptCount } = htmlArtifactReferences(text); expect(inlineScriptCount).toBe(count); expect(inlineScripts).toHaveLength(HTML_INLINE_SCRIPT_LOCATION_LIMIT); const column = 18 * (HTML_INLINE_SCRIPT_LOCATION_LIMIT - 1) + 8; expect(inlineScripts.at(-1)).toEqual({ scriptType: "classic", location: { start: { line: 1, column }, end: { line: 1, column: column + 1 }, }, }); }); it.each([ ['type=" Text/JavaScript "', "classic"], ['type="MODULE"', "module"], ['type="application/json"', null], ['type="importmap"', null], ['type="speculationrules"', null], ['language="vbscript"', null], ['type=" module "', null], ])( "retains external src with parsed JavaScript type for %s", (attributes, scriptType) => { expect( htmlArtifactReferences(``) .scripts, ).toMatchObject([{ scriptPath: "source.js", scriptType }]); }, );