diff --git a/packages/cli-json-cas/src/cli.test.ts b/packages/cli-json-cas/src/cli.test.ts index 90146d5..65479af 100644 --- a/packages/cli-json-cas/src/cli.test.ts +++ b/packages/cli-json-cas/src/cli.test.ts @@ -597,3 +597,137 @@ describe("Suite 6: CLI Integration with Templates", () => { } }); }); + +// ---- schema put - invalid schema error handling ---- + +describe("schema put - invalid schema error handling", () => { + test("invalid schema - unknown type value shows clean error", async () => { + const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-")); + try { + await runCli(["init"], tmpStore); + + const schemaFile = join(tmpStore, "invalid-schema.json"); + writeFileSync(schemaFile, JSON.stringify({ type: "invalid" })); + + const { exitCode, stderr, stdout } = await runCli( + ["schema", "put", schemaFile], + tmpStore, + ); + + expect(exitCode).not.toBe(0); + expect(stderr).toContain("Invalid schema"); + expect(stderr).not.toContain("at "); + expect(stdout).toBe(""); + } finally { + rmSync(tmpStore, { recursive: true, force: true }); + } + }); + + test("invalid schema - unknown key shows clean error", async () => { + const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-")); + try { + await runCli(["init"], tmpStore); + + const schemaFile = join(tmpStore, "invalid-schema.json"); + writeFileSync( + schemaFile, + JSON.stringify({ type: "string", unknownKey: true }), + ); + + const { exitCode, stderr, stdout } = await runCli( + ["schema", "put", schemaFile], + tmpStore, + ); + + expect(exitCode).not.toBe(0); + expect(stderr).toContain("Invalid schema"); + expect(stderr).not.toContain("at "); + expect(stdout).toBe(""); + } finally { + rmSync(tmpStore, { recursive: true, force: true }); + } + }); + + test("invalid schema - invalid nested schema shows clean error", async () => { + const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-")); + try { + await runCli(["init"], tmpStore); + + const schemaFile = join(tmpStore, "invalid-schema.json"); + writeFileSync( + schemaFile, + JSON.stringify({ + type: "object", + properties: { + name: { type: "invalid" }, + }, + }), + ); + + const { exitCode, stderr, stdout } = await runCli( + ["schema", "put", schemaFile], + tmpStore, + ); + + expect(exitCode).not.toBe(0); + expect(stderr).toContain("Invalid schema"); + expect(stderr).not.toContain("at "); + expect(stdout).toBe(""); + } finally { + rmSync(tmpStore, { recursive: true, force: true }); + } + }); + + test("invalid schema - non-object root shows clean error", async () => { + const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-")); + try { + await runCli(["init"], tmpStore); + + const schemaFile = join(tmpStore, "invalid-schema.json"); + writeFileSync(schemaFile, JSON.stringify(["type", "string"])); + + const { exitCode, stderr, stdout } = await runCli( + ["schema", "put", schemaFile], + tmpStore, + ); + + expect(exitCode).not.toBe(0); + expect(stderr).toContain("Invalid schema"); + expect(stderr).not.toContain("at "); + expect(stdout).toBe(""); + } finally { + rmSync(tmpStore, { recursive: true, force: true }); + } + }); + + test("valid schema still works (regression)", async () => { + const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-")); + try { + await runCli(["init"], tmpStore); + + const schemaFile = join(tmpStore, "valid-schema.json"); + writeFileSync( + schemaFile, + JSON.stringify({ + type: "object", + properties: { + name: { type: "string" }, + age: { type: "number" }, + }, + required: ["name"], + }), + ); + + const { exitCode, stderr, stdout } = await runCli( + ["schema", "put", schemaFile], + tmpStore, + ); + + expect(exitCode).toBe(0); + expect(stderr).toBe(""); + expect(stdout.trim()).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/); + } finally { + rmSync(tmpStore, { recursive: true, force: true }); + } + }); +}); diff --git a/packages/cli-json-cas/src/index.ts b/packages/cli-json-cas/src/index.ts index 51bdf4d..b3e5b8a 100644 --- a/packages/cli-json-cas/src/index.ts +++ b/packages/cli-json-cas/src/index.ts @@ -17,6 +17,7 @@ import { refs, renderAsync, renderDirect, + SchemaValidationError, TagLabelConflictError, VariableNotFoundError, validate, @@ -243,8 +244,15 @@ async function cmdSchemaPut(args: string[]): Promise { if (!file) die("Usage: json-cas schema put "); const schema = readJsonFile(file) as JSONSchema; const store = openStore(); - const hash = await putSchema(store, schema); - console.log(hash); + try { + const hash = await putSchema(store, schema); + console.log(hash); + } catch (e) { + if (e instanceof SchemaValidationError) { + die(e.message); + } + throw e; + } } async function cmdSchemaGet(args: string[]): Promise {