mirror of
https://github.com/morluto/rea.git
synced 2026-10-29 02:45:58 +00: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:
1 parent
3ded799bc7
commit
90c6922905
4 files changed
+176
-29
No files matched your search
@@ -2495,20 +2495,61 @@ describe("url-reference directory and empty-segment semantics", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["./nested//worker.js", "./nested//../worker.js"])(
|
||||
"does not collapse empty URL path segments: %s",
|
||||
(declaredPath) => {
|
||||
it.each([
|
||||
["./nested//worker.js", null],
|
||||
["./nested//../worker.js", "dist/nested/worker.js"],
|
||||
])(
|
||||
"keeps empty URL path segments significant: %s",
|
||||
(declaredPath, resolvedPath) => {
|
||||
// A dot segment removes the preceding empty segment, never `nested`.
|
||||
expect(new URL(declaredPath, "file:///root/dist/app.mjs").pathname).toBe(
|
||||
resolvedPath === null
|
||||
? "/root/dist/nested//worker.js"
|
||||
: `/root/${resolvedPath}`,
|
||||
);
|
||||
for (const context of ["url-reference", "html-reference"] as const)
|
||||
expect(
|
||||
resolve({
|
||||
declaredPath,
|
||||
sourcePath: "dist/app.mjs",
|
||||
context,
|
||||
files: fileMap([
|
||||
file("dist/worker.js", "root"),
|
||||
file("dist/nested/worker.js", "root"),
|
||||
]),
|
||||
}),
|
||||
context,
|
||||
).toMatchObject({ resolved_path: resolvedPath });
|
||||
expect(
|
||||
resolve({
|
||||
declaredPath,
|
||||
sourcePath: "dist/app.mjs",
|
||||
context: "url-reference",
|
||||
context: "module-specifier",
|
||||
moduleKind: "import",
|
||||
files: fileMap([
|
||||
file("dist/worker.js", "root"),
|
||||
file("dist/nested/worker.js", "root"),
|
||||
]),
|
||||
}),
|
||||
).toMatchObject({ resolved_path: null });
|
||||
).toMatchObject({ resolved_path: resolvedPath });
|
||||
// CommonJS keeps filesystem path semantics.
|
||||
expect(
|
||||
resolve({
|
||||
declaredPath,
|
||||
sourcePath: "dist/app.mjs",
|
||||
context: "module-specifier",
|
||||
moduleKind: "require",
|
||||
files: fileMap([
|
||||
file("dist/worker.js", "root"),
|
||||
file("dist/nested/worker.js", "root"),
|
||||
]),
|
||||
}),
|
||||
).toMatchObject({
|
||||
resolved_path:
|
||||
declaredPath === "./nested//worker.js"
|
||||
? "dist/nested/worker.js"
|
||||
: "dist/worker.js",
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user