qfai 0.2.5

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.
Files changed (120) hide show
  1. package/README.md +28 -0
  2. package/assets/init/qfai/README.md +6 -0
  3. package/assets/init/qfai/contracts/api/api-0001-sample.yaml +14 -0
  4. package/assets/init/qfai/contracts/db/db-0001-sample.sql +5 -0
  5. package/assets/init/qfai/contracts/ui/ui-0001-sample.yaml +4 -0
  6. package/assets/init/qfai/prompts/makeBusinessFlow.md +34 -0
  7. package/assets/init/qfai/prompts/makeOverview.md +27 -0
  8. package/assets/init/qfai/spec/decisions/ADR-0001.md +7 -0
  9. package/assets/init/qfai/spec/scenarios.feature +6 -0
  10. package/assets/init/qfai/spec/spec-0001-sample.md +29 -0
  11. package/assets/init/root/.github/workflows/qfai.yml +22 -0
  12. package/assets/init/root/qfai.config.yaml +29 -0
  13. package/dist/cli/commands/init.d.ts +8 -0
  14. package/dist/cli/commands/init.d.ts.map +1 -0
  15. package/dist/cli/commands/init.js +30 -0
  16. package/dist/cli/commands/init.js.map +1 -0
  17. package/dist/cli/commands/report.d.ts +8 -0
  18. package/dist/cli/commands/report.d.ts.map +1 -0
  19. package/dist/cli/commands/report.js +83 -0
  20. package/dist/cli/commands/report.js.map +1 -0
  21. package/dist/cli/commands/validate.d.ts +10 -0
  22. package/dist/cli/commands/validate.d.ts.map +1 -0
  23. package/dist/cli/commands/validate.js +66 -0
  24. package/dist/cli/commands/validate.js.map +1 -0
  25. package/dist/cli/index.cjs +2003 -0
  26. package/dist/cli/index.cjs.map +1 -0
  27. package/dist/cli/index.d.cts +1 -0
  28. package/dist/cli/index.d.ts +3 -0
  29. package/dist/cli/index.d.ts.map +1 -0
  30. package/dist/cli/index.js +7 -0
  31. package/dist/cli/index.js.map +1 -0
  32. package/dist/cli/index.mjs +1980 -0
  33. package/dist/cli/index.mjs.map +1 -0
  34. package/dist/cli/lib/args.d.ts +19 -0
  35. package/dist/cli/lib/args.d.ts.map +1 -0
  36. package/dist/cli/lib/args.js +107 -0
  37. package/dist/cli/lib/args.js.map +1 -0
  38. package/dist/cli/lib/assets.d.ts +2 -0
  39. package/dist/cli/lib/assets.d.ts.map +1 -0
  40. package/dist/cli/lib/assets.js +8 -0
  41. package/dist/cli/lib/assets.js.map +1 -0
  42. package/dist/cli/lib/failOn.d.ts +5 -0
  43. package/dist/cli/lib/failOn.d.ts.map +1 -0
  44. package/dist/cli/lib/failOn.js +10 -0
  45. package/dist/cli/lib/failOn.js.map +1 -0
  46. package/dist/cli/lib/fs.d.ts +11 -0
  47. package/dist/cli/lib/fs.d.ts.map +1 -0
  48. package/dist/cli/lib/fs.js +91 -0
  49. package/dist/cli/lib/fs.js.map +1 -0
  50. package/dist/cli/lib/logger.d.ts +4 -0
  51. package/dist/cli/lib/logger.d.ts.map +1 -0
  52. package/dist/cli/lib/logger.js +10 -0
  53. package/dist/cli/lib/logger.js.map +1 -0
  54. package/dist/cli/main.d.ts +2 -0
  55. package/dist/cli/main.d.ts.map +1 -0
  56. package/dist/cli/main.js +73 -0
  57. package/dist/cli/main.js.map +1 -0
  58. package/dist/core/config.d.ts +46 -0
  59. package/dist/core/config.d.ts.map +1 -0
  60. package/dist/core/config.js +224 -0
  61. package/dist/core/config.js.map +1 -0
  62. package/dist/core/discovery.d.ts +11 -0
  63. package/dist/core/discovery.d.ts.map +1 -0
  64. package/dist/core/discovery.js +31 -0
  65. package/dist/core/discovery.js.map +1 -0
  66. package/dist/core/fs.d.ts +6 -0
  67. package/dist/core/fs.d.ts.map +1 -0
  68. package/dist/core/fs.js +55 -0
  69. package/dist/core/fs.js.map +1 -0
  70. package/dist/core/ids.d.ts +5 -0
  71. package/dist/core/ids.d.ts.map +1 -0
  72. package/dist/core/ids.js +49 -0
  73. package/dist/core/ids.js.map +1 -0
  74. package/dist/core/index.d.ts +11 -0
  75. package/dist/core/index.d.ts.map +1 -0
  76. package/dist/core/index.js +11 -0
  77. package/dist/core/index.js.map +1 -0
  78. package/dist/core/report.d.ts +41 -0
  79. package/dist/core/report.d.ts.map +1 -0
  80. package/dist/core/report.js +238 -0
  81. package/dist/core/report.js.map +1 -0
  82. package/dist/core/types.d.ts +27 -0
  83. package/dist/core/types.d.ts.map +1 -0
  84. package/dist/core/types.js +2 -0
  85. package/dist/core/types.js.map +1 -0
  86. package/dist/core/validate.d.ts +4 -0
  87. package/dist/core/validate.d.ts.map +1 -0
  88. package/dist/core/validate.js +32 -0
  89. package/dist/core/validate.js.map +1 -0
  90. package/dist/core/validators/contracts.d.ts +5 -0
  91. package/dist/core/validators/contracts.d.ts.map +1 -0
  92. package/dist/core/validators/contracts.js +157 -0
  93. package/dist/core/validators/contracts.js.map +1 -0
  94. package/dist/core/validators/scenario.d.ts +5 -0
  95. package/dist/core/validators/scenario.d.ts.map +1 -0
  96. package/dist/core/validators/scenario.js +82 -0
  97. package/dist/core/validators/scenario.js.map +1 -0
  98. package/dist/core/validators/spec.d.ts +5 -0
  99. package/dist/core/validators/spec.d.ts.map +1 -0
  100. package/dist/core/validators/spec.js +69 -0
  101. package/dist/core/validators/spec.js.map +1 -0
  102. package/dist/core/validators/traceability.d.ts +4 -0
  103. package/dist/core/validators/traceability.d.ts.map +1 -0
  104. package/dist/core/validators/traceability.js +148 -0
  105. package/dist/core/validators/traceability.js.map +1 -0
  106. package/dist/core/version.d.ts +2 -0
  107. package/dist/core/version.d.ts.map +1 -0
  108. package/dist/core/version.js +25 -0
  109. package/dist/core/version.js.map +1 -0
  110. package/dist/index.cjs +1579 -0
  111. package/dist/index.cjs.map +1 -0
  112. package/dist/index.d.cts +132 -0
  113. package/dist/index.d.ts +2 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +2 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/index.mjs +1523 -0
  118. package/dist/index.mjs.map +1 -0
  119. package/dist/tsconfig.tsbuildinfo +1 -0
  120. package/package.json +38 -0
package/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # QFAI Toolkit (v0.2.5)
2
+
3
+ Single-package distribution for QFAI.
4
+
5
+ ## Install
6
+
7
+ ```
8
+ npm i -D qfai
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```
14
+ npx qfai init
15
+ npx qfai validate --fail-on error --format github --json-path .qfai/out/validate.json
16
+ npx qfai report --json-path .qfai/out/validate.json --out .qfai/out/report.md
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ `validate` は `--fail-on` / `--strict` によって CI ゲート化できます。
22
+ JSON 出力は `--json-path` 指定、または `qfai.config.yaml` の `output.format: json` で有効化できます。
23
+ `report` は `validate.json` が必須で、未生成の場合は exit code 2 で次の手順を案内します。
24
+ `report` の入力は `--json-path` が優先で、未指定の場合は `output.jsonPath` を使います。どちらも未設定の場合はレポートを生成できないため、いずれかを必ず指定してください。既定の出力は `.qfai/out/report.md`(`--format json` の場合は `.qfai/out/report.json`)です。
25
+ `init --yes` は非対話でデフォルトを採用します(現状の init は非対話が既定のため挙動は同じです。将来対話が導入されても自動で承認されます)。既存ファイルがある場合は `--force` が必要です。
26
+
27
+ 設定はリポジトリ直下の `qfai.config.yaml` で行います。
28
+ 命名規約は `docs/rules/naming.md` を参照してください。
@@ -0,0 +1,6 @@
1
+ # QFAI Project Kit
2
+
3
+ This directory contains QFAI specs and contracts.
4
+
5
+ - 設定ファイル: qfai.config.yaml(リポジトリ直下)
6
+ - CI テンプレ: .github/workflows/qfai.yml
@@ -0,0 +1,14 @@
1
+ openapi: 3.0.0
2
+ info:
3
+ title: QFAI Sample API
4
+ version: 0.1.0
5
+ paths:
6
+ /health:
7
+ get:
8
+ operationId: API-0001
9
+ x-qfai-refs:
10
+ - BR-0001
11
+ - SC-0001
12
+ responses:
13
+ "200":
14
+ description: OK
@@ -0,0 +1,5 @@
1
+ -- DATA-0001
2
+ CREATE TABLE sample_table (
3
+ id INTEGER PRIMARY KEY,
4
+ name VARCHAR(255) NOT NULL
5
+ );
@@ -0,0 +1,4 @@
1
+ id: UI-0001
2
+ name: Sample Screen
3
+ refs:
4
+ - BR-0001
@@ -0,0 +1,34 @@
1
+ # makeBusinessFlow
2
+
3
+ あなたは業務フロー(Business Flow: BF)を“推測せず”に整理するアシスタントです。
4
+ Spec群を読み、Specに明示されている情報のみを根拠として、代表的な業務フロー候補と、ステップ→Specの対応表を作成してください。
5
+
6
+ ## Inputs
7
+
8
+ - 対象: qfai/spec/spec.md と qfai/spec/spec-0001-\*.md 形式のファイル(4 桁の数字 + ハイフン + slug。実際のパターン: `spec-\d{4}-[^/\\]+\.md`。存在するもの全て)
9
+
10
+ ## Output (Option)
11
+
12
+ - docs/flows/overview.md(BF一覧)
13
+ - docs/flows/bf-0001-<slug>.md 等(個別BF)
14
+
15
+ ## Hard Rules
16
+
17
+ - Specに書かれていない業務フローを“創作”しない。
18
+ - 根拠が薄い場合は候補として列挙し `TBD` を付ける。
19
+ - BFの各ステップは必ず SPEC-ID に紐づける。
20
+ - BR/SC/UI/API/DB の参照は Spec に書かれているもののみ。
21
+
22
+ ## BF Document Format (per BF)
23
+
24
+ - BF-ID / Title
25
+ - Scope(開始条件/終了条件)
26
+ - Actors(登場人物)
27
+ - Steps(番号付き): step → SPEC-ID → 一行説明
28
+ - Related BR / SC
29
+ - Open Questions(TBD列挙)
30
+
31
+ ## Safety
32
+
33
+ - 既存ファイルがある場合は、`<!-- qfai:generated:start -->` と `<!-- qfai:generated:end -->` の範囲だけ更新。
34
+ - それ以外の手書き領域は絶対に変更しない。
@@ -0,0 +1,27 @@
1
+ # makeOverview
2
+
3
+ あなたはドキュメント生成アシスタントです。リポジトリ内の Spec を走査し、Spec一覧(overview)を生成してください。
4
+
5
+ ## Inputs
6
+
7
+ - 対象: qfai/spec/spec.md と qfai/spec/spec-0001-\*.md 形式のファイル(4 桁の数字 + ハイフン + slug。実際のパターン: `spec-\d{4}-[^/\\]+\.md`。存在するもの全て)
8
+
9
+ ## Output
10
+
11
+ - docs/specs/overview.md を更新
12
+ - 更新は必ず次の範囲のみ:
13
+ - <!-- qfai:generated:start -->
14
+ - <!-- qfai:generated:end -->
15
+
16
+ ## Rules
17
+
18
+ - Spec本文に書かれていないことは推測しない(不明は `TBD` と書く)。
19
+ - SpecのIDとタイトルは、本文先頭の `# SPEC-xxxx ...` を正とし、ファイル名は補助。
20
+ - 各Specについて最低限以下を表にする:
21
+ - SPEC-ID / Title / Outcome(1行) / Status / SC / UI / API / DB(or DATA) / Tags
22
+ - 参照が欠けている場合(例: SCが未記載)は “欠落一覧” に列挙する。
23
+
24
+ ## Format
25
+
26
+ - Markdown table
27
+ - 生成日時(JST)と、参照したSpecファイル一覧を末尾に付記する。
@@ -0,0 +1,7 @@
1
+ # ADR-0001: Sample Decision
2
+
3
+ - Status: Proposed
4
+ - Context:
5
+ - Decision:
6
+ - Consequences:
7
+ - Related: BR-0001, SPEC-0001
@@ -0,0 +1,6 @@
1
+ @SC-0001 @BR-0001 @SPEC-0001 @UI-0001 @API-0001 @DATA-0001
2
+ Feature: Sample flow
3
+ Scenario: Basic scenario
4
+ Given ...
5
+ When ...
6
+ Then ...
@@ -0,0 +1,29 @@
1
+ # SPEC-0001: Sample Spec
2
+
3
+ ## 背景
4
+
5
+ - ...
6
+
7
+ ## スコープ
8
+
9
+ - ...
10
+
11
+ ## 非ゴール
12
+
13
+ - ...
14
+
15
+ ## 用語
16
+
17
+ - ...
18
+
19
+ ## 前提
20
+
21
+ - ...
22
+
23
+ ## 決定事項
24
+
25
+ - ...
26
+
27
+ ## 業務ルール
28
+
29
+ - [BR-0001] ...
@@ -0,0 +1,22 @@
1
+ name: qfai
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ validate:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-node@v4
14
+ with:
15
+ node-version: 20
16
+ cache: npm
17
+ - run: npm ci
18
+ - run: npx qfai validate --fail-on error --format github --json-path .qfai/out/validate.json
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: qfai-validation
22
+ path: .qfai/out/validate.json
@@ -0,0 +1,29 @@
1
+ paths:
2
+ specDir: qfai/spec
3
+ decisionsDir: qfai/spec/decisions
4
+ scenariosDir: qfai/spec
5
+ rulesDir: qfai/rules
6
+ contractsDir: qfai/contracts
7
+ uiContractsDir: qfai/contracts/ui
8
+ apiContractsDir: qfai/contracts/api
9
+ dataContractsDir: qfai/contracts/db
10
+ srcDir: src
11
+ testsDir: tests
12
+ validation:
13
+ failOn: error
14
+ require:
15
+ specSections:
16
+ - 背景
17
+ - スコープ
18
+ - 非ゴール
19
+ - 用語
20
+ - 前提
21
+ - 決定事項
22
+ - 業務ルール
23
+ traceability:
24
+ brMustHaveSc: true
25
+ scMustTouchContracts: true
26
+ allowOrphanContracts: false
27
+ output:
28
+ format: text
29
+ jsonPath: .qfai/out/validate.json
@@ -0,0 +1,8 @@
1
+ export type InitOptions = {
2
+ dir: string;
3
+ force: boolean;
4
+ dryRun: boolean;
5
+ yes: boolean;
6
+ };
7
+ export declare function runInit(options: InitOptions): Promise<void>;
8
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBjE"}
@@ -0,0 +1,30 @@
1
+ import path from "node:path";
2
+ import { copyTemplateTree } from "../lib/fs.js";
3
+ import { getInitAssetsDir } from "../lib/assets.js";
4
+ import { info } from "../lib/logger.js";
5
+ export async function runInit(options) {
6
+ const assetsRoot = getInitAssetsDir();
7
+ const rootAssets = path.join(assetsRoot, "root");
8
+ const qfaiAssets = path.join(assetsRoot, "qfai");
9
+ const destRoot = path.resolve(options.dir);
10
+ const destQfai = path.join(destRoot, "qfai");
11
+ const rootResult = await copyTemplateTree(rootAssets, destRoot, {
12
+ force: options.force,
13
+ dryRun: options.dryRun,
14
+ });
15
+ const qfaiResult = await copyTemplateTree(qfaiAssets, destQfai, {
16
+ force: options.force,
17
+ dryRun: options.dryRun,
18
+ });
19
+ report([...rootResult.copied, ...qfaiResult.copied], [...rootResult.skipped, ...qfaiResult.skipped], options.dryRun, "init");
20
+ }
21
+ function report(copied, skipped, dryRun, label) {
22
+ info(`qfai ${label}: ${dryRun ? "dry-run" : "done"}`);
23
+ if (copied.length > 0) {
24
+ info(` created: ${copied.length}`);
25
+ }
26
+ if (skipped.length > 0) {
27
+ info(` skipped: ${skipped.length}`);
28
+ }
29
+ }
30
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AASxC,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAoB;IAChD,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAEjD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAE7C,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE;QAC9D,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE;QAC9D,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,MAAM,CACJ,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,EAC5C,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,EAC9C,OAAO,CAAC,MAAM,EACd,MAAM,CACP,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CACb,MAAgB,EAChB,OAAiB,EACjB,MAAe,EACf,KAAa;IAEb,IAAI,CAAC,QAAQ,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACtD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,cAAc,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,cAAc,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ export type ReportOptions = {
2
+ root: string;
3
+ format: "md" | "json";
4
+ jsonPath?: string;
5
+ outPath?: string;
6
+ };
7
+ export declare function runReport(options: ReportOptions): Promise<void>;
8
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/report.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA4CrE"}
@@ -0,0 +1,83 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { loadConfig } from "../../core/config.js";
4
+ import { createReportData, formatReportJson, formatReportMarkdown, } from "../../core/report.js";
5
+ import { VALIDATION_SCHEMA_VERSION, } from "../../core/types.js";
6
+ import { error, info } from "../lib/logger.js";
7
+ export async function runReport(options) {
8
+ const root = path.resolve(options.root);
9
+ const configResult = await loadConfig(root);
10
+ const input = options.jsonPath ?? configResult.config.output.jsonPath;
11
+ const inputPath = path.isAbsolute(input) ? input : path.resolve(root, input);
12
+ let validation;
13
+ try {
14
+ validation = await readValidationResult(inputPath);
15
+ }
16
+ catch (err) {
17
+ if (isMissingFileError(err)) {
18
+ error([
19
+ `qfai report: 入力ファイルが見つかりません: ${inputPath}`,
20
+ "",
21
+ "まず validate.json を生成してください。例:",
22
+ ` qfai validate --json-path ${input}`,
23
+ "",
24
+ "GitHub Actions テンプレを使っている場合は、workflow の validate ジョブを先に実行してください。",
25
+ ].join("\n"));
26
+ process.exitCode = 2;
27
+ return;
28
+ }
29
+ throw err;
30
+ }
31
+ const data = await createReportData(root, validation, configResult);
32
+ const output = options.format === "json"
33
+ ? formatReportJson(data)
34
+ : formatReportMarkdown(data);
35
+ const defaultOut = options.format === "json" ? ".qfai/out/report.json" : ".qfai/out/report.md";
36
+ const out = options.outPath ?? defaultOut;
37
+ const outPath = path.isAbsolute(out) ? out : path.resolve(root, out);
38
+ await mkdir(path.dirname(outPath), { recursive: true });
39
+ await writeFile(outPath, `${output}\n`, "utf-8");
40
+ info(`report: info=${validation.counts.info} warning=${validation.counts.warning} error=${validation.counts.error}`);
41
+ info(`wrote report: ${outPath}`);
42
+ }
43
+ async function readValidationResult(inputPath) {
44
+ const raw = await readFile(inputPath, "utf-8");
45
+ const parsed = JSON.parse(raw);
46
+ if (!isValidationResult(parsed)) {
47
+ throw new Error(`validate.json の形式が不正です: ${inputPath}`);
48
+ }
49
+ if (parsed.schemaVersion !== VALIDATION_SCHEMA_VERSION) {
50
+ throw new Error(`validate.json の schemaVersion が不一致です: expected ${VALIDATION_SCHEMA_VERSION}, actual ${parsed.schemaVersion}`);
51
+ }
52
+ return parsed;
53
+ }
54
+ function isValidationResult(value) {
55
+ if (!value || typeof value !== "object") {
56
+ return false;
57
+ }
58
+ const record = value;
59
+ if (typeof record.schemaVersion !== "string") {
60
+ return false;
61
+ }
62
+ if (typeof record.toolVersion !== "string") {
63
+ return false;
64
+ }
65
+ if (!Array.isArray(record.issues)) {
66
+ return false;
67
+ }
68
+ const counts = record.counts;
69
+ if (!counts) {
70
+ return false;
71
+ }
72
+ return (typeof counts.info === "number" &&
73
+ typeof counts.warning === "number" &&
74
+ typeof counts.error === "number");
75
+ }
76
+ function isMissingFileError(error) {
77
+ if (!error || typeof error !== "object") {
78
+ return false;
79
+ }
80
+ const record = error;
81
+ return record.code === "ENOENT";
82
+ }
83
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/cli/commands/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,yBAAyB,GAE1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAS/C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAsB;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,YAAY,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;IACtE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7E,IAAI,UAA4B,CAAC;IACjC,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,oBAAoB,CAAC,SAAS,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,CACH;gBACE,gCAAgC,SAAS,EAAE;gBAC3C,EAAE;gBACF,+BAA+B;gBAC/B,+BAA+B,KAAK,EAAE;gBACtC,EAAE;gBACF,kEAAkE;aACnE,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IACpE,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,KAAK,MAAM;QACvB,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC;QACxB,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAEjC,MAAM,UAAU,GACd,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,qBAAqB,CAAC;IAC9E,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAErE,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,SAAS,CAAC,OAAO,EAAE,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC,CAAC;IAEjD,IAAI,CACF,gBAAgB,UAAU,CAAC,MAAM,CAAC,IAAI,YAAY,UAAU,CAAC,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAC/G,CAAC;IACF,IAAI,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,SAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;IAC1C,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,2BAA2B,SAAS,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,aAAa,KAAK,yBAAyB,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CACb,kDAAkD,yBAAyB,YAAY,MAAM,CAAC,aAAa,EAAE,CAC9G,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,IAAI,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAA6C,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CACL,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;QAClC,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CACjC,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAAG,KAA0B,CAAC;IAC1C,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;AAClC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { FailOn, OutputFormat } from "../../core/config.js";
2
+ export type ValidateOptions = {
3
+ root: string;
4
+ strict: boolean;
5
+ failOn?: FailOn;
6
+ format?: OutputFormat;
7
+ jsonPath?: string;
8
+ };
9
+ export declare function runValidate(options: ValidateOptions): Promise<number>;
10
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/validate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMjE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAsB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B3E"}
@@ -0,0 +1,66 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { loadConfig } from "../../core/config.js";
4
+ import { validateProject } from "../../core/validate.js";
5
+ import { shouldFail } from "../lib/failOn.js";
6
+ export async function runValidate(options) {
7
+ const root = path.resolve(options.root);
8
+ const configResult = await loadConfig(root);
9
+ const result = await validateProject(root, configResult);
10
+ const format = options.format ?? configResult.config.output.format;
11
+ const explicitJsonPath = options.jsonPath;
12
+ if (format === "text") {
13
+ emitText(result);
14
+ }
15
+ if (format === "github") {
16
+ result.issues.forEach(emitGitHub);
17
+ }
18
+ const shouldWriteJson = format === "json" || explicitJsonPath !== undefined;
19
+ if (shouldWriteJson) {
20
+ const jsonPath = format === "json"
21
+ ? (options.jsonPath ?? configResult.config.output.jsonPath)
22
+ : explicitJsonPath;
23
+ if (jsonPath) {
24
+ await emitJson(result, root, jsonPath);
25
+ }
26
+ }
27
+ const failOn = resolveFailOn(options, configResult.config.validation.failOn);
28
+ return shouldFail(result, failOn) ? 1 : 0;
29
+ }
30
+ function resolveFailOn(options, fallback) {
31
+ if (options.failOn) {
32
+ return options.failOn;
33
+ }
34
+ if (options.strict) {
35
+ return "warning";
36
+ }
37
+ return fallback;
38
+ }
39
+ function emitText(result) {
40
+ for (const item of result.issues) {
41
+ const location = item.file ? ` (${item.file})` : "";
42
+ const refs = item.refs && item.refs.length > 0 ? ` refs=${item.refs.join(",")}` : "";
43
+ process.stdout.write(`[${item.severity}] ${item.code} ${item.message}${location}${refs}\n`);
44
+ }
45
+ process.stdout.write(`counts: info=${result.counts.info} warning=${result.counts.warning} error=${result.counts.error}\n`);
46
+ }
47
+ function emitGitHub(issue) {
48
+ const level = issue.severity === "error"
49
+ ? "error"
50
+ : issue.severity === "warning"
51
+ ? "warning"
52
+ : "notice";
53
+ const file = issue.file ? `file=${issue.file}` : "";
54
+ const line = issue.loc?.line ? `,line=${issue.loc.line}` : "";
55
+ const column = issue.loc?.column ? `,col=${issue.loc.column}` : "";
56
+ const location = file ? ` ${file}${line}${column}` : "";
57
+ process.stdout.write(`::${level}${location}::${issue.code}: ${issue.message}\n`);
58
+ }
59
+ async function emitJson(result, root, jsonPath) {
60
+ const abs = path.isAbsolute(jsonPath)
61
+ ? jsonPath
62
+ : path.resolve(root, jsonPath);
63
+ await mkdir(path.dirname(abs), { recursive: true });
64
+ await writeFile(abs, `${JSON.stringify(result, null, 2)}\n`, "utf-8");
65
+ }
66
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/cli/commands/validate.ts"],"names":[],"mappings":"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"}