@sorane/cli 0.2.2 → 0.2.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sorane/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "OKF-native static site generator CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -36,8 +36,8 @@
36
36
  },
37
37
  "prepublishOnly": "cd ../.. && npm run typecheck && npm test",
38
38
  "dependencies": {
39
- "@sorane/core": "0.2.1",
40
- "@sorane/okf": "0.2.0",
39
+ "@sorane/core": "0.2.3",
40
+ "@sorane/okf": "0.2.1",
41
41
  "@sorane/search": "0.2.1",
42
42
  "js-yaml": "^4.1.0",
43
43
  "tsx": "^4.19.0"
package/src/main.ts CHANGED
@@ -37,7 +37,7 @@ async function main(): Promise<void> {
37
37
  "usage: sorane <build|validate|migrate|index|search|watch> [options]\n" +
38
38
  " build --cwd <dir> [--clean] [--watch] [--skip-c2pa]\n" +
39
39
  " watch --cwd <dir> [--clean]\n" +
40
- " validate --cwd <dir>\n" +
40
+ " validate --cwd <dir> [--json]\n" +
41
41
  " migrate --cwd <dir> [--dry-run] [--bump-profile 0.2]\n" +
42
42
  " index --cwd <dir> [--force] [--hybrid] [--fts-only] [--out <path>] [--model <dir>] [--model-id <id>]\n" +
43
43
  " search <query> [--cwd <dir>] [--type article] [--tag <slug>] [--k 10] [--json] [--fts-only]\n",
package/src/validate.ts CHANGED
@@ -1,58 +1,40 @@
1
- import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
- import { join, relative, resolve } from "node:path";
3
- import { validateDiagramAltWarnings, validateHeadingWarnings } from "@sorane/core";
4
- import { extract } from "@sorane/okf";
5
- import { validateSource } from "@sorane/okf";
1
+ import { validateSiteContent } from "@sorane/core";
6
2
  import { loadSoraneConfig, parseCwdFlag } from "./config-load.ts";
7
3
 
8
- function walkMarkdown(root: string): string[] {
9
- const out: string[] = [];
10
- function visit(dir: string): void {
11
- for (const name of readdirSync(dir).sort()) {
12
- const abs = join(dir, name);
13
- if (statSync(abs).isDirectory()) visit(abs);
14
- else if (name.endsWith(".md")) out.push(abs);
4
+ function parseValidateArgs(argv: string[]): { cwd: string; json: boolean } {
5
+ return {
6
+ cwd: parseCwdFlag(argv),
7
+ json: argv.includes("--json"),
8
+ };
9
+ }
10
+
11
+ function writeHumanReport(report: ReturnType<typeof validateSiteContent>): void {
12
+ for (const file of report.files) {
13
+ for (const f of file.findings) {
14
+ const label = f.severity === "error" ? "" : "warning: ";
15
+ process.stderr.write(`[sorane] ${file.file}: ${label}${f.message}\n`);
16
+ }
17
+ }
18
+ if (report.ok) {
19
+ process.stdout.write("[sorane] all concepts valid\n");
20
+ if (report.warning_count > 0) {
21
+ process.stderr.write(`[sorane] ${report.warning_count} warning(s)\n`);
15
22
  }
16
23
  }
17
- visit(root);
18
- return out;
19
24
  }
20
25
 
21
26
  export async function runValidateCmd(argv: string[]): Promise<void> {
22
- const cwd = parseCwdFlag(argv);
27
+ const { cwd, json } = parseValidateArgs(argv);
23
28
  const config = loadSoraneConfig(cwd);
24
- const contentDir = resolve(cwd, config.build.content_dir);
25
- if (!existsSync(contentDir)) {
26
- throw new Error(`content directory not found: ${contentDir}`);
27
- }
29
+ const report = validateSiteContent(cwd, config);
28
30
 
29
- let errors = 0;
30
- for (const abs of walkMarkdown(contentDir)) {
31
- const rel = relative(contentDir, abs);
32
- const source = readFileSync(abs, "utf8");
33
- const result = validateSource(rel, source);
34
- for (const w of result.warnings) {
35
- process.stderr.write(`[sorane] ${rel}: warning: ${w}\n`);
36
- }
37
- const { body } = extract(source);
38
- if (body !== null) {
39
- for (const w of validateDiagramAltWarnings(body, config.build.diagrams ?? {})) {
40
- process.stderr.write(`[sorane] ${rel}: warning: ${w}\n`);
41
- }
42
- for (const w of validateHeadingWarnings(body)) {
43
- process.stderr.write(`[sorane] ${rel}: warning: ${w}\n`);
44
- }
45
- }
46
- if (!result.ok) {
47
- for (const issue of result.issues) {
48
- process.stderr.write(`[sorane] ${rel}: ${issue.message}\n`);
49
- }
50
- errors += result.issues.length;
51
- }
31
+ if (json) {
32
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
33
+ } else {
34
+ writeHumanReport(report);
52
35
  }
53
36
 
54
- if (errors > 0) {
55
- throw new Error(`${errors} validation error(s)`);
37
+ if (!report.ok) {
38
+ throw new Error(`${report.error_count} validation error(s)`);
56
39
  }
57
- process.stdout.write("[sorane] all concepts valid\n");
58
40
  }