qfai 0.3.3 → 0.3.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 (165) hide show
  1. package/README.md +2 -2
  2. package/assets/init/.qfai/README.md +11 -0
  3. package/assets/init/.qfai/promptpack/commands/implement.md +6 -0
  4. package/assets/init/.qfai/promptpack/commands/plan.md +9 -0
  5. package/assets/init/.qfai/promptpack/commands/release.md +6 -0
  6. package/assets/init/.qfai/promptpack/commands/review.md +6 -0
  7. package/assets/init/.qfai/promptpack/constitution.md +15 -0
  8. package/assets/init/.qfai/promptpack/modes/change.md +4 -0
  9. package/assets/init/.qfai/promptpack/modes/compatibility.md +4 -0
  10. package/assets/init/.qfai/promptpack/roles/qa.md +4 -0
  11. package/assets/init/.qfai/promptpack/roles/spec.md +4 -0
  12. package/assets/init/.qfai/promptpack/roles/test.md +4 -0
  13. package/assets/init/.qfai/promptpack/steering/compatibility-vs-change.md +8 -0
  14. package/assets/init/.qfai/promptpack/steering/naming.md +7 -0
  15. package/assets/init/.qfai/promptpack/steering/traceability.md +9 -0
  16. package/assets/init/.qfai/prompts/require-to-spec.md +4 -4
  17. package/assets/init/.qfai/require/README.md +28 -0
  18. package/assets/init/.qfai/rules/conventions.md +6 -0
  19. package/dist/cli/commands/init.d.ts +8 -0
  20. package/dist/cli/commands/init.d.ts.map +1 -0
  21. package/dist/cli/commands/init.js +30 -0
  22. package/dist/cli/commands/init.js.map +1 -0
  23. package/dist/cli/commands/report.d.ts +7 -0
  24. package/dist/cli/commands/report.d.ts.map +1 -0
  25. package/dist/cli/commands/report.js +87 -0
  26. package/dist/cli/commands/report.js.map +1 -0
  27. package/dist/cli/commands/validate.d.ts +9 -0
  28. package/dist/cli/commands/validate.d.ts.map +1 -0
  29. package/dist/cli/commands/validate.js +57 -0
  30. package/dist/cli/commands/validate.js.map +1 -0
  31. package/dist/cli/index.cjs +2 -2
  32. package/dist/cli/index.d.ts +2 -0
  33. package/dist/cli/index.d.ts.map +1 -0
  34. package/dist/cli/index.js +7 -0
  35. package/dist/cli/index.js.map +1 -0
  36. package/dist/cli/index.mjs +2 -2
  37. package/dist/cli/lib/args.d.ts +18 -0
  38. package/dist/cli/lib/args.d.ts.map +1 -0
  39. package/dist/cli/lib/args.js +98 -0
  40. package/dist/cli/lib/args.js.map +1 -0
  41. package/dist/cli/lib/assets.d.ts +2 -0
  42. package/dist/cli/lib/assets.d.ts.map +1 -0
  43. package/dist/cli/lib/assets.js +24 -0
  44. package/dist/cli/lib/assets.js.map +1 -0
  45. package/dist/cli/lib/failOn.d.ts +5 -0
  46. package/dist/cli/lib/failOn.d.ts.map +1 -0
  47. package/dist/cli/lib/failOn.js +10 -0
  48. package/dist/cli/lib/failOn.js.map +1 -0
  49. package/dist/cli/lib/fs.d.ts +11 -0
  50. package/dist/cli/lib/fs.d.ts.map +1 -0
  51. package/dist/cli/lib/fs.js +91 -0
  52. package/dist/cli/lib/fs.js.map +1 -0
  53. package/dist/cli/lib/logger.d.ts +4 -0
  54. package/dist/cli/lib/logger.d.ts.map +1 -0
  55. package/dist/cli/lib/logger.js +10 -0
  56. package/dist/cli/lib/logger.js.map +1 -0
  57. package/dist/cli/main.d.ts +2 -0
  58. package/dist/cli/main.d.ts.map +1 -0
  59. package/dist/cli/main.js +66 -0
  60. package/dist/cli/main.js.map +1 -0
  61. package/dist/core/config.d.ts +44 -0
  62. package/dist/core/config.d.ts.map +1 -0
  63. package/dist/core/config.js +218 -0
  64. package/dist/core/config.js.map +1 -0
  65. package/dist/core/contractIndex.d.ts +13 -0
  66. package/dist/core/contractIndex.d.ts.map +1 -0
  67. package/dist/core/contractIndex.js +66 -0
  68. package/dist/core/contractIndex.js.map +1 -0
  69. package/dist/core/contracts.d.ts +5 -0
  70. package/dist/core/contracts.d.ts.map +1 -0
  71. package/dist/core/contracts.js +42 -0
  72. package/dist/core/contracts.js.map +1 -0
  73. package/dist/core/discovery.d.ts +14 -0
  74. package/dist/core/discovery.d.ts.map +1 -0
  75. package/dist/core/discovery.js +55 -0
  76. package/dist/core/discovery.js.map +1 -0
  77. package/dist/core/fs.d.ts +6 -0
  78. package/dist/core/fs.d.ts.map +1 -0
  79. package/dist/core/fs.js +55 -0
  80. package/dist/core/fs.js.map +1 -0
  81. package/dist/core/gherkin/parse.d.ts +7 -0
  82. package/dist/core/gherkin/parse.d.ts.map +1 -0
  83. package/dist/core/gherkin/parse.js +25 -0
  84. package/dist/core/gherkin/parse.js.map +1 -0
  85. package/dist/core/ids.d.ts +6 -0
  86. package/dist/core/ids.d.ts.map +1 -0
  87. package/dist/core/ids.js +52 -0
  88. package/dist/core/ids.js.map +1 -0
  89. package/dist/core/index.d.ts +13 -0
  90. package/dist/core/index.d.ts.map +1 -0
  91. package/dist/core/index.js +13 -0
  92. package/dist/core/index.js.map +1 -0
  93. package/dist/core/parse/adr.d.ts +13 -0
  94. package/dist/core/parse/adr.d.ts.map +1 -0
  95. package/dist/core/parse/adr.js +33 -0
  96. package/dist/core/parse/adr.js.map +1 -0
  97. package/dist/core/parse/gherkin.d.ts +12 -0
  98. package/dist/core/parse/gherkin.d.ts.map +1 -0
  99. package/dist/core/parse/gherkin.js +22 -0
  100. package/dist/core/parse/gherkin.js.map +1 -0
  101. package/dist/core/parse/markdown.d.ts +14 -0
  102. package/dist/core/parse/markdown.d.ts.map +1 -0
  103. package/dist/core/parse/markdown.js +45 -0
  104. package/dist/core/parse/markdown.js.map +1 -0
  105. package/dist/core/parse/spec.d.ts +28 -0
  106. package/dist/core/parse/spec.d.ts.map +1 -0
  107. package/dist/core/parse/spec.js +80 -0
  108. package/dist/core/parse/spec.js.map +1 -0
  109. package/dist/core/report.d.ts +39 -0
  110. package/dist/core/report.d.ts.map +1 -0
  111. package/dist/core/report.js +226 -0
  112. package/dist/core/report.js.map +1 -0
  113. package/dist/core/scenarioModel.d.ts +33 -0
  114. package/dist/core/scenarioModel.d.ts.map +1 -0
  115. package/dist/core/scenarioModel.js +130 -0
  116. package/dist/core/scenarioModel.js.map +1 -0
  117. package/dist/core/specLayout.d.ts +8 -0
  118. package/dist/core/specLayout.d.ts.map +1 -0
  119. package/dist/core/specLayout.js +36 -0
  120. package/dist/core/specLayout.js.map +1 -0
  121. package/dist/core/types.d.ts +27 -0
  122. package/dist/core/types.d.ts.map +1 -0
  123. package/dist/core/types.js +2 -0
  124. package/dist/core/types.js.map +1 -0
  125. package/dist/core/validate.d.ts +4 -0
  126. package/dist/core/validate.d.ts.map +1 -0
  127. package/dist/core/validate.js +36 -0
  128. package/dist/core/validate.js.map +1 -0
  129. package/dist/core/validators/contracts.d.ts +5 -0
  130. package/dist/core/validators/contracts.d.ts.map +1 -0
  131. package/dist/core/validators/contracts.js +162 -0
  132. package/dist/core/validators/contracts.js.map +1 -0
  133. package/dist/core/validators/delta.d.ts +4 -0
  134. package/dist/core/validators/delta.d.ts.map +1 -0
  135. package/dist/core/validators/delta.js +68 -0
  136. package/dist/core/validators/delta.js.map +1 -0
  137. package/dist/core/validators/ids.d.ts +4 -0
  138. package/dist/core/validators/ids.d.ts.map +1 -0
  139. package/dist/core/validators/ids.js +88 -0
  140. package/dist/core/validators/ids.js.map +1 -0
  141. package/dist/core/validators/scenario.d.ts +5 -0
  142. package/dist/core/validators/scenario.d.ts.map +1 -0
  143. package/dist/core/validators/scenario.js +137 -0
  144. package/dist/core/validators/scenario.js.map +1 -0
  145. package/dist/core/validators/spec.d.ts +5 -0
  146. package/dist/core/validators/spec.d.ts.map +1 -0
  147. package/dist/core/validators/spec.js +94 -0
  148. package/dist/core/validators/spec.js.map +1 -0
  149. package/dist/core/validators/traceability.d.ts +4 -0
  150. package/dist/core/validators/traceability.d.ts.map +1 -0
  151. package/dist/core/validators/traceability.js +180 -0
  152. package/dist/core/validators/traceability.js.map +1 -0
  153. package/dist/core/version.d.ts +2 -0
  154. package/dist/core/version.d.ts.map +1 -0
  155. package/dist/core/version.js +25 -0
  156. package/dist/core/version.js.map +1 -0
  157. package/dist/index.cjs +2 -2
  158. package/dist/index.d.ts +2 -133
  159. package/dist/index.d.ts.map +1 -0
  160. package/dist/index.js +2 -0
  161. package/dist/index.js.map +1 -0
  162. package/dist/index.mjs +2 -2
  163. package/dist/tsconfig.tsbuildinfo +1 -0
  164. package/package.json +1 -1
  165. package/assets/init/root/require/README.md +0 -28
@@ -0,0 +1,94 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolvePath } from "../config.js";
3
+ import { extractIds, extractInvalidIds } from "../ids.js";
4
+ import { parseSpec } from "../parse/spec.js";
5
+ import { collectSpecEntries } from "../specLayout.js";
6
+ export async function validateSpecs(root, config) {
7
+ const specsRoot = resolvePath(root, config, "specsDir");
8
+ const entries = await collectSpecEntries(specsRoot);
9
+ if (entries.length === 0) {
10
+ const expected = "spec-0001/spec.md";
11
+ const legacy = "spec-001/spec.md";
12
+ return [
13
+ issue("QFAI-SPEC-000", `Spec ファイルが見つかりません。配置場所: ${config.paths.specsDir} / 期待パターン: ${expected} (${legacy} は非対応)`, "info", specsRoot, "spec.files"),
14
+ ];
15
+ }
16
+ const issues = [];
17
+ for (const entry of entries) {
18
+ let text;
19
+ try {
20
+ text = await readFile(entry.specPath, "utf-8");
21
+ }
22
+ catch (error) {
23
+ if (isMissingFileError(error)) {
24
+ issues.push(issue("QFAI-SPEC-005", "spec.md が見つかりません。", "error", entry.specPath, "spec.exists"));
25
+ continue;
26
+ }
27
+ throw error;
28
+ }
29
+ issues.push(...validateSpecContent(text, entry.specPath, config.validation.require.specSections));
30
+ }
31
+ return issues;
32
+ }
33
+ export function validateSpecContent(text, file, requiredSections) {
34
+ const issues = [];
35
+ const parsed = parseSpec(text, file);
36
+ const invalidIds = extractInvalidIds(text, [
37
+ "SPEC",
38
+ "BR",
39
+ "SC",
40
+ "UI",
41
+ "API",
42
+ "DATA",
43
+ "ADR",
44
+ ]);
45
+ if (invalidIds.length > 0) {
46
+ issues.push(issue("QFAI-ID-002", `ID フォーマットが不正です: ${invalidIds.join(", ")}`, "error", file, "id.format", invalidIds));
47
+ }
48
+ if (!parsed.specId) {
49
+ issues.push(issue("QFAI-SPEC-001", "SPEC ID が見つかりません。", "error", file, "spec.id"));
50
+ }
51
+ if (parsed.brs.length === 0) {
52
+ issues.push(issue("QFAI-SPEC-002", "BR ID が見つかりません。", "error", file, "spec.br"));
53
+ }
54
+ for (const br of parsed.brsWithoutPriority) {
55
+ issues.push(issue("QFAI-BR-001", `BR 行に Priority がありません: ${br.id}`, "error", file, "spec.brPriority", [br.id]));
56
+ }
57
+ for (const br of parsed.brsWithInvalidPriority) {
58
+ issues.push(issue("QFAI-BR-002", `BR Priority が不正です: ${br.id} (${br.priority})`, "error", file, "spec.brPriority", [br.id]));
59
+ }
60
+ const scIds = extractIds(text, "SC");
61
+ if (scIds.length > 0) {
62
+ issues.push(issue("QFAI-SPEC-003", "Spec は SC を参照しないルールです。", "warning", file, "spec.noSc", scIds));
63
+ }
64
+ for (const section of requiredSections) {
65
+ if (!parsed.sections.has(section)) {
66
+ issues.push(issue("QFAI-SPEC-004", `必須セクションが不足しています: ${section}`, "error", file, "spec.requiredSection"));
67
+ }
68
+ }
69
+ return issues;
70
+ }
71
+ function issue(code, message, severity, file, rule, refs) {
72
+ const issue = {
73
+ code,
74
+ severity,
75
+ message,
76
+ };
77
+ if (file) {
78
+ issue.file = file;
79
+ }
80
+ if (rule) {
81
+ issue.rule = rule;
82
+ }
83
+ if (refs && refs.length > 0) {
84
+ issue.refs = refs;
85
+ }
86
+ return issue;
87
+ }
88
+ function isMissingFileError(error) {
89
+ if (!error || typeof error !== "object") {
90
+ return false;
91
+ }
92
+ return error.code === "ENOENT";
93
+ }
94
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../../../src/core/validators/spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { QfaiConfig } from "../config.js";
2
+ import type { Issue } from "../types.js";
3
+ export declare function validateTraceability(root: string, config: QfaiConfig): Promise<Issue[]>;
4
+ //# sourceMappingURL=traceability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceability.d.ts","sourceRoot":"","sources":["../../../src/core/validators/traceability.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAQ/C,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,aAAa,CAAC;AAMxD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,KAAK,EAAE,CAAC,CAsPlB"}
@@ -0,0 +1,180 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolvePath } from "../config.js";
3
+ import { buildContractIndex } from "../contractIndex.js";
4
+ import { collectScenarioFiles, collectSpecFiles } from "../discovery.js";
5
+ import { collectFiles } from "../fs.js";
6
+ import { extractAllIds, extractIds } from "../ids.js";
7
+ import { parseSpec } from "../parse/spec.js";
8
+ import { buildScenarioAtoms, parseScenarioDocument } from "../scenarioModel.js";
9
+ const SC_TAG_RE = /^SC-\d{4}$/;
10
+ const SPEC_TAG_RE = /^SPEC-\d{4}$/;
11
+ const BR_TAG_RE = /^BR-\d{4}$/;
12
+ export async function validateTraceability(root, config) {
13
+ const issues = [];
14
+ const specsRoot = resolvePath(root, config, "specsDir");
15
+ const srcRoot = resolvePath(root, config, "srcDir");
16
+ const testsRoot = resolvePath(root, config, "testsDir");
17
+ const specFiles = await collectSpecFiles(specsRoot);
18
+ const scenarioFiles = await collectScenarioFiles(specsRoot);
19
+ const upstreamIds = new Set();
20
+ const specIds = new Set();
21
+ const brIdsInSpecs = new Set();
22
+ const brIdsInScenarios = new Set();
23
+ const scIdsInScenarios = new Set();
24
+ const scenarioContractIds = new Set();
25
+ const scWithContracts = new Set();
26
+ const specToBrIds = new Map();
27
+ const contractIndex = await buildContractIndex(root, config);
28
+ const contractIds = contractIndex.ids;
29
+ for (const file of specFiles) {
30
+ const text = await readFile(file, "utf-8");
31
+ extractAllIds(text).forEach((id) => upstreamIds.add(id));
32
+ const parsed = parseSpec(text, file);
33
+ if (parsed.specId) {
34
+ specIds.add(parsed.specId);
35
+ }
36
+ const brIds = parsed.brs.map((br) => br.id);
37
+ brIds.forEach((id) => brIdsInSpecs.add(id));
38
+ const referencedContractIds = new Set([
39
+ ...extractIds(text, "UI"),
40
+ ...extractIds(text, "API"),
41
+ ...extractIds(text, "DATA"),
42
+ ]);
43
+ const unknownContractIds = Array.from(referencedContractIds).filter((id) => !contractIds.has(id));
44
+ if (unknownContractIds.length > 0) {
45
+ issues.push(issue("QFAI-TRACE-009", `Spec が存在しない契約 ID を参照しています: ${unknownContractIds.join(", ")}`, "error", file, "traceability.specContractExists", unknownContractIds));
46
+ }
47
+ if (parsed.specId) {
48
+ const current = specToBrIds.get(parsed.specId) ?? new Set();
49
+ brIds.forEach((id) => current.add(id));
50
+ specToBrIds.set(parsed.specId, current);
51
+ }
52
+ }
53
+ for (const file of scenarioFiles) {
54
+ const text = await readFile(file, "utf-8");
55
+ extractAllIds(text).forEach((id) => upstreamIds.add(id));
56
+ const { document, errors } = parseScenarioDocument(text, file);
57
+ if (!document || errors.length > 0) {
58
+ continue;
59
+ }
60
+ const atoms = buildScenarioAtoms(document);
61
+ for (const [index, scenario] of document.scenarios.entries()) {
62
+ const atom = atoms[index];
63
+ if (!atom) {
64
+ continue;
65
+ }
66
+ const specTags = scenario.tags.filter((tag) => SPEC_TAG_RE.test(tag));
67
+ const brTags = scenario.tags.filter((tag) => BR_TAG_RE.test(tag));
68
+ const scTags = scenario.tags.filter((tag) => SC_TAG_RE.test(tag));
69
+ brTags.forEach((id) => brIdsInScenarios.add(id));
70
+ scTags.forEach((id) => scIdsInScenarios.add(id));
71
+ atom.contractIds.forEach((id) => scenarioContractIds.add(id));
72
+ if (atom.contractIds.length > 0) {
73
+ scTags.forEach((id) => scWithContracts.add(id));
74
+ }
75
+ const unknownSpecIds = specTags.filter((id) => !specIds.has(id));
76
+ if (unknownSpecIds.length > 0) {
77
+ issues.push(issue("QFAI-TRACE-005", `Scenario が存在しない SPEC を参照しています: ${unknownSpecIds.join(", ")} (${scenario.name})`, "error", file, "traceability.scenarioSpecExists", unknownSpecIds));
78
+ }
79
+ const unknownBrIds = brTags.filter((id) => !brIdsInSpecs.has(id));
80
+ if (unknownBrIds.length > 0) {
81
+ issues.push(issue("QFAI-TRACE-006", `Scenario が存在しない BR を参照しています: ${unknownBrIds.join(", ")} (${scenario.name})`, "error", file, "traceability.scenarioBrExists", unknownBrIds));
82
+ }
83
+ const unknownContractIds = atom.contractIds.filter((id) => !contractIds.has(id));
84
+ if (unknownContractIds.length > 0) {
85
+ issues.push(issue("QFAI-TRACE-008", `Scenario が存在しない契約 ID を参照しています: ${unknownContractIds.join(", ")} (${scenario.name})`, config.validation.traceability.unknownContractIdSeverity, file, "traceability.scenarioContractExists", unknownContractIds));
86
+ }
87
+ if (specTags.length > 0 && brTags.length > 0) {
88
+ const allowedBrIds = new Set();
89
+ for (const specId of specTags) {
90
+ const brIdsForSpec = specToBrIds.get(specId);
91
+ if (!brIdsForSpec) {
92
+ continue;
93
+ }
94
+ brIdsForSpec.forEach((id) => allowedBrIds.add(id));
95
+ }
96
+ const invalidBrIds = brTags.filter((id) => !allowedBrIds.has(id));
97
+ if (invalidBrIds.length > 0) {
98
+ issues.push(issue("QFAI-TRACE-007", `Scenario の BR が参照 SPEC に属していません: ${invalidBrIds.join(", ")} (SPEC: ${specTags.join(", ")}) (${scenario.name})`, "error", file, "traceability.scenarioBrUnderSpec", invalidBrIds));
99
+ }
100
+ }
101
+ }
102
+ }
103
+ if (upstreamIds.size === 0) {
104
+ return [
105
+ issue("QFAI-TRACE-000", "上流 ID が見つかりません。", "info", specsRoot, "traceability.upstream"),
106
+ ];
107
+ }
108
+ if (config.validation.traceability.brMustHaveSc && brIdsInSpecs.size > 0) {
109
+ const orphanBrIds = Array.from(brIdsInSpecs).filter((id) => !brIdsInScenarios.has(id));
110
+ if (orphanBrIds.length > 0) {
111
+ issues.push(issue("QFAI_TRACE_BR_ORPHAN", `BR が SC に紐づいていません: ${orphanBrIds.join(", ")}`, "error", specsRoot, "traceability.brMustHaveSc", orphanBrIds));
112
+ }
113
+ }
114
+ if (config.validation.traceability.scMustTouchContracts &&
115
+ scIdsInScenarios.size > 0) {
116
+ const scWithoutContracts = Array.from(scIdsInScenarios).filter((id) => !scWithContracts.has(id));
117
+ if (scWithoutContracts.length > 0) {
118
+ issues.push(issue("QFAI_TRACE_SC_NO_CONTRACT", `SC が契約(UI/API/DATA)に接続していません: ${scWithoutContracts.join(", ")}`, "error", specsRoot, "traceability.scMustTouchContracts", scWithoutContracts));
119
+ }
120
+ }
121
+ if (!config.validation.traceability.allowOrphanContracts) {
122
+ if (contractIds.size > 0) {
123
+ const orphanContracts = Array.from(contractIds).filter((id) => !scenarioContractIds.has(id));
124
+ if (orphanContracts.length > 0) {
125
+ issues.push(issue("QFAI_CONTRACT_ORPHAN", `契約が SC から参照されていません: ${orphanContracts.join(", ")}`, "error", specsRoot, "traceability.allowOrphanContracts", orphanContracts));
126
+ }
127
+ }
128
+ }
129
+ issues.push(...(await validateCodeReferences(upstreamIds, srcRoot, testsRoot)));
130
+ return issues;
131
+ }
132
+ async function validateCodeReferences(upstreamIds, srcRoot, testsRoot) {
133
+ const issues = [];
134
+ const codeFiles = await collectFiles(srcRoot, {
135
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
136
+ });
137
+ const testFiles = await collectFiles(testsRoot, {
138
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
139
+ });
140
+ const targetFiles = [...codeFiles, ...testFiles];
141
+ if (targetFiles.length === 0) {
142
+ issues.push(issue("QFAI-TRACE-001", "参照対象のコード/テストが見つかりません。", "info", srcRoot, "traceability.codeReferences"));
143
+ return issues;
144
+ }
145
+ const pattern = buildIdPattern(Array.from(upstreamIds));
146
+ let found = false;
147
+ for (const file of targetFiles) {
148
+ const text = await readFile(file, "utf-8");
149
+ if (pattern.test(text)) {
150
+ found = true;
151
+ break;
152
+ }
153
+ }
154
+ if (!found) {
155
+ issues.push(issue("QFAI-TRACE-002", "上流 ID がコード/テストに参照されていません。", "warning", srcRoot, "traceability.codeReferences"));
156
+ }
157
+ return issues;
158
+ }
159
+ function buildIdPattern(ids) {
160
+ const escaped = ids.map((id) => id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
161
+ return new RegExp(`\\b(${escaped.join("|")})\\b`);
162
+ }
163
+ function issue(code, message, severity, file, rule, refs) {
164
+ const issue = {
165
+ code,
166
+ severity,
167
+ message,
168
+ };
169
+ if (file) {
170
+ issue.file = file;
171
+ }
172
+ if (rule) {
173
+ issue.rule = rule;
174
+ }
175
+ if (refs && refs.length > 0) {
176
+ issue.refs = refs;
177
+ }
178
+ return issue;
179
+ }
180
+ //# sourceMappingURL=traceability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceability.js","sourceRoot":"","sources":["../../../src/core/validators/traceability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function resolveToolVersion(): Promise<string>;
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAMA,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAiB1D"}
@@ -0,0 +1,25 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ export async function resolveToolVersion() {
5
+ if (typeof __QFAI_TOOL_VERSION__ === "string" &&
6
+ __QFAI_TOOL_VERSION__.length > 0) {
7
+ return __QFAI_TOOL_VERSION__;
8
+ }
9
+ try {
10
+ const packagePath = resolvePackageJsonPath();
11
+ const raw = await readFile(packagePath, "utf-8");
12
+ const parsed = JSON.parse(raw);
13
+ const version = typeof parsed.version === "string" ? parsed.version : "";
14
+ return version.length > 0 ? version : "unknown";
15
+ }
16
+ catch {
17
+ return "unknown";
18
+ }
19
+ }
20
+ function resolvePackageJsonPath() {
21
+ const base = import.meta.url;
22
+ const basePath = base.startsWith("file:") ? fileURLToPath(base) : base;
23
+ return path.resolve(path.dirname(basePath), "../../package.json");
24
+ }
25
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IACE,OAAO,qBAAqB,KAAK,QAAQ;QACzC,qBAAqB,CAAC,MAAM,GAAG,CAAC,EAChC,CAAC;QACD,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA0B,CAAC;QACxD,MAAM,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAC,CAAC;AACpE,CAAC"}
package/dist/index.cjs CHANGED
@@ -591,8 +591,8 @@ var import_promises5 = require("fs/promises");
591
591
  var import_node_path4 = __toESM(require("path"), 1);
592
592
  var import_node_url = require("url");
593
593
  async function resolveToolVersion() {
594
- if ("0.3.3".length > 0) {
595
- return "0.3.3";
594
+ if ("0.3.5".length > 0) {
595
+ return "0.3.5";
596
596
  }
597
597
  try {
598
598
  const packagePath = resolvePackageJsonPath();
package/dist/index.d.ts CHANGED
@@ -1,133 +1,2 @@
1
- type IssueSeverity = "info" | "warning" | "error";
2
- declare const VALIDATION_SCHEMA_VERSION: "0.2";
3
- type IssueLocation = {
4
- line: number;
5
- column?: number;
6
- };
7
- type Issue = {
8
- code: string;
9
- severity: IssueSeverity;
10
- message: string;
11
- file?: string;
12
- refs?: string[];
13
- rule?: string;
14
- loc?: IssueLocation;
15
- };
16
- type ValidationCounts = {
17
- info: number;
18
- warning: number;
19
- error: number;
20
- };
21
- type ValidationResult = {
22
- schemaVersion: typeof VALIDATION_SCHEMA_VERSION;
23
- toolVersion: string;
24
- issues: Issue[];
25
- counts: ValidationCounts;
26
- };
27
-
28
- type FailOn = "never" | "warning" | "error";
29
- type OutputFormat = "text" | "github";
30
- type TraceabilitySeverity = "warning" | "error";
31
- type QfaiPaths = {
32
- contractsDir: string;
33
- specsDir: string;
34
- rulesDir: string;
35
- outDir: string;
36
- promptsDir: string;
37
- srcDir: string;
38
- testsDir: string;
39
- };
40
- type QfaiValidationConfig = {
41
- failOn: FailOn;
42
- require: {
43
- specSections: string[];
44
- };
45
- traceability: {
46
- brMustHaveSc: boolean;
47
- scMustTouchContracts: boolean;
48
- allowOrphanContracts: boolean;
49
- unknownContractIdSeverity: TraceabilitySeverity;
50
- };
51
- };
52
- type QfaiOutputConfig = {
53
- validateJsonPath: string;
54
- };
55
- type QfaiConfig = {
56
- paths: QfaiPaths;
57
- validation: QfaiValidationConfig;
58
- output: QfaiOutputConfig;
59
- };
60
- type ConfigPathKey = keyof QfaiPaths;
61
- type ConfigLoadResult = {
62
- config: QfaiConfig;
63
- issues: Issue[];
64
- configPath: string;
65
- };
66
- declare const defaultConfig: QfaiConfig;
67
- declare function getConfigPath(root: string): string;
68
- declare function loadConfig(root: string): Promise<ConfigLoadResult>;
69
- declare function resolvePath(root: string, config: QfaiConfig, key: ConfigPathKey): string;
70
-
71
- type IdPrefix = "SPEC" | "BR" | "SC" | "UI" | "API" | "DATA";
72
- type IdFormatPrefix = IdPrefix | "ADR";
73
- declare function extractIds(text: string, prefix: IdPrefix): string[];
74
- declare function extractAllIds(text: string): string[];
75
- declare function extractInvalidIds(text: string, prefixes: IdFormatPrefix[]): string[];
76
-
77
- type ReportSummary = {
78
- specs: number;
79
- scenarios: number;
80
- contracts: {
81
- api: number;
82
- ui: number;
83
- db: number;
84
- };
85
- counts: ValidationCounts;
86
- };
87
- type ReportIds = {
88
- spec: string[];
89
- br: string[];
90
- sc: string[];
91
- ui: string[];
92
- api: string[];
93
- data: string[];
94
- };
95
- type ReportTraceability = {
96
- upstreamIdsFound: number;
97
- referencedInCodeOrTests: boolean;
98
- };
99
- type ReportData = {
100
- tool: "qfai";
101
- version: string;
102
- generatedAt: string;
103
- root: string;
104
- configPath: string;
105
- summary: ReportSummary;
106
- ids: ReportIds;
107
- traceability: ReportTraceability;
108
- issues: Issue[];
109
- };
110
- declare function createReportData(root: string, validation?: ValidationResult, configResult?: ConfigLoadResult): Promise<ReportData>;
111
- declare function formatReportMarkdown(data: ReportData): string;
112
- declare function formatReportJson(data: ReportData): string;
113
-
114
- declare function validateProject(root: string, configResult?: ConfigLoadResult): Promise<ValidationResult>;
115
-
116
- declare function resolveToolVersion(): Promise<string>;
117
-
118
- declare function validateContracts(root: string, config: QfaiConfig): Promise<Issue[]>;
119
- declare function lintSql(text: string, file: string): Issue[];
120
-
121
- declare function validateDeltas(root: string, config: QfaiConfig): Promise<Issue[]>;
122
-
123
- declare function validateDefinedIds(root: string, config: QfaiConfig): Promise<Issue[]>;
124
-
125
- declare function validateScenarios(root: string, config: QfaiConfig): Promise<Issue[]>;
126
- declare function validateScenarioContent(text: string, file: string): Issue[];
127
-
128
- declare function validateSpecs(root: string, config: QfaiConfig): Promise<Issue[]>;
129
- declare function validateSpecContent(text: string, file: string, requiredSections: string[]): Issue[];
130
-
131
- declare function validateTraceability(root: string, config: QfaiConfig): Promise<Issue[]>;
132
-
133
- export { type ConfigLoadResult, type ConfigPathKey, type FailOn, type IdFormatPrefix, type IdPrefix, type Issue, type IssueLocation, type IssueSeverity, type OutputFormat, type QfaiConfig, type QfaiOutputConfig, type QfaiPaths, type QfaiValidationConfig, type ReportData, type ReportIds, type ReportSummary, type ReportTraceability, type TraceabilitySeverity, VALIDATION_SCHEMA_VERSION, type ValidationCounts, type ValidationResult, createReportData, defaultConfig, extractAllIds, extractIds, extractInvalidIds, formatReportJson, formatReportMarkdown, getConfigPath, lintSql, loadConfig, resolvePath, resolveToolVersion, validateContracts, validateDefinedIds, validateDeltas, validateProject, validateScenarioContent, validateScenarios, validateSpecContent, validateSpecs, validateTraceability };
1
+ export * from "./core/index.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./core/index.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
package/dist/index.mjs CHANGED
@@ -534,8 +534,8 @@ import { readFile as readFile2 } from "fs/promises";
534
534
  import path4 from "path";
535
535
  import { fileURLToPath } from "url";
536
536
  async function resolveToolVersion() {
537
- if ("0.3.3".length > 0) {
538
- return "0.3.3";
537
+ if ("0.3.5".length > 0) {
538
+ return "0.3.5";
539
539
  }
540
540
  try {
541
541
  const packagePath = resolvePackageJsonPath();