diff --git a/src/crosswalk.ts b/src/crosswalk.ts index 46bffae..1a5bd68 100644 --- a/src/crosswalk.ts +++ b/src/crosswalk.ts @@ -200,6 +200,7 @@ export type OneWayRule = z.infer; export const CrosswalkSchema: z.ZodType & { is: (value: unknown) => value is Crosswalk } = define( z .object({ + $schema: z.string().optional(), source: z.string(), target: z.string(), rules: z.array(TwoWayRuleSchema).default([]), @@ -219,6 +220,8 @@ function keptPath(path: string): MoveRule { return { op: "move", from: path, to: path }; } export interface Crosswalk { + /** The address of the JSON Schema the document declares itself written against, which editors read to validate and complete it. It has no part in encoding, decoding or validation. */ + readonly $schema?: string | undefined; readonly source: string; readonly target: string; readonly rules: readonly TwoWayRule[]; diff --git a/src/crosswalk.unit.test.ts b/src/crosswalk.unit.test.ts index 9f9c983..ab921cc 100644 --- a/src/crosswalk.unit.test.ts +++ b/src/crosswalk.unit.test.ts @@ -157,6 +157,20 @@ describe("parseCrosswalk", () => { }); }); +describe("$schema", () => { + it("is accepted as the address of the document's own schema and carries no rule", () => { + const parsed = parseCrosswalk({ $schema: "https://example.com/crossmap.schema.json", source: "a", target: "b", keep: ["x"] }); + expect(parsed.$schema).toBe("https://example.com/crossmap.schema.json"); + expect(parsed.rules).toEqual([{ op: "move", from: "x", to: "x" }]); + expect(validateCrosswalk(parsed)).toEqual([]); + }); + + it("is optional and must be text", () => { + expect(parseCrosswalk({ source: "a", target: "b" }).$schema).toBeUndefined(); + expect(() => parseCrosswalk({ $schema: 1, source: "a", target: "b" })).toThrow(CrosswalkSyntaxError); + }); +}); + describe("keep", () => { it("reads each kept path as an identity move appended after the rules, in order", () => { const parsed = parseCrosswalk({ source: "a", target: "b", rules: [{ op: "scale", from: "w", to: "weight", factor: 2 }], keep: ["meta", "nodes[].id"] });