@logicsrc/validators 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { assertSchemaKind, parseDocument, validate } from "./index.js";
5
+ function main(argv) {
6
+ const [, , kindArg, fileArg] = argv;
7
+ if (!kindArg || !fileArg) {
8
+ console.error("Usage: logicsrc-validate <task|agent|run|event|plugin|agentad-ad|agentad-placement|...> <file.yaml|file.json>");
9
+ process.exitCode = 2;
10
+ return;
11
+ }
12
+ const kind = assertSchemaKind(kindArg);
13
+ const filePath = resolve(process.cwd(), fileArg);
14
+ const input = readFileSync(filePath, "utf8");
15
+ const data = parseDocument(input, filePath);
16
+ const result = validate(kind, data);
17
+ if (!result.ok) {
18
+ console.error(`Invalid LogicSRC ${kind} document: ${filePath}`);
19
+ for (const error of result.errors) {
20
+ console.error(`- ${error.instancePath || "/"} ${error.message ?? "failed validation"}`);
21
+ }
22
+ process.exitCode = 1;
23
+ return;
24
+ }
25
+ console.log(`Valid LogicSRC ${kind} document: ${filePath}`);
26
+ }
27
+ main(process.argv);
28
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEvE,SAAS,IAAI,CAAC,IAAc;IAC1B,MAAM,CAAC,EAAE,AAAD,EAAG,OAAO,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAEpC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,+GAA+G,CAAC,CAAC;QAC/H,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAEpC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,IAAI,cAAc,QAAQ,EAAE,CAAC,CAAC;QAChE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,YAAY,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,IAAI,mBAAmB,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,cAAc,QAAQ,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { ErrorObject } from "ajv";
2
+ import { schemas, type SchemaKind } from "./schemas.js";
3
+ export type ValidationResult = {
4
+ ok: true;
5
+ kind: SchemaKind;
6
+ data: unknown;
7
+ } | {
8
+ ok: false;
9
+ kind: SchemaKind;
10
+ errors: ErrorObject[];
11
+ };
12
+ export declare function createValidator(): {
13
+ compile: (schema: unknown) => {
14
+ (data: unknown): boolean;
15
+ errors?: ErrorObject[] | null;
16
+ };
17
+ };
18
+ export declare function parseDocument(input: string, fileName?: string): unknown;
19
+ export declare function validate(kind: SchemaKind, data: unknown): ValidationResult;
20
+ export declare function assertSchemaKind(value: string): SchemaKind;
21
+ export { schemas, type SchemaKind };
package/dist/index.js ADDED
@@ -0,0 +1,45 @@
1
+ import * as Ajv2020Module from "ajv/dist/2020.js";
2
+ import * as addFormatsModule from "ajv-formats";
3
+ import { parse } from "yaml";
4
+ import { isSchemaKind, schemas } from "./schemas.js";
5
+ const Ajv2020 = Ajv2020Module.default;
6
+ const addFormats = addFormatsModule.default;
7
+ export function createValidator() {
8
+ const ajv = new Ajv2020({ allErrors: true, strict: true });
9
+ addFormats(ajv);
10
+ return ajv;
11
+ }
12
+ const _ajv = createValidator();
13
+ const _compiledValidators = new Map();
14
+ function getCompiledValidator(kind) {
15
+ if (!_compiledValidators.has(kind)) {
16
+ _compiledValidators.set(kind, _ajv.compile(schemas[kind]));
17
+ }
18
+ return _compiledValidators.get(kind);
19
+ }
20
+ export function parseDocument(input, fileName = "document") {
21
+ if (fileName.toLowerCase().endsWith(".json")) {
22
+ return JSON.parse(input);
23
+ }
24
+ return parse(input);
25
+ }
26
+ export function validate(kind, data) {
27
+ const validateDocument = getCompiledValidator(kind);
28
+ const ok = validateDocument(data);
29
+ if (ok) {
30
+ return { ok: true, kind, data };
31
+ }
32
+ return {
33
+ ok: false,
34
+ kind,
35
+ errors: validateDocument.errors ?? []
36
+ };
37
+ }
38
+ export function assertSchemaKind(value) {
39
+ if (!isSchemaKind(value)) {
40
+ throw new Error(`Unknown schema kind "${value}". Expected one of: ${Object.keys(schemas).join(", ")}`);
41
+ }
42
+ return value;
43
+ }
44
+ export { schemas };
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,gBAAgB,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAmB,MAAM,cAAc,CAAC;AAEtE,MAAM,OAAO,GAAI,aAAiL,CAAC,OAAO,CAAC;AAC3M,MAAM,UAAU,GAAI,gBAAwF,CAAC,OAAO,CAAC;AAMrH,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,UAAU,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;AAC/B,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA+C,CAAC;AAEnF,SAAS,oBAAoB,CAAC,IAAgB;IAC5C,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,QAAQ,GAAG,UAAU;IAChE,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAY,CAAC;IACtC,CAAC;IAED,OAAO,KAAK,CAAC,KAAK,CAAY,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAgB,EAAE,IAAa;IACtD,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAElC,IAAI,EAAE,EAAE,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAClC,CAAC;IAED,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI;QACJ,MAAM,EAAE,gBAAgB,CAAC,MAAM,IAAI,EAAE;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,uBAAuB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzG,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,OAAO,EAAE,OAAO,EAAmB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { describe, expect, it } from "vitest";
5
+ import { assertSchemaKind, parseDocument, schemas, validate } from "./index.js";
6
+ import { isSchemaKind } from "./schemas.js";
7
+ describe("LogicSRC validators", () => {
8
+ it("validates the task fixture", () => {
9
+ const testDir = dirname(fileURLToPath(import.meta.url));
10
+ const file = resolve(testDir, "../../schemas/fixtures/task.yaml");
11
+ const data = parseDocument(readFileSync(file, "utf8"), file);
12
+ expect(validate("task", data).ok).toBe(true);
13
+ });
14
+ it("parses JSON files case-insensitively by extension", () => {
15
+ expect(parseDocument('{"ok":true}', "TASK.JSON")).toEqual({ ok: true });
16
+ });
17
+ it("rejects a task without a DID", () => {
18
+ const result = validate("task", {
19
+ type: "logicsrc.task",
20
+ version: "0.1",
21
+ title: "Missing DID",
22
+ description: "This should fail.",
23
+ board: "/qa",
24
+ status: "open"
25
+ });
26
+ expect(result.ok).toBe(false);
27
+ });
28
+ it("validates the AgentAd ad fixture", () => {
29
+ const testDir = dirname(fileURLToPath(import.meta.url));
30
+ const file = resolve(testDir, "../../schemas/fixtures/agentad-ad.yaml");
31
+ const data = parseDocument(readFileSync(file, "utf8"), file);
32
+ expect(validate("agentad-ad", data).ok).toBe(true);
33
+ });
34
+ it("rejects an AgentAd ad that is not disclosed as sponsored", () => {
35
+ const result = validate("agentad-ad", {
36
+ type: "agentad.ad",
37
+ version: "0.1",
38
+ id: "undisclosed",
39
+ advertiser_did: "acme.coinpay",
40
+ format: "text",
41
+ title: "Buy now",
42
+ url: "https://example.com",
43
+ disclosure: { sponsored: false, label: "Sponsored" }
44
+ });
45
+ expect(result.ok).toBe(false);
46
+ });
47
+ });
48
+ describe("isSchemaKind / assertSchemaKind prototype safety", () => {
49
+ it("rejects inherited Object.prototype keys", () => {
50
+ for (const key of ["toString", "constructor", "valueOf", "hasOwnProperty"]) {
51
+ expect(isSchemaKind(key)).toBe(false);
52
+ expect(() => assertSchemaKind(key)).toThrow(/Unknown schema kind/);
53
+ }
54
+ });
55
+ it("still accepts every real schema kind", () => {
56
+ for (const key of Object.keys(schemas)) {
57
+ expect(isSchemaKind(key)).toBe(true);
58
+ expect(assertSchemaKind(key)).toBe(key);
59
+ }
60
+ });
61
+ });
62
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}