@@ -6,6 +6,7 @@ import {
|
||||
inspectWorkspace,
|
||||
parseSchemaDocument,
|
||||
validateJsonInstance,
|
||||
validateJsonInstanceSafe,
|
||||
} from "../../src/schema/model";
|
||||
|
||||
const entry = {
|
||||
@@ -109,6 +110,76 @@ function captureError(run: () => unknown): Error {
|
||||
}
|
||||
|
||||
describe("schema workspace", () => {
|
||||
it("validates pattern and patternProperties through a bounded batch runner", async () => {
|
||||
const workspace = inspectWorkspace([
|
||||
{
|
||||
name: "pattern.schema.json",
|
||||
source: JSON.stringify({
|
||||
type: "object",
|
||||
propertyNames: { pattern: "^[a-z-]+$" },
|
||||
properties: {
|
||||
label: { type: "string", pattern: "^ok(?:-|$)" },
|
||||
},
|
||||
patternProperties: {
|
||||
"^x-": { type: "integer", minimum: 0 },
|
||||
},
|
||||
additionalProperties: false,
|
||||
}),
|
||||
},
|
||||
]);
|
||||
const runner = async (
|
||||
patterns: readonly string[],
|
||||
candidates: readonly string[],
|
||||
) =>
|
||||
new Map(
|
||||
patterns.map((source) => {
|
||||
const expression = new RegExp(source, "u");
|
||||
return [
|
||||
source,
|
||||
new Set(
|
||||
candidates.filter((candidate) => expression.test(candidate)),
|
||||
),
|
||||
] as const;
|
||||
}),
|
||||
);
|
||||
|
||||
expect(
|
||||
(
|
||||
await validateJsonInstanceSafe(
|
||||
workspace,
|
||||
JSON.stringify({ label: "ok-value", "x-count": 2 }),
|
||||
workspace.entry,
|
||||
runner,
|
||||
)
|
||||
).valid,
|
||||
).toBe(true);
|
||||
|
||||
const invalid = await validateJsonInstanceSafe(
|
||||
workspace,
|
||||
JSON.stringify({ label: "bad", "x-count": "two", Other: true }),
|
||||
workspace.entry,
|
||||
runner,
|
||||
);
|
||||
expect(invalid.valid).toBe(false);
|
||||
expect(invalid.diagnostics.map((item) => item.message).join("\n")).toMatch(
|
||||
/pattern.*does not match|type.*integer|additionalProperties|false schema/iu,
|
||||
);
|
||||
});
|
||||
|
||||
it("refuses synchronous regex validation instead of executing on the caller thread", () => {
|
||||
const workspace = inspectWorkspace([
|
||||
{
|
||||
name: "pattern.schema.json",
|
||||
source: JSON.stringify({ type: "string", pattern: "^(a+)+$" }),
|
||||
},
|
||||
]);
|
||||
const result = validateJsonInstance(workspace, JSON.stringify("aaaa"));
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.diagnostics[0]?.message).toMatch(
|
||||
/bounded asynchronous validation|isolated worker/iu,
|
||||
);
|
||||
});
|
||||
|
||||
it("resolves local references, generates a sample, and validates instances", () => {
|
||||
const workspace = inspectWorkspace([entry, support], entry.name);
|
||||
expect(workspace.references).toEqual([
|
||||
@@ -451,7 +522,7 @@ describe("schema workspace", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("refuses executable regex keywords in the bounded validator", () => {
|
||||
it("routes executable regex keywords away from the synchronous validator", () => {
|
||||
const workspace = inspectWorkspace([
|
||||
{
|
||||
name: "pattern.json",
|
||||
@@ -460,7 +531,9 @@ describe("schema workspace", () => {
|
||||
]);
|
||||
const result = validateJsonInstance(workspace, JSON.stringify("aaaa"));
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.diagnostics[0]?.message).toMatch(/pattern.*not executed/iu);
|
||||
expect(result.diagnostics[0]?.message).toMatch(
|
||||
/regular expressions.*bounded asynchronous validation/iu,
|
||||
);
|
||||
});
|
||||
|
||||
it("also refuses regex and dynamic-reference keywords in supplied reference documents", () => {
|
||||
|
||||
Reference in New Issue
Block a user