eslint-plugin-traceability 1.8.0 → 1.8.2
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 +5 -5
- package/README.md +28 -29
- package/SECURITY.md +135 -0
- package/lib/src/index.d.ts +6 -35
- package/lib/src/index.js +8 -5
- package/lib/src/maintenance/cli.js +12 -16
- package/lib/src/maintenance/detect.js +28 -1
- package/lib/src/rules/helpers/require-story-io.d.ts +2 -2
- package/lib/src/rules/helpers/require-story-io.js +13 -13
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +2 -2
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +3 -3
- package/lib/src/rules/helpers/valid-annotation-utils.d.ts +5 -0
- package/lib/src/rules/helpers/valid-annotation-utils.js +43 -5
- package/lib/src/rules/helpers/valid-implements-utils.d.ts +11 -11
- package/lib/src/rules/helpers/valid-implements-utils.js +11 -11
- package/lib/src/rules/helpers/valid-story-reference-helpers.js +19 -0
- package/lib/src/rules/prefer-implements-annotation.d.ts +7 -7
- package/lib/src/rules/prefer-implements-annotation.js +21 -21
- package/lib/src/rules/valid-annotation-format.js +50 -24
- package/lib/src/rules/valid-req-reference.js +9 -9
- package/lib/src/utils/annotation-checker.js +3 -1
- package/lib/src/utils/reqAnnotationDetection.d.ts +2 -2
- package/lib/src/utils/reqAnnotationDetection.js +28 -28
- package/lib/tests/config/flat-config-presets-integration.test.d.ts +1 -0
- package/lib/tests/config/flat-config-presets-integration.test.js +75 -0
- package/lib/tests/maintenance/batch.test.js +11 -11
- package/lib/tests/maintenance/cli.test.js +34 -27
- package/lib/tests/maintenance/report.test.js +7 -7
- package/lib/tests/plugin-default-export-and-configs.test.js +0 -2
- package/lib/tests/rules/prefer-implements-annotation.test.js +48 -15
- package/lib/tests/rules/require-branch-annotation.test.js +15 -36
- package/lib/tests/rules/require-req-annotation.test.js +31 -104
- package/lib/tests/rules/require-story-annotation.test.js +3 -3
- package/lib/tests/rules/require-story-io-behavior.test.js +2 -7
- package/lib/tests/rules/require-story-io.edgecases.test.js +2 -7
- package/lib/tests/rules/require-story-visitors-edgecases.test.js +8 -8
- package/lib/tests/rules/valid-annotation-format.test.js +23 -23
- package/lib/tests/rules/valid-req-reference.test.js +9 -9
- package/lib/tests/rules/valid-story-reference.test.js +4 -43
- package/lib/tests/utils/annotation-checker.test.js +2 -6
- package/lib/tests/utils/fsTestHelpers.d.ts +7 -0
- package/lib/tests/utils/fsTestHelpers.js +26 -0
- package/lib/tests/utils/ioTestHelpers.d.ts +7 -0
- package/lib/tests/utils/ioTestHelpers.js +24 -0
- package/lib/tests/utils/temp-dir-helpers.d.ts +14 -0
- package/lib/tests/utils/temp-dir-helpers.js +61 -0
- package/package.json +8 -7
- package/user-docs/api-reference.md +37 -20
- package/user-docs/eslint-9-setup-guide.md +89 -6
- package/user-docs/migration-guide.md +37 -21
- package/docs/ci-cd-pipeline.md +0 -224
- package/docs/cli-integration.md +0 -22
- package/docs/code-quality-refactor-opportunities-2025-12-03.md +0 -78
- package/docs/config-presets.md +0 -38
- package/docs/conventional-commits-guide.md +0 -185
- package/docs/custom-rules-development-guide.md +0 -659
- package/docs/decisions/0001-allow-dynamic-require-for-built-plugins.md +0 -26
- package/docs/decisions/001-typescript-for-eslint-plugin.accepted.md +0 -111
- package/docs/decisions/002-jest-for-eslint-testing.accepted.md +0 -137
- package/docs/decisions/003-code-quality-ratcheting-plan.md +0 -48
- package/docs/decisions/004-automated-version-bumping-for-ci-cd.md +0 -196
- package/docs/decisions/005-github-actions-validation-tooling.accepted.md +0 -144
- package/docs/decisions/006-semantic-release-for-automated-publishing.accepted.md +0 -227
- package/docs/decisions/007-github-releases-over-changelog.accepted.md +0 -216
- package/docs/decisions/008-ci-audit-flags.accepted.md +0 -60
- package/docs/decisions/009-security-focused-lint-rules.accepted.md +0 -64
- package/docs/decisions/010-implements-annotation-for-multi-story-requirements.proposed.md +0 -184
- package/docs/decisions/adr-0001-console-usage-for-cli-guards.md +0 -190
- package/docs/decisions/adr-accept-dev-dep-risk-glob.md +0 -40
- package/docs/decisions/adr-commit-branch-tests.md +0 -54
- package/docs/decisions/adr-maintenance-cli-interface.md +0 -140
- package/docs/decisions/adr-pre-push-parity.md +0 -112
- package/docs/decisions/code-quality-ratcheting-plan.md +0 -53
- package/docs/dependency-health.md +0 -238
- package/docs/eslint-9-setup-guide.md +0 -517
- package/docs/eslint-plugin-development-guide.md +0 -487
- package/docs/functionality-coverage-2025-12-03.md +0 -250
- package/docs/jest-testing-guide.md +0 -100
- package/docs/rules/prefer-implements-annotation.md +0 -219
- package/docs/rules/require-branch-annotation.md +0 -71
- package/docs/rules/require-req-annotation.md +0 -203
- package/docs/rules/require-story-annotation.md +0 -159
- package/docs/rules/valid-annotation-format.md +0 -418
- package/docs/rules/valid-req-reference.md +0 -153
- package/docs/rules/valid-story-reference.md +0 -120
- package/docs/security-incidents/2025-11-17-glob-cli-incident.md +0 -45
- package/docs/security-incidents/2025-11-18-brace-expansion-redos.md +0 -45
- package/docs/security-incidents/2025-11-18-bundled-dev-deps-accepted-risk.md +0 -93
- package/docs/security-incidents/2025-11-18-tar-race-condition.md +0 -43
- package/docs/security-incidents/2025-12-03-dependency-health-review.md +0 -58
- package/docs/security-incidents/SECURITY-INCIDENT-2025-11-18-semantic-release-bundled-npm.known-error.md +0 -104
- package/docs/security-incidents/SECURITY-INCIDENT-TEMPLATE.md +0 -37
- package/docs/security-incidents/dependency-override-rationale.md +0 -57
- package/docs/security-incidents/dev-deps-high.json +0 -116
- package/docs/security-incidents/handling-procedure.md +0 -54
- package/docs/stories/001.0-DEV-PLUGIN-SETUP.story.md +0 -92
- package/docs/stories/002.0-DEV-ESLINT-CONFIG.story.md +0 -82
- package/docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md +0 -112
- package/docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md +0 -153
- package/docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md +0 -138
- package/docs/stories/006.0-DEV-FILE-VALIDATION.story.md +0 -144
- package/docs/stories/007.0-DEV-ERROR-REPORTING.story.md +0 -163
- package/docs/stories/008.0-DEV-AUTO-FIX.story.md +0 -150
- package/docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md +0 -117
- package/docs/stories/010.0-DEV-DEEP-VALIDATION.story.md +0 -124
- package/docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md +0 -149
- package/docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md +0 -216
- package/docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md +0 -236
- package/docs/stories/developer-story.map.md +0 -120
- package/docs/ts-jest-presets-guide.md +0 -548
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runFallbackTextBeforeHasStoryDetectsStoryTest = runFallbackTextBeforeHasStoryDetectsStoryTest;
|
|
4
|
+
/**
|
|
5
|
+
* Shared IO helper tests for require-story-io behavior.
|
|
6
|
+
*
|
|
7
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
8
|
+
* @req REQ-TEST-UTILS-IO - Provide reusable helpers for IO-related edge case tests
|
|
9
|
+
*/
|
|
10
|
+
function runFallbackTextBeforeHasStoryDetectsStoryTest(storyAnnotationOrFallbackFn = "@story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md", maybeFallbackFn) {
|
|
11
|
+
const isFirstArgFn = typeof storyAnnotationOrFallbackFn === "function";
|
|
12
|
+
const storyAnnotation = isFirstArgFn
|
|
13
|
+
? "@story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md"
|
|
14
|
+
: storyAnnotationOrFallbackFn;
|
|
15
|
+
const fallbackFn = isFirstArgFn
|
|
16
|
+
? storyAnnotationOrFallbackFn
|
|
17
|
+
: maybeFallbackFn;
|
|
18
|
+
const pre = `/* ${storyAnnotation} */\n`;
|
|
19
|
+
const rest = "function y() {}";
|
|
20
|
+
const full = pre + rest;
|
|
21
|
+
const fakeSource = { getText: () => full };
|
|
22
|
+
const node = { range: [full.indexOf("function"), full.length] };
|
|
23
|
+
expect(fallbackFn(fakeSource, node)).toBe(true);
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface TempDirHandle {
|
|
2
|
+
/** The absolute path to the created temporary directory. */
|
|
3
|
+
readonly dir: string;
|
|
4
|
+
/** Remove the directory recursively; safe to call multiple times. */
|
|
5
|
+
cleanup(): void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Create a temporary directory under the OS temp root with a common prefix.
|
|
9
|
+
*
|
|
10
|
+
* This helper centralizes the mkdtemp + rmSync pattern that appears in
|
|
11
|
+
* multiple maintenance tests so those tests can focus on behavior instead
|
|
12
|
+
* of filesystem plumbing.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createTempDir(prefix: string): TempDirHandle;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createTempDir = createTempDir;
|
|
37
|
+
/**
|
|
38
|
+
* Shared temp directory helpers for maintenance tests.
|
|
39
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
40
|
+
* @req REQ-MAINT-TEMP-HELPERS - Provide reusable OS tempdir setup/cleanup utilities for tests
|
|
41
|
+
*/
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
/**
|
|
46
|
+
* Create a temporary directory under the OS temp root with a common prefix.
|
|
47
|
+
*
|
|
48
|
+
* This helper centralizes the mkdtemp + rmSync pattern that appears in
|
|
49
|
+
* multiple maintenance tests so those tests can focus on behavior instead
|
|
50
|
+
* of filesystem plumbing.
|
|
51
|
+
*/
|
|
52
|
+
function createTempDir(prefix) {
|
|
53
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
54
|
+
return {
|
|
55
|
+
dir,
|
|
56
|
+
cleanup() {
|
|
57
|
+
// @implements docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-SAFE
|
|
58
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-traceability",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.2",
|
|
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",
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"lib",
|
|
9
9
|
"README.md",
|
|
10
10
|
"LICENSE",
|
|
11
|
+
"SECURITY.md",
|
|
11
12
|
"user-docs",
|
|
12
|
-
"docs",
|
|
13
13
|
"CHANGELOG.md"
|
|
14
14
|
],
|
|
15
15
|
"directories": {
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsc -p tsconfig.json",
|
|
23
|
-
"prepare": "
|
|
23
|
+
"prepare": "",
|
|
24
|
+
"postinstall": "husky",
|
|
24
25
|
"type-check": "tsc --noEmit -p tsconfig.json",
|
|
25
26
|
"check:traceability": "node scripts/traceability-check.js",
|
|
26
27
|
"lint-plugin-check": "node scripts/lint-plugin-check.js",
|
|
@@ -67,8 +68,8 @@
|
|
|
67
68
|
"@eslint/js": "^9.39.1",
|
|
68
69
|
"@semantic-release/changelog": "^6.0.3",
|
|
69
70
|
"@semantic-release/git": "^10.0.1",
|
|
70
|
-
"@semantic-release/github": "
|
|
71
|
-
"@semantic-release/npm": "
|
|
71
|
+
"@semantic-release/github": "12.0.2",
|
|
72
|
+
"@semantic-release/npm": "13.1.2",
|
|
72
73
|
"@types/eslint": "^9.6.1",
|
|
73
74
|
"@types/jest": "^30.0.0",
|
|
74
75
|
"@types/node": "^24.10.1",
|
|
@@ -80,9 +81,9 @@
|
|
|
80
81
|
"husky": "^9.1.7",
|
|
81
82
|
"jest": "^30.2.0",
|
|
82
83
|
"jscpd": "^4.0.5",
|
|
83
|
-
"lint-staged": "^16.2.
|
|
84
|
+
"lint-staged": "^16.2.7",
|
|
84
85
|
"prettier": "^3.6.2",
|
|
85
|
-
"semantic-release": "
|
|
86
|
+
"semantic-release": "25.0.2",
|
|
86
87
|
"ts-jest": "^29.4.5",
|
|
87
88
|
"typescript": "^5.9.3",
|
|
88
89
|
"secretlint": "11.2.5",
|
|
@@ -11,13 +11,15 @@ 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
|
-
In addition to the core `@story` and `@req` annotations, the plugin also understands `@
|
|
15
|
-
`@
|
|
16
|
-
For a detailed explanation of `@
|
|
14
|
+
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
|
+
`@supports docs/stories/010.0-PAYMENTS.story.md#REQ-PAYMENTS-REFUND`
|
|
16
|
+
to indicate that a given function supports a particular requirement from a payments story document within that project’s own `docs/stories` tree. For a detailed explanation of `@supports` behavior and validation, see [Migration Guide](migration-guide.md) (section **3.1 Multi-story @supports annotations**). Additional background on multi-story semantics is available in the project’s internal rule documentation, which is intended for maintainers rather than end users.
|
|
17
|
+
|
|
18
|
+
The `prefer-implements-annotation` rule is an **opt-in migration helper** that is disabled by default and **not** part of any built-in preset. It can be enabled and given a severity like `"warn"` or `"error"` using normal ESLint rule configuration when you want to gradually encourage multi-story `@supports` usage. Detailed behavior and migration guidance are documented in the project’s internal rule documentation, which is targeted at maintainers; typical end users can rely on the high-level guidance in this API reference and the [Migration Guide](migration-guide.md).
|
|
17
19
|
|
|
18
20
|
### traceability/require-story-annotation
|
|
19
21
|
|
|
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.
|
|
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 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
23
|
|
|
22
24
|
Options:
|
|
23
25
|
|
|
@@ -39,7 +41,7 @@ function initAuth() {
|
|
|
39
41
|
|
|
40
42
|
### traceability/require-req-annotation
|
|
41
43
|
|
|
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.
|
|
44
|
+
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.
|
|
43
45
|
|
|
44
46
|
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
47
|
|
|
@@ -88,11 +90,11 @@ Options:
|
|
|
88
90
|
This rule accepts an optional configuration object. The primary configuration shape is **nested**:
|
|
89
91
|
|
|
90
92
|
- `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.
|
|
92
|
-
- `example` (string, optional) – A short example `@story` path shown in error messages when `story.pattern` is configured.
|
|
93
|
+
- `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. By default, the plugin uses a pattern equivalent to `^docs/stories/.*\.story\.md$`, which matches a typical project convention such as `docs/stories/<name>.story.md`; you can override this to match however your own project organizes story files.
|
|
94
|
+
- `example` (string, optional) – A short example `@story` path shown in error messages when `story.pattern` is configured. The built-in default example is `"docs/stories/001.0-EXAMPLE.story.md"`, intended as a generic illustration of a project story file, and does not refer to this plugin’s internal documentation.
|
|
93
95
|
- `req` (object, optional) – Configuration for `@req` values.
|
|
94
96
|
- `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
|
|
97
|
+
- `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 value is used **only** for guidance and does not affect validation.
|
|
96
98
|
|
|
97
99
|
For backward compatibility, the rule also supports **flat shorthand** fields that map directly to the nested properties:
|
|
98
100
|
|
|
@@ -112,13 +114,10 @@ Behavior notes:
|
|
|
112
114
|
The `valid-annotation-format` rule is intentionally **backward compatible** with existing code that only uses `@story` and `@req`. You can:
|
|
113
115
|
|
|
114
116
|
- Continue using `@story` + `@req` for single-story functions and modules.
|
|
115
|
-
- Introduce `@
|
|
117
|
+
- Introduce `@supports` incrementally for integration code that implements requirements from multiple stories.
|
|
116
118
|
- Mix both styles in the same comment block when needed; the rule validates the format of each annotation independently.
|
|
117
119
|
|
|
118
|
-
Deep requirement checking for both `@req` and `@
|
|
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)
|
|
120
|
+
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.
|
|
122
121
|
|
|
123
122
|
Default Severity: `error`
|
|
124
123
|
Example:
|
|
@@ -196,9 +195,12 @@ The plugin provides two built-in presets for easy configuration:
|
|
|
196
195
|
|
|
197
196
|
### recommended
|
|
198
197
|
|
|
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
|
-
|
|
198
|
+
Enables the **six core traceability rules** with severities tuned for common usage (most at `error`, with
|
|
199
|
+
`traceability/valid-annotation-format` at `warn` to reduce noise). This `warn` level for `traceability/valid-annotation-format` is intentional to keep early adoption noise low, but you can safely raise it to `error` in projects that want strict enforcement of annotation formatting.
|
|
200
|
+
|
|
201
|
+
The `prefer-implements-annotation` migration rule is **not included** in this (or any) preset and remains disabled by default. If you want to encourage or enforce multi-story `@supports` annotations, you must enable `traceability/prefer-implements-annotation` explicitly in your ESLint configuration and choose an appropriate severity (for example, `"warn"` during migration or `"error"` once fully adopted).
|
|
202
|
+
|
|
203
|
+
Core rules enabled by the `recommended` preset:
|
|
202
204
|
|
|
203
205
|
- `traceability/require-story-annotation`: `error`
|
|
204
206
|
- `traceability/require-req-annotation`: `error`
|
|
@@ -218,7 +220,8 @@ export default [js.configs.recommended, traceability.configs.recommended];
|
|
|
218
220
|
|
|
219
221
|
### strict
|
|
220
222
|
|
|
221
|
-
Currently mirrors the **recommended** preset, reserved for future stricter policies.
|
|
223
|
+
Currently mirrors the **recommended** preset, reserved for future stricter policies. As with the `recommended` preset, the `traceability/prefer-implements-annotation` rule is **not** enabled here by default and must be configured manually if desired.
|
|
224
|
+
|
|
222
225
|
Usage:
|
|
223
226
|
|
|
224
227
|
```javascript
|
|
@@ -234,16 +237,30 @@ The plugin exposes a small maintenance API and a companion CLI, `traceability-ma
|
|
|
234
237
|
|
|
235
238
|
### Programmatic Maintenance API
|
|
236
239
|
|
|
237
|
-
|
|
240
|
+
The maintenance functions are available via the plugin’s `maintenance` export. You can either import the named `maintenance` export directly and destructure the functions you need, or import the default plugin export and access the same functions from `traceability.maintenance`:
|
|
238
241
|
|
|
239
242
|
```ts
|
|
240
|
-
|
|
243
|
+
// Option 1: Named `maintenance` export
|
|
244
|
+
import { maintenance } from "eslint-plugin-traceability";
|
|
245
|
+
|
|
246
|
+
const {
|
|
241
247
|
detectStaleAnnotations,
|
|
242
248
|
updateAnnotationReferences,
|
|
243
249
|
batchUpdateAnnotations,
|
|
244
250
|
verifyAnnotations,
|
|
245
251
|
generateMaintenanceReport,
|
|
246
|
-
}
|
|
252
|
+
} = maintenance;
|
|
253
|
+
|
|
254
|
+
// Option 2: Default plugin export
|
|
255
|
+
import traceability from "eslint-plugin-traceability";
|
|
256
|
+
|
|
257
|
+
const {
|
|
258
|
+
detectStaleAnnotations: detectStaleAnnotations2,
|
|
259
|
+
updateAnnotationReferences: updateAnnotationReferences2,
|
|
260
|
+
batchUpdateAnnotations: batchUpdateAnnotations2,
|
|
261
|
+
verifyAnnotations: verifyAnnotations2,
|
|
262
|
+
generateMaintenanceReport: generateMaintenanceReport2,
|
|
263
|
+
} = traceability.maintenance;
|
|
247
264
|
```
|
|
248
265
|
|
|
249
266
|
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.
|
|
@@ -28,6 +28,9 @@ npm install --save-dev eslint@^9.39.1
|
|
|
28
28
|
# Recommended configurations
|
|
29
29
|
npm install --save-dev @eslint/js@^9.39.1
|
|
30
30
|
|
|
31
|
+
# Traceability plugin
|
|
32
|
+
npm install --save-dev eslint-plugin-traceability@^1.0.0
|
|
33
|
+
|
|
31
34
|
# For TypeScript projects
|
|
32
35
|
npm install --save-dev @typescript-eslint/parser@^8.0.0
|
|
33
36
|
npm install --save-dev @typescript-eslint/utils@^8.0.0
|
|
@@ -67,13 +70,48 @@ export default [
|
|
|
67
70
|
|
|
68
71
|
### 4. Enable Traceability Plugin
|
|
69
72
|
|
|
70
|
-
To integrate the traceability plugin, update your `eslint.config.js
|
|
73
|
+
To integrate the traceability plugin with its **recommended** preset, update your `eslint.config.js`:
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
import js from "@eslint/js";
|
|
77
|
+
import traceability from "eslint-plugin-traceability";
|
|
78
|
+
|
|
79
|
+
export default [
|
|
80
|
+
js.configs.recommended,
|
|
81
|
+
{
|
|
82
|
+
plugins: {
|
|
83
|
+
traceability,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
...traceability.configs.recommended,
|
|
87
|
+
];
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
To use the **strict** preset instead:
|
|
71
91
|
|
|
72
92
|
```javascript
|
|
73
93
|
import js from "@eslint/js";
|
|
74
94
|
import traceability from "eslint-plugin-traceability";
|
|
75
95
|
|
|
76
|
-
export default [
|
|
96
|
+
export default [
|
|
97
|
+
js.configs.recommended,
|
|
98
|
+
{
|
|
99
|
+
plugins: {
|
|
100
|
+
traceability,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
...traceability.configs.strict,
|
|
104
|
+
];
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Note: The `traceability.configs.recommended` and `traceability.configs.strict` presets define rule severities only. They expect the plugin to be registered in a preceding flat-config object via:
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
{
|
|
111
|
+
plugins: {
|
|
112
|
+
traceability,
|
|
113
|
+
},
|
|
114
|
+
}
|
|
77
115
|
```
|
|
78
116
|
|
|
79
117
|
## Configuration File Format
|
|
@@ -137,9 +175,16 @@ Both forms are supported by ESLint 9 as long as the file extension and `package.
|
|
|
137
175
|
```javascript
|
|
138
176
|
// eslint.config.js
|
|
139
177
|
import js from "@eslint/js";
|
|
178
|
+
import traceability from "eslint-plugin-traceability";
|
|
140
179
|
|
|
141
180
|
export default [
|
|
142
181
|
js.configs.recommended,
|
|
182
|
+
{
|
|
183
|
+
plugins: {
|
|
184
|
+
traceability,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
...traceability.configs.recommended,
|
|
143
188
|
{
|
|
144
189
|
files: ["**/*.js", "**/*.mjs"],
|
|
145
190
|
languageOptions: {
|
|
@@ -163,9 +208,16 @@ export default [
|
|
|
163
208
|
// eslint.config.js
|
|
164
209
|
import js from "@eslint/js";
|
|
165
210
|
import typescriptParser from "@typescript-eslint/parser";
|
|
211
|
+
import traceability from "eslint-plugin-traceability";
|
|
166
212
|
|
|
167
213
|
export default [
|
|
168
214
|
js.configs.recommended,
|
|
215
|
+
{
|
|
216
|
+
plugins: {
|
|
217
|
+
traceability,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
...traceability.configs.recommended,
|
|
169
221
|
{
|
|
170
222
|
files: ["**/*.ts", "**/*.tsx"],
|
|
171
223
|
languageOptions: {
|
|
@@ -197,9 +249,16 @@ export default [
|
|
|
197
249
|
// eslint.config.js
|
|
198
250
|
import js from "@eslint/js";
|
|
199
251
|
import typescriptParser from "@typescript-eslint/parser";
|
|
252
|
+
import traceability from "eslint-plugin-traceability";
|
|
200
253
|
|
|
201
254
|
export default [
|
|
202
255
|
js.configs.recommended,
|
|
256
|
+
{
|
|
257
|
+
plugins: {
|
|
258
|
+
traceability,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
...traceability.configs.recommended,
|
|
203
262
|
{
|
|
204
263
|
files: ["**/*.{js,jsx,ts,tsx}"],
|
|
205
264
|
languageOptions: {
|
|
@@ -282,9 +341,16 @@ export default [
|
|
|
282
341
|
// eslint.config.js
|
|
283
342
|
import js from "@eslint/js";
|
|
284
343
|
import typescriptParser from "@typescript-eslint/parser";
|
|
344
|
+
import traceability from "eslint-plugin-traceability";
|
|
285
345
|
|
|
286
346
|
export default [
|
|
287
347
|
js.configs.recommended,
|
|
348
|
+
{
|
|
349
|
+
plugins: {
|
|
350
|
+
traceability,
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
...traceability.configs.recommended,
|
|
288
354
|
{
|
|
289
355
|
// Lint all packages in a monorepo/workspace
|
|
290
356
|
files: ["packages/*/src/**/*.{js,ts,tsx}"],
|
|
@@ -479,9 +545,16 @@ Solution: Use combined file patterns or separate override blocks, and import the
|
|
|
479
545
|
// eslint.config.js
|
|
480
546
|
import js from "@eslint/js";
|
|
481
547
|
import typescriptParser from "@typescript-eslint/parser";
|
|
548
|
+
import traceability from "eslint-plugin-traceability";
|
|
482
549
|
|
|
483
550
|
export default [
|
|
484
551
|
js.configs.recommended,
|
|
552
|
+
{
|
|
553
|
+
plugins: {
|
|
554
|
+
traceability,
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
...traceability.configs.recommended,
|
|
485
558
|
{
|
|
486
559
|
files: ["**/*.{js,jsx,ts,tsx}"],
|
|
487
560
|
languageOptions: {
|
|
@@ -512,6 +585,7 @@ Here's a complete working configuration for a TypeScript ESLint plugin project:
|
|
|
512
585
|
// eslint.config.js
|
|
513
586
|
import js from "@eslint/js";
|
|
514
587
|
import typescriptParser from "@typescript-eslint/parser";
|
|
588
|
+
import traceability from "eslint-plugin-traceability";
|
|
515
589
|
|
|
516
590
|
// Conditional plugin loading (for plugin development)
|
|
517
591
|
let plugin;
|
|
@@ -524,6 +598,15 @@ try {
|
|
|
524
598
|
|
|
525
599
|
export default [
|
|
526
600
|
js.configs.recommended,
|
|
601
|
+
{
|
|
602
|
+
// Register the traceability plugin for subsequent presets/rules
|
|
603
|
+
plugins: {
|
|
604
|
+
traceability,
|
|
605
|
+
...(plugin.rules ? { traceabilityDev: plugin } : {}),
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
// Apply the recommended preset for the published plugin
|
|
609
|
+
...traceability.configs.recommended,
|
|
527
610
|
{
|
|
528
611
|
// Node.js config files (CommonJS)
|
|
529
612
|
files: ["*.config.js", "*.config.mjs", "jest.config.js"],
|
|
@@ -554,7 +637,7 @@ export default [
|
|
|
554
637
|
},
|
|
555
638
|
},
|
|
556
639
|
plugins: {
|
|
557
|
-
...(plugin.rules ? {
|
|
640
|
+
...(plugin.rules ? { traceabilityDev: plugin } : {}),
|
|
558
641
|
},
|
|
559
642
|
rules: {
|
|
560
643
|
"@typescript-eslint/no-unused-vars": "error",
|
|
@@ -568,7 +651,7 @@ export default [
|
|
|
568
651
|
sourceType: "module",
|
|
569
652
|
},
|
|
570
653
|
plugins: {
|
|
571
|
-
...(plugin.rules ? {
|
|
654
|
+
...(plugin.rules ? { traceabilityDev: plugin } : {}),
|
|
572
655
|
},
|
|
573
656
|
},
|
|
574
657
|
{
|
|
@@ -621,6 +704,7 @@ export default [
|
|
|
621
704
|
"@typescript-eslint/parser": "^8.46.4",
|
|
622
705
|
"@typescript-eslint/utils": "^8.46.4",
|
|
623
706
|
"eslint": "^9.39.1",
|
|
707
|
+
"eslint-plugin-traceability": "^1.0.0",
|
|
624
708
|
"typescript": "^5.9.3"
|
|
625
709
|
}
|
|
626
710
|
}
|
|
@@ -635,5 +719,4 @@ export default [
|
|
|
635
719
|
5. **Use file patterns** instead of CLI `--ext` flags
|
|
636
720
|
6. **Structure as array of objects**, each targeting specific file types
|
|
637
721
|
7. **Use `ignores`** instead of `.eslintignore` files
|
|
638
|
-
|
|
639
|
-
This setup provides a solid foundation for ESLint 9 that works reliably across different project types and environments.
|
|
722
|
+
8. **Register plugins explicitly** in flat config before spreading their presets
|
|
@@ -37,25 +37,44 @@ export default [traceability.configs.recommended];
|
|
|
37
37
|
- `valid-req-reference` rejects path traversal (`../`) and absolute paths (`/etc/passwd`).
|
|
38
38
|
- `valid-annotation-format` enforces correct JSDoc traceability annotation syntax (`@story` and `@req` tags).
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
The following diff shows a typical migration in **your own project**, where `docs/stories/001.0-DEV-PLUGIN-SETUP.story.md` is an example of a story file path from your documentation tree:
|
|
41
41
|
|
|
42
42
|
```diff
|
|
43
43
|
- /** @story docs/stories/001.0-DEV-PLUGIN-SETUP.md */
|
|
44
44
|
+ /** @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md */
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
### 3.1 Multi-story `@
|
|
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:
|
|
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:
|
|
50
50
|
|
|
51
51
|
```js
|
|
52
52
|
/**
|
|
53
|
-
* @
|
|
53
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-IMPLEMENTS-PARSE REQ-IMPLEMENTS-VALIDATE
|
|
54
54
|
*/
|
|
55
55
|
function integrate() {}
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
You **do not** need to change existing, single-story annotations that already use `@story` and `@req`. Migration to `@
|
|
58
|
+
You **do not** need to change existing, single-story annotations that already use `@story` and `@req`. Migration to `@supports` is only recommended when a function or module genuinely implements requirements from more than one story file.
|
|
59
|
+
|
|
60
|
+
#### Optional `prefer-implements-annotation` migration rule
|
|
61
|
+
|
|
62
|
+
For teams that want to gradually migrate from `@story` + `@req` to `@supports`, the plugin provides an optional rule: `traceability/prefer-implements-annotation`.
|
|
63
|
+
|
|
64
|
+
- This rule is **disabled by default** and is **not** included in any built-in presets.
|
|
65
|
+
- You can enable it with any standard ESLint severity (`"off"`, `"warn"`, or `"error"`) in your config, for example:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
// excerpt from eslint.config.js
|
|
69
|
+
{
|
|
70
|
+
rules: {
|
|
71
|
+
"traceability/prefer-implements-annotation": "warn",
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- When enabled, it offers **conservative auto-fixes** that rewrite eligible `@story` + `@req` combinations into equivalent `@supports` lines, without attempting risky or ambiguous transformations.
|
|
77
|
+
- Detailed behavior, limitations, and examples are documented in the project’s internal rule documentation, which is primarily intended for maintainers; most users can rely on this guide and the API reference for day-to-day usage.
|
|
59
78
|
|
|
60
79
|
#### When to keep `@story` + `@req`
|
|
61
80
|
|
|
@@ -65,7 +84,7 @@ Keep your current annotations if:
|
|
|
65
84
|
- All relevant requirements live in that story file.
|
|
66
85
|
- You do not need to distinguish which story a particular requirement ID comes from.
|
|
67
86
|
|
|
68
|
-
Example (no migration required):
|
|
87
|
+
Example (no migration required). Here, `docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md` is an illustrative path representing a typical story file location in **your** documentation structure:
|
|
69
88
|
|
|
70
89
|
```js
|
|
71
90
|
/**
|
|
@@ -77,15 +96,15 @@ export function initAuth() {
|
|
|
77
96
|
}
|
|
78
97
|
```
|
|
79
98
|
|
|
80
|
-
#### When to introduce `@
|
|
99
|
+
#### When to introduce `@supports`
|
|
81
100
|
|
|
82
|
-
Adopt `@
|
|
101
|
+
Adopt `@supports` for **multi-story integration** code, especially when:
|
|
83
102
|
|
|
84
103
|
- The function combines behavior governed by **multiple** stories.
|
|
85
104
|
- Requirement IDs are reused across stories (for example, `REQ-SHARED-ID` appears in more than one story file).
|
|
86
105
|
- You want deep validation (via `valid-req-reference`) to know **which story file** each requirement came from.
|
|
87
106
|
|
|
88
|
-
Before (single-story annotations trying to describe multi-story behavior):
|
|
107
|
+
Before (single-story annotations trying to describe multi-story behavior). The story path shown here is an example of how you might name and organize a story file in your own project:
|
|
89
108
|
|
|
90
109
|
```js
|
|
91
110
|
/**
|
|
@@ -99,7 +118,7 @@ export async function applyFilters(rows, options) {
|
|
|
99
118
|
}
|
|
100
119
|
```
|
|
101
120
|
|
|
102
|
-
After (multi-story `@
|
|
121
|
+
After (multi-story `@supports`), using illustrative story paths that represent typical files in your project’s documentation tree (they are examples, not files provided by this plugin):
|
|
103
122
|
|
|
104
123
|
```js
|
|
105
124
|
/**
|
|
@@ -108,8 +127,8 @@ After (multi-story `@implements`), aligned with Story 010.2:
|
|
|
108
127
|
* @req REQ-AGE-THRESHOLD
|
|
109
128
|
* @req REQ-OUTPUT
|
|
110
129
|
*
|
|
111
|
-
* @
|
|
112
|
-
* @
|
|
130
|
+
* @supports docs/stories/003.0-DEV-IDENTIFY-OUTDATED.story.md REQ-AGE-THRESHOLD REQ-OUTPUT
|
|
131
|
+
* @supports docs/stories/004.0-DEV-FILTER-VULNERABLE-VERSIONS.story.md REQ-AUDIT-CHECK REQ-SAFE-ONLY
|
|
113
132
|
*/
|
|
114
133
|
export async function applyFilters(rows, options) {
|
|
115
134
|
// combined behavior
|
|
@@ -118,22 +137,19 @@ export async function applyFilters(rows, options) {
|
|
|
118
137
|
|
|
119
138
|
In the "after" example:
|
|
120
139
|
|
|
121
|
-
- `valid-annotation-format` ensures the `@
|
|
122
|
-
- `valid-req-reference` validates that each requirement listed after `@
|
|
140
|
+
- `valid-annotation-format` ensures the `@supports` lines use a valid story path and requirement ID format.
|
|
141
|
+
- `valid-req-reference` validates that each requirement listed after `@supports` exists in the corresponding story file.
|
|
123
142
|
|
|
124
143
|
#### Mixed usage during migration
|
|
125
144
|
|
|
126
|
-
You can introduce `@
|
|
145
|
+
You can introduce `@supports` gradually without breaking existing code:
|
|
127
146
|
|
|
128
147
|
1. Leave existing `@story` and `@req` annotations in place.
|
|
129
|
-
2. Add `@
|
|
148
|
+
2. Add `@supports` lines that group requirements by story file.
|
|
130
149
|
3. Run ESLint with `traceability/valid-annotation-format` and `traceability/valid-req-reference` enabled to confirm everything passes.
|
|
131
|
-
4. Optionally, once you are comfortable, standardize on using `@
|
|
132
|
-
|
|
133
|
-
For detailed semantics and edge cases (path validation, scoped requirement IDs, and multi-story fixtures), see:
|
|
150
|
+
4. Optionally, once you are comfortable, standardize on using `@supports` for multi-story integration functions while keeping `@story` + `@req` for simple, single-story code.
|
|
134
151
|
|
|
135
|
-
|
|
136
|
-
- Story: [`docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md`](../docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md)
|
|
152
|
+
Detailed semantics and edge cases (path validation, scoped requirement IDs, and multi-story fixtures) are ultimately governed by your own stories and requirements. For typical migrations, this guide together with the plugin’s API reference is sufficient.
|
|
137
153
|
|
|
138
154
|
## 4. Test and Validate
|
|
139
155
|
|