eslint-plugin-traceability 1.10.0 → 1.10.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/CHANGELOG.md +3 -3
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +11 -0
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +21 -0
- package/lib/src/rules/helpers/valid-annotation-format-validators.d.ts +125 -0
- package/lib/src/rules/helpers/valid-annotation-format-validators.js +270 -0
- package/lib/src/rules/valid-annotation-format.js +10 -243
- package/lib/tests/rules/valid-annotation-format.test.js +71 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
## [1.10.1](https://github.com/voder-ai/eslint-plugin-traceability/compare/v1.10.0...v1.10.1) (2025-12-05)
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
###
|
|
4
|
+
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* support JSDoc tag coexistence for annotation parsing ([31e9416](https://github.com/voder-ai/eslint-plugin-traceability/commit/31e9416d201fd347051bc44521d3d3b840a244a1))
|
|
7
7
|
|
|
8
8
|
# Changelog
|
|
9
9
|
|
|
@@ -28,3 +28,14 @@ export interface PendingAnnotation {
|
|
|
28
28
|
* of the line for downstream logic.
|
|
29
29
|
*/
|
|
30
30
|
export declare function normalizeCommentLine(rawLine: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Detect whether a normalized comment line starts with a non-traceability JSDoc tag.
|
|
33
|
+
*
|
|
34
|
+
* This is used to distinguish regular JSDoc tags (e.g. @param, @returns) from
|
|
35
|
+
* traceability-related annotations such as @story, @req, and @supports.
|
|
36
|
+
*
|
|
37
|
+
* @supports docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md
|
|
38
|
+
* @req REQ-JSDOC-BOUNDARY-DETECTION
|
|
39
|
+
* @req REQ-JSDOC-TAG-COEXISTENCE
|
|
40
|
+
*/
|
|
41
|
+
export declare function isNonTraceabilityJSDocTagLine(normalized: string): boolean;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.normalizeCommentLine = normalizeCommentLine;
|
|
16
|
+
exports.isNonTraceabilityJSDocTagLine = isNonTraceabilityJSDocTagLine;
|
|
16
17
|
/**
|
|
17
18
|
* Normalize a raw comment line to make annotation parsing more robust.
|
|
18
19
|
*
|
|
@@ -34,3 +35,23 @@ function normalizeCommentLine(rawLine) {
|
|
|
34
35
|
}
|
|
35
36
|
return trimmed.slice(annotationMatch.index);
|
|
36
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Detect whether a normalized comment line starts with a non-traceability JSDoc tag.
|
|
40
|
+
*
|
|
41
|
+
* This is used to distinguish regular JSDoc tags (e.g. @param, @returns) from
|
|
42
|
+
* traceability-related annotations such as @story, @req, and @supports.
|
|
43
|
+
*
|
|
44
|
+
* @supports docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md
|
|
45
|
+
* @req REQ-JSDOC-BOUNDARY-DETECTION
|
|
46
|
+
* @req REQ-JSDOC-TAG-COEXISTENCE
|
|
47
|
+
*/
|
|
48
|
+
function isNonTraceabilityJSDocTagLine(normalized) {
|
|
49
|
+
const trimmed = normalized.trimStart();
|
|
50
|
+
if (!trimmed || !trimmed.startsWith("@")) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (/^@(story|req|supports)\b/.test(trimmed)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validators and helper functions for the valid-annotation-format rule.
|
|
3
|
+
*
|
|
4
|
+
* This module contains the core validation logic that was originally
|
|
5
|
+
* embedded in src/rules/valid-annotation-format.ts. It is extracted
|
|
6
|
+
* here to keep the main rule module smaller and easier to read while
|
|
7
|
+
* preserving existing behavior.
|
|
8
|
+
*
|
|
9
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
10
|
+
* @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
|
|
11
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
12
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
13
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
14
|
+
* @req REQ-FORMAT-SPECIFICATION
|
|
15
|
+
* @req REQ-SYNTAX-VALIDATION
|
|
16
|
+
* @req REQ-PATH-FORMAT
|
|
17
|
+
* @req REQ-REQ-FORMAT
|
|
18
|
+
* @req REQ-MULTILINE-SUPPORT
|
|
19
|
+
* @req REQ-AUTOFIX-FORMAT
|
|
20
|
+
* @req REQ-ERROR-SPECIFICITY
|
|
21
|
+
* @req REQ-REGEX-VALIDATION
|
|
22
|
+
* @req REQ-BACKWARD-COMP
|
|
23
|
+
* @req REQ-SUPPORTS-PARSE
|
|
24
|
+
* @req REQ-FORMAT-VALIDATION
|
|
25
|
+
* @req REQ-MIXED-SUPPORT
|
|
26
|
+
*/
|
|
27
|
+
import type { ResolvedAnnotationOptions } from "./valid-annotation-options";
|
|
28
|
+
import type { PendingAnnotation } from "./valid-annotation-format-internal";
|
|
29
|
+
/**
|
|
30
|
+
* Report an invalid @story annotation without applying a fix.
|
|
31
|
+
*
|
|
32
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
33
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
34
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
35
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
36
|
+
*/
|
|
37
|
+
export declare function reportInvalidStoryFormat(context: any, comment: any, collapsed: string, options: ResolvedAnnotationOptions): void;
|
|
38
|
+
/**
|
|
39
|
+
* Compute the text replacement for an invalid @story annotation within a comment.
|
|
40
|
+
*
|
|
41
|
+
* This helper:
|
|
42
|
+
* - finds the @story tag in the raw comment text,
|
|
43
|
+
* - computes the character range of its value,
|
|
44
|
+
* - and returns an ESLint fix that replaces only that range.
|
|
45
|
+
*
|
|
46
|
+
* Returns null when the tag or value cannot be safely located.
|
|
47
|
+
*
|
|
48
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
49
|
+
* @req REQ-AUTOFIX-SAFE
|
|
50
|
+
* @req REQ-AUTOFIX-PRESERVE
|
|
51
|
+
*/
|
|
52
|
+
export declare function createStoryFix(context: any, comment: any, fixed: string): null | (() => any);
|
|
53
|
+
/**
|
|
54
|
+
* Report an invalid @story annotation and attempt a minimal, safe auto-fix
|
|
55
|
+
* for common path suffix issues by locating and replacing the path text
|
|
56
|
+
* within the original comment.
|
|
57
|
+
*
|
|
58
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
59
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
60
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
61
|
+
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
62
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
63
|
+
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and avoid changing semantics
|
|
64
|
+
* @req REQ-AUTOFIX-PRESERVE - Auto-fix must preserve surrounding formatting and comments
|
|
65
|
+
*/
|
|
66
|
+
export declare function reportInvalidStoryFormatWithFix(context: any, comment: any, collapsed: string, fixed: string): void;
|
|
67
|
+
/**
|
|
68
|
+
* Validate a @story annotation value and report detailed errors when needed.
|
|
69
|
+
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
70
|
+
*
|
|
71
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
72
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
73
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
74
|
+
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
75
|
+
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
76
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
77
|
+
* @req REQ-REGEX-VALIDATION - Validate configurable story regex patterns and fall back safely
|
|
78
|
+
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
79
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
80
|
+
*/
|
|
81
|
+
export declare function validateStoryAnnotation(context: any, comment: any, rawValue: string, options: ResolvedAnnotationOptions): void;
|
|
82
|
+
/**
|
|
83
|
+
* Validate a @req annotation value and report detailed errors when needed.
|
|
84
|
+
*
|
|
85
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
86
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
87
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
88
|
+
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
89
|
+
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
90
|
+
* @req REQ-REGEX-VALIDATION - Validate configurable requirement regex patterns and fall back safely
|
|
91
|
+
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
92
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
93
|
+
*/
|
|
94
|
+
export declare function validateReqAnnotation(context: any, comment: any, rawValue: string, options: ResolvedAnnotationOptions): void;
|
|
95
|
+
/**
|
|
96
|
+
* Validate an @supports annotation value and report detailed errors when needed.
|
|
97
|
+
*
|
|
98
|
+
* Expected format:
|
|
99
|
+
* @supports <storyPath> <REQ-ID> [<REQ-ID> ...]
|
|
100
|
+
*
|
|
101
|
+
* Validation rules:
|
|
102
|
+
* - Value must include at least a story path and one requirement ID.
|
|
103
|
+
* - Story path must match the same storyPattern used for @story (no auto-fix).
|
|
104
|
+
* - Each subsequent token must match reqPattern and is validated individually.
|
|
105
|
+
*
|
|
106
|
+
* Story path issues are reported with "invalidImplementsFormat" and
|
|
107
|
+
* requirement ID issues reuse the existing "invalidReqFormat" message.
|
|
108
|
+
*
|
|
109
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
110
|
+
* @req REQ-SUPPORTS-PARSE - Parse @supports annotations without affecting @story/@req
|
|
111
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
112
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
113
|
+
*/
|
|
114
|
+
export declare function validateImplementsAnnotation(context: any, comment: any, rawValue: string, options: ResolvedAnnotationOptions): void;
|
|
115
|
+
/**
|
|
116
|
+
* Finalize and validate the currently pending annotation, if any.
|
|
117
|
+
*
|
|
118
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
119
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
120
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
121
|
+
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
122
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
123
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
124
|
+
*/
|
|
125
|
+
export declare function finalizePendingAnnotation(context: any, comment: any, options: ResolvedAnnotationOptions, pending: PendingAnnotation | null): PendingAnnotation | null;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Validators and helper functions for the valid-annotation-format rule.
|
|
4
|
+
*
|
|
5
|
+
* This module contains the core validation logic that was originally
|
|
6
|
+
* embedded in src/rules/valid-annotation-format.ts. It is extracted
|
|
7
|
+
* here to keep the main rule module smaller and easier to read while
|
|
8
|
+
* preserving existing behavior.
|
|
9
|
+
*
|
|
10
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
11
|
+
* @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
|
|
12
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
13
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
14
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
15
|
+
* @req REQ-FORMAT-SPECIFICATION
|
|
16
|
+
* @req REQ-SYNTAX-VALIDATION
|
|
17
|
+
* @req REQ-PATH-FORMAT
|
|
18
|
+
* @req REQ-REQ-FORMAT
|
|
19
|
+
* @req REQ-MULTILINE-SUPPORT
|
|
20
|
+
* @req REQ-AUTOFIX-FORMAT
|
|
21
|
+
* @req REQ-ERROR-SPECIFICITY
|
|
22
|
+
* @req REQ-REGEX-VALIDATION
|
|
23
|
+
* @req REQ-BACKWARD-COMP
|
|
24
|
+
* @req REQ-SUPPORTS-PARSE
|
|
25
|
+
* @req REQ-FORMAT-VALIDATION
|
|
26
|
+
* @req REQ-MIXED-SUPPORT
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.reportInvalidStoryFormat = reportInvalidStoryFormat;
|
|
30
|
+
exports.createStoryFix = createStoryFix;
|
|
31
|
+
exports.reportInvalidStoryFormatWithFix = reportInvalidStoryFormatWithFix;
|
|
32
|
+
exports.validateStoryAnnotation = validateStoryAnnotation;
|
|
33
|
+
exports.validateReqAnnotation = validateReqAnnotation;
|
|
34
|
+
exports.validateImplementsAnnotation = validateImplementsAnnotation;
|
|
35
|
+
exports.finalizePendingAnnotation = finalizePendingAnnotation;
|
|
36
|
+
const valid_annotation_utils_1 = require("./valid-annotation-utils");
|
|
37
|
+
const valid_implements_utils_1 = require("./valid-implements-utils");
|
|
38
|
+
const valid_annotation_options_1 = require("./valid-annotation-options");
|
|
39
|
+
/**
|
|
40
|
+
* Report an invalid @story annotation without applying a fix.
|
|
41
|
+
*
|
|
42
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
43
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
44
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
45
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
46
|
+
*/
|
|
47
|
+
function reportInvalidStoryFormat(context, comment, collapsed, options) {
|
|
48
|
+
context.report({
|
|
49
|
+
node: comment,
|
|
50
|
+
messageId: "invalidStoryFormat",
|
|
51
|
+
data: { details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("invalid", collapsed, options) },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compute the text replacement for an invalid @story annotation within a comment.
|
|
56
|
+
*
|
|
57
|
+
* This helper:
|
|
58
|
+
* - finds the @story tag in the raw comment text,
|
|
59
|
+
* - computes the character range of its value,
|
|
60
|
+
* - and returns an ESLint fix that replaces only that range.
|
|
61
|
+
*
|
|
62
|
+
* Returns null when the tag or value cannot be safely located.
|
|
63
|
+
*
|
|
64
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
65
|
+
* @req REQ-AUTOFIX-SAFE
|
|
66
|
+
* @req REQ-AUTOFIX-PRESERVE
|
|
67
|
+
*/
|
|
68
|
+
function createStoryFix(context, comment, fixed) {
|
|
69
|
+
const sourceCode = context.getSourceCode();
|
|
70
|
+
const commentText = sourceCode.getText(comment);
|
|
71
|
+
const search = "@story";
|
|
72
|
+
const tagIndex = commentText.indexOf(search);
|
|
73
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
74
|
+
// @req REQ-AUTOFIX-SAFE - Skip auto-fix when @story tag cannot be reliably located
|
|
75
|
+
if (tagIndex === valid_annotation_utils_1.TAG_NOT_FOUND_INDEX) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const afterTagIndex = tagIndex + search.length;
|
|
79
|
+
const rest = commentText.slice(afterTagIndex);
|
|
80
|
+
const valueMatch = rest.match(/[^\S\r\n]*([^\r\n*]+)/);
|
|
81
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
82
|
+
// @req REQ-AUTOFIX-SAFE - Abort auto-fix when story value range cannot be safely determined
|
|
83
|
+
if (!valueMatch || valueMatch.index === undefined) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const valueStartInComment = afterTagIndex +
|
|
87
|
+
valueMatch.index +
|
|
88
|
+
(valueMatch[0].length - valueMatch[1].length);
|
|
89
|
+
const valueEndInComment = valueStartInComment + valueMatch[1].length;
|
|
90
|
+
const start = comment.range[0];
|
|
91
|
+
const fixRange = [
|
|
92
|
+
start + valueStartInComment,
|
|
93
|
+
start + valueEndInComment,
|
|
94
|
+
];
|
|
95
|
+
return () => (fixer) => fixer.replaceTextRange(fixRange, fixed);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Report an invalid @story annotation and attempt a minimal, safe auto-fix
|
|
99
|
+
* for common path suffix issues by locating and replacing the path text
|
|
100
|
+
* within the original comment.
|
|
101
|
+
*
|
|
102
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
103
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
104
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
105
|
+
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
106
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
107
|
+
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and avoid changing semantics
|
|
108
|
+
* @req REQ-AUTOFIX-PRESERVE - Auto-fix must preserve surrounding formatting and comments
|
|
109
|
+
*/
|
|
110
|
+
function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
111
|
+
const fixFactory = createStoryFix(context, comment, fixed);
|
|
112
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
113
|
+
// @req REQ-AUTOFIX-SAFE - Fall back to reporting without fix when safe fix cannot be created
|
|
114
|
+
if (!fixFactory) {
|
|
115
|
+
reportInvalidStoryFormat(context, comment, collapsed, (0, valid_annotation_options_1.getResolvedDefaults)());
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
context.report({
|
|
119
|
+
node: comment,
|
|
120
|
+
messageId: "invalidStoryFormat",
|
|
121
|
+
data: {
|
|
122
|
+
details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("invalid", collapsed, (0, valid_annotation_options_1.getResolvedDefaults)()),
|
|
123
|
+
},
|
|
124
|
+
fix: fixFactory(),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Validate a @story annotation value and report detailed errors when needed.
|
|
129
|
+
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
130
|
+
*
|
|
131
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
132
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
133
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
134
|
+
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
135
|
+
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
136
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
137
|
+
* @req REQ-REGEX-VALIDATION - Validate configurable story regex patterns and fall back safely
|
|
138
|
+
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
139
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
140
|
+
*/
|
|
141
|
+
function validateStoryAnnotation(context, comment, rawValue, options) {
|
|
142
|
+
const trimmed = rawValue.trim();
|
|
143
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
144
|
+
// @req REQ-PATH-FORMAT - Treat missing @story value as a specific validation error
|
|
145
|
+
if (!trimmed) {
|
|
146
|
+
context.report({
|
|
147
|
+
node: comment,
|
|
148
|
+
messageId: "invalidStoryFormat",
|
|
149
|
+
data: { details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("missing", null, options) },
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const collapsed = (0, valid_annotation_utils_1.collapseAnnotationValue)(trimmed);
|
|
154
|
+
const pathPattern = options.storyPattern;
|
|
155
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
156
|
+
// @req REQ-PATH-FORMAT - Accept @story value when it matches configured storyPattern
|
|
157
|
+
if (pathPattern.test(collapsed)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
161
|
+
// @req REQ-PATH-FORMAT - Reject @story values containing internal whitespace as invalid
|
|
162
|
+
if (/\s/.test(trimmed)) {
|
|
163
|
+
reportInvalidStoryFormat(context, comment, collapsed, options);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const fixed = (0, valid_annotation_utils_1.getFixedStoryPath)(collapsed);
|
|
167
|
+
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
168
|
+
// @req REQ-AUTOFIX-FORMAT - Apply suffix-only auto-fix when it yields a pattern-compliant path
|
|
169
|
+
if (fixed && pathPattern.test(fixed)) {
|
|
170
|
+
reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
reportInvalidStoryFormat(context, comment, collapsed, options);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Validate a @req annotation value and report detailed errors when needed.
|
|
177
|
+
*
|
|
178
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
179
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
180
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
181
|
+
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
182
|
+
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
183
|
+
* @req REQ-REGEX-VALIDATION - Validate configurable requirement regex patterns and fall back safely
|
|
184
|
+
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
185
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
186
|
+
*/
|
|
187
|
+
function validateReqAnnotation(context, comment, rawValue, options) {
|
|
188
|
+
const trimmed = rawValue.trim();
|
|
189
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
190
|
+
// @req REQ-REQ-FORMAT - Treat missing @req value as a specific validation error
|
|
191
|
+
if (!trimmed) {
|
|
192
|
+
context.report({
|
|
193
|
+
node: comment,
|
|
194
|
+
messageId: "invalidReqFormat",
|
|
195
|
+
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("missing", null, options) },
|
|
196
|
+
});
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const collapsed = (0, valid_annotation_utils_1.collapseAnnotationValue)(trimmed);
|
|
200
|
+
const reqPattern = options.reqPattern;
|
|
201
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
202
|
+
// @req REQ-REQ-FORMAT - Flag @req identifiers that do not match the configured pattern
|
|
203
|
+
if (!reqPattern.test(collapsed)) {
|
|
204
|
+
context.report({
|
|
205
|
+
node: comment,
|
|
206
|
+
messageId: "invalidReqFormat",
|
|
207
|
+
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("invalid", collapsed, options) },
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Validate an @supports annotation value and report detailed errors when needed.
|
|
213
|
+
*
|
|
214
|
+
* Expected format:
|
|
215
|
+
* @supports <storyPath> <REQ-ID> [<REQ-ID> ...]
|
|
216
|
+
*
|
|
217
|
+
* Validation rules:
|
|
218
|
+
* - Value must include at least a story path and one requirement ID.
|
|
219
|
+
* - Story path must match the same storyPattern used for @story (no auto-fix).
|
|
220
|
+
* - Each subsequent token must match reqPattern and is validated individually.
|
|
221
|
+
*
|
|
222
|
+
* Story path issues are reported with "invalidImplementsFormat" and
|
|
223
|
+
* requirement ID issues reuse the existing "invalidReqFormat" message.
|
|
224
|
+
*
|
|
225
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
226
|
+
* @req REQ-SUPPORTS-PARSE - Parse @supports annotations without affecting @story/@req
|
|
227
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
228
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
229
|
+
*/
|
|
230
|
+
function validateImplementsAnnotation(context, comment, rawValue, options) {
|
|
231
|
+
const deps = {
|
|
232
|
+
MIN_IMPLEMENTS_TOKENS: valid_implements_utils_1.MIN_IMPLEMENTS_TOKENS,
|
|
233
|
+
reportMissingImplementsReqIds: valid_implements_utils_1.reportMissingImplementsReqIds,
|
|
234
|
+
reportMissingImplementsValue: valid_implements_utils_1.reportMissingImplementsValue,
|
|
235
|
+
reportInvalidImplementsReqId: valid_implements_utils_1.reportInvalidImplementsReqId,
|
|
236
|
+
reportInvalidImplementsStoryPath: valid_implements_utils_1.reportInvalidImplementsStoryPath,
|
|
237
|
+
};
|
|
238
|
+
(0, valid_implements_utils_1.validateImplementsAnnotationHelper)(deps, context, comment, {
|
|
239
|
+
rawValue,
|
|
240
|
+
options,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Finalize and validate the currently pending annotation, if any.
|
|
245
|
+
*
|
|
246
|
+
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
247
|
+
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
248
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
249
|
+
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
250
|
+
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
251
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
252
|
+
*/
|
|
253
|
+
function finalizePendingAnnotation(context, comment, options, pending) {
|
|
254
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
255
|
+
// @req REQ-MULTILINE-SUPPORT - Do nothing when there is no pending multi-line annotation to finalize
|
|
256
|
+
if (!pending) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
260
|
+
// @req REQ-SYNTAX-VALIDATION - Dispatch to @story or @req validator based on pending annotation type
|
|
261
|
+
// @req REQ-AUTOFIX-FORMAT - Route to story validator which may apply safe auto-fixes
|
|
262
|
+
// @req REQ-MIXED-SUPPORT - Ensure @story and @req annotations are handled independently
|
|
263
|
+
if (pending.type === "story") {
|
|
264
|
+
validateStoryAnnotation(context, comment, pending.value, options);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
validateReqAnnotation(context, comment, pending.value, options);
|
|
268
|
+
}
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
@@ -1,247 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const valid_annotation_options_1 = require("./helpers/valid-annotation-options");
|
|
4
|
-
const valid_annotation_utils_1 = require("./helpers/valid-annotation-utils");
|
|
5
|
-
const valid_implements_utils_1 = require("./helpers/valid-implements-utils");
|
|
6
4
|
const valid_annotation_format_internal_1 = require("./helpers/valid-annotation-format-internal");
|
|
7
|
-
|
|
8
|
-
* Report an invalid @story annotation without applying a fix.
|
|
9
|
-
*
|
|
10
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
11
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
12
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
13
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
14
|
-
*/
|
|
15
|
-
function reportInvalidStoryFormat(context, comment, collapsed, options) {
|
|
16
|
-
context.report({
|
|
17
|
-
node: comment,
|
|
18
|
-
messageId: "invalidStoryFormat",
|
|
19
|
-
data: { details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("invalid", collapsed, options) },
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Compute the text replacement for an invalid @story annotation within a comment.
|
|
24
|
-
*
|
|
25
|
-
* This helper:
|
|
26
|
-
* - finds the @story tag in the raw comment text,
|
|
27
|
-
* - computes the character range of its value,
|
|
28
|
-
* - and returns an ESLint fix that replaces only that range.
|
|
29
|
-
*
|
|
30
|
-
* Returns null when the tag or value cannot be safely located.
|
|
31
|
-
*
|
|
32
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
33
|
-
* @req REQ-AUTOFIX-SAFE
|
|
34
|
-
* @req REQ-AUTOFIX-PRESERVE
|
|
35
|
-
*/
|
|
36
|
-
function createStoryFix(context, comment, fixed) {
|
|
37
|
-
const sourceCode = context.getSourceCode();
|
|
38
|
-
const commentText = sourceCode.getText(comment);
|
|
39
|
-
const search = "@story";
|
|
40
|
-
const tagIndex = commentText.indexOf(search);
|
|
41
|
-
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
42
|
-
// @req REQ-AUTOFIX-SAFE - Skip auto-fix when @story tag cannot be reliably located
|
|
43
|
-
if (tagIndex === valid_annotation_utils_1.TAG_NOT_FOUND_INDEX) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
const afterTagIndex = tagIndex + search.length;
|
|
47
|
-
const rest = commentText.slice(afterTagIndex);
|
|
48
|
-
const valueMatch = rest.match(/[^\S\r\n]*([^\r\n*]+)/);
|
|
49
|
-
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
50
|
-
// @req REQ-AUTOFIX-SAFE - Abort auto-fix when story value range cannot be safely determined
|
|
51
|
-
if (!valueMatch || valueMatch.index === undefined) {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
const valueStartInComment = afterTagIndex +
|
|
55
|
-
valueMatch.index +
|
|
56
|
-
(valueMatch[0].length - valueMatch[1].length);
|
|
57
|
-
const valueEndInComment = valueStartInComment + valueMatch[1].length;
|
|
58
|
-
const start = comment.range[0];
|
|
59
|
-
const fixRange = [
|
|
60
|
-
start + valueStartInComment,
|
|
61
|
-
start + valueEndInComment,
|
|
62
|
-
];
|
|
63
|
-
return () => (fixer) => fixer.replaceTextRange(fixRange, fixed);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Report an invalid @story annotation and attempt a minimal, safe auto-fix
|
|
67
|
-
* for common path suffix issues by locating and replacing the path text
|
|
68
|
-
* within the original comment.
|
|
69
|
-
*
|
|
70
|
-
* This helper:
|
|
71
|
-
* - only adjusts the story path suffix when a safe, well-understood
|
|
72
|
-
* transformation is available, satisfying REQ-AUTOFIX-SAFE.
|
|
73
|
-
* - preserves all surrounding comment formatting, spacing, and text
|
|
74
|
-
* outside the path substring, satisfying REQ-AUTOFIX-PRESERVE.
|
|
75
|
-
*
|
|
76
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
77
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
78
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
79
|
-
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
80
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
81
|
-
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and avoid changing semantics
|
|
82
|
-
* @req REQ-AUTOFIX-PRESERVE - Auto-fix must preserve surrounding formatting and comments
|
|
83
|
-
*/
|
|
84
|
-
function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
85
|
-
const fixFactory = createStoryFix(context, comment, fixed);
|
|
86
|
-
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
87
|
-
// @req REQ-AUTOFIX-SAFE - Fall back to reporting without fix when safe fix cannot be created
|
|
88
|
-
if (!fixFactory) {
|
|
89
|
-
reportInvalidStoryFormat(context, comment, collapsed, (0, valid_annotation_options_1.getResolvedDefaults)());
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
context.report({
|
|
93
|
-
node: comment,
|
|
94
|
-
messageId: "invalidStoryFormat",
|
|
95
|
-
data: {
|
|
96
|
-
details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("invalid", collapsed, (0, valid_annotation_options_1.getResolvedDefaults)()),
|
|
97
|
-
},
|
|
98
|
-
fix: fixFactory(),
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Validate a @story annotation value and report detailed errors when needed.
|
|
103
|
-
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
104
|
-
*
|
|
105
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
106
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
107
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
108
|
-
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
109
|
-
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
110
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
111
|
-
* @req REQ-REGEX-VALIDATION - Validate configurable story regex patterns and fall back safely
|
|
112
|
-
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
113
|
-
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
114
|
-
*/
|
|
115
|
-
function validateStoryAnnotation(context, comment, rawValue, options) {
|
|
116
|
-
const trimmed = rawValue.trim();
|
|
117
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
118
|
-
// @req REQ-PATH-FORMAT - Treat missing @story value as a specific validation error
|
|
119
|
-
if (!trimmed) {
|
|
120
|
-
context.report({
|
|
121
|
-
node: comment,
|
|
122
|
-
messageId: "invalidStoryFormat",
|
|
123
|
-
data: { details: (0, valid_annotation_utils_1.buildStoryErrorMessage)("missing", null, options) },
|
|
124
|
-
});
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const collapsed = (0, valid_annotation_utils_1.collapseAnnotationValue)(trimmed);
|
|
128
|
-
const pathPattern = options.storyPattern;
|
|
129
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
130
|
-
// @req REQ-PATH-FORMAT - Accept @story value when it matches configured storyPattern
|
|
131
|
-
if (pathPattern.test(collapsed)) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
135
|
-
// @req REQ-PATH-FORMAT - Reject @story values containing internal whitespace as invalid
|
|
136
|
-
if (/\s/.test(trimmed)) {
|
|
137
|
-
reportInvalidStoryFormat(context, comment, collapsed, options);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
const fixed = (0, valid_annotation_utils_1.getFixedStoryPath)(collapsed);
|
|
141
|
-
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
142
|
-
// @req REQ-AUTOFIX-FORMAT - Apply suffix-only auto-fix when it yields a pattern-compliant path
|
|
143
|
-
if (fixed && pathPattern.test(fixed)) {
|
|
144
|
-
reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed);
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
reportInvalidStoryFormat(context, comment, collapsed, options);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Validate a @req annotation value and report detailed errors when needed.
|
|
151
|
-
*
|
|
152
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
153
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
154
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
155
|
-
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
156
|
-
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
157
|
-
* @req REQ-REGEX-VALIDATION - Validate configurable requirement regex patterns and fall back safely
|
|
158
|
-
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
159
|
-
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
160
|
-
*/
|
|
161
|
-
function validateReqAnnotation(context, comment, rawValue, options) {
|
|
162
|
-
const trimmed = rawValue.trim();
|
|
163
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
164
|
-
// @req REQ-REQ-FORMAT - Treat missing @req value as a specific validation error
|
|
165
|
-
if (!trimmed) {
|
|
166
|
-
context.report({
|
|
167
|
-
node: comment,
|
|
168
|
-
messageId: "invalidReqFormat",
|
|
169
|
-
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("missing", null, options) },
|
|
170
|
-
});
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
const collapsed = (0, valid_annotation_utils_1.collapseAnnotationValue)(trimmed);
|
|
174
|
-
const reqPattern = options.reqPattern;
|
|
175
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
176
|
-
// @req REQ-REQ-FORMAT - Flag @req identifiers that do not match the configured pattern
|
|
177
|
-
if (!reqPattern.test(collapsed)) {
|
|
178
|
-
context.report({
|
|
179
|
-
node: comment,
|
|
180
|
-
messageId: "invalidReqFormat",
|
|
181
|
-
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("invalid", collapsed, options) },
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Validate an @supports annotation value and report detailed errors when needed.
|
|
187
|
-
*
|
|
188
|
-
* Expected format:
|
|
189
|
-
* @supports <storyPath> <REQ-ID> [<REQ-ID> ...]
|
|
190
|
-
*
|
|
191
|
-
* Validation rules:
|
|
192
|
-
* - Value must include at least a story path and one requirement ID.
|
|
193
|
-
* - Story path must match the same storyPattern used for @story (no auto-fix).
|
|
194
|
-
* - Each subsequent token must match reqPattern and is validated individually.
|
|
195
|
-
*
|
|
196
|
-
* Story path issues are reported with "invalidImplementsFormat" and
|
|
197
|
-
* requirement ID issues reuse the existing "invalidReqFormat" message.
|
|
198
|
-
*
|
|
199
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
200
|
-
* @req REQ-SUPPORTS-PARSE - Parse @supports annotations without affecting @story/@req
|
|
201
|
-
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
202
|
-
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
203
|
-
*/
|
|
204
|
-
function validateImplementsAnnotation(context, comment, rawValue, options) {
|
|
205
|
-
const deps = {
|
|
206
|
-
MIN_IMPLEMENTS_TOKENS: valid_implements_utils_1.MIN_IMPLEMENTS_TOKENS,
|
|
207
|
-
reportMissingImplementsReqIds: valid_implements_utils_1.reportMissingImplementsReqIds,
|
|
208
|
-
reportMissingImplementsValue: valid_implements_utils_1.reportMissingImplementsValue,
|
|
209
|
-
reportInvalidImplementsReqId: valid_implements_utils_1.reportInvalidImplementsReqId,
|
|
210
|
-
reportInvalidImplementsStoryPath: valid_implements_utils_1.reportInvalidImplementsStoryPath,
|
|
211
|
-
};
|
|
212
|
-
(0, valid_implements_utils_1.validateImplementsAnnotationHelper)(deps, context, comment, {
|
|
213
|
-
rawValue,
|
|
214
|
-
options,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Finalize and validate the currently pending annotation, if any.
|
|
219
|
-
*
|
|
220
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
221
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
222
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
223
|
-
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
224
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
225
|
-
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
226
|
-
*/
|
|
227
|
-
function finalizePendingAnnotation(context, comment, options, pending) {
|
|
228
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
229
|
-
// @req REQ-MULTILINE-SUPPORT - Do nothing when there is no pending multi-line annotation to finalize
|
|
230
|
-
if (!pending) {
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
234
|
-
// @req REQ-SYNTAX-VALIDATION - Dispatch to @story or @req validator based on pending annotation type
|
|
235
|
-
// @req REQ-AUTOFIX-FORMAT - Route to story validator which may apply safe auto-fixes
|
|
236
|
-
// @req REQ-MIXED-SUPPORT - Ensure @story and @req annotations are handled independently
|
|
237
|
-
if (pending.type === "story") {
|
|
238
|
-
validateStoryAnnotation(context, comment, pending.value, options);
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
validateReqAnnotation(context, comment, pending.value, options);
|
|
242
|
-
}
|
|
243
|
-
return null;
|
|
244
|
-
}
|
|
5
|
+
const valid_annotation_format_validators_1 = require("./helpers/valid-annotation-format-validators");
|
|
245
6
|
/**
|
|
246
7
|
* Process a single normalized comment line and update the pending annotation state.
|
|
247
8
|
*
|
|
@@ -269,7 +30,7 @@ function processCommentLine({ normalized, pending, context, comment, options, })
|
|
|
269
30
|
// @req REQ-IMPLEMENTS-PARSE - Immediately validate @supports without starting multi-line state
|
|
270
31
|
if (isImplements) {
|
|
271
32
|
const implementsValue = normalized.replace(/^@supports\b/, "").trim();
|
|
272
|
-
validateImplementsAnnotation(context, comment, implementsValue, options);
|
|
33
|
+
(0, valid_annotation_format_validators_1.validateImplementsAnnotation)(context, comment, implementsValue, options);
|
|
273
34
|
return pending;
|
|
274
35
|
}
|
|
275
36
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
@@ -279,7 +40,7 @@ function processCommentLine({ normalized, pending, context, comment, options, })
|
|
|
279
40
|
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
280
41
|
// @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
281
42
|
if (isStory || isReq) {
|
|
282
|
-
finalizePendingAnnotation(context, comment, options, pending);
|
|
43
|
+
(0, valid_annotation_format_validators_1.finalizePendingAnnotation)(context, comment, options, pending);
|
|
283
44
|
const value = normalized.replace(/^@story\b|^@req\b/, "").trim();
|
|
284
45
|
return {
|
|
285
46
|
type: isStory ? "story" : "req",
|
|
@@ -287,6 +48,12 @@ function processCommentLine({ normalized, pending, context, comment, options, })
|
|
|
287
48
|
hasValue: value.trim().length > 0,
|
|
288
49
|
};
|
|
289
50
|
}
|
|
51
|
+
// Implement JSDoc tag coexistence behavior: terminate @story/@req values when a new non-traceability JSDoc tag line (e.g., @param, @returns) is encountered.
|
|
52
|
+
// @supports docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md REQ-ANNOTATION-TERMINATION REQ-CONTINUATION-LOGIC
|
|
53
|
+
if ((0, valid_annotation_format_internal_1.isNonTraceabilityJSDocTagLine)(normalized)) {
|
|
54
|
+
(0, valid_annotation_format_validators_1.finalizePendingAnnotation)(context, comment, options, pending);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
290
57
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
291
58
|
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
292
59
|
// @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -344,7 +111,7 @@ function processComment(context, comment, options) {
|
|
|
344
111
|
options,
|
|
345
112
|
});
|
|
346
113
|
});
|
|
347
|
-
finalizePendingAnnotation(context, comment, options, pending);
|
|
114
|
+
(0, valid_annotation_format_validators_1.finalizePendingAnnotation)(context, comment, options, pending);
|
|
348
115
|
}
|
|
349
116
|
exports.default = {
|
|
350
117
|
meta: {
|
|
@@ -23,6 +23,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
23
23
|
* @req REQ-SUPPORTS-PARSE - Rule parses @supports annotations with story and requirement references
|
|
24
24
|
* @req REQ-FORMAT-VALIDATION - Rule validates story and requirement formats inside @supports annotations
|
|
25
25
|
* @req REQ-MIXED-SUPPORT - Rule supports mixed @story/@req/@supports usage in the same comment
|
|
26
|
+
* Tests for: docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md
|
|
27
|
+
* @story docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md
|
|
28
|
+
* @req REQ-JSDOC-TAG-COEXISTENCE - Rule allows traceability annotations to coexist with other JSDoc tags
|
|
29
|
+
* @req REQ-ANNOTATION-TERMINATION - Rule correctly terminates traceability annotation values at JSDoc tag boundaries
|
|
30
|
+
* @req REQ-JSDOC-BOUNDARY-DETECTION - Rule detects @param/@returns and similar tags as boundaries
|
|
31
|
+
* @req REQ-CONTINUATION-LOGIC - Rule correctly decides when to continue or stop multi-line traceability values
|
|
32
|
+
* @req REQ-NO-FALSE-POSITIVES - Rule does not report false positives when JSDoc tags follow traceability tags
|
|
33
|
+
* @req REQ-PRESERVE-MULTILINE - Rule preserves multi-line story/req values without including following JSDoc tags
|
|
26
34
|
*/
|
|
27
35
|
const eslint_1 = require("eslint");
|
|
28
36
|
const valid_annotation_format_1 = __importDefault(require("../../src/rules/valid-annotation-format"));
|
|
@@ -194,6 +202,69 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
|
|
|
194
202
|
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-IMPLEMENTS-PARSE REQ-FORMAT-VALIDATION REQ-MIXED-SUPPORT
|
|
195
203
|
*/`,
|
|
196
204
|
},
|
|
205
|
+
{
|
|
206
|
+
name: "[REQ-JSDOC-TAG-COEXISTENCE] traceability before other JSDoc tags",
|
|
207
|
+
code: `/**
|
|
208
|
+
* @story docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md
|
|
209
|
+
* @req REQ-JSDOC-TAG-COEXISTENCE
|
|
210
|
+
* @param {string} id - Identifier for the lookup.
|
|
211
|
+
* @returns {Promise<void>} - Completes when finished.
|
|
212
|
+
*/
|
|
213
|
+
function fetchById(id) {
|
|
214
|
+
return Promise.resolve();
|
|
215
|
+
}`,
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: "[REQ-JSDOC-TAG-COEXISTENCE] traceability after other JSDoc tags",
|
|
219
|
+
code: `/**
|
|
220
|
+
* Fetch a user by id.
|
|
221
|
+
*
|
|
222
|
+
* @param {string} id - Identifier for the lookup.
|
|
223
|
+
* @returns {Promise<void>} - Completes when finished.
|
|
224
|
+
* @story docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md
|
|
225
|
+
* @req REQ-ANNOTATION-TERMINATION
|
|
226
|
+
*/
|
|
227
|
+
function fetchUser(id) {
|
|
228
|
+
return Promise.resolve();
|
|
229
|
+
}`,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: "[REQ-JSDOC-TAG-COEXISTENCE] mixed positions of traceability and other JSDoc tags",
|
|
233
|
+
code: `/**
|
|
234
|
+
* Update a record with new data.
|
|
235
|
+
*
|
|
236
|
+
* @story docs/stories/022.0-DEV-JSDOC-COEXISTENCE.story.md
|
|
237
|
+
* @param {string} id - Identifier.
|
|
238
|
+
* @req REQ-JSDOC-BOUNDARY-DETECTION
|
|
239
|
+
* @param {object} payload - Updated fields.
|
|
240
|
+
* @returns {boolean} - True if updated.
|
|
241
|
+
* @req REQ-CONTINUATION-LOGIC
|
|
242
|
+
*/
|
|
243
|
+
function updateRecord(id, payload) {
|
|
244
|
+
return true;
|
|
245
|
+
}`,
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "[REQ-PRESERVE-MULTILINE] multi-line @story annotation before other JSDoc tags",
|
|
249
|
+
code: `/**
|
|
250
|
+
* @story docs/stories/022.0-DEV-
|
|
251
|
+
* JSDOC-COEXISTENCE.story.md
|
|
252
|
+
* @param {string} id - Identifier for the lookup.
|
|
253
|
+
* @returns {Promise<void>} - Completes when finished.
|
|
254
|
+
*/
|
|
255
|
+
function loadForStory(id) {
|
|
256
|
+
return Promise.resolve();
|
|
257
|
+
}`,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: "[REQ-NO-FALSE-POSITIVES] JSDoc tags do not pollute requirement ID when following @req",
|
|
261
|
+
code: `/**
|
|
262
|
+
* @req REQ-OPTIMIZATION
|
|
263
|
+
* @param {object} data - Input payload.
|
|
264
|
+
* @returns {void}
|
|
265
|
+
*/
|
|
266
|
+
function optimize(data) {}`,
|
|
267
|
+
},
|
|
197
268
|
],
|
|
198
269
|
invalid: [
|
|
199
270
|
makeInvalidStory({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-traceability",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.1",
|
|
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",
|