mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-13 22:37:29 +00:00
Scaffold LogicSRC and CommandBoard plugins
This commit is contained in:
parent
59927e140c
commit
5c9ea821f6
67 changed files with 5958 additions and 0 deletions
24
packages/validators/package.json
Normal file
24
packages/validators/package.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "@logicsrc/validators",
|
||||
"version": "0.1.0",
|
||||
"description": "LogicSRC schema validation helpers.",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"bin": {
|
||||
"logicsrc-validate": "./dist/cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"test": "vitest run src",
|
||||
"validate:fixtures": "node dist/cli.js task ../schemas/fixtures/task.yaml && node dist/cli.js agent ../schemas/fixtures/agent.yaml"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.17.1",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"yaml": "^2.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitest": "^4.0.8"
|
||||
}
|
||||
}
|
||||
33
packages/validators/src/cli.ts
Normal file
33
packages/validators/src/cli.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env node
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { assertSchemaKind, parseDocument, validate } from "./index.js";
|
||||
|
||||
function main(argv: string[]) {
|
||||
const [, , kindArg, fileArg] = argv;
|
||||
|
||||
if (!kindArg || !fileArg) {
|
||||
console.error("Usage: logicsrc-validate <task|agent|run|event|plugin> <file.yaml|file.json>");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
const kind = assertSchemaKind(kindArg);
|
||||
const filePath = resolve(process.cwd(), fileArg);
|
||||
const input = readFileSync(filePath, "utf8");
|
||||
const data = parseDocument(input, filePath);
|
||||
const result = validate(kind, data);
|
||||
|
||||
if (!result.ok) {
|
||||
console.error(`Invalid LogicSRC ${kind} document: ${filePath}`);
|
||||
for (const error of result.errors) {
|
||||
console.error(`- ${error.instancePath || "/"} ${error.message ?? "failed validation"}`);
|
||||
}
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Valid LogicSRC ${kind} document: ${filePath}`);
|
||||
}
|
||||
|
||||
main(process.argv);
|
||||
28
packages/validators/src/index.test.ts
Normal file
28
packages/validators/src/index.test.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parseDocument, validate } from "./index.js";
|
||||
|
||||
describe("LogicSRC validators", () => {
|
||||
it("validates the task fixture", () => {
|
||||
const testDir = dirname(fileURLToPath(import.meta.url));
|
||||
const file = resolve(testDir, "../../schemas/fixtures/task.yaml");
|
||||
const data = parseDocument(readFileSync(file, "utf8"), file);
|
||||
|
||||
expect(validate("task", data).ok).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects a task without a DID", () => {
|
||||
const result = validate("task", {
|
||||
type: "logicsrc.task",
|
||||
version: "0.1",
|
||||
title: "Missing DID",
|
||||
description: "This should fail.",
|
||||
board: "/qa",
|
||||
status: "open"
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
52
packages/validators/src/index.ts
Normal file
52
packages/validators/src/index.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import * as Ajv2020Module from "ajv/dist/2020.js";
|
||||
import * as addFormatsModule from "ajv-formats";
|
||||
import type { ErrorObject } from "ajv";
|
||||
import { parse } from "yaml";
|
||||
import { isSchemaKind, schemas, type SchemaKind } from "./schemas.js";
|
||||
|
||||
const Ajv2020 = (Ajv2020Module as unknown as { default: new (options: Record<string, unknown>) => { compile: (schema: unknown) => { (data: unknown): boolean; errors?: ErrorObject[] | null } } }).default;
|
||||
const addFormats = (addFormatsModule as unknown as { default: (ajv: InstanceType<typeof Ajv2020>) => void }).default;
|
||||
|
||||
export type ValidationResult =
|
||||
| { ok: true; kind: SchemaKind; data: unknown }
|
||||
| { ok: false; kind: SchemaKind; errors: ErrorObject[] };
|
||||
|
||||
export function createValidator() {
|
||||
const ajv = new Ajv2020({ allErrors: true, strict: true });
|
||||
addFormats(ajv);
|
||||
return ajv;
|
||||
}
|
||||
|
||||
export function parseDocument(input: string, fileName = "document") {
|
||||
if (fileName.endsWith(".json")) {
|
||||
return JSON.parse(input) as unknown;
|
||||
}
|
||||
|
||||
return parse(input) as unknown;
|
||||
}
|
||||
|
||||
export function validate(kind: SchemaKind, data: unknown): ValidationResult {
|
||||
const ajv = createValidator();
|
||||
const validateDocument = ajv.compile(schemas[kind]);
|
||||
const ok = validateDocument(data);
|
||||
|
||||
if (ok) {
|
||||
return { ok: true, kind, data };
|
||||
}
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
kind,
|
||||
errors: validateDocument.errors ?? []
|
||||
};
|
||||
}
|
||||
|
||||
export function assertSchemaKind(value: string): SchemaKind {
|
||||
if (!isSchemaKind(value)) {
|
||||
throw new Error(`Unknown schema kind "${value}". Expected one of: ${Object.keys(schemas).join(", ")}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export { schemas, type SchemaKind };
|
||||
19
packages/validators/src/schemas.ts
Normal file
19
packages/validators/src/schemas.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import agentSchema from "../../schemas/schemas/logicsrc-agent.schema.json" with { type: "json" };
|
||||
import eventSchema from "../../schemas/schemas/logicsrc-event.schema.json" with { type: "json" };
|
||||
import pluginSchema from "../../schemas/schemas/logicsrc-plugin.schema.json" with { type: "json" };
|
||||
import runSchema from "../../schemas/schemas/logicsrc-run.schema.json" with { type: "json" };
|
||||
import taskSchema from "../../schemas/schemas/logicsrc-task.schema.json" with { type: "json" };
|
||||
|
||||
export const schemas = {
|
||||
agent: agentSchema,
|
||||
event: eventSchema,
|
||||
plugin: pluginSchema,
|
||||
run: runSchema,
|
||||
task: taskSchema
|
||||
} as const;
|
||||
|
||||
export type SchemaKind = keyof typeof schemas;
|
||||
|
||||
export function isSchemaKind(value: string): value is SchemaKind {
|
||||
return value in schemas;
|
||||
}
|
||||
8
packages/validators/tsconfig.json
Normal file
8
packages/validators/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue