eslint-plugin-traceability 1.7.1 → 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.
- package/CHANGELOG.md +82 -0
- package/README.md +72 -32
- package/docs/ci-cd-pipeline.md +224 -0
- package/docs/cli-integration.md +22 -0
- package/docs/code-quality-refactor-opportunities-2025-12-03.md +78 -0
- package/docs/config-presets.md +38 -0
- package/docs/conventional-commits-guide.md +185 -0
- package/docs/custom-rules-development-guide.md +659 -0
- package/docs/decisions/0001-allow-dynamic-require-for-built-plugins.md +26 -0
- package/docs/decisions/001-typescript-for-eslint-plugin.accepted.md +111 -0
- package/docs/decisions/002-jest-for-eslint-testing.accepted.md +137 -0
- package/docs/decisions/003-code-quality-ratcheting-plan.md +48 -0
- package/docs/decisions/004-automated-version-bumping-for-ci-cd.md +196 -0
- package/docs/decisions/005-github-actions-validation-tooling.accepted.md +144 -0
- package/docs/decisions/006-semantic-release-for-automated-publishing.accepted.md +227 -0
- package/docs/decisions/007-github-releases-over-changelog.accepted.md +216 -0
- package/docs/decisions/008-ci-audit-flags.accepted.md +60 -0
- package/docs/decisions/009-security-focused-lint-rules.accepted.md +64 -0
- package/docs/decisions/010-implements-annotation-for-multi-story-requirements.proposed.md +184 -0
- package/docs/decisions/adr-0001-console-usage-for-cli-guards.md +190 -0
- package/docs/decisions/adr-accept-dev-dep-risk-glob.md +40 -0
- package/docs/decisions/adr-commit-branch-tests.md +54 -0
- package/docs/decisions/adr-maintenance-cli-interface.md +140 -0
- package/docs/decisions/adr-pre-push-parity.md +112 -0
- package/docs/decisions/code-quality-ratcheting-plan.md +53 -0
- package/docs/dependency-health.md +238 -0
- package/docs/eslint-9-setup-guide.md +517 -0
- package/docs/eslint-plugin-development-guide.md +487 -0
- package/docs/functionality-coverage-2025-12-03.md +250 -0
- package/docs/jest-testing-guide.md +100 -0
- package/docs/rules/prefer-implements-annotation.md +219 -0
- package/docs/rules/require-branch-annotation.md +71 -0
- package/docs/rules/require-req-annotation.md +203 -0
- package/docs/rules/require-story-annotation.md +159 -0
- package/docs/rules/valid-annotation-format.md +418 -0
- package/docs/rules/valid-req-reference.md +153 -0
- package/docs/rules/valid-story-reference.md +120 -0
- package/docs/security-incidents/2025-11-17-glob-cli-incident.md +45 -0
- package/docs/security-incidents/2025-11-18-brace-expansion-redos.md +45 -0
- package/docs/security-incidents/2025-11-18-bundled-dev-deps-accepted-risk.md +93 -0
- package/docs/security-incidents/2025-11-18-tar-race-condition.md +43 -0
- package/docs/security-incidents/2025-12-03-dependency-health-review.md +58 -0
- package/docs/security-incidents/SECURITY-INCIDENT-2025-11-18-semantic-release-bundled-npm.known-error.md +104 -0
- package/docs/security-incidents/SECURITY-INCIDENT-TEMPLATE.md +37 -0
- package/docs/security-incidents/dependency-override-rationale.md +57 -0
- package/docs/security-incidents/dev-deps-high.json +116 -0
- package/docs/security-incidents/handling-procedure.md +54 -0
- package/docs/stories/001.0-DEV-PLUGIN-SETUP.story.md +92 -0
- package/docs/stories/002.0-DEV-ESLINT-CONFIG.story.md +82 -0
- package/docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md +112 -0
- package/docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md +153 -0
- package/docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md +138 -0
- package/docs/stories/006.0-DEV-FILE-VALIDATION.story.md +144 -0
- package/docs/stories/007.0-DEV-ERROR-REPORTING.story.md +163 -0
- package/docs/stories/008.0-DEV-AUTO-FIX.story.md +150 -0
- package/docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md +117 -0
- package/docs/stories/010.0-DEV-DEEP-VALIDATION.story.md +124 -0
- package/docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md +149 -0
- package/docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md +216 -0
- package/docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md +236 -0
- package/docs/stories/developer-story.map.md +120 -0
- package/docs/ts-jest-presets-guide.md +548 -0
- package/lib/src/maintenance/batch.d.ts +5 -0
- package/lib/src/maintenance/batch.js +5 -0
- package/lib/src/maintenance/cli.js +34 -212
- package/lib/src/maintenance/commands.d.ts +32 -0
- package/lib/src/maintenance/commands.js +139 -0
- package/lib/src/maintenance/detect.d.ts +2 -0
- package/lib/src/maintenance/detect.js +4 -0
- package/lib/src/maintenance/flags.d.ts +99 -0
- package/lib/src/maintenance/flags.js +121 -0
- package/lib/src/maintenance/report.d.ts +2 -0
- package/lib/src/maintenance/report.js +2 -0
- package/lib/src/maintenance/update.d.ts +4 -0
- package/lib/src/maintenance/update.js +4 -0
- package/lib/src/rules/helpers/require-story-io.d.ts +3 -0
- package/lib/src/rules/helpers/require-story-io.js +20 -6
- package/lib/src/rules/helpers/valid-annotation-options.js +15 -4
- package/lib/src/rules/helpers/valid-annotation-utils.js +5 -0
- package/lib/src/rules/helpers/valid-story-reference-helpers.d.ts +3 -4
- package/lib/src/utils/reqAnnotationDetection.d.ts +4 -1
- package/lib/src/utils/reqAnnotationDetection.js +43 -15
- package/lib/tests/maintenance/cli.test.js +89 -0
- package/lib/tests/rules/require-req-annotation.test.js +8 -1
- package/lib/tests/rules/require-story-annotation.test.js +9 -4
- package/lib/tests/utils/ts-language-options.d.ts +1 -7
- package/lib/tests/utils/ts-language-options.js +8 -5
- package/package.json +7 -3
- package/user-docs/api-reference.md +507 -0
- package/user-docs/eslint-9-setup-guide.md +639 -0
- package/user-docs/examples.md +74 -0
- package/user-docs/migration-guide.md +158 -0
|
@@ -6,15 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
/**
|
|
7
7
|
* Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
8
8
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
9
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
9
10
|
* @req REQ-ANNOTATION-REQUIRED - Verify require-story-annotation rule enforces @story annotation on functions
|
|
11
|
+
* @req REQ-REQUIRE-ACCEPTS-IMPLEMENTS - Verify @implements annotation is accepted as satisfying story requirements
|
|
10
12
|
*/
|
|
11
13
|
const eslint_1 = require("eslint");
|
|
12
14
|
const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
|
|
13
15
|
const ts_language_options_1 = require("../utils/ts-language-options");
|
|
14
16
|
const ruleTester = new eslint_1.RuleTester({
|
|
15
|
-
languageOptions:
|
|
16
|
-
parserOptions: { ecmaVersion: 2020, sourceType: "module" },
|
|
17
|
-
},
|
|
17
|
+
languageOptions: ts_language_options_1.tsRuleTesterLanguageOptions,
|
|
18
18
|
});
|
|
19
19
|
describe("Require Story Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", () => {
|
|
20
20
|
ruleTester.run("require-story-annotation", require_story_annotation_1.default, {
|
|
@@ -23,6 +23,10 @@ describe("Require Story Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)",
|
|
|
23
23
|
name: "[REQ-ANNOTATION-REQUIRED] valid with JSDoc @story annotation",
|
|
24
24
|
code: `/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n */\nfunction foo() {}`,
|
|
25
25
|
},
|
|
26
|
+
{
|
|
27
|
+
name: "[REQ-REQUIRE-ACCEPTS-IMPLEMENTS] valid with only @implements annotation",
|
|
28
|
+
code: `/**\n * @implements docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED\n */\nfunction implOnly() {}`,
|
|
29
|
+
},
|
|
26
30
|
{
|
|
27
31
|
name: "[REQ-ANNOTATION-REQUIRED] valid with line comment @story annotation",
|
|
28
32
|
code: `// @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
@@ -60,7 +64,8 @@ declare function tsDecl(): void;`,
|
|
|
60
64
|
],
|
|
61
65
|
invalid: [
|
|
62
66
|
{
|
|
63
|
-
|
|
67
|
+
// Backward compatibility: plain unannotated functions remain invalid under multi-story support
|
|
68
|
+
name: "[REQ-ANNOTATION-REQUIRED][BACKCOMPAT] missing @story annotation on function with no @implements",
|
|
64
69
|
code: `function bar() {}`,
|
|
65
70
|
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction bar() {}`,
|
|
66
71
|
errors: [
|
|
@@ -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
|
-
|
|
13
|
-
|
|
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.
|
|
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/(
|
|
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
|
+
```
|