eslint-plugin-traceability 1.14.1 → 1.16.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 (36) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/README.md +61 -13
  3. package/lib/src/index.js +61 -0
  4. package/lib/src/rules/helpers/require-story-core.js +1 -1
  5. package/lib/src/rules/helpers/require-story-helpers.d.ts +10 -3
  6. package/lib/src/rules/helpers/require-story-helpers.js +66 -7
  7. package/lib/src/rules/no-redundant-annotation.js +73 -55
  8. package/lib/src/rules/require-branch-annotation.js +2 -2
  9. package/lib/src/rules/require-req-annotation.js +2 -2
  10. package/lib/src/rules/require-story-annotation.js +8 -3
  11. package/lib/src/rules/require-traceability.d.ts +19 -0
  12. package/lib/src/rules/require-traceability.js +72 -0
  13. package/lib/src/utils/annotation-checker.js +23 -4
  14. package/lib/tests/cli-error-handling.test.js +10 -1
  15. package/lib/tests/config/flat-config-presets-integration.test.js +2 -0
  16. package/lib/tests/integration/cli-integration.test.js +5 -0
  17. package/lib/tests/integration/require-traceability-aliases.integration.test.js +126 -0
  18. package/lib/tests/plugin-default-export-and-configs.test.js +26 -0
  19. package/lib/tests/rules/auto-fix-behavior-008.test.js +7 -7
  20. package/lib/tests/rules/error-reporting.test.js +1 -1
  21. package/lib/tests/rules/no-redundant-annotation.test.js +20 -0
  22. package/lib/tests/rules/require-story-annotation.test.js +49 -10
  23. package/lib/tests/rules/require-story-helpers.test.js +32 -0
  24. package/lib/tests/rules/require-story-utils.test.d.ts +7 -0
  25. package/lib/tests/rules/require-story-utils.test.js +158 -0
  26. package/lib/tests/utils/annotation-checker-branches.test.d.ts +5 -0
  27. package/lib/tests/utils/annotation-checker-branches.test.js +103 -0
  28. package/lib/tests/utils/annotation-scope-analyzer.test.js +134 -0
  29. package/lib/tests/utils/branch-annotation-helpers.test.js +66 -0
  30. package/package.json +2 -2
  31. package/user-docs/api-reference.md +80 -21
  32. package/user-docs/examples.md +24 -13
  33. package/user-docs/migration-guide.md +127 -4
  34. package/user-docs/traceability-overview.md +116 -0
  35. package/lib/tests/integration/dogfooding-validation.test.js +0 -129
  36. /package/lib/tests/integration/{dogfooding-validation.test.d.ts → require-traceability-aliases.integration.test.d.ts} +0 -0
@@ -11,15 +11,30 @@ Security and dependency hygiene for the published package are enforced by the sa
11
11
 
12
12
  Each rule enforces traceability conventions in your code. Below is a summary of each rule exposed by this plugin.
13
13
 
14
+ For function-level traceability, new configurations should treat `traceability/require-traceability` as the **canonical** rule: it composes both story and requirement checks and understands both the newer `@supports` style and the legacy `@story` / `@req` pairing. The older keys `traceability/require-story-annotation` and `traceability/require-req-annotation` remain available as **backward-compatible aliases** so existing configs keep working, but they are no longer the primary entry points and are mainly useful when you need to tune severities independently. For new and multi-story scenarios, prefer `@supports` annotations; `@story` and `@req` remain valid and are still appropriate for simple single-story code paths where a consolidated `@supports` tag is not yet required.
15
+
14
16
  In addition to the core `@story` and `@req` annotations, the plugin also understands `@supports` for code that fulfills requirements from multiple stories—for example, a consuming project might use a path like
15
17
  `@supports docs/stories/010.0-PAYMENTS.story.md#REQ-PAYMENTS-REFUND`
16
18
  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
19
 
18
20
  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 for maintainers; typical end users can rely on the high-level guidance in this API reference and the [Migration Guide](migration-guide.md).
19
21
 
22
+ ### Function-level rules overview
23
+
24
+ For function-level traceability, the plugin exposes a unified rule and two legacy keys:
25
+
26
+ - `traceability/require-traceability` is the **canonical function-level rule** for new configurations. It ensures functions and methods have both story coverage and requirement coverage, and it accepts either `@supports` (preferred) or legacy `@story` / `@req` annotations.
27
+ - `traceability/require-story-annotation` and `traceability/require-req-annotation` are **backward-compatible aliases** that focus on the story and requirement aspects separately. They are retained for existing configurations and share the same underlying implementation model as the unified rule, but new ESLint configs should normally rely on `traceability/require-traceability` rather than enabling these legacy keys directly.
28
+
29
+ All three rule keys can still be configured individually if you need fine-grained control (for example, to tune severities separately), but the recommended and strict presets enable `traceability/require-traceability` by default and keep the legacy keys primarily for projects that adopted them before the unified rule existed.
30
+
31
+ ### traceability/require-traceability
32
+
33
+ Description: Unified function-level traceability rule that composes the behavior of `traceability/require-story-annotation` and `traceability/require-req-annotation`. When enabled, it enforces that in‑scope functions and methods carry both a story reference (`@story` or an equivalent `@supports` tag) and at least one requirement reference (`@req` or, when configured, `@supports`). The recommended flat‑config presets in this plugin enable `traceability/require-traceability` by default alongside the legacy rule keys for backward compatibility, so that existing configurations referring to `traceability/require-story-annotation` or `traceability/require-req-annotation` continue to work without change.
34
+
20
35
  ### traceability/require-story-annotation
21
36
 
22
- Description: Ensures every function declaration has a JSDoc comment with an `@story` annotation referencing the related user story. When you adopt multi-story `@supports` annotations, this rule also accepts `@supports` as an alternative way to prove story coverage, so either `@story` or at least one `@supports` tag will satisfy the presence check. When run with `--fix`, the rule inserts a single-line placeholder JSDoc `@story` annotation above missing functions, methods, TypeScript declare functions, and interface method signatures using a built-in template aligned with Story 008.0. This template is now configurable on a per-rule basis, and the rule exposes an explicit auto-fix toggle so you can choose between diagnostic-only behavior and automatic placeholder insertion. The default template remains aligned with Story 008.0, but you can now customize it per rule configuration and optionally disable auto-fix entirely when you only want diagnostics without edits.
37
+ Description: **Legacy function-level key:** This rule key is retained for backward compatibility and conceptually composes the same checks as `traceability/require-traceability`. New configurations should normally enable `traceability/require-traceability` instead and rely on this key only when you need to tune it independently. Ensures every function declaration has a traceability annotation, preferring `@supports` for story coverage while still accepting legacy `@story` annotations referencing the related user story. When you adopt multi-story `@supports` annotations, this rule also accepts `@supports` as an alternative way to prove story coverage, so either `@story` or at least one `@supports` tag will satisfy the presence check. When run with `--fix`, the rule inserts a single-line placeholder JSDoc `@story` annotation above missing functions, methods, TypeScript declare functions, and interface method signatures using a built-in template aligned with Story 008.0. This template is now configurable on a per-rule basis, and the rule exposes an explicit auto-fix toggle so you can choose between diagnostic-only behavior and automatic placeholder insertion. The default template remains aligned with Story 008.0, but you can now customize it per rule configuration and optionally disable auto-fix entirely when you only want diagnostics without edits.
23
38
 
24
39
  Options:
25
40
 
@@ -28,6 +43,7 @@ Options:
28
43
  - `annotationTemplate` (string, optional) – Overrides the default placeholder JSDoc used when inserting missing `@story` annotations for functions and non-method constructs. When omitted or blank, the built-in template from Story 008.0 is used.
29
44
  - `methodAnnotationTemplate` (string, optional) – Overrides the default placeholder JSDoc used when inserting missing `@story` annotations for class methods and TypeScript method signatures. When omitted or blank, falls back to `annotationTemplate` if provided, otherwise the built-in template.
30
45
  - `autoFix` (boolean, optional) – When set to `false`, disables all automatic fix behavior for this rule while retaining its suggestions and diagnostics. When omitted or `true`, the rule behaves as before, inserting placeholder annotations in `--fix` mode.
46
+ - `excludeTestCallbacks` (boolean, optional) – When `true` (default), excludes anonymous arrow functions that are direct callbacks to common test framework functions (for example, Jest/Mocha/Vitest `describe`/`it`/`test`/`beforeEach`/`afterEach`/`beforeAll`/`afterAll`, plus focused/skipped/concurrent variants such as `fdescribe`, `xdescribe`, `fit`, `xit`, `test.concurrent`, `describe.concurrent`) from function-level annotation requirements. This assumes those test files are already covered by file-level `@supports` annotations and `traceability/require-test-traceability`. When set to `false`, these callbacks are treated like any other arrow function and must be annotated when in-scope.
31
47
 
32
48
  Default Severity: `error`
33
49
  Example:
@@ -42,9 +58,11 @@ function initAuth() {
42
58
  }
43
59
  ```
44
60
 
61
+ Among the supported scopes, anonymous callbacks passed directly to common test framework functions are excluded from annotation requirements by default via `excludeTestCallbacks`; projects that prefer stricter enforcement for these callbacks can disable this exclusion by setting `excludeTestCallbacks: false` in their rule configuration.
62
+
45
63
  ### traceability/require-req-annotation
46
64
 
47
- Description: Ensures that function-like constructs consistently declare their linked requirement using an `@req` annotation in JSDoc. The rule targets the same function-like node types as `traceability/require-story-annotation` (standard function declarations, non-arrow function expressions used as callbacks or assignments, class/object methods, TypeScript declare functions, and interface method signatures), and enforces that each of them has at least one `@req` tag in the nearest associated JSDoc comment. When you adopt multi-story `@supports` annotations, this rule also treats `@supports story-path REQ-ID...` tags as satisfying the requirement coverage check, although deep verification of requirement IDs continues to be handled by `traceability/valid-req-reference`. Arrow functions (`ArrowFunctionExpression`) are not currently checked by this rule.
65
+ Description: **Legacy function-level key:** This rule key is retained for backward compatibility and conceptually composes the same checks as `traceability/require-traceability`. New configurations should normally enable `traceability/require-traceability` instead and rely on this key only when you need to tune it independently. Ensures that function-like constructs consistently declare their linked requirements via traceability annotations, preferring `@supports` when possible while still accepting `@req`. The rule targets the same function-like node types as `traceability/require-story-annotation` (standard function declarations, non-arrow function expressions used as callbacks or assignments, class/object methods, TypeScript declare functions, and interface method signatures), and enforces that each of them has at least one `@req` tag in the nearest associated JSDoc comment. When you adopt multi-story `@supports` annotations, this rule also treats `@supports story-path REQ-ID...` tags as satisfying the requirement coverage check, although deep verification of requirement IDs continues to be handled by `traceability/valid-req-reference`. Arrow functions (`ArrowFunctionExpression`) are not currently checked by this rule.
48
66
 
49
67
  This rule is typically used alongside `traceability/require-story-annotation` so that each function-level traceability block includes both an `@story` and an `@req` annotation, but it can also be enabled independently if you only want to enforce requirement linkage. Unlike `traceability/require-story-annotation`, this rule does not currently provide an auto-fix mode for inserting placeholder `@req` annotations; it only reports missing or malformed requirement annotations on the configured scopes.
50
68
 
@@ -68,7 +86,7 @@ function initAuth() {
68
86
 
69
87
  ### traceability/require-branch-annotation
70
88
 
71
- Description: Ensures significant code branches (if/else chains, loops, switch cases, try/catch) have both `@story` and `@req` annotations in nearby comments. When you adopt multi-story `@supports` annotations, a single `@supports <storyPath> <REQ-ID>...` line placed in any of the valid branch comment locations is treated as satisfying both the story and requirement presence checks for that branch, while detailed format validation of the `@supports` value (including story paths and requirement IDs) continues to be handled by `traceability/valid-annotation-format`, `traceability/valid-story-reference`, and `traceability/valid-req-reference`.
89
+ Description: Ensures significant code branches (if/else chains, loops, switch cases, try/catch) have traceability coverage, typically via a single `@supports` line, while still accepting legacy `@story` and `@req` annotations in nearby comments. When you adopt multi-story `@supports` annotations, a single `@supports <storyPath> <REQ-ID>...` line placed in any of the valid branch comment locations is treated as satisfying both the story and requirement presence checks for that branch, while detailed format validation of the `@supports` value (including story paths and requirement IDs) continues to be handled by `traceability/valid-annotation-format`, `traceability/valid-story-reference`, and `traceability/valid-req-reference`.
72
90
 
73
91
  For most branches, the rule looks for annotations in comments immediately preceding the branch keyword (for example, the line above an `if` or `for` statement). For `catch` clauses and `else if` branches, the rule is formatter-aware and accepts annotations in additional positions that common formatters like Prettier use when they reflow code.
74
92
 
@@ -108,7 +126,7 @@ if (error) {
108
126
 
109
127
  ### traceability/valid-annotation-format
110
128
 
111
- Description: Validates that all traceability annotations (`@story`, `@req`) follow the correct JSDoc or inline comment format. When run with `--fix`, the rule limits changes to safe `@story` path suffix normalization only—for example, adding `.md` when the path ends with `.story`, or adding `.story.md` when the base path has no extension—using targeted replacements implemented in the `getFixedStoryPath` and `reportInvalidStoryFormatWithFix` helpers. It does not change directories, infer new story names, or modify any surrounding comment text or whitespace, in line with Story 008.0. Selective disabling of this suffix-normalization auto-fix behavior is available via the `autoFix` option, which defaults to `true` for backward compatibility.
129
+ Description: Validates that all traceability annotations (`@supports` as the preferred form for new code, plus legacy `@story` and `@req`) follow the correct JSDoc or inline comment format. When run with `--fix`, the rule limits changes to safe `@story` path suffix normalization only—for example, adding `.md` when the path ends with `.story`, or adding `.story.md` when the base path has no extension—using targeted replacements implemented in the `getFixedStoryPath` and `reportInvalidStoryFormatWithFix` helpers. It does not change directories, infer new story names, or modify any surrounding comment text or whitespace, in line with Story 008.0. Selective disabling of this suffix-normalization auto-fix behavior is available via the `autoFix` option, which defaults to `true` for backward compatibility.
112
130
 
113
131
  Options:
114
132
 
@@ -135,8 +153,6 @@ Behavior notes:
135
153
  - When options are omitted, the rule behaves exactly as in earlier versions, relying on its built‑in defaults and path‑suffix normalization logic only.
136
154
  - The pattern checks are additional validation; they do not change the existing auto‑fix behavior, which remains limited to safe `@story` suffix normalization described above.
137
155
 
138
- You can customize these validations to match your own naming conventions by overriding `story.pattern`/`storyPathPattern` and `req.pattern`/`requirementIdPattern`. This is useful when you store stories outside `docs/stories`, avoid `DEV` in filenames, or use a different requirement ID scheme instead of the default `REQ-...` format. Any custom values must still be valid JavaScript regular expression **sources** (without surrounding `/` characters).
139
-
140
156
  #### Migration and mixed usage
141
157
 
142
158
  The `valid-annotation-format` rule is intentionally **backward compatible** with existing code that only uses `@story` and `@req`. You can:
@@ -148,21 +164,34 @@ The `valid-annotation-format` rule is intentionally **backward compatible** with
148
164
  Deep requirement checking for both `@req` and `@supports` is handled by the `valid-req-reference` rule in the plugin's internal docs. Advanced edge cases and internal semantics are mainly of interest to maintainers; typical end users can rely on the options and examples in this API reference when configuring the rule for their projects.
149
165
 
150
166
  Default Severity: `error`
151
- Example:
167
+
168
+ Primary example (recommended `@supports` style):
169
+
170
+ ```javascript
171
+ /**
172
+ * @supports docs/stories/005.0-DEV-VALIDATION.story.md#REQ-FORMAT-VALIDATION
173
+ */
174
+ function example() {
175
+ // ...
176
+ }
177
+ ```
178
+
179
+ Legacy example (`@story` + `@req`, still valid but not preferred for new code):
152
180
 
153
181
  ```javascript
154
182
  /**
155
183
  * @story docs/stories/005.0-DEV-VALIDATION.story.md
156
184
  * @req REQ-FORMAT-VALIDATION
157
185
  */
158
- function example() {
186
+ function legacyExample() {
159
187
  // ...
160
188
  }
161
189
  ```
162
190
 
163
191
  ### traceability/valid-story-reference
164
192
 
165
- Description: Checks that the file paths in `@story` annotations point to existing story markdown files.
193
+ Description: Checks that the story file paths used by traceability annotations point to existing story markdown files in an `@supports`‑first world. Modern code typically encodes story paths in `@supports` tags (for example, `@supports docs/stories/010.0-PAYMENTS.story.md#REQ-ID`), but this rule continues to operate on the underlying `@story` values for file‑existence checks, keeping legacy annotations and mixed blocks fully supported.
194
+
166
195
  Options:
167
196
  Configure rule behavior using an options object with these properties:
168
197
 
@@ -188,31 +217,57 @@ Example configuration:
188
217
  ```
189
218
 
190
219
  Default Severity: `error`
191
- Example:
220
+
221
+ Primary example (recommended `@supports` style, with a companion `@story` used for existence checks):
222
+
223
+ ```javascript
224
+ /**
225
+ * @supports docs/stories/006.0-DEV-STORY-EXISTS.story.md#REQ-STORY-EXISTS
226
+ * @story docs/stories/006.0-DEV-STORY-EXISTS.story.md // used for file-existence validation; kept for backward compatibility
227
+ */
228
+ function example() {
229
+ // ...
230
+ }
231
+ ```
232
+
233
+ Legacy-only example (`@story` + `@req`, still supported as an input to this rule):
192
234
 
193
235
  ```javascript
194
236
  /**
195
237
  * @story docs/stories/006.0-DEV-STORY-EXISTS.story.md
196
238
  * @req REQ-STORY-EXISTS
197
239
  */
198
- function example() {
240
+ function legacyExample() {
199
241
  // ...
200
242
  }
201
243
  ```
202
244
 
203
245
  ### traceability/valid-req-reference
204
246
 
205
- Description: Verifies that the IDs used in `@req` annotations match known requirement identifiers.
247
+ Description: Verifies that the requirement IDs used in traceability annotations match known requirement identifiers, whether they appear in modern `@supports` tags or in legacy `@req` annotations.
248
+
206
249
  Options: None
207
250
  Default Severity: `error`
208
- Example:
251
+
252
+ Primary example (recommended `@supports` style with requirement IDs):
253
+
254
+ ```javascript
255
+ /**
256
+ * @supports docs/stories/007.0-DEV-REQ-REFERENCE.story.md#REQ-VALID-REFERENCE REQ-VALID-REFERENCE-EDGE
257
+ */
258
+ function example() {
259
+ // ...
260
+ }
261
+ ```
262
+
263
+ Legacy example (`@story` + `@req`, still valid for backward compatibility):
209
264
 
210
265
  ```javascript
211
266
  /**
212
267
  * @story docs/stories/007.0-DEV-REQ-REFERENCE.story.md
213
268
  * @req REQ-VALID-REFERENCE
214
269
  */
215
- function example() {
270
+ function legacyExample() {
216
271
  // ...
217
272
  }
218
273
  ```
@@ -294,19 +349,21 @@ Behavior notes:
294
349
 
295
350
  Default Severity: `warn`
296
351
 
297
- This rule is **not** enabled in the `recommended` or `strict` presets by default. To use it, add it explicitly to your ESLint configuration with an appropriate severity level:
352
+ This rule is enabled at severity `warn` in both the `recommended` and `strict` presets. You can override its behavior in your own configuration — for example, by raising it to `error` for stricter enforcement, or by explicitly disabling it if you prefer to keep statement-level duplication.
353
+
354
+ Configuration example (override preset severity from `warn` to `error`):
298
355
 
299
356
  ```jsonc
300
357
  {
301
358
  "rules": {
302
- "traceability/no-redundant-annotation": "warn",
359
+ "traceability/no-redundant-annotation": "error",
303
360
  },
304
361
  }
305
362
  ```
306
363
 
307
364
  ### traceability/prefer-supports-annotation
308
365
 
309
- 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 builtin 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.
366
+ 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.
310
367
 
311
368
  Options: None – this rule does not accept a configuration object. All tuning is done via the ESLint rule level (`"off"`, `"warn"`, `"error"`).
312
369
 
@@ -325,7 +382,7 @@ Main behaviors:
325
382
 
326
383
  ```js
327
384
  /**
328
- * @supports docs/stories/010.0-PAYMENTS.story.md#REQ-PAYMENTS-REFUND REQ-PAYMENTS-EDGE
385
+ * @supports docs/stories/010.0-PAYMENTS.story.md#REQ-PAYMENTS-REFUND REQ-PAYMENTS-REFUND-EDGE
329
386
  */
330
387
  ```
331
388
 
@@ -349,7 +406,7 @@ Main behaviors:
349
406
  Deliberate non‑targets and ignored comments:
350
407
 
351
408
  - JSDoc blocks that contain **only** `@story`, **only** `@req`, or **only** `@supports` are **not** modified by this rule. They remain valid and continue to be governed solely by the core rules such as `require-story-annotation`, `require-req-annotation`, and `valid-annotation-format`.
352
- - Inline or line comments like `// @story ...`, `// @req ...`, or `// @supports ...` are also supported in a limited, migration‑oriented way: when the rule detects a simple, consecutive pair or small run of `// @story ...` and `// @req ...` lines that are directly attached to a function or branch, it can, in `--fix` mode, consolidate them into a single `// @supports ...` line while preserving indentation and the comment’s relative position next to the code. More complex inline patterns (such as mixed traceability and nontraceability content, multiple distinct stories, or interleaved unrelated comments) are still reported without auto‑fix for safety. As with JSDoc migration, this behavior is opt‑in: the rule remains disabled by default and must be explicitly enabled with your desired severity when you are ready to start migrating inline annotations.
409
+ - Inline or line comments like `// @story ...`, `// @req ...`, or `// @supports ...` are also supported in a limited, migration‑oriented way: when the rule detects a simple, consecutive pair or small run of `// @story ...` and `// @req ...` lines that are directly attached to a function or branch, it can, in `--fix` mode, consolidate them into a single `// @supports ...` line while preserving indentation and the comment’s relative position next to the code. More complex inline patterns (such as mixed traceability and non-traceability content, multiple distinct stories, or interleaved unrelated comments) are still reported without auto‑fix for safety. As with JSDoc migration, this behavior is opt‑in: the rule remains disabled by default and must be explicitly enabled with your desired severity when you are ready to start migrating inline annotations.
353
410
  - Any block that does not match the “single story + simple requirements, no supports” shape is treated conservatively: the rule may report a diagnostic to flag the legacy/mixed pattern, but it will not rewrite comments unless it is clearly safe.
354
411
 
355
412
  Interaction with other rules:
@@ -422,13 +479,15 @@ The `prefer-supports-annotation` migration rule (and its deprecated alias key `t
422
479
 
423
480
  Core rules enabled by the `recommended` preset:
424
481
 
425
- - `traceability/require-story-annotation`: `error`
426
- - `traceability/require-req-annotation`: `error`
482
+ - `traceability/require-traceability`: `error` (unified function-level rule; composes story + req checks)
483
+ - `traceability/require-story-annotation`: `error` (legacy key; kept for backward compatibility)
484
+ - `traceability/require-req-annotation`: `error` (legacy key; kept for backward compatibility)
427
485
  - `traceability/require-branch-annotation`: `error`
428
486
  - `traceability/valid-annotation-format`: `warn`
429
487
  - `traceability/valid-story-reference`: `error`
430
488
  - `traceability/valid-req-reference`: `error`
431
489
  - `traceability/require-test-traceability`: `error`
490
+ - `traceability/no-redundant-annotation`: `warn`
432
491
 
433
492
  Usage:
434
493
 
@@ -43,7 +43,21 @@ npx eslint "src/**/*.js"
43
43
 
44
44
  ## 3. CLI Invocation Example
45
45
 
46
- You can use the plugin without a config file by specifying rules inline:
46
+ You can use the plugin without a config file by specifying rules inline. The recommended approach for new setups is to use the unified `traceability/require-traceability` rule:
47
+
48
+ ```bash
49
+ npx eslint --no-eslintrc \
50
+ --rule "traceability/require-traceability:error" \
51
+ sample.js
52
+ ```
53
+
54
+ This unified function-level rule enforces both story and requirement coverage via `@supports` (preferred) or, for backward compatibility, via legacy `@story`/`@req` annotations.
55
+
56
+ Replace `sample.js` with your JavaScript or TypeScript file.
57
+
58
+ ### 3.1 Legacy aliases (for existing configurations)
59
+
60
+ If you have older configurations that already refer to the legacy keys `traceability/require-story-annotation` and `traceability/require-req-annotation`, you can still enable them explicitly to avoid breaking those setups:
47
61
 
48
62
  ```bash
49
63
  npx eslint --no-eslintrc \
@@ -53,9 +67,7 @@ npx eslint --no-eslintrc \
53
67
  ```
54
68
 
55
69
  - `--no-eslintrc` tells ESLint to ignore user configs.
56
- - `--rule` options enable the traceability rules you need.
57
-
58
- Replace `sample.js` with your JavaScript or TypeScript file.
70
+ - `--rule` options enable either the unified rule (recommended for new configurations) or the legacy aliases when you must preserve older setups.
59
71
 
60
72
  ## 4. Linting a Specific Directory
61
73
 
@@ -103,6 +115,9 @@ describe("Story 021.0-DEV-TEST-TRACEABILITY", () => {
103
115
  // Act
104
116
  const result = performOperation(input);
105
117
 
118
+ // Assert
119
+ const result = performOperation(input);
120
+
106
121
  // Assert
107
122
  expect(result).toBe("edge-ok");
108
123
  });
@@ -125,13 +140,11 @@ In this version, annotations are placed immediately before each significant bran
125
140
 
126
141
  ```ts
127
142
  function pickCategory(score: number): string {
128
- // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
129
- // @req REQ-BRANCH-DETECTION
143
+ // @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-BRANCH-DETECTION
130
144
  if (score >= 80) {
131
145
  return "high";
132
146
  }
133
- // @story docs/stories/026.0-DEV-ELSE-IF-ANNOTATION-POSITION.story.md
134
- // @req REQ-DUAL-POSITION-DETECTION-ELSE-IF
147
+ // @supports docs/stories/026.0-DEV-ELSE-IF-ANNOTATION-POSITION.story.md REQ-DUAL-POSITION-DETECTION-ELSE-IF
135
148
  else if (score >= 50) {
136
149
  return "medium";
137
150
  }
@@ -156,13 +169,11 @@ Prettier may reflow your `else if` line, wrap the condition, or move comments in
156
169
 
157
170
  ```ts
158
171
  function pickCategory(score: number): string {
159
- // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
160
- // @req REQ-BRANCH-DETECTION
172
+ // @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-BRANCH-DETECTION
161
173
  if (score >= 80) {
162
174
  return "high";
163
175
  } else if (score >= 50) {
164
- // @story docs/stories/026.0-DEV-ELSE-IF-ANNOTATION-POSITION.story.md
165
- // @req REQ-DUAL-POSITION-DETECTION-ELSE-IF
176
+ // @supports docs/stories/026.0-DEV-ELSE-IF-ANNOTATION-POSITION.story.md REQ-DUAL-POSITION-DETECTION-ELSE-IF
166
177
  return "medium";
167
178
  } else {
168
179
  return "low";
@@ -173,6 +184,6 @@ function pickCategory(score: number): string {
173
184
  Depending on your Prettier version and configuration, the exact layout of the `else if` line and braces may differ, but as long as your annotations are in one of the supported locations, the rule will accept them.
174
185
 
175
186
  - Notes:
176
- - For most branch types, `traceability/require-branch-annotation` associates comments immediately before the branch keyword (such as `if`, `else`, `switch`, `case`) with that branch.
187
+ - For most branch types, `traceability/require-branch-annotation` associates comments immediately before the branch keyword (such as `if`, `else`, `switch`, `case`) with that branch. Branches can be annotated either with a single `@supports` line (preferred), or with the older `@story`/`@req` pair for backward compatibility. The rule treats a valid `@supports` annotation as satisfying both the story and requirement presence checks.
177
188
  - For `catch` clauses and `else if` branches, the rule is formatter-aware and also looks at comments between the condition and the block, as well as the first comment-only lines inside the block body, so you do not need to fight Prettier if it moves your annotations.
178
189
  - When annotations exist in more than one place around an `else if` branch, the rule prefers comments immediately before the `else if` line, then comments between the condition and the block, and finally comments inside the block body, matching the behavior described in the API reference and stories `025.0` and `026.0`.
@@ -46,7 +46,7 @@ The following diff shows a typical migration in **your own project**, where `doc
46
46
 
47
47
  ### 3.1 Multi-story `@supports` annotations
48
48
 
49
- Starting in v1.x, `eslint-plugin-traceability` supports an additional annotation form for integration code that implements requirements from multiple stories in a consuming project. The following snippet shows one example of how you might structure such an annotation in **your** codebase:
49
+ Starting in v1.x, `eslint-plugin-traceability` introduces and prefers the `@supports` annotation for integration code that implements requirements from multiple stories in a consuming project. The following snippet shows one example of how you might structure such an annotation in **your** codebase:
50
50
 
51
51
  ```js
52
52
  /**
@@ -102,10 +102,20 @@ Aligned with the internal rule behavior, the key cases are:
102
102
  The following are **ignored** by this rule and remain valid:
103
103
  - Comments that contain only `@story` lines,
104
104
  - Comments that contain only `@req` lines,
105
- - Comments that contain only `@supports` lines, and
106
- - Line comments such as `// @story ...`.
105
+ - Comments that contain only `@supports` lines.
107
106
 
108
- These forms are still supported by the plugin and are not modified by `traceability/prefer-supports-annotation`.
107
+ Line comments are treated more selectively:
108
+ - Simple, consecutive line comments such as:
109
+
110
+ ```js
111
+ // @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
112
+ // @req REQ-ANNOTATION-REQUIRED
113
+ function initAuth() {}
114
+ ```
115
+
116
+ that are directly attached to a function, method, or branch and describe exactly one story path plus one or more requirement IDs can now be migrated automatically. When the rule is enabled and you run ESLint with `--fix`, these are consolidated into a single `// @supports ...` line that preserves the same story path and requirement IDs.
117
+
118
+ - More complex inline patterns — for example, mixed traceability and non-traceability content, multiple distinct `@story` paths, or interleaved unrelated comments between `@story` and `@req` lines — are still reported but are **not** auto-fixed. In these cases, the rule continues to treat unsupported inline shapes conservatively, emitting diagnostics and leaving the comments unchanged so you can adjust them manually.
109
119
 
110
120
  A typical migration path is:
111
121
 
@@ -133,6 +143,8 @@ export function initAuth() {
133
143
  }
134
144
  ```
135
145
 
146
+ These `@story` and `@req` forms are treated as a legacy single-story style that remains valid for simple cases, while new multi-story integrations should prefer `@supports` as the primary format.
147
+
136
148
  #### When to introduce `@supports`
137
149
 
138
150
  Adopt `@supports` for **multi-story integration** code, especially when:
@@ -183,6 +195,7 @@ You can introduce `@supports` gradually without breaking existing code:
183
195
 
184
196
  1. Leave existing `@story` and `@req` annotations in place.
185
197
  2. Add `@supports` lines that group requirements by story file.
198
+ Over time, teams are encouraged to converge on `@supports` as the canonical format for multi-story integrations, keeping `@story`/`@req` primarily for simple, single-story cases.
186
199
  3. Run ESLint with `traceability/valid-annotation-format` and `traceability/valid-req-reference` enabled to confirm everything passes.
187
200
  4. Optionally, once you are comfortable, standardize on using `@supports` for multi-story integration functions while keeping `@story` + `@req` for simple, single-story code.
188
201
 
@@ -197,6 +210,116 @@ Versions 1.x of `eslint-plugin-traceability` extend the `traceability/require-br
197
210
 
198
211
  If you previously added suppressions or workaround comments around `else if` branches due to formatter conflicts, you can usually remove those workarounds after upgrading to 1.x as long as your annotations live in one of the supported locations. For new code, you can place annotations either directly above the `else if` or, when you know a formatter will wrap a long condition, on the first comment-only line inside the consequent block body, which is where the rule places auto-fix placeholders by default.
199
212
 
213
+ ### 3.3 Redundant traceability annotation cleanup
214
+
215
+ As you move toward an **`@supports`-first** style while still supporting legacy `@story`/`@req`, v1.x adds `traceability/no-redundant-annotation` to help clean up redundant **statement-level** annotations that often accumulate during migration and refactoring.
216
+
217
+ This rule is enabled as `"warn"` in the built-in recommended presets, so you automatically get guidance without breaking existing builds.
218
+
219
+ At a high level, the rule targets common duplication patterns where multiple adjacent statements or branches repeat the **same story/requirement coverage**, for example:
220
+
221
+ - **Branch + statement duplication** — the `if`/`else` branch is annotated, and the first statement inside the block repeats the exact same coverage.
222
+ - **Sequential simple statements** — back‑to‑back statements each carry identical traceability, even though they form a single logical step.
223
+ - **Trivial returns** — a branch and an immediately returning statement both repeat the same story/requirement pair.
224
+
225
+ In all cases, the rule is conservative:
226
+
227
+ - It **never removes the last annotation** that provides coverage for a given `(story path, requirement ID)` pair.
228
+ - It prefers to keep annotations in the positions that are easiest to reason about (for example, on the controlling branch or on the first statement in a short sequence), and trims only clearly redundant copies.
229
+
230
+ The rule operates over both `@supports` and legacy `@story`/`@req` style annotations, so it continues to work even in mixed codebases during a long-running migration.
231
+
232
+ A simplified example, using an illustrative story path that represents a file in **your** documentation tree:
233
+
234
+ Before (redundant duplication inside a branch):
235
+
236
+ ```js
237
+ if (!user) {
238
+ // @supports docs/stories/010.0-AUTH-SESSION-MANAGEMENT.story.md REQ-UNAUTH-REDIRECT
239
+ // @supports docs/stories/010.0-AUTH-SESSION-MANAGEMENT.story.md REQ-UNAUTH-REDIRECT
240
+ return redirectToLogin();
241
+ }
242
+ ```
243
+
244
+ After (`no-redundant-annotation` auto-fix, coverage preserved but duplication removed):
245
+
246
+ ```js
247
+ if (!user) {
248
+ // @supports docs/stories/010.0-AUTH-SESSION-MANAGEMENT.story.md REQ-UNAUTH-REDIRECT
249
+ return redirectToLogin();
250
+ }
251
+ ```
252
+
253
+ Another example where the branch and first statement are both annotated with the same coverage:
254
+
255
+ Before:
256
+
257
+ ```js
258
+ // @supports docs/stories/020.0-ORDERS-CHECKOUT.story.md REQ-CALCULATE-TOTAL
259
+ if (cart.items.length === 0) {
260
+ // @supports docs/stories/020.0-ORDERS-CHECKOUT.story.md REQ-CALCULATE-TOTAL
261
+ return 0;
262
+ }
263
+ ```
264
+
265
+ After (keep coverage at the branch, drop the redundant inner statement annotation):
266
+
267
+ ```js
268
+ // @supports docs/stories/020.0-ORDERS-CHECKOUT.story.md REQ-CALCULATE-TOTAL
269
+ if (cart.items.length === 0) {
270
+ return 0;
271
+ }
272
+ ```
273
+
274
+ #### Safe migration workflow
275
+
276
+ To use `traceability/no-redundant-annotation` safely during your v1.x migration:
277
+
278
+ 1. **Start from the recommended preset**
279
+
280
+ Make sure your ESLint flat config includes the plugin’s recommended config (which enables this rule as `"warn"`):
281
+
282
+ ```js
283
+ import traceability from "eslint-plugin-traceability";
284
+
285
+ export default [traceability.configs.recommended];
286
+ ```
287
+
288
+ 2. **Run ESLint without auto-fix**
289
+
290
+ Run ESLint without `--fix` to review the warnings:
291
+
292
+ ```bash
293
+ npm run lint
294
+ ```
295
+
296
+ Look for diagnostics from `traceability/no-redundant-annotation` and confirm that the suggested removals match your expectations.
297
+
298
+ 3. **Run with `--fix` once comfortable**
299
+
300
+ When you are satisfied with the behavior, re-run ESLint with auto-fix enabled to apply safe cleanups in bulk:
301
+
302
+ ```bash
303
+ npm run lint -- --fix
304
+ ```
305
+
306
+ 4. **Optionally tighten over time**
307
+
308
+ As your team gets comfortable:
309
+ - You can raise the rule severity to `"error"` for new code, and/or
310
+ - Increase strictness via configuration (see below) to catch more subtle forms of duplication.
311
+
312
+ #### Key configuration knobs
313
+
314
+ The full API reference documents all options, but the most important knobs for migration are:
315
+
316
+ - **`strictness`** — controls how aggressively the rule interprets “redundant.” Lower settings only remove obvious duplication; higher levels consider more complex patterns across nearby statements and branches.
317
+ - **`allowEmphasisDuplication`** — when `true`, allows an explicit “emphasis” annotation to repeat coverage (for example, keeping a second comment in a particularly critical spot) without being reported as redundant.
318
+ - **`maxScopeDepth`** — limits how far into nested blocks the rule looks when deciding what is redundant, which can be useful if you want very local cleanups only.
319
+ - **`alwaysCovered`** — a safety valve that forces the rule to preserve at least one annotation for each `(story, requirement)` pair within the relevant scope, even under stricter modes.
320
+
321
+ For most teams, the defaults in the recommended preset are a good starting point; you can then tune these options incrementally as your traceability style and `@supports` usage stabilize.
322
+
200
323
  ## 4. Test and Validate
201
324
 
202
325
  Run your test suite to confirm everything passes:
@@ -0,0 +1,116 @@
1
+ # Traceability Overview and FAQ
2
+
3
+ Created autonomously by [voder.ai](https://voder.ai).
4
+
5
+ This page gives a high-level overview of how to use `eslint-plugin-traceability` in day-to-day development and answers common questions about annotations, rules, and their relationship to legacy aliases.
6
+
7
+ For detailed rule and option descriptions, see the [API Reference](api-reference.md). For concrete code samples, see the [Examples](examples.md) document.
8
+
9
+ ## Which annotations should I use?
10
+
11
+ The plugin understands three annotation forms:
12
+
13
+ - `@supports` – **Preferred for new code and multi-story integrations.**
14
+ Use this when a function, module, or branch implements requirements from one or more stories. A single `@supports` tag can express both the story path and the requirement IDs it implements.
15
+ - `@story` – Legacy story-level tag.
16
+ Still valid and useful when a function is tied to a single story file and you have not yet migrated to `@supports`.
17
+ - `@req` – Legacy requirement-level tag.
18
+ Pairs naturally with `@story` for simple, single-story scenarios.
19
+
20
+ Recommended usage:
21
+
22
+ - For **new or refactored code**, prefer `@supports` as your primary annotation.
23
+ - For **simple, single-story functions** that already use `@story` + `@req`, you can keep that style; there is no forced cut-over.
24
+ - During migration, you can temporarily have both `@story`/`@req` and `@supports` in the same block; the core rules and the optional `traceability/prefer-supports-annotation` rule are designed to support this.
25
+
26
+ The [Migration Guide](migration-guide.md) explains when and how to introduce `@supports` in more detail, including conservative auto-fix behavior.
27
+
28
+ ## Which ESLint rule should I enable for functions?
29
+
30
+ For function-level checks, think in terms of a single canonical rule plus a small set of supporting rules.
31
+
32
+ - `traceability/require-traceability` – **Canonical function-level rule for new configurations.**
33
+ Ensures that in-scope functions and methods have both story and requirement coverage. It understands both `@supports` (preferred) and legacy `@story` / `@req` annotations.
34
+
35
+ Most users can choose one of these options:
36
+
37
+ 1. **Use the recommended preset** (simplest):
38
+
39
+ ```js
40
+ // eslint.config.js
41
+ import js from "@eslint/js";
42
+ import traceability from "eslint-plugin-traceability";
43
+
44
+ export default [js.configs.recommended, traceability.configs.recommended];
45
+ ```
46
+
47
+ This enables `traceability/require-traceability` and the other core rules with sensible defaults.
48
+
49
+ 2. **Manually enable the unified rule and common helpers** (when you need custom tuning):
50
+
51
+ ```js
52
+ // eslint.config.js
53
+ import traceability from "eslint-plugin-traceability";
54
+
55
+ export default [
56
+ {
57
+ plugins: { traceability },
58
+ rules: {
59
+ // Canonical function-level rule
60
+ "traceability/require-traceability": "error",
61
+
62
+ // Common supporting rules
63
+ "traceability/require-branch-annotation": "warn",
64
+ "traceability/valid-annotation-format": "error",
65
+ "traceability/valid-story-reference": "error",
66
+ "traceability/valid-req-reference": "error",
67
+
68
+ // Optional: enforce test traceability conventions
69
+ "traceability/require-test-traceability": "warn",
70
+ },
71
+ },
72
+ ];
73
+ ```
74
+
75
+ The same guidance is summarized in the README under **"Canonical function-level rule and legacy aliases"**.
76
+
77
+ ## What about the legacy alias rules?
78
+
79
+ Two additional rule keys exist for backward compatibility:
80
+
81
+ - `traceability/require-story-annotation`
82
+ - `traceability/require-req-annotation`
83
+
84
+ Key points:
85
+
86
+ - They are **legacy aliases** that share the same underlying engine as `traceability/require-traceability`.
87
+ - They are kept so that older configurations continue to work without change.
88
+ - New configurations should **not** rely on these keys directly unless you have a specific reason to tune their severities independently.
89
+
90
+ If you are starting from scratch, you can safely ignore the legacy keys and use only `traceability/require-traceability` together with the supporting rules listed above.
91
+
92
+ ## Do I have to migrate existing `@story` / `@req` annotations to `@supports`?
93
+
94
+ No. Existing `@story` + `@req` annotations remain valid and fully supported.
95
+
96
+ Typical migration path:
97
+
98
+ 1. Keep your current `@story` + `@req` annotations for simple, single-story functions.
99
+ 2. Introduce `@supports` gradually for integration code that naturally spans multiple stories.
100
+ 3. Optionally enable `traceability/prefer-supports-annotation` at `"warn"` to get gentle guidance and conservative auto-fixes for straightforward single-story blocks.
101
+ 4. Once you are comfortable, you can tighten enforcement or standardize on `@supports` for new multi-story work.
102
+
103
+ See the [Migration Guide](migration-guide.md#31-multi-story-supports-annotations) for concrete before/after examples.
104
+
105
+ ## Where can I see concrete examples?
106
+
107
+ - **Quick start and minimal config:** See the main [README](../README.md#quick-start).
108
+ - **Full rule list and options:** See the [API Reference](api-reference.md#rules).
109
+ - **End-to-end examples:** See the [Examples](examples.md) document, including:
110
+ - Flat-config snippets using the recommended and strict presets.
111
+ - CLI usage with the unified rule and clearly labeled legacy-alias examples.
112
+ - Test traceability examples using `traceability/require-test-traceability`.
113
+ - Branch annotation patterns that work well with formatters such as Prettier.
114
+ - **Migration guidance:** See the [Migration Guide](migration-guide.md).
115
+
116
+ These resources are designed to be complementary: start with this overview to choose the right annotations and rules, then refer to the API reference and examples when you need exact configuration shapes or runnable code samples.