eslint-plugin-traceability 1.5.1 → 1.6.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/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-story-annotation.d.ts +2 -0
- package/lib/src/rules/require-story-annotation.js +3 -0
- package/lib/src/rules/valid-annotation-format.js +134 -6
- package/lib/src/rules/valid-req-reference.js +30 -51
- package/lib/tests/rules/auto-fix-behavior-008.test.d.ts +1 -0
- package/lib/tests/rules/auto-fix-behavior-008.test.js +84 -0
- package/lib/tests/rules/error-reporting.test.js +1 -0
- 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) {
|
|
@@ -5,6 +5,7 @@
|
|
|
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
|
|
9
10
|
*/
|
|
10
11
|
import type { Rule } from "eslint";
|
|
@@ -12,6 +13,7 @@ import type { Rule } from "eslint";
|
|
|
12
13
|
* ESLint rule to require @story annotations on functions/methods.
|
|
13
14
|
*
|
|
14
15
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
16
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
15
17
|
* @req REQ-ANNOTATION-REQUIRED
|
|
16
18
|
*/
|
|
17
19
|
declare const rule: Rule.RuleModule;
|
|
@@ -6,6 +6,7 @@ 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
|
|
10
11
|
*/
|
|
11
12
|
const rule = {
|
|
@@ -16,6 +17,7 @@ const rule = {
|
|
|
16
17
|
recommended: "error",
|
|
17
18
|
},
|
|
18
19
|
hasSuggestions: true,
|
|
20
|
+
fixable: "code",
|
|
19
21
|
messages: {
|
|
20
22
|
missingStory: "Missing @story annotation for function '{{name}}' (REQ-ANNOTATION-REQUIRED)",
|
|
21
23
|
},
|
|
@@ -38,6 +40,7 @@ const rule = {
|
|
|
38
40
|
* Create the rule visitor functions.
|
|
39
41
|
*
|
|
40
42
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
43
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
41
44
|
* @req REQ-CREATE-HOOK
|
|
42
45
|
*/
|
|
43
46
|
create(context) {
|
|
@@ -1,6 +1,15 @@
|
|
|
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
|
+
*/
|
|
12
|
+
const TAG_NOT_FOUND_INDEX = -1;
|
|
4
13
|
/**
|
|
5
14
|
* Normalize a raw comment line to make annotation parsing more robust.
|
|
6
15
|
*
|
|
@@ -8,7 +17,9 @@ const STORY_EXAMPLE_PATH = "docs/stories/005.0-DEV-EXAMPLE.story.md";
|
|
|
8
17
|
* later in the line, and supports common JSDoc styles such as leading "*".
|
|
9
18
|
*
|
|
10
19
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
20
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
11
21
|
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
22
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
12
23
|
*/
|
|
13
24
|
function normalizeCommentLine(rawLine) {
|
|
14
25
|
const trimmed = rawLine.trim();
|
|
@@ -31,7 +42,9 @@ function normalizeCommentLine(rawLine) {
|
|
|
31
42
|
* multiple lines will be collapsed before validation.
|
|
32
43
|
*
|
|
33
44
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
45
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
34
46
|
* @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
|
|
47
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
35
48
|
*/
|
|
36
49
|
function collapseAnnotationValue(value) {
|
|
37
50
|
return value.replace(/\s+/g, "");
|
|
@@ -40,7 +53,9 @@ function collapseAnnotationValue(value) {
|
|
|
40
53
|
* Build a detailed error message for invalid @story annotations.
|
|
41
54
|
*
|
|
42
55
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
56
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
43
57
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
58
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
44
59
|
*/
|
|
45
60
|
function buildStoryErrorMessage(kind, value) {
|
|
46
61
|
if (kind === "missing") {
|
|
@@ -52,7 +67,9 @@ function buildStoryErrorMessage(kind, value) {
|
|
|
52
67
|
* Build a detailed error message for invalid @req annotations.
|
|
53
68
|
*
|
|
54
69
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
70
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
55
71
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
72
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
56
73
|
*/
|
|
57
74
|
function buildReqErrorMessage(kind, value) {
|
|
58
75
|
if (kind === "missing") {
|
|
@@ -60,12 +77,101 @@ function buildReqErrorMessage(kind, value) {
|
|
|
60
77
|
}
|
|
61
78
|
return `Invalid requirement ID "${value ?? ""}" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).`;
|
|
62
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Attempt a minimal, safe auto-fix for common @story path suffix issues.
|
|
82
|
+
*
|
|
83
|
+
* Only handles:
|
|
84
|
+
* - missing ".md"
|
|
85
|
+
* - missing ".story.md"
|
|
86
|
+
* and skips any paths with traversal segments (e.g. "..").
|
|
87
|
+
*
|
|
88
|
+
* Returns the fixed path when safe, or null if no fix should be applied.
|
|
89
|
+
*
|
|
90
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
91
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
92
|
+
*/
|
|
93
|
+
function getFixedStoryPath(original) {
|
|
94
|
+
if (original.includes("..")) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
if (/\.story\.md$/.test(original)) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (/\.story$/.test(original)) {
|
|
101
|
+
return `${original}.md`;
|
|
102
|
+
}
|
|
103
|
+
if (/\.md$/.test(original)) {
|
|
104
|
+
return original.replace(/\.md$/, ".story.md");
|
|
105
|
+
}
|
|
106
|
+
return `${original}.story.md`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Report an invalid @story annotation without applying a fix.
|
|
110
|
+
*
|
|
111
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
112
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
113
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
114
|
+
*/
|
|
115
|
+
function reportInvalidStoryFormat(context, comment, collapsed) {
|
|
116
|
+
context.report({
|
|
117
|
+
node: comment,
|
|
118
|
+
messageId: "invalidStoryFormat",
|
|
119
|
+
data: { details: buildStoryErrorMessage("invalid", collapsed) },
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Report an invalid @story annotation and attempt a minimal, safe auto-fix
|
|
124
|
+
* for common path suffix issues by locating and replacing the path text
|
|
125
|
+
* within the original comment.
|
|
126
|
+
*
|
|
127
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
128
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
129
|
+
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
130
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
131
|
+
*/
|
|
132
|
+
function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
133
|
+
const sourceCode = context.getSourceCode();
|
|
134
|
+
const commentText = sourceCode.getText(comment);
|
|
135
|
+
const search = "@story";
|
|
136
|
+
const tagIndex = commentText.indexOf(search);
|
|
137
|
+
if (tagIndex === TAG_NOT_FOUND_INDEX) {
|
|
138
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const afterTagIndex = tagIndex + search.length;
|
|
142
|
+
const rest = commentText.slice(afterTagIndex);
|
|
143
|
+
const valueMatch = rest.match(/[^\S\r\n]*([^\r\n*]+)/);
|
|
144
|
+
if (!valueMatch || valueMatch.index === undefined) {
|
|
145
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const valueStartInComment = afterTagIndex +
|
|
149
|
+
valueMatch.index +
|
|
150
|
+
(valueMatch[0].length - valueMatch[1].length);
|
|
151
|
+
const valueEndInComment = valueStartInComment + valueMatch[1].length;
|
|
152
|
+
const start = comment.range[0];
|
|
153
|
+
const fixRange = [
|
|
154
|
+
start + valueStartInComment,
|
|
155
|
+
start + valueEndInComment,
|
|
156
|
+
];
|
|
157
|
+
context.report({
|
|
158
|
+
node: comment,
|
|
159
|
+
messageId: "invalidStoryFormat",
|
|
160
|
+
data: { details: buildStoryErrorMessage("invalid", collapsed) },
|
|
161
|
+
fix(fixer) {
|
|
162
|
+
return fixer.replaceTextRange(fixRange, fixed);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
}
|
|
63
166
|
/**
|
|
64
167
|
* Validate a @story annotation value and report detailed errors when needed.
|
|
168
|
+
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
65
169
|
*
|
|
66
170
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
171
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
67
172
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
68
173
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
174
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
69
175
|
*/
|
|
70
176
|
function validateStoryAnnotation(context, comment, rawValue) {
|
|
71
177
|
const trimmed = rawValue.trim();
|
|
@@ -79,18 +185,25 @@ function validateStoryAnnotation(context, comment, rawValue) {
|
|
|
79
185
|
}
|
|
80
186
|
const collapsed = collapseAnnotationValue(trimmed);
|
|
81
187
|
const pathPattern = /^docs\/stories\/[0-9]+\.[0-9]+-DEV-[\w-]+\.story\.md$/;
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
188
|
+
if (pathPattern.test(collapsed)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (/\s/.test(trimmed)) {
|
|
192
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const fixed = getFixedStoryPath(collapsed);
|
|
196
|
+
if (fixed && pathPattern.test(fixed)) {
|
|
197
|
+
reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed);
|
|
198
|
+
return;
|
|
88
199
|
}
|
|
200
|
+
reportInvalidStoryFormat(context, comment, collapsed);
|
|
89
201
|
}
|
|
90
202
|
/**
|
|
91
203
|
* Validate a @req annotation value and report detailed errors when needed.
|
|
92
204
|
*
|
|
93
205
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
206
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
94
207
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
95
208
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
96
209
|
*/
|
|
@@ -122,8 +235,10 @@ function validateReqAnnotation(context, comment, rawValue) {
|
|
|
122
235
|
* validated against the configured patterns.
|
|
123
236
|
*
|
|
124
237
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
238
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
125
239
|
* @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
|
|
126
240
|
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
241
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
127
242
|
*/
|
|
128
243
|
function processComment(context, comment) {
|
|
129
244
|
const rawLines = (comment.value || "").split(/\r?\n/);
|
|
@@ -132,14 +247,18 @@ function processComment(context, comment) {
|
|
|
132
247
|
* Finalize and validate the currently pending annotation, if any.
|
|
133
248
|
*
|
|
134
249
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
250
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
135
251
|
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
252
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
136
253
|
*/
|
|
137
254
|
function finalizePending() {
|
|
138
255
|
if (!pending) {
|
|
139
256
|
return;
|
|
140
257
|
}
|
|
141
258
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
259
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
142
260
|
// @req REQ-SYNTAX-VALIDATION - Dispatch validation based on annotation type
|
|
261
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
143
262
|
if (pending.type === "story") {
|
|
144
263
|
validateStoryAnnotation(context, comment, pending.value);
|
|
145
264
|
}
|
|
@@ -156,7 +275,9 @@ function processComment(context, comment) {
|
|
|
156
275
|
const isStory = /@story\b/.test(normalized);
|
|
157
276
|
const isReq = /@req\b/.test(normalized);
|
|
158
277
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
278
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
159
279
|
// @req REQ-SYNTAX-VALIDATION - Start new pending annotation when a tag is found
|
|
280
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
160
281
|
if (isStory || isReq) {
|
|
161
282
|
finalizePending();
|
|
162
283
|
const value = normalized.replace(/^@story\b|^@req\b/, "").trim();
|
|
@@ -168,7 +289,9 @@ function processComment(context, comment) {
|
|
|
168
289
|
return;
|
|
169
290
|
}
|
|
170
291
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
292
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
171
293
|
// @req REQ-MULTILINE-SUPPORT - Treat subsequent lines as continuation for pending annotation
|
|
294
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
172
295
|
if (pending) {
|
|
173
296
|
const continuation = normalized.trim();
|
|
174
297
|
if (!continuation) {
|
|
@@ -194,11 +317,14 @@ exports.default = {
|
|
|
194
317
|
invalidReqFormat: "{{details}}",
|
|
195
318
|
},
|
|
196
319
|
schema: [],
|
|
320
|
+
fixable: "code",
|
|
197
321
|
},
|
|
198
322
|
/**
|
|
199
323
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
324
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
200
325
|
* @req REQ-SYNTAX-VALIDATION - Ensure rule create function validates annotations syntax
|
|
201
326
|
* @req REQ-FORMAT-SPECIFICATION - Implement formatting checks per specification
|
|
327
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
202
328
|
*/
|
|
203
329
|
create(context) {
|
|
204
330
|
const sourceCode = context.getSourceCode();
|
|
@@ -207,8 +333,10 @@ exports.default = {
|
|
|
207
333
|
* Program-level handler that inspects all comments for @story and @req tags
|
|
208
334
|
*
|
|
209
335
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
336
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
210
337
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
211
338
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
339
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
212
340
|
*/
|
|
213
341
|
Program() {
|
|
214
342
|
const comments = sourceCode.getAllComments() || [];
|
|
@@ -7,21 +7,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
/**
|
|
8
8
|
* Rule to validate @req annotation references refer to existing requirements in story files
|
|
9
9
|
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
10
|
-
* @req REQ-DEEP-PARSE - Parse
|
|
11
|
-
* @req REQ-DEEP-MATCH -
|
|
12
|
-
* @req REQ-DEEP-CACHE - Cache
|
|
13
|
-
* @req REQ-DEEP-PATH -
|
|
10
|
+
* @req REQ-DEEP-PARSE - Parse comments and extract story/requirement metadata
|
|
11
|
+
* @req REQ-DEEP-MATCH - Match @req annotations to story file requirements
|
|
12
|
+
* @req REQ-DEEP-CACHE - Cache requirement IDs per story file for efficient validation
|
|
13
|
+
* @req REQ-DEEP-PATH - Validate and resolve story file paths safely
|
|
14
14
|
*/
|
|
15
15
|
const fs_1 = __importDefault(require("fs"));
|
|
16
16
|
const path_1 = __importDefault(require("path"));
|
|
17
17
|
/**
|
|
18
18
|
* Extract the story path from a JSDoc comment.
|
|
19
|
-
* Parses comment.value lines for @story annotation.
|
|
20
|
-
* @param comment any JSDoc comment node
|
|
21
|
-
* @returns story path or null if not found
|
|
22
|
-
*
|
|
23
19
|
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
24
|
-
* @req REQ-DEEP-PARSE -
|
|
20
|
+
* @req REQ-DEEP-PARSE - Parse JSDoc comment lines to locate @story annotations
|
|
25
21
|
*/
|
|
26
22
|
function extractStoryPath(comment) {
|
|
27
23
|
const rawLines = comment.value.split(/\r?\n/);
|
|
@@ -37,14 +33,11 @@ function extractStoryPath(comment) {
|
|
|
37
33
|
/**
|
|
38
34
|
* Validate a @req annotation line against the extracted story content.
|
|
39
35
|
* Performs path validation, file reading, caching, and requirement existence checks.
|
|
40
|
-
*
|
|
41
|
-
* @param opts options bag
|
|
42
|
-
*
|
|
43
36
|
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
44
|
-
* @req REQ-DEEP-PATH -
|
|
45
|
-
* @req REQ-DEEP-CACHE -
|
|
46
|
-
* @req REQ-DEEP-MATCH -
|
|
47
|
-
* @req REQ-DEEP-PARSE -
|
|
37
|
+
* @req REQ-DEEP-PATH - Validate and resolve referenced story file paths
|
|
38
|
+
* @req REQ-DEEP-CACHE - Cache requirement IDs discovered in story files
|
|
39
|
+
* @req REQ-DEEP-MATCH - Verify that a referenced requirement ID exists in the story
|
|
40
|
+
* @req REQ-DEEP-PARSE - Parse story file contents to extract requirement identifiers
|
|
48
41
|
*/
|
|
49
42
|
function validateReqLine(opts) {
|
|
50
43
|
const { comment, context, line, storyPath, cwd, reqCache } = opts;
|
|
@@ -96,15 +89,10 @@ function validateReqLine(opts) {
|
|
|
96
89
|
}
|
|
97
90
|
}
|
|
98
91
|
/**
|
|
99
|
-
* Handle a single annotation line.
|
|
100
|
-
* @story Updates the current story path when encountering an @story annotation
|
|
101
|
-
* @req Validates the requirement reference against the current story content
|
|
102
|
-
*
|
|
103
|
-
* @param opts handler options
|
|
104
|
-
*
|
|
92
|
+
* Handle a single annotation line for story or requirement metadata.
|
|
105
93
|
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
106
|
-
* @req REQ-DEEP-PARSE -
|
|
107
|
-
* @req REQ-DEEP-MATCH -
|
|
94
|
+
* @req REQ-DEEP-PARSE - Parse annotation lines for @story and @req tags
|
|
95
|
+
* @req REQ-DEEP-MATCH - Dispatch @req lines for validation against story requirements
|
|
108
96
|
*/
|
|
109
97
|
function handleAnnotationLine(opts) {
|
|
110
98
|
const { line, comment, context, cwd, reqCache, storyPath } = opts;
|
|
@@ -119,14 +107,11 @@ function handleAnnotationLine(opts) {
|
|
|
119
107
|
return storyPath;
|
|
120
108
|
}
|
|
121
109
|
/**
|
|
122
|
-
* Handle JSDoc story and req annotations.
|
|
123
|
-
*
|
|
124
|
-
* @param opts options for comment handling
|
|
125
|
-
*
|
|
110
|
+
* Handle JSDoc story and req annotations for a single comment block.
|
|
126
111
|
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
127
|
-
* @req REQ-DEEP-PARSE -
|
|
128
|
-
* @req REQ-DEEP-MATCH -
|
|
129
|
-
* @req REQ-DEEP-CACHE -
|
|
112
|
+
* @req REQ-DEEP-PARSE - Iterate comment lines to process @story/@req annotations
|
|
113
|
+
* @req REQ-DEEP-MATCH - Coordinate annotation handling across a comment block
|
|
114
|
+
* @req REQ-DEEP-CACHE - Maintain and reuse discovered story path across comments
|
|
130
115
|
*/
|
|
131
116
|
function handleComment(opts) {
|
|
132
117
|
const { comment, context, cwd, reqCache, rawStoryPath } = opts;
|
|
@@ -147,30 +132,25 @@ function handleComment(opts) {
|
|
|
147
132
|
}
|
|
148
133
|
/**
|
|
149
134
|
* Create a Program listener that iterates comments and validates annotations.
|
|
150
|
-
*
|
|
151
|
-
* @param context ESLint rule context
|
|
152
|
-
* @returns Program visitor function
|
|
153
|
-
*
|
|
154
135
|
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
155
|
-
* @req REQ-DEEP-CACHE -
|
|
156
|
-
* @req REQ-DEEP-PATH -
|
|
136
|
+
* @req REQ-DEEP-CACHE - Initialize and share a requirement cache for the program
|
|
137
|
+
* @req REQ-DEEP-PATH - Derive the working directory context for path resolution
|
|
157
138
|
*/
|
|
158
139
|
function programListener(context) {
|
|
159
140
|
const sourceCode = context.getSourceCode();
|
|
160
141
|
const cwd = process.cwd();
|
|
161
142
|
const reqCache = new Map();
|
|
162
143
|
let rawStoryPath = null;
|
|
144
|
+
/**
|
|
145
|
+
* Program visitor that walks all comments to validate story/requirement references.
|
|
146
|
+
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
147
|
+
* @req REQ-DEEP-PARSE - Collect all comments from the source code
|
|
148
|
+
* @req REQ-DEEP-MATCH - Drive comment-level handling for traceability checks
|
|
149
|
+
* @req REQ-DEEP-CACHE - Reuse story path and requirement cache across comments
|
|
150
|
+
* @req REQ-DEEP-PATH - Ensure validation respects project-relative paths
|
|
151
|
+
*/
|
|
163
152
|
return function Program() {
|
|
164
153
|
const comments = sourceCode.getAllComments() || [];
|
|
165
|
-
/**
|
|
166
|
-
* Process each comment to handle story and requirement annotations.
|
|
167
|
-
*
|
|
168
|
-
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
169
|
-
* @req REQ-DEEP-PARSE - Parse annotations from comment blocks
|
|
170
|
-
* @req REQ-DEEP-MATCH - Validate @req references found in comments
|
|
171
|
-
* @req REQ-DEEP-CACHE - Use cache for parsed story files to avoid repeated IO
|
|
172
|
-
* @req REQ-DEEP-PATH - Enforce path validation when resolving story files
|
|
173
|
-
*/
|
|
174
154
|
comments.forEach((comment) => {
|
|
175
155
|
rawStoryPath = handleComment({
|
|
176
156
|
comment,
|
|
@@ -197,12 +177,11 @@ exports.default = {
|
|
|
197
177
|
},
|
|
198
178
|
/**
|
|
199
179
|
* Rule create entrypoint that returns the Program visitor.
|
|
200
|
-
*
|
|
201
180
|
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
202
|
-
* @req REQ-DEEP-MATCH -
|
|
203
|
-
* @req REQ-DEEP-PARSE -
|
|
204
|
-
* @req REQ-DEEP-CACHE -
|
|
205
|
-
* @req REQ-DEEP-PATH -
|
|
181
|
+
* @req REQ-DEEP-MATCH - Register the Program visitor with ESLint
|
|
182
|
+
* @req REQ-DEEP-PARSE - Integrate comment parsing into the ESLint rule lifecycle
|
|
183
|
+
* @req REQ-DEEP-CACHE - Ensure cache and context are wired into the listener
|
|
184
|
+
* @req REQ-DEEP-PATH - Propagate path context into the program listener
|
|
206
185
|
*/
|
|
207
186
|
create(context) {
|
|
208
187
|
return { Program: programListener(context) };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
/**
|
|
7
|
+
* Tests for: docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
8
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
9
|
+
* @req REQ-AUTOFIX-MISSING - Verify ESLint --fix automatically adds missing @story annotations to functions
|
|
10
|
+
* @req REQ-AUTOFIX-FORMAT - Verify ESLint --fix corrects simple annotation format issues for @story annotations
|
|
11
|
+
*/
|
|
12
|
+
const eslint_1 = require("eslint");
|
|
13
|
+
const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
|
|
14
|
+
const valid_annotation_format_1 = __importDefault(require("../../src/rules/valid-annotation-format"));
|
|
15
|
+
const functionRuleTester = new eslint_1.RuleTester({
|
|
16
|
+
languageOptions: {
|
|
17
|
+
parserOptions: { ecmaVersion: 2020, sourceType: "module" },
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const formatRuleTester = new eslint_1.RuleTester({
|
|
21
|
+
languageOptions: { parserOptions: { ecmaVersion: 2020 } },
|
|
22
|
+
});
|
|
23
|
+
describe("Auto-fix behavior (Story 008.0-DEV-AUTO-FIX)", () => {
|
|
24
|
+
describe("[REQ-AUTOFIX-MISSING] require-story-annotation auto-fix", () => {
|
|
25
|
+
functionRuleTester.run("require-story-annotation --fix", require_story_annotation_1.default, {
|
|
26
|
+
valid: [
|
|
27
|
+
{
|
|
28
|
+
name: "[REQ-AUTOFIX-MISSING] already annotated function is unchanged",
|
|
29
|
+
code: `/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n */\nfunction alreadyAnnotated() {}`,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
invalid: [
|
|
33
|
+
{
|
|
34
|
+
name: "[REQ-AUTOFIX-MISSING] adds @story before function declaration when missing",
|
|
35
|
+
code: `function autoFixMe() {}`,
|
|
36
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction autoFixMe() {}`,
|
|
37
|
+
errors: [
|
|
38
|
+
{
|
|
39
|
+
messageId: "missingStory",
|
|
40
|
+
suggestions: [
|
|
41
|
+
{
|
|
42
|
+
desc: "Add JSDoc @story annotation for function 'autoFixMe', e.g., /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */",
|
|
43
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction autoFixMe() {}`,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe("[REQ-AUTOFIX-FORMAT] valid-annotation-format auto-fix", () => {
|
|
53
|
+
formatRuleTester.run("valid-annotation-format --fix simple @story extension issues", valid_annotation_format_1.default, {
|
|
54
|
+
valid: [
|
|
55
|
+
{
|
|
56
|
+
name: "[REQ-AUTOFIX-FORMAT] already-correct story path is unchanged",
|
|
57
|
+
code: `// @story docs/stories/005.0-DEV-EXAMPLE.story.md`,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
invalid: [
|
|
61
|
+
{
|
|
62
|
+
name: "[REQ-AUTOFIX-FORMAT] adds .md extension for .story path",
|
|
63
|
+
code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story`,
|
|
64
|
+
output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
|
|
65
|
+
errors: [
|
|
66
|
+
{
|
|
67
|
+
messageId: "invalidStoryFormat",
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "[REQ-AUTOFIX-FORMAT] adds .story.md extension when missing entirely",
|
|
73
|
+
code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION`,
|
|
74
|
+
output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
|
|
75
|
+
errors: [
|
|
76
|
+
{
|
|
77
|
+
messageId: "invalidStoryFormat",
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -29,6 +29,7 @@ describe("Error Reporting Enhancements for require-story-annotation (Story 007.0
|
|
|
29
29
|
{
|
|
30
30
|
name: "[REQ-ERROR-SPECIFIC] missing @story annotation should report specific details and suggestion",
|
|
31
31
|
code: `function bar() {}`,
|
|
32
|
+
output: "/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction bar() {}",
|
|
32
33
|
errors: [
|
|
33
34
|
{
|
|
34
35
|
messageId: "missingStory",
|
|
@@ -69,6 +69,7 @@ declare function tsDecl(): void;`,
|
|
|
69
69
|
{
|
|
70
70
|
name: "[REQ-ANNOTATION-REQUIRED] missing @story annotation on function",
|
|
71
71
|
code: `function bar() {}`,
|
|
72
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction bar() {}`,
|
|
72
73
|
errors: [
|
|
73
74
|
{
|
|
74
75
|
messageId: "missingStory",
|
|
@@ -84,6 +85,7 @@ declare function tsDecl(): void;`,
|
|
|
84
85
|
{
|
|
85
86
|
name: "[REQ-ANNOTATION-REQUIRED] missing @story on function expression",
|
|
86
87
|
code: `const fnExpr = function() {};`,
|
|
88
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nconst fnExpr = function() {};`,
|
|
87
89
|
errors: [
|
|
88
90
|
{
|
|
89
91
|
messageId: "missingStory",
|
|
@@ -99,6 +101,7 @@ declare function tsDecl(): void;`,
|
|
|
99
101
|
{
|
|
100
102
|
name: "[REQ-ANNOTATION-REQUIRED] missing @story on class method",
|
|
101
103
|
code: `class C {\n method() {}\n}`,
|
|
104
|
+
output: `class C {\n /** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\n method() {}\n}`,
|
|
102
105
|
errors: [
|
|
103
106
|
{
|
|
104
107
|
messageId: "missingStory",
|
|
@@ -114,6 +117,7 @@ declare function tsDecl(): void;`,
|
|
|
114
117
|
{
|
|
115
118
|
name: "[REQ-ANNOTATION-REQUIRED] missing @story on TS declare function",
|
|
116
119
|
code: `declare function tsDecl(): void;`,
|
|
120
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\ndeclare function tsDecl(): void;`,
|
|
117
121
|
languageOptions: {
|
|
118
122
|
parser: require("@typescript-eslint/parser"),
|
|
119
123
|
parserOptions: { ecmaVersion: 2020, sourceType: "module" },
|
|
@@ -133,6 +137,7 @@ declare function tsDecl(): void;`,
|
|
|
133
137
|
{
|
|
134
138
|
name: "[REQ-ANNOTATION-REQUIRED] missing @story on TS method signature",
|
|
135
139
|
code: `interface D {\n method(): void;\n}`,
|
|
140
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\ninterface D {\n method(): void;\n}`,
|
|
136
141
|
languageOptions: {
|
|
137
142
|
parser: require("@typescript-eslint/parser"),
|
|
138
143
|
parserOptions: { ecmaVersion: 2020, sourceType: "module" },
|
|
@@ -173,6 +178,7 @@ declare function tsDecl(): void;`,
|
|
|
173
178
|
{
|
|
174
179
|
name: "[exportPriority] exported function missing @story annotation",
|
|
175
180
|
code: `export function exportedMissing() {}`,
|
|
181
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nexport function exportedMissing() {}`,
|
|
176
182
|
options: [{ exportPriority: "exported" }],
|
|
177
183
|
errors: [
|
|
178
184
|
{
|
|
@@ -200,6 +206,7 @@ declare function tsDecl(): void;`,
|
|
|
200
206
|
{
|
|
201
207
|
name: "[scope] function declaration missing annotation when scope is FunctionDeclaration",
|
|
202
208
|
code: `function onlyDecl() {}`,
|
|
209
|
+
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction onlyDecl() {}`,
|
|
203
210
|
options: [{ scope: ["FunctionDeclaration"] }],
|
|
204
211
|
errors: [
|
|
205
212
|
{
|
|
@@ -69,6 +69,7 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
|
|
|
69
69
|
{
|
|
70
70
|
name: "[REQ-PATH-FORMAT] invalid story file extension",
|
|
71
71
|
code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story`,
|
|
72
|
+
output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
|
|
72
73
|
errors: [
|
|
73
74
|
{
|
|
74
75
|
messageId: "invalidStoryFormat",
|
|
@@ -81,6 +82,7 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
|
|
|
81
82
|
{
|
|
82
83
|
name: "[REQ-PATH-FORMAT] missing extension in story path",
|
|
83
84
|
code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION`,
|
|
85
|
+
output: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
|
|
84
86
|
errors: [
|
|
85
87
|
{
|
|
86
88
|
messageId: "invalidStoryFormat",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-traceability",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "A customizable ESLint plugin that enforces traceability annotations in your code, ensuring each implementation is linked to its requirement or test case.",
|
|
5
5
|
"main": "lib/src/index.js",
|
|
6
6
|
"types": "lib/src/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"lint": "eslint --config eslint.config.js \"src/**/*.{js,ts}\" \"tests/**/*.{js,ts}\" --max-warnings=0",
|
|
23
23
|
"test": "jest --ci --bail",
|
|
24
24
|
"ci-verify": "npm run type-check && npm run lint && npm run format:check && npm run duplication && npm run check:traceability && npm test && npm run audit:ci && npm run safety:deps",
|
|
25
|
-
"ci-verify:full": "npm run check:traceability && npm run safety:deps && npm run audit:ci && npm run build && npm run type-check && npm run lint-plugin-check && npm run lint -- --max-warnings=0 && npm run duplication && npm run test -- --coverage && npm run format:check && npm audit --
|
|
25
|
+
"ci-verify:full": "npm run check:traceability && npm run safety:deps && npm run audit:ci && npm run build && npm run type-check && npm run lint-plugin-check && npm run lint -- --max-warnings=0 && npm run duplication && npm run test -- --coverage && npm run format:check && npm audit --omit=dev --audit-level=high && npm run audit:dev-high",
|
|
26
26
|
"ci-verify:fast": "npm run type-check && npm run check:traceability && npm run duplication && jest --ci --bail --passWithNoTests --testPathPatterns 'tests/(unit|fast)'",
|
|
27
27
|
"format": "prettier --write .",
|
|
28
28
|
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
@@ -30,8 +30,7 @@
|
|
|
30
30
|
"audit:dev-high": "node scripts/generate-dev-deps-audit.js",
|
|
31
31
|
"safety:deps": "node scripts/ci-safety-deps.js",
|
|
32
32
|
"audit:ci": "node scripts/ci-audit.js",
|
|
33
|
-
"smoke-test": "./scripts/smoke-test.sh"
|
|
34
|
-
"prepare": "husky install"
|
|
33
|
+
"smoke-test": "./scripts/smoke-test.sh"
|
|
35
34
|
},
|
|
36
35
|
"lint-staged": {
|
|
37
36
|
"src/**/*.{js,jsx,ts,tsx,json,md}": [
|