eslint-plugin-traceability 1.11.1 → 1.11.2
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 +2 -2
- package/README.md +1 -1
- package/lib/src/index.d.ts +12 -1
- package/lib/src/index.js +43 -6
- package/lib/src/maintenance/commands.js +2 -3
- package/lib/src/maintenance/update.js +1 -14
- package/lib/src/rules/helpers/require-story-core.d.ts +12 -4
- package/lib/src/rules/helpers/require-story-core.js +59 -30
- package/lib/src/rules/helpers/require-story-helpers.d.ts +7 -41
- package/lib/src/rules/helpers/require-story-helpers.js +13 -70
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +12 -13
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +21 -16
- package/lib/src/rules/helpers/valid-annotation-format-validators.d.ts +29 -3
- package/lib/src/rules/helpers/valid-annotation-format-validators.js +29 -3
- package/lib/src/rules/helpers/valid-annotation-utils.d.ts +3 -3
- package/lib/src/rules/helpers/valid-annotation-utils.js +10 -10
- package/lib/src/rules/helpers/valid-req-reference-helpers.d.ts +11 -0
- package/lib/src/rules/helpers/valid-req-reference-helpers.js +362 -0
- package/lib/src/rules/prefer-implements-annotation.js +7 -7
- package/lib/src/rules/require-story-annotation.d.ts +2 -0
- package/lib/src/rules/require-story-annotation.js +1 -1
- package/lib/src/rules/valid-req-reference.d.ts +4 -0
- package/lib/src/rules/valid-req-reference.js +5 -349
- package/lib/src/rules/valid-story-reference.d.ts +1 -1
- package/lib/src/rules/valid-story-reference.js +17 -10
- package/lib/src/utils/branch-annotation-helpers.d.ts +2 -2
- package/lib/src/utils/branch-annotation-helpers.js +4 -4
- package/lib/tests/cli-error-handling.test.js +1 -1
- package/lib/tests/config/eslint-config-validation.test.js +73 -0
- package/lib/tests/fixtures/stale/example.js +1 -1
- package/lib/tests/fixtures/update/example.js +1 -1
- package/lib/tests/integration/dogfooding-validation.test.d.ts +1 -0
- package/lib/tests/integration/dogfooding-validation.test.js +94 -0
- package/lib/tests/maintenance/cli.test.js +37 -0
- package/lib/tests/maintenance/detect-isolated.test.js +5 -5
- package/lib/tests/perf/maintenance-cli-large-workspace.test.js +18 -0
- package/lib/tests/perf/require-branch-annotation-large-file.test.d.ts +1 -0
- package/lib/tests/perf/require-branch-annotation-large-file.test.js +67 -0
- package/lib/tests/plugin-setup.test.js +12 -1
- package/lib/tests/rules/require-branch-annotation.test.js +33 -1
- package/lib/tests/rules/valid-annotation-format-internal.test.d.ts +8 -0
- package/lib/tests/rules/valid-annotation-format-internal.test.js +47 -0
- package/package.json +2 -2
- package/user-docs/api-reference.md +5 -5
- package/user-docs/examples.md +2 -1
- package/user-docs/migration-guide.md +2 -2
|
@@ -23,38 +23,34 @@ const require_story_core_1 = require("./require-story-core");
|
|
|
23
23
|
Object.defineProperty(exports, "DEFAULT_SCOPE", { enumerable: true, get: function () { return require_story_core_1.DEFAULT_SCOPE; } });
|
|
24
24
|
Object.defineProperty(exports, "EXPORT_PRIORITY_VALUES", { enumerable: true, get: function () { return require_story_core_1.EXPORT_PRIORITY_VALUES; } });
|
|
25
25
|
Object.defineProperty(exports, "STORY_PATH", { enumerable: true, get: function () { return require_story_core_1.STORY_PATH; } });
|
|
26
|
-
/**
|
|
27
|
-
* Derive the annotation template, optionally using an override.
|
|
28
|
-
* When override is a non-empty string, its trimmed value is used.
|
|
29
|
-
* Otherwise, the default template is returned.
|
|
30
|
-
*/
|
|
31
26
|
function getAnnotationTemplate(override) {
|
|
32
27
|
if (typeof override === "string" && override.trim().length > 0) {
|
|
33
28
|
return override.trim();
|
|
34
29
|
}
|
|
35
30
|
return `/** @story ${require_story_core_1.STORY_PATH} */`;
|
|
36
31
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Determine whether auto-fix should be applied.
|
|
39
|
-
* Explicit false disables auto-fix; all other values enable it.
|
|
40
|
-
*/
|
|
41
32
|
function shouldApplyAutoFix(autoFix) {
|
|
42
33
|
if (autoFix === false) {
|
|
43
34
|
return false;
|
|
44
35
|
}
|
|
45
36
|
return true;
|
|
46
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Build the effective annotation template and autofix toggle
|
|
40
|
+
* from the provided report options.
|
|
41
|
+
*/
|
|
42
|
+
function buildTemplateConfig(options) {
|
|
43
|
+
const effectiveTemplate = getAnnotationTemplate(options?.annotationTemplateOverride);
|
|
44
|
+
const allowFix = shouldApplyAutoFix(options?.autoFixToggle);
|
|
45
|
+
return { effectiveTemplate, allowFix };
|
|
46
|
+
}
|
|
47
47
|
/**
|
|
48
48
|
* Determine if a node is in an export declaration
|
|
49
49
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
50
50
|
* @req REQ-ANNOTATION-REQUIRED - Check node ancestry to find export declarations
|
|
51
|
-
* @param {any} node - AST node to check for export ancestry
|
|
52
|
-
* @returns {boolean} true if node is within an export declaration
|
|
53
51
|
*/
|
|
54
52
|
function isExportedNode(node) {
|
|
55
53
|
let p = node.parent;
|
|
56
|
-
// @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
57
|
-
// @req REQ-ANNOTATION-REQUIRED - Walk parent chain to find Export declarations
|
|
58
54
|
while (p) {
|
|
59
55
|
if (p.type === "ExportNamedDeclaration" ||
|
|
60
56
|
p.type === "ExportDefaultDeclaration") {
|
|
@@ -68,9 +64,6 @@ function isExportedNode(node) {
|
|
|
68
64
|
* Check whether the JSDoc associated with node contains @story
|
|
69
65
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
70
66
|
* @req REQ-ANNOTATION-REQUIRED - Extract JSDoc based detection into helper
|
|
71
|
-
* @param {any} sourceCode - ESLint sourceCode object
|
|
72
|
-
* @param {any} node - AST node to inspect
|
|
73
|
-
* @returns {boolean} true if JSDoc contains @story
|
|
74
67
|
*/
|
|
75
68
|
function jsdocHasStory(sourceCode, node) {
|
|
76
69
|
if (typeof sourceCode?.getJSDocComment !== "function") {
|
|
@@ -85,9 +78,6 @@ function jsdocHasStory(sourceCode, node) {
|
|
|
85
78
|
* Check whether comments returned by sourceCode.getCommentsBefore contain @story
|
|
86
79
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
87
80
|
* @req REQ-ANNOTATION-REQUIRED - Extract comment-before detection into helper
|
|
88
|
-
* @param {any} sourceCode - ESLint sourceCode object
|
|
89
|
-
* @param {any} node - AST node to inspect
|
|
90
|
-
* @returns {boolean} true if any preceding comment contains @story
|
|
91
81
|
*/
|
|
92
82
|
function commentsBeforeHasStory(sourceCode, node) {
|
|
93
83
|
if (typeof sourceCode?.getCommentsBefore !== "function") {
|
|
@@ -101,8 +91,6 @@ function commentsBeforeHasStory(sourceCode, node) {
|
|
|
101
91
|
* Check whether leadingComments attached to the node contain @story
|
|
102
92
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
103
93
|
* @req REQ-ANNOTATION-REQUIRED - Extract leadingComments detection into helper
|
|
104
|
-
* @param {any} node - AST node to inspect
|
|
105
|
-
* @returns {boolean} true if any leading comment contains @story
|
|
106
94
|
*/
|
|
107
95
|
function leadingCommentsHasStory(node) {
|
|
108
96
|
const leadingComments = (node && node.leadingComments) || [];
|
|
@@ -114,9 +102,6 @@ function leadingCommentsHasStory(node) {
|
|
|
114
102
|
* Consolidates a variety of heuristics through smaller helpers.
|
|
115
103
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
116
104
|
* @req REQ-ANNOTATION-REQUIRED - Detect existing story annotations in JSDoc or comments
|
|
117
|
-
* @param {any} sourceCode - ESLint sourceCode object
|
|
118
|
-
* @param {any} node - AST node to inspect for existing annotations
|
|
119
|
-
* @returns {boolean} true if @story annotation already present
|
|
120
105
|
*/
|
|
121
106
|
function hasStoryAnnotation(sourceCode, node) {
|
|
122
107
|
try {
|
|
@@ -139,8 +124,10 @@ function hasStoryAnnotation(sourceCode, node) {
|
|
|
139
124
|
return true;
|
|
140
125
|
}
|
|
141
126
|
}
|
|
142
|
-
catch {
|
|
143
|
-
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (process.env.TRACEABILITY_DEBUG === "1") {
|
|
129
|
+
console.error("[traceability] hasStoryAnnotation failed for node", error?.message ?? error);
|
|
130
|
+
}
|
|
144
131
|
}
|
|
145
132
|
return false;
|
|
146
133
|
}
|
|
@@ -148,9 +135,6 @@ function hasStoryAnnotation(sourceCode, node) {
|
|
|
148
135
|
* Determine AST node where annotation should be inserted
|
|
149
136
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
150
137
|
* @req REQ-ANNOTATION-REQUIRED - Determine correct insertion target for annotation
|
|
151
|
-
* @param {any} sourceCode - ESLint sourceCode object (unused but kept for parity)
|
|
152
|
-
* @param {any} node - function-like AST node to resolve target for
|
|
153
|
-
* @returns {any} AST node that should receive the annotation
|
|
154
138
|
*/
|
|
155
139
|
function resolveTargetNode(sourceCode, node) {
|
|
156
140
|
if (node.type === "TSMethodSignature") {
|
|
@@ -178,11 +162,8 @@ function resolveTargetNode(sourceCode, node) {
|
|
|
178
162
|
}
|
|
179
163
|
/**
|
|
180
164
|
* Extract a direct Identifier name when available on the given node.
|
|
181
|
-
* This focuses only on plain Identifier nodes and ignores container shapes.
|
|
182
165
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
183
166
|
* @req REQ-ANNOTATION-REQUIRED - Extract direct Identifier-based names from nodes
|
|
184
|
-
* @param {any} node - AST node to inspect
|
|
185
|
-
* @returns {string | null} identifier name or null when not applicable
|
|
186
167
|
*/
|
|
187
168
|
function getDirectIdentifierName(node) {
|
|
188
169
|
if (node &&
|
|
@@ -195,11 +176,8 @@ function getDirectIdentifierName(node) {
|
|
|
195
176
|
}
|
|
196
177
|
/**
|
|
197
178
|
* Normalize container nodes that expose names via id/key properties.
|
|
198
|
-
* Supports common function and method containers, including literal keys.
|
|
199
179
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
200
180
|
* @req REQ-ANNOTATION-REQUIRED - Normalize container id/key-based names into a single helper
|
|
201
|
-
* @param {any} node - AST node that may contain id/key name information
|
|
202
|
-
* @returns {string | null} resolved container name or null when unavailable
|
|
203
181
|
*/
|
|
204
182
|
function getContainerKeyOrIdName(node) {
|
|
205
183
|
if (!node) {
|
|
@@ -226,11 +204,8 @@ function getContainerKeyOrIdName(node) {
|
|
|
226
204
|
}
|
|
227
205
|
/**
|
|
228
206
|
* Small utility to walk the node and its parents to extract an Identifier or key name.
|
|
229
|
-
* Walks up the parent chain and inspects common properties (id, key, name, Identifier nodes).
|
|
230
207
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
231
208
|
* @req REQ-ANNOTATION-REQUIRED - Walk node and parents to find Identifier/Key name
|
|
232
|
-
* @param {any} node - AST node to extract a name from
|
|
233
|
-
* @returns {string} extracted name or "(anonymous)" when no name found
|
|
234
209
|
*/
|
|
235
210
|
function extractName(node) {
|
|
236
211
|
let current = node;
|
|
@@ -251,15 +226,6 @@ function extractName(node) {
|
|
|
251
226
|
}
|
|
252
227
|
return "(anonymous)";
|
|
253
228
|
}
|
|
254
|
-
/**
|
|
255
|
-
* Check if this node is within scope and matches exportPriority
|
|
256
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
257
|
-
* @req REQ-ANNOTATION-REQUIRED - Determine whether a node should be processed by rule
|
|
258
|
-
* @param {any} node - AST node to evaluate
|
|
259
|
-
* @param {string[]} scope - allowed node types
|
|
260
|
-
* @param {string} [exportPriority='all'] - 'all' | 'exported' | 'non-exported' (default: 'all')
|
|
261
|
-
* @returns {boolean} whether node should be processed
|
|
262
|
-
*/
|
|
263
229
|
function shouldProcessNode(node, scope, exportPriority = "all") {
|
|
264
230
|
if (!scope.includes(node.type)) {
|
|
265
231
|
return false;
|
|
@@ -275,11 +241,8 @@ function shouldProcessNode(node, scope, exportPriority = "all") {
|
|
|
275
241
|
}
|
|
276
242
|
/**
|
|
277
243
|
* Resolve the effective function name to report for a node.
|
|
278
|
-
* Normalizes id/key handling before delegating to extractName.
|
|
279
244
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
280
245
|
* @req REQ-ANNOTATION-REQUIRED - Centralize reported function name resolution
|
|
281
|
-
* @param {any} node - AST node used to derive the function name
|
|
282
|
-
* @returns {string} resolved function name
|
|
283
246
|
*/
|
|
284
247
|
function getReportedFunctionName(node) {
|
|
285
248
|
const candidate = node && (node.id || node.key) ? node.id || node.key : node;
|
|
@@ -287,11 +250,8 @@ function getReportedFunctionName(node) {
|
|
|
287
250
|
}
|
|
288
251
|
/**
|
|
289
252
|
* Determine the most appropriate AST node to anchor error location for a report.
|
|
290
|
-
* Prefers Identifier nodes from id/key properties when available.
|
|
291
253
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
292
254
|
* @req REQ-ANNOTATION-REQUIRED - Normalize name node selection for error reporting
|
|
293
|
-
* @param {any} node - AST node used for error anchoring
|
|
294
|
-
* @returns {any} node to use as the report location
|
|
295
255
|
*/
|
|
296
256
|
function getNameNodeForReport(node) {
|
|
297
257
|
if (node?.id?.type === "Identifier") {
|
|
@@ -307,27 +267,10 @@ function getNameNodeForReport(node) {
|
|
|
307
267
|
* respecting an explicitly passed target when provided.
|
|
308
268
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
309
269
|
* @req REQ-ANNOTATION-REQUIRED - Centralize annotation target node resolution
|
|
310
|
-
* @param {any} sourceCode - ESLint sourceCode object
|
|
311
|
-
* @param {any} node - original function-like AST node
|
|
312
|
-
* @param {any} passedTarget - optional explicit annotation target
|
|
313
|
-
* @returns {any} node that should receive the annotation
|
|
314
270
|
*/
|
|
315
271
|
function resolveAnnotationTargetNode(sourceCode, node, passedTarget) {
|
|
316
272
|
return passedTarget ?? resolveTargetNode(sourceCode, node);
|
|
317
273
|
}
|
|
318
|
-
/**
|
|
319
|
-
* Build the effective annotation template and autofix toggle
|
|
320
|
-
* from the provided report options.
|
|
321
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
322
|
-
* @req REQ-ANNOTATION-REQUIRED - Normalize template and autofix configuration
|
|
323
|
-
* @param {ReportOptions} [options] - optional report configuration
|
|
324
|
-
* @returns {{ effectiveTemplate: string; allowFix: boolean }} template and autofix flags
|
|
325
|
-
*/
|
|
326
|
-
function buildTemplateConfig(options) {
|
|
327
|
-
const effectiveTemplate = getAnnotationTemplate(options?.annotationTemplateOverride);
|
|
328
|
-
const allowFix = shouldApplyAutoFix(options?.autoFixToggle);
|
|
329
|
-
return { effectiveTemplate, allowFix };
|
|
330
|
-
}
|
|
331
274
|
function reportMissing(context, sourceCode, config) {
|
|
332
275
|
(0, require_story_core_1.coreReportMissing)({
|
|
333
276
|
hasStoryAnnotation,
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Internal helpers and types for the valid-annotation-format rule.
|
|
3
3
|
*
|
|
4
|
-
* @
|
|
5
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
6
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
7
|
-
* @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
|
|
8
|
-
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
9
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
10
|
-
* @req REQ-SUPPORTS-PARSE - Parse @supports annotations without affecting @story/@req
|
|
11
|
-
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
4
|
+
* @supports docs/stories/024.0-DEV-IGNORE-INLINE-CODE-REFS.story.md REQ-IGNORE-INLINE-CODE REQ-PRESERVE-BOUNDARIES REQ-CENTRALIZED-FILTER
|
|
12
5
|
*/
|
|
13
6
|
/**
|
|
14
7
|
* Pending annotation state tracked while iterating through comment lines.
|
|
@@ -21,8 +14,10 @@ export interface PendingAnnotation {
|
|
|
21
14
|
/**
|
|
22
15
|
* Normalize a raw comment line to make annotation parsing more robust.
|
|
23
16
|
*
|
|
24
|
-
* This function trims whitespace,
|
|
25
|
-
*
|
|
17
|
+
* This function trims whitespace, strips any inline code spans wrapped in
|
|
18
|
+
* backticks (replacing them with spaces of equal length to preserve character
|
|
19
|
+
* boundaries), keeps any annotation tags that appear later in the line, and
|
|
20
|
+
* supports common JSDoc styles such as leading "*".
|
|
26
21
|
*
|
|
27
22
|
* It detects @story, @req, and @supports tags while preserving the rest
|
|
28
23
|
* of the line for downstream logic.
|
|
@@ -34,8 +29,12 @@ export declare function normalizeCommentLine(rawLine: string): string;
|
|
|
34
29
|
* This is used to distinguish regular JSDoc tags (e.g. @param, @returns) from
|
|
35
30
|
* traceability-related annotations such as @story, @req, and @supports.
|
|
36
31
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
32
|
+
* Supports coexistence with JSDoc by:
|
|
33
|
+
* - Detecting boundaries between traceability tags and other tags
|
|
34
|
+
* - Allowing regular JSDoc tags to live alongside traceability annotations
|
|
35
|
+
*
|
|
36
|
+
* Related requirements:
|
|
37
|
+
* - REQ-JSDOC-BOUNDARY-DETECTION
|
|
38
|
+
* - REQ-JSDOC-TAG-COEXISTENCE
|
|
40
39
|
*/
|
|
41
40
|
export declare function isNonTraceabilityJSDocTagLine(normalized: string): boolean;
|
|
@@ -2,14 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Internal helpers and types for the valid-annotation-format rule.
|
|
4
4
|
*
|
|
5
|
-
* @
|
|
6
|
-
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
7
|
-
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
8
|
-
* @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
|
|
9
|
-
* @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
|
|
10
|
-
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
11
|
-
* @req REQ-SUPPORTS-PARSE - Parse @supports annotations without affecting @story/@req
|
|
12
|
-
* @req REQ-MIXED-SUPPORT - Support mixed @story/@req/@implements usage in comments
|
|
5
|
+
* @supports docs/stories/024.0-DEV-IGNORE-INLINE-CODE-REFS.story.md REQ-IGNORE-INLINE-CODE REQ-PRESERVE-BOUNDARIES REQ-CENTRALIZED-FILTER
|
|
13
6
|
*/
|
|
14
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
8
|
exports.normalizeCommentLine = normalizeCommentLine;
|
|
@@ -17,8 +10,10 @@ exports.isNonTraceabilityJSDocTagLine = isNonTraceabilityJSDocTagLine;
|
|
|
17
10
|
/**
|
|
18
11
|
* Normalize a raw comment line to make annotation parsing more robust.
|
|
19
12
|
*
|
|
20
|
-
* This function trims whitespace,
|
|
21
|
-
*
|
|
13
|
+
* This function trims whitespace, strips any inline code spans wrapped in
|
|
14
|
+
* backticks (replacing them with spaces of equal length to preserve character
|
|
15
|
+
* boundaries), keeps any annotation tags that appear later in the line, and
|
|
16
|
+
* supports common JSDoc styles such as leading "*".
|
|
22
17
|
*
|
|
23
18
|
* It detects @story, @req, and @supports tags while preserving the rest
|
|
24
19
|
* of the line for downstream logic.
|
|
@@ -28,12 +23,18 @@ function normalizeCommentLine(rawLine) {
|
|
|
28
23
|
if (!trimmed) {
|
|
29
24
|
return "";
|
|
30
25
|
}
|
|
31
|
-
|
|
26
|
+
// @supports docs/stories/024.0-DEV-IGNORE-INLINE-CODE-REFS.story.md REQ-IGNORE-INLINE-CODE REQ-PRESERVE-BOUNDARIES REQ-CENTRALIZED-FILTER
|
|
27
|
+
// Strip backtick-wrapped content while preserving character positions by
|
|
28
|
+
// replacing each matched segment with spaces of the same length.
|
|
29
|
+
// This ensures annotations that appear outside code spans are still
|
|
30
|
+
// detected at their original indices.
|
|
31
|
+
const filtered = trimmed.replace(/`[^`]*`/g, (match) => " ".repeat(match.length));
|
|
32
|
+
const annotationMatch = filtered.match(/@story\b|@req\b|@supports\b/);
|
|
32
33
|
if (!annotationMatch || annotationMatch.index === undefined) {
|
|
33
|
-
const withoutLeadingStar =
|
|
34
|
+
const withoutLeadingStar = filtered.replace(/^\*\s?/, "");
|
|
34
35
|
return withoutLeadingStar;
|
|
35
36
|
}
|
|
36
|
-
return
|
|
37
|
+
return filtered.slice(annotationMatch.index);
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
40
|
* Detect whether a normalized comment line starts with a non-traceability JSDoc tag.
|
|
@@ -41,9 +42,13 @@ function normalizeCommentLine(rawLine) {
|
|
|
41
42
|
* This is used to distinguish regular JSDoc tags (e.g. @param, @returns) from
|
|
42
43
|
* traceability-related annotations such as @story, @req, and @supports.
|
|
43
44
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* Supports coexistence with JSDoc by:
|
|
46
|
+
* - Detecting boundaries between traceability tags and other tags
|
|
47
|
+
* - Allowing regular JSDoc tags to live alongside traceability annotations
|
|
48
|
+
*
|
|
49
|
+
* Related requirements:
|
|
50
|
+
* - REQ-JSDOC-BOUNDARY-DETECTION
|
|
51
|
+
* - REQ-JSDOC-TAG-COEXISTENCE
|
|
47
52
|
*/
|
|
48
53
|
function isNonTraceabilityJSDocTagLine(normalized) {
|
|
49
54
|
const trimmed = normalized.trimStart();
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* Validators and helper functions for the valid-annotation-format rule.
|
|
3
3
|
*
|
|
4
4
|
* This module contains the core validation logic that was originally
|
|
5
|
-
* embedded in src/rules/valid-annotation-format.ts.
|
|
6
|
-
*
|
|
7
|
-
* preserving existing behavior.
|
|
5
|
+
* embedded in src/rules/valid-annotation-format.ts. The logic is extracted
|
|
6
|
+
* into this helper to keep the main rule implementation smaller and easier
|
|
7
|
+
* to read while still preserving all existing behavior.
|
|
8
|
+
*
|
|
9
|
+
* The implementation in this module supports:
|
|
10
|
+
* - validation of @story annotations
|
|
11
|
+
* - validation of @req annotations
|
|
12
|
+
* - validation of @implements/@supports-style annotations
|
|
13
|
+
* - safe, minimal auto-fixes for certain invalid formats
|
|
8
14
|
*
|
|
9
15
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
10
16
|
* @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
|
|
@@ -29,6 +35,8 @@ import type { PendingAnnotation } from "./valid-annotation-format-internal";
|
|
|
29
35
|
/**
|
|
30
36
|
* Report an invalid @story annotation without applying a fix.
|
|
31
37
|
*
|
|
38
|
+
* The invalid @story annotation is detected and reported but left unchanged.
|
|
39
|
+
*
|
|
32
40
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
33
41
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
34
42
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -55,6 +63,9 @@ export declare function createStoryFix(context: any, comment: any, fixed: string
|
|
|
55
63
|
* for common path suffix issues by locating and replacing the path text
|
|
56
64
|
* within the original comment.
|
|
57
65
|
*
|
|
66
|
+
* Reporting includes both the original invalid value and, where applicable,
|
|
67
|
+
* a suggested corrected story path that only adjusts the suffix.
|
|
68
|
+
*
|
|
58
69
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
59
70
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
60
71
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -68,6 +79,12 @@ export declare function reportInvalidStoryFormatWithFix(context: any, comment: a
|
|
|
68
79
|
* Validate a @story annotation value and report detailed errors when needed.
|
|
69
80
|
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
70
81
|
*
|
|
82
|
+
* Processing of @story values includes:
|
|
83
|
+
* - trimming whitespace,
|
|
84
|
+
* - collapsing multi-line text,
|
|
85
|
+
* - matching against the configured story regex,
|
|
86
|
+
* - and attempting a conservative suffix-only correction when possible.
|
|
87
|
+
*
|
|
71
88
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
72
89
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
73
90
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -82,6 +99,11 @@ export declare function validateStoryAnnotation(context: any, comment: any, rawV
|
|
|
82
99
|
/**
|
|
83
100
|
* Validate a @req annotation value and report detailed errors when needed.
|
|
84
101
|
*
|
|
102
|
+
* This behavior covers:
|
|
103
|
+
* - detecting missing identifiers,
|
|
104
|
+
* - collapsing multi-line requirement identifiers,
|
|
105
|
+
* - and validating the final identifier against the configured regex.
|
|
106
|
+
*
|
|
85
107
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
86
108
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
87
109
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -115,6 +137,10 @@ export declare function validateImplementsAnnotation(context: any, comment: any,
|
|
|
115
137
|
/**
|
|
116
138
|
* Finalize and validate the currently pending annotation, if any.
|
|
117
139
|
*
|
|
140
|
+
* Pending annotation state is produced by earlier parsing of multi-line
|
|
141
|
+
* comments. This function dispatches that accumulated value to the
|
|
142
|
+
* appropriate validator and then clears the pending state.
|
|
143
|
+
*
|
|
118
144
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
119
145
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
120
146
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -3,9 +3,15 @@
|
|
|
3
3
|
* Validators and helper functions for the valid-annotation-format rule.
|
|
4
4
|
*
|
|
5
5
|
* This module contains the core validation logic that was originally
|
|
6
|
-
* embedded in src/rules/valid-annotation-format.ts.
|
|
7
|
-
*
|
|
8
|
-
* preserving existing behavior.
|
|
6
|
+
* embedded in src/rules/valid-annotation-format.ts. The logic is extracted
|
|
7
|
+
* into this helper to keep the main rule implementation smaller and easier
|
|
8
|
+
* to read while still preserving all existing behavior.
|
|
9
|
+
*
|
|
10
|
+
* The implementation in this module supports:
|
|
11
|
+
* - validation of @story annotations
|
|
12
|
+
* - validation of @req annotations
|
|
13
|
+
* - validation of @implements/@supports-style annotations
|
|
14
|
+
* - safe, minimal auto-fixes for certain invalid formats
|
|
9
15
|
*
|
|
10
16
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
11
17
|
* @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
|
|
@@ -39,6 +45,8 @@ const valid_annotation_options_1 = require("./valid-annotation-options");
|
|
|
39
45
|
/**
|
|
40
46
|
* Report an invalid @story annotation without applying a fix.
|
|
41
47
|
*
|
|
48
|
+
* The invalid @story annotation is detected and reported but left unchanged.
|
|
49
|
+
*
|
|
42
50
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
43
51
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
44
52
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -99,6 +107,9 @@ function createStoryFix(context, comment, fixed) {
|
|
|
99
107
|
* for common path suffix issues by locating and replacing the path text
|
|
100
108
|
* within the original comment.
|
|
101
109
|
*
|
|
110
|
+
* Reporting includes both the original invalid value and, where applicable,
|
|
111
|
+
* a suggested corrected story path that only adjusts the suffix.
|
|
112
|
+
*
|
|
102
113
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
103
114
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
104
115
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -128,6 +139,12 @@ function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
|
128
139
|
* Validate a @story annotation value and report detailed errors when needed.
|
|
129
140
|
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
130
141
|
*
|
|
142
|
+
* Processing of @story values includes:
|
|
143
|
+
* - trimming whitespace,
|
|
144
|
+
* - collapsing multi-line text,
|
|
145
|
+
* - matching against the configured story regex,
|
|
146
|
+
* - and attempting a conservative suffix-only correction when possible.
|
|
147
|
+
*
|
|
131
148
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
132
149
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
133
150
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -179,6 +196,11 @@ function validateStoryAnnotation(context, comment, rawValue, options) {
|
|
|
179
196
|
/**
|
|
180
197
|
* Validate a @req annotation value and report detailed errors when needed.
|
|
181
198
|
*
|
|
199
|
+
* This behavior covers:
|
|
200
|
+
* - detecting missing identifiers,
|
|
201
|
+
* - collapsing multi-line requirement identifiers,
|
|
202
|
+
* - and validating the final identifier against the configured regex.
|
|
203
|
+
*
|
|
182
204
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
183
205
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
184
206
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -247,6 +269,10 @@ function validateImplementsAnnotation(context, comment, rawValue, options) {
|
|
|
247
269
|
/**
|
|
248
270
|
* Finalize and validate the currently pending annotation, if any.
|
|
249
271
|
*
|
|
272
|
+
* Pending annotation state is produced by earlier parsing of multi-line
|
|
273
|
+
* comments. This function dispatches that accumulated value to the
|
|
274
|
+
* appropriate validator and then clears the pending state.
|
|
275
|
+
*
|
|
250
276
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
251
277
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
252
278
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
@@ -44,7 +44,7 @@ export declare function collapseAnnotationValue(value: string): string;
|
|
|
44
44
|
*
|
|
45
45
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
46
46
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
47
|
-
* @story docs/stories/010.1-
|
|
47
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
48
48
|
* @story docs/stories/010.2-REQ-STORY-PATH-AUTOFIX.story.md
|
|
49
49
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
50
50
|
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and never broaden the referenced path
|
|
@@ -56,7 +56,7 @@ export declare function getFixedStoryPath(original: string): string | null;
|
|
|
56
56
|
*
|
|
57
57
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
58
58
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
59
|
-
* @story docs/stories/010.1-
|
|
59
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
60
60
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
61
61
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
62
62
|
*/
|
|
@@ -66,7 +66,7 @@ export declare function buildStoryErrorMessage(kind: "missing" | "invalid", valu
|
|
|
66
66
|
*
|
|
67
67
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
68
68
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
69
|
-
* @story docs/stories/010.1-
|
|
69
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
70
70
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
71
71
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
72
72
|
*/
|
|
@@ -54,19 +54,19 @@ function collapseAnnotationValue(value) {
|
|
|
54
54
|
*
|
|
55
55
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
56
56
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
57
|
-
* @story docs/stories/010.1-
|
|
57
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
58
58
|
* @story docs/stories/010.2-REQ-STORY-PATH-AUTOFIX.story.md
|
|
59
59
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
60
60
|
* @req REQ-AUTOFIX-SAFE - Auto-fix must be conservative and never broaden the referenced path
|
|
61
61
|
* @req REQ-AUTOFIX-PRESERVE - Preserve surrounding formatting when normalizing story path suffixes
|
|
62
62
|
*/
|
|
63
63
|
function getFixedStoryPath(original) {
|
|
64
|
-
// @story docs/stories/010.1-
|
|
64
|
+
// @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md | REQ-AUTOFIX-SAFE - Reject auto-fix when the path contains ".." traversal segments to avoid broadening the reference.
|
|
65
65
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-REQ-FORMAT REQ-ERROR-SPECIFICITY - Enforces correctness of the story identifier by rejecting paths that use unsafe traversal segments.
|
|
66
66
|
if (original.includes("..")) {
|
|
67
67
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-REQ-FORMAT
|
|
68
68
|
// @supports docs/stories/008.0-DEV-AUTO-FIX.story.md REQ-AUTOFIX-SAFE
|
|
69
|
-
// @supports docs/stories/010.1-
|
|
69
|
+
// @supports docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md REQ-AUTOFIX-SAFE
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
72
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md | REQ-AUTOFIX-FORMAT - Leave correctly formatted ".story.md" paths unchanged so diagnostics are not hidden by redundant fixes.
|
|
@@ -74,7 +74,7 @@ function getFixedStoryPath(original) {
|
|
|
74
74
|
if (/\.story\.md$/.test(original)) {
|
|
75
75
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-REQ-FORMAT
|
|
76
76
|
// @supports docs/stories/008.0-DEV-AUTO-FIX.story.md REQ-AUTOFIX-FORMAT
|
|
77
|
-
// @supports docs/stories/010.1-
|
|
77
|
+
// @supports docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md REQ-AUTOFIX-FORMAT
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
80
80
|
// @story docs/stories/008.0-DEV-AUTO-FIX.story.md | REQ-AUTOFIX-FORMAT REQ-AUTOFIX-PRESERVE - When ".story" is present but ".md" is missing, append only the extension without altering the base path.
|
|
@@ -105,7 +105,7 @@ function getFixedStoryPath(original) {
|
|
|
105
105
|
*
|
|
106
106
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
107
107
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
108
|
-
* @story docs/stories/010.1-
|
|
108
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
109
109
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
110
110
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
111
111
|
*/
|
|
@@ -115,11 +115,11 @@ function buildStoryErrorMessage(kind, value, options) {
|
|
|
115
115
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-REQ-FORMAT REQ-ERROR-SPECIFICITY - Enforces presence of the story identifier by emitting a targeted message when the @story value is absent.
|
|
116
116
|
if (kind === "missing") {
|
|
117
117
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-ERROR-SPECIFICITY
|
|
118
|
-
// @supports docs/stories/010.1-
|
|
118
|
+
// @supports docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md REQ-ERROR-SPECIFICITY
|
|
119
119
|
return `Missing story path for @story annotation. Expected a path like "${example}".`;
|
|
120
120
|
}
|
|
121
121
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-ERROR-SPECIFICITY
|
|
122
|
-
// @supports docs/stories/010.1-
|
|
122
|
+
// @supports docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md REQ-ERROR-SPECIFICITY
|
|
123
123
|
return `Invalid story path "${value ?? ""}" for @story annotation. Expected a path like "${example}".`;
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
@@ -127,7 +127,7 @@ function buildStoryErrorMessage(kind, value, options) {
|
|
|
127
127
|
*
|
|
128
128
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
129
129
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
130
|
-
* @story docs/stories/010.1-
|
|
130
|
+
* @story docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md
|
|
131
131
|
* @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
|
|
132
132
|
* @req REQ-AUTOFIX-FORMAT - Provide safe, minimal automatic fixes for common format issues
|
|
133
133
|
*/
|
|
@@ -137,10 +137,10 @@ function buildReqErrorMessage(kind, value, options) {
|
|
|
137
137
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-REQ-FORMAT REQ-ERROR-SPECIFICITY - Enforces presence of the requirement identifier by emitting a specific message when the @req value is missing.
|
|
138
138
|
if (kind === "missing") {
|
|
139
139
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-ERROR-SPECIFICITY
|
|
140
|
-
// @supports docs/stories/010.1-
|
|
140
|
+
// @supports docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md REQ-ERROR-SPECIFICITY
|
|
141
141
|
return `Missing requirement ID for @req annotation. Expected an identifier like "${example}".`;
|
|
142
142
|
}
|
|
143
143
|
// @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-ERROR-SPECIFICITY
|
|
144
|
-
// @supports docs/stories/010.1-
|
|
144
|
+
// @supports docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md REQ-ERROR-SPECIFICITY
|
|
145
145
|
return `Invalid requirement ID "${value ?? ""}" for @req annotation. Expected an identifier like "${example}" (uppercase letters, numbers, and dashes only).`;
|
|
146
146
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
/**
|
|
3
|
+
* Factory used by the valid-req-reference rule to construct its Program
|
|
4
|
+
* visitor. Keeping this in a helper module allows the rule entrypoint
|
|
5
|
+
* itself to remain small and focused on meta configuration while the
|
|
6
|
+
* heavier deep-validation logic is encapsulated here.
|
|
7
|
+
*
|
|
8
|
+
* @supports docs/stories/010.0-DEV-DEEP-VALIDATION.story.md REQ-DEEP-PARSE REQ-DEEP-MATCH REQ-DEEP-CACHE
|
|
9
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-SUPPORTS-VALIDATE REQ-MIXED-SUPPORT REQ-SCOPED-IDS
|
|
10
|
+
*/
|
|
11
|
+
export declare function createValidReqReferenceProgramVisitor(context: Rule.RuleContext): () => void;
|