@reqord/shared 0.1.0

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 (107) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +38 -0
  3. package/dist/constants/index.d.ts +2 -0
  4. package/dist/constants/index.d.ts.map +1 -0
  5. package/dist/constants/index.js +2 -0
  6. package/dist/constants/index.js.map +1 -0
  7. package/dist/constants/paths.d.ts +13 -0
  8. package/dist/constants/paths.d.ts.map +1 -0
  9. package/dist/constants/paths.js +13 -0
  10. package/dist/constants/paths.js.map +1 -0
  11. package/dist/constants/paths.test.d.ts +2 -0
  12. package/dist/constants/paths.test.d.ts.map +1 -0
  13. package/dist/constants/paths.test.js +11 -0
  14. package/dist/constants/paths.test.js.map +1 -0
  15. package/dist/index.d.ts +7 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +7 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/rules/consistency.d.ts +12 -0
  20. package/dist/rules/consistency.d.ts.map +1 -0
  21. package/dist/rules/consistency.js +34 -0
  22. package/dist/rules/consistency.js.map +1 -0
  23. package/dist/rules/consistency.test.d.ts +2 -0
  24. package/dist/rules/consistency.test.d.ts.map +1 -0
  25. package/dist/rules/consistency.test.js +97 -0
  26. package/dist/rules/consistency.test.js.map +1 -0
  27. package/dist/rules/index.d.ts +3 -0
  28. package/dist/rules/index.d.ts.map +1 -0
  29. package/dist/rules/index.js +3 -0
  30. package/dist/rules/index.js.map +1 -0
  31. package/dist/rules/status-transitions.d.ts +5 -0
  32. package/dist/rules/status-transitions.d.ts.map +1 -0
  33. package/dist/rules/status-transitions.js +13 -0
  34. package/dist/rules/status-transitions.js.map +1 -0
  35. package/dist/rules/status-transitions.test.d.ts +2 -0
  36. package/dist/rules/status-transitions.test.d.ts.map +1 -0
  37. package/dist/rules/status-transitions.test.js +53 -0
  38. package/dist/rules/status-transitions.test.js.map +1 -0
  39. package/dist/schemas/common.d.ts +33 -0
  40. package/dist/schemas/common.d.ts.map +1 -0
  41. package/dist/schemas/common.js +19 -0
  42. package/dist/schemas/common.js.map +1 -0
  43. package/dist/schemas/feedback.d.ts +249 -0
  44. package/dist/schemas/feedback.d.ts.map +1 -0
  45. package/dist/schemas/feedback.js +39 -0
  46. package/dist/schemas/feedback.js.map +1 -0
  47. package/dist/schemas/feedback.test.d.ts +2 -0
  48. package/dist/schemas/feedback.test.d.ts.map +1 -0
  49. package/dist/schemas/feedback.test.js +234 -0
  50. package/dist/schemas/feedback.test.js.map +1 -0
  51. package/dist/schemas/index.d.ts +8 -0
  52. package/dist/schemas/index.d.ts.map +1 -0
  53. package/dist/schemas/index.js +8 -0
  54. package/dist/schemas/index.js.map +1 -0
  55. package/dist/schemas/project-context.d.ts +116 -0
  56. package/dist/schemas/project-context.d.ts.map +1 -0
  57. package/dist/schemas/project-context.js +25 -0
  58. package/dist/schemas/project-context.js.map +1 -0
  59. package/dist/schemas/requirement.d.ts +242 -0
  60. package/dist/schemas/requirement.d.ts.map +1 -0
  61. package/dist/schemas/requirement.js +52 -0
  62. package/dist/schemas/requirement.js.map +1 -0
  63. package/dist/schemas/requirement.test.d.ts +2 -0
  64. package/dist/schemas/requirement.test.d.ts.map +1 -0
  65. package/dist/schemas/requirement.test.js +38 -0
  66. package/dist/schemas/requirement.test.js.map +1 -0
  67. package/dist/schemas/specification.d.ts +217 -0
  68. package/dist/schemas/specification.d.ts.map +1 -0
  69. package/dist/schemas/specification.js +32 -0
  70. package/dist/schemas/specification.js.map +1 -0
  71. package/dist/schemas/specification.test.d.ts +2 -0
  72. package/dist/schemas/specification.test.d.ts.map +1 -0
  73. package/dist/schemas/specification.test.js +89 -0
  74. package/dist/schemas/specification.test.js.map +1 -0
  75. package/dist/schemas/task.d.ts +177 -0
  76. package/dist/schemas/task.d.ts.map +1 -0
  77. package/dist/schemas/task.js +29 -0
  78. package/dist/schemas/task.js.map +1 -0
  79. package/dist/schemas/task.test.d.ts +2 -0
  80. package/dist/schemas/task.test.d.ts.map +1 -0
  81. package/dist/schemas/task.test.js +203 -0
  82. package/dist/schemas/task.test.js.map +1 -0
  83. package/dist/schemas/validation.d.ts +174 -0
  84. package/dist/schemas/validation.d.ts.map +1 -0
  85. package/dist/schemas/validation.js +31 -0
  86. package/dist/schemas/validation.js.map +1 -0
  87. package/dist/utils/zod-error-formatter.d.ts +25 -0
  88. package/dist/utils/zod-error-formatter.d.ts.map +1 -0
  89. package/dist/utils/zod-error-formatter.js +115 -0
  90. package/dist/utils/zod-error-formatter.js.map +1 -0
  91. package/dist/utils/zod-error-formatter.test.d.ts +2 -0
  92. package/dist/utils/zod-error-formatter.test.d.ts.map +1 -0
  93. package/dist/utils/zod-error-formatter.test.js +314 -0
  94. package/dist/utils/zod-error-formatter.test.js.map +1 -0
  95. package/dist/validation/ambiguous-phrases.d.ts +11 -0
  96. package/dist/validation/ambiguous-phrases.d.ts.map +1 -0
  97. package/dist/validation/ambiguous-phrases.js +56 -0
  98. package/dist/validation/ambiguous-phrases.js.map +1 -0
  99. package/dist/validation/smart-scoring.d.ts +15 -0
  100. package/dist/validation/smart-scoring.d.ts.map +1 -0
  101. package/dist/validation/smart-scoring.js +225 -0
  102. package/dist/validation/smart-scoring.js.map +1 -0
  103. package/dist/validation/smart-scoring.test.d.ts +2 -0
  104. package/dist/validation/smart-scoring.test.d.ts.map +1 -0
  105. package/dist/validation/smart-scoring.test.js +136 -0
  106. package/dist/validation/smart-scoring.test.js.map +1 -0
  107. package/package.json +40 -0
@@ -0,0 +1,314 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { formatPath, formatZodIssue, formatZodError } from "./zod-error-formatter.js";
3
+ import { z, ZodError } from "zod";
4
+ import { RequirementSchema } from "../schemas/requirement.js";
5
+ describe("formatPath", () => {
6
+ it("空の配列は (root) を返す", () => {
7
+ expect(formatPath([])).toBe("(root)");
8
+ });
9
+ it("単一要素は要素名を返す", () => {
10
+ expect(formatPath(["status"])).toBe("status");
11
+ });
12
+ it("ネストしたパスはドット区切りで返す", () => {
13
+ expect(formatPath(["dependencies", "blockedBy"])).toBe("dependencies.blockedBy");
14
+ });
15
+ it("配列インデックスは角括弧で返す", () => {
16
+ expect(formatPath(["dependencies", "blockedBy", 0])).toBe("dependencies.blockedBy[0]");
17
+ });
18
+ it("複雑なパスを正しくフォーマットする", () => {
19
+ expect(formatPath(["arr", 1, "nested", 2])).toBe("arr[1].nested[2]");
20
+ });
21
+ it("複数のネストした配列インデックスを処理する", () => {
22
+ expect(formatPath(["a", 0, "b", 1, "c", 2])).toBe("a[0].b[1].c[2]");
23
+ });
24
+ });
25
+ describe("formatZodIssue", () => {
26
+ describe("invalid_type", () => {
27
+ it("型が不正な場合のメッセージをフォーマットする", () => {
28
+ const schema = z.object({ status: z.string() });
29
+ const result = schema.safeParse({ status: 123 });
30
+ expect(result.success).toBe(false);
31
+ if (!result.success) {
32
+ const issue = result.error.issues[0];
33
+ const message = formatZodIssue(issue);
34
+ expect(message).toBe("status: 文字列が必要です(実際の型: 数値)");
35
+ }
36
+ });
37
+ it("オブジェクトが必要な場合", () => {
38
+ const schema = z.object({ data: z.object({ name: z.string() }) });
39
+ const result = schema.safeParse({ data: "not-object" });
40
+ expect(result.success).toBe(false);
41
+ if (!result.success) {
42
+ const issue = result.error.issues[0];
43
+ const message = formatZodIssue(issue);
44
+ expect(message).toBe("data: オブジェクトが必要です(実際の型: 文字列)");
45
+ }
46
+ });
47
+ it("配列が必要な場合", () => {
48
+ const schema = z.object({ items: z.array(z.string()) });
49
+ const result = schema.safeParse({ items: "not-array" });
50
+ expect(result.success).toBe(false);
51
+ if (!result.success) {
52
+ const issue = result.error.issues[0];
53
+ const message = formatZodIssue(issue);
54
+ expect(message).toBe("items: 配列が必要です(実際の型: 文字列)");
55
+ }
56
+ });
57
+ });
58
+ describe("invalid_enum_value", () => {
59
+ it("enumの値が不正な場合", () => {
60
+ const schema = z.object({ status: z.enum(["draft", "active", "completed"]) });
61
+ const result = schema.safeParse({ status: "invalid" });
62
+ expect(result.success).toBe(false);
63
+ if (!result.success) {
64
+ const issue = result.error.issues[0];
65
+ const message = formatZodIssue(issue);
66
+ expect(message).toBe("status: 不正な値 'invalid'(期待値: 'draft', 'active', 'completed')");
67
+ }
68
+ });
69
+ });
70
+ describe("too_small", () => {
71
+ it("文字列が短すぎる場合", () => {
72
+ const schema = z.object({ name: z.string().min(5) });
73
+ const result = schema.safeParse({ name: "ab" });
74
+ expect(result.success).toBe(false);
75
+ if (!result.success) {
76
+ const issue = result.error.issues[0];
77
+ const message = formatZodIssue(issue);
78
+ expect(message).toBe("name: 5文字以上の文字列が必要です");
79
+ }
80
+ });
81
+ it("数値が小さすぎる場合", () => {
82
+ const schema = z.object({ age: z.number().min(18) });
83
+ const result = schema.safeParse({ age: 10 });
84
+ expect(result.success).toBe(false);
85
+ if (!result.success) {
86
+ const issue = result.error.issues[0];
87
+ const message = formatZodIssue(issue);
88
+ expect(message).toBe("age: 18以上の数値が必要です");
89
+ }
90
+ });
91
+ it("正の数値が必要な場合", () => {
92
+ const schema = z.object({ count: z.number().positive() });
93
+ const result = schema.safeParse({ count: -5 });
94
+ expect(result.success).toBe(false);
95
+ if (!result.success) {
96
+ const issue = result.error.issues[0];
97
+ const message = formatZodIssue(issue);
98
+ expect(message).toBe("count: 正の数値が必要です");
99
+ }
100
+ });
101
+ it("配列の要素数が少ない場合", () => {
102
+ const schema = z.object({ items: z.array(z.string()).min(3) });
103
+ const result = schema.safeParse({ items: ["a"] });
104
+ expect(result.success).toBe(false);
105
+ if (!result.success) {
106
+ const issue = result.error.issues[0];
107
+ const message = formatZodIssue(issue);
108
+ expect(message).toBe("items: 3個以上の要素が必要です");
109
+ }
110
+ });
111
+ it("未サポートの型の場合はissue.messageを使用(fallback)", () => {
112
+ const schema = z.object({ value: z.date().min(new Date("2025-01-01")) });
113
+ const result = schema.safeParse({ value: new Date("2024-01-01") });
114
+ expect(result.success).toBe(false);
115
+ if (!result.success) {
116
+ const issue = result.error.issues[0];
117
+ const message = formatZodIssue(issue);
118
+ expect(message).toBe(`value: ${issue.message}`);
119
+ }
120
+ });
121
+ });
122
+ describe("too_big", () => {
123
+ it("文字列が長すぎる場合", () => {
124
+ const schema = z.object({ name: z.string().max(5) });
125
+ const result = schema.safeParse({ name: "abcdefghij" });
126
+ expect(result.success).toBe(false);
127
+ if (!result.success) {
128
+ const issue = result.error.issues[0];
129
+ const message = formatZodIssue(issue);
130
+ expect(message).toBe("name: 5文字以下の文字列が必要です");
131
+ }
132
+ });
133
+ it("数値が大きすぎる場合", () => {
134
+ const schema = z.object({ age: z.number().max(100) });
135
+ const result = schema.safeParse({ age: 150 });
136
+ expect(result.success).toBe(false);
137
+ if (!result.success) {
138
+ const issue = result.error.issues[0];
139
+ const message = formatZodIssue(issue);
140
+ expect(message).toBe("age: 100以下の数値が必要です");
141
+ }
142
+ });
143
+ it("配列の要素数が多い場合", () => {
144
+ const schema = z.object({ items: z.array(z.string()).max(2) });
145
+ const result = schema.safeParse({ items: ["a", "b", "c", "d"] });
146
+ expect(result.success).toBe(false);
147
+ if (!result.success) {
148
+ const issue = result.error.issues[0];
149
+ const message = formatZodIssue(issue);
150
+ expect(message).toBe("items: 2個以下の要素が必要です");
151
+ }
152
+ });
153
+ it("未サポートの型の場合はissue.messageを使用(fallback)", () => {
154
+ const schema = z.object({ value: z.set(z.string()).max(2) });
155
+ const result = schema.safeParse({ value: new Set(["a", "b", "c"]) });
156
+ expect(result.success).toBe(false);
157
+ if (!result.success) {
158
+ const issue = result.error.issues[0];
159
+ const message = formatZodIssue(issue);
160
+ expect(message).toBe(`value: ${issue.message}`);
161
+ }
162
+ });
163
+ });
164
+ describe("invalid_string", () => {
165
+ it("メールアドレスの形式が不正な場合", () => {
166
+ const schema = z.object({ email: z.string().email() });
167
+ const result = schema.safeParse({ email: "not-an-email" });
168
+ expect(result.success).toBe(false);
169
+ if (!result.success) {
170
+ const issue = result.error.issues[0];
171
+ const message = formatZodIssue(issue);
172
+ expect(message).toBe("email: 形式が不正です");
173
+ }
174
+ });
175
+ it("URLの形式が不正な場合", () => {
176
+ const schema = z.object({ url: z.string().url() });
177
+ const result = schema.safeParse({ url: "not-a-url" });
178
+ expect(result.success).toBe(false);
179
+ if (!result.success) {
180
+ const issue = result.error.issues[0];
181
+ const message = formatZodIssue(issue);
182
+ expect(message).toBe("url: 形式が不正です");
183
+ }
184
+ });
185
+ });
186
+ describe("unrecognized_keys", () => {
187
+ it("不明なフィールドがある場合", () => {
188
+ const schema = z.object({ name: z.string() }).strict();
189
+ const result = schema.safeParse({ name: "test", unknown1: "value1", unknown2: "value2" });
190
+ expect(result.success).toBe(false);
191
+ if (!result.success) {
192
+ const issue = result.error.issues[0];
193
+ const message = formatZodIssue(issue);
194
+ expect(message).toBe("(root): 不明なフィールド 'unknown1, unknown2'");
195
+ }
196
+ });
197
+ });
198
+ describe("fallback", () => {
199
+ it("その他のエラーコードの場合はissue.messageを使用", () => {
200
+ const schema = z.object({ value: z.string().refine((val) => val.includes("test"), {
201
+ message: "Must contain 'test'"
202
+ }) });
203
+ const result = schema.safeParse({ value: "no-match" });
204
+ expect(result.success).toBe(false);
205
+ if (!result.success) {
206
+ const issue = result.error.issues[0];
207
+ const message = formatZodIssue(issue);
208
+ expect(message).toBe(`value: ${issue.message}`);
209
+ }
210
+ });
211
+ });
212
+ });
213
+ describe("formatZodError", () => {
214
+ it("空のissues配列の場合は空文字列を返す", () => {
215
+ const error = new ZodError([]);
216
+ const message = formatZodError(error);
217
+ expect(message).toBe("");
218
+ });
219
+ it("単一のエラーをデフォルトオプションでフォーマットする", () => {
220
+ const schema = z.object({ name: z.string() });
221
+ const result = schema.safeParse({ name: 123 });
222
+ expect(result.success).toBe(false);
223
+ if (!result.success) {
224
+ const message = formatZodError(result.error);
225
+ expect(message).toBe("- name: 文字列が必要です(実際の型: 数値)");
226
+ }
227
+ });
228
+ it("複数のエラーを改行区切りでフォーマットする", () => {
229
+ const schema = z.object({
230
+ name: z.string(),
231
+ age: z.number(),
232
+ email: z.string().email(),
233
+ });
234
+ const result = schema.safeParse({ name: 123, age: "not-a-number", email: "invalid" });
235
+ expect(result.success).toBe(false);
236
+ if (!result.success) {
237
+ const message = formatZodError(result.error);
238
+ const lines = message.split("\n");
239
+ expect(lines).toHaveLength(3);
240
+ expect(lines[0]).toBe("- name: 文字列が必要です(実際の型: 数値)");
241
+ expect(lines[1]).toBe("- age: 数値が必要です(実際の型: 文字列)");
242
+ expect(lines[2]).toBe("- email: 形式が不正です");
243
+ }
244
+ });
245
+ it("カスタムprefixを使用できる", () => {
246
+ const schema = z.object({ name: z.string() });
247
+ const result = schema.safeParse({ name: 123 });
248
+ expect(result.success).toBe(false);
249
+ if (!result.success) {
250
+ const message = formatZodError(result.error, { prefix: " * " });
251
+ expect(message).toBe(" * name: 文字列が必要です(実際の型: 数値)");
252
+ }
253
+ });
254
+ it("カスタムseparatorを使用できる", () => {
255
+ const schema = z.object({
256
+ name: z.string(),
257
+ age: z.number(),
258
+ });
259
+ const result = schema.safeParse({ name: 123, age: "not-a-number" });
260
+ expect(result.success).toBe(false);
261
+ if (!result.success) {
262
+ const message = formatZodError(result.error, { separator: " | " });
263
+ expect(message).toBe("- name: 文字列が必要です(実際の型: 数値) | - age: 数値が必要です(実際の型: 文字列)");
264
+ }
265
+ });
266
+ it("prefix空文字列とseparatorカスタム指定の組み合わせ", () => {
267
+ const schema = z.object({
268
+ name: z.string(),
269
+ age: z.number(),
270
+ });
271
+ const result = schema.safeParse({ name: 123, age: "not-a-number" });
272
+ expect(result.success).toBe(false);
273
+ if (!result.success) {
274
+ const message = formatZodError(result.error, { prefix: "", separator: ", " });
275
+ expect(message).toBe("name: 文字列が必要です(実際の型: 数値), age: 数値が必要です(実際の型: 文字列)");
276
+ }
277
+ });
278
+ });
279
+ describe("formatZodError - RequirementSchemaとの統合", () => {
280
+ it("IDの形式エラーをフォーマットする", () => {
281
+ const result = RequirementSchema.safeParse({
282
+ id: "invalid-id",
283
+ title: "Test",
284
+ createdAt: "2025-01-01T00:00:00Z",
285
+ updatedAt: "2025-01-01T00:00:00Z",
286
+ files: { description: "test.md" },
287
+ format: { type: "free-form" },
288
+ });
289
+ expect(result.success).toBe(false);
290
+ if (!result.success) {
291
+ const message = formatZodError(result.error);
292
+ expect(message).toContain("id:");
293
+ expect(message).toContain("形式が不正です");
294
+ }
295
+ });
296
+ it("複数の深くネストしたエラーをフォーマットする", () => {
297
+ const result = RequirementSchema.safeParse({
298
+ id: "req-000001",
299
+ title: "Test",
300
+ createdAt: "2025-01-01T00:00:00Z",
301
+ updatedAt: "2025-01-01T00:00:00Z",
302
+ files: { description: "test.md" },
303
+ format: { type: "user-story", userStory: { as: "", iWant: 123, soThat: "value" } },
304
+ estimatedHours: -5,
305
+ });
306
+ expect(result.success).toBe(false);
307
+ if (!result.success) {
308
+ const message = formatZodError(result.error);
309
+ const lines = message.split("\n");
310
+ expect(lines.length).toBeGreaterThanOrEqual(2);
311
+ }
312
+ });
313
+ });
314
+ //# sourceMappingURL=zod-error-formatter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-error-formatter.test.js","sourceRoot":"","sources":["../../src/utils/zod-error-formatter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 曖昧表現リスト — 要件の品質チェックで使用
3
+ * 現在はJapanese-onlyスコープ(v0.1)
4
+ */
5
+ export declare const AMBIGUOUS_PHRASES_JA: readonly ["適切に", "適切な", "なるべく", "できるだけ", "可能な限り", "必要に応じて", "等", "など", "その他", "ある程度", "十分に", "十分な", "高速に", "高速な", "効率的に", "効率的な", "柔軟に", "柔軟な", "簡単に", "容易に", "使いやすい", "わかりやすい", "見やすい", "きれいに", "きれいな", "スムーズに", "スムーズな", "シンプルに", "シンプルな", "正しく", "うまく", "良い", "悪い", "多い", "少ない", "大きい", "小さい"];
6
+ /**
7
+ * 言語コードに応じた曖昧表現リストを返す。
8
+ * 現時点ではjaのみ。将来はlanguage codeで切り替え可能。
9
+ */
10
+ export declare function getAmbiguousPhrases(language?: string): readonly string[];
11
+ //# sourceMappingURL=ambiguous-phrases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ambiguous-phrases.d.ts","sourceRoot":"","sources":["../../src/validation/ambiguous-phrases.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,oBAAoB,mSAsCvB,CAAC;AAEX;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,MAAa,GAAG,SAAS,MAAM,EAAE,CAO9E"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * 曖昧表現リスト — 要件の品質チェックで使用
3
+ * 現在はJapanese-onlyスコープ(v0.1)
4
+ */
5
+ export const AMBIGUOUS_PHRASES_JA = [
6
+ "適切に",
7
+ "適切な",
8
+ "なるべく",
9
+ "できるだけ",
10
+ "可能な限り",
11
+ "必要に応じて",
12
+ "等",
13
+ "など",
14
+ "その他",
15
+ "ある程度",
16
+ "十分に",
17
+ "十分な",
18
+ "高速に",
19
+ "高速な",
20
+ "効率的に",
21
+ "効率的な",
22
+ "柔軟に",
23
+ "柔軟な",
24
+ "簡単に",
25
+ "容易に",
26
+ "使いやすい",
27
+ "わかりやすい",
28
+ "見やすい",
29
+ "きれいに",
30
+ "きれいな",
31
+ "スムーズに",
32
+ "スムーズな",
33
+ "シンプルに",
34
+ "シンプルな",
35
+ "正しく",
36
+ "うまく",
37
+ "良い",
38
+ "悪い",
39
+ "多い",
40
+ "少ない",
41
+ "大きい",
42
+ "小さい",
43
+ ];
44
+ /**
45
+ * 言語コードに応じた曖昧表現リストを返す。
46
+ * 現時点ではjaのみ。将来はlanguage codeで切り替え可能。
47
+ */
48
+ export function getAmbiguousPhrases(language = "ja") {
49
+ switch (language) {
50
+ case "ja":
51
+ return AMBIGUOUS_PHRASES_JA;
52
+ default:
53
+ return AMBIGUOUS_PHRASES_JA; // TODO: i18n — 英語等の曖昧表現リスト追加
54
+ }
55
+ }
56
+ //# sourceMappingURL=ambiguous-phrases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ambiguous-phrases.js","sourceRoot":"","sources":["../../src/validation/ambiguous-phrases.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,KAAK;IACL,KAAK;IACL,MAAM;IACN,OAAO;IACP,OAAO;IACP,QAAQ;IACR,GAAG;IACH,IAAI;IACJ,KAAK;IACL,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,OAAO;IACP,QAAQ;IACR,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,KAAK;IACL,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,KAAK;IACL,KAAK;CACG,CAAC;AAEX;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB,IAAI;IACzD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,oBAAoB,CAAC;QAC9B;YACE,OAAO,oBAAoB,CAAC,CAAC,6BAA6B;IAC9D,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Requirement } from "../schemas/requirement.js";
2
+ import type { SmartScore } from "../schemas/validation.js";
3
+ export interface SmartScoringInput {
4
+ requirement: Requirement;
5
+ description: string | null;
6
+ language?: string;
7
+ }
8
+ /**
9
+ * SMART基準に基づくスコアを算出する。
10
+ * ルールベース(AI不要)でオフライン動作する。
11
+ */
12
+ export declare function calculateSmartScore(input: SmartScoringInput): SmartScore;
13
+ export declare function countAmbiguousPhrases(text: string, phrases: readonly string[]): number;
14
+ export declare function isComplexityHoursConsistent(complexity: string, hours: number): boolean;
15
+ //# sourceMappingURL=smart-scoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-scoring.d.ts","sourceRoot":"","sources":["../../src/validation/smart-scoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAG3D,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,UAAU,CAgBxE;AAoLD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAMtF;AASD,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAItF"}
@@ -0,0 +1,225 @@
1
+ import { getAmbiguousPhrases } from "./ambiguous-phrases.js";
2
+ /**
3
+ * SMART基準に基づくスコアを算出する。
4
+ * ルールベース(AI不要)でオフライン動作する。
5
+ */
6
+ export function calculateSmartScore(input) {
7
+ const specific = scoreSpecific(input);
8
+ const measurable = scoreMeasurable(input);
9
+ const achievable = scoreAchievable(input);
10
+ const relevant = scoreRelevant(input);
11
+ const timeBound = scoreTimeBound(input);
12
+ const overall = (specific + measurable + achievable + relevant + timeBound) / 5;
13
+ return {
14
+ specific: round(specific),
15
+ measurable: round(measurable),
16
+ achievable: round(achievable),
17
+ relevant: round(relevant),
18
+ timeBound: round(timeBound),
19
+ overall: round(overall),
20
+ };
21
+ }
22
+ function round(value) {
23
+ return Math.round(value * 100) / 100;
24
+ }
25
+ /**
26
+ * Specific: 具体性スコア
27
+ * - タイトルの長さ
28
+ * - description有無・長さ
29
+ * - format詳細の充実度
30
+ * - 曖昧表現の少なさ
31
+ */
32
+ function scoreSpecific(input) {
33
+ const { requirement, description, language } = input;
34
+ let score = 0;
35
+ // タイトルの充実度 (0〜0.2)
36
+ if (requirement.title.length >= 10)
37
+ score += 0.2;
38
+ else if (requirement.title.length >= 5)
39
+ score += 0.1;
40
+ // description有無・長さ (0〜0.3)
41
+ if (description) {
42
+ if (description.length >= 200)
43
+ score += 0.3;
44
+ else if (description.length >= 50)
45
+ score += 0.2;
46
+ else
47
+ score += 0.1;
48
+ }
49
+ // format詳細の充実度 (0〜0.3)
50
+ score += scoreFormatDetail(requirement);
51
+ // 曖昧表現の少なさ (0〜0.2)
52
+ const ambiguousPhrases = getAmbiguousPhrases(language);
53
+ const allText = gatherText(requirement, description);
54
+ const ambiguousCount = countAmbiguousPhrases(allText, ambiguousPhrases);
55
+ if (ambiguousCount === 0)
56
+ score += 0.2;
57
+ else if (ambiguousCount <= 2)
58
+ score += 0.1;
59
+ return Math.min(score, 1);
60
+ }
61
+ /**
62
+ * Measurable: 測定可能性スコア
63
+ * - 成功基準の数と具体性
64
+ */
65
+ function scoreMeasurable(input) {
66
+ const { requirement } = input;
67
+ const criteria = requirement.successCriteria;
68
+ let score = 0;
69
+ // 成功基準の有無 (0〜0.4)
70
+ if (criteria.length >= 3)
71
+ score += 0.4;
72
+ else if (criteria.length >= 1)
73
+ score += 0.2;
74
+ // 成功基準の具体性 — 平均文字数 (0〜0.3)
75
+ if (criteria.length > 0) {
76
+ const avgLen = criteria.reduce((sum, c) => sum + c.length, 0) / criteria.length;
77
+ if (avgLen >= 30)
78
+ score += 0.3;
79
+ else if (avgLen >= 15)
80
+ score += 0.2;
81
+ else
82
+ score += 0.1;
83
+ }
84
+ // 数値的な基準が含まれているか (0〜0.3)
85
+ const hasNumeric = criteria.some((c) => /\d+/.test(c));
86
+ if (hasNumeric)
87
+ score += 0.3;
88
+ else if (criteria.length > 0)
89
+ score += 0.1;
90
+ return Math.min(score, 1);
91
+ }
92
+ /**
93
+ * Achievable: 達成可能性スコア
94
+ * - 複雑度と見積もり時間の整合性
95
+ * - 依存関係の明確性
96
+ */
97
+ function scoreAchievable(input) {
98
+ const { requirement } = input;
99
+ let score = 0.5; // ベーススコア
100
+ // 複雑度が設定されている (0〜0.2)
101
+ if (requirement.estimatedComplexity)
102
+ score += 0.2;
103
+ // 見積もり時間が設定されている (0〜0.2)
104
+ if (requirement.estimatedHours)
105
+ score += 0.2;
106
+ // 複雑度と見積もり時間の整合性 (0〜0.1)
107
+ if (requirement.estimatedComplexity && requirement.estimatedHours) {
108
+ if (isComplexityHoursConsistent(requirement.estimatedComplexity, requirement.estimatedHours)) {
109
+ score += 0.1;
110
+ }
111
+ }
112
+ return Math.min(score, 1);
113
+ }
114
+ /**
115
+ * Relevant: 関連性スコア
116
+ * - formatが充実しているか(ユーザーストーリー/EARS)
117
+ * - 依存関係が定義されているか
118
+ */
119
+ function scoreRelevant(input) {
120
+ const { requirement } = input;
121
+ let score = 0.4; // ベーススコア
122
+ // formatタイプが具体的か (0〜0.3)
123
+ if (requirement.format.type === "user-story") {
124
+ const us = requirement.format.userStory;
125
+ if (us.as && us.iWant && us.soThat)
126
+ score += 0.3;
127
+ else if (us.as || us.iWant)
128
+ score += 0.15;
129
+ }
130
+ else if (requirement.format.type === "ears") {
131
+ const ears = requirement.format.ears;
132
+ if (ears.action)
133
+ score += 0.3;
134
+ else
135
+ score += 0.15;
136
+ }
137
+ else {
138
+ score += 0.1; // free-form
139
+ }
140
+ // 依存関係が定義されているか (0〜0.3)
141
+ const deps = requirement.dependencies;
142
+ const hasDeps = deps.blockedBy.length > 0 || deps.blocks.length > 0 || deps.relatedTo.length > 0;
143
+ if (hasDeps)
144
+ score += 0.3;
145
+ else
146
+ score += 0.1;
147
+ return Math.min(score, 1);
148
+ }
149
+ /**
150
+ * TimeBound: 期限・時間制約スコア
151
+ * - 見積もり時間の有無
152
+ * - 複雑度の設定
153
+ */
154
+ function scoreTimeBound(input) {
155
+ const { requirement } = input;
156
+ let score = 0;
157
+ // 見積もり時間 (0〜0.5)
158
+ if (requirement.estimatedHours)
159
+ score += 0.5;
160
+ // 複雑度 (0〜0.3)
161
+ if (requirement.estimatedComplexity)
162
+ score += 0.3;
163
+ // 成功基準に時間制約的な表現があるか (0〜0.2)
164
+ const timeRelated = requirement.successCriteria.some((c) => /(\d+秒|\d+ms|\d+分|\d+時間|\d+日|以内|まで|期限|deadline)/i.test(c));
165
+ if (timeRelated)
166
+ score += 0.2;
167
+ return Math.min(score, 1);
168
+ }
169
+ // --- Helper functions ---
170
+ function scoreFormatDetail(requirement) {
171
+ if (requirement.format.type === "user-story") {
172
+ const us = requirement.format.userStory;
173
+ let filled = 0;
174
+ if (us.as)
175
+ filled++;
176
+ if (us.iWant)
177
+ filled++;
178
+ if (us.soThat)
179
+ filled++;
180
+ return (filled / 3) * 0.3;
181
+ }
182
+ if (requirement.format.type === "ears") {
183
+ const ears = requirement.format.ears;
184
+ let filled = 0;
185
+ if (ears.type)
186
+ filled++;
187
+ if (ears.action)
188
+ filled++;
189
+ if (ears.trigger)
190
+ filled++;
191
+ if (ears.condition)
192
+ filled++;
193
+ if (ears.response)
194
+ filled++;
195
+ return (filled / 5) * 0.3;
196
+ }
197
+ return 0;
198
+ }
199
+ function gatherText(requirement, description) {
200
+ const parts = [requirement.title, ...requirement.successCriteria];
201
+ if (description)
202
+ parts.push(description);
203
+ return parts.join(" ");
204
+ }
205
+ export function countAmbiguousPhrases(text, phrases) {
206
+ let count = 0;
207
+ for (const phrase of phrases) {
208
+ if (text.includes(phrase))
209
+ count++;
210
+ }
211
+ return count;
212
+ }
213
+ const COMPLEXITY_HOURS_RANGES = {
214
+ small: [1, 8],
215
+ medium: [4, 40],
216
+ large: [20, 120],
217
+ xlarge: [80, 500],
218
+ };
219
+ export function isComplexityHoursConsistent(complexity, hours) {
220
+ const range = COMPLEXITY_HOURS_RANGES[complexity];
221
+ if (!range)
222
+ return true;
223
+ return hours >= range[0] && hours <= range[1];
224
+ }
225
+ //# sourceMappingURL=smart-scoring.js.map