eslint-plugin-traceability 1.23.1 → 1.25.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 +3 -9
- package/README.md +42 -1
- package/lib/maintenance/batch.d.ts +7 -2
- package/lib/maintenance/batch.js +8 -4
- package/lib/maintenance/commands.d.ts +3 -0
- package/lib/maintenance/commands.js +20 -5
- package/lib/maintenance/detect.d.ts +4 -1
- package/lib/maintenance/detect.js +5 -2
- package/lib/maintenance/flags.d.ts +1 -0
- package/lib/maintenance/flags.js +20 -0
- package/lib/maintenance/report.d.ts +3 -1
- package/lib/maintenance/report.js +166 -5
- package/lib/maintenance/update.d.ts +3 -1
- package/lib/maintenance/update.js +3 -2
- package/lib/maintenance/utils.d.ts +18 -1
- package/lib/maintenance/utils.js +35 -4
- package/lib/rules/require-traceability.js +49 -4
- package/package.json +1 -1
- package/user-docs/api-reference.md +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
# [1.25.0](https://github.com/voder-ai/eslint-plugin-traceability/compare/v1.24.0...v1.25.0) (2026-01-10)
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
###
|
|
4
|
+
### Features
|
|
5
5
|
|
|
6
|
-
*
|
|
7
|
-
* correct plugin path in smoke test to lib/index.js ([3f343f6](https://github.com/voder-ai/eslint-plugin-traceability/commit/3f343f6686eaad9ce2528f9da7b6895c8bb083b7))
|
|
8
|
-
* correct runtime smoke test path resolution in CI ([bf20b02](https://github.com/voder-ai/eslint-plugin-traceability/commit/bf20b025e4e9743f2a87f259959ba61563196b11))
|
|
9
|
-
* correct smoke test ESLint rule name and test file annotations ([766b767](https://github.com/voder-ai/eslint-plugin-traceability/commit/766b76731713d2cadb36fb5b5619ee3a5c1d0fa9))
|
|
10
|
-
* correct TypeScript output paths from lib/src to lib ([9c82640](https://github.com/voder-ai/eslint-plugin-traceability/commit/9c8264027080ef8333bdd21106fdd773df3e4fd7))
|
|
11
|
-
* use direct path to eslint.js in smoke test ([401c1ee](https://github.com/voder-ai/eslint-plugin-traceability/commit/401c1ee750e43c7dc68f46f67b09be6cc790e809))
|
|
12
|
-
* use project eslint binary instead of npx in smoke test ([1c8cfce](https://github.com/voder-ai/eslint-plugin-traceability/commit/1c8cfcecba6f947808375694a318995421dabab3))
|
|
6
|
+
* **maintenance:** add ESLint config integration and circular reference detection ([44d1dd9](https://github.com/voder-ai/eslint-plugin-traceability/commit/44d1dd9f11c7e9fa03c5077d43fec837a6aaea36))
|
|
13
7
|
|
|
14
8
|
# Changelog
|
|
15
9
|
|
package/README.md
CHANGED
|
@@ -298,7 +298,7 @@ The `traceability-maint` CLI helps you maintain and audit `@story` annotations o
|
|
|
298
298
|
|
|
299
299
|
- `detect` – Scan the workspace and detect `@story` annotations that reference missing story files.
|
|
300
300
|
- `verify` – Verify that no stale `@story` annotations exist under the workspace root.
|
|
301
|
-
- `report` – Generate a human-readable or JSON report of stale story references.
|
|
301
|
+
- `report` – Generate a human-readable or JSON report of stale story references and circular dependencies.
|
|
302
302
|
- `update` – Apply safe, scripted updates to `@story` annotations (e.g., when a story file is renamed).
|
|
303
303
|
|
|
304
304
|
### Usage
|
|
@@ -312,6 +312,9 @@ npx traceability-maint --help
|
|
|
312
312
|
# Detect stale story references
|
|
313
313
|
npx traceability-maint detect --root .
|
|
314
314
|
|
|
315
|
+
# Detect with ESLint-style ignore patterns
|
|
316
|
+
npx traceability-maint detect --root . --ignore-pattern node_modules --ignore-pattern dist
|
|
317
|
+
|
|
315
318
|
# Verify that annotations are valid
|
|
316
319
|
npx traceability-maint verify --root .
|
|
317
320
|
|
|
@@ -323,8 +326,46 @@ npx traceability-maint update \
|
|
|
323
326
|
--root . \
|
|
324
327
|
--from "stories/feature-authentication.story.md" \
|
|
325
328
|
--to "stories/feature-auth-v2.story.md"
|
|
329
|
+
|
|
330
|
+
# Update with ignore patterns to skip generated code
|
|
331
|
+
npx traceability-maint update \
|
|
332
|
+
--root . \
|
|
333
|
+
--from "stories/old.story.md" \
|
|
334
|
+
--to "stories/new.story.md" \
|
|
335
|
+
--ignore-pattern dist
|
|
326
336
|
```
|
|
327
337
|
|
|
338
|
+
### Options
|
|
339
|
+
|
|
340
|
+
- `--root <path>` – Workspace root directory (defaults to current directory)
|
|
341
|
+
- `--json` – Output results in JSON format
|
|
342
|
+
- `--format <text|json>` – Report format (for `report` command)
|
|
343
|
+
- `--from <path>` – Source story path (for `update` command)
|
|
344
|
+
- `--to <path>` – Destination story path (for `update` command)
|
|
345
|
+
- `--dry-run` – Preview changes without modifying files (for `update` command)
|
|
346
|
+
- `--ignore-pattern <pattern>` – Path or directory to ignore (can be specified multiple times)
|
|
347
|
+
|
|
348
|
+
### ESLint Configuration Integration
|
|
349
|
+
|
|
350
|
+
The maintenance tools support integration with ESLint configuration through `--ignore-pattern` flags. This allows you to:
|
|
351
|
+
|
|
352
|
+
- Skip generated code directories (e.g., `dist`, `build`)
|
|
353
|
+
- Ignore dependency folders (e.g., `node_modules`)
|
|
354
|
+
- Exclude test fixtures or temporary files
|
|
355
|
+
|
|
356
|
+
Multiple patterns can be specified:
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
npx traceability-maint detect \
|
|
360
|
+
--ignore-pattern node_modules \
|
|
361
|
+
--ignore-pattern dist \
|
|
362
|
+
--ignore-pattern coverage
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Circular Reference Detection
|
|
366
|
+
|
|
367
|
+
The `report` command now includes detection of circular `@story` references in your story files. Circular references occur when story files reference each other in a cycle (e.g., A → B → A or A → B → C → A). These are reported separately in the maintenance report output to help identify potential documentation issues.
|
|
368
|
+
|
|
328
369
|
For a full description of options and JSON payloads, see the [Maintenance API and CLI](user-docs/api-reference.md#maintenance-api-and-cli) section in the API Reference.
|
|
329
370
|
|
|
330
371
|
## Plugin Validation
|
|
@@ -1,21 +1,26 @@
|
|
|
1
|
+
import { GetAllFilesOptions } from "./utils";
|
|
1
2
|
/**
|
|
2
3
|
* Batch update annotations and verify references
|
|
3
4
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
4
5
|
* @req REQ-MAINT-BATCH - Perform batch updates
|
|
5
6
|
* @req REQ-MAINT-VERIFY - Verify annotation references
|
|
7
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
6
8
|
* @param codebasePath Absolute path to the workspace root where annotations will be updated.
|
|
7
9
|
* @param mappings Array of mapping objects describing path changes, each containing an oldPath and newPath.
|
|
10
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
8
11
|
* @returns Total number of updated @story annotations across all mappings.
|
|
9
12
|
*/
|
|
10
13
|
export declare function batchUpdateAnnotations(codebasePath: string, mappings: {
|
|
11
14
|
oldPath: string;
|
|
12
15
|
newPath: string;
|
|
13
|
-
}[]): number;
|
|
16
|
+
}[], options?: GetAllFilesOptions): number;
|
|
14
17
|
/**
|
|
15
18
|
* Verify annotation references in codebase after maintenance operations
|
|
16
19
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
17
20
|
* @req REQ-MAINT-VERIFY - Verify annotation references
|
|
21
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
18
22
|
* @param codebasePath Absolute path to the workspace root whose annotations should be verified.
|
|
23
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
19
24
|
* @returns Boolean indicating whether there are no stale annotations remaining (true if clean, false if any remain).
|
|
20
25
|
*/
|
|
21
|
-
export declare function verifyAnnotations(codebasePath: string): boolean;
|
|
26
|
+
export declare function verifyAnnotations(codebasePath: string, options?: GetAllFilesOptions): boolean;
|
package/lib/maintenance/batch.js
CHANGED
|
@@ -9,14 +9,16 @@ const detect_1 = require("./detect");
|
|
|
9
9
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
10
10
|
* @req REQ-MAINT-BATCH - Perform batch updates
|
|
11
11
|
* @req REQ-MAINT-VERIFY - Verify annotation references
|
|
12
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
12
13
|
* @param codebasePath Absolute path to the workspace root where annotations will be updated.
|
|
13
14
|
* @param mappings Array of mapping objects describing path changes, each containing an oldPath and newPath.
|
|
15
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
14
16
|
* @returns Total number of updated @story annotations across all mappings.
|
|
15
17
|
*/
|
|
16
|
-
function batchUpdateAnnotations(codebasePath, mappings) {
|
|
18
|
+
function batchUpdateAnnotations(codebasePath, mappings, options) {
|
|
17
19
|
let totalUpdated = 0;
|
|
18
20
|
for (const { oldPath, newPath } of mappings) {
|
|
19
|
-
totalUpdated += (0, update_1.updateAnnotationReferences)(codebasePath, oldPath, newPath);
|
|
21
|
+
totalUpdated += (0, update_1.updateAnnotationReferences)(codebasePath, oldPath, newPath, options);
|
|
20
22
|
}
|
|
21
23
|
return totalUpdated;
|
|
22
24
|
}
|
|
@@ -24,10 +26,12 @@ function batchUpdateAnnotations(codebasePath, mappings) {
|
|
|
24
26
|
* Verify annotation references in codebase after maintenance operations
|
|
25
27
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
26
28
|
* @req REQ-MAINT-VERIFY - Verify annotation references
|
|
29
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
27
30
|
* @param codebasePath Absolute path to the workspace root whose annotations should be verified.
|
|
31
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
28
32
|
* @returns Boolean indicating whether there are no stale annotations remaining (true if clean, false if any remain).
|
|
29
33
|
*/
|
|
30
|
-
function verifyAnnotations(codebasePath) {
|
|
31
|
-
const staleAnnotations = (0, detect_1.detectStaleAnnotations)(codebasePath);
|
|
34
|
+
function verifyAnnotations(codebasePath, options) {
|
|
35
|
+
const staleAnnotations = (0, detect_1.detectStaleAnnotations)(codebasePath, options);
|
|
32
36
|
return staleAnnotations.length === 0;
|
|
33
37
|
}
|
|
@@ -7,6 +7,7 @@ export declare const EXIT_USAGE = 2;
|
|
|
7
7
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
8
8
|
* @req REQ-MAINT-DETECT - CLI surface for detection of stale annotations
|
|
9
9
|
* @req REQ-MAINT-SAFE - Return specific exit codes for stale vs clean states
|
|
10
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
10
11
|
* @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-DETECT REQ-MAINT-SAFE
|
|
11
12
|
*/
|
|
12
13
|
export declare function handleDetect(normalized: NormalizedCliArgs): number;
|
|
@@ -15,6 +16,7 @@ export declare function handleDetect(normalized: NormalizedCliArgs): number;
|
|
|
15
16
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
16
17
|
* @req REQ-MAINT-VERIFY - CLI surface for verification of annotations
|
|
17
18
|
* @req REQ-MAINT-SAFE - Return distinct exit codes for verification failures
|
|
19
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
18
20
|
* @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-VERIFY REQ-MAINT-SAFE
|
|
19
21
|
*/
|
|
20
22
|
export declare function handleVerify(normalized: NormalizedCliArgs): number;
|
|
@@ -23,6 +25,7 @@ export declare function handleVerify(normalized: NormalizedCliArgs): number;
|
|
|
23
25
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
24
26
|
* @req REQ-MAINT-REPORT - CLI surface for human-readable maintenance reports
|
|
25
27
|
* @req REQ-MAINT-SAFE - Support machine-readable formats for safe automation
|
|
28
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
26
29
|
* @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-REPORT REQ-MAINT-SAFE
|
|
27
30
|
*/
|
|
28
31
|
export declare function handleReport(normalized: NormalizedCliArgs): number;
|
|
@@ -28,12 +28,16 @@ exports.EXIT_USAGE = 2;
|
|
|
28
28
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
29
29
|
* @req REQ-MAINT-DETECT - CLI surface for detection of stale annotations
|
|
30
30
|
* @req REQ-MAINT-SAFE - Return specific exit codes for stale vs clean states
|
|
31
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
31
32
|
* @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-DETECT REQ-MAINT-SAFE
|
|
32
33
|
*/
|
|
33
34
|
function handleDetect(normalized) {
|
|
34
35
|
const flags = (0, flags_1.parseFlags)(normalized);
|
|
35
36
|
const root = flags.root;
|
|
36
|
-
const
|
|
37
|
+
const options = flags.ignorePatterns
|
|
38
|
+
? { ignorePatterns: flags.ignorePatterns }
|
|
39
|
+
: undefined;
|
|
40
|
+
const stale = (0, detect_1.detectStaleAnnotations)(root, options);
|
|
37
41
|
if (flags.json) {
|
|
38
42
|
// Emit JSON output to support consumption by external tools and scripts.
|
|
39
43
|
console.log(JSON.stringify({ root, stale }));
|
|
@@ -55,12 +59,16 @@ Run 'traceability-maint report' for a structured summary.`);
|
|
|
55
59
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
56
60
|
* @req REQ-MAINT-VERIFY - CLI surface for verification of annotations
|
|
57
61
|
* @req REQ-MAINT-SAFE - Return distinct exit codes for verification failures
|
|
62
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
58
63
|
* @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-VERIFY REQ-MAINT-SAFE
|
|
59
64
|
*/
|
|
60
65
|
function handleVerify(normalized) {
|
|
61
66
|
const flags = (0, flags_1.parseFlags)(normalized);
|
|
62
67
|
const root = flags.root;
|
|
63
|
-
const
|
|
68
|
+
const options = flags.ignorePatterns
|
|
69
|
+
? { ignorePatterns: flags.ignorePatterns }
|
|
70
|
+
: undefined;
|
|
71
|
+
const valid = (0, batch_1.verifyAnnotations)(root, options);
|
|
64
72
|
if (valid) {
|
|
65
73
|
console.log(`All traceability annotations under ${root} are valid.`);
|
|
66
74
|
return exports.EXIT_OK;
|
|
@@ -73,13 +81,17 @@ function handleVerify(normalized) {
|
|
|
73
81
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
74
82
|
* @req REQ-MAINT-REPORT - CLI surface for human-readable maintenance reports
|
|
75
83
|
* @req REQ-MAINT-SAFE - Support machine-readable formats for safe automation
|
|
84
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
76
85
|
* @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-REPORT REQ-MAINT-SAFE
|
|
77
86
|
*/
|
|
78
87
|
function handleReport(normalized) {
|
|
79
88
|
const flags = (0, flags_1.parseFlags)(normalized);
|
|
80
89
|
const root = flags.root;
|
|
81
90
|
const format = flags.format ?? "text";
|
|
82
|
-
const
|
|
91
|
+
const options = flags.ignorePatterns
|
|
92
|
+
? { ignorePatterns: flags.ignorePatterns }
|
|
93
|
+
: undefined;
|
|
94
|
+
const report = (0, report_1.generateMaintenanceReport)(root, options);
|
|
83
95
|
if (format === "json") {
|
|
84
96
|
console.log(JSON.stringify({ root, report }));
|
|
85
97
|
}
|
|
@@ -104,6 +116,9 @@ function handleReport(normalized) {
|
|
|
104
116
|
function handleUpdate(normalized) {
|
|
105
117
|
const flags = (0, flags_1.parseFlags)(normalized);
|
|
106
118
|
const root = flags.root;
|
|
119
|
+
const options = flags.ignorePatterns
|
|
120
|
+
? { ignorePatterns: flags.ignorePatterns }
|
|
121
|
+
: undefined;
|
|
107
122
|
if (!flags.from || !flags.to) {
|
|
108
123
|
console.error("'update' requires --from <oldPath> and --to <newPath>.");
|
|
109
124
|
return exports.EXIT_USAGE;
|
|
@@ -113,7 +128,7 @@ function handleUpdate(normalized) {
|
|
|
113
128
|
if (flags.dryRun) {
|
|
114
129
|
// For now, we cannot get a per-file diff without changing the maintenance API.
|
|
115
130
|
// We conservatively reuse generateMaintenanceReport to indicate potential impact.
|
|
116
|
-
const beforeReport = (0, report_1.generateMaintenanceReport)(root);
|
|
131
|
+
const beforeReport = (0, report_1.generateMaintenanceReport)(root, options);
|
|
117
132
|
const potentialChanges = beforeReport ? beforeReport.split("\n").length : 0;
|
|
118
133
|
const summary = {
|
|
119
134
|
root,
|
|
@@ -131,7 +146,7 @@ function handleUpdate(normalized) {
|
|
|
131
146
|
}
|
|
132
147
|
return exports.EXIT_OK;
|
|
133
148
|
}
|
|
134
|
-
const count = (0, update_1.updateAnnotationReferences)(root, from, to);
|
|
149
|
+
const count = (0, update_1.updateAnnotationReferences)(root, from, to, options);
|
|
135
150
|
if (flags.json) {
|
|
136
151
|
console.log(JSON.stringify({ root, from, to, updated: count }));
|
|
137
152
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { GetAllFilesOptions } from "./utils";
|
|
1
2
|
/**
|
|
2
3
|
* Detect stale annotation references that point to moved or deleted story files
|
|
3
4
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
4
5
|
* @req REQ-MAINT-DETECT - Detect stale annotation references
|
|
6
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
5
7
|
* @param codebasePath Path to the codebase root, treated as a workspace root and resolved against process.cwd().
|
|
8
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
6
9
|
* @returns A de-duplicated array of stale @story paths (as strings) whose resolved targets no longer exist on disk.
|
|
7
10
|
*/
|
|
8
|
-
export declare function detectStaleAnnotations(codebasePath: string): string[];
|
|
11
|
+
export declare function detectStaleAnnotations(codebasePath: string, options?: GetAllFilesOptions): string[];
|
|
@@ -42,10 +42,12 @@ const storyReferenceUtils_1 = require("../utils/storyReferenceUtils");
|
|
|
42
42
|
* Detect stale annotation references that point to moved or deleted story files
|
|
43
43
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
44
44
|
* @req REQ-MAINT-DETECT - Detect stale annotation references
|
|
45
|
+
* @req REQ-MAINT-UPDATE - Integrate with ESLint configuration
|
|
45
46
|
* @param codebasePath Path to the codebase root, treated as a workspace root and resolved against process.cwd().
|
|
47
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
46
48
|
* @returns A de-duplicated array of stale @story paths (as strings) whose resolved targets no longer exist on disk.
|
|
47
49
|
*/
|
|
48
|
-
function detectStaleAnnotations(codebasePath) {
|
|
50
|
+
function detectStaleAnnotations(codebasePath, options) {
|
|
49
51
|
const cwd = process.cwd();
|
|
50
52
|
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
51
53
|
// @req REQ-MAINT-DETECT - Treat codebasePath as a workspace root resolved from process.cwd()
|
|
@@ -62,7 +64,8 @@ function detectStaleAnnotations(codebasePath) {
|
|
|
62
64
|
const stale = new Set();
|
|
63
65
|
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
64
66
|
// @req REQ-MAINT-DETECT - Iterate over all files in the isolated workspace root
|
|
65
|
-
|
|
67
|
+
// @req REQ-MAINT-UPDATE - Apply ESLint ignore patterns during file discovery
|
|
68
|
+
const files = (0, utils_1.getAllFiles)(workspaceRoot, options);
|
|
66
69
|
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
67
70
|
// @req REQ-MAINT-DETECT - Loop over each workspace file to inspect its @story annotations
|
|
68
71
|
for (const file of files) {
|
package/lib/maintenance/flags.js
CHANGED
|
@@ -152,6 +152,22 @@ function handleDryRunFlag(flags, args, index) {
|
|
|
152
152
|
flags.dryRun = true;
|
|
153
153
|
return index;
|
|
154
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Handle the --ignore-pattern flag, collecting ignore patterns for ESLint integration
|
|
157
|
+
*
|
|
158
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
159
|
+
* @req REQ-MAINT-UPDATE - Support ESLint configuration integration
|
|
160
|
+
*/
|
|
161
|
+
function handleIgnorePatternFlag(flags, args, index) {
|
|
162
|
+
if (args[index] !== "--ignore-pattern" || !isNextValueString(args, index)) {
|
|
163
|
+
return index;
|
|
164
|
+
}
|
|
165
|
+
if (!flags.ignorePatterns) {
|
|
166
|
+
flags.ignorePatterns = [];
|
|
167
|
+
}
|
|
168
|
+
flags.ignorePatterns.push(args[index + 1]);
|
|
169
|
+
return index + 1;
|
|
170
|
+
}
|
|
155
171
|
/**
|
|
156
172
|
* Handle a single CLI argument and update the flags accordingly.
|
|
157
173
|
*
|
|
@@ -183,6 +199,10 @@ function applyFlag(flags, args, index) {
|
|
|
183
199
|
if (afterDryRun !== index) {
|
|
184
200
|
return afterDryRun;
|
|
185
201
|
}
|
|
202
|
+
const afterIgnorePattern = handleIgnorePatternFlag(flags, args, index);
|
|
203
|
+
if (afterIgnorePattern !== index) {
|
|
204
|
+
return afterIgnorePattern;
|
|
205
|
+
}
|
|
186
206
|
return index;
|
|
187
207
|
}
|
|
188
208
|
/**
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { GetAllFilesOptions } from "./utils";
|
|
1
2
|
/**
|
|
2
3
|
* Generate a report of maintenance operations performed
|
|
3
4
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
4
5
|
* @req REQ-MAINT-REPORT - Generate maintenance report
|
|
5
6
|
* @req REQ-MAINT-SAFE - Ensure operations are safe and reversible
|
|
6
7
|
* @param codebasePath The workspace root to scan for stale maintenance annotations.
|
|
8
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
7
9
|
* @returns An empty string when no stale annotations are found, or a newline-separated list of stale `@story` paths.
|
|
8
10
|
*/
|
|
9
|
-
export declare function generateMaintenanceReport(codebasePath: string): string;
|
|
11
|
+
export declare function generateMaintenanceReport(codebasePath: string, options?: GetAllFilesOptions): string;
|
|
@@ -1,21 +1,182 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.generateMaintenanceReport = generateMaintenanceReport;
|
|
4
37
|
const detect_1 = require("./detect");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
/**
|
|
41
|
+
* Detect circular references in story annotations
|
|
42
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
43
|
+
* @req REQ-MAINT-REPORT - Handle circular reference edge cases
|
|
44
|
+
* @param codebasePath The workspace root to scan for circular references
|
|
45
|
+
* @returns Array of circular reference chains detected
|
|
46
|
+
*/
|
|
47
|
+
function detectCircularReferences(codebasePath) {
|
|
48
|
+
const circularChains = [];
|
|
49
|
+
const storyGraph = new Map();
|
|
50
|
+
// Build a graph of story file references
|
|
51
|
+
try {
|
|
52
|
+
buildStoryGraph(codebasePath, storyGraph);
|
|
53
|
+
// Detect cycles using DFS
|
|
54
|
+
const visited = new Set();
|
|
55
|
+
const recursionStack = new Set();
|
|
56
|
+
for (const storyPath of storyGraph.keys()) {
|
|
57
|
+
if (!visited.has(storyPath)) {
|
|
58
|
+
detectCycles(storyPath, {
|
|
59
|
+
graph: storyGraph,
|
|
60
|
+
visited,
|
|
61
|
+
recursionStack,
|
|
62
|
+
path: [],
|
|
63
|
+
circularChains,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Silently handle errors during circular reference detection
|
|
70
|
+
// to avoid breaking the main report generation
|
|
71
|
+
}
|
|
72
|
+
return circularChains;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build a graph of story file cross-references
|
|
76
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
77
|
+
* @req REQ-MAINT-REPORT - Build dependency graph for circular detection
|
|
78
|
+
*/
|
|
79
|
+
function buildStoryGraph(codebasePath, graph) {
|
|
80
|
+
const storyFiles = findStoryFiles(codebasePath);
|
|
81
|
+
for (const storyFile of storyFiles) {
|
|
82
|
+
const content = fs.readFileSync(storyFile, "utf8");
|
|
83
|
+
const references = extractStoryReferences(content);
|
|
84
|
+
const relativePath = path.relative(codebasePath, storyFile);
|
|
85
|
+
if (!graph.has(relativePath)) {
|
|
86
|
+
graph.set(relativePath, new Set());
|
|
87
|
+
}
|
|
88
|
+
for (const ref of references) {
|
|
89
|
+
graph.get(relativePath)?.add(ref);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Find all story files in the codebase
|
|
95
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
96
|
+
* @req REQ-MAINT-REPORT - Locate story files for circular detection
|
|
97
|
+
*/
|
|
98
|
+
function findStoryFiles(dir) {
|
|
99
|
+
const storyFiles = [];
|
|
100
|
+
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
101
|
+
return storyFiles;
|
|
102
|
+
}
|
|
103
|
+
const entries = fs.readdirSync(dir);
|
|
104
|
+
for (const entry of entries) {
|
|
105
|
+
const fullPath = path.join(dir, entry);
|
|
106
|
+
const stat = fs.statSync(fullPath);
|
|
107
|
+
if (stat.isDirectory()) {
|
|
108
|
+
storyFiles.push(...findStoryFiles(fullPath));
|
|
109
|
+
}
|
|
110
|
+
else if (stat.isFile() && entry.endsWith(".story.md")) {
|
|
111
|
+
storyFiles.push(fullPath);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return storyFiles;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Extract story references from file content
|
|
118
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
119
|
+
* @req REQ-MAINT-REPORT - Parse story references for circular detection
|
|
120
|
+
*/
|
|
121
|
+
function extractStoryReferences(content) {
|
|
122
|
+
const references = [];
|
|
123
|
+
const storyPattern = /@story\s+([^\s]+\.story\.md)/g;
|
|
124
|
+
let match;
|
|
125
|
+
while ((match = storyPattern.exec(content)) !== null) {
|
|
126
|
+
references.push(match[1]);
|
|
127
|
+
}
|
|
128
|
+
return references;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Detect cycles in the story dependency graph using DFS
|
|
132
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
133
|
+
* @req REQ-MAINT-REPORT - Detect circular dependencies using graph traversal
|
|
134
|
+
*/
|
|
135
|
+
function detectCycles(node, options) {
|
|
136
|
+
const { graph, visited, recursionStack, path, circularChains } = options;
|
|
137
|
+
visited.add(node);
|
|
138
|
+
recursionStack.add(node);
|
|
139
|
+
path.push(node);
|
|
140
|
+
const neighbors = graph.get(node) || new Set();
|
|
141
|
+
for (const neighbor of neighbors) {
|
|
142
|
+
if (!visited.has(neighbor)) {
|
|
143
|
+
detectCycles(neighbor, options);
|
|
144
|
+
}
|
|
145
|
+
else if (recursionStack.has(neighbor)) {
|
|
146
|
+
// Found a cycle
|
|
147
|
+
const cycleStart = path.indexOf(neighbor);
|
|
148
|
+
const cycle = path.slice(cycleStart).concat(neighbor);
|
|
149
|
+
circularChains.push(`Circular reference: ${cycle.join(" -> ")}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
path.pop();
|
|
153
|
+
recursionStack.delete(node);
|
|
154
|
+
}
|
|
5
155
|
/**
|
|
6
156
|
* Generate a report of maintenance operations performed
|
|
7
157
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
8
158
|
* @req REQ-MAINT-REPORT - Generate maintenance report
|
|
9
159
|
* @req REQ-MAINT-SAFE - Ensure operations are safe and reversible
|
|
10
160
|
* @param codebasePath The workspace root to scan for stale maintenance annotations.
|
|
161
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
11
162
|
* @returns An empty string when no stale annotations are found, or a newline-separated list of stale `@story` paths.
|
|
12
163
|
*/
|
|
13
|
-
function generateMaintenanceReport(codebasePath) {
|
|
14
|
-
const staleAnnotations = (0, detect_1.detectStaleAnnotations)(codebasePath);
|
|
164
|
+
function generateMaintenanceReport(codebasePath, options) {
|
|
165
|
+
const staleAnnotations = (0, detect_1.detectStaleAnnotations)(codebasePath, options);
|
|
166
|
+
const circularReferences = detectCircularReferences(codebasePath);
|
|
167
|
+
const reportSections = [];
|
|
15
168
|
// @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-SAFE
|
|
16
169
|
// @supports docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md REQ-MAINT-REPORT
|
|
17
|
-
if (staleAnnotations.length
|
|
18
|
-
|
|
170
|
+
if (staleAnnotations.length > 0) {
|
|
171
|
+
reportSections.push("Stale Annotations:");
|
|
172
|
+
reportSections.push(...staleAnnotations);
|
|
173
|
+
}
|
|
174
|
+
if (circularReferences.length > 0) {
|
|
175
|
+
if (reportSections.length > 0) {
|
|
176
|
+
reportSections.push("");
|
|
177
|
+
}
|
|
178
|
+
reportSections.push("Circular References:");
|
|
179
|
+
reportSections.push(...circularReferences);
|
|
19
180
|
}
|
|
20
|
-
return
|
|
181
|
+
return reportSections.join("\n");
|
|
21
182
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GetAllFilesOptions } from "./utils";
|
|
1
2
|
/**
|
|
2
3
|
* Update annotation references when story files are moved or renamed
|
|
3
4
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
@@ -5,6 +6,7 @@
|
|
|
5
6
|
* @param codebasePath Absolute or workspace-root path whose files will be updated in-place.
|
|
6
7
|
* @param oldPath The original @story path to search for in annotation comments.
|
|
7
8
|
* @param newPath The replacement @story path that will replace occurrences of oldPath.
|
|
9
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
8
10
|
* @returns The number of @story annotations that were updated across the codebase.
|
|
9
11
|
*/
|
|
10
|
-
export declare function updateAnnotationReferences(codebasePath: string, oldPath: string, newPath: string): number;
|
|
12
|
+
export declare function updateAnnotationReferences(codebasePath: string, oldPath: string, newPath: string, options?: GetAllFilesOptions): number;
|
|
@@ -70,9 +70,10 @@ function processFileForAnnotationUpdates(fullPath, regex, newPath, replacementCo
|
|
|
70
70
|
* @param codebasePath Absolute or workspace-root path whose files will be updated in-place.
|
|
71
71
|
* @param oldPath The original @story path to search for in annotation comments.
|
|
72
72
|
* @param newPath The replacement @story path that will replace occurrences of oldPath.
|
|
73
|
+
* @param options Optional configuration including ESLint ignore patterns
|
|
73
74
|
* @returns The number of @story annotations that were updated across the codebase.
|
|
74
75
|
*/
|
|
75
|
-
function updateAnnotationReferences(codebasePath, oldPath, newPath) {
|
|
76
|
+
function updateAnnotationReferences(codebasePath, oldPath, newPath, options) {
|
|
76
77
|
/**
|
|
77
78
|
* Check that the provided codebase path exists and is a directory.
|
|
78
79
|
* If not, abort early.
|
|
@@ -87,7 +88,7 @@ function updateAnnotationReferences(codebasePath, oldPath, newPath) {
|
|
|
87
88
|
const replacementCountRef = { count: 0 };
|
|
88
89
|
const escapedOldPath = oldPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
89
90
|
const regex = new RegExp(`(@story\\s*)${escapedOldPath}`, "g");
|
|
90
|
-
const files = (0, utils_1.getAllFiles)(codebasePath);
|
|
91
|
+
const files = (0, utils_1.getAllFiles)(codebasePath, options);
|
|
91
92
|
/**
|
|
92
93
|
* Iterate over all files and replace annotation references
|
|
93
94
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
@@ -1,6 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for file traversal with optional ignore patterns
|
|
3
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
4
|
+
* @req REQ-MAINT-UPDATE - Support ESLint configuration integration
|
|
5
|
+
*/
|
|
6
|
+
export interface GetAllFilesOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Array of glob patterns or absolute paths to ignore during traversal.
|
|
9
|
+
* Supports both directory paths (to skip entire directories) and file patterns.
|
|
10
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
11
|
+
* @req REQ-MAINT-UPDATE - Respect ESLint ignore patterns
|
|
12
|
+
*/
|
|
13
|
+
ignorePatterns?: string[];
|
|
14
|
+
}
|
|
1
15
|
/**
|
|
2
16
|
* Recursively retrieve all files in a directory.
|
|
3
17
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
4
18
|
* @req REQ-MAINT-UTILS - Extract common file traversal logic for maintenance tools
|
|
19
|
+
* @req REQ-MAINT-UPDATE - Support ESLint configuration integration
|
|
20
|
+
* @param dir Root directory to scan
|
|
21
|
+
* @param options Optional configuration including ignore patterns from ESLint config
|
|
5
22
|
*/
|
|
6
|
-
export declare function getAllFiles(dir: string): string[];
|
|
23
|
+
export declare function getAllFiles(dir: string, options?: GetAllFilesOptions): string[];
|
package/lib/maintenance/utils.js
CHANGED
|
@@ -40,9 +40,13 @@ const path = __importStar(require("path"));
|
|
|
40
40
|
* Recursively retrieve all files in a directory.
|
|
41
41
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
42
42
|
* @req REQ-MAINT-UTILS - Extract common file traversal logic for maintenance tools
|
|
43
|
+
* @req REQ-MAINT-UPDATE - Support ESLint configuration integration
|
|
44
|
+
* @param dir Root directory to scan
|
|
45
|
+
* @param options Optional configuration including ignore patterns from ESLint config
|
|
43
46
|
*/
|
|
44
|
-
function getAllFiles(dir) {
|
|
47
|
+
function getAllFiles(dir, options) {
|
|
45
48
|
const fileList = [];
|
|
49
|
+
const ignorePatterns = options?.ignorePatterns ?? [];
|
|
46
50
|
/**
|
|
47
51
|
* Ensure the provided path exists and is a directory before traversal.
|
|
48
52
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
@@ -56,15 +60,34 @@ function getAllFiles(dir) {
|
|
|
56
60
|
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
57
61
|
return fileList;
|
|
58
62
|
}
|
|
59
|
-
traverseDirectory(dir, fileList);
|
|
63
|
+
traverseDirectory(dir, fileList, ignorePatterns);
|
|
60
64
|
return fileList;
|
|
61
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a path should be ignored based on patterns
|
|
68
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
69
|
+
* @req REQ-MAINT-UPDATE - Respect ESLint ignore patterns
|
|
70
|
+
*/
|
|
71
|
+
function shouldIgnore(filePath, ignorePatterns) {
|
|
72
|
+
for (const pattern of ignorePatterns) {
|
|
73
|
+
// Support both exact path matches and directory prefix matches
|
|
74
|
+
if (filePath === pattern ||
|
|
75
|
+
filePath.startsWith(pattern + path.sep) ||
|
|
76
|
+
// Support common patterns like node_modules, dist, etc.
|
|
77
|
+
filePath.includes(path.sep + pattern + path.sep) ||
|
|
78
|
+
filePath.endsWith(path.sep + pattern)) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
62
84
|
/**
|
|
63
85
|
* Recursively traverse a directory and collect file paths.
|
|
64
86
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
65
87
|
* @req REQ-MAINT-UTILS-TRAVERSE - Helper traversal function used by getAllFiles
|
|
88
|
+
* @req REQ-MAINT-UPDATE - Apply ignore patterns during traversal
|
|
66
89
|
*/
|
|
67
|
-
function traverseDirectory(currentDir, fileList) {
|
|
90
|
+
function traverseDirectory(currentDir, fileList, ignorePatterns) {
|
|
68
91
|
const entries = fs.readdirSync(currentDir);
|
|
69
92
|
/**
|
|
70
93
|
* Iterate over directory entries using a for-of loop.
|
|
@@ -73,6 +96,14 @@ function traverseDirectory(currentDir, fileList) {
|
|
|
73
96
|
*/
|
|
74
97
|
for (const entry of entries) {
|
|
75
98
|
const fullPath = path.join(currentDir, entry);
|
|
99
|
+
/**
|
|
100
|
+
* Skip ignored paths based on ESLint configuration
|
|
101
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
102
|
+
* @req REQ-MAINT-UPDATE - Respect ESLint ignore patterns
|
|
103
|
+
*/
|
|
104
|
+
if (shouldIgnore(fullPath, ignorePatterns)) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
76
107
|
const stat = fs.statSync(fullPath);
|
|
77
108
|
/**
|
|
78
109
|
* Recurse into directories to continue traversal.
|
|
@@ -80,7 +111,7 @@ function traverseDirectory(currentDir, fileList) {
|
|
|
80
111
|
* @req REQ-MAINT-UTILS-TRAVERSE-DIR - Handle directory entries during traversal
|
|
81
112
|
*/
|
|
82
113
|
if (stat.isDirectory()) {
|
|
83
|
-
traverseDirectory(fullPath, fileList);
|
|
114
|
+
traverseDirectory(fullPath, fileList, ignorePatterns);
|
|
84
115
|
/**
|
|
85
116
|
* Collect regular file entries during traversal.
|
|
86
117
|
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
@@ -39,7 +39,7 @@ const rule = {
|
|
|
39
39
|
recommended: "error",
|
|
40
40
|
},
|
|
41
41
|
hasSuggestions: true,
|
|
42
|
-
fixable:
|
|
42
|
+
fixable: "code",
|
|
43
43
|
messages: {
|
|
44
44
|
// Unified messageId for potential future direct use by this rule.
|
|
45
45
|
missingTraceability: "Function '{{name}}' must declare both story and requirement traceability annotations.",
|
|
@@ -48,11 +48,56 @@ const rule = {
|
|
|
48
48
|
...(storyRule.meta?.messages ?? {}),
|
|
49
49
|
...(reqRule.meta?.messages ?? {}),
|
|
50
50
|
},
|
|
51
|
-
schema: [
|
|
51
|
+
schema: [
|
|
52
|
+
{
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
scope: {
|
|
56
|
+
type: "array",
|
|
57
|
+
items: {
|
|
58
|
+
type: "string",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
exportPriority: {
|
|
62
|
+
type: "string",
|
|
63
|
+
enum: ["all", "exported", "non-exported"],
|
|
64
|
+
},
|
|
65
|
+
annotationTemplate: {
|
|
66
|
+
type: "string",
|
|
67
|
+
},
|
|
68
|
+
methodAnnotationTemplate: {
|
|
69
|
+
type: "string",
|
|
70
|
+
},
|
|
71
|
+
autoFix: {
|
|
72
|
+
type: "boolean",
|
|
73
|
+
description: "When false, disables automatic fix behavior while retaining diagnostics. When true (default), the rule inserts placeholder annotations in --fix mode.",
|
|
74
|
+
},
|
|
75
|
+
excludeTestCallbacks: {
|
|
76
|
+
type: "boolean",
|
|
77
|
+
},
|
|
78
|
+
annotationPlacement: {
|
|
79
|
+
type: "string",
|
|
80
|
+
enum: ["before", "inside"],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
additionalProperties: false,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
52
86
|
},
|
|
53
87
|
create(context) {
|
|
54
|
-
|
|
55
|
-
|
|
88
|
+
// Create a modified context that passes through options to composed rules
|
|
89
|
+
// We need to preserve all context methods while modifying the options array
|
|
90
|
+
const options = context.options[0] || {};
|
|
91
|
+
const modifiedContext = Object.create(context, {
|
|
92
|
+
options: {
|
|
93
|
+
value: [options],
|
|
94
|
+
writable: false,
|
|
95
|
+
enumerable: true,
|
|
96
|
+
configurable: false,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
const storyListeners = storyRule.create(modifiedContext) || {};
|
|
100
|
+
const reqListeners = reqRule.create(modifiedContext) || {};
|
|
56
101
|
const mergedListener = {};
|
|
57
102
|
const allEventNames = new Set([
|
|
58
103
|
...Object.keys(storyListeners),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-traceability",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.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/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -32,6 +32,31 @@ All three rule keys can still be configured individually if you need fine-graine
|
|
|
32
32
|
|
|
33
33
|
Description: Unified function-level traceability rule that composes the behavior of `traceability/require-story-annotation` and `traceability/require-req-annotation`. When enabled, it enforces that in‑scope functions and methods carry both a story reference (`@story` or an equivalent `@supports` tag) and at least one requirement reference (`@req` or, when configured, `@supports`). The recommended flat‑config presets in this plugin enable `traceability/require-traceability` by default alongside the legacy rule keys for backward compatibility, so that existing configurations referring to `traceability/require-story-annotation` or `traceability/require-req-annotation` continue to work without change.
|
|
34
34
|
|
|
35
|
+
When run with `--fix`, the rule delegates auto-fix behavior to its composed rules, primarily adding placeholder `@story` annotations for missing story coverage via the underlying `require-story-annotation` implementation. The rule supports the same `autoFix` option as the legacy rules, allowing you to disable automatic fixes while retaining diagnostics. All options (including `annotationTemplate`, `methodAnnotationTemplate`, `autoFix`, `scope`, `exportPriority`, `excludeTestCallbacks`, and `annotationPlacement`) are passed through to the composed rules, ensuring consistent behavior across the unified and legacy rule keys.
|
|
36
|
+
|
|
37
|
+
Options:
|
|
38
|
+
|
|
39
|
+
- `scope` (string[], optional) – Controls which function-like node types are required to have traceability annotations. Passed through to composed rules. Default behavior matches require-story-annotation defaults.
|
|
40
|
+
- `exportPriority` ("all" | "exported" | "non-exported", optional) – Controls whether the rule checks all functions, only exported ones, or only non-exported ones. Passed through to composed rules. Default: "all".
|
|
41
|
+
- `annotationTemplate` (string, optional) – Overrides the default placeholder JSDoc used when inserting missing `@story` annotations. Passed through to require-story-annotation. When omitted or blank, the built-in template from Story 008.0 is used.
|
|
42
|
+
- `methodAnnotationTemplate` (string, optional) – Overrides the default placeholder JSDoc used for class methods and TypeScript method signatures. Passed through to require-story-annotation.
|
|
43
|
+
- `autoFix` (boolean, optional) – When set to `false`, disables all automatic fix behavior for this rule while retaining its suggestions and diagnostics. When omitted or `true`, the rule behaves as before, inserting placeholder annotations in `--fix` mode. This option is passed through to the composed rules.
|
|
44
|
+
- `excludeTestCallbacks` (boolean, optional) – When `true` (default), excludes anonymous arrow functions that are direct callbacks to common test framework functions from annotation requirements. Passed through to composed rules.
|
|
45
|
+
- `annotationPlacement` ("before" | "inside", optional) – Controls whether annotations are expected before functions (`"before"`, default) or as the first lines inside function bodies (`"inside"`). Passed through to composed rules.
|
|
46
|
+
|
|
47
|
+
Default Severity: `error`
|
|
48
|
+
Example:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
/**
|
|
52
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
53
|
+
* @req REQ-ANNOTATION-REQUIRED
|
|
54
|
+
*/
|
|
55
|
+
function initAuth() {
|
|
56
|
+
// authentication logic
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
35
60
|
### traceability/require-story-annotation
|
|
36
61
|
|
|
37
62
|
Description: **Legacy function-level key:** This rule key is retained for backward compatibility and conceptually composes the same checks as `traceability/require-traceability`. New configurations should normally enable `traceability/require-traceability` instead and rely on this key only when you need to tune it independently. Ensures every function declaration has a traceability annotation, preferring `@supports` for story coverage while still accepting legacy `@story` annotations referencing the related user story. When you adopt multi-story `@supports` annotations, this rule also accepts `@supports` as an alternative way to prove story coverage, so either `@story` or at least one `@supports` tag will satisfy the presence check. When run with `--fix`, the rule inserts a single-line placeholder JSDoc `@story` annotation above missing functions, methods, TypeScript declare functions, and interface method signatures using a built-in template aligned with Story 008.0. This template is now configurable on a per-rule basis, and the rule exposes an explicit auto-fix toggle so you can choose between diagnostic-only behavior and automatic placeholder insertion. The default template remains aligned with Story 008.0, but you can now customize it per rule configuration and optionally disable auto-fix entirely when you only want diagnostics without edits.
|