eslint-plugin-traceability 1.10.1 → 1.11.1

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 (70) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +3 -2
  3. package/lib/src/maintenance/cli.js +12 -12
  4. package/lib/src/maintenance/detect.js +19 -19
  5. package/lib/src/maintenance/flags.js +111 -25
  6. package/lib/src/rules/helpers/require-story-core.d.ts +55 -9
  7. package/lib/src/rules/helpers/require-story-core.js +85 -62
  8. package/lib/src/rules/helpers/require-story-helpers.d.ts +27 -48
  9. package/lib/src/rules/helpers/require-story-helpers.js +154 -116
  10. package/lib/src/rules/helpers/require-story-io.js +51 -31
  11. package/lib/src/rules/helpers/require-story-visitors.js +47 -6
  12. package/lib/src/rules/helpers/valid-annotation-format-validators.js +5 -1
  13. package/lib/src/rules/helpers/valid-annotation-options.d.ts +9 -0
  14. package/lib/src/rules/helpers/valid-annotation-options.js +67 -20
  15. package/lib/src/rules/helpers/valid-annotation-utils.js +31 -31
  16. package/lib/src/rules/helpers/valid-story-reference-helpers.js +19 -19
  17. package/lib/src/rules/prefer-implements-annotation.js +29 -1
  18. package/lib/src/rules/require-story-annotation.js +15 -0
  19. package/lib/src/rules/require-test-traceability.js +1 -6
  20. package/lib/src/utils/annotation-checker.js +32 -8
  21. package/lib/src/utils/reqAnnotationDetection.js +36 -22
  22. package/lib/tests/cli-error-handling.test.js +1 -0
  23. package/lib/tests/config/eslint-config-validation.test.d.ts +8 -0
  24. package/lib/tests/config/eslint-config-validation.test.js +8 -0
  25. package/lib/tests/config/flat-config-presets-integration.test.js +1 -3
  26. package/lib/tests/config/require-story-annotation-config.test.d.ts +9 -0
  27. package/lib/tests/config/require-story-annotation-config.test.js +9 -0
  28. package/lib/tests/integration/cli-integration.test.js +9 -1
  29. package/lib/tests/maintenance/batch.test.js +1 -0
  30. package/lib/tests/maintenance/cli.test.js +1 -0
  31. package/lib/tests/maintenance/detect-isolated.test.js +1 -0
  32. package/lib/tests/maintenance/detect.test.js +1 -0
  33. package/lib/tests/maintenance/index.test.js +1 -0
  34. package/lib/tests/maintenance/report.test.js +1 -0
  35. package/lib/tests/maintenance/update-isolated.test.js +1 -0
  36. package/lib/tests/maintenance/update.test.js +1 -0
  37. package/lib/tests/perf/maintenance-cli-large-workspace.test.d.ts +1 -0
  38. package/lib/tests/perf/maintenance-cli-large-workspace.test.js +130 -0
  39. package/lib/tests/perf/maintenance-large-workspace.test.d.ts +1 -0
  40. package/lib/tests/perf/maintenance-large-workspace.test.js +149 -0
  41. package/lib/tests/plugin-default-export-and-configs.test.js +2 -0
  42. package/lib/tests/plugin-setup-error.test.d.ts +1 -0
  43. package/lib/tests/plugin-setup-error.test.js +1 -0
  44. package/lib/tests/plugin-setup.test.js +1 -1
  45. package/lib/tests/rules/auto-fix-behavior-008.test.js +39 -0
  46. package/lib/tests/rules/error-reporting.test.js +1 -0
  47. package/lib/tests/rules/prefer-implements-annotation.test.js +8 -0
  48. package/lib/tests/rules/require-branch-annotation.test.js +2 -0
  49. package/lib/tests/rules/require-story-core-edgecases.test.js +1 -0
  50. package/lib/tests/rules/require-story-core.autofix.test.js +10 -3
  51. package/lib/tests/rules/require-story-core.test.js +14 -7
  52. package/lib/tests/rules/require-story-helpers-edgecases.test.d.ts +1 -0
  53. package/lib/tests/rules/require-story-helpers-edgecases.test.js +2 -1
  54. package/lib/tests/rules/require-story-helpers.test.js +18 -11
  55. package/lib/tests/rules/require-story-io-behavior.test.d.ts +1 -0
  56. package/lib/tests/rules/require-story-io-behavior.test.js +1 -0
  57. package/lib/tests/rules/require-story-io.edgecases.test.d.ts +1 -0
  58. package/lib/tests/rules/require-story-io.edgecases.test.js +1 -0
  59. package/lib/tests/rules/require-story-visitors-edgecases.test.d.ts +1 -0
  60. package/lib/tests/rules/require-story-visitors-edgecases.test.js +1 -0
  61. package/lib/tests/rules/valid-story-reference.test.js +2 -0
  62. package/lib/tests/utils/annotation-checker.test.js +2 -1
  63. package/lib/tests/utils/branch-annotation-helpers.test.js +2 -1
  64. package/lib/tests/utils/require-story-core-test-helpers.d.ts +1 -1
  65. package/lib/tests/utils/require-story-core-test-helpers.js +16 -16
  66. package/lib/tests/utils/temp-dir-helpers.js +1 -1
  67. package/package.json +9 -2
  68. package/user-docs/api-reference.md +123 -12
  69. package/user-docs/examples.md +41 -0
  70. package/user-docs/migration-guide.md +36 -3
@@ -2,4 +2,5 @@
2
2
  * Tests for: docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
3
3
  * @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
4
4
  * @req REQ-ERROR-HANDLING - Gracefully handles plugin loading errors and missing dependencies
5
+ * @supports docs/stories/001.0-DEV-PLUGIN-SETUP.story.md REQ-ERROR-HANDLING
5
6
  */
@@ -3,6 +3,7 @@
3
3
  * Tests for: docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
4
4
  * @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
5
5
  * @req REQ-ERROR-HANDLING - Gracefully handles plugin loading errors and missing dependencies
6
+ * @supports docs/stories/001.0-DEV-PLUGIN-SETUP.story.md REQ-ERROR-HANDLING
6
7
  */
7
8
  describe("Traceability ESLint Plugin Error Handling (Story 001.0-DEV-PLUGIN-SETUP)", () => {
8
9
  beforeEach(() => {
@@ -36,7 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  /**
37
37
  * Tests for: docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
38
38
  * @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
39
- * @req REQ-PLUGIN-STRUCTURE - plugin exports rules and configs
39
+ * @supports docs/stories/001.0-DEV-PLUGIN-SETUP.story.md REQ-PLUGIN-STRUCTURE
40
40
  */
41
41
  const index_1 = __importStar(require("../src/index"));
42
42
  describe("Traceability ESLint Plugin (Story 001.0-DEV-PLUGIN-SETUP)", () => {
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
8
8
  * @story docs/stories/008.0-DEV-AUTO-FIX.story.md
9
9
  * @req REQ-AUTOFIX-MISSING - Verify ESLint --fix automatically adds missing @story annotations to functions
10
10
  * @req REQ-AUTOFIX-FORMAT - Verify ESLint --fix corrects simple annotation format issues for @story annotations
11
+ * @supports docs/stories/008.0-DEV-AUTO-FIX.story.md REQ-AUTOFIX-MISSING REQ-AUTOFIX-FORMAT
11
12
  */
12
13
  const eslint_1 = require("eslint");
13
14
  const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
@@ -122,6 +123,29 @@ describe("Auto-fix behavior (Story 008.0-DEV-AUTO-FIX)", () => {
122
123
  },
123
124
  ],
124
125
  },
126
+ {
127
+ name: "[REQ-AUTOFIX-TEMPLATE] uses configured templates for functions and methods",
128
+ code: `function fn() {}\nclass C { method() {} }`,
129
+ output: `/** @story CUSTOM-FN */\nfunction fn() {}\nclass C { /** @story CUSTOM-METHOD */\n method() {} }`,
130
+ options: [
131
+ {
132
+ annotationTemplate: "/** @story CUSTOM-FN */",
133
+ methodAnnotationTemplate: "/** @story CUSTOM-METHOD */",
134
+ },
135
+ ],
136
+ errors: 2,
137
+ },
138
+ {
139
+ name: "[REQ-AUTOFIX-SELECTIVE] does not insert annotations when autoFix is false",
140
+ code: `function fnNoFix() {}`,
141
+ output: null,
142
+ options: [
143
+ {
144
+ autoFix: false,
145
+ },
146
+ ],
147
+ errors: 1,
148
+ },
125
149
  ],
126
150
  });
127
151
  });
@@ -154,6 +178,21 @@ describe("Auto-fix behavior (Story 008.0-DEV-AUTO-FIX)", () => {
154
178
  },
155
179
  ],
156
180
  },
181
+ {
182
+ name: "[REQ-AUTOFIX-SELECTIVE] does not apply suffix fix when autoFix is false",
183
+ code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story`,
184
+ output: null,
185
+ options: [
186
+ {
187
+ autoFix: false,
188
+ },
189
+ ],
190
+ errors: [
191
+ {
192
+ messageId: "invalidStoryFormat",
193
+ },
194
+ ],
195
+ },
157
196
  ],
158
197
  });
159
198
  });
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  /**
7
7
  * Tests for: docs/stories/007.0-DEV-ERROR-REPORTING.story.md
8
8
  * @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
9
+ * @supports docs/stories/007.0-DEV-ERROR-REPORTING.story.md REQ-ERROR-SPECIFIC REQ-ERROR-SUGGESTION REQ-ERROR-CONTEXT REQ-ERROR-LOCATION
9
10
  * @req REQ-ERROR-SPECIFIC - Specific details about what annotation is missing or invalid
10
11
  * @req REQ-ERROR-SUGGESTION - Suggest concrete steps to fix the issue
11
12
  * @req REQ-ERROR-CONTEXT - Include relevant context in error messages
@@ -33,6 +33,14 @@ describe("prefer-implements-annotation rule (Story 010.3-DEV-MIGRATE-TO-SUPPORTS
33
33
  name: "[REQ-BACKWARD-COMP-VALIDATION] comment with @supports only is ignored",
34
34
  code: `/**\n * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED\n */\nfunction alreadyImplements() {}`,
35
35
  },
36
+ {
37
+ name: "[REQ-BACKWARD-COMP-VALIDATION] comment with @story and @supports but no @req is ignored",
38
+ code: `/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED\n */\nfunction storyAndSupportsNoReq() {}`,
39
+ },
40
+ {
41
+ name: "[REQ-BACKWARD-COMP-VALIDATION] comment with @req and @supports but no @story is ignored",
42
+ code: `/**\n * @req REQ-ANNOTATION-REQUIRED\n * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED\n */\nfunction reqAndSupportsNoStory() {}`,
43
+ },
36
44
  ],
37
45
  invalid: [
38
46
  {
@@ -11,6 +11,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
11
11
  * @req REQ-ERROR-SPECIFIC - Branch-level missing-annotation error messages are specific and informative
12
12
  * @req REQ-ERROR-CONSISTENCY - Branch-level missing-annotation error messages follow shared conventions
13
13
  * @req REQ-ERROR-SUGGESTION - Branch-level missing-annotation errors include suggestions when applicable
14
+ * @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-BRANCH-DETECTION
15
+ * @supports docs/stories/007.0-DEV-ERROR-REPORTING.story.md REQ-ERROR-SPECIFIC REQ-ERROR-CONSISTENCY REQ-ERROR-SUGGESTION
14
16
  */
15
17
  const eslint_1 = require("eslint");
16
18
  const require_branch_annotation_1 = __importDefault(require("../../src/rules/require-branch-annotation"));
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  * Edge-case tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
6
6
  * @req REQ-AUTOFIX - Cover additional branch cases in require-story-core (addStoryFixer/reportMissing)
7
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-AUTOFIX
7
8
  */
8
9
  const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
9
10
  const require_story_core_test_helpers_1 = require("../utils/require-story-core-test-helpers");
@@ -4,14 +4,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
6
6
  * @req REQ-AUTOFIX - Cover additional branch cases in require-story-core (addStoryFixer/reportMissing)
7
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-AUTOFIX
7
8
  */
8
9
  const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
9
10
  const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
10
11
  const require_story_core_test_helpers_1 = require("../utils/require-story-core-test-helpers");
11
12
  describe("Require Story Core (Story 003.0)", () => {
12
13
  test("createAddStoryFix covers primary branch combinations via shared helper", () => {
13
- (0, require_story_core_test_helpers_1.exerciseCreateAddStoryFixBranches)(require_story_core_1.createAddStoryFix, {
14
- annotationText: require_story_helpers_1.ANNOTATION + "\n",
14
+ const defaultTemplate = (0, require_story_helpers_1.getAnnotationTemplate)();
15
+ const factory = (target, _annotationTemplate) => (0, require_story_core_1.createAddStoryFix)(target, defaultTemplate);
16
+ (0, require_story_core_test_helpers_1.exerciseCreateAddStoryFixBranches)(factory, {
17
+ annotationText: defaultTemplate,
15
18
  });
16
19
  });
17
20
  test("reportMissing uses context.getSourceCode fallback when sourceCode not provided and still reports", () => {
@@ -24,7 +27,11 @@ describe("Require Story Core (Story 003.0)", () => {
24
27
  /* intentionally missing getJSDocComment to exercise branch */ getText: () => "",
25
28
  };
26
29
  const context = { getSourceCode: () => fakeSource, report: jest.fn() };
27
- (0, require_story_core_1.reportMissing)(context, undefined, node, node);
30
+ (0, require_story_helpers_1.reportMissing)(context, undefined, {
31
+ node,
32
+ target: node,
33
+ options: { autoFixToggle: true },
34
+ });
28
35
  expect(context.report).toHaveBeenCalledTimes(1);
29
36
  const call = context.report.mock.calls[0][0];
30
37
  expect(call.node).toBe(node);
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
6
6
  * @req REQ-AUTOFIX - Verify createMethodFix and reportMethod behaviors
7
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-AUTOFIX
7
8
  */
8
9
  const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
9
10
  const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
@@ -17,13 +18,15 @@ describe("Require Story Core (Story 003.0)", () => {
17
18
  const fixer = {
18
19
  insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
19
20
  };
20
- const fixFn = (0, require_story_core_1.createMethodFix)(node);
21
+ const defaultTemplate = (0, require_story_helpers_1.getAnnotationTemplate)();
22
+ const fixFn = (0, require_story_core_1.createMethodFix)(node, defaultTemplate);
21
23
  const result = fixFn(fixer);
22
24
  expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
23
25
  const calledArgs = fixer.insertTextBeforeRange.mock.calls[0];
24
26
  expect(calledArgs[0]).toEqual([12, 12]);
25
- expect(calledArgs[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n `);
26
- expect(result).toEqual({ r: [12, 12], t: `${require_story_helpers_1.ANNOTATION}\n ` });
27
+ expect(typeof calledArgs[1]).toBe("string");
28
+ expect(calledArgs[1].length).toBeGreaterThan(0);
29
+ expect(result).toEqual({ r: [12, 12], t: calledArgs[1] });
27
30
  });
28
31
  test("reportMethod calls context.report with proper data and suggest.fix works", () => {
29
32
  const node = {
@@ -37,11 +40,14 @@ describe("Require Story Core (Story 003.0)", () => {
37
40
  getSourceCode: () => fakeSource,
38
41
  report: jest.fn(),
39
42
  };
40
- (0, require_story_core_1.reportMethod)(context, fakeSource, node, node);
43
+ (0, require_story_helpers_1.reportMethod)(context, fakeSource, { node, target: node });
41
44
  expect(context.report).toHaveBeenCalledTimes(1);
42
45
  const call = context.report.mock.calls[0][0];
43
46
  expect(call.messageId).toBe("missingStory");
44
- expect(call.data).toEqual({ name: "myMethod" });
47
+ expect(call.data).toHaveProperty("name");
48
+ expect(call.data).toHaveProperty("functionName");
49
+ expect(typeof call.data.name).toBe("string");
50
+ expect(typeof call.data.functionName).toBe("string");
45
51
  // The suggest fix should be a function; exercise it with a mock fixer
46
52
  expect(Array.isArray(call.suggest)).toBe(true);
47
53
  expect(typeof call.suggest[0].fix).toBe("function");
@@ -52,7 +58,8 @@ describe("Require Story Core (Story 003.0)", () => {
52
58
  expect(fixer.insertTextBeforeRange).toHaveBeenCalled();
53
59
  const args = fixer.insertTextBeforeRange.mock.calls[0];
54
60
  expect(args[0]).toEqual([40, 40]);
55
- expect(args[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n `);
56
- expect(fixResult).toEqual({ r: [40, 40], t: `${require_story_helpers_1.ANNOTATION}\n ` });
61
+ expect(typeof args[1]).toBe("string");
62
+ expect(args[1].length).toBeGreaterThan(0);
63
+ expect(fixResult).toEqual({ r: [40, 40], t: args[1] });
57
64
  });
58
65
  });
@@ -2,5 +2,6 @@
2
2
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
3
3
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @req REQ-HELPERS-EDGE-CASES - Edge-case behavior tests for helpers in require-story-helpers.ts
5
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-HELPERS-EDGE-CASES
5
6
  */
6
7
  export {};
@@ -3,6 +3,7 @@
3
3
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @req REQ-HELPERS-EDGE-CASES - Edge-case behavior tests for helpers in require-story-helpers.ts
6
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-HELPERS-EDGE-CASES
6
7
  */
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
9
  const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
@@ -73,7 +74,7 @@ describe("Require Story Helpers - edge cases (Story 003.0)", () => {
73
74
  },
74
75
  };
75
76
  const context = { getSourceCode: () => fakeSource, report: jest.fn() };
76
- (0, require_story_helpers_1.reportMissing)(context, fakeSource, node, node);
77
+ (0, require_story_helpers_1.reportMissing)(context, fakeSource, { node, target: node });
77
78
  expect(context.report).not.toHaveBeenCalled();
78
79
  });
79
80
  });
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
6
6
  * @req REQ-ANNOTATION-REQUIRED - Verify helper functions in require-story helpers produce correct fixes and reporting behavior
7
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED
7
8
  */
8
9
  const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
9
10
  const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
@@ -17,13 +18,15 @@ describe("Require Story Helpers (Story 003.0)", () => {
17
18
  const fixer = {
18
19
  insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
19
20
  };
20
- const fixFn = (0, require_story_core_1.createAddStoryFix)(target);
21
+ const defaultTemplate = (0, require_story_helpers_1.getAnnotationTemplate)();
22
+ const fixFn = (0, require_story_core_1.createAddStoryFix)(target, defaultTemplate);
21
23
  const result = fixFn(fixer);
22
24
  expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
23
25
  const calledArgs = fixer.insertTextBeforeRange.mock.calls[0];
24
26
  expect(calledArgs[0]).toEqual([10, 10]);
25
- expect(calledArgs[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
26
- expect(result).toEqual({ r: [10, 10], t: `${require_story_helpers_1.ANNOTATION}\n` });
27
+ expect(typeof calledArgs[1]).toBe("string");
28
+ expect(calledArgs[1].length).toBeGreaterThan(0);
29
+ expect(result).toEqual({ r: [10, 10], t: calledArgs[1] });
27
30
  });
28
31
  test("createMethodFix falls back to node.range when parent not export", () => {
29
32
  const node = {
@@ -34,16 +37,20 @@ describe("Require Story Helpers (Story 003.0)", () => {
34
37
  const fixer = {
35
38
  insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
36
39
  };
37
- const fixFn = (0, require_story_core_1.createMethodFix)(node);
40
+ const defaultTemplate = (0, require_story_helpers_1.getAnnotationTemplate)();
41
+ const fixFn = (0, require_story_core_1.createMethodFix)(node, defaultTemplate);
38
42
  const res = fixFn(fixer);
39
43
  expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([30, 30]);
40
- expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${require_story_helpers_1.ANNOTATION}\n `);
41
- expect(res).toEqual({ r: [30, 30], t: `${require_story_helpers_1.ANNOTATION}\n ` });
44
+ const insertedText = fixer.insertTextBeforeRange.mock
45
+ .calls[0][1];
46
+ expect(typeof insertedText).toBe("string");
47
+ expect(insertedText.length).toBeGreaterThan(0);
48
+ expect(res).toEqual({ r: [30, 30], t: insertedText });
42
49
  });
43
50
  test("reportMissing does not call context.report if JSDoc contains @story", () => {
44
51
  const node = {
45
52
  type: "FunctionDeclaration",
46
- id: { name: "fn" },
53
+ id: { type: "Identifier", name: "fn" },
47
54
  range: [0, 10],
48
55
  };
49
56
  const fakeSource = {
@@ -56,13 +63,13 @@ describe("Require Story Helpers (Story 003.0)", () => {
56
63
  getSourceCode: () => fakeSource,
57
64
  report: jest.fn(),
58
65
  };
59
- (0, require_story_core_1.reportMissing)(context, fakeSource, node, node);
66
+ (0, require_story_helpers_1.reportMissing)(context, fakeSource, { node, target: node });
60
67
  expect(context.report).not.toHaveBeenCalled();
61
68
  });
62
69
  test("reportMissing calls context.report when no JSDoc story present", () => {
63
70
  const node = {
64
71
  type: "FunctionDeclaration",
65
- id: { name: "fn2" },
72
+ id: { type: "Identifier", name: "fn2" },
66
73
  range: [0, 10],
67
74
  };
68
75
  const fakeSource = {
@@ -73,10 +80,10 @@ describe("Require Story Helpers (Story 003.0)", () => {
73
80
  getSourceCode: () => fakeSource,
74
81
  report: jest.fn(),
75
82
  };
76
- (0, require_story_core_1.reportMissing)(context, fakeSource, node, node);
83
+ (0, require_story_helpers_1.reportMissing)(context, fakeSource, { node, target: node });
77
84
  expect(context.report).toHaveBeenCalledTimes(1);
78
85
  const call = context.report.mock.calls[0][0];
79
- expect(call.node).toBe(node);
86
+ expect(call.node).toBe(node.id);
80
87
  expect(call.messageId).toBe("missingStory");
81
88
  });
82
89
  /**
@@ -2,5 +2,6 @@
2
2
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
3
3
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @req REQ-IO-BEHAVIOR-EDGE-CASES - Edge-case behavior tests for IO helpers in require-story-io.ts
5
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-IO-BEHAVIOR-EDGE-CASES
5
6
  */
6
7
  export {};
@@ -3,6 +3,7 @@
3
3
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @req REQ-IO-BEHAVIOR-EDGE-CASES - Edge-case behavior tests for IO helpers in require-story-io.ts
6
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-IO-BEHAVIOR-EDGE-CASES
6
7
  */
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
9
  const require_story_io_1 = require("../../src/rules/helpers/require-story-io");
@@ -2,5 +2,6 @@
2
2
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
3
3
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @req REQ-ANNOTATION-REQUIRED - Edge case tests for IO helpers (linesBeforeHasStory/fallbackTextBeforeHasStory/parentChainHasStory)
5
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED
5
6
  */
6
7
  export {};
@@ -3,6 +3,7 @@
3
3
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @req REQ-ANNOTATION-REQUIRED - Edge case tests for IO helpers (linesBeforeHasStory/fallbackTextBeforeHasStory/parentChainHasStory)
6
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED
6
7
  */
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
9
  const require_story_io_1 = require("../../src/rules/helpers/require-story-io");
@@ -2,5 +2,6 @@
2
2
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
3
3
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @req REQ-VISITORS-BEHAVIOR - Behavior tests for visitors in require-story-visitors.ts
5
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-VISITORS-BEHAVIOR
5
6
  */
6
7
  export {};
@@ -3,6 +3,7 @@
3
3
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
5
  * @req REQ-VISITORS-BEHAVIOR - Behavior tests for visitors in require-story-visitors.ts
6
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-VISITORS-BEHAVIOR
6
7
  */
7
8
  Object.defineProperty(exports, "__esModule", { value: true });
8
9
  const require_story_visitors_1 = require("../../src/rules/helpers/require-story-visitors");
@@ -45,6 +45,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
45
45
  * @req REQ-ERROR-CONTEXT - Verify file-related error messages include contextual information (path, underlying error)
46
46
  * @req REQ-ERROR-CONSISTENCY - Verify file-related error messages follow consistent formatting and identifiers
47
47
  * @req REQ-ERROR-HANDLING - Verify file-related errors are reported via diagnostics instead of uncaught exceptions
48
+ * @supports docs/stories/006.0-DEV-FILE-VALIDATION.story.md REQ-FILE-EXISTENCE REQ-CONFIGURABLE-PATHS
49
+ * @supports docs/stories/007.0-DEV-ERROR-REPORTING.story.md REQ-ERROR-SPECIFIC REQ-ERROR-CONTEXT REQ-ERROR-CONSISTENCY REQ-ERROR-HANDLING
48
50
  */
49
51
  const eslint_1 = require("eslint");
50
52
  const valid_story_reference_1 = __importDefault(require("../../src/rules/valid-story-reference"));
@@ -6,6 +6,7 @@ exports.runAnnotationCheckerTests = runAnnotationCheckerTests;
6
6
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
7
7
  * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
8
8
  * @req REQ-TEST-UTILS-TS-LANG - Shared TS RuleTester language options helper
9
+ * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-TYPESCRIPT-SUPPORT REQ-TEST-UTILS-TS-LANG
9
10
  */
10
11
  const eslint_1 = require("eslint");
11
12
  const annotation_checker_1 = require("../../src/utils/annotation-checker");
@@ -52,7 +53,7 @@ const rule = {
52
53
  };
53
54
  },
54
55
  };
55
- describe("annotation-checker helper", () => {
56
+ describe("annotation-checker helper (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", () => {
56
57
  runAnnotationCheckerTests("annotation-checker", {
57
58
  rule,
58
59
  valid: [
@@ -5,9 +5,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  * Tests for: docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
6
6
  * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
7
7
  * @req REQ-CONFIGURABLE-SCOPE - Allow configuration of branch types for annotation enforcement
8
+ * @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-CONFIGURABLE-SCOPE
8
9
  */
9
10
  const branch_annotation_helpers_1 = require("../../src/utils/branch-annotation-helpers");
10
- describe("validateBranchTypes helper", () => {
11
+ describe("validateBranchTypes helper (Story 004.0-DEV-BRANCH-ANNOTATIONS)", () => {
11
12
  let context;
12
13
  beforeEach(() => {
13
14
  context = { options: [], report: jest.fn() };
@@ -6,5 +6,5 @@
6
6
  interface ExerciseOptions {
7
7
  annotationText?: string;
8
8
  }
9
- export declare function exerciseCreateAddStoryFixBranches(createAddStoryFix: any, options?: ExerciseOptions): void;
9
+ export declare function exerciseCreateAddStoryFixBranches(createAddStoryFixFactory: (_target: any, _annotationTemplate: string) => (_fixer: any) => any, options?: ExerciseOptions): void;
10
10
  export {};
@@ -19,36 +19,36 @@ function baseFixer() {
19
19
  insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
20
20
  };
21
21
  }
22
- function exerciseBranch1(createAddStoryFix, annotation) {
22
+ function exerciseBranch1(createAddStoryFixFactory, annotation) {
23
23
  const fixer = baseFixer();
24
- const fixFn = createAddStoryFix(null);
24
+ const fixFn = createAddStoryFixFactory(null, annotation);
25
25
  const res = fixFn(fixer);
26
26
  expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
27
27
  const args = fixer.insertTextBeforeRange.mock.calls[0];
28
28
  expect(args[0]).toEqual([0, 0]);
29
- expect(args[1]).toBe(annotation);
29
+ expect(args[1]).toBe(`${annotation}\n`);
30
30
  expect(res).toEqual({
31
31
  r: [0, 0],
32
- t: annotation,
32
+ t: `${annotation}\n`,
33
33
  });
34
34
  }
35
- function exerciseBranch2(createAddStoryFix, annotation) {
35
+ function exerciseBranch2(createAddStoryFixFactory, annotation) {
36
36
  const target = {
37
37
  type: "FunctionDeclaration",
38
38
  range: [RANGE_ONE_START, RANGE_ONE_END],
39
39
  parent: { type: "ClassBody" },
40
40
  };
41
41
  const fixer = baseFixer();
42
- const fixFn = createAddStoryFix(target);
42
+ const fixFn = createAddStoryFixFactory(target, annotation);
43
43
  const res = fixFn(fixer);
44
44
  expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([RANGE_ONE_START, RANGE_ONE_START]);
45
- expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(annotation);
45
+ expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${annotation}\n`);
46
46
  expect(res).toEqual({
47
47
  r: [RANGE_ONE_START, RANGE_ONE_START],
48
- t: annotation,
48
+ t: `${annotation}\n`,
49
49
  });
50
50
  }
51
- function exerciseBranch3(createAddStoryFix, annotation) {
51
+ function exerciseBranch3(createAddStoryFixFactory, annotation) {
52
52
  const target = {
53
53
  type: "FunctionDeclaration",
54
54
  range: [RANGE_TWO_START, RANGE_TWO_END],
@@ -58,18 +58,18 @@ function exerciseBranch3(createAddStoryFix, annotation) {
58
58
  },
59
59
  };
60
60
  const fixer = baseFixer();
61
- const fixFn = createAddStoryFix(target);
61
+ const fixFn = createAddStoryFixFactory(target, annotation);
62
62
  const res = fixFn(fixer);
63
63
  expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([RANGE_PARENT_START, RANGE_PARENT_START]);
64
- expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(annotation);
64
+ expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${annotation}\n`);
65
65
  expect(res).toEqual({
66
66
  r: [RANGE_PARENT_START, RANGE_PARENT_START],
67
- t: annotation,
67
+ t: `${annotation}\n`,
68
68
  });
69
69
  }
70
- function exerciseCreateAddStoryFixBranches(createAddStoryFix, options = {}) {
70
+ function exerciseCreateAddStoryFixBranches(createAddStoryFixFactory, options = {}) {
71
71
  const annotation = options.annotationText ?? DEFAULT_ANNOTATION;
72
- exerciseBranch1(createAddStoryFix, annotation);
73
- exerciseBranch2(createAddStoryFix, annotation);
74
- exerciseBranch3(createAddStoryFix, annotation);
72
+ exerciseBranch1(createAddStoryFixFactory, annotation);
73
+ exerciseBranch2(createAddStoryFixFactory, annotation);
74
+ exerciseBranch3(createAddStoryFixFactory, annotation);
75
75
  }
@@ -54,7 +54,7 @@ function createTempDir(prefix) {
54
54
  return {
55
55
  dir,
56
56
  cleanup() {
57
- // @implements docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-SAFE
57
+ // @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-SAFE
58
58
  fs.rmSync(dir, { recursive: true, force: true });
59
59
  },
60
60
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-traceability",
3
- "version": "1.10.1",
3
+ "version": "1.11.1",
4
4
  "description": "A customizable ESLint plugin that enforces traceability annotations in your code, ensuring each implementation is linked to its requirement or test case.",
5
5
  "main": "lib/src/index.js",
6
6
  "types": "lib/src/index.d.ts",
@@ -35,12 +35,19 @@
35
35
  "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
36
36
  "lint-staged": "lint-staged",
37
37
  "duplication": "jscpd src tests --reporters console --threshold 3 --ignore tests/utils/**",
38
+ "coverage:branches": "node scripts/extract-uncovered-branches.js",
38
39
  "deps:maturity": "dry-aged-deps",
39
40
  "audit:dev-high": "node scripts/generate-dev-deps-audit.js",
40
41
  "safety:deps": "node scripts/ci-safety-deps.js",
41
42
  "audit:ci": "node scripts/ci-audit.js",
43
+ "check:ci-artifacts": "node scripts/check-no-tracked-ci-artifacts.js",
42
44
  "security:secrets": "secretlint \"**/*\" --no-color",
43
- "smoke-test": "./scripts/smoke-test.sh"
45
+ "smoke-test": "./scripts/smoke-test.sh",
46
+ "debug:cli": "node scripts/cli-debug.js",
47
+ "debug:require-story": "node scripts/debug-require-story.js",
48
+ "debug:repro": "node scripts/debug-repro.js",
49
+ "report:eslint-suppressions": "node scripts/report-eslint-suppressions.js",
50
+ "check:scripts": "node scripts/validate-scripts-nonempty.js"
44
51
  },
45
52
  "lint-staged": {
46
53
  "src/**/*.{js,jsx,ts,tsx,json,md}": [