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
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  */
11
11
  const eslint_1 = require("eslint");
12
12
  const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
13
+ const ts_language_options_1 = require("../utils/ts-language-options");
13
14
  const ruleTester = new eslint_1.RuleTester({
14
15
  languageOptions: {
15
16
  parserOptions: { ecmaVersion: 2020, sourceType: "module" },
@@ -36,30 +37,22 @@ function foo() {}`,
36
37
  code: `// @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
37
38
  const arrowFn = () => {};`,
38
39
  },
39
- {
40
+ (0, ts_language_options_1.withTsLanguageOptions)({
40
41
  name: "[REQ-ANNOTATION-REQUIRED] valid on class method with annotation",
41
42
  code: `class A {\n /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\n method() {}\n}`,
42
- },
43
- {
43
+ }),
44
+ (0, ts_language_options_1.withTsLanguageOptions)({
44
45
  name: "[REQ-FUNCTION-DETECTION] valid with annotation on TS declare function",
45
46
  code: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
46
47
  declare function tsDecl(): void;`,
47
- languageOptions: {
48
- parser: require("@typescript-eslint/parser"),
49
- parserOptions: { ecmaVersion: 2020, sourceType: "module" },
50
- },
51
- },
52
- {
48
+ }),
49
+ (0, ts_language_options_1.withTsLanguageOptions)({
53
50
  name: "[REQ-FUNCTION-DETECTION] valid with annotation on TS method signature",
54
51
  code: `interface C {
55
52
  /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
56
53
  method(): void;
57
54
  }`,
58
- languageOptions: {
59
- parser: require("@typescript-eslint/parser"),
60
- parserOptions: { ecmaVersion: 2020, sourceType: "module" },
61
- },
62
- },
55
+ }),
63
56
  {
64
57
  name: "[REQ-ANNOTATION-REQUIRED] unannotated arrow function allowed by default",
65
58
  code: `const arrowFn = () => {};`,
@@ -98,7 +91,7 @@ declare function tsDecl(): void;`,
98
91
  },
99
92
  ],
100
93
  },
101
- {
94
+ (0, ts_language_options_1.withTsLanguageOptions)({
102
95
  name: "[REQ-ANNOTATION-REQUIRED] missing @story on class method",
103
96
  code: `class C {\n method() {}\n}`,
104
97
  output: `class C {\n /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\n method() {}\n}`,
@@ -114,15 +107,11 @@ declare function tsDecl(): void;`,
114
107
  ],
115
108
  },
116
109
  ],
117
- },
118
- {
110
+ }),
111
+ (0, ts_language_options_1.withTsLanguageOptions)({
119
112
  name: "[REQ-ANNOTATION-REQUIRED] missing @story on TS declare function",
120
113
  code: `declare function tsDecl(): void;`,
121
114
  output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\ndeclare function tsDecl(): void;`,
122
- languageOptions: {
123
- parser: require("@typescript-eslint/parser"),
124
- parserOptions: { ecmaVersion: 2020, sourceType: "module" },
125
- },
126
115
  errors: [
127
116
  {
128
117
  messageId: "missingStory",
@@ -134,15 +123,11 @@ declare function tsDecl(): void;`,
134
123
  ],
135
124
  },
136
125
  ],
137
- },
138
- {
126
+ }),
127
+ (0, ts_language_options_1.withTsLanguageOptions)({
139
128
  name: "[REQ-ANNOTATION-REQUIRED] missing @story on TS method signature",
140
129
  code: `interface D {\n method(): void;\n}`,
141
130
  output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\ninterface D {\n method(): void;\n}`,
142
- languageOptions: {
143
- parser: require("@typescript-eslint/parser"),
144
- parserOptions: { ecmaVersion: 2020, sourceType: "module" },
145
- },
146
131
  errors: [
147
132
  {
148
133
  messageId: "missingStory",
@@ -154,7 +139,7 @@ declare function tsDecl(): void;`,
154
139
  ],
155
140
  },
156
141
  ],
157
- },
142
+ }),
158
143
  ],
159
144
  });
160
145
  ruleTester.run("require-story-annotation with exportPriority option", require_story_annotation_1.default, {
@@ -6,64 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  * @req REQ-AUTOFIX - Cover additional branch cases in require-story-core (addStoryFixer/reportMissing)
7
7
  */
8
8
  const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
9
- const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
9
+ const require_story_core_test_helpers_1 = require("../utils/require-story-core-test-helpers");
10
10
  describe("Require Story Core - edge cases (Story 003.0)", () => {
11
- test("createAddStoryFix falls back to 0 when target is falsy", () => {
12
- const fixer = {
13
- insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
14
- };
15
- const fixFn = (0, require_story_core_1.createAddStoryFix)(null);
16
- const res = fixFn(fixer);
17
- expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
18
- const args = fixer.insertTextBeforeRange.mock.calls[0];
19
- expect(args[0]).toEqual([0, 0]);
20
- expect(args[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
21
- expect(res).toEqual({ r: [0, 0], t: `${require_story_helpers_1.ANNOTATION}\n` });
22
- });
23
- test("createAddStoryFix uses target.range when parent not export and parent.range missing", () => {
24
- const target = {
25
- type: "FunctionDeclaration",
26
- range: [21, 33],
27
- parent: { type: "ClassBody" },
28
- };
29
- const fixer = {
30
- insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
31
- };
32
- const fixFn = (0, require_story_core_1.createAddStoryFix)(target);
33
- const res = fixFn(fixer);
34
- expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([21, 21]);
35
- expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
36
- expect(res).toEqual({ r: [21, 21], t: `${require_story_helpers_1.ANNOTATION}\n` });
37
- });
38
- test("createAddStoryFix prefers ExportDefaultDeclaration parent.range when present", () => {
39
- const target = {
40
- type: "FunctionDeclaration",
41
- range: [50, 70],
42
- parent: { type: "ExportDefaultDeclaration", range: [5, 100] },
43
- };
44
- const fixer = {
45
- insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
46
- };
47
- const fixFn = (0, require_story_core_1.createAddStoryFix)(target);
48
- const res = fixFn(fixer);
49
- expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([5, 5]);
50
- expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
51
- expect(res).toEqual({ r: [5, 5], t: `${require_story_helpers_1.ANNOTATION}\n` });
52
- });
53
- test("reportMissing uses context.getSourceCode fallback when sourceCode not provided and still reports", () => {
54
- const node = {
55
- type: "FunctionDeclaration",
56
- id: { name: "fnX" },
57
- range: [0, 10],
58
- };
59
- const fakeSource = {
60
- /* intentionally missing getJSDocComment to exercise branch */ getText: () => "",
61
- };
62
- const context = { getSourceCode: () => fakeSource, report: jest.fn() };
63
- (0, require_story_core_1.reportMissing)(context, undefined, node, node);
64
- expect(context.report).toHaveBeenCalledTimes(1);
65
- const call = context.report.mock.calls[0][0];
66
- expect(call.node).toBe(node);
67
- expect(call.messageId).toBe("missingStory");
11
+ test("createAddStoryFix covers primary branch combinations via shared helper (edge cases)", () => {
12
+ (0, require_story_core_test_helpers_1.exerciseCreateAddStoryFixBranches)(require_story_core_1.createAddStoryFix);
68
13
  });
69
14
  });
@@ -7,48 +7,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  */
8
8
  const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
9
9
  const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
10
+ const require_story_core_test_helpers_1 = require("../utils/require-story-core-test-helpers");
10
11
  describe("Require Story Core (Story 003.0)", () => {
11
- test("createAddStoryFix falls back to 0 when target is falsy", () => {
12
- const fixer = {
13
- insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
14
- };
15
- const fixFn = (0, require_story_core_1.createAddStoryFix)(null);
16
- const res = fixFn(fixer);
17
- expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
18
- const args = fixer.insertTextBeforeRange.mock.calls[0];
19
- expect(args[0]).toEqual([0, 0]);
20
- expect(args[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
21
- expect(res).toEqual({ r: [0, 0], t: `${require_story_helpers_1.ANNOTATION}\n` });
22
- });
23
- test("createAddStoryFix uses target.range when parent not export and parent.range missing", () => {
24
- const target = {
25
- type: "FunctionDeclaration",
26
- range: [21, 33],
27
- parent: { type: "ClassBody" },
28
- };
29
- const fixer = {
30
- insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
31
- };
32
- const fixFn = (0, require_story_core_1.createAddStoryFix)(target);
33
- const res = fixFn(fixer);
34
- expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([21, 21]);
35
- expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
36
- expect(res).toEqual({ r: [21, 21], t: `${require_story_helpers_1.ANNOTATION}\n` });
37
- });
38
- test("createAddStoryFix prefers ExportDefaultDeclaration parent.range when present", () => {
39
- const target = {
40
- type: "FunctionDeclaration",
41
- range: [50, 70],
42
- parent: { type: "ExportDefaultDeclaration", range: [5, 100] },
43
- };
44
- const fixer = {
45
- insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
46
- };
47
- const fixFn = (0, require_story_core_1.createAddStoryFix)(target);
48
- const res = fixFn(fixer);
49
- expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([5, 5]);
50
- expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
51
- expect(res).toEqual({ r: [5, 5], t: `${require_story_helpers_1.ANNOTATION}\n` });
12
+ 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",
15
+ });
52
16
  });
53
17
  test("reportMissing uses context.getSourceCode fallback when sourceCode not provided and still reports", () => {
54
18
  const node = {