qfai 0.4.7 → 0.4.9

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 (155) hide show
  1. package/README.md +3 -1
  2. package/dist/cli/index.cjs +2 -2
  3. package/dist/cli/index.d.ts +0 -2
  4. package/dist/cli/index.mjs +2 -2
  5. package/dist/index.cjs +2 -2
  6. package/dist/index.d.ts +167 -2
  7. package/dist/index.mjs +2 -2
  8. package/package.json +3 -1
  9. package/dist/cli/commands/init.d.ts +0 -8
  10. package/dist/cli/commands/init.d.ts.map +0 -1
  11. package/dist/cli/commands/init.js +0 -30
  12. package/dist/cli/commands/init.js.map +0 -1
  13. package/dist/cli/commands/report.d.ts +0 -7
  14. package/dist/cli/commands/report.d.ts.map +0 -1
  15. package/dist/cli/commands/report.js +0 -108
  16. package/dist/cli/commands/report.js.map +0 -1
  17. package/dist/cli/commands/validate.d.ts +0 -9
  18. package/dist/cli/commands/validate.d.ts.map +0 -1
  19. package/dist/cli/commands/validate.js +0 -57
  20. package/dist/cli/commands/validate.js.map +0 -1
  21. package/dist/cli/index.d.ts.map +0 -1
  22. package/dist/cli/index.js +0 -7
  23. package/dist/cli/index.js.map +0 -1
  24. package/dist/cli/lib/args.d.ts +0 -18
  25. package/dist/cli/lib/args.d.ts.map +0 -1
  26. package/dist/cli/lib/args.js +0 -98
  27. package/dist/cli/lib/args.js.map +0 -1
  28. package/dist/cli/lib/assets.d.ts +0 -2
  29. package/dist/cli/lib/assets.d.ts.map +0 -1
  30. package/dist/cli/lib/assets.js +0 -24
  31. package/dist/cli/lib/assets.js.map +0 -1
  32. package/dist/cli/lib/failOn.d.ts +0 -5
  33. package/dist/cli/lib/failOn.d.ts.map +0 -1
  34. package/dist/cli/lib/failOn.js +0 -10
  35. package/dist/cli/lib/failOn.js.map +0 -1
  36. package/dist/cli/lib/fs.d.ts +0 -11
  37. package/dist/cli/lib/fs.d.ts.map +0 -1
  38. package/dist/cli/lib/fs.js +0 -91
  39. package/dist/cli/lib/fs.js.map +0 -1
  40. package/dist/cli/lib/logger.d.ts +0 -4
  41. package/dist/cli/lib/logger.d.ts.map +0 -1
  42. package/dist/cli/lib/logger.js +0 -10
  43. package/dist/cli/lib/logger.js.map +0 -1
  44. package/dist/cli/main.d.ts +0 -2
  45. package/dist/cli/main.d.ts.map +0 -1
  46. package/dist/cli/main.js +0 -66
  47. package/dist/cli/main.js.map +0 -1
  48. package/dist/core/config.d.ts +0 -47
  49. package/dist/core/config.d.ts.map +0 -1
  50. package/dist/core/config.js +0 -224
  51. package/dist/core/config.js.map +0 -1
  52. package/dist/core/contractIndex.d.ts +0 -12
  53. package/dist/core/contractIndex.d.ts.map +0 -1
  54. package/dist/core/contractIndex.js +0 -38
  55. package/dist/core/contractIndex.js.map +0 -1
  56. package/dist/core/contracts.d.ts +0 -5
  57. package/dist/core/contracts.d.ts.map +0 -1
  58. package/dist/core/contracts.js +0 -42
  59. package/dist/core/contracts.js.map +0 -1
  60. package/dist/core/contractsDecl.d.ts +0 -3
  61. package/dist/core/contractsDecl.d.ts.map +0 -1
  62. package/dist/core/contractsDecl.js +0 -19
  63. package/dist/core/contractsDecl.js.map +0 -1
  64. package/dist/core/discovery.d.ts +0 -14
  65. package/dist/core/discovery.d.ts.map +0 -1
  66. package/dist/core/discovery.js +0 -55
  67. package/dist/core/discovery.js.map +0 -1
  68. package/dist/core/fs.d.ts +0 -11
  69. package/dist/core/fs.d.ts.map +0 -1
  70. package/dist/core/fs.js +0 -68
  71. package/dist/core/fs.js.map +0 -1
  72. package/dist/core/gherkin/parse.d.ts +0 -7
  73. package/dist/core/gherkin/parse.d.ts.map +0 -1
  74. package/dist/core/gherkin/parse.js +0 -25
  75. package/dist/core/gherkin/parse.js.map +0 -1
  76. package/dist/core/ids.d.ts +0 -6
  77. package/dist/core/ids.d.ts.map +0 -1
  78. package/dist/core/ids.js +0 -52
  79. package/dist/core/ids.js.map +0 -1
  80. package/dist/core/index.d.ts +0 -13
  81. package/dist/core/index.d.ts.map +0 -1
  82. package/dist/core/index.js +0 -13
  83. package/dist/core/index.js.map +0 -1
  84. package/dist/core/parse/adr.d.ts +0 -13
  85. package/dist/core/parse/adr.d.ts.map +0 -1
  86. package/dist/core/parse/adr.js +0 -33
  87. package/dist/core/parse/adr.js.map +0 -1
  88. package/dist/core/parse/gherkin.d.ts +0 -12
  89. package/dist/core/parse/gherkin.d.ts.map +0 -1
  90. package/dist/core/parse/gherkin.js +0 -22
  91. package/dist/core/parse/gherkin.js.map +0 -1
  92. package/dist/core/parse/markdown.d.ts +0 -14
  93. package/dist/core/parse/markdown.d.ts.map +0 -1
  94. package/dist/core/parse/markdown.js +0 -45
  95. package/dist/core/parse/markdown.js.map +0 -1
  96. package/dist/core/parse/spec.d.ts +0 -36
  97. package/dist/core/parse/spec.d.ts.map +0 -1
  98. package/dist/core/parse/spec.js +0 -123
  99. package/dist/core/parse/spec.js.map +0 -1
  100. package/dist/core/report.d.ts +0 -55
  101. package/dist/core/report.d.ts.map +0 -1
  102. package/dist/core/report.js +0 -393
  103. package/dist/core/report.js.map +0 -1
  104. package/dist/core/scenarioModel.d.ts +0 -33
  105. package/dist/core/scenarioModel.d.ts.map +0 -1
  106. package/dist/core/scenarioModel.js +0 -128
  107. package/dist/core/scenarioModel.js.map +0 -1
  108. package/dist/core/specLayout.d.ts +0 -8
  109. package/dist/core/specLayout.d.ts.map +0 -1
  110. package/dist/core/specLayout.js +0 -36
  111. package/dist/core/specLayout.js.map +0 -1
  112. package/dist/core/traceability.d.ts +0 -26
  113. package/dist/core/traceability.d.ts.map +0 -1
  114. package/dist/core/traceability.js +0 -157
  115. package/dist/core/traceability.js.map +0 -1
  116. package/dist/core/types.d.ts +0 -31
  117. package/dist/core/types.d.ts.map +0 -1
  118. package/dist/core/types.js +0 -2
  119. package/dist/core/types.js.map +0 -1
  120. package/dist/core/validate.d.ts +0 -4
  121. package/dist/core/validate.d.ts.map +0 -1
  122. package/dist/core/validate.js +0 -45
  123. package/dist/core/validate.js.map +0 -1
  124. package/dist/core/validators/contracts.d.ts +0 -5
  125. package/dist/core/validators/contracts.d.ts.map +0 -1
  126. package/dist/core/validators/contracts.js +0 -189
  127. package/dist/core/validators/contracts.js.map +0 -1
  128. package/dist/core/validators/delta.d.ts +0 -4
  129. package/dist/core/validators/delta.d.ts.map +0 -1
  130. package/dist/core/validators/delta.js +0 -68
  131. package/dist/core/validators/delta.js.map +0 -1
  132. package/dist/core/validators/ids.d.ts +0 -4
  133. package/dist/core/validators/ids.d.ts.map +0 -1
  134. package/dist/core/validators/ids.js +0 -88
  135. package/dist/core/validators/ids.js.map +0 -1
  136. package/dist/core/validators/scenario.d.ts +0 -5
  137. package/dist/core/validators/scenario.d.ts.map +0 -1
  138. package/dist/core/validators/scenario.js +0 -127
  139. package/dist/core/validators/scenario.js.map +0 -1
  140. package/dist/core/validators/spec.d.ts +0 -5
  141. package/dist/core/validators/spec.d.ts.map +0 -1
  142. package/dist/core/validators/spec.js +0 -94
  143. package/dist/core/validators/spec.js.map +0 -1
  144. package/dist/core/validators/traceability.d.ts +0 -4
  145. package/dist/core/validators/traceability.d.ts.map +0 -1
  146. package/dist/core/validators/traceability.js +0 -222
  147. package/dist/core/validators/traceability.js.map +0 -1
  148. package/dist/core/version.d.ts +0 -2
  149. package/dist/core/version.d.ts.map +0 -1
  150. package/dist/core/version.js +0 -25
  151. package/dist/core/version.js.map +0 -1
  152. package/dist/index.d.ts.map +0 -1
  153. package/dist/index.js +0 -2
  154. package/dist/index.js.map +0 -1
  155. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,189 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { resolvePath } from "../config.js";
4
- import { parseStructuredContract } from "../contracts.js";
5
- import { buildContractIndex } from "../contractIndex.js";
6
- import { extractDeclaredContractIds, stripContractDeclarationLines, } from "../contractsDecl.js";
7
- import { collectApiContractFiles, collectDbContractFiles, collectUiContractFiles, } from "../discovery.js";
8
- import { extractInvalidIds } from "../ids.js";
9
- const SQL_DANGEROUS_PATTERNS = [
10
- { pattern: /\bDROP\s+TABLE\b/i, label: "DROP TABLE" },
11
- { pattern: /\bDROP\s+DATABASE\b/i, label: "DROP DATABASE" },
12
- { pattern: /\bTRUNCATE\b/i, label: "TRUNCATE" },
13
- {
14
- pattern: /\bALTER\s+TABLE\b[\s\S]*\bDROP\b/i,
15
- label: "ALTER TABLE ... DROP",
16
- },
17
- ];
18
- export async function validateContracts(root, config) {
19
- const issues = [];
20
- const contractsRoot = resolvePath(root, config, "contractsDir");
21
- issues.push(...(await validateUiContracts(path.join(contractsRoot, "ui"))));
22
- issues.push(...(await validateApiContracts(path.join(contractsRoot, "api"))));
23
- issues.push(...(await validateDbContracts(path.join(contractsRoot, "db"))));
24
- const contractIndex = await buildContractIndex(root, config);
25
- issues.push(...validateDuplicateContractIds(contractIndex));
26
- return issues;
27
- }
28
- async function validateUiContracts(uiRoot) {
29
- const files = await collectUiContractFiles(uiRoot);
30
- if (files.length === 0) {
31
- return [
32
- issue("QFAI-UI-000", "UI 契約ファイルが見つかりません。", "info", uiRoot, "contracts.ui.files"),
33
- ];
34
- }
35
- const issues = [];
36
- for (const file of files) {
37
- const text = await readFile(file, "utf-8");
38
- const invalidIds = extractInvalidIds(text, [
39
- "SPEC",
40
- "BR",
41
- "SC",
42
- "UI",
43
- "API",
44
- "DB",
45
- "ADR",
46
- ]);
47
- if (invalidIds.length > 0) {
48
- issues.push(issue("QFAI-ID-002", `ID フォーマットが不正です: ${invalidIds.join(", ")}`, "error", file, "id.format", invalidIds));
49
- }
50
- const declaredIds = extractDeclaredContractIds(text);
51
- issues.push(...validateDeclaredContractIds(declaredIds, file, "UI"));
52
- try {
53
- parseStructuredContract(file, stripContractDeclarationLines(text));
54
- }
55
- catch (error) {
56
- issues.push(issue("QFAI-CONTRACT-001", `UI 契約ファイルの解析に失敗しました: ${file} (${formatError(error)})`, "error", file, "contracts.ui.parse"));
57
- }
58
- }
59
- return issues;
60
- }
61
- async function validateApiContracts(apiRoot) {
62
- const files = await collectApiContractFiles(apiRoot);
63
- if (files.length === 0) {
64
- return [
65
- issue("QFAI-API-000", "API 契約ファイルが見つかりません。", "info", apiRoot, "contracts.api.files"),
66
- ];
67
- }
68
- const issues = [];
69
- for (const file of files) {
70
- const text = await readFile(file, "utf-8");
71
- const invalidIds = extractInvalidIds(text, [
72
- "SPEC",
73
- "BR",
74
- "SC",
75
- "UI",
76
- "API",
77
- "DB",
78
- "ADR",
79
- ]);
80
- if (invalidIds.length > 0) {
81
- issues.push(issue("QFAI-ID-002", `ID フォーマットが不正です: ${invalidIds.join(", ")}`, "error", file, "id.format", invalidIds));
82
- }
83
- const declaredIds = extractDeclaredContractIds(text);
84
- issues.push(...validateDeclaredContractIds(declaredIds, file, "API"));
85
- let doc;
86
- try {
87
- doc = parseStructuredContract(file, stripContractDeclarationLines(text));
88
- }
89
- catch (error) {
90
- issues.push(issue("QFAI-CONTRACT-001", `API 契約ファイルの解析に失敗しました: ${file} (${formatError(error)})`, "error", file, "contracts.api.parse"));
91
- continue;
92
- }
93
- if (!hasOpenApi(doc)) {
94
- issues.push(issue("QFAI-API-001", "OpenAPI 定義が見つかりません。", "error", file, "contracts.api.openapi"));
95
- }
96
- }
97
- return issues;
98
- }
99
- async function validateDbContracts(dbRoot) {
100
- const files = await collectDbContractFiles(dbRoot);
101
- if (files.length === 0) {
102
- return [
103
- issue("QFAI-DB-000", "DB 契約ファイルが見つかりません。", "info", dbRoot, "contracts.db.files"),
104
- ];
105
- }
106
- const issues = [];
107
- for (const file of files) {
108
- const text = await readFile(file, "utf-8");
109
- const invalidIds = extractInvalidIds(text, [
110
- "SPEC",
111
- "BR",
112
- "SC",
113
- "UI",
114
- "API",
115
- "DB",
116
- "ADR",
117
- ]);
118
- if (invalidIds.length > 0) {
119
- issues.push(issue("QFAI-ID-002", `ID フォーマットが不正です: ${invalidIds.join(", ")}`, "error", file, "id.format", invalidIds));
120
- }
121
- const declaredIds = extractDeclaredContractIds(text);
122
- issues.push(...validateDeclaredContractIds(declaredIds, file, "DB"));
123
- issues.push(...lintSql(text, file));
124
- }
125
- return issues;
126
- }
127
- export function lintSql(text, file) {
128
- const issues = [];
129
- for (const { pattern, label } of SQL_DANGEROUS_PATTERNS) {
130
- if (pattern.test(text)) {
131
- issues.push(issue("QFAI-DB-001", `危険な SQL 操作が含まれています: ${label}`, "warning", file, "contracts.db.sql"));
132
- }
133
- }
134
- return issues;
135
- }
136
- function validateDeclaredContractIds(ids, file, kind) {
137
- const issues = [];
138
- if (ids.length === 0) {
139
- issues.push(issue("QFAI-CONTRACT-010", `契約ファイルに QFAI-CONTRACT-ID がありません: ${file}`, "error", file, "contracts.declaration"));
140
- return issues;
141
- }
142
- if (ids.length > 1) {
143
- issues.push(issue("QFAI-CONTRACT-011", `契約ファイルに複数の QFAI-CONTRACT-ID が宣言されています: ${ids.join(", ")}`, "error", file, "contracts.declaration", ids));
144
- return issues;
145
- }
146
- const [id] = ids;
147
- if (id && !id.startsWith(`${kind}-`)) {
148
- issues.push(issue("QFAI-CONTRACT-013", `契約ファイルの QFAI-CONTRACT-ID が ${kind}- ではありません: ${id}`, "error", file, "contracts.declarationPrefix", [id]));
149
- }
150
- return issues;
151
- }
152
- function validateDuplicateContractIds(contractIndex) {
153
- const issues = [];
154
- for (const [id, files] of contractIndex.idToFiles.entries()) {
155
- if (files.size <= 1) {
156
- continue;
157
- }
158
- const sortedFiles = Array.from(files).sort((a, b) => a.localeCompare(b));
159
- issues.push(issue("QFAI-CONTRACT-012", `契約 ID が複数ファイルで宣言されています: ${id} (${sortedFiles.join(", ")})`, "error", sortedFiles[0], "contracts.idDuplicate", [id]));
160
- }
161
- return issues;
162
- }
163
- function hasOpenApi(doc) {
164
- return typeof doc.openapi === "string" && doc.openapi.length > 0;
165
- }
166
- function formatError(error) {
167
- if (error instanceof Error) {
168
- return error.message;
169
- }
170
- return String(error);
171
- }
172
- function issue(code, message, severity, file, rule, refs) {
173
- const issue = {
174
- code,
175
- severity,
176
- message,
177
- };
178
- if (file) {
179
- issue.file = file;
180
- }
181
- if (rule) {
182
- issue.rule = rule;
183
- }
184
- if (refs && refs.length > 0) {
185
- issue.refs = refs;
186
- }
187
- return issue;
188
- }
189
- //# sourceMappingURL=contracts.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../../src/core/validators/contracts.ts"],"names":[],"mappings":"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"}
@@ -1,4 +0,0 @@
1
- import type { QfaiConfig } from "../config.js";
2
- import type { Issue } from "../types.js";
3
- export declare function validateDeltas(root: string, config: QfaiConfig): Promise<Issue[]>;
4
- //# sourceMappingURL=delta.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delta.d.ts","sourceRoot":"","sources":["../../../src/core/validators/delta.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,aAAa,CAAC;AAQxD,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,KAAK,EAAE,CAAC,CA6DlB"}
@@ -1,68 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { resolvePath } from "../config.js";
4
- import { collectSpecPackDirs } from "../discovery.js";
5
- const SECTION_RE = /^##\s+変更区分/m;
6
- const COMPAT_LINE_RE = /^\s*-\s*\[[ xX]\]\s*Compatibility\b/m;
7
- const CHANGE_LINE_RE = /^\s*-\s*\[[ xX]\]\s*Change\/Improvement\b/m;
8
- const COMPAT_CHECKED_RE = /^\s*-\s*\[[xX]\]\s*Compatibility\b/m;
9
- const CHANGE_CHECKED_RE = /^\s*-\s*\[[xX]\]\s*Change\/Improvement\b/m;
10
- export async function validateDeltas(root, config) {
11
- const specsRoot = resolvePath(root, config, "specsDir");
12
- const packs = await collectSpecPackDirs(specsRoot);
13
- if (packs.length === 0) {
14
- return [];
15
- }
16
- const issues = [];
17
- for (const pack of packs) {
18
- const deltaPath = path.join(pack, "delta.md");
19
- let text;
20
- try {
21
- text = await readFile(deltaPath, "utf-8");
22
- }
23
- catch (error) {
24
- if (isMissingFileError(error)) {
25
- issues.push(issue("QFAI-DELTA-001", "delta.md が見つかりません。", "error", deltaPath, "delta.exists"));
26
- continue;
27
- }
28
- throw error;
29
- }
30
- const hasSection = SECTION_RE.test(text);
31
- const hasCompatibility = COMPAT_LINE_RE.test(text);
32
- const hasChange = CHANGE_LINE_RE.test(text);
33
- if (!hasSection || !hasCompatibility || !hasChange) {
34
- issues.push(issue("QFAI-DELTA-002", "delta.md の変更区分が不足しています。", "error", deltaPath, "delta.section"));
35
- continue;
36
- }
37
- const compatibilityChecked = COMPAT_CHECKED_RE.test(text);
38
- const changeChecked = CHANGE_CHECKED_RE.test(text);
39
- if (compatibilityChecked === changeChecked) {
40
- issues.push(issue("QFAI-DELTA-003", "delta.md の変更区分はどちらか1つだけ選択してください(両方ON/両方OFFは無効です)。", "error", deltaPath, "delta.classification"));
41
- }
42
- }
43
- return issues;
44
- }
45
- function isMissingFileError(error) {
46
- if (!error || typeof error !== "object") {
47
- return false;
48
- }
49
- return error.code === "ENOENT";
50
- }
51
- function issue(code, message, severity, file, rule, refs) {
52
- const issue = {
53
- code,
54
- severity,
55
- message,
56
- };
57
- if (file) {
58
- issue.file = file;
59
- }
60
- if (rule) {
61
- issue.rule = rule;
62
- }
63
- if (refs && refs.length > 0) {
64
- issue.refs = refs;
65
- }
66
- return issue;
67
- }
68
- //# sourceMappingURL=delta.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delta.js","sourceRoot":"","sources":["../../../src/core/validators/delta.ts"],"names":[],"mappings":"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"}
@@ -1,4 +0,0 @@
1
- import type { QfaiConfig } from "../config.js";
2
- import type { Issue } from "../types.js";
3
- export declare function validateDefinedIds(root: string, config: QfaiConfig): Promise<Issue[]>;
4
- //# sourceMappingURL=ids.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../../src/core/validators/ids.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,aAAa,CAAC;AAIxD,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,KAAK,EAAE,CAAC,CAmClB"}
@@ -1,88 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { resolvePath } from "../config.js";
4
- import { buildContractIndex } from "../contractIndex.js";
5
- import { collectScenarioFiles, collectSpecFiles } from "../discovery.js";
6
- import { parseSpec } from "../parse/spec.js";
7
- import { parseScenarioDocument } from "../scenarioModel.js";
8
- const SC_TAG_RE = /^SC-\d{4}$/;
9
- export async function validateDefinedIds(root, config) {
10
- const issues = [];
11
- const specsRoot = resolvePath(root, config, "specsDir");
12
- const specFiles = await collectSpecFiles(specsRoot);
13
- const scenarioFiles = await collectScenarioFiles(specsRoot);
14
- const defined = new Map();
15
- await collectSpecDefinitionIds(specFiles, defined);
16
- await collectScenarioDefinitionIds(scenarioFiles, defined);
17
- const contractIndex = await buildContractIndex(root, config);
18
- for (const [id, files] of contractIndex.idToFiles.entries()) {
19
- for (const file of files) {
20
- recordId(defined, id, file);
21
- }
22
- }
23
- for (const [id, files] of defined.entries()) {
24
- if (files.size <= 1) {
25
- continue;
26
- }
27
- const sorted = Array.from(files).sort();
28
- issues.push(issue("QFAI-ID-001", `ID が重複しています: ${id} (${formatFileList(sorted, root)})`, "error", sorted[0], "id.duplicate"));
29
- }
30
- return issues;
31
- }
32
- async function collectSpecDefinitionIds(files, out) {
33
- for (const file of files) {
34
- const text = await readFile(file, "utf-8");
35
- const parsed = parseSpec(text, file);
36
- if (parsed.specId) {
37
- recordId(out, parsed.specId, file);
38
- }
39
- parsed.brs.forEach((br) => recordId(out, br.id, file));
40
- }
41
- }
42
- async function collectScenarioDefinitionIds(files, out) {
43
- for (const file of files) {
44
- const text = await readFile(file, "utf-8");
45
- const { document, errors } = parseScenarioDocument(text, file);
46
- if (!document || errors.length > 0) {
47
- continue;
48
- }
49
- for (const scenario of document.scenarios) {
50
- for (const tag of scenario.tags) {
51
- if (SC_TAG_RE.test(tag)) {
52
- recordId(out, tag, file);
53
- }
54
- }
55
- }
56
- }
57
- }
58
- function recordId(out, id, file) {
59
- const current = out.get(id) ?? new Set();
60
- current.add(file);
61
- out.set(id, current);
62
- }
63
- function formatFileList(files, root) {
64
- return files
65
- .map((file) => {
66
- const relative = path.relative(root, file);
67
- return relative.length > 0 ? relative : file;
68
- })
69
- .join(", ");
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
- //# sourceMappingURL=ids.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ids.js","sourceRoot":"","sources":["../../../src/core/validators/ids.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import type { QfaiConfig } from "../config.js";
2
- import type { Issue } from "../types.js";
3
- export declare function validateScenarios(root: string, config: QfaiConfig): Promise<Issue[]>;
4
- export declare function validateScenarioContent(text: string, file: string): Issue[];
5
- //# sourceMappingURL=scenario.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../../src/core/validators/scenario.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK/C,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,aAAa,CAAC;AAQxD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,KAAK,EAAE,CAAC,CA0ClB;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CAwI3E"}
@@ -1,127 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { resolvePath } from "../config.js";
3
- import { extractInvalidIds } from "../ids.js";
4
- import { collectSpecEntries } from "../specLayout.js";
5
- import { parseScenarioDocument } from "../scenarioModel.js";
6
- const GIVEN_PATTERN = /\bGiven\b/;
7
- const WHEN_PATTERN = /\bWhen\b/;
8
- const THEN_PATTERN = /\bThen\b/;
9
- const SC_TAG_RE = /^SC-\d{4}$/;
10
- const SPEC_TAG_RE = /^SPEC-\d{4}$/;
11
- export async function validateScenarios(root, config) {
12
- const specsRoot = resolvePath(root, config, "specsDir");
13
- const entries = await collectSpecEntries(specsRoot);
14
- if (entries.length === 0) {
15
- const expected = "spec-0001/scenario.md";
16
- const legacy = "spec-001/scenario.md";
17
- return [
18
- issue("QFAI-SC-000", `Scenario ファイルが見つかりません。配置場所: ${config.paths.specsDir} / 期待パターン: ${expected} (${legacy} は非対応)`, "info", specsRoot, "scenario.files"),
19
- ];
20
- }
21
- const issues = [];
22
- for (const entry of entries) {
23
- let text;
24
- try {
25
- text = await readFile(entry.scenarioPath, "utf-8");
26
- }
27
- catch (error) {
28
- if (isMissingFileError(error)) {
29
- issues.push(issue("QFAI-SC-001", "scenario.md が見つかりません。", "error", entry.scenarioPath, "scenario.exists"));
30
- continue;
31
- }
32
- throw error;
33
- }
34
- issues.push(...validateScenarioContent(text, entry.scenarioPath));
35
- }
36
- return issues;
37
- }
38
- export function validateScenarioContent(text, file) {
39
- const issues = [];
40
- const invalidIds = extractInvalidIds(text, [
41
- "SPEC",
42
- "BR",
43
- "SC",
44
- "UI",
45
- "API",
46
- "DB",
47
- "ADR",
48
- ]);
49
- if (invalidIds.length > 0) {
50
- issues.push(issue("QFAI-ID-002", `ID フォーマットが不正です: ${invalidIds.join(", ")}`, "error", file, "id.format", invalidIds));
51
- }
52
- const { document, errors } = parseScenarioDocument(text, file);
53
- if (!document || errors.length > 0) {
54
- issues.push(issue("QFAI-SC-010", `Gherkin の解析に失敗しました: ${errors.join(", ") || "unknown"}`, "error", file, "scenario.parse"));
55
- return issues;
56
- }
57
- const featureSpecTags = document.featureTags.filter((tag) => SPEC_TAG_RE.test(tag));
58
- if (featureSpecTags.length > 1) {
59
- issues.push(issue("QFAI-SC-009", `Feature の SPEC タグが複数あります: ${featureSpecTags.join(", ")}`, "error", file, "scenario.featureSpec", featureSpecTags));
60
- }
61
- const missingStructure = [];
62
- if (!document.featureName)
63
- missingStructure.push("Feature");
64
- if (document.scenarios.length === 0)
65
- missingStructure.push("Scenario");
66
- if (missingStructure.length > 0) {
67
- issues.push(issue("QFAI-SC-006", `Scenario ファイルに必要な構造がありません: ${missingStructure.join(", ")}`, "error", file, "scenario.structure"));
68
- }
69
- for (const scenario of document.scenarios) {
70
- if (scenario.tags.length === 0) {
71
- issues.push(issue("QFAI-SC-007", `Scenario タグが見つかりません: ${scenario.name}`, "error", file, "scenario.tags"));
72
- continue;
73
- }
74
- const missingTags = [];
75
- const scTags = scenario.tags.filter((tag) => SC_TAG_RE.test(tag));
76
- if (scTags.length === 0) {
77
- missingTags.push("SC(0件)");
78
- }
79
- else if (scTags.length > 1) {
80
- missingTags.push(`SC(${scTags.length}件/1件必須)`);
81
- }
82
- if (missingTags.length > 0) {
83
- issues.push(issue("QFAI-SC-008", `Scenario タグに不足があります: ${missingTags.join(", ")} (${scenario.name})`, "error", file, "scenario.tagIds"));
84
- }
85
- }
86
- for (const scenario of document.scenarios) {
87
- const missingSteps = [];
88
- const keywords = scenario.steps.map((step) => step.keyword.trim());
89
- if (!keywords.some((keyword) => GIVEN_PATTERN.test(keyword))) {
90
- missingSteps.push("Given");
91
- }
92
- if (!keywords.some((keyword) => WHEN_PATTERN.test(keyword))) {
93
- missingSteps.push("When");
94
- }
95
- if (!keywords.some((keyword) => THEN_PATTERN.test(keyword))) {
96
- missingSteps.push("Then");
97
- }
98
- if (missingSteps.length > 0) {
99
- issues.push(issue("QFAI-SC-005", `Given/When/Then が不足しています: ${missingSteps.join(", ")} (${scenario.name})`, "warning", file, "scenario.steps"));
100
- }
101
- }
102
- return issues;
103
- }
104
- function issue(code, message, severity, file, rule, refs) {
105
- const issue = {
106
- code,
107
- severity,
108
- message,
109
- };
110
- if (file) {
111
- issue.file = file;
112
- }
113
- if (rule) {
114
- issue.rule = rule;
115
- }
116
- if (refs && refs.length > 0) {
117
- issue.refs = refs;
118
- }
119
- return issue;
120
- }
121
- function isMissingFileError(error) {
122
- if (!error || typeof error !== "object") {
123
- return false;
124
- }
125
- return error.code === "ENOENT";
126
- }
127
- //# sourceMappingURL=scenario.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scenario.js","sourceRoot":"","sources":["../../../src/core/validators/scenario.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import type { QfaiConfig } from "../config.js";
2
- import type { Issue } from "../types.js";
3
- export declare function validateSpecs(root: string, config: QfaiConfig): Promise<Issue[]>;
4
- export declare function validateSpecContent(text: string, file: string, requiredSections: string[]): Issue[];
5
- //# sourceMappingURL=spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../src/core/validators/spec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK/C,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,aAAa,CAAC;AAExD,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,KAAK,EAAE,CAAC,CAgDlB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,MAAM,EAAE,GACzB,KAAK,EAAE,CA0GT"}
@@ -1,94 +0,0 @@
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
- "DB",
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