eslint-plugin-traceability 1.5.1 → 1.6.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 +2 -0
- package/lib/src/rules/helpers/require-story-helpers.d.ts +4 -0
- package/lib/src/rules/helpers/require-story-helpers.js +6 -0
- package/lib/src/rules/require-branch-annotation.d.ts +11 -4
- package/lib/src/rules/require-branch-annotation.js +18 -4
- package/lib/src/rules/require-req-annotation.d.ts +9 -4
- package/lib/src/rules/require-req-annotation.js +69 -21
- package/lib/src/rules/require-story-annotation.d.ts +6 -0
- package/lib/src/rules/require-story-annotation.js +15 -1
- package/lib/src/rules/valid-annotation-format.js +154 -6
- package/lib/src/rules/valid-req-reference.js +30 -51
- package/lib/src/utils/annotation-checker.d.ts +7 -1
- package/lib/src/utils/annotation-checker.js +51 -8
- package/lib/tests/rules/auto-fix-behavior-008.test.d.ts +1 -0
- package/lib/tests/rules/auto-fix-behavior-008.test.js +160 -0
- package/lib/tests/rules/error-reporting.test.js +1 -0
- package/lib/tests/rules/require-req-annotation.test.js +139 -4
- package/lib/tests/rules/require-story-annotation.test.js +7 -0
- package/lib/tests/rules/valid-annotation-format.test.js +2 -0
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -55,6 +55,8 @@ module.exports = [
|
|
|
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
57
|
|
|
58
|
+
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
|
+
|
|
58
60
|
For development and contribution guidelines, see docs/eslint-plugin-development-guide.md.
|
|
59
61
|
|
|
60
62
|
## Quick Start
|
|
@@ -100,7 +100,9 @@ declare function shouldProcessNode(node: any, scope: string[], exportPriority?:
|
|
|
100
100
|
* Report a missing @story annotation for a function-like node
|
|
101
101
|
* Provides a suggestion to add the annotation.
|
|
102
102
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
103
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
103
104
|
* @req REQ-ANNOTATION-REQUIRED - Implement reporting for missing annotations with suggestion
|
|
105
|
+
* @req REQ-AUTOFIX-MISSING - Provide autofix for missing annotations while preserving suggestions
|
|
104
106
|
* @param {Rule.RuleContext} context - ESLint rule context used to report
|
|
105
107
|
* @param {any} sourceCode - ESLint sourceCode object
|
|
106
108
|
* @param {any} node - AST node that is missing the annotation
|
|
@@ -111,7 +113,9 @@ declare function reportMissing(context: Rule.RuleContext, sourceCode: any, node:
|
|
|
111
113
|
* Report a missing @story annotation for a method-like node
|
|
112
114
|
* Provides a suggestion to update the method/interface with the annotation.
|
|
113
115
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
116
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
114
117
|
* @req REQ-ANNOTATION-REQUIRED - Implement reporting for missing method/interface annotations with suggestion
|
|
118
|
+
* @req REQ-AUTOFIX-MISSING - Provide autofix for missing method/interface annotations while preserving suggestions
|
|
115
119
|
* @param {Rule.RuleContext} context - ESLint rule context to report
|
|
116
120
|
* @param {any} sourceCode - ESLint sourceCode object
|
|
117
121
|
* @param {any} node - AST node that is missing the annotation
|
|
@@ -238,7 +238,9 @@ function shouldProcessNode(node, scope, exportPriority = "all") {
|
|
|
238
238
|
* Report a missing @story annotation for a function-like node
|
|
239
239
|
* Provides a suggestion to add the annotation.
|
|
240
240
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
241
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
241
242
|
* @req REQ-ANNOTATION-REQUIRED - Implement reporting for missing annotations with suggestion
|
|
243
|
+
* @req REQ-AUTOFIX-MISSING - Provide autofix for missing annotations while preserving suggestions
|
|
242
244
|
* @param {Rule.RuleContext} context - ESLint rule context used to report
|
|
243
245
|
* @param {any} sourceCode - ESLint sourceCode object
|
|
244
246
|
* @param {any} node - AST node that is missing the annotation
|
|
@@ -259,6 +261,7 @@ function reportMissing(context, sourceCode, node, passedTarget) {
|
|
|
259
261
|
node: nameNode,
|
|
260
262
|
messageId: "missingStory",
|
|
261
263
|
data: { name },
|
|
264
|
+
fix: (0, require_story_core_1.createAddStoryFix)(resolvedTarget),
|
|
262
265
|
suggest: [
|
|
263
266
|
{
|
|
264
267
|
desc: `Add JSDoc @story annotation for function '${name}', e.g., ${ANNOTATION}`,
|
|
@@ -275,7 +278,9 @@ function reportMissing(context, sourceCode, node, passedTarget) {
|
|
|
275
278
|
* Report a missing @story annotation for a method-like node
|
|
276
279
|
* Provides a suggestion to update the method/interface with the annotation.
|
|
277
280
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
281
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
278
282
|
* @req REQ-ANNOTATION-REQUIRED - Implement reporting for missing method/interface annotations with suggestion
|
|
283
|
+
* @req REQ-AUTOFIX-MISSING - Provide autofix for missing method/interface annotations while preserving suggestions
|
|
279
284
|
* @param {Rule.RuleContext} context - ESLint rule context to report
|
|
280
285
|
* @param {any} sourceCode - ESLint sourceCode object
|
|
281
286
|
* @param {any} node - AST node that is missing the annotation
|
|
@@ -293,6 +298,7 @@ function reportMethod(context, sourceCode, node, passedTarget) {
|
|
|
293
298
|
node: nameNode,
|
|
294
299
|
messageId: "missingStory",
|
|
295
300
|
data: { name },
|
|
301
|
+
fix: (0, require_story_core_1.createMethodFix)(resolvedTarget),
|
|
296
302
|
suggest: [
|
|
297
303
|
{
|
|
298
304
|
desc: `Add JSDoc @story annotation for function '${name}', e.g., ${ANNOTATION}`,
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
* Rule to enforce @story and @req annotations on significant code branches
|
|
1
|
+
/**
|
|
2
|
+
* Rule to enforce @story and @req annotations on significant code branches.
|
|
3
|
+
*
|
|
3
4
|
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
4
|
-
* @req REQ-BRANCH-DETECTION
|
|
5
|
-
* @req REQ-CONFIGURABLE-SCOPE
|
|
5
|
+
* @req REQ-BRANCH-DETECTION
|
|
6
|
+
* @req REQ-CONFIGURABLE-SCOPE
|
|
6
7
|
*/
|
|
7
8
|
import type { Rule } from "eslint";
|
|
9
|
+
/**
|
|
10
|
+
* ESLint rule definition for require-branch-annotation.
|
|
11
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
12
|
+
* @req REQ-BRANCH-DETECTION - Enforce @story/@req presence on configured branch types
|
|
13
|
+
* @req REQ-CONFIGURABLE-SCOPE - Respect configurable branchTypes option
|
|
14
|
+
*/
|
|
8
15
|
declare const rule: Rule.RuleModule;
|
|
9
16
|
export default rule;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const branch_annotation_helpers_1 = require("../utils/branch-annotation-helpers");
|
|
4
|
+
/**
|
|
5
|
+
* ESLint rule definition for require-branch-annotation.
|
|
6
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
7
|
+
* @req REQ-BRANCH-DETECTION - Enforce @story/@req presence on configured branch types
|
|
8
|
+
* @req REQ-CONFIGURABLE-SCOPE - Respect configurable branchTypes option
|
|
9
|
+
*/
|
|
4
10
|
const rule = {
|
|
5
11
|
meta: {
|
|
6
12
|
type: "problem",
|
|
@@ -28,12 +34,20 @@ const rule = {
|
|
|
28
34
|
},
|
|
29
35
|
/**
|
|
30
36
|
* Create visitor for require-branch-annotation rule.
|
|
37
|
+
*
|
|
31
38
|
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
32
|
-
* @req REQ-BRANCH-DETECTION
|
|
33
|
-
* @req REQ-CONFIGURABLE-SCOPE
|
|
39
|
+
* @req REQ-BRANCH-DETECTION
|
|
40
|
+
* @req REQ-CONFIGURABLE-SCOPE
|
|
34
41
|
*/
|
|
35
42
|
create(context) {
|
|
36
43
|
const branchTypesOrListener = (0, branch_annotation_helpers_1.validateBranchTypes)(context);
|
|
44
|
+
/**
|
|
45
|
+
* Branch configuration guard: if validation returns a listener, use it directly
|
|
46
|
+
* instead of branch-type iteration.
|
|
47
|
+
*
|
|
48
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
49
|
+
* @req REQ-CONFIGURABLE-SCOPE
|
|
50
|
+
*/
|
|
37
51
|
if (!Array.isArray(branchTypesOrListener)) {
|
|
38
52
|
return branchTypesOrListener;
|
|
39
53
|
}
|
|
@@ -44,8 +58,8 @@ const rule = {
|
|
|
44
58
|
/**
|
|
45
59
|
* Handler for a specific branch node type.
|
|
46
60
|
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
47
|
-
* @req REQ-BRANCH-DETECTION
|
|
48
|
-
* @req REQ-CONFIGURABLE-SCOPE
|
|
61
|
+
* @req REQ-BRANCH-DETECTION
|
|
62
|
+
* @req REQ-CONFIGURABLE-SCOPE
|
|
49
63
|
*/
|
|
50
64
|
handlers[type] = function branchHandler(node) {
|
|
51
65
|
if (type === "SwitchCase" && node.test == null) {
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/****
|
|
2
|
+
* Rule to enforce @req annotation on functions
|
|
2
3
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
3
|
-
* @req REQ-RULE-EXPORT - Export the rule object for ESLint
|
|
4
4
|
* @req REQ-ANNOTATION-REQUIRED - Require @req annotation on functions
|
|
5
|
+
* @req REQ-FUNCTION-DETECTION - Detect function declarations, function expressions, and method definitions (including TypeScript declarations)
|
|
6
|
+
* @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
|
|
7
|
+
* @req REQ-CONFIGURABLE-SCOPE - Allow configuration of which exports are checked
|
|
8
|
+
* @req REQ-EXPORT-PRIORITY - Allow configuration of export priority behavior
|
|
5
9
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
import type { Rule } from "eslint";
|
|
11
|
+
declare const rule: Rule.RuleModule;
|
|
12
|
+
export default rule;
|
|
@@ -1,37 +1,59 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
* Rule to enforce @req annotation on functions
|
|
5
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
6
|
-
* @req REQ-ANNOTATION-REQUIRED - Require @req annotation on functions
|
|
7
|
-
* @req REQ-FUNCTION-DETECTION - Detect function declarations, expressions, arrow functions, and methods
|
|
8
|
-
* @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
|
|
9
|
-
*/
|
|
3
|
+
const require_story_helpers_1 = require("./helpers/require-story-helpers");
|
|
10
4
|
const annotation_checker_1 = require("../utils/annotation-checker");
|
|
11
|
-
|
|
12
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
13
|
-
* @req REQ-RULE-EXPORT - Export the rule object for ESLint
|
|
14
|
-
* @req REQ-ANNOTATION-REQUIRED - Require @req annotation on functions
|
|
15
|
-
*/
|
|
16
|
-
exports.default = {
|
|
5
|
+
const rule = {
|
|
17
6
|
meta: {
|
|
18
7
|
type: "problem",
|
|
19
8
|
fixable: "code",
|
|
20
9
|
docs: {
|
|
21
|
-
description: "Require @req annotations on functions",
|
|
10
|
+
description: "Require @req annotations on function-like exports (declarations, expressions, and methods, excluding arrow functions)",
|
|
22
11
|
recommended: "error",
|
|
23
12
|
},
|
|
24
13
|
messages: {
|
|
25
14
|
missingReq: "Missing @req annotation for function '{{name}}' (REQ-ANNOTATION-REQUIRED)",
|
|
26
15
|
},
|
|
27
|
-
schema: [
|
|
16
|
+
schema: [
|
|
17
|
+
{
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
scope: {
|
|
21
|
+
type: "array",
|
|
22
|
+
items: {
|
|
23
|
+
enum: require_story_helpers_1.DEFAULT_SCOPE,
|
|
24
|
+
},
|
|
25
|
+
uniqueItems: true,
|
|
26
|
+
},
|
|
27
|
+
exportPriority: {
|
|
28
|
+
enum: require_story_helpers_1.EXPORT_PRIORITY_VALUES,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
additionalProperties: false,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
28
34
|
},
|
|
29
35
|
/**
|
|
30
36
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
31
37
|
* @req REQ-CREATE-HOOK - Provide create(context) hook for rule behavior
|
|
32
|
-
* @req REQ-FUNCTION-DETECTION - Detect function declarations, expressions,
|
|
38
|
+
* @req REQ-FUNCTION-DETECTION - Detect function declarations, function expressions, and method definitions (including TS-specific nodes)
|
|
39
|
+
* @req REQ-CONFIGURABLE-SCOPE - Respect configurable scope of which exports are checked
|
|
40
|
+
* @req REQ-EXPORT-PRIORITY - Respect configurable export priority when determining which nodes to check
|
|
33
41
|
*/
|
|
34
42
|
create(context) {
|
|
43
|
+
const options = context.options?.[0] ?? {};
|
|
44
|
+
const rawScope = options?.scope;
|
|
45
|
+
const scope = Array.isArray(rawScope) && rawScope.length > 0 ? rawScope : require_story_helpers_1.DEFAULT_SCOPE;
|
|
46
|
+
const exportPriority = options?.exportPriority ?? "all";
|
|
47
|
+
const shouldCheck = (node) => (0, require_story_helpers_1.shouldProcessNode)(node, scope, exportPriority);
|
|
48
|
+
/**
|
|
49
|
+
* Helper to conditionally run the annotation check only when the node
|
|
50
|
+
* should be processed according to scope/exportPriority.
|
|
51
|
+
*/
|
|
52
|
+
const runCheck = (node) => {
|
|
53
|
+
if (!shouldCheck(node))
|
|
54
|
+
return;
|
|
55
|
+
(0, annotation_checker_1.checkReqAnnotation)(context, node, { enableFix: false });
|
|
56
|
+
};
|
|
35
57
|
return {
|
|
36
58
|
/**
|
|
37
59
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
@@ -39,18 +61,44 @@ exports.default = {
|
|
|
39
61
|
* @req REQ-ANNOTATION-REQUIRED - Enforce @req annotation on function declarations
|
|
40
62
|
*/
|
|
41
63
|
FunctionDeclaration(node) {
|
|
42
|
-
|
|
64
|
+
runCheck(node);
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
68
|
+
* @req REQ-FUNCTION-DETECTION - Detect function expressions
|
|
69
|
+
* @req REQ-ANNOTATION-REQUIRED - Enforce @req annotation on function expressions
|
|
70
|
+
*/
|
|
71
|
+
FunctionExpression(node) {
|
|
72
|
+
if (node.parent && node.parent.type === "MethodDefinition") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
runCheck(node);
|
|
43
76
|
},
|
|
44
77
|
/**
|
|
45
78
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
46
|
-
* @req REQ-
|
|
79
|
+
* @req REQ-FUNCTION-DETECTION - Detect method definitions
|
|
80
|
+
* @req REQ-ANNOTATION-REQUIRED - Enforce @req annotation on method definitions
|
|
47
81
|
*/
|
|
48
|
-
|
|
82
|
+
MethodDefinition(node) {
|
|
83
|
+
runCheck(node);
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
87
|
+
* @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript declare functions
|
|
88
|
+
* @req REQ-ANNOTATION-REQUIRED - Enforce @req annotation on TS declare functions
|
|
89
|
+
*/
|
|
90
|
+
TSDeclareFunction(node) {
|
|
91
|
+
runCheck(node);
|
|
92
|
+
},
|
|
49
93
|
/**
|
|
50
94
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
51
|
-
* @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript
|
|
95
|
+
* @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript method signatures
|
|
96
|
+
* @req REQ-ANNOTATION-REQUIRED - Enforce @req annotation on TS method signatures
|
|
52
97
|
*/
|
|
53
|
-
TSMethodSignature
|
|
98
|
+
TSMethodSignature(node) {
|
|
99
|
+
runCheck(node);
|
|
100
|
+
},
|
|
54
101
|
};
|
|
55
102
|
},
|
|
56
103
|
};
|
|
104
|
+
exports.default = rule;
|
|
@@ -5,14 +5,20 @@
|
|
|
5
5
|
* on functions and methods according to configured scope and export priority.
|
|
6
6
|
*
|
|
7
7
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
8
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
8
9
|
* @req REQ-ANNOTATION-REQUIRED
|
|
10
|
+
* @req REQ-AUTOFIX-MISSING - This rule supports auto-fixing missing @story annotations per Story 008.0 auto-fix behavior.
|
|
11
|
+
* @req REQ-AUTOFIX-SAFE - Auto-fix behavior only inserts @story annotation JSDoc comments and never changes executable or runtime code.
|
|
12
|
+
* @req REQ-AUTOFIX-PRESERVE - Auto-fix inserts a minimal placeholder JSDoc in a way that preserves existing surrounding formatting and structure.
|
|
9
13
|
*/
|
|
10
14
|
import type { Rule } from "eslint";
|
|
11
15
|
/**
|
|
12
16
|
* ESLint rule to require @story annotations on functions/methods.
|
|
13
17
|
*
|
|
14
18
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
19
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
15
20
|
* @req REQ-ANNOTATION-REQUIRED
|
|
21
|
+
* @req REQ-AUTOFIX-MISSING - This rule participates in auto-fix for missing @story annotations.
|
|
16
22
|
*/
|
|
17
23
|
declare const rule: Rule.RuleModule;
|
|
18
24
|
export default rule;
|
|
@@ -6,16 +6,28 @@ const require_story_helpers_1 = require("./helpers/require-story-helpers");
|
|
|
6
6
|
* ESLint rule to require @story annotations on functions/methods.
|
|
7
7
|
*
|
|
8
8
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
9
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
9
10
|
* @req REQ-ANNOTATION-REQUIRED
|
|
11
|
+
* @req REQ-AUTOFIX-MISSING - This rule participates in auto-fix for missing @story annotations.
|
|
10
12
|
*/
|
|
11
13
|
const rule = {
|
|
12
14
|
meta: {
|
|
13
15
|
type: "problem",
|
|
14
16
|
docs: {
|
|
15
|
-
description: "Require @story annotations on functions",
|
|
17
|
+
description: "Require @story annotations on functions and auto-fix missing annotations where possible",
|
|
16
18
|
recommended: "error",
|
|
17
19
|
},
|
|
18
20
|
hasSuggestions: true,
|
|
21
|
+
/**
|
|
22
|
+
* Auto-fix support for inserting @story annotations.
|
|
23
|
+
*
|
|
24
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
25
|
+
* @req REQ-ANNOTATION-REQUIRED
|
|
26
|
+
* @req REQ-AUTOFIX-MISSING - `fixable: \"code\"` is used to implement REQ-AUTOFIX-MISSING for missing @story annotations.
|
|
27
|
+
* @req REQ-AUTOFIX-SAFE - Auto-fix is conservative and only adds a single-line JSDoc @story annotation without modifying existing runtime expressions.
|
|
28
|
+
* @req REQ-AUTOFIX-PRESERVE - Auto-fix behavior preserves surrounding code formatting and indentation when inserting the placeholder JSDoc.
|
|
29
|
+
*/
|
|
30
|
+
fixable: "code",
|
|
19
31
|
messages: {
|
|
20
32
|
missingStory: "Missing @story annotation for function '{{name}}' (REQ-ANNOTATION-REQUIRED)",
|
|
21
33
|
},
|
|
@@ -38,7 +50,9 @@ const rule = {
|
|
|
38
50
|
* Create the rule visitor functions.
|
|
39
51
|
*
|
|
40
52
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
53
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
41
54
|
* @req REQ-CREATE-HOOK
|
|
55
|
+
* @req REQ-AUTOFIX-MISSING - The create hook wires in visitors that are capable of providing auto-fix suggestions for missing @story annotations.
|
|
42
56
|
*/
|
|
43
57
|
create(context) {
|
|
44
58
|
const sourceCode = context.getSourceCode();
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const STORY_EXAMPLE_PATH = "docs/stories/005.0-DEV-EXAMPLE.story.md";
|
|
4
|
+
/**
|
|
5
|
+
* Constant to represent the "tag not found" index when searching
|
|
6
|
+
* for @story or @req within a comment.
|
|
7
|
+
*
|
|
8
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
9
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
10
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
11
|
+
* @req REQ-AUTOFIX-PRESERVE - Avoid risky text replacements when the annotation tag cannot be located
|
|
12
|
+
*/
|
|
13
|
+
const TAG_NOT_FOUND_INDEX = -1;
|
|
4
14
|
/**
|
|
5
15
|
* Normalize a raw comment line to make annotation parsing more robust.
|
|
6
16
|
*
|
|
@@ -8,7 +18,9 @@ const STORY_EXAMPLE_PATH = "docs/stories/005.0-DEV-EXAMPLE.story.md";
|
|
|
8
18
|
* later in the line, and supports common JSDoc styles such as leading "*".
|
|
9
19
|
*
|
|
10
20
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
21
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
11
22
|
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
23
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
12
24
|
*/
|
|
13
25
|
function normalizeCommentLine(rawLine) {
|
|
14
26
|
const trimmed = rawLine.trim();
|
|
@@ -31,7 +43,9 @@ function normalizeCommentLine(rawLine) {
|
|
|
31
43
|
* multiple lines will be collapsed before validation.
|
|
32
44
|
*
|
|
33
45
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
46
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
34
47
|
* @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
|
|
48
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
35
49
|
*/
|
|
36
50
|
function collapseAnnotationValue(value) {
|
|
37
51
|
return value.replace(/\s+/g, "");
|
|
@@ -40,7 +54,9 @@ function collapseAnnotationValue(value) {
|
|
|
40
54
|
* Build a detailed error message for invalid @story annotations.
|
|
41
55
|
*
|
|
42
56
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
57
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
43
58
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
59
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
44
60
|
*/
|
|
45
61
|
function buildStoryErrorMessage(kind, value) {
|
|
46
62
|
if (kind === "missing") {
|
|
@@ -52,7 +68,9 @@ function buildStoryErrorMessage(kind, value) {
|
|
|
52
68
|
* Build a detailed error message for invalid @req annotations.
|
|
53
69
|
*
|
|
54
70
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
71
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
55
72
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
73
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
56
74
|
*/
|
|
57
75
|
function buildReqErrorMessage(kind, value) {
|
|
58
76
|
if (kind === "missing") {
|
|
@@ -60,12 +78,111 @@ function buildReqErrorMessage(kind, value) {
|
|
|
60
78
|
}
|
|
61
79
|
return `Invalid requirement ID "${value ?? ""}" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).`;
|
|
62
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Attempt a minimal, safe auto-fix for common @story path suffix issues.
|
|
83
|
+
*
|
|
84
|
+
* Only handles:
|
|
85
|
+
* - missing ".md"
|
|
86
|
+
* - missing ".story.md"
|
|
87
|
+
* and skips any paths with traversal segments (e.g. "..").
|
|
88
|
+
*
|
|
89
|
+
* Returns the fixed path when safe, or null if no fix should be applied.
|
|
90
|
+
*
|
|
91
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
92
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
93
|
+
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and never broaden the referenced path
|
|
94
|
+
* @req REQ-AUTOFIX-PRESERVE - Preserve surrounding formatting when normalizing story path suffixes
|
|
95
|
+
*/
|
|
96
|
+
function getFixedStoryPath(original) {
|
|
97
|
+
if (original.includes("..")) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (/\.story\.md$/.test(original)) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (/\.story$/.test(original)) {
|
|
104
|
+
return `${original}.md`;
|
|
105
|
+
}
|
|
106
|
+
if (/\.md$/.test(original)) {
|
|
107
|
+
return original.replace(/\.md$/, ".story.md");
|
|
108
|
+
}
|
|
109
|
+
return `${original}.story.md`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Report an invalid @story annotation without applying a fix.
|
|
113
|
+
*
|
|
114
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
115
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
116
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
117
|
+
*/
|
|
118
|
+
function reportInvalidStoryFormat(context, comment, collapsed) {
|
|
119
|
+
context.report({
|
|
120
|
+
node: comment,
|
|
121
|
+
messageId: "invalidStoryFormat",
|
|
122
|
+
data: { details: buildStoryErrorMessage("invalid", collapsed) },
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Report an invalid @story annotation and attempt a minimal, safe auto-fix
|
|
127
|
+
* for common path suffix issues by locating and replacing the path text
|
|
128
|
+
* within the original comment.
|
|
129
|
+
*
|
|
130
|
+
* This helper:
|
|
131
|
+
* - only adjusts the story path suffix when a safe, well-understood
|
|
132
|
+
* transformation is available, satisfying REQ-AUTOFIX-SAFE.
|
|
133
|
+
* - preserves all surrounding comment formatting, spacing, and text
|
|
134
|
+
* outside the path substring, satisfying REQ-AUTOFIX-PRESERVE.
|
|
135
|
+
*
|
|
136
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
137
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
138
|
+
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
139
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
140
|
+
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and avoid changing semantics
|
|
141
|
+
* @req REQ-AUTOFIX-PRESERVE - Auto-fix must preserve surrounding formatting and comments
|
|
142
|
+
*/
|
|
143
|
+
function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
144
|
+
const sourceCode = context.getSourceCode();
|
|
145
|
+
const commentText = sourceCode.getText(comment);
|
|
146
|
+
const search = "@story";
|
|
147
|
+
const tagIndex = commentText.indexOf(search);
|
|
148
|
+
if (tagIndex === TAG_NOT_FOUND_INDEX) {
|
|
149
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const afterTagIndex = tagIndex + search.length;
|
|
153
|
+
const rest = commentText.slice(afterTagIndex);
|
|
154
|
+
const valueMatch = rest.match(/[^\S\r\n]*([^\r\n*]+)/);
|
|
155
|
+
if (!valueMatch || valueMatch.index === undefined) {
|
|
156
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const valueStartInComment = afterTagIndex +
|
|
160
|
+
valueMatch.index +
|
|
161
|
+
(valueMatch[0].length - valueMatch[1].length);
|
|
162
|
+
const valueEndInComment = valueStartInComment + valueMatch[1].length;
|
|
163
|
+
const start = comment.range[0];
|
|
164
|
+
const fixRange = [
|
|
165
|
+
start + valueStartInComment,
|
|
166
|
+
start + valueEndInComment,
|
|
167
|
+
];
|
|
168
|
+
context.report({
|
|
169
|
+
node: comment,
|
|
170
|
+
messageId: "invalidStoryFormat",
|
|
171
|
+
data: { details: buildStoryErrorMessage("invalid", collapsed) },
|
|
172
|
+
fix(fixer) {
|
|
173
|
+
return fixer.replaceTextRange(fixRange, fixed);
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
}
|
|
63
177
|
/**
|
|
64
178
|
* Validate a @story annotation value and report detailed errors when needed.
|
|
179
|
+
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
65
180
|
*
|
|
66
181
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
182
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
67
183
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
68
184
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
185
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
69
186
|
*/
|
|
70
187
|
function validateStoryAnnotation(context, comment, rawValue) {
|
|
71
188
|
const trimmed = rawValue.trim();
|
|
@@ -79,18 +196,25 @@ function validateStoryAnnotation(context, comment, rawValue) {
|
|
|
79
196
|
}
|
|
80
197
|
const collapsed = collapseAnnotationValue(trimmed);
|
|
81
198
|
const pathPattern = /^docs\/stories\/[0-9]+\.[0-9]+-DEV-[\w-]+\.story\.md$/;
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
199
|
+
if (pathPattern.test(collapsed)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (/\s/.test(trimmed)) {
|
|
203
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const fixed = getFixedStoryPath(collapsed);
|
|
207
|
+
if (fixed && pathPattern.test(fixed)) {
|
|
208
|
+
reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed);
|
|
209
|
+
return;
|
|
88
210
|
}
|
|
211
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
89
212
|
}
|
|
90
213
|
/**
|
|
91
214
|
* Validate a @req annotation value and report detailed errors when needed.
|
|
92
215
|
*
|
|
93
216
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
217
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
94
218
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
95
219
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
96
220
|
*/
|
|
@@ -122,8 +246,10 @@ function validateReqAnnotation(context, comment, rawValue) {
|
|
|
122
246
|
* validated against the configured patterns.
|
|
123
247
|
*
|
|
124
248
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
249
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
125
250
|
* @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
|
|
126
251
|
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
252
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
127
253
|
*/
|
|
128
254
|
function processComment(context, comment) {
|
|
129
255
|
const rawLines = (comment.value || "").split(/\r?\n/);
|
|
@@ -132,14 +258,18 @@ function processComment(context, comment) {
|
|
|
132
258
|
* Finalize and validate the currently pending annotation, if any.
|
|
133
259
|
*
|
|
134
260
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
261
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
135
262
|
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
263
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
136
264
|
*/
|
|
137
265
|
function finalizePending() {
|
|
138
266
|
if (!pending) {
|
|
139
267
|
return;
|
|
140
268
|
}
|
|
141
269
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
270
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
142
271
|
// @req REQ-SYNTAX-VALIDATION - Dispatch validation based on annotation type
|
|
272
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
143
273
|
if (pending.type === "story") {
|
|
144
274
|
validateStoryAnnotation(context, comment, pending.value);
|
|
145
275
|
}
|
|
@@ -156,7 +286,9 @@ function processComment(context, comment) {
|
|
|
156
286
|
const isStory = /@story\b/.test(normalized);
|
|
157
287
|
const isReq = /@req\b/.test(normalized);
|
|
158
288
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
289
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
159
290
|
// @req REQ-SYNTAX-VALIDATION - Start new pending annotation when a tag is found
|
|
291
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
160
292
|
if (isStory || isReq) {
|
|
161
293
|
finalizePending();
|
|
162
294
|
const value = normalized.replace(/^@story\b|^@req\b/, "").trim();
|
|
@@ -168,7 +300,9 @@ function processComment(context, comment) {
|
|
|
168
300
|
return;
|
|
169
301
|
}
|
|
170
302
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
303
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
171
304
|
// @req REQ-MULTILINE-SUPPORT - Treat subsequent lines as continuation for pending annotation
|
|
305
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
172
306
|
if (pending) {
|
|
173
307
|
const continuation = normalized.trim();
|
|
174
308
|
if (!continuation) {
|
|
@@ -194,11 +328,23 @@ exports.default = {
|
|
|
194
328
|
invalidReqFormat: "{{details}}",
|
|
195
329
|
},
|
|
196
330
|
schema: [],
|
|
331
|
+
/**
|
|
332
|
+
* This rule's fixable support is limited to safe @story path suffix normalization per Story 008.0.
|
|
333
|
+
* Fixes are limited strictly to adjusting the suffix portion of the @story path (e.g., adding
|
|
334
|
+
* `.md` or `.story.md`), preserving all other comment text and whitespace exactly as written.
|
|
335
|
+
*
|
|
336
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
337
|
+
* @req REQ-AUTOFIX-SAFE
|
|
338
|
+
* @req REQ-AUTOFIX-PRESERVE
|
|
339
|
+
*/
|
|
340
|
+
fixable: "code",
|
|
197
341
|
},
|
|
198
342
|
/**
|
|
199
343
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
344
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
200
345
|
* @req REQ-SYNTAX-VALIDATION - Ensure rule create function validates annotations syntax
|
|
201
346
|
* @req REQ-FORMAT-SPECIFICATION - Implement formatting checks per specification
|
|
347
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
202
348
|
*/
|
|
203
349
|
create(context) {
|
|
204
350
|
const sourceCode = context.getSourceCode();
|
|
@@ -207,8 +353,10 @@ exports.default = {
|
|
|
207
353
|
* Program-level handler that inspects all comments for @story and @req tags
|
|
208
354
|
*
|
|
209
355
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
356
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
210
357
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
211
358
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
359
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
212
360
|
*/
|
|
213
361
|
Program() {
|
|
214
362
|
const comments = sourceCode.getAllComments() || [];
|