eslint-plugin-traceability 1.21.0 → 1.22.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 (83) hide show
  1. package/CHANGELOG.md +7 -2
  2. package/README.md +6 -6
  3. package/lib/src/maintenance/batch.js +0 -1
  4. package/lib/src/maintenance/cli.js +8 -10
  5. package/lib/src/maintenance/commands.d.ts +2 -2
  6. package/lib/src/maintenance/commands.js +2 -2
  7. package/lib/src/maintenance/detect.js +7 -7
  8. package/lib/src/maintenance/report.js +2 -2
  9. package/lib/src/maintenance/storyParser.d.ts +16 -0
  10. package/lib/src/maintenance/storyParser.js +167 -0
  11. package/lib/src/rules/helpers/pattern-validators.d.ts +42 -0
  12. package/lib/src/rules/helpers/pattern-validators.js +65 -0
  13. package/lib/src/rules/helpers/prefer-implements-inline.d.ts +16 -0
  14. package/lib/src/rules/helpers/prefer-implements-inline.js +146 -0
  15. package/lib/src/rules/helpers/require-story-comment-detection.d.ts +47 -0
  16. package/lib/src/rules/helpers/require-story-comment-detection.js +141 -0
  17. package/lib/src/rules/helpers/require-story-core.d.ts +6 -6
  18. package/lib/src/rules/helpers/require-story-core.js +10 -10
  19. package/lib/src/rules/helpers/require-story-helpers.d.ts +5 -63
  20. package/lib/src/rules/helpers/require-story-helpers.js +29 -337
  21. package/lib/src/rules/helpers/require-story-io.js +1 -0
  22. package/lib/src/rules/helpers/require-story-name-extraction.d.ts +35 -0
  23. package/lib/src/rules/helpers/require-story-name-extraction.js +107 -0
  24. package/lib/src/rules/helpers/require-story-node-utils.d.ts +43 -0
  25. package/lib/src/rules/helpers/require-story-node-utils.js +115 -0
  26. package/lib/src/rules/helpers/require-test-traceability-helpers.js +1 -0
  27. package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +2 -2
  28. package/lib/src/rules/helpers/valid-annotation-format-internal.js +13 -5
  29. package/lib/src/rules/helpers/valid-annotation-format-validators.d.ts +14 -14
  30. package/lib/src/rules/helpers/valid-annotation-format-validators.js +31 -22
  31. package/lib/src/rules/helpers/valid-annotation-options.d.ts +0 -10
  32. package/lib/src/rules/helpers/valid-annotation-options.js +22 -92
  33. package/lib/src/rules/helpers/valid-annotation-utils.js +1 -0
  34. package/lib/src/rules/helpers/valid-req-reference-helpers.js +1 -1
  35. package/lib/src/rules/no-redundant-annotation.js +4 -238
  36. package/lib/src/rules/prefer-implements-annotation.d.ts +12 -0
  37. package/lib/src/rules/prefer-implements-annotation.js +9 -164
  38. package/lib/src/rules/require-traceability.d.ts +8 -0
  39. package/lib/src/rules/require-traceability.js +8 -0
  40. package/lib/src/rules/valid-annotation-format.js +14 -10
  41. package/lib/src/utils/annotation-checker.d.ts +3 -2
  42. package/lib/src/utils/annotation-checker.js +4 -2
  43. package/lib/src/utils/branch-annotation-catch-helpers.d.ts +22 -0
  44. package/lib/src/utils/branch-annotation-catch-helpers.js +70 -0
  45. package/lib/src/utils/branch-annotation-helpers.js +11 -187
  46. package/lib/src/utils/branch-annotation-if-helpers.d.ts +1 -0
  47. package/lib/src/utils/branch-annotation-if-helpers.js +59 -0
  48. package/lib/src/utils/branch-annotation-indent-helpers.d.ts +1 -1
  49. package/lib/src/utils/branch-annotation-switch-helpers.d.ts +8 -2
  50. package/lib/src/utils/branch-annotation-switch-helpers.js +10 -4
  51. package/lib/src/utils/branch-validation.d.ts +9 -0
  52. package/lib/src/utils/branch-validation.js +58 -0
  53. package/lib/src/utils/comment-text-helpers.d.ts +31 -0
  54. package/lib/src/utils/comment-text-helpers.js +54 -0
  55. package/lib/src/utils/redundancy-detector.d.ts +85 -0
  56. package/lib/src/utils/redundancy-detector.js +235 -0
  57. package/lib/src/utils/reqAnnotationDetection.js +1 -0
  58. package/lib/tests/config/eslint-config-validation.test.js +1 -0
  59. package/lib/tests/config/flat-config-presets-integration.test.js +1 -0
  60. package/lib/tests/config/require-story-annotation-config.test.js +1 -0
  61. package/lib/tests/fixtures/stale/example.js +1 -0
  62. package/lib/tests/fixtures/update/example.js +1 -0
  63. package/lib/tests/integration/annotation-placement-inside-prettier.integration.test.js +1 -0
  64. package/lib/tests/integration/catch-annotation-prettier.integration.test.js +1 -0
  65. package/lib/tests/integration/else-if-annotation-prettier.integration.test.js +1 -0
  66. package/lib/tests/integration/prettier-test-helpers.js +1 -0
  67. package/lib/tests/integration/require-traceability-test-callbacks.integration.test.js +1 -0
  68. package/lib/tests/maintenance/detect-isolated.test.js +1 -0
  69. package/lib/tests/maintenance/storyParser.test.d.ts +8 -0
  70. package/lib/tests/maintenance/storyParser.test.js +505 -0
  71. package/lib/tests/perf/maintenance-large-workspace.test.js +1 -0
  72. package/lib/tests/perf/valid-annotation-format-large-file.test.js +1 -0
  73. package/lib/tests/plugin-setup.test.js +1 -0
  74. package/lib/tests/rules/error-reporting.test.js +1 -0
  75. package/lib/tests/rules/no-redundant-annotation.test.js +1 -0
  76. package/lib/tests/rules/require-story-helpers.test.js +3 -2
  77. package/lib/tests/rules/require-test-traceability.test.js +1 -0
  78. package/lib/tests/rules/valid-req-reference.test.js +2 -0
  79. package/lib/tests/utils/branch-annotation-catch-insert-position.test.js +1 -0
  80. package/lib/tests/utils/branch-annotation-else-if-insert-position.test.js +1 -0
  81. package/lib/tests/utils/branch-annotation-helpers.test.js +1 -0
  82. package/package.json +18 -10
  83. package/user-docs/api-reference.md +2 -2
@@ -0,0 +1,505 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for storyParser module
4
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
5
+ * @req REQ-DEEP-PARSE - Test parsing story file content to identify available requirements
6
+ * @req REQ-DEEP-FORMAT - Test finding requirement IDs in multiple markdown contexts
7
+ * @req REQ-DEEP-SECTION - Test handling requirements in different story file sections
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const os = __importStar(require("os"));
46
+ const storyParser_1 = require("../../src/maintenance/storyParser");
47
+ describe("storyParser", () => {
48
+ describe("extractRequirementsFromContent", () => {
49
+ /**
50
+ * Test extraction from structured ## Requirements section
51
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
52
+ * @req REQ-DEEP-SECTION - Parse ## Requirements sections
53
+ */
54
+ it("should extract requirements from ## Requirements section", () => {
55
+ const content = `
56
+ # Story Title
57
+
58
+ ## Requirements
59
+
60
+ - **REQ-FOO-001**: First requirement
61
+ - **REQ-FOO-002**: Second requirement
62
+ - **REQ-BAR-003**: Third requirement
63
+
64
+ ## Other Section
65
+ `;
66
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
67
+ expect(requirements).toEqual(new Set(["REQ-FOO-001", "REQ-FOO-002", "REQ-BAR-003"]));
68
+ });
69
+ /**
70
+ * Test extraction from ## Acceptance Criteria section
71
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
72
+ * @req REQ-DEEP-SECTION - Parse ## Acceptance Criteria sections
73
+ */
74
+ it("should extract requirements from ## Acceptance Criteria section", () => {
75
+ const content = `
76
+ # Story Title
77
+
78
+ ## Acceptance Criteria
79
+
80
+ - **REQ-AC-001**: Acceptance criterion one
81
+ - **REQ-AC-002**: Acceptance criterion two
82
+
83
+ ## Other Section
84
+ `;
85
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
86
+ expect(requirements).toEqual(new Set(["REQ-AC-001", "REQ-AC-002"]));
87
+ });
88
+ /**
89
+ * Test extraction from both structured sections
90
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
91
+ * @req REQ-DEEP-SECTION - Handle requirements in different story file sections
92
+ */
93
+ it("should extract requirements from both Requirements and Acceptance Criteria sections", () => {
94
+ const content = `
95
+ # Story Title
96
+
97
+ ## Requirements
98
+
99
+ - **REQ-REQ-001**: First requirement
100
+
101
+ ## Acceptance Criteria
102
+
103
+ - **REQ-AC-001**: First criterion
104
+
105
+ ## Implementation Notes
106
+ `;
107
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
108
+ expect(requirements).toEqual(new Set(["REQ-REQ-001", "REQ-AC-001"]));
109
+ });
110
+ /**
111
+ * Test extraction with bold format
112
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
113
+ * @req REQ-DEEP-FORMAT - Extract from bold requirement format
114
+ */
115
+ it("should extract requirements in bold format **REQ-XXX-YYY**", () => {
116
+ const content = `
117
+ ## Requirements
118
+
119
+ - **REQ-BOLD-001**: Description here
120
+ - Some text with **REQ-BOLD-002** in the middle
121
+ `;
122
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
123
+ expect(requirements).toEqual(new Set(["REQ-BOLD-001", "REQ-BOLD-002"]));
124
+ });
125
+ /**
126
+ * Test extraction with plain text format
127
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
128
+ * @req REQ-DEEP-FORMAT - Extract from plain text mentions
129
+ */
130
+ it("should extract requirements in plain text format REQ-XXX-YYY", () => {
131
+ const content = `
132
+ ## Requirements
133
+
134
+ - REQ-PLAIN-001: Description here
135
+ - Some text with REQ-PLAIN-002 in the middle
136
+ `;
137
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
138
+ expect(requirements).toEqual(new Set(["REQ-PLAIN-001", "REQ-PLAIN-002"]));
139
+ });
140
+ /**
141
+ * Test extraction from multiple line formats
142
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
143
+ * @req REQ-DEEP-FORMAT - Support finding requirement IDs in multiple markdown contexts
144
+ */
145
+ it("should extract requirements from mixed formats", () => {
146
+ const content = `
147
+ ## Requirements
148
+
149
+ - **REQ-MIX-001**: Bold format
150
+ - REQ-MIX-002: Plain format
151
+ - Description mentions REQ-MIX-003 inline
152
+ - Multiple **REQ-MIX-004** and REQ-MIX-005 in one line
153
+ `;
154
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
155
+ expect(requirements).toEqual(new Set([
156
+ "REQ-MIX-001",
157
+ "REQ-MIX-002",
158
+ "REQ-MIX-003",
159
+ "REQ-MIX-004",
160
+ "REQ-MIX-005",
161
+ ]));
162
+ });
163
+ /**
164
+ * Test regex fallback for requirements outside sections
165
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
166
+ * @req REQ-DEEP-FORMAT - Support finding requirement IDs in multiple markdown contexts
167
+ */
168
+ it("should extract requirements outside structured sections using regex fallback", () => {
169
+ const content = `
170
+ # Story Title
171
+
172
+ This story implements REQ-FALLBACK-001 and REQ-FALLBACK-002.
173
+
174
+ ## Implementation
175
+
176
+ Code example:
177
+ // @req REQ-FALLBACK-003 - This requirement is in a code comment
178
+ `;
179
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
180
+ expect(requirements).toEqual(new Set(["REQ-FALLBACK-001", "REQ-FALLBACK-002", "REQ-FALLBACK-003"]));
181
+ });
182
+ /**
183
+ * Test handling of empty content
184
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
185
+ * @req REQ-DEEP-PARSE - Handle edge cases gracefully
186
+ */
187
+ it("should return empty set for empty content", () => {
188
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)("");
189
+ expect(requirements).toEqual(new Set());
190
+ });
191
+ /**
192
+ * Test handling of content with no requirements
193
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
194
+ * @req REQ-DEEP-PARSE - Handle edge cases gracefully
195
+ */
196
+ it("should return empty set for content with no requirements", () => {
197
+ const content = `
198
+ # Story Title
199
+
200
+ ## Description
201
+
202
+ This story has no requirements mentioned.
203
+
204
+ ## Implementation Notes
205
+
206
+ Just some notes here.
207
+ `;
208
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
209
+ expect(requirements).toEqual(new Set());
210
+ });
211
+ /**
212
+ * Test case sensitivity
213
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
214
+ * @req REQ-DEEP-FORMAT - Extract requirement IDs correctly
215
+ */
216
+ it("should handle different casing in section headers", () => {
217
+ const content = `
218
+ ## requirements
219
+
220
+ - **REQ-LOWER-001**: From lowercase section
221
+
222
+ ## REQUIREMENTS
223
+
224
+ - **REQ-UPPER-001**: From uppercase section
225
+
226
+ ## Requirements
227
+
228
+ - **REQ-TITLE-001**: From title case section
229
+ `;
230
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
231
+ expect(requirements).toEqual(new Set(["REQ-LOWER-001", "REQ-UPPER-001", "REQ-TITLE-001"]));
232
+ });
233
+ /**
234
+ * Test section boundary detection
235
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
236
+ * @req REQ-DEEP-SECTION - Handle requirements in different story file sections
237
+ */
238
+ it("should stop extracting when encountering new section header", () => {
239
+ const content = `
240
+ ## Requirements
241
+
242
+ - **REQ-SEC-001**: Should be extracted
243
+
244
+ ## Implementation Notes
245
+
246
+ - **REQ-SEC-002**: Should be extracted via regex fallback only
247
+ `;
248
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
249
+ // Both should be extracted, but REQ-SEC-002 via regex fallback
250
+ expect(requirements).toEqual(new Set(["REQ-SEC-001", "REQ-SEC-002"]));
251
+ });
252
+ /**
253
+ * Test multiple occurrences of same requirement
254
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
255
+ * @req REQ-DEEP-PARSE - Avoid duplicate requirements in results
256
+ */
257
+ it("should deduplicate repeated requirements", () => {
258
+ const content = `
259
+ ## Requirements
260
+
261
+ - **REQ-DUP-001**: First mention
262
+ - REQ-DUP-001: Second mention
263
+
264
+ ## Acceptance Criteria
265
+
266
+ - REQ-DUP-001: Third mention
267
+ `;
268
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
269
+ expect(requirements).toEqual(new Set(["REQ-DUP-001"]));
270
+ expect(requirements.size).toBe(1);
271
+ });
272
+ /**
273
+ * Test requirements with hyphens in ID
274
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
275
+ * @req REQ-DEEP-FORMAT - Support requirement ID format with multiple hyphens
276
+ */
277
+ it("should extract requirements with multiple hyphens in ID", () => {
278
+ const content = `
279
+ ## Requirements
280
+
281
+ - **REQ-MULTI-HYPHEN-001**: Complex ID
282
+ - **REQ-A-B-C-D-123**: Very complex ID
283
+ `;
284
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
285
+ expect(requirements).toEqual(new Set(["REQ-MULTI-HYPHEN-001", "REQ-A-B-C-D-123"]));
286
+ });
287
+ /**
288
+ * Test requirements with numbers in various positions
289
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
290
+ * @req REQ-DEEP-FORMAT - Support alphanumeric requirement IDs
291
+ */
292
+ it("should extract requirements with numbers in various positions", () => {
293
+ const content = `
294
+ ## Requirements
295
+
296
+ - **REQ-123-ABC**: Numbers first
297
+ - **REQ-ABC-123**: Numbers last
298
+ - **REQ-A1B2C3**: Numbers mixed
299
+ `;
300
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
301
+ expect(requirements).toEqual(new Set(["REQ-123-ABC", "REQ-ABC-123", "REQ-A1B2C3"]));
302
+ });
303
+ /**
304
+ * Test nested list items
305
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
306
+ * @req REQ-DEEP-FORMAT - Handle requirements in nested list structures
307
+ */
308
+ it("should extract requirements from nested list items", () => {
309
+ const content = `
310
+ ## Requirements
311
+
312
+ - **REQ-NEST-001**: Top level
313
+ - **REQ-NEST-002**: Nested item
314
+ - **REQ-NEST-003**: Deeply nested
315
+ `;
316
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
317
+ expect(requirements).toEqual(new Set(["REQ-NEST-001", "REQ-NEST-002", "REQ-NEST-003"]));
318
+ });
319
+ /**
320
+ * Test requirements in tables
321
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
322
+ * @req REQ-DEEP-FORMAT - Support finding requirement IDs in tables
323
+ */
324
+ it("should extract requirements from markdown tables", () => {
325
+ const content = `
326
+ ## Requirements
327
+
328
+ | ID | Description |
329
+ |----|-------------|
330
+ | REQ-TABLE-001 | First requirement |
331
+ | REQ-TABLE-002 | Second requirement |
332
+ `;
333
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
334
+ expect(requirements).toEqual(new Set(["REQ-TABLE-001", "REQ-TABLE-002"]));
335
+ });
336
+ /**
337
+ * Test requirements with special characters nearby
338
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
339
+ * @req REQ-DEEP-FORMAT - Handle requirement IDs with adjacent punctuation
340
+ */
341
+ it("should extract requirements adjacent to punctuation", () => {
342
+ const content = `
343
+ ## Requirements
344
+
345
+ - (REQ-PUNC-001): In parentheses
346
+ - [REQ-PUNC-002]: In brackets
347
+ - REQ-PUNC-003, REQ-PUNC-004: Comma separated
348
+ - REQ-PUNC-005. With period after
349
+ `;
350
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
351
+ expect(requirements).toEqual(new Set([
352
+ "REQ-PUNC-001",
353
+ "REQ-PUNC-002",
354
+ "REQ-PUNC-003",
355
+ "REQ-PUNC-004",
356
+ "REQ-PUNC-005",
357
+ ]));
358
+ });
359
+ /**
360
+ * Test multiline content within section
361
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
362
+ * @req REQ-DEEP-FORMAT - Handle multiline requirement descriptions
363
+ */
364
+ it("should extract requirements from multiline descriptions", () => {
365
+ const content = `
366
+ ## Requirements
367
+
368
+ - **REQ-MULTI-001**: This is a long description
369
+ that spans multiple lines
370
+ and continues here
371
+ - **REQ-MULTI-002**: Another requirement
372
+ `;
373
+ const requirements = (0, storyParser_1.extractRequirementsFromContent)(content);
374
+ expect(requirements).toEqual(new Set(["REQ-MULTI-001", "REQ-MULTI-002"]));
375
+ });
376
+ });
377
+ describe("extractRequirementsFromStoryFile", () => {
378
+ let tempDir;
379
+ beforeEach(async () => {
380
+ // Create temp directory for test files
381
+ tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "story-parser-test-"));
382
+ });
383
+ afterEach(async () => {
384
+ // Clean up temp directory
385
+ await fs.promises.rm(tempDir, { recursive: true, force: true });
386
+ });
387
+ /**
388
+ * Test reading from actual file
389
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
390
+ * @req REQ-DEEP-PARSE - Parse story file content from filesystem
391
+ */
392
+ it("should extract requirements from an actual story file", async () => {
393
+ const storyPath = path.join(tempDir, "test-story.md");
394
+ const content = `
395
+ # Test Story
396
+
397
+ ## Requirements
398
+
399
+ - **REQ-FILE-001**: First requirement
400
+ - **REQ-FILE-002**: Second requirement
401
+ `;
402
+ await fs.promises.writeFile(storyPath, content, "utf8");
403
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(storyPath);
404
+ expect(requirements).toEqual(new Set(["REQ-FILE-001", "REQ-FILE-002"]));
405
+ });
406
+ /**
407
+ * Test error handling for non-existent file
408
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
409
+ * @req REQ-DEEP-PARSE - Handle file read errors gracefully
410
+ */
411
+ it("should return empty set for non-existent file", () => {
412
+ const nonExistentPath = path.join(tempDir, "does-not-exist.md");
413
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(nonExistentPath);
414
+ expect(requirements).toEqual(new Set());
415
+ });
416
+ /**
417
+ * Test error handling for invalid file path
418
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
419
+ * @req REQ-DEEP-PARSE - Handle file read errors gracefully
420
+ */
421
+ it("should return empty set for invalid file path", () => {
422
+ const invalidPath = "/invalid/\x00/path.md";
423
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(invalidPath);
424
+ expect(requirements).toEqual(new Set());
425
+ });
426
+ /**
427
+ * Test reading empty file
428
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
429
+ * @req REQ-DEEP-PARSE - Handle empty files
430
+ */
431
+ it("should return empty set for empty file", async () => {
432
+ const emptyPath = path.join(tempDir, "empty.md");
433
+ await fs.promises.writeFile(emptyPath, "", "utf8");
434
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(emptyPath);
435
+ expect(requirements).toEqual(new Set());
436
+ });
437
+ /**
438
+ * Test reading file with no requirements
439
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
440
+ * @req REQ-DEEP-PARSE - Handle files with no requirements
441
+ */
442
+ it("should return empty set for file with no requirements", async () => {
443
+ const noReqPath = path.join(tempDir, "no-requirements.md");
444
+ const content = `
445
+ # Story without requirements
446
+
447
+ ## Description
448
+
449
+ This story has no requirements.
450
+ `;
451
+ await fs.promises.writeFile(noReqPath, content, "utf8");
452
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(noReqPath);
453
+ expect(requirements).toEqual(new Set());
454
+ });
455
+ /**
456
+ * Test file with UTF-8 encoding
457
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
458
+ * @req REQ-DEEP-PARSE - Handle files with UTF-8 encoding
459
+ */
460
+ it("should handle UTF-8 encoded files", async () => {
461
+ const utf8Path = path.join(tempDir, "utf8-story.md");
462
+ const content = `
463
+ # Story with UTF-8 ✓
464
+
465
+ ## Requirements
466
+
467
+ - **REQ-UTF8-001**: Requirement with emoji 🚀
468
+ - **REQ-UTF8-002**: Requirement with accents: café, naïve
469
+ `;
470
+ await fs.promises.writeFile(utf8Path, content, "utf8");
471
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(utf8Path);
472
+ expect(requirements).toEqual(new Set(["REQ-UTF8-001", "REQ-UTF8-002"]));
473
+ });
474
+ /**
475
+ * Test file with Windows line endings
476
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
477
+ * @req REQ-DEEP-PARSE - Handle files with different line endings
478
+ */
479
+ it("should handle files with Windows line endings (CRLF)", async () => {
480
+ const crlfPath = path.join(tempDir, "crlf-story.md");
481
+ const content = "## Requirements\r\n\r\n- **REQ-CRLF-001**: First\r\n- **REQ-CRLF-002**: Second\r\n";
482
+ await fs.promises.writeFile(crlfPath, content, "utf8");
483
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(crlfPath);
484
+ expect(requirements).toEqual(new Set(["REQ-CRLF-001", "REQ-CRLF-002"]));
485
+ });
486
+ /**
487
+ * Test large file handling
488
+ * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
489
+ * @req REQ-DEEP-PARSE - Handle large story files efficiently
490
+ */
491
+ it("should handle large files with many requirements", async () => {
492
+ const largePath = path.join(tempDir, "large-story.md");
493
+ let content = "# Large Story\n\n## Requirements\n\n";
494
+ // Generate 100 requirements
495
+ for (let i = 1; i <= 100; i++) {
496
+ content += `- **REQ-LARGE-${i.toString().padStart(3, "0")}**: Requirement ${i}\n`;
497
+ }
498
+ await fs.promises.writeFile(largePath, content, "utf8");
499
+ const requirements = (0, storyParser_1.extractRequirementsFromStoryFile)(largePath);
500
+ expect(requirements.size).toBe(100);
501
+ expect(requirements.has("REQ-LARGE-001")).toBe(true);
502
+ expect(requirements.has("REQ-LARGE-100")).toBe(true);
503
+ });
504
+ });
505
+ });
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ /* eslint-disable traceability/valid-annotation-format */
36
37
  /**
37
38
  * Performance and stress tests for maintenance tools on large workspaces.
38
39
  * @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-DETECT REQ-MAINT-VERIFY REQ-MAINT-REPORT REQ-MAINT-UPDATE REQ-MAINT-BATCH
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ /* eslint-disable traceability/valid-annotation-format */
6
7
  /**
7
8
  * Performance tests for valid-annotation-format on large annotated files.
8
9
  *
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ /* eslint-disable traceability/valid-annotation-format */
36
37
  /**
37
38
  * Tests for: docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
38
39
  * @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ /* eslint-disable traceability/valid-annotation-format */
6
7
  /**
7
8
  * Tests for: docs/stories/007.0-DEV-ERROR-REPORTING.story.md
8
9
  * @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  * @req REQ-SAFE-REMOVAL - Verify that auto-fix removes only redundant annotations and preserves code
13
13
  * @req REQ-DIFFERENT-REQUIREMENTS - Verify that annotations with different requirement IDs are preserved
14
14
  * @req REQ-CATCH-BLOCK-HANDLING - Verify that catch block annotations are not incorrectly treated as redundant
15
+ * @supports docs/stories/027.0-DEV-REDUNDANT-ANNOTATION-DETECTION.story.md REQ-SCOPE-ANALYSIS REQ-DUPLICATION-DETECTION REQ-STATEMENT-SIGNIFICANCE REQ-SAFE-REMOVAL REQ-DIFFERENT-REQUIREMENTS REQ-CATCH-BLOCK-HANDLING REQ-SUPPORTS-COVERAGE REQ-SCOPE-INHERITANCE REQ-CONFIGURABLE-STRICTNESS
15
16
  */
16
17
  const eslint_1 = require("eslint");
17
18
  const no_redundant_annotation_1 = __importDefault(require("../../src/rules/no-redundant-annotation"));
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
8
8
  */
9
9
  const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
10
10
  const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
11
+ const require_story_utils_1 = require("../../src/rules/helpers/require-story-utils");
11
12
  describe("Require Story Helpers (Story 003.0)", () => {
12
13
  test("createAddStoryFix uses parent range start when available", () => {
13
14
  const target = {
@@ -117,8 +118,8 @@ describe("Require Story Helpers (Story 003.0)", () => {
117
118
  id: { name: "myFunc" },
118
119
  };
119
120
  const propNode = { type: "MethodDefinition", key: { name: "myProp" } };
120
- expect((0, require_story_helpers_1.getNodeName)(funcNode)).toBe("myFunc");
121
- expect((0, require_story_helpers_1.getNodeName)(propNode)).toBe("myProp");
121
+ expect((0, require_story_utils_1.getNodeName)(funcNode)).toBe("myFunc");
122
+ expect((0, require_story_utils_1.getNodeName)(propNode)).toBe("myProp");
122
123
  });
123
124
  test("shouldProcessNode returns booleans for typical node types", () => {
124
125
  const funcDecl = { type: "FunctionDeclaration" };
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ /* eslint-disable traceability/valid-annotation-format */
6
7
  /**
7
8
  * Tests for:
8
9
  * - docs/stories/020.0-DEV-TEST-ANNOTATION-VALIDATION.story.md
@@ -13,6 +13,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  * @req REQ-ERROR-SPECIFIC - Verify requirement-level errors identify the exact missing requirement
14
14
  * @req REQ-ERROR-CONTEXT - Verify requirement-level errors include relevant story path context
15
15
  * @req REQ-ERROR-CONSISTENCY - Verify requirement-level error messages are consistent across cases
16
+ * @supports docs/stories/010.0-DEV-DEEP-VALIDATION.story.md REQ-DEEP-PARSE REQ-DEEP-BULLET REQ-DEEP-IMPLEMENTS REQ-DEEP-MATCH
17
+ * @supports docs/stories/007.0-DEV-ERROR-REPORTING.story.md REQ-ERROR-SPECIFIC REQ-ERROR-CONTEXT REQ-ERROR-CONSISTENCY
16
18
  */
17
19
  const eslint_1 = require("eslint");
18
20
  const valid_req_reference_1 = __importDefault(require("../../src/rules/valid-req-reference"));
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable traceability/valid-annotation-format */
3
4
  /**
4
5
  * Unit tests for CatchClause insert position calculation.
5
6
  * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable traceability/valid-annotation-format */
3
4
  /**
4
5
  * Unit tests for else-if insert position calculation.
5
6
  * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable traceability/valid-annotation-format */
3
4
  /**
4
5
  * Unit tests for branch annotation helpers
5
6
  * Tests for: docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md