eslint-plugin-traceability 1.7.0 → 1.8.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 (107) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +73 -32
  3. package/docs/ci-cd-pipeline.md +224 -0
  4. package/docs/cli-integration.md +22 -0
  5. package/docs/code-quality-refactor-opportunities-2025-12-03.md +78 -0
  6. package/docs/config-presets.md +38 -0
  7. package/docs/conventional-commits-guide.md +185 -0
  8. package/docs/custom-rules-development-guide.md +659 -0
  9. package/docs/decisions/0001-allow-dynamic-require-for-built-plugins.md +26 -0
  10. package/docs/decisions/001-typescript-for-eslint-plugin.accepted.md +111 -0
  11. package/docs/decisions/002-jest-for-eslint-testing.accepted.md +137 -0
  12. package/docs/decisions/003-code-quality-ratcheting-plan.md +48 -0
  13. package/docs/decisions/004-automated-version-bumping-for-ci-cd.md +196 -0
  14. package/docs/decisions/005-github-actions-validation-tooling.accepted.md +144 -0
  15. package/docs/decisions/006-semantic-release-for-automated-publishing.accepted.md +227 -0
  16. package/docs/decisions/007-github-releases-over-changelog.accepted.md +216 -0
  17. package/docs/decisions/008-ci-audit-flags.accepted.md +60 -0
  18. package/docs/decisions/009-security-focused-lint-rules.accepted.md +64 -0
  19. package/docs/decisions/010-implements-annotation-for-multi-story-requirements.proposed.md +184 -0
  20. package/docs/decisions/adr-0001-console-usage-for-cli-guards.md +190 -0
  21. package/docs/decisions/adr-accept-dev-dep-risk-glob.md +40 -0
  22. package/docs/decisions/adr-commit-branch-tests.md +54 -0
  23. package/docs/decisions/adr-maintenance-cli-interface.md +140 -0
  24. package/docs/decisions/adr-pre-push-parity.md +112 -0
  25. package/docs/decisions/code-quality-ratcheting-plan.md +53 -0
  26. package/docs/dependency-health.md +238 -0
  27. package/docs/eslint-9-setup-guide.md +517 -0
  28. package/docs/eslint-plugin-development-guide.md +487 -0
  29. package/docs/functionality-coverage-2025-12-03.md +250 -0
  30. package/docs/jest-testing-guide.md +100 -0
  31. package/docs/rules/prefer-implements-annotation.md +219 -0
  32. package/docs/rules/require-branch-annotation.md +71 -0
  33. package/docs/rules/require-req-annotation.md +203 -0
  34. package/docs/rules/require-story-annotation.md +159 -0
  35. package/docs/rules/valid-annotation-format.md +418 -0
  36. package/docs/rules/valid-req-reference.md +153 -0
  37. package/docs/rules/valid-story-reference.md +120 -0
  38. package/docs/security-incidents/2025-11-17-glob-cli-incident.md +45 -0
  39. package/docs/security-incidents/2025-11-18-brace-expansion-redos.md +45 -0
  40. package/docs/security-incidents/2025-11-18-bundled-dev-deps-accepted-risk.md +93 -0
  41. package/docs/security-incidents/2025-11-18-tar-race-condition.md +43 -0
  42. package/docs/security-incidents/2025-12-03-dependency-health-review.md +58 -0
  43. package/docs/security-incidents/SECURITY-INCIDENT-2025-11-18-semantic-release-bundled-npm.known-error.md +104 -0
  44. package/docs/security-incidents/SECURITY-INCIDENT-TEMPLATE.md +37 -0
  45. package/docs/security-incidents/dependency-override-rationale.md +57 -0
  46. package/docs/security-incidents/dev-deps-high.json +116 -0
  47. package/docs/security-incidents/handling-procedure.md +54 -0
  48. package/docs/stories/001.0-DEV-PLUGIN-SETUP.story.md +92 -0
  49. package/docs/stories/002.0-DEV-ESLINT-CONFIG.story.md +82 -0
  50. package/docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md +112 -0
  51. package/docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md +153 -0
  52. package/docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md +138 -0
  53. package/docs/stories/006.0-DEV-FILE-VALIDATION.story.md +144 -0
  54. package/docs/stories/007.0-DEV-ERROR-REPORTING.story.md +163 -0
  55. package/docs/stories/008.0-DEV-AUTO-FIX.story.md +150 -0
  56. package/docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md +117 -0
  57. package/docs/stories/010.0-DEV-DEEP-VALIDATION.story.md +124 -0
  58. package/docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md +149 -0
  59. package/docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md +216 -0
  60. package/docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md +236 -0
  61. package/docs/stories/developer-story.map.md +120 -0
  62. package/docs/ts-jest-presets-guide.md +548 -0
  63. package/lib/src/index.d.ts +2 -2
  64. package/lib/src/index.js +2 -0
  65. package/lib/src/maintenance/batch.d.ts +5 -0
  66. package/lib/src/maintenance/batch.js +5 -0
  67. package/lib/src/maintenance/cli.js +34 -212
  68. package/lib/src/maintenance/commands.d.ts +32 -0
  69. package/lib/src/maintenance/commands.js +139 -0
  70. package/lib/src/maintenance/detect.d.ts +2 -0
  71. package/lib/src/maintenance/detect.js +4 -0
  72. package/lib/src/maintenance/flags.d.ts +99 -0
  73. package/lib/src/maintenance/flags.js +121 -0
  74. package/lib/src/maintenance/report.d.ts +2 -0
  75. package/lib/src/maintenance/report.js +2 -0
  76. package/lib/src/maintenance/update.d.ts +4 -0
  77. package/lib/src/maintenance/update.js +4 -0
  78. package/lib/src/rules/helpers/require-story-io.d.ts +3 -0
  79. package/lib/src/rules/helpers/require-story-io.js +20 -6
  80. package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +30 -0
  81. package/lib/src/rules/helpers/valid-annotation-format-internal.js +36 -0
  82. package/lib/src/rules/helpers/valid-annotation-options.js +15 -4
  83. package/lib/src/rules/helpers/valid-annotation-utils.js +5 -0
  84. package/lib/src/rules/helpers/valid-implements-utils.d.ts +75 -0
  85. package/lib/src/rules/helpers/valid-implements-utils.js +149 -0
  86. package/lib/src/rules/helpers/valid-story-reference-helpers.d.ts +3 -4
  87. package/lib/src/rules/prefer-implements-annotation.d.ts +39 -0
  88. package/lib/src/rules/prefer-implements-annotation.js +276 -0
  89. package/lib/src/rules/valid-annotation-format.js +87 -28
  90. package/lib/src/rules/valid-req-reference.js +71 -0
  91. package/lib/src/utils/reqAnnotationDetection.d.ts +4 -1
  92. package/lib/src/utils/reqAnnotationDetection.js +43 -15
  93. package/lib/tests/maintenance/cli.test.js +89 -0
  94. package/lib/tests/plugin-default-export-and-configs.test.js +3 -0
  95. package/lib/tests/rules/prefer-implements-annotation.test.d.ts +1 -0
  96. package/lib/tests/rules/prefer-implements-annotation.test.js +84 -0
  97. package/lib/tests/rules/require-req-annotation.test.js +8 -1
  98. package/lib/tests/rules/require-story-annotation.test.js +9 -4
  99. package/lib/tests/rules/valid-annotation-format.test.js +78 -0
  100. package/lib/tests/rules/valid-req-reference.test.js +34 -0
  101. package/lib/tests/utils/ts-language-options.d.ts +1 -7
  102. package/lib/tests/utils/ts-language-options.js +8 -5
  103. package/package.json +7 -3
  104. package/user-docs/api-reference.md +507 -0
  105. package/user-docs/eslint-9-setup-guide.md +639 -0
  106. package/user-docs/examples.md +74 -0
  107. package/user-docs/migration-guide.md +158 -0
@@ -32,6 +32,15 @@ describe("Valid Req Reference Rule (Story 010.0-DEV-DEEP-VALIDATION)", () => {
32
32
  code: `// @story tests/fixtures/story_bullet.md
33
33
  // @req REQ-BULLET-LIST`,
34
34
  },
35
+ {
36
+ name: "[REQ-DEEP-IMPLEMENTS] single implements line with multiple requirements in multi-story fixture (see 010.2-DEV-MULTI-STORY-SUPPORT)",
37
+ code: `// @implements tests/fixtures/story_multi_a.md REQ-SHARED-ID REQ-ONLY-A`,
38
+ },
39
+ {
40
+ name: "[REQ-DEEP-IMPLEMENTS] multi-story implements with shared requirement IDs (see 010.2-DEV-MULTI-STORY-SUPPORT)",
41
+ code: `// @implements tests/fixtures/story_multi_a.md REQ-SHARED-ID REQ-ONLY-A
42
+ // @implements tests/fixtures/story_multi_b.md REQ-SHARED-ID REQ-ONLY-B`,
43
+ },
35
44
  ],
36
45
  invalid: [
37
46
  {
@@ -88,6 +97,31 @@ describe("Valid Req Reference Rule (Story 010.0-DEV-DEEP-VALIDATION)", () => {
88
97
  },
89
98
  ],
90
99
  },
100
+ {
101
+ name: "[REQ-DEEP-IMPLEMENTS] missing implements requirement in multi-story fixture (see 010.2-DEV-MULTI-STORY-SUPPORT)",
102
+ code: `// @implements tests/fixtures/story_multi_a.md REQ-NOT-IN-A`,
103
+ errors: [
104
+ {
105
+ messageId: "reqMissing",
106
+ data: {
107
+ reqId: "REQ-NOT-IN-A",
108
+ storyPath: "tests/fixtures/story_multi_a.md",
109
+ },
110
+ },
111
+ ],
112
+ },
113
+ {
114
+ name: "[REQ-DEEP-IMPLEMENTS] disallow path traversal in implements story path (see 010.2-DEV-MULTI-STORY-SUPPORT)",
115
+ code: `// @implements ../tests/fixtures/story_multi_a.md REQ-SHARED-ID`,
116
+ errors: [
117
+ {
118
+ messageId: "invalidPath",
119
+ data: {
120
+ storyPath: "../tests/fixtures/story_multi_a.md",
121
+ },
122
+ },
123
+ ],
124
+ },
91
125
  ],
92
126
  });
93
127
  });
@@ -3,13 +3,7 @@
3
3
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
4
  * @req REQ-TYPESCRIPT-SUPPORT - Provide reusable TypeScript parser setup for tests
5
5
  */
6
- export declare const tsRuleTesterLanguageOptions: {
7
- readonly parser: any;
8
- readonly parserOptions: {
9
- readonly ecmaVersion: 2022;
10
- readonly sourceType: "module";
11
- };
12
- };
6
+ export declare const tsRuleTesterLanguageOptions: any;
13
7
  /**
14
8
  * Attach shared TypeScript RuleTester language options to a test case definition.
15
9
  * This helper allows tests to avoid repeating the languageOptions assignment.
@@ -1,16 +1,19 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tsRuleTesterLanguageOptions = void 0;
4
- exports.withTsLanguageOptions = withTsLanguageOptions;
5
2
  /**
6
3
  * Shared TypeScript RuleTester language options for traceability tests.
7
4
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
8
5
  * @req REQ-TYPESCRIPT-SUPPORT - Provide reusable TypeScript parser setup for tests
9
6
  */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.tsRuleTesterLanguageOptions = void 0;
9
+ exports.withTsLanguageOptions = withTsLanguageOptions;
10
+ const tsEcmaVersion = 2022;
10
11
  exports.tsRuleTesterLanguageOptions = {
11
12
  parser: require("@typescript-eslint/parser"),
12
- // eslint-disable-next-line no-magic-numbers -- ECMAScript version constant
13
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
13
+ parserOptions: {
14
+ ecmaVersion: tsEcmaVersion,
15
+ sourceType: "module",
16
+ },
14
17
  };
15
18
  /**
16
19
  * Attach shared TypeScript RuleTester language options to a test case definition.
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "eslint-plugin-traceability",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
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",
7
7
  "files": [
8
8
  "lib",
9
9
  "README.md",
10
- "LICENSE"
10
+ "LICENSE",
11
+ "user-docs",
12
+ "docs",
13
+ "CHANGELOG.md"
11
14
  ],
12
15
  "directories": {
13
16
  "doc": "docs"
@@ -27,11 +30,12 @@
27
30
  "test": "jest --ci --bail",
28
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",
29
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",
30
- "ci-verify:fast": "npm run type-check && npm run check:traceability && npm run duplication && jest --ci --bail --passWithNoTests --testPathPatterns 'tests/(unit|fast)'",
33
+ "ci-verify:fast": "npm run type-check && npm run check:traceability && npm run duplication && jest --ci --bail --passWithNoTests --testPathPatterns 'tests/(rules|maintenance)'",
31
34
  "format": "prettier --write .",
32
35
  "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
33
36
  "lint-staged": "lint-staged",
34
37
  "duplication": "jscpd src tests --reporters console --threshold 3 --ignore tests/utils/**",
38
+ "deps:maturity": "dry-aged-deps",
35
39
  "audit:dev-high": "node scripts/generate-dev-deps-audit.js",
36
40
  "safety:deps": "node scripts/ci-safety-deps.js",
37
41
  "audit:ci": "node scripts/ci-audit.js",
@@ -0,0 +1,507 @@
1
+ # API Reference
2
+
3
+ Created autonomously by [voder.ai](https://voder.ai).
4
+ Applies to eslint-plugin-traceability 1.x releases. For the current published version and detailed changelog, see GitHub Releases: <https://github.com/voder-ai/eslint-plugin-traceability/releases>.
5
+
6
+ Supported runtime: Node.js >=18.18.0, ESLint ^9.0.0
7
+
8
+ Security and dependency hygiene for the published package are enforced by the same CI scripts described in the project README (including `npm audit --omit=dev --audit-level=high` and `dry-aged-deps` checks) to prevent known-vulnerable or stale runtime dependencies from being shipped; additional internal review and maintenance practices exist but are out of scope for normal usage of this plugin.
9
+
10
+ ## Rules
11
+
12
+ Each rule enforces traceability conventions in your code. Below is a summary of each rule exposed by this plugin.
13
+
14
+ In addition to the core `@story` and `@req` annotations, the plugin also understands `@implements` for code that fulfills requirements from multiple stories—for example:
15
+ `@implements docs/stories/010.0-PAYMENTS.story.md#REQ-PAYMENTS-REFUND`.
16
+ For a detailed explanation of `@implements` behavior and validation, see [`user-docs/migration-guide.md`](../user-docs/migration-guide.md) (section **3.1 Multi-story @implements annotations**) and the rule docs at [`docs/rules/valid-annotation-format.md`](../docs/rules/valid-annotation-format.md) and [`docs/rules/valid-req-reference.md`](../docs/rules/valid-req-reference.md).
17
+
18
+ ### traceability/require-story-annotation
19
+
20
+ Description: Ensures every function declaration has a JSDoc comment with an `@story` annotation referencing the related user story. 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 currently fixed but structured for future configurability, and fixes are strictly limited to adding this placeholder annotation without altering the function body or changing any runtime behavior. Selective enabling of different auto-fix behaviors (such as applying fixes only to certain scopes or node types) is planned for a future version.
21
+
22
+ Options:
23
+
24
+ - `scope` (string[], optional) – Controls which function-like node types are required to have @story annotations. Allowed values: "FunctionDeclaration", "FunctionExpression", "MethodDefinition", "TSDeclareFunction", "TSMethodSignature". Default: ["FunctionDeclaration", "FunctionExpression", "MethodDefinition", "TSDeclareFunction", "TSMethodSignature"].
25
+ - `exportPriority` ("all" | "exported" | "non-exported", optional) – Controls whether the rule checks all functions, only exported ones, or only non-exported ones. Default: "all".
26
+
27
+ Default Severity: `error`
28
+ Example:
29
+
30
+ ```javascript
31
+ /**
32
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
33
+ * @req REQ-ANNOTATION-REQUIRED
34
+ */
35
+ function initAuth() {
36
+ // authentication logic
37
+ }
38
+ ```
39
+
40
+ ### traceability/require-req-annotation
41
+
42
+ 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. Arrow functions (`ArrowFunctionExpression`) are not currently checked by this rule.
43
+
44
+ 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.
45
+
46
+ Options:
47
+
48
+ - `scope` (string[], optional) – Controls which function-like node types are required to have @req annotations. Allowed values: "FunctionDeclaration", "FunctionExpression", "MethodDefinition", "TSDeclareFunction", "TSMethodSignature". Default: ["FunctionDeclaration", "FunctionExpression", "MethodDefinition", "TSDeclareFunction", "TSMethodSignature"].
49
+ - `exportPriority` ("all" | "exported" | "non-exported", optional) – Controls whether the rule checks all functions, only exported ones, or only non-exported ones. Default: "all".
50
+
51
+ Default Severity: `error`
52
+ Example (with both `@story` and `@req`, as typically used when both rules are enabled):
53
+
54
+ ```javascript
55
+ /**
56
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
57
+ * @req REQ-ANNOTATION-REQUIRED
58
+ */
59
+ function initAuth() {
60
+ // authentication logic
61
+ }
62
+ ```
63
+
64
+ ### traceability/require-branch-annotation
65
+
66
+ Description: Ensures significant code branches (if/else, loops, switch cases, try/catch) have both `@story` and `@req` annotations in preceding comments.
67
+ Options:
68
+
69
+ - `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.
70
+
71
+ Default Severity: `error`
72
+ Example:
73
+
74
+ ```javascript
75
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
76
+ // @req REQ-BRANCH-DETECTION
77
+ if (error) {
78
+ handleError();
79
+ }
80
+ ```
81
+
82
+ ### traceability/valid-annotation-format
83
+
84
+ 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; more advanced path normalization strategies and selective toggles to enable or disable specific auto-fix behaviors are not yet implemented.
85
+
86
+ Options:
87
+
88
+ This rule accepts an optional configuration object. The primary configuration shape is **nested**:
89
+
90
+ - `story` (object, optional) – Configuration for `@story` values.
91
+ - `pattern` (string, optional) – A JavaScript regular expression **source** (without leading and trailing `/`) that all `@story` values must match. If provided, the rule validates each `@story` against this pattern in addition to its built‑in structural checks. Defaults to the value returned by `getDefaultStoryPattern()`, which is equivalent to `^docs/stories/.*\.story\.md$`, aligning with the standard `docs/stories/<name>.story.md` convention.
92
+ - `example` (string, optional) – A short example `@story` path shown in error messages when `story.pattern` is configured. Defaults to the value returned by `getDefaultStoryExample()`, `"docs/stories/001.0-EXAMPLE.story.md"`. This value is used **only** for guidance and does not affect validation.
93
+ - `req` (object, optional) – Configuration for `@req` values.
94
+ - `pattern` (string, optional) – A JavaScript regular expression **source** (without leading and trailing `/`) that all `@req` values must match. If provided, the rule validates each `@req` identifier against this pattern. Defaults to the value returned by `getDefaultReqPattern()`, which is equivalent to `^REQ-[A-Z0-9_-]+$`, matching IDs such as `REQ-USER-AUTH` or `REQ-1234`.
95
+ - `example` (string, optional) – A short example requirement ID shown in error messages when `req.pattern` is configured. Defaults to the value returned by `getDefaultReqExample()`, `"REQ-USER-AUTH"`. This is purely informational and does not participate in matching.
96
+
97
+ For backward compatibility, the rule also supports **flat shorthand** fields that map directly to the nested properties:
98
+
99
+ - `storyPathPattern` (string, optional) – Shorthand for `story.pattern`. If `story.pattern` is provided, it takes precedence over `storyPathPattern`.
100
+ - `storyPathExample` (string, optional) – Shorthand for `story.example`. If `story.example` is provided, it takes precedence over `storyPathExample`.
101
+ - `requirementIdPattern` (string, optional) – Shorthand for `req.pattern`. If `req.pattern` is provided, it takes precedence over `requirementIdPattern`.
102
+ - `requirementIdExample` (string, optional) – Shorthand for `req.example`. If `req.example` is provided, it takes precedence over `requirementIdExample`.
103
+
104
+ Behavior notes:
105
+
106
+ - Patterns are compiled with the `u` flag; invalid patterns cause a rule configuration error.
107
+ - When options are omitted, the rule behaves exactly as in earlier versions, relying on its built‑in defaults and path‑suffix normalization logic only.
108
+ - 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.
109
+
110
+ #### Migration and mixed usage
111
+
112
+ The `valid-annotation-format` rule is intentionally **backward compatible** with existing code that only uses `@story` and `@req`. You can:
113
+
114
+ - Continue using `@story` + `@req` for single-story functions and modules.
115
+ - Introduce `@implements` incrementally for integration code that implements requirements from multiple stories.
116
+ - Mix both styles in the same comment block when needed; the rule validates the format of each annotation independently.
117
+
118
+ Deep requirement checking for both `@req` and `@implements` is handled by `traceability/valid-req-reference`. For step-by-step guidance on when and how to migrate, see:
119
+
120
+ - **Migration guide:** [`user-docs/migration-guide.md`](../user-docs/migration-guide.md) (section **3.1 Multi-story `@implements` annotations**)
121
+ - **Rule docs:** [`docs/rules/valid-annotation-format.md`](../docs/rules/valid-annotation-format.md), [`docs/rules/valid-req-reference.md`](../docs/rules/valid-req-reference.md)
122
+
123
+ Default Severity: `error`
124
+ Example:
125
+
126
+ ```javascript
127
+ /**
128
+ * @story docs/stories/005.0-DEV-VALIDATION.story.md
129
+ * @req REQ-FORMAT-VALIDATION
130
+ */
131
+ function example() {
132
+ // ...
133
+ }
134
+ ```
135
+
136
+ ### traceability/valid-story-reference
137
+
138
+ Description: Checks that the file paths in `@story` annotations point to existing story markdown files.
139
+ Options:
140
+ Configure rule behavior using an options object with these properties:
141
+
142
+ - `storyDirectories` (string[], optional) – One or more directories (relative to the project root) to search for story files. Defaults to `["docs/stories", "stories"]`.
143
+ - `allowAbsolutePaths` (boolean, optional) – When `true`, allows absolute story paths (e.g., `/absolute/path/to/story.story.md`). Defaults to `false`.
144
+ - `requireStoryExtension` (boolean, optional) – When `true` (default), requires the story path to end with `.story.md`. Set to `false` to allow other extensions.
145
+
146
+ Example configuration:
147
+
148
+ ```json
149
+ {
150
+ "rules": {
151
+ "traceability/valid-story-reference": [
152
+ "error",
153
+ {
154
+ "storyDirectories": ["docs/stories", "stories"],
155
+ "allowAbsolutePaths": false,
156
+ "requireStoryExtension": true
157
+ }
158
+ ]
159
+ }
160
+ }
161
+ ```
162
+
163
+ Default Severity: `error`
164
+ Example:
165
+
166
+ ```javascript
167
+ /**
168
+ * @story docs/stories/006.0-DEV-STORY-EXISTS.story.md
169
+ * @req REQ-STORY-EXISTS
170
+ */
171
+ function example() {
172
+ // ...
173
+ }
174
+ ```
175
+
176
+ ### traceability/valid-req-reference
177
+
178
+ Description: Verifies that the IDs used in `@req` annotations match known requirement identifiers.
179
+ Options: None
180
+ Default Severity: `error`
181
+ Example:
182
+
183
+ ```javascript
184
+ /**
185
+ * @story docs/stories/007.0-DEV-REQ-REFERENCE.story.md
186
+ * @req REQ-VALID-REFERENCE
187
+ */
188
+ function example() {
189
+ // ...
190
+ }
191
+ ```
192
+
193
+ ## Configuration Presets
194
+
195
+ The plugin provides two built-in presets for easy configuration:
196
+
197
+ ### recommended
198
+
199
+ Enables the core traceability rules with severities tuned for common usage (most at `error`, with
200
+ `traceability/valid-annotation-format` at `warn` to reduce noise):
201
+ 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.
202
+
203
+ - `traceability/require-story-annotation`: `error`
204
+ - `traceability/require-req-annotation`: `error`
205
+ - `traceability/require-branch-annotation`: `error`
206
+ - `traceability/valid-annotation-format`: `warn`
207
+ - `traceability/valid-story-reference`: `error`
208
+ - `traceability/valid-req-reference`: `error`
209
+
210
+ Usage:
211
+
212
+ ```javascript
213
+ import js from "@eslint/js";
214
+ import traceability from "eslint-plugin-traceability";
215
+
216
+ export default [js.configs.recommended, traceability.configs.recommended];
217
+ ```
218
+
219
+ ### strict
220
+
221
+ Currently mirrors the **recommended** preset, reserved for future stricter policies.
222
+ Usage:
223
+
224
+ ```javascript
225
+ import js from "@eslint/js";
226
+ import traceability from "eslint-plugin-traceability";
227
+
228
+ export default [js.configs.recommended, traceability.configs.strict];
229
+ ```
230
+
231
+ ## Maintenance API and CLI
232
+
233
+ The plugin exposes a small maintenance API and a companion CLI, `traceability-maint`, for bulk operations on `@story` annotations. These tools are intentionally minimal and focused on stale **story** references only; requirement-level maintenance and more advanced filtering are planned but **not yet implemented**. All maintenance functions operate only on the local filesystem under the provided root directory; they do not make any network calls or interact with external services.
234
+
235
+ ### Programmatic Maintenance API
236
+
237
+ All functions are exported from the plugin’s maintenance module:
238
+
239
+ ```ts
240
+ import {
241
+ detectStaleAnnotations,
242
+ updateAnnotationReferences,
243
+ batchUpdateAnnotations,
244
+ verifyAnnotations,
245
+ generateMaintenanceReport,
246
+ } from "eslint-plugin-traceability/maintenance";
247
+ ```
248
+
249
+ The current maintenance API operates on a **single workspace root** and scans all files beneath that directory. It does not yet accept include/exclude globs or explicit story/requirement lists.
250
+
251
+ #### `detectStaleAnnotations(rootDir)`
252
+
253
+ Scans the workspace for `@story` annotations that point to missing or out-of-project story files.
254
+
255
+ **Parameters:**
256
+
257
+ - `rootDir` (string, required) – Workspace root to scan. This is resolved against `process.cwd()`.
258
+
259
+ **Returns:**
260
+
261
+ - `string[]` – A de-duplicated list of stale story paths exactly as they appear in `@story` annotations.
262
+
263
+ **Behavior notes:**
264
+
265
+ - The function recursively walks all files under `rootDir`.
266
+ - Story paths that would escape the workspace (e.g., path traversal or unsafe absolute paths) are ignored rather than treated as stale.
267
+ - If `rootDir` does not exist or is not a directory, an empty array is returned.
268
+
269
+ #### `updateAnnotationReferences(rootDir, oldPath, newPath)`
270
+
271
+ Performs a targeted text replacement of `@story` values across the workspace.
272
+
273
+ **Parameters:**
274
+
275
+ - `rootDir` (string, required) – Workspace root to update in-place.
276
+ - `oldPath` (string, required) – The story path to search for after `@story`.
277
+ - `newPath` (string, required) – The replacement story path.
278
+
279
+ **Returns:**
280
+
281
+ - `number` – The count of `@story` annotations that were updated.
282
+
283
+ **Behavior notes:**
284
+
285
+ - Only `@story` annotations are modified; `@req` annotations are never changed.
286
+ - Files are only written when the content actually changes.
287
+ - If `rootDir` does not exist or is not a directory, the function returns `0` without modifying anything.
288
+
289
+ #### `batchUpdateAnnotations(rootDir, mappings)`
290
+
291
+ Runs multiple `updateAnnotationReferences` operations in sequence.
292
+
293
+ **Parameters:**
294
+
295
+ - `rootDir` (string, required)
296
+ - `mappings` (array, required) – Array of objects `{ oldPath: string; newPath: string }`.
297
+
298
+ **Returns:**
299
+
300
+ - `number` – The total number of `@story` annotations updated across all mappings.
301
+
302
+ **Behavior notes:**
303
+
304
+ - There is no special batching logic; this helper simply loops over the provided mappings.
305
+ - For each mapping, it calls `updateAnnotationReferences(rootDir, oldPath, newPath)` and sums the counts.
306
+
307
+ #### `verifyAnnotations(rootDir)`
308
+
309
+ Checks whether any stale `@story` annotations exist under the workspace.
310
+
311
+ **Parameters:**
312
+
313
+ - `rootDir` (string, required)
314
+
315
+ **Returns:**
316
+
317
+ - `boolean` – `true` if **no** stale annotations are found, `false` otherwise.
318
+
319
+ **Behavior notes:**
320
+
321
+ - Internally, this function calls `detectStaleAnnotations(rootDir)` and returns `stale.length === 0`.
322
+ - Verification is currently limited to story references; requirement IDs are not re-validated here.
323
+
324
+ #### `generateMaintenanceReport(rootDir)`
325
+
326
+ Generates a simple, text-only report of stale `@story` annotations.
327
+
328
+ **Parameters:**
329
+
330
+ - `rootDir` (string, required)
331
+
332
+ **Returns:**
333
+
334
+ - `string` – A newline-separated list of stale story paths, or an empty string if none are found.
335
+
336
+ **Behavior notes:**
337
+
338
+ - This function is intentionally simple and is used by the CLI to produce human-readable output.
339
+ - It does not write to the filesystem or perform any updates.
340
+
341
+ ### `traceability-maint` CLI
342
+
343
+ The `traceability-maint` CLI wraps the maintenance API for use in scripts and CI. It is typically available via `npx traceability-maint` or as an npm script.
344
+
345
+ These tools are intentionally minimal and focused on stale **story** references only; requirement-level maintenance and more advanced filtering are planned but **not yet implemented**. The CLI currently focuses on stale `@story` annotations only. It does **not** build or consume a separate index file, and it does not yet support requirement-level maintenance.
346
+
347
+ #### General usage
348
+
349
+ ```bash
350
+ traceability-maint <command> [options]
351
+ ```
352
+
353
+ Common options:
354
+
355
+ - `--root <dir>` – Workspace root to scan (defaults to the current working directory).
356
+ - `--json` – For commands that support it, emit machine-readable JSON instead of human-readable text.
357
+ - `--format <text|json>` – Output format for the `report` command only (default: `text`).
358
+ - `--from <oldPath>` – Old story path for the `update` command.
359
+ - `--to <newPath>` – New story path for the `update` command.
360
+ - `--dry-run` – For `update`, estimate impact without modifying any files.
361
+ - `-h`, `--help` – Show command help and exit.
362
+
363
+ Exit codes:
364
+
365
+ - `0` – Success (no stale annotations for detection/verification commands, or command completed successfully).
366
+ - `1` – Stale or invalid annotations detected.
367
+ - `2` – Usage or configuration error (e.g., unknown command, missing required flags).
368
+
369
+ The CLI follows the same security posture as the rest of the plugin: it does not perform network requests, does not invoke the shell with dynamically constructed input, and limits its effects to the local filesystem under the configured root. Its runtime dependencies are covered by the same `npm audit --omit=dev --audit-level=high` and `dry-aged-deps` checks described in the project README.
370
+
371
+ #### Commands
372
+
373
+ ##### `detect`
374
+
375
+ Detects `@story` annotations that reference missing story files under the chosen workspace root.
376
+
377
+ ```bash
378
+ traceability-maint detect --root .
379
+ ```
380
+
381
+ - Output (text):
382
+ - When no stale annotations are found: prints `No stale @story annotations found.`
383
+ - When stale annotations are found: prints each stale story path on its own line, followed by a short summary.
384
+ - Output (JSON with `--json`):
385
+
386
+ ```json
387
+ {
388
+ "root": "/absolute/path/to/workspace",
389
+ "stale": ["missing.story.md", "old/renamed.story.md"]
390
+ }
391
+ ```
392
+
393
+ - Exit code:
394
+ - `0` if no stale annotations are found.
395
+ - `1` if any stale annotations are detected.
396
+
397
+ ##### `verify`
398
+
399
+ Runs a simple verification check using the same logic as `detect` and reports whether any stale `@story` annotations exist.
400
+
401
+ ```bash
402
+ traceability-maint verify --root .
403
+ ```
404
+
405
+ - Output (text):
406
+ - `All traceability annotations under <root> are valid.` when no stale annotations are found.
407
+ - A short message indicating that stale or invalid annotations were detected, with guidance to run `detect` or `report` for details.
408
+ - Exit code:
409
+ - `0` if all annotations pass verification.
410
+ - `1` if any stale annotations are found.
411
+
412
+ > Note: The `verify` command does **not** currently support `--json` output.
413
+
414
+ ##### `report`
415
+
416
+ Generates a plain-text or JSON report of stale story references.
417
+
418
+ ```bash
419
+ # Human-readable text report (default)
420
+ traceability-maint report --root .
421
+
422
+ # JSON report suitable for CI
423
+ traceability-maint report --root . --format json
424
+ ```
425
+
426
+ - Output (text, default):
427
+ - When there are no stale annotations: `No stale @story annotations found. Nothing to report.`
428
+ - When stale annotations exist, a small Markdown-style report, including a header and a list of stale story paths.
429
+ - Output (JSON with `--format json`):
430
+
431
+ ```json
432
+ {
433
+ "root": "/absolute/path/to/workspace",
434
+ "report": "missing.story.md\nold/renamed.story.md"
435
+ }
436
+ ```
437
+
438
+ - Exit code:
439
+ - Always `0` (report generation is considered successful even when stale annotations are present).
440
+
441
+ ##### `update`
442
+
443
+ Updates `@story` annotations that reference a specific path.
444
+
445
+ ```bash
446
+ # Perform an in-place update
447
+ traceability-maint update --root . --from old.path.story.md --to new.path.story.md
448
+
449
+ # Estimate impact without modifying files
450
+ traceability-maint update --root . --from old.path.story.md --to new.path.story.md --dry-run
451
+ ```
452
+
453
+ Required options:
454
+
455
+ - `--from <oldPath>` – The existing story path to replace.
456
+ - `--to <newPath>` – The new story path.
457
+
458
+ Optional options:
459
+
460
+ - `--root <dir>` – Workspace root (defaults to current directory).
461
+ - `--dry-run` – Show an estimated impact without modifying files.
462
+ - `--json` – JSON output for both normal and dry-run modes.
463
+
464
+ Behavior:
465
+
466
+ - When `--dry-run` is **not** provided, the command:
467
+ - Replaces `@story <oldPath>` with `@story <newPath>` across the workspace.
468
+ - Prints a short summary (or a JSON object with `root`, `from`, `to`, and `updated` fields when `--json` is used).
469
+ - Exits with code `0`.
470
+ - When `--dry-run` **is** provided, the command:
471
+ - Does **not** modify any files.
472
+ - Uses `generateMaintenanceReport` to estimate the number of stale annotations before changes.
473
+ - Prints a human-readable summary, or a JSON object of the form:
474
+
475
+ ```json
476
+ {
477
+ "mode": "dry-run",
478
+ "root": "/absolute/path/to/workspace",
479
+ "from": "old.path.story.md",
480
+ "to": "new.path.story.md",
481
+ "estimatedStaleCount": 3
482
+ }
483
+ ```
484
+
485
+ - Exits with code `0`.
486
+
487
+ If `--from` or `--to` is missing, the CLI prints an error, shows the help text, and exits with code `2`.
488
+
489
+ ### Minimal CLI integration example
490
+
491
+ `package.json`:
492
+
493
+ ```json
494
+ {
495
+ "scripts": {
496
+ "traceability:detect": "traceability-maint detect --root .",
497
+ "traceability:verify": "traceability-maint verify --root .",
498
+ "traceability:report": "traceability-maint report --root . --format json > traceability-report.json"
499
+ }
500
+ }
501
+ ```
502
+
503
+ In CI:
504
+
505
+ ```bash
506
+ npm run traceability:verify
507
+ ```