eslint-plugin-traceability 1.6.4 → 1.7.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 (42) hide show
  1. package/README.md +38 -1
  2. package/lib/src/index.d.ts +28 -25
  3. package/lib/src/index.js +49 -31
  4. package/lib/src/maintenance/cli.d.ts +12 -0
  5. package/lib/src/maintenance/cli.js +279 -0
  6. package/lib/src/maintenance/detect.js +30 -15
  7. package/lib/src/maintenance/update.js +42 -34
  8. package/lib/src/maintenance/utils.js +30 -30
  9. package/lib/src/rules/helpers/require-story-io.js +51 -15
  10. package/lib/src/rules/helpers/require-story-visitors.js +5 -16
  11. package/lib/src/rules/helpers/valid-annotation-options.d.ts +118 -0
  12. package/lib/src/rules/helpers/valid-annotation-options.js +167 -0
  13. package/lib/src/rules/helpers/valid-annotation-utils.d.ts +68 -0
  14. package/lib/src/rules/helpers/valid-annotation-utils.js +103 -0
  15. package/lib/src/rules/helpers/valid-story-reference-helpers.d.ts +67 -0
  16. package/lib/src/rules/helpers/valid-story-reference-helpers.js +92 -0
  17. package/lib/src/rules/require-story-annotation.js +9 -14
  18. package/lib/src/rules/valid-annotation-format.js +168 -180
  19. package/lib/src/rules/valid-req-reference.js +139 -29
  20. package/lib/src/rules/valid-story-reference.d.ts +7 -0
  21. package/lib/src/rules/valid-story-reference.js +38 -80
  22. package/lib/src/utils/annotation-checker.js +2 -145
  23. package/lib/src/utils/branch-annotation-helpers.js +12 -3
  24. package/lib/src/utils/reqAnnotationDetection.d.ts +6 -0
  25. package/lib/src/utils/reqAnnotationDetection.js +152 -0
  26. package/lib/tests/maintenance/cli.test.d.ts +1 -0
  27. package/lib/tests/maintenance/cli.test.js +172 -0
  28. package/lib/tests/maintenance/detect-isolated.test.js +68 -1
  29. package/lib/tests/maintenance/report.test.js +2 -2
  30. package/lib/tests/rules/require-branch-annotation.test.js +3 -2
  31. package/lib/tests/rules/require-req-annotation.test.js +57 -68
  32. package/lib/tests/rules/require-story-annotation.test.js +13 -28
  33. package/lib/tests/rules/require-story-core-edgecases.test.js +3 -58
  34. package/lib/tests/rules/require-story-core.autofix.test.js +5 -41
  35. package/lib/tests/rules/valid-annotation-format.test.js +328 -51
  36. package/lib/tests/utils/annotation-checker.test.d.ts +23 -0
  37. package/lib/tests/utils/annotation-checker.test.js +24 -17
  38. package/lib/tests/utils/require-story-core-test-helpers.d.ts +10 -0
  39. package/lib/tests/utils/require-story-core-test-helpers.js +75 -0
  40. package/lib/tests/utils/ts-language-options.d.ts +22 -0
  41. package/lib/tests/utils/ts-language-options.js +27 -0
  42. package/package.json +12 -3
@@ -12,12 +12,45 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  * @req REQ-ERROR-MESSAGES-CONSISTENT - Verify invalid annotation errors use consistent wording and structure
13
13
  * @req REQ-ERROR-MESSAGES-ACTIONABLE - Verify invalid annotation errors provide actionable guidance and examples
14
14
  * @req REQ-ERROR-MESSAGES-IDENTIFIERS - Verify invalid annotation errors echo the offending identifier/path in the message
15
+ * Tests for: docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
16
+ * @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
17
+ * @req REQ-CONFIGURABLE-PATTERNS-STORY - Rule supports configurable story path regex patterns
18
+ * @req REQ-CONFIGURABLE-PATTERNS-REQ - Rule supports configurable requirement ID regex patterns
19
+ * @req REQ-CONFIGURABLE-PATTERNS-EXAMPLES - Rule supports configurable example strings in error messages
20
+ * @req REQ-CONFIGURABLE-PATTERNS-FALLBACK - Invalid regex patterns fall back to default behavior without crashing
15
21
  */
16
22
  const eslint_1 = require("eslint");
17
23
  const valid_annotation_format_1 = __importDefault(require("../../src/rules/valid-annotation-format"));
18
24
  const ruleTester = new eslint_1.RuleTester({
19
25
  languageOptions: { parserOptions: { ecmaVersion: 2020 } },
20
26
  });
27
+ const makeInvalid = ({ name, code, output, messageId, details, options, }) => ({
28
+ name,
29
+ code,
30
+ ...(output ? { output } : {}),
31
+ ...(options ? { options } : {}),
32
+ errors: [
33
+ {
34
+ messageId,
35
+ data: {
36
+ details,
37
+ },
38
+ },
39
+ ],
40
+ });
41
+ /**
42
+ * Test-only convenience for Story 005.0 error messaging consistency.
43
+ * Preconfigures the invalidStoryFormat messageId so tests only specify
44
+ * name, code, and details (plus optional output/options).
45
+ */
46
+ const makeInvalidStory = ({ name, code, details, output, options, }) => makeInvalid({
47
+ name,
48
+ code,
49
+ output,
50
+ options,
51
+ messageId: "invalidStoryFormat",
52
+ details,
53
+ });
21
54
  describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)", () => {
22
55
  ruleTester.run("valid-annotation-format", valid_annotation_format_1.default, {
23
56
  valid: [
@@ -57,148 +90,392 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
57
90
  * @req REQ-FLEXIBLE-PARSING
58
91
  */`,
59
92
  },
60
- ],
61
- invalid: [
62
93
  {
63
- name: "[REQ-PATH-FORMAT] missing story path (single line)",
64
- code: `// @story`,
65
- errors: [
94
+ name: "[REQ-CONFIGURABLE-PATTERNS-STORY] custom storyPathPattern accepts alternate extension",
95
+ code: `// @story stories/feature-010.1-CUSTOM.story.mdx`,
96
+ options: [
66
97
  {
67
- messageId: "invalidStoryFormat",
68
- data: {
69
- details: 'Missing story path for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
98
+ story: {
99
+ pattern: "^stories\\/[^\\s]+\\.story\\.mdx$",
100
+ example: "stories/example-010.1-CUSTOM.story.mdx",
101
+ },
102
+ },
103
+ ],
104
+ },
105
+ {
106
+ name: "[REQ-CONFIGURABLE-PATTERNS-REQ] custom requirementIdPattern accepts PROJECT-123 style IDs",
107
+ code: `// @req PROJECT-123`,
108
+ options: [
109
+ {
110
+ req: {
111
+ pattern: "^[A-Z]+-[0-9]+$",
112
+ example: "PROJECT-123",
113
+ },
114
+ },
115
+ ],
116
+ },
117
+ {
118
+ name: "[REQ-CONFIGURABLE-PATTERNS-BOTH] custom patterns accept alternative story and req shapes",
119
+ code: `/**
120
+ * @story stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.mdx
121
+ * @req STORY-10
122
+ */`,
123
+ options: [
124
+ {
125
+ story: {
126
+ pattern: "^stories\\/[^\\s]+\\.story\\.mdx$",
127
+ example: "stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.mdx",
70
128
  },
129
+ req: {
130
+ pattern: "^[A-Z]+-[0-9]+$",
131
+ example: "STORY-10",
132
+ },
133
+ },
134
+ ],
135
+ },
136
+ {
137
+ name: "[REQ-CONFIGURABLE-PATTERNS-STORY-FLAT] flat storyPathPattern accepts alternate extension when nested config not provided",
138
+ code: `// @story stories/feature-010.1-CUSTOM.story.mdx`,
139
+ options: [
140
+ {
141
+ storyPathPattern: "^stories\\/[^\\s]+\\.story\\.mdx$",
142
+ storyPathExample: "stories/example-010.1-CUSTOM.story.mdx",
71
143
  },
72
144
  ],
73
145
  },
74
146
  {
147
+ name: "[REQ-CONFIGURABLE-PATTERNS-REQ-FLAT] flat requirementIdPattern accepts PROJECT-123 style IDs when nested config not provided",
148
+ code: `// @req PROJECT-123`,
149
+ options: [
150
+ {
151
+ requirementIdPattern: "^[A-Z]+-[0-9]+$",
152
+ requirementIdExample: "PROJECT-123",
153
+ },
154
+ ],
155
+ },
156
+ {
157
+ name: "[REQ-CONFIGURABLE-PATTERNS-BOTH-FLAT] flat patterns accept alternative story and req shapes when nested config not provided",
158
+ code: `/**
159
+ * @story stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.mdx
160
+ * @req STORY-10
161
+ */`,
162
+ options: [
163
+ {
164
+ storyPathPattern: "^stories\\/[^\\s]+\\.story\\.mdx$",
165
+ storyPathExample: "stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.mdx",
166
+ requirementIdPattern: "^[A-Z]+-[0-9]+$",
167
+ requirementIdExample: "STORY-10",
168
+ },
169
+ ],
170
+ },
171
+ ],
172
+ invalid: [
173
+ makeInvalidStory({
174
+ name: "[REQ-PATH-FORMAT] missing story path (single line)",
175
+ code: `// @story`,
176
+ details: 'Missing story path for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
177
+ }),
178
+ makeInvalidStory({
75
179
  name: "[REQ-PATH-FORMAT] invalid story file extension",
76
180
  code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story`,
77
181
  output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
182
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
183
+ }),
184
+ makeInvalidStory({
185
+ name: "[REQ-PATH-FORMAT] missing extension in story path",
186
+ code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION`,
187
+ output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
188
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
189
+ }),
190
+ makeInvalidStory({
191
+ name: "[REQ-PATH-FORMAT] story path must not use path traversal",
192
+ code: `// @story ../docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
193
+ details: 'Invalid story path "../docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
194
+ }),
195
+ makeInvalid({
196
+ name: "[REQ-REQ-FORMAT] missing req id (single line)",
197
+ code: `// @req`,
198
+ messageId: "invalidReqFormat",
199
+ details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
200
+ }),
201
+ makeInvalid({
202
+ name: "[REQ-REQ-FORMAT] invalid req id format (single line)",
203
+ code: `// @req invalid-format`,
204
+ messageId: "invalidReqFormat",
205
+ details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
206
+ }),
207
+ makeInvalid({
208
+ name: "[REQ-REQ-FORMAT] missing req identifier with trailing space",
209
+ code: `// @req `,
210
+ messageId: "invalidReqFormat",
211
+ details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
212
+ }),
213
+ makeInvalidStory({
214
+ name: "[REQ-MULTILINE-SUPPORT] missing story path with multi-line block comment",
215
+ code: `/**
216
+ * @story
217
+ */`,
218
+ details: 'Missing story path for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
219
+ }),
220
+ makeInvalidStory({
221
+ name: "[REQ-MULTILINE-SUPPORT] invalid multi-line story path after collapsing whitespace",
222
+ code: `/**
223
+ * @story docs/stories/005.0-
224
+ * DEV-ANNOTATION-VALIDATION.story
225
+ */`,
226
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
227
+ }),
228
+ makeInvalid({
229
+ name: "[REQ-MULTILINE-SUPPORT] missing req id with multi-line block comment",
230
+ code: `/**
231
+ * @req
232
+ */`,
233
+ messageId: "invalidReqFormat",
234
+ details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
235
+ }),
236
+ makeInvalid({
237
+ name: "[REQ-MULTILINE-SUPPORT] invalid multi-line req id after collapsing whitespace",
238
+ code: `/**
239
+ * @req invalid-
240
+ * format
241
+ */`,
242
+ messageId: "invalidReqFormat",
243
+ details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
244
+ }),
245
+ {
246
+ name: "[REQ-CONFIGURABLE-PATTERNS-EXAMPLES] custom story example appears in error message",
247
+ code: `// @story invalid/path.txt`,
248
+ options: [
249
+ {
250
+ story: {
251
+ pattern: "^stories\\/[^\\s]+\\.story\\.mdx$",
252
+ example: "stories/example-010.1-CUSTOM.story.mdx",
253
+ },
254
+ },
255
+ ],
78
256
  errors: [
79
257
  {
80
258
  messageId: "invalidStoryFormat",
81
259
  data: {
82
- details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
260
+ details: 'Invalid story path "invalid/path.txt" for @story annotation. Expected a path like "stories/example-010.1-CUSTOM.story.mdx".',
83
261
  },
84
262
  },
85
263
  ],
86
264
  },
87
265
  {
88
- name: "[REQ-PATH-FORMAT] missing extension in story path",
89
- code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION`,
90
- output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
266
+ name: "[REQ-CONFIGURABLE-PATTERNS-EXAMPLES] custom requirement example appears in error message",
267
+ code: `// @req not-matching`,
268
+ options: [
269
+ {
270
+ req: {
271
+ pattern: "^[A-Z]+-[0-9]+$",
272
+ example: "PROJECT-123",
273
+ },
274
+ },
275
+ ],
91
276
  errors: [
92
277
  {
93
- messageId: "invalidStoryFormat",
278
+ messageId: "invalidReqFormat",
94
279
  data: {
95
- details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
280
+ details: 'Invalid requirement ID "not-matching" for @req annotation. Expected an identifier like "PROJECT-123" (uppercase letters, numbers, and dashes only).',
96
281
  },
97
282
  },
98
283
  ],
99
284
  },
100
285
  {
101
- name: "[REQ-PATH-FORMAT] story path must not use path traversal",
102
- code: `// @story ../docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
286
+ name: "[REQ-CONFIGURABLE-PATTERNS-FALLBACK] invalid storyPathPattern falls back to default behavior",
287
+ code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story`,
288
+ options: [
289
+ {
290
+ // invalid regex should be caught by the rule and ignored
291
+ story: {
292
+ pattern: "[unclosed",
293
+ },
294
+ },
295
+ ],
296
+ output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
103
297
  errors: [
298
+ {
299
+ // Configuration error should also be reported
300
+ messageId: "invalidRuleConfiguration",
301
+ data: {
302
+ details: 'Invalid regular expression for option "story.pattern": "[unclosed"',
303
+ },
304
+ },
104
305
  {
105
306
  messageId: "invalidStoryFormat",
106
307
  data: {
107
- details: 'Invalid story path "../docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
308
+ // Because we fall back, we still use the default example text
309
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
108
310
  },
109
311
  },
110
312
  ],
111
313
  },
112
314
  {
113
- name: "[REQ-REQ-FORMAT] missing req id (single line)",
114
- code: `// @req`,
315
+ name: "[REQ-CONFIGURABLE-PATTERNS-FALLBACK] invalid requirementIdPattern falls back to default behavior",
316
+ code: `// @req invalid-format`,
317
+ options: [
318
+ {
319
+ // invalid regex should be caught by the rule and ignored
320
+ req: {
321
+ pattern: "(unclosed",
322
+ },
323
+ },
324
+ ],
115
325
  errors: [
326
+ {
327
+ // Configuration error should also be reported
328
+ messageId: "invalidRuleConfiguration",
329
+ data: {
330
+ details: 'Invalid regular expression for option "req.pattern": "(unclosed"',
331
+ },
332
+ },
116
333
  {
117
334
  messageId: "invalidReqFormat",
118
335
  data: {
119
- details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
336
+ // Because we fall back, we still use the default example text
337
+ details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
120
338
  },
121
339
  },
122
340
  ],
123
341
  },
124
342
  {
125
- name: "[REQ-REQ-FORMAT] invalid req id format (single line)",
126
- code: `// @req invalid-format`,
343
+ name: "[REQ-CONFIGURABLE-PATTERNS-FALLBACK-FLAT] invalid flat storyPathPattern falls back to default and reports config error",
344
+ code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story`,
345
+ options: [
346
+ {
347
+ // invalid regex should be caught by the rule and ignored
348
+ storyPathPattern: "[unclosed",
349
+ },
350
+ ],
351
+ output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
127
352
  errors: [
128
353
  {
129
- messageId: "invalidReqFormat",
354
+ // Configuration error should also be reported
355
+ messageId: "invalidRuleConfiguration",
130
356
  data: {
131
- details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
357
+ details: 'Invalid regular expression for option "storyPathPattern": "[unclosed"',
358
+ },
359
+ },
360
+ {
361
+ // Because we fall back, we still use the default example text
362
+ messageId: "invalidStoryFormat",
363
+ data: {
364
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
132
365
  },
133
366
  },
134
367
  ],
135
368
  },
136
369
  {
137
- name: "[REQ-REQ-FORMAT] missing req identifier with trailing space",
138
- code: `// @req `,
370
+ name: "[REQ-CONFIGURABLE-PATTERNS-FALLBACK-FLAT] invalid flat requirementIdPattern falls back to default and reports config error",
371
+ code: `// @req invalid-format`,
372
+ options: [
373
+ {
374
+ // invalid regex should be caught by the rule and ignored
375
+ requirementIdPattern: "(unclosed",
376
+ },
377
+ ],
139
378
  errors: [
140
379
  {
380
+ // Configuration error should also be reported
381
+ messageId: "invalidRuleConfiguration",
382
+ data: {
383
+ details: 'Invalid regular expression for option "requirementIdPattern": "(unclosed"',
384
+ },
385
+ },
386
+ {
387
+ // Because we fall back, we still use the default example text
141
388
  messageId: "invalidReqFormat",
142
389
  data: {
143
- details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
390
+ details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
144
391
  },
145
392
  },
146
393
  ],
147
394
  },
148
395
  {
149
- name: "[REQ-MULTILINE-SUPPORT] missing story path with multi-line block comment",
150
- code: `/**
151
- * @story
152
- */`,
396
+ name: "[REQ-PATTERN-CONFIG] nested story.pattern takes precedence over flat storyPathPattern and its example",
397
+ code: `// @story not-matching.mdx`,
398
+ options: [
399
+ {
400
+ story: {
401
+ pattern: "^stories\\/nested-only\\.story\\.mdx$",
402
+ example: "stories/nested-only.story.mdx",
403
+ },
404
+ storyPathPattern: "^docs\\/stories\\/should-not-apply\\.story\\.mdx$",
405
+ storyPathExample: "docs/stories/should-not-apply.story.mdx",
406
+ },
407
+ ],
153
408
  errors: [
154
409
  {
155
410
  messageId: "invalidStoryFormat",
156
411
  data: {
157
- details: 'Missing story path for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
412
+ details: 'Invalid story path "not-matching.mdx" for @story annotation. Expected a path like "stories/nested-only.story.mdx".',
158
413
  },
159
414
  },
160
415
  ],
161
416
  },
162
417
  {
163
- name: "[REQ-MULTILINE-SUPPORT] invalid multi-line story path after collapsing whitespace",
164
- code: `/**
165
- * @story docs/stories/005.0-
166
- * DEV-ANNOTATION-VALIDATION.story
167
- */`,
418
+ name: "[REQ-PATTERN-CONFIG] nested req.pattern takes precedence over flat requirementIdPattern and its example",
419
+ code: `// @req DOES-NOT-MATCH`,
420
+ options: [
421
+ {
422
+ req: {
423
+ pattern: "^REQ-[0-9]{4}$",
424
+ example: "REQ-0001",
425
+ },
426
+ requirementIdPattern: "^[A-Z]+-[0-9]+$",
427
+ requirementIdExample: "PROJECT-123",
428
+ },
429
+ ],
168
430
  errors: [
169
431
  {
170
- messageId: "invalidStoryFormat",
432
+ messageId: "invalidReqFormat",
171
433
  data: {
172
- details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
434
+ details: 'Invalid requirement ID "DOES-NOT-MATCH" for @req annotation. Expected an identifier like "REQ-0001" (uppercase letters, numbers, and dashes only).',
173
435
  },
174
436
  },
175
437
  ],
176
438
  },
177
439
  {
178
- name: "[REQ-MULTILINE-SUPPORT] missing req id with multi-line block comment",
179
- code: `/**
180
- * @req
181
- */`,
440
+ name: "[REQ-EXAMPLE-MESSAGES] nested story example text overrides flat storyPathExample in error messages",
441
+ code: `// @story invalid/path.txt`,
442
+ options: [
443
+ {
444
+ story: {
445
+ pattern: "^stories\\/special\\/.+\\.story\\.mdx$",
446
+ example: "stories/special/example.story.mdx",
447
+ },
448
+ storyPathPattern: "^stories\\/ignored\\/.+\\.story\\.mdx$",
449
+ storyPathExample: "stories/ignored/example.story.mdx",
450
+ },
451
+ ],
182
452
  errors: [
183
453
  {
184
- messageId: "invalidReqFormat",
454
+ messageId: "invalidStoryFormat",
185
455
  data: {
186
- details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
456
+ details: 'Invalid story path "invalid/path.txt" for @story annotation. Expected a path like "stories/special/example.story.mdx".',
187
457
  },
188
458
  },
189
459
  ],
190
460
  },
191
461
  {
192
- name: "[REQ-MULTILINE-SUPPORT] invalid multi-line req id after collapsing whitespace",
193
- code: `/**
194
- * @req invalid-
195
- * format
196
- */`,
462
+ name: "[REQ-EXAMPLE-MESSAGES] nested req example text overrides flat requirementIdExample in error messages",
463
+ code: `// @req bad-id`,
464
+ options: [
465
+ {
466
+ req: {
467
+ pattern: "^REQ-[A-Z]+-[0-9]{3}$",
468
+ example: "REQ-FOO-001",
469
+ },
470
+ requirementIdPattern: "^[A-Z]+-[0-9]+$",
471
+ requirementIdExample: "PROJECT-123",
472
+ },
473
+ ],
197
474
  errors: [
198
475
  {
199
476
  messageId: "invalidReqFormat",
200
477
  data: {
201
- details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
478
+ details: 'Invalid requirement ID "bad-id" for @req annotation. Expected an identifier like "REQ-FOO-001" (uppercase letters, numbers, and dashes only).',
202
479
  },
203
480
  },
204
481
  ],
@@ -1 +1,24 @@
1
+ type AnnotationCheckerTestConfig = {
2
+ rule: any;
3
+ valid: Array<{
4
+ name: string;
5
+ code: string;
6
+ [key: string]: any;
7
+ }>;
8
+ invalid: Array<{
9
+ name: string;
10
+ code: string;
11
+ errors: any[];
12
+ [key: string]: any;
13
+ }>;
14
+ };
15
+ /**
16
+ * Shared helper for running tests that exercise the annotation-checker logic
17
+ * for TypeScript constructs.
18
+ *
19
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
20
+ * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
21
+ * @req REQ-TEST-UTILS-TS-LANG - Shared TS RuleTester language options helper
22
+ */
23
+ export declare function runAnnotationCheckerTests(ruleName: string, config: AnnotationCheckerTestConfig): void;
1
24
  export {};
@@ -1,13 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAnnotationCheckerTests = runAnnotationCheckerTests;
3
4
  /**
4
5
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
6
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
6
7
  * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
8
+ * @req REQ-TEST-UTILS-TS-LANG - Shared TS RuleTester language options helper
7
9
  */
8
10
  const eslint_1 = require("eslint");
9
11
  const annotation_checker_1 = require("../../src/utils/annotation-checker");
12
+ const ts_language_options_1 = require("./ts-language-options");
10
13
  const ruleTester = new eslint_1.RuleTester();
14
+ const withTsAnnotationCheckerOptions = (test) => ({
15
+ ...test,
16
+ languageOptions: ts_language_options_1.tsRuleTesterLanguageOptions,
17
+ });
18
+ /**
19
+ * Shared helper for running tests that exercise the annotation-checker logic
20
+ * for TypeScript constructs.
21
+ *
22
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
23
+ * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
24
+ * @req REQ-TEST-UTILS-TS-LANG - Shared TS RuleTester language options helper
25
+ */
26
+ function runAnnotationCheckerTests(ruleName, config) {
27
+ const { rule, valid, invalid } = config;
28
+ ruleTester.run(ruleName, rule, {
29
+ valid: valid.map(withTsAnnotationCheckerOptions),
30
+ invalid: invalid.map(withTsAnnotationCheckerOptions),
31
+ });
32
+ }
11
33
  const rule = {
12
34
  meta: {
13
35
  type: "problem",
@@ -35,23 +57,16 @@ const rule = {
35
57
  },
36
58
  };
37
59
  describe("annotation-checker helper", () => {
38
- ruleTester.run("annotation-checker", rule, {
60
+ runAnnotationCheckerTests("annotation-checker", {
61
+ rule,
39
62
  valid: [
40
63
  {
41
64
  name: "[REQ-TYPESCRIPT-SUPPORT] valid TSDeclareFunction with @req",
42
65
  code: `/** @req REQ-TEST */\ndeclare function foo(): void;`,
43
- languageOptions: {
44
- parser: require("@typescript-eslint/parser"),
45
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
46
- },
47
66
  },
48
67
  {
49
68
  name: "[REQ-TYPESCRIPT-SUPPORT] valid TSMethodSignature with @req",
50
69
  code: `interface I { /** @req REQ-TEST */ method(): void; }`,
51
- languageOptions: {
52
- parser: require("@typescript-eslint/parser"),
53
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
54
- },
55
70
  },
56
71
  ],
57
72
  invalid: [
@@ -60,20 +75,12 @@ describe("annotation-checker helper", () => {
60
75
  code: `declare function foo(): void;`,
61
76
  output: `/** @req <REQ-ID> */\ndeclare function foo(): void;`,
62
77
  errors: [{ messageId: "missingReq" }],
63
- languageOptions: {
64
- parser: require("@typescript-eslint/parser"),
65
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
66
- },
67
78
  },
68
79
  {
69
80
  name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSMethodSignature",
70
81
  code: `interface I { method(): void; }`,
71
82
  output: `interface I { /** @req <REQ-ID> */\nmethod(): void; }`,
72
83
  errors: [{ messageId: "missingReq" }],
73
- languageOptions: {
74
- parser: require("@typescript-eslint/parser"),
75
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
76
- },
77
84
  },
78
85
  ],
79
86
  });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared test helpers for require-story-core branch coverage.
3
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
+ * @req REQ-AUTOFIX - Provide reusable helpers to exercise autofix branches
5
+ */
6
+ interface ExerciseOptions {
7
+ annotationText?: string;
8
+ }
9
+ export declare function exerciseCreateAddStoryFixBranches(createAddStoryFix: any, options?: ExerciseOptions): void;
10
+ export {};