eslint-plugin-traceability 1.11.1 → 1.11.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +3 -3
  3. package/lib/src/index.d.ts +10 -5
  4. package/lib/src/index.js +71 -6
  5. package/lib/src/maintenance/commands.js +2 -3
  6. package/lib/src/maintenance/update.js +1 -14
  7. package/lib/src/rules/helpers/require-story-core.d.ts +12 -4
  8. package/lib/src/rules/helpers/require-story-core.js +59 -30
  9. package/lib/src/rules/helpers/require-story-helpers.d.ts +7 -41
  10. package/lib/src/rules/helpers/require-story-helpers.js +13 -70
  11. package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +12 -13
  12. package/lib/src/rules/helpers/valid-annotation-format-internal.js +21 -16
  13. package/lib/src/rules/helpers/valid-annotation-format-validators.d.ts +29 -3
  14. package/lib/src/rules/helpers/valid-annotation-format-validators.js +29 -3
  15. package/lib/src/rules/helpers/valid-annotation-utils.d.ts +3 -3
  16. package/lib/src/rules/helpers/valid-annotation-utils.js +10 -10
  17. package/lib/src/rules/helpers/valid-req-reference-helpers.d.ts +11 -0
  18. package/lib/src/rules/helpers/valid-req-reference-helpers.js +362 -0
  19. package/lib/src/rules/prefer-implements-annotation.js +7 -7
  20. package/lib/src/rules/require-story-annotation.d.ts +2 -0
  21. package/lib/src/rules/require-story-annotation.js +1 -1
  22. package/lib/src/rules/valid-req-reference.d.ts +4 -0
  23. package/lib/src/rules/valid-req-reference.js +5 -349
  24. package/lib/src/rules/valid-story-reference.d.ts +1 -1
  25. package/lib/src/rules/valid-story-reference.js +17 -10
  26. package/lib/src/utils/branch-annotation-helpers.d.ts +2 -2
  27. package/lib/src/utils/branch-annotation-helpers.js +96 -17
  28. package/lib/tests/cli-error-handling.test.js +1 -1
  29. package/lib/tests/config/eslint-config-validation.test.js +73 -0
  30. package/lib/tests/fixtures/stale/example.js +1 -1
  31. package/lib/tests/fixtures/update/example.js +1 -1
  32. package/lib/tests/integration/catch-annotation-prettier.integration.test.d.ts +1 -0
  33. package/lib/tests/integration/catch-annotation-prettier.integration.test.js +131 -0
  34. package/lib/tests/integration/dogfooding-validation.test.d.ts +1 -0
  35. package/lib/tests/integration/dogfooding-validation.test.js +94 -0
  36. package/lib/tests/maintenance/cli.test.js +37 -0
  37. package/lib/tests/maintenance/detect-isolated.test.js +5 -5
  38. package/lib/tests/perf/maintenance-cli-large-workspace.test.js +18 -0
  39. package/lib/tests/perf/require-branch-annotation-large-file.test.d.ts +1 -0
  40. package/lib/tests/perf/require-branch-annotation-large-file.test.js +67 -0
  41. package/lib/tests/perf/valid-annotation-format-large-file.test.d.ts +1 -0
  42. package/lib/tests/perf/valid-annotation-format-large-file.test.js +74 -0
  43. package/lib/tests/plugin-default-export-and-configs.test.js +1 -0
  44. package/lib/tests/plugin-setup.test.js +12 -1
  45. package/lib/tests/rules/prefer-implements-annotation.test.js +84 -70
  46. package/lib/tests/rules/require-branch-annotation.test.js +33 -1
  47. package/lib/tests/rules/valid-annotation-format-internal.test.d.ts +8 -0
  48. package/lib/tests/rules/valid-annotation-format-internal.test.js +47 -0
  49. package/lib/tests/utils/branch-annotation-catch-insert-position.test.d.ts +1 -0
  50. package/lib/tests/utils/branch-annotation-catch-insert-position.test.js +68 -0
  51. package/lib/tests/utils/branch-annotation-catch-position.test.d.ts +1 -0
  52. package/lib/tests/utils/branch-annotation-catch-position.test.js +115 -0
  53. package/lib/tests/utils/req-annotation-detection.test.d.ts +1 -0
  54. package/lib/tests/utils/req-annotation-detection.test.js +247 -0
  55. package/package.json +4 -4
  56. package/user-docs/api-reference.md +20 -12
  57. package/user-docs/examples.md +2 -1
  58. package/user-docs/migration-guide.md +11 -7
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const reqAnnotationDetection_1 = require("../../src/utils/reqAnnotationDetection");
4
+ // Small helper to construct a minimal SourceCode-like object for the detection helpers.
5
+ function createMockSourceCode(options = {}) {
6
+ const { lines = null, text = "", commentsBefore = [] } = options;
7
+ return {
8
+ lines: lines ?? undefined,
9
+ getText() {
10
+ return text;
11
+ },
12
+ getCommentsBefore() {
13
+ return commentsBefore;
14
+ },
15
+ };
16
+ }
17
+ describe("reqAnnotationDetection advanced heuristics (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", () => {
18
+ it("[REQ-ANNOTATION-REQ-DETECTION] returns false when sourceCode is missing", () => {
19
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], undefined, {
20
+ loc: null,
21
+ });
22
+ expect(has).toBe(false);
23
+ });
24
+ it("[REQ-ANNOTATION-REQ-DETECTION] returns false when node is missing", () => {
25
+ const context = {
26
+ getSourceCode() {
27
+ return createMockSourceCode({ lines: ["/** @req REQ-TEST */"] });
28
+ },
29
+ };
30
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, undefined);
31
+ expect(has).toBe(false);
32
+ });
33
+ it("[REQ-ANNOTATION-REQ-DETECTION] inspects jsdoc and comments when advanced heuristics throw", () => {
34
+ const context = {
35
+ getSourceCode() {
36
+ // This object intentionally causes hasReqInAdvancedHeuristics to throw by
37
+ // providing a getCommentsBefore implementation that throws on access.
38
+ return {
39
+ getCommentsBefore() {
40
+ throw new Error("boom");
41
+ },
42
+ };
43
+ },
44
+ };
45
+ const jsdoc = { value: "/** @req REQ-FROM-JSDOC */" };
46
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(jsdoc, [], context, {
47
+ // Minimal shape – the helper will call into the mock sourceCode and trigger the throw
48
+ parent: {},
49
+ });
50
+ expect(has).toBe(true);
51
+ });
52
+ it("[REQ-ANNOTATION-REQ-DETECTION] treats @supports in comments as satisfying requirement", () => {
53
+ const context = {
54
+ getSourceCode() {
55
+ return createMockSourceCode();
56
+ },
57
+ };
58
+ const comments = [{ value: "// @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-X" }];
59
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, comments, context, {
60
+ parent: {},
61
+ });
62
+ expect(has).toBe(true);
63
+ });
64
+ it("[REQ-ANNOTATION-REQ-DETECTION] linesBeforeHasReq returns false when lines is not an array", () => {
65
+ const context = {
66
+ getSourceCode() {
67
+ // lines is null here, causing the helper to see a non-array and return false
68
+ return createMockSourceCode({ lines: null });
69
+ },
70
+ };
71
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, {
72
+ // Provide a minimal location so advanced heuristics try to use line info
73
+ loc: { start: { line: 5 } },
74
+ parent: {},
75
+ });
76
+ expect(has).toBe(false);
77
+ });
78
+ it("[REQ-ANNOTATION-REQ-DETECTION] linesBeforeHasReq returns false when startLine is not a number", () => {
79
+ const sourceCode = createMockSourceCode({ lines: ["// @req REQ-SHOULD-NOT-BE-SEEN"] });
80
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], { getSourceCode: () => sourceCode }, {
81
+ // loc is missing/undefined; startLine will not be a valid number
82
+ loc: undefined,
83
+ parent: {},
84
+ });
85
+ expect(has).toBe(false);
86
+ });
87
+ it("[REQ-ANNOTATION-REQ-DETECTION] parentChainHasReq returns false when getCommentsBefore is not a function and no leadingComments/parents have req", () => {
88
+ const context = {
89
+ getSourceCode() {
90
+ return {
91
+ // getCommentsBefore is not a function here
92
+ getCommentsBefore: 123,
93
+ };
94
+ },
95
+ };
96
+ const node = {
97
+ parent: {
98
+ leadingComments: [{ value: "no req here" }],
99
+ parent: {
100
+ leadingComments: [{ value: "still nothing" }],
101
+ },
102
+ },
103
+ };
104
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, node);
105
+ expect(has).toBe(false);
106
+ });
107
+ it("[REQ-ANNOTATION-REQ-DETECTION] parentChainHasReq returns true when getCommentsBefore returns comments containing @req", () => {
108
+ const sourceCode = {
109
+ getCommentsBefore(n) {
110
+ if (n && n.isTargetParent) {
111
+ return [{ value: "/* @req REQ-FROM-PARENT */" }];
112
+ }
113
+ return [];
114
+ },
115
+ };
116
+ const context = {
117
+ getSourceCode() {
118
+ return sourceCode;
119
+ },
120
+ };
121
+ const node = {
122
+ parent: {
123
+ isTargetParent: true,
124
+ parent: {},
125
+ },
126
+ };
127
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, node);
128
+ expect(has).toBe(true);
129
+ });
130
+ it("[REQ-ANNOTATION-REQ-DETECTION] fallbackTextBeforeHasReq returns false when getText is not a function", () => {
131
+ const context = {
132
+ getSourceCode() {
133
+ return {
134
+ // getText is not a function
135
+ getText: "not-a-function",
136
+ };
137
+ },
138
+ };
139
+ const node = {
140
+ range: [0, 10],
141
+ parent: {},
142
+ };
143
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, node);
144
+ expect(has).toBe(false);
145
+ });
146
+ it("[REQ-ANNOTATION-REQ-DETECTION] fallbackTextBeforeHasReq returns false when node.range is not an array", () => {
147
+ const context = {
148
+ getSourceCode() {
149
+ return createMockSourceCode({ text: "/* @req REQ-IN-TEXT */" });
150
+ },
151
+ };
152
+ const node = {
153
+ // range is missing; helper should see non-array range and return false
154
+ range: null,
155
+ parent: {},
156
+ };
157
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, node);
158
+ expect(has).toBe(false);
159
+ });
160
+ it("[REQ-ANNOTATION-REQ-DETECTION] fallbackTextBeforeHasReq returns true when text window contains @req", () => {
161
+ const fullText = `
162
+ // some header
163
+ /** @req REQ-IN-TEXT-WINDOW */
164
+ function foo() {}
165
+ `;
166
+ const context = {
167
+ getSourceCode() {
168
+ return createMockSourceCode({ text: fullText });
169
+ },
170
+ };
171
+ // Choose a range that starts after the @req comment so the "text before"
172
+ // window that the helper inspects includes the annotation.
173
+ const startIndex = fullText.indexOf("function foo");
174
+ const node = {
175
+ range: [startIndex, startIndex + 5],
176
+ parent: {},
177
+ };
178
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, node);
179
+ expect(has).toBe(true);
180
+ });
181
+ it("[REQ-ANNOTATION-REQ-DETECTION] fallbackTextBeforeHasReq returns false when getText throws", () => {
182
+ const context = {
183
+ getSourceCode() {
184
+ return {
185
+ getText() {
186
+ throw new Error("boom from getText");
187
+ },
188
+ };
189
+ },
190
+ };
191
+ const node = {
192
+ range: [0, 10],
193
+ parent: {},
194
+ };
195
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, node);
196
+ expect(has).toBe(false);
197
+ });
198
+ it("[REQ-ANNOTATION-REQ-DETECTION] hasReqInAdvancedHeuristics short-circuits and returns false when sourceCode is missing", () => {
199
+ const context = {
200
+ // No getSourceCode method at all – internal advanced heuristics
201
+ // should immediately return false and not throw.
202
+ };
203
+ const node = {
204
+ loc: { start: { line: 3 } },
205
+ range: [0, 10],
206
+ parent: {},
207
+ };
208
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, node);
209
+ expect(has).toBe(false);
210
+ });
211
+ it("[REQ-ANNOTATION-REQ-DETECTION] hasReqInAdvancedHeuristics short-circuits and returns false when node is missing", () => {
212
+ const context = {
213
+ getSourceCode() {
214
+ return createMockSourceCode({ text: "@req REQ-SHOULD-NOT-BE-SEEN" });
215
+ },
216
+ };
217
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(null, [], context, undefined);
218
+ expect(has).toBe(false);
219
+ });
220
+ it("[REQ-ANNOTATION-REQ-DETECTION] hasReqAnnotation returns true when jsdoc contains @supports and advanced heuristics are false", () => {
221
+ const context = {
222
+ getSourceCode() {
223
+ // Returning a sourceCode that will not satisfy any advanced heuristic
224
+ // (no lines, no comments, empty text).
225
+ return createMockSourceCode({ lines: [], text: "" });
226
+ },
227
+ };
228
+ const jsdoc = {
229
+ value: "/** @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-JSDOC-SUPPORTS */",
230
+ };
231
+ const node = {
232
+ parent: {},
233
+ };
234
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(jsdoc, [], context, node);
235
+ expect(has).toBe(true);
236
+ });
237
+ it("[REQ-ANNOTATION-REQ-DETECTION] falls back to jsdoc/comments when context.getSourceCode throws", () => {
238
+ const context = {
239
+ getSourceCode() {
240
+ throw new Error("boom from getSourceCode");
241
+ },
242
+ };
243
+ const jsdoc = { value: "/** @req REQ-FROM-GETSOURCECODE */" };
244
+ const has = (0, reqAnnotationDetection_1.hasReqAnnotation)(jsdoc, [], context, { parent: {} });
245
+ expect(has).toBe(true);
246
+ });
247
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-traceability",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
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",
@@ -29,7 +29,7 @@
29
29
  "lint": "eslint --config eslint.config.js \"src/**/*.{js,ts}\" \"tests/**/*.{js,ts}\" --max-warnings=0",
30
30
  "test": "jest --ci --bail",
31
31
  "ci-verify": "npm run type-check && npm run lint && npm run format:check && npm run duplication && npm run check:traceability && npm test && npm run audit:ci && npm run safety:deps",
32
- "ci-verify:full": "npm run check:traceability && npm run safety:deps && npm run audit:ci && npm run build && npm run type-check && npm run lint-plugin-check && npm run lint -- --max-warnings=0 && npm run duplication && npm run test -- --coverage && npm run format:check && npm audit --omit=dev --audit-level=high && npm run audit:dev-high",
32
+ "ci-verify:full": "npm run check:traceability && npm run safety:deps && npm run audit:ci && npm run build && npm run type-check && npm run lint-plugin-check && npm run lint -- --max-warnings=0 && npm run duplication && npm run test -- --coverage && npm run format:check && npm audit --omit=dev --audit-level=high && npm run audit:dev-high && npm run check:ci-artifacts",
33
33
  "ci-verify:fast": "npm run type-check && npm run check:traceability && npm run duplication && jest --ci --bail --passWithNoTests --testPathPatterns 'tests/(rules|maintenance)'",
34
34
  "format": "prettier --write .",
35
35
  "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
@@ -41,7 +41,7 @@
41
41
  "safety:deps": "node scripts/ci-safety-deps.js",
42
42
  "audit:ci": "node scripts/ci-audit.js",
43
43
  "check:ci-artifacts": "node scripts/check-no-tracked-ci-artifacts.js",
44
- "security:secrets": "secretlint \"**/*\" --no-color",
44
+ "security:secrets": "secretlint \"**/*\"",
45
45
  "smoke-test": "./scripts/smoke-test.sh",
46
46
  "debug:cli": "node scripts/cli-debug.js",
47
47
  "debug:require-story": "node scripts/debug-require-story.js",
@@ -99,7 +99,7 @@
99
99
  "eslint": "^9.0.0"
100
100
  },
101
101
  "engines": {
102
- "node": ">=18.18.0"
102
+ "node": "^18.18.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
103
103
  },
104
104
  "overrides": {
105
105
  "glob": "12.0.0",
@@ -15,7 +15,7 @@ In addition to the core `@story` and `@req` annotations, the plugin also underst
15
15
  `@supports docs/stories/010.0-PAYMENTS.story.md#REQ-PAYMENTS-REFUND`
16
16
  to indicate that a given function supports a particular requirement from a payments story document within that project’s own `docs/stories` tree. For a detailed explanation of `@supports` behavior and validation, see [Migration Guide](migration-guide.md) (section **3.1 Multi-story @supports annotations**). Additional background on multi-story semantics is available in the project’s internal rule documentation, which is intended for maintainers rather than end users.
17
17
 
18
- The `prefer-implements-annotation` rule is an **opt-in migration helper** that is disabled by default and **not** part of any built-in preset. It can be enabled and given a severity like `"warn"` or `"error"` using normal ESLint rule configuration when you want to gradually encourage multi-story `@supports` usage. Detailed behavior and migration guidance are documented in the project’s internal rule documentation, which is targeted at maintainers; typical end users can rely on the high-level guidance in this API reference and the [Migration Guide](migration-guide.md).
18
+ The `prefer-supports-annotation` rule is an **opt-in migration helper** that is disabled by default and **not** part of any built-in preset. It can be enabled and given a severity like `"warn"` or `"error"` using normal ESLint rule configuration when you want to gradually encourage multi-story `@supports` usage. The legacy rule key `traceability/prefer-implements-annotation` remains available as a **deprecated alias** for backward compatibility, but new configurations should prefer `traceability/prefer-supports-annotation`. Detailed behavior and migration guidance are documented in the project’s internal rule documentation, which is targeted at maintainers; typical end users can rely on the high-level guidance in this API reference and the [Migration Guide](migration-guide.md).
19
19
 
20
20
  ### traceability/require-story-annotation
21
21
 
@@ -68,11 +68,17 @@ function initAuth() {
68
68
 
69
69
  ### traceability/require-branch-annotation
70
70
 
71
- Description: Ensures significant code branches (if/else, loops, switch cases, try/catch) have both `@story` and `@req` annotations in preceding comments.
71
+ Description: Ensures significant code branches (if/else, loops, switch cases, try/catch) have both `@story` and `@req` annotations in preceding comments. For `catch` clauses specifically, the rule accepts annotations either immediately before the `catch` keyword or as the first comment-only lines inside the catch block. This dual-position handling is designed to stay compatible with common formatters such as Prettier, which often move comments from before `catch` into the catch body.
72
+
72
73
  Options:
73
74
 
74
75
  - `branchTypes` (string[], optional) – AST node types that are treated as significant branches for annotation enforcement. Allowed values: "IfStatement", "SwitchCase", "TryStatement", "CatchClause", "ForStatement", "ForOfStatement", "ForInStatement", "WhileStatement", "DoWhileStatement". Default: ["IfStatement", "SwitchCase", "TryStatement", "CatchClause", "ForStatement", "ForOfStatement", "ForInStatement", "WhileStatement", "DoWhileStatement"]. If an invalid branch type is provided, the rule reports a configuration error for each invalid value.
75
76
 
77
+ Behavior notes:
78
+
79
+ - When both before-`catch` and inside-block annotations are present for the same catch clause, the comments immediately before `catch` take precedence for validation and reporting.
80
+ - When auto-fixing missing annotations on a catch clause, the rule inserts placeholder comments inside the catch body so that formatters like Prettier preserve them and do not move them to unexpected locations.
81
+
76
82
  Default Severity: `error`
77
83
  Example:
78
84
 
@@ -246,9 +252,9 @@ describe("Refunds flow docs/stories/010.0-PAYMENTS.story.md", () => {
246
252
  });
247
253
  ```
248
254
 
249
- ### traceability/prefer-implements-annotation
255
+ ### traceability/prefer-supports-annotation
250
256
 
251
- Description: An optional, opt-in migration helper that encourages converting legacy single‑story `@story` + `@req` JSDoc blocks into the newer multi‑story `@supports` format. The rule is **disabled by default** and is **not included in any built‑in preset**; you enable it explicitly and control its behavior entirely via ESLint severity (`"off" | "warn" | "error"`). It does not change what the core rules consider valid—it only adds migration recommendations and safe auto‑fixes on top of existing validation.
257
+ Description: An optional, opt-in migration helper that encourages converting legacy single‑story `@story` + `@req` JSDoc blocks into the newer multi‑story `@supports` format. The rule is **disabled by default** and is **not included in any built‑in preset**; you enable it explicitly and control its behavior entirely via ESLint severity (`"off" | "warn" | "error"`). It does not change what the core rules consider valid—it only adds migration recommendations and safe auto‑fixes on top of existing validation. The legacy rule key `traceability/prefer-implements-annotation` is still recognized as a **deprecated alias** for `traceability/prefer-supports-annotation` so that existing configurations continue to work unchanged.
252
258
 
253
259
  Options: None – this rule does not accept a configuration object. All tuning is done via the ESLint rule level (`"off"`, `"warn"`, `"error"`).
254
260
 
@@ -272,7 +278,6 @@ Main behaviors:
272
278
  ```
273
279
 
274
280
  Conceptually, the auto‑fix:
275
-
276
281
  - Extracts the single `@story` value.
277
282
  - Collects the requirement IDs from each `@req` line in that block.
278
283
  - Emits a single `@supports story-path#REQ-1 REQ-2 ...` line (or your project’s equivalent anchor scheme).
@@ -319,7 +324,7 @@ function issueRefund() {
319
324
  }
320
325
  ```
321
326
 
322
- With `traceability/prefer-implements-annotation` enabled and ESLint run with `--fix`, the rule rewrites it to:
327
+ With `traceability/prefer-supports-annotation` enabled (or its deprecated alias `traceability/prefer-implements-annotation`) and ESLint run with `--fix`, the rule rewrites it to:
323
328
 
324
329
  ```js
325
330
  /**
@@ -344,9 +349,11 @@ export default [
344
349
  traceability.configs.recommended,
345
350
  {
346
351
  rules: {
347
- "traceability/prefer-implements-annotation": "warn"
348
- }
349
- }
352
+ "traceability/prefer-supports-annotation": "warn",
353
+ // The deprecated alias is still honored if you prefer:
354
+ // "traceability/prefer-implements-annotation": "warn",
355
+ },
356
+ },
350
357
  ];
351
358
  ```
352
359
 
@@ -359,7 +366,7 @@ The plugin provides two built-in presets for easy configuration:
359
366
  Enables the **six core traceability rules** with severities tuned for common usage (most at `error`, with
360
367
  `traceability/valid-annotation-format` at `warn` to reduce noise). This `warn` level for `traceability/valid-annotation-format` is intentional to keep early adoption noise low, but you can safely raise it to `error` in projects that want strict enforcement of annotation formatting.
361
368
 
362
- The `prefer-implements-annotation` migration rule is **not included** in this (or any) preset and remains disabled by default. If you want to encourage or enforce multi-story `@supports` annotations, you must enable `traceability/prefer-implements-annotation` explicitly in your ESLint configuration and choose an appropriate severity (for example, `"warn"` during migration or `"error"` once fully adopted).
369
+ The `prefer-supports-annotation` migration rule (and its deprecated alias key `traceability/prefer-implements-annotation`) is **not included** in this (or any) preset and remains disabled by default. If you want to encourage or enforce multi-story `@supports` annotations, you must enable `traceability/prefer-supports-annotation` explicitly in your ESLint configuration and choose an appropriate severity (for example, `"warn"` during migration or `"error"` once fully adopted).
363
370
 
364
371
  Core rules enabled by the `recommended` preset:
365
372
 
@@ -382,7 +389,7 @@ export default [js.configs.recommended, traceability.configs.recommended];
382
389
 
383
390
  ### strict
384
391
 
385
- Currently mirrors the **recommended** preset, reserved for future stricter policies. As with the `recommended` preset, the `traceability/prefer-implements-annotation` rule is **not** enabled here by default and must be configured manually if desired.
392
+ Currently mirrors the **recommended** preset, reserved for future stricter policies. As with the `recommended` preset, the `traceability/prefer-supports-annotation` rule is **not** enabled here by default, and the deprecated alias key `traceability/prefer-implements-annotation` continues to be honored only when you opt into it manually in your own configuration.
386
393
 
387
394
  Usage:
388
395
 
@@ -682,4 +689,5 @@ If `--from` or `--to` is missing, the CLI prints an error, shows the help text,
682
689
  In CI:
683
690
 
684
691
  ```bash
685
- npm run traceability:verify
692
+ npm run traceability:verify
693
+ ```
@@ -112,4 +112,5 @@ describe("Story 021.0-DEV-TEST-TRACEABILITY", () => {
112
112
  function performOperation(input: string): string {
113
113
  if (input === "edge-case") return "edge-ok";
114
114
  return "ok";
115
- }
115
+ }
116
+ ```
@@ -57,18 +57,22 @@ function integrate() {}
57
57
 
58
58
  You **do not** need to change existing, single-story annotations that already use `@story` and `@req`. Migration to `@supports` is only recommended when a function or module genuinely implements requirements from more than one story file.
59
59
 
60
- #### Optional `prefer-implements-annotation` migration rule
60
+ #### Optional `prefer-supports-annotation` migration rule
61
61
 
62
- For teams that want to gradually migrate from `@story` + `@req` to `@supports`, the plugin provides an optional rule: `traceability/prefer-implements-annotation`.
62
+ For teams that want to gradually migrate from `@story` + `@req` to `@supports`, the plugin provides an optional rule: `traceability/prefer-supports-annotation`.
63
63
 
64
- - This rule is **disabled by default** and is **not** included in any built-in presets.
64
+ - This is the canonical rule name starting in v1.x.
65
+ - The legacy key `traceability/prefer-implements-annotation` remains supported as a **deprecated alias** for backward compatibility, but should not be used in new configurations.
66
+
67
+ - This rule is **disabled by default** and is **not** included in any built-in presets (the deprecated alias is also not enabled by any presets).
65
68
  - You can enable it with any standard ESLint severity (`"off"`, `"warn"`, or `"error"`) in your config, for example:
66
69
 
67
70
  ```js
68
71
  // excerpt from eslint.config.js
69
72
  {
70
73
  rules: {
71
- "traceability/prefer-implements-annotation": "warn",
74
+ "traceability/prefer-supports-annotation": "warn",
75
+ // "traceability/prefer-implements-annotation": "warn", // deprecated alias
72
76
  },
73
77
  }
74
78
  ```
@@ -100,8 +104,8 @@ Aligned with the internal rule behavior, the key cases are:
100
104
  - Comments that contain only `@req` lines,
101
105
  - Comments that contain only `@supports` lines, and
102
106
  - Line comments such as `// @story ...`.
103
-
104
- These forms are still supported by the plugin and are not modified by `traceability/prefer-implements-annotation`.
107
+
108
+ These forms are still supported by the plugin and are not modified by `traceability/prefer-supports-annotation`.
105
109
 
106
110
  A typical migration path is:
107
111
 
@@ -204,4 +208,4 @@ Production dependency guarantees are enforced by CI scripts that run `npm audit
204
208
 
205
209
  ---
206
210
 
207
- If you encounter any issues during migration, please file an issue at https://github.com/voder-ai/eslint-plugin-traceability/issues.
211
+ If you encounter any issues during migration, please file an issue at https://github.com/voder-ai/eslint-plugin-traceability/issues.