@h-rig/validator-kit 0.0.6-alpha.16 → 0.0.6-alpha.161
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/src/checks.d.ts +17 -0
- package/dist/src/checks.js +49 -0
- package/dist/src/content.d.ts +7 -0
- package/dist/src/exec.d.ts +23 -0
- package/dist/src/exec.js +19 -0
- package/dist/src/fs.d.ts +19 -0
- package/dist/src/grep.d.ts +6 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +113 -0
- package/dist/src/result.d.ts +27 -0
- package/dist/src/validator-registry.d.ts +27 -0
- package/dist/src/validator-registry.js +64 -0
- package/package.json +6 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Checker } from "./result";
|
|
2
|
+
import { type RunCommand } from "./exec";
|
|
3
|
+
/** Check a file exists. */
|
|
4
|
+
export declare function requireFileCheck(checker: Checker, path: string, checkName: string): void;
|
|
5
|
+
/** Check a directory exists. */
|
|
6
|
+
export declare function requireDirCheck(checker: Checker, path: string, checkName: string): void;
|
|
7
|
+
/** Validate standard package structure: package.json + tsconfig.json + src/. */
|
|
8
|
+
export declare function requirePackageStructure(checker: Checker, serviceDir: string, prefix: string): void;
|
|
9
|
+
/** Check test files exist in a project directory. */
|
|
10
|
+
export declare function checkTestsExist(checker: Checker, projectDir: string, checkName: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Check that a TypeScript project compiles cleanly (`tsc --noEmit`). Runs the
|
|
13
|
+
* compile through the injectable {@link RunCommand} primitive — the default is
|
|
14
|
+
* exec.ts's minimal Bun.spawn runner; callers may inject a richer runtime
|
|
15
|
+
* runner. Records a pass/fail on the {@link Checker}; never throws.
|
|
16
|
+
*/
|
|
17
|
+
export declare function checkTypescriptCompiles(checker: Checker, projectDir: string, checkName: string, run?: RunCommand): Promise<void>;
|
package/dist/src/checks.js
CHANGED
|
@@ -30,6 +30,22 @@ function countTestFiles(dir) {
|
|
|
30
30
|
return count;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// packages/validator-kit/src/exec.ts
|
|
34
|
+
var runCommand = async (cmd, cwd) => {
|
|
35
|
+
const proc = Bun.spawn([...cmd], {
|
|
36
|
+
cwd,
|
|
37
|
+
stdout: "pipe",
|
|
38
|
+
stderr: "pipe",
|
|
39
|
+
env: { ...process.env, PWD: cwd, INIT_CWD: cwd }
|
|
40
|
+
});
|
|
41
|
+
const exitCode = await proc.exited;
|
|
42
|
+
return {
|
|
43
|
+
exitCode,
|
|
44
|
+
stdout: await new Response(proc.stdout).text(),
|
|
45
|
+
stderr: await new Response(proc.stderr).text()
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
33
49
|
// packages/validator-kit/src/checks.ts
|
|
34
50
|
function requireFileCheck(checker, path, checkName) {
|
|
35
51
|
if (existsSync2(path)) {
|
|
@@ -58,9 +74,42 @@ function checkTestsExist(checker, projectDir, checkName) {
|
|
|
58
74
|
checker.fail(checkName, "no test files found");
|
|
59
75
|
}
|
|
60
76
|
}
|
|
77
|
+
function resolveTypescriptCommand(projectDir) {
|
|
78
|
+
const tsconfigPath = resolve2(projectDir, "tsconfig.json");
|
|
79
|
+
const candidates = [
|
|
80
|
+
resolve2(projectDir, "node_modules", "typescript", "lib", "tsc.js"),
|
|
81
|
+
resolve2(projectDir, "..", "node_modules", "typescript", "lib", "tsc.js"),
|
|
82
|
+
resolve2(projectDir, "..", "..", "node_modules", "typescript", "lib", "tsc.js"),
|
|
83
|
+
resolve2(projectDir, "..", "..", "..", "node_modules", "typescript", "lib", "tsc.js")
|
|
84
|
+
];
|
|
85
|
+
for (const candidate of candidates) {
|
|
86
|
+
if (existsSync2(candidate)) {
|
|
87
|
+
return [process.execPath, candidate, "--noEmit", "--project", tsconfigPath];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return ["bunx", "tsc", "--noEmit", "--project", tsconfigPath];
|
|
91
|
+
}
|
|
92
|
+
async function checkTypescriptCompiles(checker, projectDir, checkName, run = runCommand) {
|
|
93
|
+
if (!existsSync2(resolve2(projectDir, "tsconfig.json"))) {
|
|
94
|
+
checker.fail(checkName, "no tsconfig.json found");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const command = resolveTypescriptCommand(projectDir);
|
|
98
|
+
const result = await run(command, projectDir);
|
|
99
|
+
if (result.exitCode === 0) {
|
|
100
|
+
checker.pass(checkName);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const combined = result.stdout + result.stderr;
|
|
104
|
+
const errorCount = combined.split(`
|
|
105
|
+
`).filter((line) => line.includes("error TS")).length;
|
|
106
|
+
const detail = errorCount > 0 ? `${errorCount} TypeScript errors` : `TypeScript command exited ${result.exitCode} without TS diagnostics`;
|
|
107
|
+
checker.fail(checkName, detail);
|
|
108
|
+
}
|
|
61
109
|
export {
|
|
62
110
|
requirePackageStructure,
|
|
63
111
|
requireFileCheck,
|
|
64
112
|
requireDirCheck,
|
|
113
|
+
checkTypescriptCompiles,
|
|
65
114
|
checkTestsExist
|
|
66
115
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Checker } from "./result";
|
|
2
|
+
/** Check markdown file has section headings matching each term. */
|
|
3
|
+
export declare function requireMarkdownSections(checker: Checker, filePath: string, sections: string[]): void;
|
|
4
|
+
/** Check document contains terms (case-insensitive). Pattern can include | for alternation. */
|
|
5
|
+
export declare function requireTerms(checker: Checker, filePath: string, terms: Record<string, string>): void;
|
|
6
|
+
/** Parse JSON and check key paths exist (dot-separated, e.g. ".summary.total"). */
|
|
7
|
+
export declare function requireJsonKeys(checker: Checker, filePath: string, keys: string[]): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal honest command-runner for validator checks.
|
|
3
|
+
*
|
|
4
|
+
* @rig/validator-kit is floor-neutral (contracts-only deps), so it does NOT
|
|
5
|
+
* depend on @rig/runtime's `resolveBunCli`/build-macro machinery. There is no
|
|
6
|
+
* shared `runCommand` PRIMITIVE for this floor to wire to yet, so this is the
|
|
7
|
+
* minimal honest implementation: a thin Bun.spawn wrapper that captures exit
|
|
8
|
+
* code + stdout + stderr. It is INJECTABLE — every check that needs to run a
|
|
9
|
+
* command accepts a `RunCommand` so a caller (or test) can substitute the
|
|
10
|
+
* runtime's richer runner. When a real shared primitive lands, swap the default.
|
|
11
|
+
*/
|
|
12
|
+
export type RunCommandResult = {
|
|
13
|
+
readonly exitCode: number;
|
|
14
|
+
readonly stdout: string;
|
|
15
|
+
readonly stderr: string;
|
|
16
|
+
};
|
|
17
|
+
export type RunCommand = (cmd: readonly string[], cwd: string) => Promise<RunCommandResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Default runner: spawn the command verbatim and capture output. Honest about
|
|
20
|
+
* its limits — it does not resolve a baked bun path or inject build env; it runs
|
|
21
|
+
* exactly what it is handed. Callers needing that resolution inject their own.
|
|
22
|
+
*/
|
|
23
|
+
export declare const runCommand: RunCommand;
|
package/dist/src/exec.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/validator-kit/src/exec.ts
|
|
3
|
+
var runCommand = async (cmd, cwd) => {
|
|
4
|
+
const proc = Bun.spawn([...cmd], {
|
|
5
|
+
cwd,
|
|
6
|
+
stdout: "pipe",
|
|
7
|
+
stderr: "pipe",
|
|
8
|
+
env: { ...process.env, PWD: cwd, INIT_CWD: cwd }
|
|
9
|
+
});
|
|
10
|
+
const exitCode = await proc.exited;
|
|
11
|
+
return {
|
|
12
|
+
exitCode,
|
|
13
|
+
stdout: await new Response(proc.stdout).text(),
|
|
14
|
+
stderr: await new Response(proc.stderr).text()
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
runCommand
|
|
19
|
+
};
|
package/dist/src/fs.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Return the first existing path from candidates, or null. */
|
|
2
|
+
export declare function findFirstFile(candidates: string[]): string | null;
|
|
3
|
+
/** Read a file as UTF-8 or return null if missing. */
|
|
4
|
+
export declare function readFileSafe(path: string): string | null;
|
|
5
|
+
export declare function requireFile(path: string, id: string, description: string): string;
|
|
6
|
+
/** Check if file content matches a pattern. */
|
|
7
|
+
export declare function fileContains(path: string, pattern: RegExp): boolean;
|
|
8
|
+
/** Walk a directory tree, calling fn for each file. Skips node_modules/.git. */
|
|
9
|
+
export declare function walkDir(dir: string, fn: (filePath: string) => void): void;
|
|
10
|
+
/** List subdirectories of a directory. */
|
|
11
|
+
export declare function listSubdirs(dir: string): string[];
|
|
12
|
+
/** Count .ts files in a directory (excluding tests). */
|
|
13
|
+
export declare function countTsFiles(dir: string): number;
|
|
14
|
+
/** Count test files (.test.ts / .spec.ts) in a directory. */
|
|
15
|
+
export declare function countTestFiles(dir: string): number;
|
|
16
|
+
/** Find first directory matching candidates. */
|
|
17
|
+
export declare function findFirstDir(candidates: string[]): string | null;
|
|
18
|
+
/** Find files by name pattern (glob-free, recursive). */
|
|
19
|
+
export declare function findFilesByName(dir: string, namePattern: RegExp): string[];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Find files whose content matches pattern. Optionally filter by extension. */
|
|
2
|
+
export declare function grepFiles(dir: string, pattern: RegExp, extensions?: string[]): string[];
|
|
3
|
+
/** Count files matching pattern. */
|
|
4
|
+
export declare function grepCount(dir: string, pattern: RegExp, extensions?: string[]): number;
|
|
5
|
+
/** Get matching lines from files in a directory. */
|
|
6
|
+
export declare function grepLines(dir: string, pattern: RegExp, extensions?: string[], maxLines?: number): string[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { ValidatorOutput } from "./result";
|
|
2
|
+
export { pass, fail, error, Checker } from "./result";
|
|
3
|
+
export { findFirstFile, readFileSafe, requireFile, fileContains, walkDir, listSubdirs, countTsFiles, countTestFiles, findFirstDir, findFilesByName, } from "./fs";
|
|
4
|
+
export { grepFiles, grepCount, grepLines } from "./grep";
|
|
5
|
+
export { requireMarkdownSections, requireTerms, requireJsonKeys, } from "./content";
|
|
6
|
+
export { requireFileCheck, requireDirCheck, requirePackageStructure, checkTestsExist, checkTypescriptCompiles, } from "./checks";
|
|
7
|
+
export { runCommand } from "./exec";
|
|
8
|
+
export type { RunCommand, RunCommandResult } from "./exec";
|
|
9
|
+
export { createValidatorRegistry } from "./validator-registry";
|
|
10
|
+
export type { ValidatorResult, ValidatorContext, RegisteredValidator, ValidatorRegistry, } from "./validator-registry";
|
package/dist/src/index.js
CHANGED
|
@@ -233,6 +233,24 @@ function requireJsonKeys(checker, filePath, keys) {
|
|
|
233
233
|
// packages/validator-kit/src/checks.ts
|
|
234
234
|
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
235
235
|
import { resolve as resolve2 } from "path";
|
|
236
|
+
|
|
237
|
+
// packages/validator-kit/src/exec.ts
|
|
238
|
+
var runCommand = async (cmd, cwd) => {
|
|
239
|
+
const proc = Bun.spawn([...cmd], {
|
|
240
|
+
cwd,
|
|
241
|
+
stdout: "pipe",
|
|
242
|
+
stderr: "pipe",
|
|
243
|
+
env: { ...process.env, PWD: cwd, INIT_CWD: cwd }
|
|
244
|
+
});
|
|
245
|
+
const exitCode = await proc.exited;
|
|
246
|
+
return {
|
|
247
|
+
exitCode,
|
|
248
|
+
stdout: await new Response(proc.stdout).text(),
|
|
249
|
+
stderr: await new Response(proc.stderr).text()
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// packages/validator-kit/src/checks.ts
|
|
236
254
|
function requireFileCheck(checker, path, checkName) {
|
|
237
255
|
if (existsSync2(path)) {
|
|
238
256
|
checker.pass(checkName);
|
|
@@ -260,8 +278,101 @@ function checkTestsExist(checker, projectDir, checkName) {
|
|
|
260
278
|
checker.fail(checkName, "no test files found");
|
|
261
279
|
}
|
|
262
280
|
}
|
|
281
|
+
function resolveTypescriptCommand(projectDir) {
|
|
282
|
+
const tsconfigPath = resolve2(projectDir, "tsconfig.json");
|
|
283
|
+
const candidates = [
|
|
284
|
+
resolve2(projectDir, "node_modules", "typescript", "lib", "tsc.js"),
|
|
285
|
+
resolve2(projectDir, "..", "node_modules", "typescript", "lib", "tsc.js"),
|
|
286
|
+
resolve2(projectDir, "..", "..", "node_modules", "typescript", "lib", "tsc.js"),
|
|
287
|
+
resolve2(projectDir, "..", "..", "..", "node_modules", "typescript", "lib", "tsc.js")
|
|
288
|
+
];
|
|
289
|
+
for (const candidate of candidates) {
|
|
290
|
+
if (existsSync2(candidate)) {
|
|
291
|
+
return [process.execPath, candidate, "--noEmit", "--project", tsconfigPath];
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return ["bunx", "tsc", "--noEmit", "--project", tsconfigPath];
|
|
295
|
+
}
|
|
296
|
+
async function checkTypescriptCompiles(checker, projectDir, checkName, run = runCommand) {
|
|
297
|
+
if (!existsSync2(resolve2(projectDir, "tsconfig.json"))) {
|
|
298
|
+
checker.fail(checkName, "no tsconfig.json found");
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const command = resolveTypescriptCommand(projectDir);
|
|
302
|
+
const result = await run(command, projectDir);
|
|
303
|
+
if (result.exitCode === 0) {
|
|
304
|
+
checker.pass(checkName);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const combined = result.stdout + result.stderr;
|
|
308
|
+
const errorCount = combined.split(`
|
|
309
|
+
`).filter((line) => line.includes("error TS")).length;
|
|
310
|
+
const detail = errorCount > 0 ? `${errorCount} TypeScript errors` : `TypeScript command exited ${result.exitCode} without TS diagnostics`;
|
|
311
|
+
checker.fail(checkName, detail);
|
|
312
|
+
}
|
|
313
|
+
// packages/validator-kit/src/validator-registry.ts
|
|
314
|
+
import { existsSync as existsSync3 } from "fs";
|
|
315
|
+
import { join } from "path";
|
|
316
|
+
function createValidatorRegistry() {
|
|
317
|
+
const map = new Map;
|
|
318
|
+
const order = [];
|
|
319
|
+
const registry = {
|
|
320
|
+
register(v) {
|
|
321
|
+
if (map.has(v.id))
|
|
322
|
+
throw new Error(`validator already registered: ${v.id}`);
|
|
323
|
+
map.set(v.id, v);
|
|
324
|
+
order.push(v);
|
|
325
|
+
},
|
|
326
|
+
resolve(id) {
|
|
327
|
+
const v = map.get(id);
|
|
328
|
+
if (!v)
|
|
329
|
+
throw new Error(`validator not registered: ${id}`);
|
|
330
|
+
return v;
|
|
331
|
+
},
|
|
332
|
+
list: () => order
|
|
333
|
+
};
|
|
334
|
+
registerBuiltInValidators(registry);
|
|
335
|
+
return registry;
|
|
336
|
+
}
|
|
337
|
+
function registerBuiltInValidators(registry) {
|
|
338
|
+
registry.register({
|
|
339
|
+
id: "std:typecheck",
|
|
340
|
+
category: "custom",
|
|
341
|
+
description: "Runs the package typecheck script when present.",
|
|
342
|
+
run: async (ctx) => runStdTypecheck(ctx)
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
async function runStdTypecheck(ctx) {
|
|
346
|
+
const packageJsonPath = join(ctx.workspaceRoot, "package.json");
|
|
347
|
+
if (!existsSync3(packageJsonPath)) {
|
|
348
|
+
return {
|
|
349
|
+
id: "std:typecheck",
|
|
350
|
+
passed: false,
|
|
351
|
+
summary: `package.json not found at ${packageJsonPath}`
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
const proc = Bun.spawn(["bun", "run", "typecheck"], {
|
|
355
|
+
cwd: ctx.workspaceRoot,
|
|
356
|
+
env: process.env,
|
|
357
|
+
stdout: "pipe",
|
|
358
|
+
stderr: "pipe"
|
|
359
|
+
});
|
|
360
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
361
|
+
proc.exited,
|
|
362
|
+
new Response(proc.stdout).text(),
|
|
363
|
+
new Response(proc.stderr).text()
|
|
364
|
+
]);
|
|
365
|
+
const output = `${stdout}${stderr}`.trim();
|
|
366
|
+
return {
|
|
367
|
+
id: "std:typecheck",
|
|
368
|
+
passed: exitCode === 0,
|
|
369
|
+
summary: exitCode === 0 ? "typecheck passed" : "typecheck failed",
|
|
370
|
+
...output ? { details: output.slice(0, 4000) } : {}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
263
373
|
export {
|
|
264
374
|
walkDir,
|
|
375
|
+
runCommand,
|
|
265
376
|
requireTerms,
|
|
266
377
|
requirePackageStructure,
|
|
267
378
|
requireMarkdownSections,
|
|
@@ -281,8 +392,10 @@ export {
|
|
|
281
392
|
fileContains,
|
|
282
393
|
fail,
|
|
283
394
|
error,
|
|
395
|
+
createValidatorRegistry,
|
|
284
396
|
countTsFiles,
|
|
285
397
|
countTestFiles,
|
|
398
|
+
checkTypescriptCompiles,
|
|
286
399
|
checkTestsExist,
|
|
287
400
|
Checker
|
|
288
401
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validator output contract and result helpers.
|
|
3
|
+
*
|
|
4
|
+
* Provides the `ValidatorOutput` shape, single-shot exit helpers (`pass`,
|
|
5
|
+
* `fail`, `error`), and the multi-check `Checker` accumulator.
|
|
6
|
+
*
|
|
7
|
+
* Moved from packages/runtime/src/control-plane/validators/shared.ts
|
|
8
|
+
* in Phase 3 Task 3.3 of the Rig extraction.
|
|
9
|
+
*/
|
|
10
|
+
export type ValidatorOutput = {
|
|
11
|
+
id: string;
|
|
12
|
+
passed: boolean;
|
|
13
|
+
summary: string;
|
|
14
|
+
details?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function pass(id: string, summary: string): never;
|
|
17
|
+
export declare function fail(id: string, summary: string, details?: string): never;
|
|
18
|
+
export declare function error(id: string, message: string): never;
|
|
19
|
+
export declare class Checker {
|
|
20
|
+
private results;
|
|
21
|
+
pass(name: string): void;
|
|
22
|
+
fail(name: string, reason: string): void;
|
|
23
|
+
/** Fail and immediately emit — for fatal precondition failures. */
|
|
24
|
+
fatal(id: string, reason: string): never;
|
|
25
|
+
/** Print JSON result and exit. */
|
|
26
|
+
emit(id: string): never;
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ValidatorRegistration } from "@rig/contracts";
|
|
2
|
+
export interface ValidatorResult {
|
|
3
|
+
id: string;
|
|
4
|
+
passed: boolean;
|
|
5
|
+
summary: string;
|
|
6
|
+
details?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ValidatorContext {
|
|
9
|
+
taskId: string;
|
|
10
|
+
workspaceRoot: string;
|
|
11
|
+
scope: readonly string[];
|
|
12
|
+
/** Absolute path to the monorepo checkout root (MONOREPO_ROOT / MONOREPO_MAIN_ROOT env equiv). */
|
|
13
|
+
monorepoRoot?: string;
|
|
14
|
+
/** Absolute path to the task's artifacts output directory (ARTIFACTS_DIR env equiv). */
|
|
15
|
+
artifactsDir?: string;
|
|
16
|
+
/** The full task config entry for this task — opaque to the registry, but available for advanced validators. */
|
|
17
|
+
taskConfig?: unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface RegisteredValidator extends ValidatorRegistration {
|
|
20
|
+
run(ctx: ValidatorContext): Promise<ValidatorResult>;
|
|
21
|
+
}
|
|
22
|
+
export interface ValidatorRegistry {
|
|
23
|
+
register(v: RegisteredValidator): void;
|
|
24
|
+
resolve(id: string): RegisteredValidator;
|
|
25
|
+
list(): readonly RegisteredValidator[];
|
|
26
|
+
}
|
|
27
|
+
export declare function createValidatorRegistry(): ValidatorRegistry;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/validator-kit/src/validator-registry.ts
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
function createValidatorRegistry() {
|
|
6
|
+
const map = new Map;
|
|
7
|
+
const order = [];
|
|
8
|
+
const registry = {
|
|
9
|
+
register(v) {
|
|
10
|
+
if (map.has(v.id))
|
|
11
|
+
throw new Error(`validator already registered: ${v.id}`);
|
|
12
|
+
map.set(v.id, v);
|
|
13
|
+
order.push(v);
|
|
14
|
+
},
|
|
15
|
+
resolve(id) {
|
|
16
|
+
const v = map.get(id);
|
|
17
|
+
if (!v)
|
|
18
|
+
throw new Error(`validator not registered: ${id}`);
|
|
19
|
+
return v;
|
|
20
|
+
},
|
|
21
|
+
list: () => order
|
|
22
|
+
};
|
|
23
|
+
registerBuiltInValidators(registry);
|
|
24
|
+
return registry;
|
|
25
|
+
}
|
|
26
|
+
function registerBuiltInValidators(registry) {
|
|
27
|
+
registry.register({
|
|
28
|
+
id: "std:typecheck",
|
|
29
|
+
category: "custom",
|
|
30
|
+
description: "Runs the package typecheck script when present.",
|
|
31
|
+
run: async (ctx) => runStdTypecheck(ctx)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function runStdTypecheck(ctx) {
|
|
35
|
+
const packageJsonPath = join(ctx.workspaceRoot, "package.json");
|
|
36
|
+
if (!existsSync(packageJsonPath)) {
|
|
37
|
+
return {
|
|
38
|
+
id: "std:typecheck",
|
|
39
|
+
passed: false,
|
|
40
|
+
summary: `package.json not found at ${packageJsonPath}`
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const proc = Bun.spawn(["bun", "run", "typecheck"], {
|
|
44
|
+
cwd: ctx.workspaceRoot,
|
|
45
|
+
env: process.env,
|
|
46
|
+
stdout: "pipe",
|
|
47
|
+
stderr: "pipe"
|
|
48
|
+
});
|
|
49
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
50
|
+
proc.exited,
|
|
51
|
+
new Response(proc.stdout).text(),
|
|
52
|
+
new Response(proc.stderr).text()
|
|
53
|
+
]);
|
|
54
|
+
const output = `${stdout}${stderr}`.trim();
|
|
55
|
+
return {
|
|
56
|
+
id: "std:typecheck",
|
|
57
|
+
passed: exitCode === 0,
|
|
58
|
+
summary: exitCode === 0 ? "typecheck passed" : "typecheck failed",
|
|
59
|
+
...output ? { details: output.slice(0, 4000) } : {}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
createValidatorRegistry
|
|
64
|
+
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/validator-kit",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.161",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Rig
|
|
5
|
+
"description": "Validator schema helpers for Rig plugin contributions; not a validation runtime.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
+
"types": "./dist/src/index.d.ts",
|
|
13
14
|
"import": "./dist/src/index.js"
|
|
14
15
|
}
|
|
15
16
|
},
|
|
@@ -18,8 +19,9 @@
|
|
|
18
19
|
},
|
|
19
20
|
"main": "./dist/src/index.js",
|
|
20
21
|
"module": "./dist/src/index.js",
|
|
22
|
+
"types": "./dist/src/index.d.ts",
|
|
21
23
|
"dependencies": {
|
|
22
|
-
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.
|
|
23
|
-
"effect": "4.0.0-beta.
|
|
24
|
+
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.161",
|
|
25
|
+
"effect": "4.0.0-beta.90"
|
|
24
26
|
}
|
|
25
27
|
}
|