eslint-plugin-traceability 1.6.4 → 1.7.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 +38 -1
- package/lib/src/index.d.ts +28 -25
- package/lib/src/index.js +49 -31
- package/lib/src/maintenance/cli.d.ts +12 -0
- package/lib/src/maintenance/cli.js +279 -0
- package/lib/src/maintenance/detect.js +30 -15
- 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/require-story-visitors.js +5 -16
- 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-story-reference-helpers.d.ts +67 -0
- package/lib/src/rules/helpers/valid-story-reference-helpers.js +92 -0
- package/lib/src/rules/require-story-annotation.js +9 -14
- package/lib/src/rules/valid-annotation-format.js +168 -180
- package/lib/src/rules/valid-req-reference.js +139 -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/maintenance/detect-isolated.test.js +68 -1
- package/lib/tests/maintenance/report.test.js +2 -2
- 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 +328 -51
- 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
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
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;
|
|
3
|
+
const valid_annotation_options_1 = require("./helpers/valid-annotation-options");
|
|
4
|
+
const valid_annotation_utils_1 = require("./helpers/valid-annotation-utils");
|
|
14
5
|
/**
|
|
15
6
|
* Normalize a raw comment line to make annotation parsing more robust.
|
|
16
7
|
*
|
|
@@ -35,92 +26,57 @@ function normalizeCommentLine(rawLine) {
|
|
|
35
26
|
return trimmed.slice(annotationMatch.index);
|
|
36
27
|
}
|
|
37
28
|
/**
|
|
38
|
-
*
|
|
39
|
-
* annotations are treated as a single logical value.
|
|
40
|
-
*
|
|
41
|
-
* Example:
|
|
42
|
-
* "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md" across
|
|
43
|
-
* multiple lines will be collapsed before validation.
|
|
44
|
-
*
|
|
45
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
46
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
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
|
|
49
|
-
*/
|
|
50
|
-
function collapseAnnotationValue(value) {
|
|
51
|
-
return value.replace(/\s+/g, "");
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Build a detailed error message for invalid @story annotations.
|
|
55
|
-
*
|
|
56
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
57
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
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
|
|
60
|
-
*/
|
|
61
|
-
function buildStoryErrorMessage(kind, value) {
|
|
62
|
-
if (kind === "missing") {
|
|
63
|
-
return `Missing story path for @story annotation. Expected a path like "${STORY_EXAMPLE_PATH}".`;
|
|
64
|
-
}
|
|
65
|
-
return `Invalid story path "${value ?? ""}" for @story annotation. Expected a path like "${STORY_EXAMPLE_PATH}".`;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Build a detailed error message for invalid @req annotations.
|
|
29
|
+
* Report an invalid @story annotation without applying a fix.
|
|
69
30
|
*
|
|
70
31
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
71
32
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
72
|
-
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
73
33
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
74
34
|
*/
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
35
|
+
function reportInvalidStoryFormat(context, comment, collapsed, options) {
|
|
36
|
+
context.report({
|
|
37
|
+
node: comment,
|
|
38
|
+
messageId: "invalidStoryFormat",
|
|
39
|
+
data: { details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("invalid", collapsed, options) },
|
|
40
|
+
});
|
|
80
41
|
}
|
|
81
42
|
/**
|
|
82
|
-
*
|
|
43
|
+
* Compute the text replacement for an invalid @story annotation within a comment.
|
|
83
44
|
*
|
|
84
|
-
*
|
|
85
|
-
* -
|
|
86
|
-
* -
|
|
87
|
-
* and
|
|
45
|
+
* This helper:
|
|
46
|
+
* - finds the @story tag in the raw comment text,
|
|
47
|
+
* - computes the character range of its value,
|
|
48
|
+
* - and returns an ESLint fix that replaces only that range.
|
|
88
49
|
*
|
|
89
|
-
* Returns
|
|
50
|
+
* Returns null when the tag or value cannot be safely located.
|
|
90
51
|
*
|
|
91
52
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
92
|
-
* @req REQ-AUTOFIX-
|
|
93
|
-
* @req REQ-AUTOFIX-
|
|
94
|
-
* @req REQ-AUTOFIX-PRESERVE - Preserve surrounding formatting when normalizing story path suffixes
|
|
53
|
+
* @req REQ-AUTOFIX-SAFE
|
|
54
|
+
* @req REQ-AUTOFIX-PRESERVE
|
|
95
55
|
*/
|
|
96
|
-
function
|
|
97
|
-
|
|
56
|
+
function createStoryFix(context, comment, fixed) {
|
|
57
|
+
const sourceCode = context.getSourceCode();
|
|
58
|
+
const commentText = sourceCode.getText(comment);
|
|
59
|
+
const search = "@story";
|
|
60
|
+
const tagIndex = commentText.indexOf(search);
|
|
61
|
+
if (tagIndex === valid_annotation_utils_1.TAG_NOT_FOUND_INDEX) {
|
|
98
62
|
return null;
|
|
99
63
|
}
|
|
100
|
-
|
|
64
|
+
const afterTagIndex = tagIndex + search.length;
|
|
65
|
+
const rest = commentText.slice(afterTagIndex);
|
|
66
|
+
const valueMatch = rest.match(/[^\S\r\n]*([^\r\n*]+)/);
|
|
67
|
+
if (!valueMatch || valueMatch.index === undefined) {
|
|
101
68
|
return null;
|
|
102
69
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
});
|
|
70
|
+
const valueStartInComment = afterTagIndex +
|
|
71
|
+
valueMatch.index +
|
|
72
|
+
(valueMatch[0].length - valueMatch[1].length);
|
|
73
|
+
const valueEndInComment = valueStartInComment + valueMatch[1].length;
|
|
74
|
+
const start = comment.range[0];
|
|
75
|
+
const fixRange = [
|
|
76
|
+
start + valueStartInComment,
|
|
77
|
+
start + valueEndInComment,
|
|
78
|
+
];
|
|
79
|
+
return () => (fixer) => fixer.replaceTextRange(fixRange, fixed);
|
|
124
80
|
}
|
|
125
81
|
/**
|
|
126
82
|
* Report an invalid @story annotation and attempt a minimal, safe auto-fix
|
|
@@ -141,37 +97,18 @@ function reportInvalidStoryFormat(context, comment, collapsed) {
|
|
|
141
97
|
* @req REQ-AUTOFIX-PRESERVE - Auto-fix must preserve surrounding formatting and comments
|
|
142
98
|
*/
|
|
143
99
|
function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
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);
|
|
100
|
+
const fixFactory = createStoryFix(context, comment, fixed);
|
|
101
|
+
if (!fixFactory) {
|
|
102
|
+
reportInvalidStoryFormat(context, comment, collapsed, (0, valid_annotation_options_1.getResolvedDefaults)());
|
|
157
103
|
return;
|
|
158
104
|
}
|
|
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
105
|
context.report({
|
|
169
106
|
node: comment,
|
|
170
107
|
messageId: "invalidStoryFormat",
|
|
171
|
-
data: {
|
|
172
|
-
|
|
173
|
-
return fixer.replaceTextRange(fixRange, fixed);
|
|
108
|
+
data: {
|
|
109
|
+
details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("invalid", collapsed, (0, valid_annotation_options_1.getResolvedDefaults)()),
|
|
174
110
|
},
|
|
111
|
+
fix: fixFactory(),
|
|
175
112
|
});
|
|
176
113
|
}
|
|
177
114
|
/**
|
|
@@ -183,32 +120,34 @@ function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
|
183
120
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
184
121
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
185
122
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
123
|
+
* @req REQ-REGEX-VALIDATION - Validate configurable story regex patterns and fall back safely
|
|
124
|
+
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
186
125
|
*/
|
|
187
|
-
function validateStoryAnnotation(context, comment, rawValue) {
|
|
126
|
+
function validateStoryAnnotation(context, comment, rawValue, options) {
|
|
188
127
|
const trimmed = rawValue.trim();
|
|
189
128
|
if (!trimmed) {
|
|
190
129
|
context.report({
|
|
191
130
|
node: comment,
|
|
192
131
|
messageId: "invalidStoryFormat",
|
|
193
|
-
data: { details: buildStoryErrorMessage("missing", null) },
|
|
132
|
+
data: { details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("missing", null, options) },
|
|
194
133
|
});
|
|
195
134
|
return;
|
|
196
135
|
}
|
|
197
|
-
const collapsed = collapseAnnotationValue(trimmed);
|
|
198
|
-
const pathPattern =
|
|
136
|
+
const collapsed = (0, valid_annotation_utils_1.collapseAnnotationValue)(trimmed);
|
|
137
|
+
const pathPattern = options.storyPattern;
|
|
199
138
|
if (pathPattern.test(collapsed)) {
|
|
200
139
|
return;
|
|
201
140
|
}
|
|
202
141
|
if (/\s/.test(trimmed)) {
|
|
203
|
-
reportInvalidStoryFormat(context, comment, collapsed);
|
|
142
|
+
reportInvalidStoryFormat(context, comment, collapsed, options);
|
|
204
143
|
return;
|
|
205
144
|
}
|
|
206
|
-
const fixed = getFixedStoryPath(collapsed);
|
|
145
|
+
const fixed = (0, valid_annotation_utils_1.getFixedStoryPath)(collapsed);
|
|
207
146
|
if (fixed && pathPattern.test(fixed)) {
|
|
208
147
|
reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed);
|
|
209
148
|
return;
|
|
210
149
|
}
|
|
211
|
-
reportInvalidStoryFormat(context, comment, collapsed);
|
|
150
|
+
reportInvalidStoryFormat(context, comment, collapsed, options);
|
|
212
151
|
}
|
|
213
152
|
/**
|
|
214
153
|
* Validate a @req annotation value and report detailed errors when needed.
|
|
@@ -217,27 +156,101 @@ function validateStoryAnnotation(context, comment, rawValue) {
|
|
|
217
156
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
218
157
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
219
158
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
159
|
+
* @req REQ-REGEX-VALIDATION - Validate configurable requirement regex patterns and fall back safely
|
|
160
|
+
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
220
161
|
*/
|
|
221
|
-
function validateReqAnnotation(context, comment, rawValue) {
|
|
162
|
+
function validateReqAnnotation(context, comment, rawValue, options) {
|
|
222
163
|
const trimmed = rawValue.trim();
|
|
223
164
|
if (!trimmed) {
|
|
224
165
|
context.report({
|
|
225
166
|
node: comment,
|
|
226
167
|
messageId: "invalidReqFormat",
|
|
227
|
-
data: { details: buildReqErrorMessage("missing", null) },
|
|
168
|
+
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("missing", null, options) },
|
|
228
169
|
});
|
|
229
170
|
return;
|
|
230
171
|
}
|
|
231
|
-
const collapsed = collapseAnnotationValue(trimmed);
|
|
232
|
-
const reqPattern =
|
|
172
|
+
const collapsed = (0, valid_annotation_utils_1.collapseAnnotationValue)(trimmed);
|
|
173
|
+
const reqPattern = options.reqPattern;
|
|
233
174
|
if (!reqPattern.test(collapsed)) {
|
|
234
175
|
context.report({
|
|
235
176
|
node: comment,
|
|
236
177
|
messageId: "invalidReqFormat",
|
|
237
|
-
data: { details: buildReqErrorMessage("invalid", collapsed) },
|
|
178
|
+
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("invalid", collapsed, options) },
|
|
238
179
|
});
|
|
239
180
|
}
|
|
240
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Finalize and validate the currently pending annotation, if any.
|
|
184
|
+
*
|
|
185
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
186
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
187
|
+
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
188
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
189
|
+
*/
|
|
190
|
+
function finalizePendingAnnotation(context, comment, options, pending) {
|
|
191
|
+
if (!pending) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
195
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
196
|
+
// @req REQ-SYNTAX-VALIDATION - Dispatch validation based on annotation type
|
|
197
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
198
|
+
if (pending.type === "story") {
|
|
199
|
+
validateStoryAnnotation(context, comment, pending.value, options);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
validateReqAnnotation(context, comment, pending.value, options);
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Process a single normalized comment line and update the pending annotation state.
|
|
208
|
+
*
|
|
209
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
210
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
211
|
+
* @req REQ-SYNTAX-VALIDATION - Start new pending annotation when a tag is found
|
|
212
|
+
* @req REQ-MULTILINE-SUPPORT - Treat subsequent lines as continuation for pending annotation
|
|
213
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
214
|
+
*/
|
|
215
|
+
function processCommentLine({ normalized, pending, context, comment, options, }) {
|
|
216
|
+
if (!normalized) {
|
|
217
|
+
return pending;
|
|
218
|
+
}
|
|
219
|
+
const isStory = /@story\b/.test(normalized);
|
|
220
|
+
const isReq = /@req\b/.test(normalized);
|
|
221
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
222
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
223
|
+
// @req REQ-SYNTAX-VALIDATION - Start new pending annotation when a tag is found
|
|
224
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
225
|
+
if (isStory || isReq) {
|
|
226
|
+
finalizePendingAnnotation(context, comment, options, pending);
|
|
227
|
+
const value = normalized.replace(/^@story\b|^@req\b/, "").trim();
|
|
228
|
+
return {
|
|
229
|
+
type: isStory ? "story" : "req",
|
|
230
|
+
value,
|
|
231
|
+
hasValue: value.trim().length > 0,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
235
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
236
|
+
// @req REQ-MULTILINE-SUPPORT - Treat subsequent lines as continuation for pending annotation
|
|
237
|
+
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
238
|
+
if (pending) {
|
|
239
|
+
const continuation = normalized.trim();
|
|
240
|
+
if (!continuation) {
|
|
241
|
+
return pending;
|
|
242
|
+
}
|
|
243
|
+
const updatedValue = pending.value
|
|
244
|
+
? `${pending.value} ${continuation}`
|
|
245
|
+
: continuation;
|
|
246
|
+
return {
|
|
247
|
+
...pending,
|
|
248
|
+
value: updatedValue,
|
|
249
|
+
hasValue: pending.hasValue || continuation.length > 0,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
return pending;
|
|
253
|
+
}
|
|
241
254
|
/**
|
|
242
255
|
* Process a single comment node and validate any @story/@req annotations it contains.
|
|
243
256
|
*
|
|
@@ -251,70 +264,20 @@ function validateReqAnnotation(context, comment, rawValue) {
|
|
|
251
264
|
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
252
265
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
253
266
|
*/
|
|
254
|
-
function processComment(context, comment) {
|
|
267
|
+
function processComment(context, comment, options) {
|
|
255
268
|
const rawLines = (comment.value || "").split(/\r?\n/);
|
|
256
269
|
let pending = null;
|
|
257
|
-
/**
|
|
258
|
-
* Finalize and validate the currently pending annotation, if any.
|
|
259
|
-
*
|
|
260
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
261
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
262
|
-
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
263
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
264
|
-
*/
|
|
265
|
-
function finalizePending() {
|
|
266
|
-
if (!pending) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
270
|
-
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
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
|
|
273
|
-
if (pending.type === "story") {
|
|
274
|
-
validateStoryAnnotation(context, comment, pending.value);
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
validateReqAnnotation(context, comment, pending.value);
|
|
278
|
-
}
|
|
279
|
-
pending = null;
|
|
280
|
-
}
|
|
281
270
|
rawLines.forEach((rawLine) => {
|
|
282
271
|
const normalized = normalizeCommentLine(rawLine);
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
|
292
|
-
if (isStory || isReq) {
|
|
293
|
-
finalizePending();
|
|
294
|
-
const value = normalized.replace(/^@story\b|^@req\b/, "").trim();
|
|
295
|
-
pending = {
|
|
296
|
-
type: isStory ? "story" : "req",
|
|
297
|
-
value,
|
|
298
|
-
hasValue: value.trim().length > 0,
|
|
299
|
-
};
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
303
|
-
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
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
|
|
306
|
-
if (pending) {
|
|
307
|
-
const continuation = normalized.trim();
|
|
308
|
-
if (!continuation) {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
pending.value = pending.value
|
|
312
|
-
? `${pending.value} ${continuation}`
|
|
313
|
-
: continuation;
|
|
314
|
-
pending.hasValue = pending.hasValue || continuation.length > 0;
|
|
315
|
-
}
|
|
272
|
+
pending = processCommentLine({
|
|
273
|
+
normalized,
|
|
274
|
+
pending,
|
|
275
|
+
context,
|
|
276
|
+
comment,
|
|
277
|
+
options,
|
|
278
|
+
});
|
|
316
279
|
});
|
|
317
|
-
|
|
280
|
+
finalizePendingAnnotation(context, comment, options, pending);
|
|
318
281
|
}
|
|
319
282
|
exports.default = {
|
|
320
283
|
meta: {
|
|
@@ -338,8 +301,14 @@ exports.default = {
|
|
|
338
301
|
* @req REQ-ERROR-CONSISTENCY - Use shared "Invalid annotation format: {{details}}." message pattern across rules
|
|
339
302
|
*/
|
|
340
303
|
invalidReqFormat: "Invalid annotation format: {{details}}.",
|
|
304
|
+
/**
|
|
305
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
306
|
+
* @req REQ-REGEX-VALIDATION - Surface configuration errors for invalid regex patterns
|
|
307
|
+
* @req REQ-BACKWARD-COMP - Preserve behavior by falling back to default patterns on error
|
|
308
|
+
*/
|
|
309
|
+
invalidRuleConfiguration: "Invalid configuration for valid-annotation-format: {{details}}",
|
|
341
310
|
},
|
|
342
|
-
schema:
|
|
311
|
+
schema: (0, valid_annotation_options_1.getRuleSchema)(),
|
|
343
312
|
/**
|
|
344
313
|
* This rule's fixable support is limited to safe @story path suffix normalization per Story 008.0.
|
|
345
314
|
* Fixes are limited strictly to adjusting the suffix portion of the @story path (e.g., adding
|
|
@@ -348,32 +317,51 @@ exports.default = {
|
|
|
348
317
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
349
318
|
* @req REQ-AUTOFIX-SAFE
|
|
350
319
|
* @req REQ-AUTOFIX-PRESERVE
|
|
320
|
+
* @req REQ-REGEX-VALIDATION - Ensure regex configuration does not affect fix safety
|
|
321
|
+
* @req REQ-BACKWARD-COMP - Maintain previous auto-fix behavior under invalid configs
|
|
351
322
|
*/
|
|
352
323
|
fixable: "code",
|
|
353
324
|
},
|
|
354
325
|
/**
|
|
355
326
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
356
327
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
328
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
357
329
|
* @req REQ-SYNTAX-VALIDATION - Ensure rule create function validates annotations syntax
|
|
358
330
|
* @req REQ-FORMAT-SPECIFICATION - Implement formatting checks per specification
|
|
359
331
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
332
|
+
* @req REQ-REGEX-VALIDATION - Derive validation regexes from shared options helper
|
|
333
|
+
* @req REQ-BACKWARD-COMP - Fall back to default patterns and continue validation on config errors
|
|
360
334
|
*/
|
|
361
335
|
create(context) {
|
|
362
336
|
const sourceCode = context.getSourceCode();
|
|
337
|
+
const options = (0, valid_annotation_options_1.resolveOptions)(context.options || []);
|
|
338
|
+
const optionErrors = (0, valid_annotation_options_1.getOptionErrors)();
|
|
363
339
|
return {
|
|
364
340
|
/**
|
|
365
341
|
* Program-level handler that inspects all comments for @story and @req tags
|
|
366
342
|
*
|
|
367
343
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
368
344
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
345
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
369
346
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
370
347
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
371
348
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
349
|
+
* @req REQ-REGEX-VALIDATION - Surface regex configuration errors without blocking validation
|
|
350
|
+
* @req REQ-BACKWARD-COMP - Continue validating comments using default patterns on error
|
|
372
351
|
*/
|
|
373
|
-
Program() {
|
|
352
|
+
Program(node) {
|
|
353
|
+
if (optionErrors && optionErrors.length > 0) {
|
|
354
|
+
optionErrors.forEach((details) => {
|
|
355
|
+
context.report({
|
|
356
|
+
node,
|
|
357
|
+
messageId: "invalidRuleConfiguration",
|
|
358
|
+
data: { details },
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
}
|
|
374
362
|
const comments = sourceCode.getAllComments() || [];
|
|
375
363
|
comments.forEach((comment) => {
|
|
376
|
-
processComment(context, comment);
|
|
364
|
+
processComment(context, comment, options);
|
|
377
365
|
});
|
|
378
366
|
},
|
|
379
367
|
};
|