eslint-plugin-traceability 1.6.1 → 1.6.3

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.
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  * @req REQ-ERROR-SPECIFIC - Specific details about what annotation is missing or invalid
10
10
  * @req REQ-ERROR-SUGGESTION - Suggest concrete steps to fix the issue
11
11
  * @req REQ-ERROR-CONTEXT - Include relevant context in error messages
12
+ * @req REQ-ERROR-LOCATION - Include precise location information in error messages
12
13
  */
13
14
  const eslint_1 = require("eslint");
14
15
  const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
@@ -18,31 +19,79 @@ const ruleTester = new eslint_1.RuleTester({
18
19
  },
19
20
  });
20
21
  describe("Error Reporting Enhancements for require-story-annotation (Story 007.0-DEV-ERROR-REPORTING)", () => {
21
- ruleTester.run("require-story-annotation", require_story_annotation_1.default, {
22
- valid: [
23
- {
24
- name: "[007.0-DEV-ERROR-REPORTING] valid with existing annotation",
25
- code: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */ function foo() {}`,
26
- },
27
- ],
28
- invalid: [
29
- {
30
- name: "[REQ-ERROR-SPECIFIC] missing @story annotation should report specific details and suggestion",
31
- code: `function bar() {}`,
32
- output: "/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction bar() {}",
33
- errors: [
22
+ describe("valid cases", () => {
23
+ ruleTester.run("require-story-annotation", require_story_annotation_1.default, {
24
+ valid: [
25
+ {
26
+ name: "[007.0-DEV-ERROR-REPORTING] valid with existing annotation",
27
+ code: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */ function foo() {}`,
28
+ },
29
+ ],
30
+ invalid: [],
31
+ });
32
+ });
33
+ describe("REQ-ERROR-SPECIFIC - missing @story annotation should report specific details and suggestion", () => {
34
+ it("reports specific message, data, and suggestions for function 'bar'", () => {
35
+ const code = "function bar() {}";
36
+ const reported = [];
37
+ const context = {
38
+ id: "require-story-annotation",
39
+ options: [],
40
+ report: (descriptor) => {
41
+ reported.push(descriptor);
42
+ },
43
+ getFilename: () => "test.js",
44
+ getSourceCode: () => ({
45
+ text: code,
46
+ getText: () => code,
47
+ ast: {
48
+ type: "Program",
49
+ body: [],
50
+ sourceType: "module",
51
+ },
52
+ }),
53
+ };
54
+ const listeners = require_story_annotation_1.default.create(context);
55
+ // Minimal synthetic AST nodes for the visitors
56
+ const programNode = {
57
+ type: "Program",
58
+ body: [
34
59
  {
35
- messageId: "missingStory",
36
- data: { name: "bar" },
37
- suggestions: [
38
- {
39
- desc: "Add JSDoc @story annotation for function 'bar', e.g., /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */",
40
- output: "/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction bar() {}",
41
- },
42
- ],
60
+ type: "FunctionDeclaration",
61
+ id: { type: "Identifier", name: "bar" },
62
+ params: [],
63
+ body: {
64
+ type: "BlockStatement",
65
+ body: [],
66
+ },
43
67
  },
44
68
  ],
45
- },
46
- ],
69
+ sourceType: "module",
70
+ };
71
+ const functionNode = programNode.body[0];
72
+ // Invoke visitors if they exist
73
+ if (typeof listeners.Program === "function") {
74
+ listeners.Program(programNode);
75
+ }
76
+ if (typeof listeners.FunctionDeclaration === "function") {
77
+ listeners.FunctionDeclaration(functionNode);
78
+ }
79
+ expect(reported.length).toBe(1);
80
+ const error = reported[0];
81
+ // Message template should be defined and contain the {{name}} placeholder
82
+ const template = require_story_annotation_1.default.meta?.messages?.missingStory;
83
+ expect(typeof template).toBe("string");
84
+ expect(template.length).toBeGreaterThan(0);
85
+ expect(template.includes("{{name}}")).toBe(true);
86
+ // Ensure messageId and data wiring is correct
87
+ expect(error.messageId).toBe("missingStory");
88
+ expect(error.data).toEqual({ name: "bar", functionName: "bar" });
89
+ // Suggestions
90
+ expect(Array.isArray(error.suggest)).toBe(true);
91
+ expect(error.suggest.length).toBeGreaterThanOrEqual(1);
92
+ const suggestion = error.suggest[0];
93
+ expect(suggestion.desc).toBe("Add JSDoc @story annotation for function 'bar', e.g., /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */");
94
+ expect(suggestion.fix).toBeDefined();
95
+ });
47
96
  });
48
97
  });
@@ -4,9 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  /**
7
- * Tests for: docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
7
+ * Tests for: docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md, docs/stories/007.0-DEV-ERROR-REPORTING.story.md
8
8
  * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
9
+ * @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
9
10
  * @req REQ-BRANCH-DETECTION - Verify require-branch-annotation rule enforces branch annotations
11
+ * @req REQ-ERROR-SPECIFIC - Branch-level missing-annotation error messages are specific and informative
12
+ * @req REQ-ERROR-CONSISTENCY - Branch-level missing-annotation error messages follow shared conventions
13
+ * @req REQ-ERROR-SUGGESTION - Branch-level missing-annotation errors include suggestions when applicable
10
14
  */
11
15
  const eslint_1 = require("eslint");
12
16
  const require_branch_annotation_1 = __importDefault(require("../../src/rules/require-branch-annotation"));
@@ -108,17 +108,32 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
108
108
  {
109
109
  name: "[REQ-ANNOTATION-REQUIRED] missing @req on function without JSDoc",
110
110
  code: `function baz() {}`,
111
- errors: [{ messageId: "missingReq", data: { name: "baz" } }],
111
+ errors: [
112
+ {
113
+ messageId: "missingReq",
114
+ data: { name: "baz", functionName: "baz" },
115
+ },
116
+ ],
112
117
  },
113
118
  {
114
119
  name: "[REQ-ANNOTATION-REQUIRED] missing @req on function with only @story annotation",
115
120
  code: `/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n */\nfunction qux() {}`,
116
- errors: [{ messageId: "missingReq", data: { name: "qux" } }],
121
+ errors: [
122
+ {
123
+ messageId: "missingReq",
124
+ data: { name: "qux", functionName: "qux" },
125
+ },
126
+ ],
117
127
  },
118
128
  {
119
129
  name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSDeclareFunction",
120
130
  code: `declare function baz(): void;`,
121
- errors: [{ messageId: "missingReq", data: { name: "baz" } }],
131
+ errors: [
132
+ {
133
+ messageId: "missingReq",
134
+ data: { name: "baz", functionName: "baz" },
135
+ },
136
+ ],
122
137
  languageOptions: {
123
138
  parser: require("@typescript-eslint/parser"),
124
139
  parserOptions: { ecmaVersion: 2022, sourceType: "module" },
@@ -127,7 +142,12 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
127
142
  {
128
143
  name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSMethodSignature",
129
144
  code: `interface I { method(): void; }`,
130
- errors: [{ messageId: "missingReq", data: { name: "method" } }],
145
+ errors: [
146
+ {
147
+ messageId: "missingReq",
148
+ data: { name: "method", functionName: "method" },
149
+ },
150
+ ],
131
151
  languageOptions: {
132
152
  parser: require("@typescript-eslint/parser"),
133
153
  parserOptions: { ecmaVersion: 2022, sourceType: "module" },
@@ -136,27 +156,52 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
136
156
  {
137
157
  name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on FunctionExpression assigned to variable",
138
158
  code: `const fn = function () {};`,
139
- errors: [{ messageId: "missingReq", data: { name: "fn" } }],
159
+ errors: [
160
+ {
161
+ messageId: "missingReq",
162
+ data: { name: "fn", functionName: "fn" },
163
+ },
164
+ ],
140
165
  },
141
166
  {
142
167
  name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on anonymous FunctionExpression (no variable name)",
143
168
  code: `(function () {})();`,
144
- errors: [{ messageId: "missingReq", data: { name: "(anonymous)" } }],
169
+ errors: [
170
+ {
171
+ messageId: "missingReq",
172
+ data: { name: "(anonymous)", functionName: "(anonymous)" },
173
+ },
174
+ ],
145
175
  },
146
176
  {
147
177
  name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on MethodDefinition in class",
148
178
  code: `class C {\n m() {}\n}`,
149
- errors: [{ messageId: "missingReq" }],
179
+ errors: [
180
+ {
181
+ messageId: "missingReq",
182
+ data: { name: "m", functionName: "m" },
183
+ },
184
+ ],
150
185
  },
151
186
  {
152
187
  name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on MethodDefinition in object literal",
153
188
  code: `const o = { m() {} };`,
154
- errors: [{ messageId: "missingReq" }],
189
+ errors: [
190
+ {
191
+ messageId: "missingReq",
192
+ data: { name: "m", functionName: "m" },
193
+ },
194
+ ],
155
195
  },
156
196
  {
157
197
  name: "[REQ-TYPESCRIPT-SUPPORT][REQ-FUNCTION-DETECTION][Story 003.0] missing @req on TS FunctionExpression in variable declarator",
158
198
  code: `const fn = function () {};`,
159
- errors: [{ messageId: "missingReq", data: { name: "fn" } }],
199
+ errors: [
200
+ {
201
+ messageId: "missingReq",
202
+ data: { name: "fn", functionName: "fn" },
203
+ },
204
+ ],
160
205
  languageOptions: {
161
206
  parser: require("@typescript-eslint/parser"),
162
207
  parserOptions: { ecmaVersion: 2022, sourceType: "module" },
@@ -165,7 +210,12 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
165
210
  {
166
211
  name: "[REQ-TYPESCRIPT-SUPPORT][REQ-FUNCTION-DETECTION][Story 003.0] missing @req on exported TS FunctionExpression in variable declarator",
167
212
  code: `export const fn = function () {};`,
168
- errors: [{ messageId: "missingReq", data: { name: "fn" } }],
213
+ errors: [
214
+ {
215
+ messageId: "missingReq",
216
+ data: { name: "fn", functionName: "fn" },
217
+ },
218
+ ],
169
219
  languageOptions: {
170
220
  parser: require("@typescript-eslint/parser"),
171
221
  parserOptions: { ecmaVersion: 2022, sourceType: "module" },
@@ -175,43 +225,78 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
175
225
  name: "[REQ-CONFIGURABLE-SCOPE][Story 003.0] FunctionDeclaration still reported when scope only includes FunctionDeclaration",
176
226
  code: `function scoped() {}`,
177
227
  options: [{ scope: ["FunctionDeclaration"] }],
178
- errors: [{ messageId: "missingReq", data: { name: "scoped" } }],
228
+ errors: [
229
+ {
230
+ messageId: "missingReq",
231
+ data: { name: "scoped", functionName: "scoped" },
232
+ },
233
+ ],
179
234
  },
180
235
  {
181
236
  name: "[REQ-EXPORT-PRIORITY][Story 003.0] exported function reported when exportPriority is 'exported'",
182
237
  code: `export function exportedFn() {}`,
183
238
  options: [{ exportPriority: "exported" }],
184
- errors: [{ messageId: "missingReq", data: { name: "exportedFn" } }],
239
+ errors: [
240
+ {
241
+ messageId: "missingReq",
242
+ data: { name: "exportedFn", functionName: "exportedFn" },
243
+ },
244
+ ],
185
245
  },
186
246
  {
187
247
  name: "[REQ-EXPORT-PRIORITY][Story 003.0] non-exported function reported when exportPriority is 'non-exported'",
188
248
  code: `function nonExported() {}`,
189
249
  options: [{ exportPriority: "non-exported" }],
190
- errors: [{ messageId: "missingReq", data: { name: "nonExported" } }],
250
+ errors: [
251
+ {
252
+ messageId: "missingReq",
253
+ data: { name: "nonExported", functionName: "nonExported" },
254
+ },
255
+ ],
191
256
  },
192
257
  {
193
258
  name: "[REQ-EXPORT-PRIORITY][Story 003.0] exported method reported when exportPriority is 'exported'",
194
259
  code: `export class C {\n m() {}\n}`,
195
- errors: [{ messageId: "missingReq" }],
260
+ errors: [
261
+ {
262
+ messageId: "missingReq",
263
+ data: { name: "m", functionName: "m" },
264
+ },
265
+ ],
196
266
  options: [{ exportPriority: "exported" }],
197
267
  },
198
268
  {
199
269
  name: "[REQ-EXPORT-PRIORITY][Story 003.0] non-exported method reported when exportPriority is 'non-exported'",
200
270
  code: `class C {\n m() {}\n}`,
201
- errors: [{ messageId: "missingReq" }],
271
+ errors: [
272
+ {
273
+ messageId: "missingReq",
274
+ data: { name: "m", functionName: "m" },
275
+ },
276
+ ],
202
277
  options: [{ exportPriority: "non-exported" }],
203
278
  },
204
279
  {
205
280
  name: "[REQ-EXPORT-PRIORITY][Story 003.0] exported FunctionExpression reported when exportPriority is 'exported'",
206
281
  code: `export const fn = function () {};`,
207
282
  options: [{ exportPriority: "exported" }],
208
- errors: [{ messageId: "missingReq", data: { name: "fn" } }],
283
+ errors: [
284
+ {
285
+ messageId: "missingReq",
286
+ data: { name: "fn", functionName: "fn" },
287
+ },
288
+ ],
209
289
  },
210
290
  {
211
291
  name: "[REQ-EXPORT-PRIORITY][Story 003.0] non-exported FunctionExpression reported when exportPriority is 'non-exported'",
212
292
  code: `const fn = function () {};`,
213
293
  options: [{ exportPriority: "non-exported" }],
214
- errors: [{ messageId: "missingReq", data: { name: "fn" } }],
294
+ errors: [
295
+ {
296
+ messageId: "missingReq",
297
+ data: { name: "fn", functionName: "fn" },
298
+ },
299
+ ],
215
300
  },
216
301
  ],
217
302
  });
@@ -105,6 +105,7 @@ declare function tsDecl(): void;`,
105
105
  errors: [
106
106
  {
107
107
  messageId: "missingStory",
108
+ data: { name: "method", functionName: "method" },
108
109
  suggestions: [
109
110
  {
110
111
  desc: `Add JSDoc @story annotation for function 'method', e.g., /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */`,
@@ -7,6 +7,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  * Tests for: docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
8
8
  * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
9
9
  * @req REQ-FORMAT-SPECIFICATION - Verify valid-annotation-format rule enforces annotation format syntax
10
+ * Tests for: docs/stories/007.0-DEV-ERROR-REPORTING.story.md
11
+ * @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
12
+ * @req REQ-ERROR-MESSAGES-CONSISTENT - Verify invalid annotation errors use consistent wording and structure
13
+ * @req REQ-ERROR-MESSAGES-ACTIONABLE - Verify invalid annotation errors provide actionable guidance and examples
14
+ * @req REQ-ERROR-MESSAGES-IDENTIFIERS - Verify invalid annotation errors echo the offending identifier/path in the message
10
15
  */
11
16
  const eslint_1 = require("eslint");
12
17
  const valid_annotation_format_1 = __importDefault(require("../../src/rules/valid-annotation-format"));
@@ -7,6 +7,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  * Tests for: docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
8
8
  * @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
9
9
  * @req REQ-DEEP-PARSE - Verify valid-req-reference rule enforces existing requirement content
10
+ *
11
+ * Additional coverage for error reporting behavior:
12
+ * @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
13
+ * @req REQ-ERROR-SPECIFIC - Verify requirement-level errors identify the exact missing requirement
14
+ * @req REQ-ERROR-CONTEXT - Verify requirement-level errors include relevant story path context
15
+ * @req REQ-ERROR-CONSISTENCY - Verify requirement-level error messages are consistent across cases
10
16
  */
11
17
  const eslint_1 = require("eslint");
12
18
  const valid_req_reference_1 = __importDefault(require("../../src/rules/valid-req-reference"));