eslint-plugin-traceability 1.6.5 → 1.7.1
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/README.md +39 -1
- package/lib/src/index.d.ts +30 -27
- package/lib/src/index.js +51 -31
- package/lib/src/maintenance/cli.d.ts +12 -0
- package/lib/src/maintenance/cli.js +279 -0
- package/lib/src/maintenance/detect.js +27 -12
- package/lib/src/maintenance/update.js +42 -34
- package/lib/src/maintenance/utils.js +30 -30
- package/lib/src/rules/helpers/require-story-io.js +51 -15
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +30 -0
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +36 -0
- package/lib/src/rules/helpers/valid-annotation-options.d.ts +118 -0
- package/lib/src/rules/helpers/valid-annotation-options.js +167 -0
- package/lib/src/rules/helpers/valid-annotation-utils.d.ts +68 -0
- package/lib/src/rules/helpers/valid-annotation-utils.js +103 -0
- package/lib/src/rules/helpers/valid-implements-utils.d.ts +75 -0
- package/lib/src/rules/helpers/valid-implements-utils.js +149 -0
- package/lib/src/rules/helpers/valid-story-reference-helpers.d.ts +67 -0
- package/lib/src/rules/helpers/valid-story-reference-helpers.js +92 -0
- package/lib/src/rules/prefer-implements-annotation.d.ts +39 -0
- package/lib/src/rules/prefer-implements-annotation.js +276 -0
- package/lib/src/rules/valid-annotation-format.js +255 -208
- package/lib/src/rules/valid-req-reference.js +210 -29
- package/lib/src/rules/valid-story-reference.d.ts +7 -0
- package/lib/src/rules/valid-story-reference.js +38 -80
- package/lib/src/utils/annotation-checker.js +2 -145
- package/lib/src/utils/branch-annotation-helpers.js +12 -3
- package/lib/src/utils/reqAnnotationDetection.d.ts +6 -0
- package/lib/src/utils/reqAnnotationDetection.js +152 -0
- package/lib/tests/maintenance/cli.test.d.ts +1 -0
- package/lib/tests/maintenance/cli.test.js +172 -0
- package/lib/tests/plugin-default-export-and-configs.test.js +3 -0
- package/lib/tests/rules/prefer-implements-annotation.test.d.ts +1 -0
- package/lib/tests/rules/prefer-implements-annotation.test.js +84 -0
- package/lib/tests/rules/require-branch-annotation.test.js +3 -2
- package/lib/tests/rules/require-req-annotation.test.js +57 -68
- package/lib/tests/rules/require-story-annotation.test.js +13 -28
- package/lib/tests/rules/require-story-core-edgecases.test.js +3 -58
- package/lib/tests/rules/require-story-core.autofix.test.js +5 -41
- package/lib/tests/rules/valid-annotation-format.test.js +395 -40
- package/lib/tests/rules/valid-req-reference.test.js +34 -0
- package/lib/tests/utils/annotation-checker.test.d.ts +23 -0
- package/lib/tests/utils/annotation-checker.test.js +24 -17
- package/lib/tests/utils/require-story-core-test-helpers.d.ts +10 -0
- package/lib/tests/utils/require-story-core-test-helpers.js +75 -0
- package/lib/tests/utils/ts-language-options.d.ts +22 -0
- package/lib/tests/utils/ts-language-options.js +27 -0
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Created autonomously by [voder.ai](https://voder.ai).
|
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
|
-
Prerequisites: Node.js >=
|
|
11
|
+
Prerequisites: Node.js >=18.18.0 and ESLint v9+.
|
|
12
12
|
|
|
13
13
|
1. Using npm
|
|
14
14
|
npm install --save-dev eslint-plugin-traceability
|
|
@@ -54,6 +54,7 @@ module.exports = [
|
|
|
54
54
|
- `traceability/valid-annotation-format` Enforces correct format of traceability annotations. ([Documentation](docs/rules/valid-annotation-format.md))
|
|
55
55
|
- `traceability/valid-story-reference` Validates that `@story` references point to existing story files. ([Documentation](docs/rules/valid-story-reference.md))
|
|
56
56
|
- `traceability/valid-req-reference` Validates that `@req` references point to existing requirement IDs. ([Documentation](docs/rules/valid-req-reference.md))
|
|
57
|
+
- `traceability/prefer-implements-annotation` Recommends migration from legacy `@story`/`@req` annotations to `@implements` (disabled by default). ([Documentation](docs/rules/prefer-implements-annotation.md))
|
|
57
58
|
|
|
58
59
|
Configuration options: For detailed per-rule options (such as scopes, branch types, and story directory settings), see the individual rule docs in `docs/rules/` and the consolidated [API Reference](user-docs/api-reference.md).
|
|
59
60
|
|
|
@@ -99,6 +100,43 @@ Detailed API specification and configuration options can be found in the [API Re
|
|
|
99
100
|
|
|
100
101
|
Practical usage examples and sample configurations are available in the [Examples](user-docs/examples.md) document.
|
|
101
102
|
|
|
103
|
+
## Maintenance CLI
|
|
104
|
+
|
|
105
|
+
The `traceability-maint` CLI helps you maintain and audit `@story` annotations outside of ESLint runs. It focuses on repository-wide checks for stale story references and safe batch updates.
|
|
106
|
+
|
|
107
|
+
### Commands
|
|
108
|
+
|
|
109
|
+
- `detect` – Scan the workspace and detect `@story` annotations that reference missing story files.
|
|
110
|
+
- `verify` – Verify that no stale `@story` annotations exist under the workspace root.
|
|
111
|
+
- `report` – Generate a human-readable or JSON report of stale story references.
|
|
112
|
+
- `update` – Apply safe, scripted updates to `@story` annotations (e.g., when a story file is renamed).
|
|
113
|
+
|
|
114
|
+
### Usage
|
|
115
|
+
|
|
116
|
+
All commands are run from your project root:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Show help and all options
|
|
120
|
+
npx traceability-maint --help
|
|
121
|
+
|
|
122
|
+
# Detect stale story references
|
|
123
|
+
npx traceability-maint detect --root .
|
|
124
|
+
|
|
125
|
+
# Verify that annotations are valid
|
|
126
|
+
npx traceability-maint verify --root .
|
|
127
|
+
|
|
128
|
+
# Generate a JSON report for CI pipelines
|
|
129
|
+
npx traceability-maint report --root . --format json
|
|
130
|
+
|
|
131
|
+
# Update references when a story file is renamed
|
|
132
|
+
npx traceability-maint update \
|
|
133
|
+
--root . \
|
|
134
|
+
--from "docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md" \
|
|
135
|
+
--to "docs/stories/003.0-DEV-FN-ANNOTATIONS.story.md"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
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.
|
|
139
|
+
|
|
102
140
|
## Plugin Validation
|
|
103
141
|
|
|
104
142
|
You can validate the plugin by running ESLint CLI with the plugin on a sample file:
|
package/lib/src/index.d.ts
CHANGED
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
* @req REQ-ERROR-HANDLING - Gracefully handles plugin loading errors and missing dependencies
|
|
6
6
|
*/
|
|
7
7
|
import type { Rule } from "eslint";
|
|
8
|
+
/**
|
|
9
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
10
|
+
* @req REQ-MAINTENANCE-API-EXPORT - Expose maintenance utilities alongside core plugin exports
|
|
11
|
+
*/
|
|
12
|
+
import { detectStaleAnnotations, updateAnnotationReferences, batchUpdateAnnotations, verifyAnnotations, generateMaintenanceReport } from "./maintenance";
|
|
8
13
|
/**
|
|
9
14
|
* @story docs/stories/002.0-DYNAMIC-RULE-LOADING.story.md
|
|
10
15
|
* @req REQ-RULE-LIST - Enumerate supported rule file names for plugin discovery
|
|
11
16
|
*/
|
|
12
|
-
declare const RULE_NAMES: readonly ["require-story-annotation", "require-req-annotation", "require-branch-annotation", "valid-annotation-format", "valid-story-reference", "valid-req-reference"];
|
|
17
|
+
declare const RULE_NAMES: readonly ["require-story-annotation", "require-req-annotation", "require-branch-annotation", "valid-annotation-format", "valid-story-reference", "valid-req-reference", "prefer-implements-annotation"];
|
|
13
18
|
type RuleName = (typeof RULE_NAMES)[number];
|
|
14
19
|
declare const rules: Record<RuleName, Rule.RuleModule>;
|
|
15
20
|
/**
|
|
@@ -24,12 +29,7 @@ declare const configs: {
|
|
|
24
29
|
traceability: {};
|
|
25
30
|
};
|
|
26
31
|
rules: {
|
|
27
|
-
"
|
|
28
|
-
"traceability/require-req-annotation": string;
|
|
29
|
-
"traceability/require-branch-annotation": string;
|
|
30
|
-
"traceability/valid-annotation-format": string;
|
|
31
|
-
"traceability/valid-story-reference": string;
|
|
32
|
-
"traceability/valid-req-reference": string;
|
|
32
|
+
[x: string]: "error" | "warn";
|
|
33
33
|
};
|
|
34
34
|
}[];
|
|
35
35
|
strict: {
|
|
@@ -37,30 +37,31 @@ declare const configs: {
|
|
|
37
37
|
traceability: {};
|
|
38
38
|
};
|
|
39
39
|
rules: {
|
|
40
|
-
"
|
|
41
|
-
"traceability/require-req-annotation": string;
|
|
42
|
-
"traceability/require-branch-annotation": string;
|
|
43
|
-
"traceability/valid-annotation-format": string;
|
|
44
|
-
"traceability/valid-story-reference": string;
|
|
45
|
-
"traceability/valid-req-reference": string;
|
|
40
|
+
[x: string]: "error" | "warn";
|
|
46
41
|
};
|
|
47
42
|
}[];
|
|
48
43
|
};
|
|
49
|
-
|
|
44
|
+
/**
|
|
45
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
46
|
+
* @req REQ-MAINTENANCE-API-EXPORT - Expose maintenance utilities alongside core plugin exports
|
|
47
|
+
*/
|
|
48
|
+
declare const maintenance: {
|
|
49
|
+
detectStaleAnnotations: typeof detectStaleAnnotations;
|
|
50
|
+
updateAnnotationReferences: typeof updateAnnotationReferences;
|
|
51
|
+
batchUpdateAnnotations: typeof batchUpdateAnnotations;
|
|
52
|
+
verifyAnnotations: typeof verifyAnnotations;
|
|
53
|
+
generateMaintenanceReport: typeof generateMaintenanceReport;
|
|
54
|
+
};
|
|
55
|
+
export { rules, configs, maintenance };
|
|
50
56
|
declare const _default: {
|
|
51
|
-
rules: Record<"require-story-annotation" | "require-req-annotation" | "require-branch-annotation" | "valid-annotation-format" | "valid-story-reference" | "valid-req-reference", Rule.RuleModule>;
|
|
57
|
+
rules: Record<"require-story-annotation" | "require-req-annotation" | "require-branch-annotation" | "valid-annotation-format" | "valid-story-reference" | "valid-req-reference" | "prefer-implements-annotation", Rule.RuleModule>;
|
|
52
58
|
configs: {
|
|
53
59
|
recommended: {
|
|
54
60
|
plugins: {
|
|
55
61
|
traceability: {};
|
|
56
62
|
};
|
|
57
63
|
rules: {
|
|
58
|
-
"
|
|
59
|
-
"traceability/require-req-annotation": string;
|
|
60
|
-
"traceability/require-branch-annotation": string;
|
|
61
|
-
"traceability/valid-annotation-format": string;
|
|
62
|
-
"traceability/valid-story-reference": string;
|
|
63
|
-
"traceability/valid-req-reference": string;
|
|
64
|
+
[x: string]: "error" | "warn";
|
|
64
65
|
};
|
|
65
66
|
}[];
|
|
66
67
|
strict: {
|
|
@@ -68,14 +69,16 @@ declare const _default: {
|
|
|
68
69
|
traceability: {};
|
|
69
70
|
};
|
|
70
71
|
rules: {
|
|
71
|
-
"
|
|
72
|
-
"traceability/require-req-annotation": string;
|
|
73
|
-
"traceability/require-branch-annotation": string;
|
|
74
|
-
"traceability/valid-annotation-format": string;
|
|
75
|
-
"traceability/valid-story-reference": string;
|
|
76
|
-
"traceability/valid-req-reference": string;
|
|
72
|
+
[x: string]: "error" | "warn";
|
|
77
73
|
};
|
|
78
74
|
}[];
|
|
79
75
|
};
|
|
76
|
+
maintenance: {
|
|
77
|
+
detectStaleAnnotations: typeof detectStaleAnnotations;
|
|
78
|
+
updateAnnotationReferences: typeof updateAnnotationReferences;
|
|
79
|
+
batchUpdateAnnotations: typeof batchUpdateAnnotations;
|
|
80
|
+
verifyAnnotations: typeof verifyAnnotations;
|
|
81
|
+
generateMaintenanceReport: typeof generateMaintenanceReport;
|
|
82
|
+
};
|
|
80
83
|
};
|
|
81
84
|
export default _default;
|
package/lib/src/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.configs = exports.rules = void 0;
|
|
3
|
+
exports.maintenance = exports.configs = exports.rules = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
6
|
+
* @req REQ-MAINTENANCE-API-EXPORT - Expose maintenance utilities alongside core plugin exports
|
|
7
|
+
*/
|
|
8
|
+
const maintenance_1 = require("./maintenance");
|
|
4
9
|
/**
|
|
5
10
|
* @story docs/stories/002.0-DYNAMIC-RULE-LOADING.story.md
|
|
6
11
|
* @req REQ-RULE-LIST - Enumerate supported rule file names for plugin discovery
|
|
@@ -12,6 +17,7 @@ const RULE_NAMES = [
|
|
|
12
17
|
"valid-annotation-format",
|
|
13
18
|
"valid-story-reference",
|
|
14
19
|
"valid-req-reference",
|
|
20
|
+
"prefer-implements-annotation",
|
|
15
21
|
];
|
|
16
22
|
const rules = {};
|
|
17
23
|
exports.rules = rules;
|
|
@@ -73,37 +79,51 @@ RULE_NAMES.forEach(
|
|
|
73
79
|
* The recommended and strict configs treat missing annotations and missing references as errors,
|
|
74
80
|
* while formatting issues are reported as warnings, matching the story's severity conventions.
|
|
75
81
|
*/
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
const TRACEABILITY_RULE_SEVERITIES = {
|
|
83
|
+
"traceability/require-story-annotation": "error",
|
|
84
|
+
"traceability/require-req-annotation": "error",
|
|
85
|
+
"traceability/require-branch-annotation": "error",
|
|
86
|
+
"traceability/valid-annotation-format": "warn",
|
|
87
|
+
"traceability/valid-story-reference": "error",
|
|
88
|
+
"traceability/valid-req-reference": "error",
|
|
89
|
+
"traceability/prefer-implements-annotation": "warn",
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
|
|
93
|
+
* @req REQ-PLUGIN-STRUCTURE - Provide foundational plugin export and registration
|
|
94
|
+
* @req REQ-ERROR-SEVERITY - Map rule types to appropriate ESLint severity levels (errors vs warnings)
|
|
95
|
+
*/
|
|
96
|
+
function createTraceabilityFlatConfig() {
|
|
97
|
+
return {
|
|
98
|
+
plugins: {
|
|
99
|
+
traceability: {},
|
|
90
100
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
{
|
|
94
|
-
plugins: {
|
|
95
|
-
traceability: {},
|
|
96
|
-
},
|
|
97
|
-
rules: {
|
|
98
|
-
"traceability/require-story-annotation": "error",
|
|
99
|
-
"traceability/require-req-annotation": "error",
|
|
100
|
-
"traceability/require-branch-annotation": "error",
|
|
101
|
-
"traceability/valid-annotation-format": "warn",
|
|
102
|
-
"traceability/valid-story-reference": "error",
|
|
103
|
-
"traceability/valid-req-reference": "error",
|
|
104
|
-
},
|
|
101
|
+
rules: {
|
|
102
|
+
...TRACEABILITY_RULE_SEVERITIES,
|
|
105
103
|
},
|
|
106
|
-
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
|
|
108
|
+
* @req REQ-ERROR-SEVERITY - Map rule types to appropriate ESLint severity levels (errors vs warnings)
|
|
109
|
+
* The recommended and strict configs treat missing annotations and missing references as errors,
|
|
110
|
+
* while formatting issues are reported as warnings, matching the story's severity conventions.
|
|
111
|
+
*/
|
|
112
|
+
const configs = {
|
|
113
|
+
recommended: [createTraceabilityFlatConfig()],
|
|
114
|
+
strict: [createTraceabilityFlatConfig()],
|
|
107
115
|
};
|
|
108
116
|
exports.configs = configs;
|
|
109
|
-
|
|
117
|
+
/**
|
|
118
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
119
|
+
* @req REQ-MAINTENANCE-API-EXPORT - Expose maintenance utilities alongside core plugin exports
|
|
120
|
+
*/
|
|
121
|
+
const maintenance = {
|
|
122
|
+
detectStaleAnnotations: maintenance_1.detectStaleAnnotations,
|
|
123
|
+
updateAnnotationReferences: maintenance_1.updateAnnotationReferences,
|
|
124
|
+
batchUpdateAnnotations: maintenance_1.batchUpdateAnnotations,
|
|
125
|
+
verifyAnnotations: maintenance_1.verifyAnnotations,
|
|
126
|
+
generateMaintenanceReport: maintenance_1.generateMaintenanceReport,
|
|
127
|
+
};
|
|
128
|
+
exports.maintenance = maintenance;
|
|
129
|
+
exports.default = { rules, configs, maintenance };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Maintenance CLI entry point.
|
|
4
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
5
|
+
* @req REQ-MAINT-DETECT - CLI support for detection of stale annotations
|
|
6
|
+
* @req REQ-MAINT-VERIFY - CLI support for verification of annotations
|
|
7
|
+
* @req REQ-MAINT-REPORT - CLI support for human-readable reports
|
|
8
|
+
* @req REQ-MAINT-UPDATE - CLI support for updating annotation references
|
|
9
|
+
* @req REQ-MAINT-BATCH - CLI support for batch maintenance operations
|
|
10
|
+
* @req REQ-MAINT-SAFE - Provide clear exit codes and avoid unsafe defaults
|
|
11
|
+
*/
|
|
12
|
+
export declare function runMaintenanceCli(rawArgv: string[]): number;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.runMaintenanceCli = runMaintenanceCli;
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const detect_1 = require("./detect");
|
|
10
|
+
const batch_1 = require("./batch");
|
|
11
|
+
const update_1 = require("./update");
|
|
12
|
+
const report_1 = require("./report");
|
|
13
|
+
const EXIT_OK = 0;
|
|
14
|
+
const EXIT_STALE = 1;
|
|
15
|
+
const EXIT_USAGE = 2;
|
|
16
|
+
/**
|
|
17
|
+
* Extract the subcommand and its arguments from a raw argv array.
|
|
18
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
19
|
+
* @req REQ-MAINT-SAFE - Centralize parsing of CLI command and arguments
|
|
20
|
+
*/
|
|
21
|
+
function parseCliInput(rawArgv) {
|
|
22
|
+
const [, , command, ...rest] = rawArgv;
|
|
23
|
+
return { command, args: rest };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Maintenance CLI entry point.
|
|
27
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
28
|
+
* @req REQ-MAINT-DETECT - CLI support for detection of stale annotations
|
|
29
|
+
* @req REQ-MAINT-VERIFY - CLI support for verification of annotations
|
|
30
|
+
* @req REQ-MAINT-REPORT - CLI support for human-readable reports
|
|
31
|
+
* @req REQ-MAINT-UPDATE - CLI support for updating annotation references
|
|
32
|
+
* @req REQ-MAINT-BATCH - CLI support for batch maintenance operations
|
|
33
|
+
* @req REQ-MAINT-SAFE - Provide clear exit codes and avoid unsafe defaults
|
|
34
|
+
*/
|
|
35
|
+
function runMaintenanceCli(rawArgv) {
|
|
36
|
+
const { command, args } = parseCliInput(rawArgv);
|
|
37
|
+
if (!command || command === "-h" || command === "--help") {
|
|
38
|
+
printHelp();
|
|
39
|
+
return EXIT_OK;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
switch (command) {
|
|
43
|
+
case "detect":
|
|
44
|
+
return handleDetect(args);
|
|
45
|
+
case "verify":
|
|
46
|
+
return handleVerify(args);
|
|
47
|
+
case "report":
|
|
48
|
+
return handleReport(args);
|
|
49
|
+
case "update":
|
|
50
|
+
return handleUpdate(args);
|
|
51
|
+
default:
|
|
52
|
+
console.error(`Unknown command: ${command}`);
|
|
53
|
+
printHelp();
|
|
54
|
+
return EXIT_USAGE;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
59
|
+
// @req REQ-MAINT-SAFE - Catch unexpected errors and emit concise diagnostics
|
|
60
|
+
const message = error instanceof Error
|
|
61
|
+
? error.message
|
|
62
|
+
: "Unknown error in maintenance CLI";
|
|
63
|
+
console.error(`traceability-maint failed: ${message}`);
|
|
64
|
+
return EXIT_USAGE;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Initialize default flags for the maintenance CLI.
|
|
69
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
70
|
+
* @req REQ-MAINT-SAFE - Provide predictable, minimal argument parsing
|
|
71
|
+
*/
|
|
72
|
+
function createDefaultFlags() {
|
|
73
|
+
return {
|
|
74
|
+
root: process.cwd(),
|
|
75
|
+
json: false,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Handle a single CLI argument and update the flags accordingly.
|
|
80
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
81
|
+
* @req REQ-MAINT-SAFE - Provide predictable, minimal argument parsing
|
|
82
|
+
*/
|
|
83
|
+
function applyFlag(flags, args, index) {
|
|
84
|
+
const arg = args[index];
|
|
85
|
+
if (arg === "--root" && typeof args[index + 1] === "string") {
|
|
86
|
+
flags.root = path_1.default.resolve(args[index + 1]);
|
|
87
|
+
return index + 1;
|
|
88
|
+
}
|
|
89
|
+
if (arg === "--json") {
|
|
90
|
+
flags.json = true;
|
|
91
|
+
return index;
|
|
92
|
+
}
|
|
93
|
+
if (arg === "--format" && typeof args[index + 1] === "string") {
|
|
94
|
+
const value = args[index + 1];
|
|
95
|
+
if (value === "text" || value === "json") {
|
|
96
|
+
flags.format = value;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
throw new Error(`Invalid format: ${value}. Expected 'text' or 'json'.`);
|
|
100
|
+
}
|
|
101
|
+
return index + 1;
|
|
102
|
+
}
|
|
103
|
+
if (arg === "--from" && typeof args[index + 1] === "string") {
|
|
104
|
+
flags.from = args[index + 1];
|
|
105
|
+
return index + 1;
|
|
106
|
+
}
|
|
107
|
+
if (arg === "--to" && typeof args[index + 1] === "string") {
|
|
108
|
+
flags.to = args[index + 1];
|
|
109
|
+
return index + 1;
|
|
110
|
+
}
|
|
111
|
+
if (arg === "--dry-run") {
|
|
112
|
+
flags.dryRun = true;
|
|
113
|
+
return index;
|
|
114
|
+
}
|
|
115
|
+
return index;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Basic flag parser for maintenance CLI subcommands.
|
|
119
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
120
|
+
* @req REQ-MAINT-SAFE - Provide predictable, minimal argument parsing
|
|
121
|
+
*/
|
|
122
|
+
function parseFlags(args) {
|
|
123
|
+
const flags = createDefaultFlags();
|
|
124
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
125
|
+
i = applyFlag(flags, args, i);
|
|
126
|
+
}
|
|
127
|
+
return flags;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handle the `detect` subcommand for stale @story annotations.
|
|
131
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
132
|
+
* @req REQ-MAINT-DETECT - CLI surface for detection of stale annotations
|
|
133
|
+
* @req REQ-MAINT-SAFE - Return specific exit codes for stale vs clean states
|
|
134
|
+
*/
|
|
135
|
+
function handleDetect(args) {
|
|
136
|
+
const flags = parseFlags(args);
|
|
137
|
+
const root = flags.root;
|
|
138
|
+
const stale = (0, detect_1.detectStaleAnnotations)(root);
|
|
139
|
+
if (flags.json) {
|
|
140
|
+
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
141
|
+
// @req REQ-MAINT-REPORT - JSON-friendly output for tooling integration
|
|
142
|
+
console.log(JSON.stringify({ root, stale }));
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
if (stale.length === 0) {
|
|
146
|
+
console.log("No stale @story annotations found.");
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
stale.forEach((story) => {
|
|
150
|
+
console.log(story);
|
|
151
|
+
});
|
|
152
|
+
console.log(`Found ${stale.length} stale @story annotation${stale.length === 1 ? "" : "s"}.
|
|
153
|
+
Run 'traceability-maint report' for a structured summary.`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return stale.length === 0 ? EXIT_OK : EXIT_STALE;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Handle the `verify` subcommand to validate traceability annotations.
|
|
160
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
161
|
+
* @req REQ-MAINT-VERIFY - CLI surface for verification of annotations
|
|
162
|
+
* @req REQ-MAINT-SAFE - Return distinct exit codes for verification failures
|
|
163
|
+
*/
|
|
164
|
+
function handleVerify(args) {
|
|
165
|
+
const flags = parseFlags(args);
|
|
166
|
+
const root = flags.root;
|
|
167
|
+
const valid = (0, batch_1.verifyAnnotations)(root);
|
|
168
|
+
if (valid) {
|
|
169
|
+
console.log(`All traceability annotations under ${root} are valid.`);
|
|
170
|
+
return EXIT_OK;
|
|
171
|
+
}
|
|
172
|
+
console.log(`Stale or invalid traceability annotations detected under ${root}.\nRun 'traceability-maint detect' or 'traceability-maint report' for details.`);
|
|
173
|
+
return EXIT_STALE;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Handle the `report` subcommand to generate a maintenance report.
|
|
177
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
178
|
+
* @req REQ-MAINT-REPORT - CLI surface for human-readable maintenance reports
|
|
179
|
+
* @req REQ-MAINT-SAFE - Support machine-readable formats for safe automation
|
|
180
|
+
*/
|
|
181
|
+
function handleReport(args) {
|
|
182
|
+
const flags = parseFlags(args);
|
|
183
|
+
const root = flags.root;
|
|
184
|
+
const format = flags.format ?? "text";
|
|
185
|
+
const report = (0, report_1.generateMaintenanceReport)(root);
|
|
186
|
+
if (format === "json") {
|
|
187
|
+
console.log(JSON.stringify({ root, report }));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
if (!report) {
|
|
191
|
+
console.log("No stale @story annotations found. Nothing to report.");
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
console.log(`# Traceability Maintenance Report for ${root}`);
|
|
195
|
+
console.log("");
|
|
196
|
+
console.log("Stale story references:");
|
|
197
|
+
console.log(report);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return EXIT_OK;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Handle the `update` subcommand to rewrite @story annotation references.
|
|
204
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
205
|
+
* @req REQ-MAINT-UPDATE - CLI surface for updating annotation references
|
|
206
|
+
* @req REQ-MAINT-SAFE - Provide dry-run mode and explicit parameter checks
|
|
207
|
+
*/
|
|
208
|
+
function handleUpdate(args) {
|
|
209
|
+
const flags = parseFlags(args);
|
|
210
|
+
const root = flags.root;
|
|
211
|
+
if (!flags.from || !flags.to) {
|
|
212
|
+
console.error("'update' requires --from <oldPath> and --to <newPath>.");
|
|
213
|
+
printHelp();
|
|
214
|
+
return EXIT_USAGE;
|
|
215
|
+
}
|
|
216
|
+
const from = flags.from;
|
|
217
|
+
const to = flags.to;
|
|
218
|
+
if (flags.dryRun) {
|
|
219
|
+
// For now, we cannot get a per-file diff without changing the maintenance API.
|
|
220
|
+
// We conservatively reuse generateMaintenanceReport to indicate potential impact.
|
|
221
|
+
const beforeReport = (0, report_1.generateMaintenanceReport)(root);
|
|
222
|
+
const potentialChanges = beforeReport ? beforeReport.split("\n").length : 0;
|
|
223
|
+
const summary = {
|
|
224
|
+
root,
|
|
225
|
+
from,
|
|
226
|
+
to,
|
|
227
|
+
estimatedStaleCount: potentialChanges,
|
|
228
|
+
};
|
|
229
|
+
if (flags.json) {
|
|
230
|
+
console.log(JSON.stringify({ mode: "dry-run", ...summary }));
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
console.log("Dry run: no files were modified.");
|
|
234
|
+
console.log(`Would update @story annotations from '${from}' to '${to}' under ${root}.`);
|
|
235
|
+
console.log(`Estimated stale annotations before update: ${summary.estimatedStaleCount}.`);
|
|
236
|
+
}
|
|
237
|
+
return EXIT_OK;
|
|
238
|
+
}
|
|
239
|
+
const count = (0, update_1.updateAnnotationReferences)(root, from, to);
|
|
240
|
+
if (flags.json) {
|
|
241
|
+
console.log(JSON.stringify({ root, from, to, updated: count }));
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
console.log(`Updated ${count} @story annotation${count === 1 ? "" : "s"} from '${from}' to '${to}' under ${root}.`);
|
|
245
|
+
}
|
|
246
|
+
return EXIT_OK;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Print CLI usage help for the maintenance tools.
|
|
250
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
251
|
+
* @req REQ-MAINT-SAFE - Provide discoverable CLI usage information
|
|
252
|
+
*/
|
|
253
|
+
function printHelp() {
|
|
254
|
+
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
255
|
+
// @req REQ-MAINT-SAFE - Provide discoverable CLI usage information
|
|
256
|
+
console.log(`traceability-maint - Traceability annotation maintenance tools
|
|
257
|
+
|
|
258
|
+
Usage:
|
|
259
|
+
traceability-maint <command> [options]
|
|
260
|
+
|
|
261
|
+
Commands:
|
|
262
|
+
detect Detect stale @story annotations
|
|
263
|
+
verify Verify that traceability annotations are valid
|
|
264
|
+
report Generate a maintenance report
|
|
265
|
+
update Update @story annotation references
|
|
266
|
+
|
|
267
|
+
Options:
|
|
268
|
+
--root <dir> Workspace root to scan (defaults to current directory)
|
|
269
|
+
--json Output JSON where supported
|
|
270
|
+
--format <text|json> Output format for 'report' (default: text)
|
|
271
|
+
--from <oldPath> Old story path for 'update'
|
|
272
|
+
--to <newPath> New story path for 'update'
|
|
273
|
+
--dry-run Plan changes for 'update' without modifying files
|
|
274
|
+
-h, --help Show this help message
|
|
275
|
+
`);
|
|
276
|
+
}
|
|
277
|
+
if (require.main === module) {
|
|
278
|
+
process.exit(runMaintenanceCli(process.argv));
|
|
279
|
+
}
|
|
@@ -101,6 +101,25 @@ function handleStoryMatch(storyPath, workspaceRoot, cwd, stale) {
|
|
|
101
101
|
const storyCodebaseCandidate = path.resolve(workspaceRoot, storyPath);
|
|
102
102
|
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
103
103
|
// @req REQ-MAINT-DETECT - Enforce workspaceRoot as the project boundary for resolved story paths
|
|
104
|
+
const inProjectCandidates = getInProjectCandidates(storyProjectCandidate, storyCodebaseCandidate, workspaceRoot);
|
|
105
|
+
// If both candidates are out-of-project, do not mark as stale and skip FS checks
|
|
106
|
+
if (inProjectCandidates.length === 0) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
110
|
+
// @req REQ-MAINT-DETECT - Only check existence for in-project candidates
|
|
111
|
+
const anyExists = anyInProjectCandidateExists(inProjectCandidates);
|
|
112
|
+
// @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
113
|
+
// @req REQ-MAINT-DETECT - Mark story as stale if any in-project candidate exists conceptually but none exist on disk
|
|
114
|
+
if (!anyExists) {
|
|
115
|
+
stale.add(storyPath);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
120
|
+
* @req REQ-MAINT-DETECT - Enforce project boundary and return in-project candidates
|
|
121
|
+
*/
|
|
122
|
+
function getInProjectCandidates(storyProjectCandidate, storyCodebaseCandidate, workspaceRoot) {
|
|
104
123
|
let projectBoundary;
|
|
105
124
|
let codebaseBoundary;
|
|
106
125
|
try {
|
|
@@ -128,16 +147,12 @@ function handleStoryMatch(storyPath, workspaceRoot, cwd, stale) {
|
|
|
128
147
|
if (codebaseBoundary.isWithinProject) {
|
|
129
148
|
inProjectCandidates.push(codebaseBoundary.candidate);
|
|
130
149
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// @req REQ-MAINT-DETECT - Mark story as stale if any in-project candidate exists conceptually but none exist on disk
|
|
140
|
-
if (!anyExists) {
|
|
141
|
-
stale.add(storyPath);
|
|
142
|
-
}
|
|
150
|
+
return inProjectCandidates;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
|
|
154
|
+
* @req REQ-MAINT-DETECT - Check on-disk existence of in-project candidates
|
|
155
|
+
*/
|
|
156
|
+
function anyInProjectCandidateExists(inProjectCandidates) {
|
|
157
|
+
return inProjectCandidates.some((p) => fs.existsSync(p));
|
|
143
158
|
}
|