eslint-plugin-traceability 1.7.0 → 1.8.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/CHANGELOG.md +82 -0
- package/README.md +73 -32
- package/docs/ci-cd-pipeline.md +224 -0
- package/docs/cli-integration.md +22 -0
- package/docs/code-quality-refactor-opportunities-2025-12-03.md +78 -0
- package/docs/config-presets.md +38 -0
- package/docs/conventional-commits-guide.md +185 -0
- package/docs/custom-rules-development-guide.md +659 -0
- package/docs/decisions/0001-allow-dynamic-require-for-built-plugins.md +26 -0
- package/docs/decisions/001-typescript-for-eslint-plugin.accepted.md +111 -0
- package/docs/decisions/002-jest-for-eslint-testing.accepted.md +137 -0
- package/docs/decisions/003-code-quality-ratcheting-plan.md +48 -0
- package/docs/decisions/004-automated-version-bumping-for-ci-cd.md +196 -0
- package/docs/decisions/005-github-actions-validation-tooling.accepted.md +144 -0
- package/docs/decisions/006-semantic-release-for-automated-publishing.accepted.md +227 -0
- package/docs/decisions/007-github-releases-over-changelog.accepted.md +216 -0
- package/docs/decisions/008-ci-audit-flags.accepted.md +60 -0
- package/docs/decisions/009-security-focused-lint-rules.accepted.md +64 -0
- package/docs/decisions/010-implements-annotation-for-multi-story-requirements.proposed.md +184 -0
- package/docs/decisions/adr-0001-console-usage-for-cli-guards.md +190 -0
- package/docs/decisions/adr-accept-dev-dep-risk-glob.md +40 -0
- package/docs/decisions/adr-commit-branch-tests.md +54 -0
- package/docs/decisions/adr-maintenance-cli-interface.md +140 -0
- package/docs/decisions/adr-pre-push-parity.md +112 -0
- package/docs/decisions/code-quality-ratcheting-plan.md +53 -0
- package/docs/dependency-health.md +238 -0
- package/docs/eslint-9-setup-guide.md +517 -0
- package/docs/eslint-plugin-development-guide.md +487 -0
- package/docs/functionality-coverage-2025-12-03.md +250 -0
- package/docs/jest-testing-guide.md +100 -0
- package/docs/rules/prefer-implements-annotation.md +219 -0
- package/docs/rules/require-branch-annotation.md +71 -0
- package/docs/rules/require-req-annotation.md +203 -0
- package/docs/rules/require-story-annotation.md +159 -0
- package/docs/rules/valid-annotation-format.md +418 -0
- package/docs/rules/valid-req-reference.md +153 -0
- package/docs/rules/valid-story-reference.md +120 -0
- package/docs/security-incidents/2025-11-17-glob-cli-incident.md +45 -0
- package/docs/security-incidents/2025-11-18-brace-expansion-redos.md +45 -0
- package/docs/security-incidents/2025-11-18-bundled-dev-deps-accepted-risk.md +93 -0
- package/docs/security-incidents/2025-11-18-tar-race-condition.md +43 -0
- package/docs/security-incidents/2025-12-03-dependency-health-review.md +58 -0
- package/docs/security-incidents/SECURITY-INCIDENT-2025-11-18-semantic-release-bundled-npm.known-error.md +104 -0
- package/docs/security-incidents/SECURITY-INCIDENT-TEMPLATE.md +37 -0
- package/docs/security-incidents/dependency-override-rationale.md +57 -0
- package/docs/security-incidents/dev-deps-high.json +116 -0
- package/docs/security-incidents/handling-procedure.md +54 -0
- package/docs/stories/001.0-DEV-PLUGIN-SETUP.story.md +92 -0
- package/docs/stories/002.0-DEV-ESLINT-CONFIG.story.md +82 -0
- package/docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md +112 -0
- package/docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md +153 -0
- package/docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md +138 -0
- package/docs/stories/006.0-DEV-FILE-VALIDATION.story.md +144 -0
- package/docs/stories/007.0-DEV-ERROR-REPORTING.story.md +163 -0
- package/docs/stories/008.0-DEV-AUTO-FIX.story.md +150 -0
- package/docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md +117 -0
- package/docs/stories/010.0-DEV-DEEP-VALIDATION.story.md +124 -0
- package/docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md +149 -0
- package/docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md +216 -0
- package/docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md +236 -0
- package/docs/stories/developer-story.map.md +120 -0
- package/docs/ts-jest-presets-guide.md +548 -0
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.js +2 -0
- package/lib/src/maintenance/batch.d.ts +5 -0
- package/lib/src/maintenance/batch.js +5 -0
- package/lib/src/maintenance/cli.js +34 -212
- package/lib/src/maintenance/commands.d.ts +32 -0
- package/lib/src/maintenance/commands.js +139 -0
- package/lib/src/maintenance/detect.d.ts +2 -0
- package/lib/src/maintenance/detect.js +4 -0
- package/lib/src/maintenance/flags.d.ts +99 -0
- package/lib/src/maintenance/flags.js +121 -0
- package/lib/src/maintenance/report.d.ts +2 -0
- package/lib/src/maintenance/report.js +2 -0
- package/lib/src/maintenance/update.d.ts +4 -0
- package/lib/src/maintenance/update.js +4 -0
- package/lib/src/rules/helpers/require-story-io.d.ts +3 -0
- package/lib/src/rules/helpers/require-story-io.js +20 -6
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +30 -0
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +36 -0
- package/lib/src/rules/helpers/valid-annotation-options.js +15 -4
- package/lib/src/rules/helpers/valid-annotation-utils.js +5 -0
- package/lib/src/rules/helpers/valid-implements-utils.d.ts +75 -0
- package/lib/src/rules/helpers/valid-implements-utils.js +149 -0
- package/lib/src/rules/helpers/valid-story-reference-helpers.d.ts +3 -4
- package/lib/src/rules/prefer-implements-annotation.d.ts +39 -0
- package/lib/src/rules/prefer-implements-annotation.js +276 -0
- package/lib/src/rules/valid-annotation-format.js +87 -28
- package/lib/src/rules/valid-req-reference.js +71 -0
- package/lib/src/utils/reqAnnotationDetection.d.ts +4 -1
- package/lib/src/utils/reqAnnotationDetection.js +43 -15
- package/lib/tests/maintenance/cli.test.js +89 -0
- package/lib/tests/plugin-default-export-and-configs.test.js +3 -0
- package/lib/tests/rules/prefer-implements-annotation.test.d.ts +1 -0
- package/lib/tests/rules/prefer-implements-annotation.test.js +84 -0
- package/lib/tests/rules/require-req-annotation.test.js +8 -1
- package/lib/tests/rules/require-story-annotation.test.js +9 -4
- package/lib/tests/rules/valid-annotation-format.test.js +78 -0
- package/lib/tests/rules/valid-req-reference.test.js +34 -0
- package/lib/tests/utils/ts-language-options.d.ts +1 -7
- package/lib/tests/utils/ts-language-options.js +8 -5
- package/package.json +7 -3
- package/user-docs/api-reference.md +507 -0
- package/user-docs/eslint-9-setup-guide.md +639 -0
- package/user-docs/examples.md +74 -0
- package/user-docs/migration-guide.md +158 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint rule implementation for preferring the consolidated `@implements`
|
|
3
|
+
* annotation over legacy combinations of `@story` and `@req` within JSDoc
|
|
4
|
+
* block comments. This module provides:
|
|
5
|
+
*
|
|
6
|
+
* - Detection of legacy `@story` + `@req` patterns.
|
|
7
|
+
* - Identification of multi-story comment blocks that are not safely
|
|
8
|
+
* auto-fixable.
|
|
9
|
+
* - A conservative auto-fix that rewrites simple, single-story patterns into
|
|
10
|
+
* a single `@implements` annotation while preserving formatting.
|
|
11
|
+
*
|
|
12
|
+
* The rule is intended as an **optional migration aid** to help projects
|
|
13
|
+
* gradually move to the newer `@implements` format without breaking existing
|
|
14
|
+
* traceability links.
|
|
15
|
+
*
|
|
16
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
17
|
+
* @req REQ-OPTIONAL-WARNING - Emit configurable recommendation diagnostics for legacy @story/@req usage
|
|
18
|
+
* @req REQ-MULTI-STORY-DETECT - Detect multi-story patterns that cannot be auto-fixed
|
|
19
|
+
* @req REQ-SINGLE-STORY-FIX - Restrict auto-fix to single-story, single-path cases
|
|
20
|
+
* @req REQ-PRESERVE-FORMAT - Preserve original JSDoc indentation and prefix formatting
|
|
21
|
+
* @req REQ-VALID-OUTPUT - Avoid emitting auto-fixes for complex or ambiguous patterns
|
|
22
|
+
* @req REQ-BACKWARD-COMP-VALIDATION - Keep legacy @story/@req annotations valid when the rule is disabled
|
|
23
|
+
* @req REQ-AUTO-FIX - Provide safe, opt-in auto-fix for simple legacy patterns
|
|
24
|
+
*/
|
|
25
|
+
import type { Rule } from "eslint";
|
|
26
|
+
/**
|
|
27
|
+
* ESLint rule: prefer-implements-annotation
|
|
28
|
+
*
|
|
29
|
+
* Recommend migrating from legacy `@story` + `@req` annotations to the
|
|
30
|
+
* newer `@implements` format. This rule is **disabled by default** and
|
|
31
|
+
* is intended as an optional, opt-in migration aid.
|
|
32
|
+
*
|
|
33
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
34
|
+
* @req REQ-OPTIONAL-WARNING - Emit configurable recommendation diagnostics for legacy @story/@req usage
|
|
35
|
+
* @req REQ-MULTI-STORY-DETECT - Detect multi-story patterns that cannot be auto-fixed
|
|
36
|
+
* @req REQ-BACKWARD-COMP-VALIDATION - Keep legacy @story/@req annotations valid when the rule is disabled
|
|
37
|
+
*/
|
|
38
|
+
declare const preferImplementsAnnotationRule: Rule.RuleModule;
|
|
39
|
+
export default preferImplementsAnnotationRule;
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const valid_annotation_format_internal_1 = require("./helpers/valid-annotation-format-internal");
|
|
4
|
+
// Maximum number of distinct @story paths allowed before treating as "multi-story".
|
|
5
|
+
// @req REQ-MULTI-STORY-DETECT - Centralized threshold constant for detecting multi-story patterns
|
|
6
|
+
const MULTI_STORY_THRESHOLD = 1;
|
|
7
|
+
// Minimum number of tokens required for a valid @story annotation line.
|
|
8
|
+
// @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
9
|
+
// @req REQ-MULTI-STORY-DETECT
|
|
10
|
+
const MIN_STORY_TOKENS = 2;
|
|
11
|
+
// Minimum number of tokens required for a valid @req annotation line, aligned with story tokens.
|
|
12
|
+
const MIN_REQ_TOKENS = MIN_STORY_TOKENS;
|
|
13
|
+
// Length of the opening "/*" portion of a block comment prefix.
|
|
14
|
+
const COMMENT_PREFIX_LENGTH = 2;
|
|
15
|
+
function collectStoryAndReqMetadata(comment) {
|
|
16
|
+
const rawValue = comment.value || "";
|
|
17
|
+
const rawLines = rawValue.split(/\r?\n/);
|
|
18
|
+
const storyLineIndices = [];
|
|
19
|
+
const reqLineIndices = [];
|
|
20
|
+
const reqIds = [];
|
|
21
|
+
let storyPath = null;
|
|
22
|
+
rawLines.forEach((rawLine, index) => {
|
|
23
|
+
const normalized = (0, valid_annotation_format_internal_1.normalizeCommentLine)(rawLine);
|
|
24
|
+
if (!normalized)
|
|
25
|
+
return;
|
|
26
|
+
if (/^@implements\b/.test(normalized)) {
|
|
27
|
+
// Mixed @implements usage should have been filtered out earlier
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (/^@story\b/.test(normalized)) {
|
|
31
|
+
const parts = normalized.split(/\s+/);
|
|
32
|
+
if (parts.length === MIN_STORY_TOKENS) {
|
|
33
|
+
storyLineIndices.push(index);
|
|
34
|
+
storyPath = parts[1];
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
storyPath = null;
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (/^@req\b/.test(normalized)) {
|
|
42
|
+
const parts = normalized.split(/\s+/);
|
|
43
|
+
if (parts.length === MIN_REQ_TOKENS) {
|
|
44
|
+
reqLineIndices.push(index);
|
|
45
|
+
reqIds.push(parts[1]);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Complex @req form; bail out entirely.
|
|
49
|
+
storyPath = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return { storyLineIndices, reqLineIndices, reqIds, storyPath };
|
|
54
|
+
}
|
|
55
|
+
function applyImplementsReplacement(context, comment, details) {
|
|
56
|
+
const { storyIdx, allIndicesToRemove, storyPath, reqIds } = details;
|
|
57
|
+
const rawValue = comment.value || "";
|
|
58
|
+
const rawLines = rawValue.split(/\r?\n/);
|
|
59
|
+
const implAnnotation = `@implements ${storyPath} ${reqIds.join(" ")}`;
|
|
60
|
+
// Determine the leading prefix (indentation and `*`) from the original @story line
|
|
61
|
+
const storyRawLine = rawLines[storyIdx];
|
|
62
|
+
const prefixMatch = storyRawLine.match(/^(\s*\*?\s*)/);
|
|
63
|
+
const linePrefix = prefixMatch ? prefixMatch[1] : "";
|
|
64
|
+
const implementsLine = `${linePrefix}${implAnnotation}`;
|
|
65
|
+
const fixedLines = [];
|
|
66
|
+
rawLines.forEach((line, index) => {
|
|
67
|
+
if (index === storyIdx) {
|
|
68
|
+
fixedLines.push(implementsLine);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (allIndicesToRemove.has(index)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
fixedLines.push(line);
|
|
75
|
+
});
|
|
76
|
+
const fixedValue = fixedLines.join("\n");
|
|
77
|
+
const sourceCode = context.getSourceCode();
|
|
78
|
+
return (fixer) => fixer.replaceTextRange([comment.range[0], comment.range[1]], sourceCode.text.slice(comment.range[0], comment.range[0] + COMMENT_PREFIX_LENGTH) +
|
|
79
|
+
fixedValue +
|
|
80
|
+
"*/");
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build an ESLint auto-fix for simple single-story `@story` + `@req` JSDoc
|
|
84
|
+
* blocks, converting them to a single `@implements` annotation while
|
|
85
|
+
* preserving the original comment formatting.
|
|
86
|
+
*
|
|
87
|
+
* The fixer is intentionally conservative and only activates when:
|
|
88
|
+
* - There is exactly one distinct `@story` path.
|
|
89
|
+
* - Exactly one `@story` line is present.
|
|
90
|
+
* - At least one `@req` line is present.
|
|
91
|
+
* - Each `@req` line has the simple form `@req <REQ-ID>` (no extra tokens).
|
|
92
|
+
*
|
|
93
|
+
* When applicable, the fix:
|
|
94
|
+
* - Removes the original `@story` and `@req` lines.
|
|
95
|
+
* - Inserts a single `@implements` line in their place, preserving the
|
|
96
|
+
* original leading comment prefix (indentation and `*` markers).
|
|
97
|
+
*
|
|
98
|
+
* More complex patterns remain diagnostics-only with no fix to avoid
|
|
99
|
+
* producing invalid or ambiguous output.
|
|
100
|
+
*
|
|
101
|
+
* @implements docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
102
|
+
* @req REQ-AUTO-FIX - Provide safe, opt-in auto-fix for simple legacy patterns
|
|
103
|
+
* @req REQ-SINGLE-STORY-FIX - Restrict auto-fix to single-story, single-path cases
|
|
104
|
+
* @req REQ-PRESERVE-FORMAT - Preserve original JSDoc indentation and prefix formatting
|
|
105
|
+
* @req REQ-VALID-OUTPUT - Avoid emitting auto-fixes for complex or ambiguous patterns
|
|
106
|
+
*/
|
|
107
|
+
function buildImplementsAutoFix(context, comment, storyPaths) {
|
|
108
|
+
if (storyPaths.size !== 1)
|
|
109
|
+
return null;
|
|
110
|
+
const { storyLineIndices, reqLineIndices, reqIds, storyPath } = collectStoryAndReqMetadata(comment);
|
|
111
|
+
if (storyPaths.size !== 1 ||
|
|
112
|
+
storyLineIndices.length !== 1 ||
|
|
113
|
+
reqLineIndices.length < 1 ||
|
|
114
|
+
storyPath === null) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const storyIdx = storyLineIndices[0];
|
|
118
|
+
const allIndicesToRemove = new Set([
|
|
119
|
+
...storyLineIndices,
|
|
120
|
+
...reqLineIndices,
|
|
121
|
+
]);
|
|
122
|
+
return applyImplementsReplacement(context, comment, {
|
|
123
|
+
storyIdx,
|
|
124
|
+
allIndicesToRemove,
|
|
125
|
+
storyPath,
|
|
126
|
+
reqIds,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function analyzeComment(comment) {
|
|
130
|
+
const rawLines = (comment.value || "").split(/\r?\n/);
|
|
131
|
+
let hasStory = false;
|
|
132
|
+
let hasReq = false;
|
|
133
|
+
let hasImplements = false;
|
|
134
|
+
const storyPaths = new Set();
|
|
135
|
+
rawLines.forEach((rawLine) => {
|
|
136
|
+
const normalized = (0, valid_annotation_format_internal_1.normalizeCommentLine)(rawLine);
|
|
137
|
+
if (!normalized)
|
|
138
|
+
return;
|
|
139
|
+
if (/^@implements\b/.test(normalized)) {
|
|
140
|
+
hasImplements = true;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (/^@story\b/.test(normalized)) {
|
|
144
|
+
hasStory = true;
|
|
145
|
+
const parts = normalized.split(/\s+/);
|
|
146
|
+
if (parts.length >= MIN_STORY_TOKENS) {
|
|
147
|
+
storyPaths.add(parts[1]);
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (/^@req\b/.test(normalized)) {
|
|
152
|
+
hasReq = true;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return { hasStory, hasReq, hasImplements, storyPaths };
|
|
156
|
+
}
|
|
157
|
+
function hasMultipleStories(storyPaths) {
|
|
158
|
+
// @req REQ-MULTI-STORY-DETECT - Use named threshold constant instead of a magic number
|
|
159
|
+
return storyPaths.size > MULTI_STORY_THRESHOLD;
|
|
160
|
+
}
|
|
161
|
+
function processComment(comment, context) {
|
|
162
|
+
const { hasStory, hasReq, hasImplements, storyPaths } = analyzeComment(comment);
|
|
163
|
+
if (!hasStory || !hasReq) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (hasImplements) {
|
|
167
|
+
context.report({
|
|
168
|
+
node: comment,
|
|
169
|
+
messageId: "cannotAutoFix",
|
|
170
|
+
data: {
|
|
171
|
+
reason: "comment mixes @story/@req with existing @implements annotations",
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (hasMultipleStories(storyPaths)) {
|
|
177
|
+
context.report({
|
|
178
|
+
node: comment,
|
|
179
|
+
messageId: "multiStoryDetected",
|
|
180
|
+
});
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const fix = buildImplementsAutoFix(context, comment, storyPaths);
|
|
184
|
+
context.report({
|
|
185
|
+
node: comment,
|
|
186
|
+
messageId: "preferImplements",
|
|
187
|
+
fix: fix ?? undefined,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* ESLint rule: prefer-implements-annotation
|
|
192
|
+
*
|
|
193
|
+
* Recommend migrating from legacy `@story` + `@req` annotations to the
|
|
194
|
+
* newer `@implements` format. This rule is **disabled by default** and
|
|
195
|
+
* is intended as an optional, opt-in migration aid.
|
|
196
|
+
*
|
|
197
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
198
|
+
* @req REQ-OPTIONAL-WARNING - Emit configurable recommendation diagnostics for legacy @story/@req usage
|
|
199
|
+
* @req REQ-MULTI-STORY-DETECT - Detect multi-story patterns that cannot be auto-fixed
|
|
200
|
+
* @req REQ-BACKWARD-COMP-VALIDATION - Keep legacy @story/@req annotations valid when the rule is disabled
|
|
201
|
+
*/
|
|
202
|
+
const preferImplementsAnnotationRule = {
|
|
203
|
+
meta: {
|
|
204
|
+
type: "suggestion",
|
|
205
|
+
docs: {
|
|
206
|
+
description: "Recommend using @implements instead of legacy @story + @req annotations (optional migration rule)",
|
|
207
|
+
recommended: false,
|
|
208
|
+
},
|
|
209
|
+
// Auto-fix support will be wired in a later iteration; the rule starts as
|
|
210
|
+
// a recommendation-only warning with no code modifications.
|
|
211
|
+
fixable: "code",
|
|
212
|
+
messages: {
|
|
213
|
+
/**
|
|
214
|
+
* Recommend migrating simple, single-story @story + @req blocks to a
|
|
215
|
+
* single @implements line. Auto-fix is provided where safe in a
|
|
216
|
+
* follow-up iteration.
|
|
217
|
+
*
|
|
218
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
219
|
+
* @req REQ-OPTIONAL-WARNING
|
|
220
|
+
*/
|
|
221
|
+
preferImplements: "Consider using @implements instead of @story + @req for clearer traceability. Run ESLint with --fix to auto-convert.",
|
|
222
|
+
/**
|
|
223
|
+
* Report situations where the rule detects a legacy annotation pattern
|
|
224
|
+
* but cannot safely provide an automatic fix. The `reason` field gives
|
|
225
|
+
* a short, human-readable explanation to guide manual migration.
|
|
226
|
+
*
|
|
227
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
228
|
+
* @req REQ-MULTI-STORY-DETECT
|
|
229
|
+
*/
|
|
230
|
+
cannotAutoFix: "Cannot auto-fix: {{reason}}. Manual migration to @implements required.",
|
|
231
|
+
/**
|
|
232
|
+
* Specialized message for the most common non-fixable case where more
|
|
233
|
+
* than one @story annotation appears in the same block, indicating a
|
|
234
|
+
* likely multi-story integration that must be converted manually.
|
|
235
|
+
*
|
|
236
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
237
|
+
* @req REQ-MULTI-STORY-DETECT
|
|
238
|
+
*/
|
|
239
|
+
multiStoryDetected: "Multiple @story annotations detected in the same comment block. Manually convert to separate @implements lines.",
|
|
240
|
+
},
|
|
241
|
+
schema: [],
|
|
242
|
+
},
|
|
243
|
+
/**
|
|
244
|
+
* Rule entrypoint.
|
|
245
|
+
*
|
|
246
|
+
* This initial implementation focuses on **detection and messaging only**:
|
|
247
|
+
* it surfaces recommendations when legacy `@story` + `@req` combinations are
|
|
248
|
+
* present but does not yet perform automatic code modifications.
|
|
249
|
+
*
|
|
250
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
251
|
+
* @req REQ-OPTIONAL-WARNING
|
|
252
|
+
* @req REQ-MULTI-STORY-DETECT
|
|
253
|
+
*/
|
|
254
|
+
create(context) {
|
|
255
|
+
const sourceCode = context.getSourceCode();
|
|
256
|
+
return {
|
|
257
|
+
/**
|
|
258
|
+
* Program-level visitor that scans all comments for legacy
|
|
259
|
+
* `@story` + `@req` usage and emits recommendation diagnostics.
|
|
260
|
+
*
|
|
261
|
+
* @story docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md
|
|
262
|
+
* @req REQ-OPTIONAL-WARNING - Emit recommendations when legacy annotations are detected
|
|
263
|
+
* @req REQ-MULTI-STORY-DETECT - Detect multi-story and mixed annotation patterns
|
|
264
|
+
*/
|
|
265
|
+
Program() {
|
|
266
|
+
const comments = sourceCode.getAllComments() || [];
|
|
267
|
+
comments
|
|
268
|
+
.filter((comment) => comment.type === "Block")
|
|
269
|
+
.forEach((comment) => {
|
|
270
|
+
processComment(comment, context);
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
exports.default = preferImplementsAnnotationRule;
|
|
@@ -2,34 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const valid_annotation_options_1 = require("./helpers/valid-annotation-options");
|
|
4
4
|
const valid_annotation_utils_1 = require("./helpers/valid-annotation-utils");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* This function trims whitespace, keeps any annotation tags that appear
|
|
9
|
-
* later in the line, and supports common JSDoc styles such as leading "*".
|
|
10
|
-
*
|
|
11
|
-
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
12
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
13
|
-
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
14
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
15
|
-
*/
|
|
16
|
-
function normalizeCommentLine(rawLine) {
|
|
17
|
-
const trimmed = rawLine.trim();
|
|
18
|
-
if (!trimmed) {
|
|
19
|
-
return "";
|
|
20
|
-
}
|
|
21
|
-
const annotationMatch = trimmed.match(/@story\b|@req\b/);
|
|
22
|
-
if (!annotationMatch || annotationMatch.index === undefined) {
|
|
23
|
-
const withoutLeadingStar = trimmed.replace(/^\*\s?/, "");
|
|
24
|
-
return withoutLeadingStar;
|
|
25
|
-
}
|
|
26
|
-
return trimmed.slice(annotationMatch.index);
|
|
27
|
-
}
|
|
5
|
+
const valid_implements_utils_1 = require("./helpers/valid-implements-utils");
|
|
6
|
+
const valid_annotation_format_internal_1 = require("./helpers/valid-annotation-format-internal");
|
|
28
7
|
/**
|
|
29
8
|
* Report an invalid @story annotation without applying a fix.
|
|
30
9
|
*
|
|
31
10
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
32
11
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
12
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
33
13
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
34
14
|
*/
|
|
35
15
|
function reportInvalidStoryFormat(context, comment, collapsed, options) {
|
|
@@ -91,6 +71,7 @@ function createStoryFix(context, comment, fixed) {
|
|
|
91
71
|
*
|
|
92
72
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
93
73
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
74
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
94
75
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
95
76
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
96
77
|
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and avoid changing semantics
|
|
@@ -117,11 +98,13 @@ function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
|
117
98
|
*
|
|
118
99
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
119
100
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
101
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
120
102
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
121
103
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
122
104
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
123
105
|
* @req REQ-REGEX-VALIDATION - Validate configurable story regex patterns and fall back safely
|
|
124
106
|
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
107
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
125
108
|
*/
|
|
126
109
|
function validateStoryAnnotation(context, comment, rawValue, options) {
|
|
127
110
|
const trimmed = rawValue.trim();
|
|
@@ -154,10 +137,12 @@ function validateStoryAnnotation(context, comment, rawValue, options) {
|
|
|
154
137
|
*
|
|
155
138
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
156
139
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
140
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
157
141
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
158
142
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
159
143
|
* @req REQ-REGEX-VALIDATION - Validate configurable requirement regex patterns and fall back safely
|
|
160
144
|
* @req REQ-BACKWARD-COMP - Preserve behavior when invalid regex config is supplied
|
|
145
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
161
146
|
*/
|
|
162
147
|
function validateReqAnnotation(context, comment, rawValue, options) {
|
|
163
148
|
const trimmed = rawValue.trim();
|
|
@@ -179,13 +164,47 @@ function validateReqAnnotation(context, comment, rawValue, options) {
|
|
|
179
164
|
});
|
|
180
165
|
}
|
|
181
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Validate an @implements annotation value and report detailed errors when needed.
|
|
169
|
+
*
|
|
170
|
+
* Expected format:
|
|
171
|
+
* @implements <storyPath> <REQ-ID> [<REQ-ID> ...]
|
|
172
|
+
*
|
|
173
|
+
* Validation rules:
|
|
174
|
+
* - Value must include at least a story path and one requirement ID.
|
|
175
|
+
* - Story path must match the same storyPattern used for @story (no auto-fix).
|
|
176
|
+
* - Each subsequent token must match reqPattern and is validated individually.
|
|
177
|
+
*
|
|
178
|
+
* Story path issues are reported with "invalidImplementsFormat" and
|
|
179
|
+
* requirement ID issues reuse the existing "invalidReqFormat" message.
|
|
180
|
+
*
|
|
181
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
182
|
+
* @req REQ-IMPLEMENTS-PARSE - Parse @implements annotations without affecting @story/@req
|
|
183
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
184
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
185
|
+
*/
|
|
186
|
+
function validateImplementsAnnotation(context, comment, rawValue, options) {
|
|
187
|
+
const deps = {
|
|
188
|
+
MIN_IMPLEMENTS_TOKENS: valid_implements_utils_1.MIN_IMPLEMENTS_TOKENS,
|
|
189
|
+
reportMissingImplementsReqIds: valid_implements_utils_1.reportMissingImplementsReqIds,
|
|
190
|
+
reportMissingImplementsValue: valid_implements_utils_1.reportMissingImplementsValue,
|
|
191
|
+
reportInvalidImplementsReqId: valid_implements_utils_1.reportInvalidImplementsReqId,
|
|
192
|
+
reportInvalidImplementsStoryPath: valid_implements_utils_1.reportInvalidImplementsStoryPath,
|
|
193
|
+
};
|
|
194
|
+
(0, valid_implements_utils_1.validateImplementsAnnotationHelper)(deps, context, comment, {
|
|
195
|
+
rawValue,
|
|
196
|
+
options,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
182
199
|
/**
|
|
183
200
|
* Finalize and validate the currently pending annotation, if any.
|
|
184
201
|
*
|
|
185
202
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
186
203
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
204
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
187
205
|
* @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
|
|
188
206
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
207
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
189
208
|
*/
|
|
190
209
|
function finalizePendingAnnotation(context, comment, options, pending) {
|
|
191
210
|
if (!pending) {
|
|
@@ -193,8 +212,10 @@ function finalizePendingAnnotation(context, comment, options, pending) {
|
|
|
193
212
|
}
|
|
194
213
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
195
214
|
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
215
|
+
// @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
196
216
|
// @req REQ-SYNTAX-VALIDATION - Dispatch validation based on annotation type
|
|
197
217
|
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
218
|
+
// @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
198
219
|
if (pending.type === "story") {
|
|
199
220
|
validateStoryAnnotation(context, comment, pending.value, options);
|
|
200
221
|
}
|
|
@@ -208,9 +229,13 @@ function finalizePendingAnnotation(context, comment, options, pending) {
|
|
|
208
229
|
*
|
|
209
230
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
210
231
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
232
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
211
233
|
* @req REQ-SYNTAX-VALIDATION - Start new pending annotation when a tag is found
|
|
212
234
|
* @req REQ-MULTILINE-SUPPORT - Treat subsequent lines as continuation for pending annotation
|
|
213
235
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
236
|
+
* @req REQ-IMPLEMENTS-PARSE - Parse @implements annotations without affecting @story/@req
|
|
237
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
238
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
214
239
|
*/
|
|
215
240
|
function processCommentLine({ normalized, pending, context, comment, options, }) {
|
|
216
241
|
if (!normalized) {
|
|
@@ -218,10 +243,19 @@ function processCommentLine({ normalized, pending, context, comment, options, })
|
|
|
218
243
|
}
|
|
219
244
|
const isStory = /@story\b/.test(normalized);
|
|
220
245
|
const isReq = /@req\b/.test(normalized);
|
|
246
|
+
const isImplements = /@implements\b/.test(normalized);
|
|
247
|
+
// Handle @implements as an immediate, single-line annotation
|
|
248
|
+
if (isImplements) {
|
|
249
|
+
const implementsValue = normalized.replace(/^@implements\b/, "").trim();
|
|
250
|
+
validateImplementsAnnotation(context, comment, implementsValue, options);
|
|
251
|
+
return pending;
|
|
252
|
+
}
|
|
221
253
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
222
254
|
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
255
|
+
// @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
223
256
|
// @req REQ-SYNTAX-VALIDATION - Start new pending annotation when a tag is found
|
|
224
257
|
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
258
|
+
// @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
225
259
|
if (isStory || isReq) {
|
|
226
260
|
finalizePendingAnnotation(context, comment, options, pending);
|
|
227
261
|
const value = normalized.replace(/^@story\b|^@req\b/, "").trim();
|
|
@@ -233,8 +267,10 @@ function processCommentLine({ normalized, pending, context, comment, options, })
|
|
|
233
267
|
}
|
|
234
268
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
235
269
|
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
270
|
+
// @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
236
271
|
// @req REQ-MULTILINE-SUPPORT - Treat subsequent lines as continuation for pending annotation
|
|
237
272
|
// @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
273
|
+
// @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
238
274
|
if (pending) {
|
|
239
275
|
const continuation = normalized.trim();
|
|
240
276
|
if (!continuation) {
|
|
@@ -252,23 +288,30 @@ function processCommentLine({ normalized, pending, context, comment, options, })
|
|
|
252
288
|
return pending;
|
|
253
289
|
}
|
|
254
290
|
/**
|
|
255
|
-
* Process a single comment node and validate any @story/@req annotations it contains.
|
|
291
|
+
* Process a single comment node and validate any @story/@req/@implements annotations it contains.
|
|
256
292
|
*
|
|
257
|
-
* Supports annotations whose values span multiple lines within the same
|
|
293
|
+
* Supports @story and @req annotations whose values span multiple lines within the same
|
|
258
294
|
* comment block, collapsing whitespace so that the logical value can be
|
|
259
295
|
* validated against the configured patterns.
|
|
260
296
|
*
|
|
297
|
+
* @implements annotations are validated immediately per-line and are not
|
|
298
|
+
* accumulated into pending multi-line state.
|
|
299
|
+
*
|
|
261
300
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
262
301
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
302
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
263
303
|
* @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
|
|
264
304
|
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
265
305
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
306
|
+
* @req REQ-IMPLEMENTS-PARSE - Parse @implements annotations without affecting @story/@req
|
|
307
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
308
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
266
309
|
*/
|
|
267
310
|
function processComment(context, comment, options) {
|
|
268
311
|
const rawLines = (comment.value || "").split(/\r?\n/);
|
|
269
312
|
let pending = null;
|
|
270
313
|
rawLines.forEach((rawLine) => {
|
|
271
|
-
const normalized = normalizeCommentLine(rawLine);
|
|
314
|
+
const normalized = (0, valid_annotation_format_internal_1.normalizeCommentLine)(rawLine);
|
|
272
315
|
pending = processCommentLine({
|
|
273
316
|
normalized,
|
|
274
317
|
pending,
|
|
@@ -283,7 +326,7 @@ exports.default = {
|
|
|
283
326
|
meta: {
|
|
284
327
|
type: "problem",
|
|
285
328
|
docs: {
|
|
286
|
-
description: "Validate format and syntax of @story and @
|
|
329
|
+
description: "Validate format and syntax of @story, @req, and @implements annotations",
|
|
287
330
|
recommended: "error",
|
|
288
331
|
},
|
|
289
332
|
messages: {
|
|
@@ -301,6 +344,14 @@ exports.default = {
|
|
|
301
344
|
* @req REQ-ERROR-CONSISTENCY - Use shared "Invalid annotation format: {{details}}." message pattern across rules
|
|
302
345
|
*/
|
|
303
346
|
invalidReqFormat: "Invalid annotation format: {{details}}.",
|
|
347
|
+
/**
|
|
348
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
349
|
+
* @req REQ-ERROR-SPECIFIC - Provide specific details about invalid @implements annotation format
|
|
350
|
+
* @req REQ-ERROR-CONTEXT - Include human-readable details about the expected @implements annotation format
|
|
351
|
+
* @req REQ-ERROR-CONSISTENCY - Use shared "Invalid annotation format: {{details}}." message pattern across rules
|
|
352
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
353
|
+
*/
|
|
354
|
+
invalidImplementsFormat: "Invalid annotation format: {{details}}.",
|
|
304
355
|
/**
|
|
305
356
|
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
306
357
|
* @req REQ-REGEX-VALIDATION - Surface configuration errors for invalid regex patterns
|
|
@@ -326,11 +377,15 @@ exports.default = {
|
|
|
326
377
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
327
378
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
328
379
|
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
380
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
329
381
|
* @req REQ-SYNTAX-VALIDATION - Ensure rule create function validates annotations syntax
|
|
330
382
|
* @req REQ-FORMAT-SPECIFICATION - Implement formatting checks per specification
|
|
331
383
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
332
384
|
* @req REQ-REGEX-VALIDATION - Derive validation regexes from shared options helper
|
|
333
385
|
* @req REQ-BACKWARD-COMP - Fall back to default patterns and continue validation on config errors
|
|
386
|
+
* @req REQ-IMPLEMENTS-PARSE - Parse @implements annotations without affecting @story/@req
|
|
387
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
388
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
334
389
|
*/
|
|
335
390
|
create(context) {
|
|
336
391
|
const sourceCode = context.getSourceCode();
|
|
@@ -338,16 +393,20 @@ exports.default = {
|
|
|
338
393
|
const optionErrors = (0, valid_annotation_options_1.getOptionErrors)();
|
|
339
394
|
return {
|
|
340
395
|
/**
|
|
341
|
-
* Program-level handler that inspects all comments for @story and @
|
|
396
|
+
* Program-level handler that inspects all comments for @story, @req, and @implements tags
|
|
342
397
|
*
|
|
343
398
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
344
399
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
345
400
|
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
401
|
+
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
346
402
|
* @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
|
|
347
403
|
* @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
|
|
348
404
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
349
405
|
* @req REQ-REGEX-VALIDATION - Surface regex configuration errors without blocking validation
|
|
350
406
|
* @req REQ-BACKWARD-COMP - Continue validating comments using default patterns on error
|
|
407
|
+
* @req REQ-IMPLEMENTS-PARSE - Parse @implements annotations without affecting @story/@req
|
|
408
|
+
* @req REQ-FORMAT-VALIDATION - Validate @implements story path and requirement IDs
|
|
409
|
+
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
351
410
|
*/
|
|
352
411
|
Program(node) {
|
|
353
412
|
if (optionErrors && optionErrors.length > 0) {
|