Release Schema Tools 0.2.0
Verify / verify (push) Canceled after 0s

This commit is contained in:
2026-09-02 08:04:49 +02:00
parent 754608e52b
commit 0c47ec5105
30 changed files with 587 additions and 94 deletions
+75 -2
View File
@@ -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", () => {