mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
fix(javascript): keep empty URL path segments significant (#3792)
* fix(javascript): keep empty URL path segments significant ESM imports and HTML script references were joined with POSIX path rules, which collapse '//' before applying '..'. URL resolution removes the empty segment instead, so './assets//../app.js' names assets/app.js, not app.js, and the graph linked the importer and renderer to the wrong file. URL references refused every '//' even when dot segments cancel it. Resolve ESM, HTML (including document base) and URL references through one URL dot-segment helper. A remaining empty segment stays unavailable, references above the artifact root are still rejected, and CommonJS keeps filesystem path semantics. Fixes #3307 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(javascript): resolve HTML base and reference as one URL path The base href was turned into a canonical path before the script reference was applied. A base empty segment that the reference's '..' would remove was rejected early, and an above-root '..' from the base became a removable segment that the reference's '..' could cancel. Keep one URL path state through base and reference resolution, with above-root escapes held apart from removable segments, and reject empty segments only in the final path. Remove the superseded htmlBaseDirectory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ const paths = [
|
||||
"assets/app.js",
|
||||
"renderer/app.js",
|
||||
"renderer/a/app.js",
|
||||
"renderer/assets/app.js",
|
||||
"app.js",
|
||||
];
|
||||
const files = new Map<string, JavaScriptArtifactFile>(
|
||||
@@ -105,6 +106,26 @@ describe("HTML base href dot segments", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
describe("HTML base href empty segments", () => {
|
||||
it("lets the script reference remove an empty segment from the base", () => {
|
||||
// URL resolution keeps the base's empty segment until `..` removes it.
|
||||
expect(
|
||||
new URL("../app.js", new URL("./assets//", documentUrl)).pathname,
|
||||
).toBe("/renderer/assets/app.js");
|
||||
expect(resolve("../app.js", "./assets//")).toMatchObject({
|
||||
resolution_status: "resolved",
|
||||
resolved_path: "renderer/assets/app.js",
|
||||
});
|
||||
});
|
||||
it("keeps an above-root base escape when the reference also climbs", () => {
|
||||
expect(resolve("../app.js", "../../")).toMatchObject({
|
||||
resolution_status: "rejected",
|
||||
limitations: [
|
||||
"The resolved candidate escapes the canonical artifact root.",
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("HTML base href path syntax", () => {
|
||||
it.each(["%2e%2e/secret/", "/a/%2e%2e/", "/a\\b/", "a\0b"])(
|
||||
"rejects base href %j with the same admission rules a declared path gets",
|
||||
|
||||
Reference in New Issue
Block a user