mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(contracts): advertise a v-mode portable Windows absolute-path pattern (#7152)
Use portable hex escapes for Windows absolute-path separators in the shared local path schema. Preserve host path semantics and caller spelling; validate Annex B/u/v compilation and Node win32 agreement. Closes #7151.
This commit is contained in:
1 parent
63417bf3f0
commit
4557791a2e
2 files changed
+42
-15
No files matched your search
@@ -1,22 +1,27 @@
|
|||||||
import { isAbsolute } from "node:path";
|
import { isAbsolute, win32 } from "node:path";
|
||||||
|
|
||||||
import { expect, it } from "vitest";
|
import { expect, it } from "vitest";
|
||||||
|
|
||||||
import { absoluteLocalPathStringSchema } from "./localPath.js";
|
import {
|
||||||
|
absoluteLocalPathStringSchema,
|
||||||
|
windowsAbsolutePathPattern,
|
||||||
|
} from "./localPath.js";
|
||||||
|
|
||||||
|
const PATHS = [
|
||||||
|
"/absolute/path",
|
||||||
|
"/",
|
||||||
|
"relative/path",
|
||||||
|
"C:\\absolute\\path",
|
||||||
|
"c:/absolute/path",
|
||||||
|
"C:relative/path",
|
||||||
|
"\\\\server\\share\\path",
|
||||||
|
"\\rooted\\path",
|
||||||
|
"//server/share/path",
|
||||||
|
"file:///absolute/path",
|
||||||
|
];
|
||||||
|
|
||||||
it("matches the host path module for absolute local paths", () => {
|
it("matches the host path module for absolute local paths", () => {
|
||||||
for (const path of [
|
for (const path of PATHS) {
|
||||||
"/absolute/path",
|
|
||||||
"/",
|
|
||||||
"relative/path",
|
|
||||||
"C:\\absolute\\path",
|
|
||||||
"c:/absolute/path",
|
|
||||||
"C:relative/path",
|
|
||||||
"\\\\server\\share\\path",
|
|
||||||
"\\rooted\\path",
|
|
||||||
"//server/share/path",
|
|
||||||
"file:///absolute/path",
|
|
||||||
]) {
|
|
||||||
expect(absoluteLocalPathStringSchema.safeParse(path).success).toBe(
|
expect(absoluteLocalPathStringSchema.safeParse(path).success).toBe(
|
||||||
isAbsolute(path),
|
isAbsolute(path),
|
||||||
);
|
);
|
||||||
@@ -26,3 +31,17 @@ it("matches the host path module for absolute local paths", () => {
|
|||||||
absoluteLocalPathStringSchema.safeParse("/absolute/with\0nul").success,
|
absoluteLocalPathStringSchema.safeParse("/absolute/with\0nul").success,
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps the Windows absolute-path pattern valid in every client mode", () => {
|
||||||
|
// Annex B and `u` accept an unescaped `/` inside a class; `v` does not, and a
|
||||||
|
// client that compiles advertised patterns rejects the complete tools request.
|
||||||
|
for (const flags of ["", "u", "v"])
|
||||||
|
expect(
|
||||||
|
() => new RegExp(windowsAbsolutePathPattern.source, flags),
|
||||||
|
flags,
|
||||||
|
).not.toThrow();
|
||||||
|
for (const path of PATHS)
|
||||||
|
expect(windowsAbsolutePathPattern.test(path), path).toBe(
|
||||||
|
win32.isAbsolute(path),
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -19,9 +19,17 @@ export const nulFreeStringSchema = z
|
|||||||
/** A selected local filesystem path: nonempty and free of NUL bytes. */
|
/** A selected local filesystem path: nonempty and free of NUL bytes. */
|
||||||
export const localPathStringSchema = nulFreeStringSchema.min(1);
|
export const localPathStringSchema = nulFreeStringSchema.min(1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Windows absolute path: rooted, UNC, or drive-qualified. The classes spell
|
||||||
|
* backslash and slash as `\x5C` and `\x2F` because `v` mode rejects an
|
||||||
|
* unescaped `/` inside a class, and Windows hosts advertise this pattern.
|
||||||
|
*/
|
||||||
|
export const windowsAbsolutePathPattern =
|
||||||
|
/^(?:[\x5C\x2F]|[A-Za-z]:[\x5C\x2F])/u;
|
||||||
|
|
||||||
/** A caller-selected path that is absolute on the host running REA. */
|
/** A caller-selected path that is absolute on the host running REA. */
|
||||||
export const absoluteLocalPathStringSchema = localPathStringSchema.regex(
|
export const absoluteLocalPathStringSchema = localPathStringSchema.regex(
|
||||||
process.platform === "win32" ? /^(?:[\\/]|[A-Za-z]:[\\/])/u : /^\//u,
|
process.platform === "win32" ? windowsAbsolutePathPattern : /^\//u,
|
||||||
"must be an absolute local filesystem path",
|
"must be an absolute local filesystem path",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user