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 { 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", () => {
|
||||
for (const path of [
|
||||
"/absolute/path",
|
||||
"/",
|
||||
"relative/path",
|
||||
"C:\\absolute\\path",
|
||||
"c:/absolute/path",
|
||||
"C:relative/path",
|
||||
"\\\\server\\share\\path",
|
||||
"\\rooted\\path",
|
||||
"//server/share/path",
|
||||
"file:///absolute/path",
|
||||
]) {
|
||||
for (const path of PATHS) {
|
||||
expect(absoluteLocalPathStringSchema.safeParse(path).success).toBe(
|
||||
isAbsolute(path),
|
||||
);
|
||||
@@ -26,3 +31,17 @@ it("matches the host path module for absolute local paths", () => {
|
||||
absoluteLocalPathStringSchema.safeParse("/absolute/with\0nul").success,
|
||||
).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. */
|
||||
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. */
|
||||
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",
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user