pi-mono/packages/schema/test/shared.test.ts
Mario Zechner 8ffea8a1bf
Some checks are pending
CI / build-check (push) Waiting to run
CI / test (coding-agent) (push) Waiting to run
CI / test (durable) (push) Waiting to run
CI / test (other) (push) Waiting to run
CI / mcp-conformance (push) Waiting to run
Environments / daemons (push) Waiting to run
Environments / check (push) Blocked by required conditions
Environments / release-daemons (darwin-arm64, macos-latest) (push) Blocked by required conditions
Environments / release-daemons (darwin-x64, macos-latest) (push) Blocked by required conditions
Environments / release-daemons (linux-arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
Environments / release-daemons (linux-x64, ubuntu-latest) (push) Blocked by required conditions
Environments / release-daemons (windows-arm64, windows-11-arm) (push) Blocked by required conditions
Environments / release-daemons (windows-x64, windows-latest) (push) Blocked by required conditions
Environments / tests (macos-latest) (push) Waiting to run
Environments / tests (ubuntu-24.04-arm) (push) Waiting to run
Environments / tests (ubuntu-latest) (push) Waiting to run
Environments / tests (windows-11-arm) (push) Waiting to run
Environments / tests (windows-latest) (push) Waiting to run
feat(schema): faster object checks and compile, less memory
- Declared-object checks walk the value's own keys with for...in, whose
  property reads V8 serves from the enum cache, instead of reading each
  declared name from a list: nested Chord-style arguments 535 -> 409 ns
  (TypeBox 474), recursive $ref schemas 1.1 us -> 753 ns.
- Schemas are indexed for references only on the first $ref; base URIs are
  derived from $id while compiling. Compiling a new schema 43 -> 21 us.
- Drop the keyed cache of leaf checks: on distinct schemas its entries cost
  more than sharing saved. Bare types still share module-level checks and
  patterns share their RegExp. 3,200 distinct schemas 7.9 -> 7.1 MB
  (cfworker 7.6 MB).
2026-10-31 21:59:21 +00:00

42 lines
1.6 KiB
TypeScript

// Values shared across compiled schemas hold nothing alive: a cached pattern goes once its schemas are collected.
import { setFlagsFromString } from "node:v8";
import { runInNewContext } from "node:vm";
import { describe, expect, it } from "vitest";
import { compile } from "../src/index.ts";
import { sharedRegexCount } from "../src/shared.ts";
setFlagsFromString("--expose-gc");
const gc = runInNewContext("gc") as () => void;
async function collectGarbage(): Promise<void> {
for (let round = 0; round < 6; round++) {
await new Promise((resolve) => setImmediate(resolve));
gc();
}
}
describe("shared checks", () => {
it("share the module-level check of a bare type", () => {
const a = compile({ type: "string", description: "a" });
const b = compile({ type: "string", title: "b" });
expect(a.check).toBe(b.check);
});
it("share a pattern's regular expression and drop it with the last schema that uses it", async () => {
await collectGarbage();
const before = sharedRegexCount();
let validators: { check: object }[] | undefined = Array.from({ length: 50 }, (_, i) =>
compile({ type: "string", pattern: `^unique-${i}$` }),
);
const again = compile({ type: "string", pattern: "^unique-0$" });
expect(sharedRegexCount()).toBe(before + 50);
expect(again.check("unique-0")).toBe(true);
const check = new WeakRef(validators[0].check);
validators = undefined;
await collectGarbage();
// `again` still uses ^unique-0$; the other 49 patterns are gone.
expect(check.deref()).toBeUndefined();
expect(sharedRegexCount()).toBe(before + 1);
});
});