eslint-plugin-traceability 1.20.0 → 1.21.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/README.md +8 -7
- package/lib/src/maintenance/batch.js +1 -0
- package/lib/src/maintenance/cli.js +1 -0
- package/lib/src/maintenance/commands.js +1 -0
- package/lib/src/maintenance/detect.js +1 -0
- package/lib/src/maintenance/report.js +1 -0
- package/lib/src/maintenance/update.js +1 -0
- package/lib/src/rules/helpers/require-story-core.d.ts +2 -0
- package/lib/src/rules/helpers/require-story-core.js +7 -4
- package/lib/src/rules/helpers/require-story-helpers.d.ts +19 -1
- package/lib/src/rules/helpers/require-story-helpers.js +48 -4
- package/lib/src/rules/helpers/require-story-io.js +1 -0
- package/lib/src/rules/helpers/require-story-visitors.js +6 -0
- package/lib/src/rules/helpers/require-test-traceability-helpers.js +1 -0
- package/lib/src/rules/helpers/test-callback-exclusion.d.ts +1 -0
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +2 -2
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +2 -2
- package/lib/src/rules/helpers/valid-annotation-format-validators.d.ts +14 -14
- package/lib/src/rules/helpers/valid-annotation-format-validators.js +31 -22
- package/lib/src/rules/helpers/valid-annotation-utils.js +1 -0
- package/lib/src/rules/helpers/valid-req-reference-helpers.js +1 -0
- package/lib/src/rules/require-req-annotation.d.ts +2 -3
- package/lib/src/rules/require-req-annotation.js +11 -2
- package/lib/src/rules/require-story-annotation.js +46 -20
- package/lib/src/rules/valid-annotation-format.js +14 -10
- package/lib/src/utils/annotation-checker.d.ts +1 -0
- package/lib/src/utils/annotation-checker.js +14 -0
- package/lib/src/utils/reqAnnotationDetection.js +1 -0
- package/lib/tests/config/eslint-config-validation.test.js +1 -0
- package/lib/tests/config/flat-config-presets-integration.test.js +1 -0
- package/lib/tests/config/require-story-annotation-config.test.js +2 -0
- package/lib/tests/fixtures/stale/example.js +1 -0
- package/lib/tests/fixtures/update/example.js +1 -0
- package/lib/tests/integration/annotation-placement-inside-prettier.integration.test.js +1 -0
- package/lib/tests/integration/catch-annotation-prettier.integration.test.js +1 -0
- package/lib/tests/integration/else-if-annotation-prettier.integration.test.js +1 -0
- package/lib/tests/integration/prettier-test-helpers.js +1 -0
- package/lib/tests/integration/require-traceability-aliases.integration.test.js +26 -0
- package/lib/tests/integration/require-traceability-test-callbacks.integration.test.js +1 -0
- package/lib/tests/maintenance/detect-isolated.test.js +1 -0
- package/lib/tests/perf/maintenance-large-workspace.test.js +1 -0
- package/lib/tests/perf/valid-annotation-format-large-file.test.js +1 -0
- package/lib/tests/plugin-setup.test.js +1 -0
- package/lib/tests/rules/error-reporting.test.js +1 -0
- package/lib/tests/rules/require-req-annotation.test.js +20 -0
- package/lib/tests/rules/require-story-annotation.test.js +26 -0
- package/lib/tests/rules/require-test-traceability.test.js +1 -0
- package/lib/tests/utils/branch-annotation-catch-insert-position.test.js +1 -0
- package/lib/tests/utils/branch-annotation-else-if-insert-position.test.js +1 -0
- package/lib/tests/utils/branch-annotation-helpers.test.js +1 -0
- package/package.json +1 -1
- package/user-docs/api-reference.md +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
## [1.21.1](https://github.com/voder-ai/eslint-plugin-traceability/compare/v1.21.0...v1.21.1) (2025-12-21)
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
###
|
|
4
|
+
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* **rules:** harden valid-annotation-format parsing ([7c914f1](https://github.com/voder-ai/eslint-plugin-traceability/commit/7c914f100b93923bec63f97dfa122e1c4686ecff))
|
|
7
7
|
|
|
8
8
|
# Changelog
|
|
9
9
|
|
package/README.md
CHANGED
|
@@ -117,15 +117,16 @@ Traceability annotations are typically placed immediately adjacent to the code t
|
|
|
117
117
|
}
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
+
The `annotationPlacement` option is also supported by the function-level rules (`traceability/require-story-annotation` and `traceability/require-req-annotation`) when you configure them directly. In `"inside"` mode, these rules treat only the first comment-only lines inside function and method bodies as satisfying the annotation requirement; JSDoc and before-function comments are ignored for block-bodied functions and methods, while TypeScript declarations and signature-only nodes continue to use before-node annotations.
|
|
121
|
+
|
|
120
122
|
- **Function-level (`traceability/require-story-annotation`, `traceability/require-req-annotation`)**
|
|
121
123
|
|
|
122
|
-
Function-level rules
|
|
123
|
-
|
|
124
|
-
-
|
|
124
|
+
Function-level rules support both before-function and inside-body placement, controlled by the same `annotationPlacement` option described above:
|
|
125
|
+
|
|
126
|
+
- `"before"` – Annotations are written as JSDoc blocks immediately preceding the function, or as line comments placed directly before the function declaration or expression.
|
|
127
|
+
- `"inside"` – Annotations are expected to appear on the first comment-only lines inside function and method bodies; comments before the function are ignored for block-bodied functions in this mode, while TypeScript declarations and signature-only nodes still rely on before-node annotations.
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
- By default, annotations are still placed immediately before the function (JSDoc or line comments).
|
|
128
|
-
- When you configure `annotationPlacement: "inside"` on `traceability/require-story-annotation`, the rule prefers annotations as the first comment-only lines inside the function or method body, mirroring the branch-level inside-brace standard from Story 028.0. Declaration-only shapes such as `TSDeclareFunction` and `TSMethodSignature` remain before-function only, since they have no executable body.
|
|
129
|
+
For full details and migration guidance between placement styles, see the [API Reference](user-docs/api-reference.md) and the migration guide ([user-docs/migration-guide.md](user-docs/migration-guide.md)).
|
|
129
130
|
|
|
130
131
|
For full configuration details and migration guidance between placement styles, see:
|
|
131
132
|
|
|
@@ -429,4 +430,4 @@ For the canonical, user-facing security policy (including how to report vulnerab
|
|
|
429
430
|
- Contribution guide: <https://github.com/voder-ai/eslint-plugin-traceability/blob/main/CONTRIBUTING.md>
|
|
430
431
|
- Issue tracker: <https://github.com/voder-ai/eslint-plugin-traceability/issues>
|
|
431
432
|
- Changelog: [CHANGELOG.md](CHANGELOG.md)
|
|
432
|
-
- Versioning and Releases: This project uses semantic-release for automated versioning. The authoritative list of published versions and release notes is on GitHub Releases: <https://github.com/voder-ai/eslint-plugin-traceability/releases>
|
|
433
|
+
- Versioning and Releases: This project uses semantic-release for automated versioning. The authoritative list of published versions and release notes is on GitHub Releases: <https://github.com/voder-ai/eslint-plugin-traceability/releases>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.batchUpdateAnnotations = batchUpdateAnnotations;
|
|
4
4
|
exports.verifyAnnotations = verifyAnnotations;
|
|
5
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
5
6
|
const update_1 = require("./update");
|
|
6
7
|
const detect_1 = require("./detect");
|
|
7
8
|
/**
|
|
@@ -5,6 +5,7 @@ exports.handleDetect = handleDetect;
|
|
|
5
5
|
exports.handleVerify = handleVerify;
|
|
6
6
|
exports.handleReport = handleReport;
|
|
7
7
|
exports.handleUpdate = handleUpdate;
|
|
8
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
8
9
|
/**
|
|
9
10
|
* Subcommand handlers for the traceability-maint CLI.
|
|
10
11
|
*
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.detectStaleAnnotations = detectStaleAnnotations;
|
|
37
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const path = __importStar(require("path"));
|
|
39
40
|
const utils_1 = require("./utils");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateMaintenanceReport = generateMaintenanceReport;
|
|
4
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
4
5
|
const detect_1 = require("./detect");
|
|
5
6
|
/**
|
|
6
7
|
* Generate a report of maintenance operations performed
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.updateAnnotationReferences = updateAnnotationReferences;
|
|
37
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const utils_1 = require("./utils");
|
|
39
40
|
/**
|
|
@@ -38,6 +38,7 @@ import type { Rule } from "eslint";
|
|
|
38
38
|
type CoreReportOptions = {
|
|
39
39
|
annotationTemplateOverride?: string;
|
|
40
40
|
autoFixToggle?: boolean;
|
|
41
|
+
annotationPlacement?: "before" | "inside";
|
|
41
42
|
};
|
|
42
43
|
type ReportDeps = {
|
|
43
44
|
hasStoryAnnotation: (_sourceCode: any, _node: any) => boolean;
|
|
@@ -53,6 +54,7 @@ type ReportDeps = {
|
|
|
53
54
|
shouldApplyAutoFix: (_autoFix: boolean | undefined) => boolean;
|
|
54
55
|
createAddStoryFix: (_target: any, _annotationTemplate: string) => any;
|
|
55
56
|
createMethodFix: (_node: any, _annotationTemplate: string) => any;
|
|
57
|
+
hasStoryAnnotationWithPlacement?: (_sourceCode: any, _node: any, _placement: "before" | "inside") => boolean;
|
|
56
58
|
};
|
|
57
59
|
/**
|
|
58
60
|
* Core helper to report a missing @story annotation for a function-like node.
|
|
@@ -5,6 +5,7 @@ exports.createAddStoryFix = createAddStoryFix;
|
|
|
5
5
|
exports.createMethodFix = createMethodFix;
|
|
6
6
|
exports.coreReportMissing = coreReportMissing;
|
|
7
7
|
exports.coreReportMethod = coreReportMethod;
|
|
8
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
8
9
|
/**
|
|
9
10
|
* Compute the insertion start offset for inserting annotations before a node.
|
|
10
11
|
* This helper ensures we insert before any export wrapper when present, while
|
|
@@ -158,11 +159,13 @@ function coreReportMissing(deps, context, sourceCode, config) {
|
|
|
158
159
|
const { node, target: passedTarget, options = {} } = config;
|
|
159
160
|
withSafeReporting("coreReportMissing", () => {
|
|
160
161
|
const annotationPlacement = resolveAnnotationPlacement(options);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
const hasWithPlacement = deps.hasStoryAnnotationWithPlacement;
|
|
163
|
+
if (typeof hasWithPlacement === "function") {
|
|
164
|
+
if (hasWithPlacement(sourceCode, node, annotationPlacement)) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
164
167
|
}
|
|
165
|
-
if (deps.hasStoryAnnotation(sourceCode, node)) {
|
|
168
|
+
else if (deps.hasStoryAnnotation(sourceCode, node)) {
|
|
166
169
|
return;
|
|
167
170
|
}
|
|
168
171
|
const functionName = deps.getReportedFunctionName(node);
|
|
@@ -18,6 +18,7 @@ import { type CallbackExclusionOptions } from "./test-callback-exclusion";
|
|
|
18
18
|
interface ReportOptions extends CallbackExclusionOptions {
|
|
19
19
|
annotationTemplateOverride?: string;
|
|
20
20
|
autoFixToggle?: boolean;
|
|
21
|
+
annotationPlacement?: "before" | "inside";
|
|
21
22
|
}
|
|
22
23
|
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
23
24
|
declare function getAnnotationTemplate(override?: string, _options?: CallbackExclusionOptions): string;
|
|
@@ -53,7 +54,24 @@ declare function leadingCommentsHasStory(node: any): boolean;
|
|
|
53
54
|
* @req REQ-ANNOTATION-REQUIRED - Detect existing story annotations in JSDoc or comments
|
|
54
55
|
*/
|
|
55
56
|
declare function hasStoryAnnotation(sourceCode: any, node: any): boolean;
|
|
56
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Placement-aware story detection helper used by core reporting.
|
|
59
|
+
*
|
|
60
|
+
* When annotationPlacement is "inside" and the node supports inside-brace
|
|
61
|
+
* semantics, this helper only treats annotations found on the first
|
|
62
|
+
* comment-only lines inside the function or method body as satisfying the
|
|
63
|
+
* requirement. JSDoc and before-function comments are intentionally ignored so
|
|
64
|
+
* that misplaced annotations are reported as violations under the inside
|
|
65
|
+
* standard.
|
|
66
|
+
*
|
|
67
|
+
* For nodes that do not support inside placement (such as TS declarations,
|
|
68
|
+
* signature-only nodes, or functions without block bodies), this helper
|
|
69
|
+
* delegates to the existing hasStoryAnnotation heuristics so that they
|
|
70
|
+
* continue to rely on before-function placement.
|
|
71
|
+
*
|
|
72
|
+
* @supports docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md REQ-ALL-BLOCK-TYPES REQ-INSIDE-BRACE-PLACEMENT REQ-PLACEMENT-CONFIG
|
|
73
|
+
*/
|
|
74
|
+
declare function hasStoryAnnotationWithPlacement(sourceCode: any, node: any, annotationPlacement: "before" | "inside"): boolean;
|
|
57
75
|
/**
|
|
58
76
|
* Determine AST node where annotation should be inserted
|
|
59
77
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fallbackTextBeforeHasStory = exports.parentChainHasStory = exports.linesBeforeHasStory = exports.EXPORT_PRIORITY_VALUES = exports.DEFAULT_SCOPE = exports.getNodeName = exports.
|
|
3
|
+
exports.fallbackTextBeforeHasStory = exports.parentChainHasStory = exports.linesBeforeHasStory = exports.EXPORT_PRIORITY_VALUES = exports.DEFAULT_SCOPE = exports.getNodeName = exports.STORY_PATH = void 0;
|
|
4
4
|
exports.getAnnotationTemplate = getAnnotationTemplate;
|
|
5
5
|
exports.shouldApplyAutoFix = shouldApplyAutoFix;
|
|
6
6
|
exports.isExportedNode = isExportedNode;
|
|
@@ -8,6 +8,7 @@ exports.jsdocHasStory = jsdocHasStory;
|
|
|
8
8
|
exports.commentsBeforeHasStory = commentsBeforeHasStory;
|
|
9
9
|
exports.leadingCommentsHasStory = leadingCommentsHasStory;
|
|
10
10
|
exports.hasStoryAnnotation = hasStoryAnnotation;
|
|
11
|
+
exports.hasStoryAnnotationWithPlacement = hasStoryAnnotationWithPlacement;
|
|
11
12
|
exports.extractName = extractName;
|
|
12
13
|
exports.resolveTargetNode = resolveTargetNode;
|
|
13
14
|
exports.shouldProcessNode = shouldProcessNode;
|
|
@@ -19,6 +20,7 @@ Object.defineProperty(exports, "parentChainHasStory", { enumerable: true, get: f
|
|
|
19
20
|
Object.defineProperty(exports, "fallbackTextBeforeHasStory", { enumerable: true, get: function () { return require_story_io_1.fallbackTextBeforeHasStory; } });
|
|
20
21
|
const require_story_utils_1 = require("./require-story-utils");
|
|
21
22
|
Object.defineProperty(exports, "getNodeName", { enumerable: true, get: function () { return require_story_utils_1.getNodeName; } });
|
|
23
|
+
const function_annotation_helpers_1 = require("../../utils/function-annotation-helpers");
|
|
22
24
|
const require_story_core_1 = require("./require-story-core");
|
|
23
25
|
Object.defineProperty(exports, "DEFAULT_SCOPE", { enumerable: true, get: function () { return require_story_core_1.DEFAULT_SCOPE; } });
|
|
24
26
|
Object.defineProperty(exports, "EXPORT_PRIORITY_VALUES", { enumerable: true, get: function () { return require_story_core_1.EXPORT_PRIORITY_VALUES; } });
|
|
@@ -220,9 +222,49 @@ function hasStoryAnnotation(sourceCode, node) {
|
|
|
220
222
|
}
|
|
221
223
|
return false;
|
|
222
224
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
/**
|
|
226
|
+
* Placement-aware story detection helper used by core reporting.
|
|
227
|
+
*
|
|
228
|
+
* When annotationPlacement is "inside" and the node supports inside-brace
|
|
229
|
+
* semantics, this helper only treats annotations found on the first
|
|
230
|
+
* comment-only lines inside the function or method body as satisfying the
|
|
231
|
+
* requirement. JSDoc and before-function comments are intentionally ignored so
|
|
232
|
+
* that misplaced annotations are reported as violations under the inside
|
|
233
|
+
* standard.
|
|
234
|
+
*
|
|
235
|
+
* For nodes that do not support inside placement (such as TS declarations,
|
|
236
|
+
* signature-only nodes, or functions without block bodies), this helper
|
|
237
|
+
* delegates to the existing hasStoryAnnotation heuristics so that they
|
|
238
|
+
* continue to rely on before-function placement.
|
|
239
|
+
*
|
|
240
|
+
* @supports docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md REQ-ALL-BLOCK-TYPES REQ-INSIDE-BRACE-PLACEMENT REQ-PLACEMENT-CONFIG
|
|
241
|
+
*/
|
|
242
|
+
function hasStoryAnnotationWithPlacement(sourceCode, node, annotationPlacement) {
|
|
243
|
+
// Backward-compatible default: use existing heuristics when placement is
|
|
244
|
+
// "before" or when the function does not support inside-brace semantics.
|
|
245
|
+
if (annotationPlacement !== "inside" ||
|
|
246
|
+
!(0, function_annotation_helpers_1.supportsInsidePlacementForFunction)(node)) {
|
|
247
|
+
return hasStoryAnnotation(sourceCode, node);
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const insideText = (0, function_annotation_helpers_1.getFunctionInsideBodyCommentText)(sourceCode, node);
|
|
251
|
+
if (typeof insideText === "string" &&
|
|
252
|
+
(insideText.includes("@story") || insideText.includes("@supports"))) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
if (process.env.TRACEABILITY_DEBUG === "1") {
|
|
258
|
+
// Debug logging only when explicitly enabled for troubleshooting helper failures.
|
|
259
|
+
console.error("[traceability] hasStoryAnnotationWithPlacement failed for node", error?.message ?? error);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// In inside-placement mode for block-bodied functions and methods we
|
|
263
|
+
// intentionally do not fall back to before-function heuristics; callers
|
|
264
|
+
// should treat this as a missing annotation so that misplaced comments are
|
|
265
|
+
// reported as violations.
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
226
268
|
/**
|
|
227
269
|
* Determine AST node where annotation should be inserted
|
|
228
270
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
@@ -375,6 +417,7 @@ function resolveAnnotationTargetNode(sourceCode, node, passedTarget) {
|
|
|
375
417
|
function reportMissing(context, sourceCode, config) {
|
|
376
418
|
(0, require_story_core_1.coreReportMissing)({
|
|
377
419
|
hasStoryAnnotation,
|
|
420
|
+
hasStoryAnnotationWithPlacement,
|
|
378
421
|
getReportedFunctionName,
|
|
379
422
|
resolveAnnotationTargetNode,
|
|
380
423
|
getNameNodeForReport,
|
|
@@ -390,6 +433,7 @@ function reportMissing(context, sourceCode, config) {
|
|
|
390
433
|
function reportMethod(context, sourceCode, config) {
|
|
391
434
|
(0, require_story_core_1.coreReportMethod)({
|
|
392
435
|
hasStoryAnnotation,
|
|
436
|
+
hasStoryAnnotationWithPlacement,
|
|
393
437
|
getReportedFunctionName,
|
|
394
438
|
resolveAnnotationTargetNode,
|
|
395
439
|
getNameNodeForReport,
|
|
@@ -33,6 +33,7 @@ function buildFunctionDeclarationVisitor(context, sourceCode, options) {
|
|
|
33
33
|
options: {
|
|
34
34
|
annotationTemplateOverride: options.annotationTemplate,
|
|
35
35
|
autoFixToggle: options.autoFix,
|
|
36
|
+
annotationPlacement: options.annotationPlacement,
|
|
36
37
|
},
|
|
37
38
|
});
|
|
38
39
|
}
|
|
@@ -68,6 +69,7 @@ function buildFunctionExpressionVisitor(context, sourceCode, options) {
|
|
|
68
69
|
options: {
|
|
69
70
|
annotationTemplateOverride: options.annotationTemplate,
|
|
70
71
|
autoFixToggle: options.autoFix,
|
|
72
|
+
annotationPlacement: options.annotationPlacement,
|
|
71
73
|
},
|
|
72
74
|
});
|
|
73
75
|
}
|
|
@@ -96,6 +98,7 @@ function buildArrowFunctionVisitor(context, sourceCode, options) {
|
|
|
96
98
|
options: {
|
|
97
99
|
annotationTemplateOverride: options.annotationTemplate,
|
|
98
100
|
autoFixToggle: options.autoFix,
|
|
101
|
+
annotationPlacement: options.annotationPlacement,
|
|
99
102
|
},
|
|
100
103
|
});
|
|
101
104
|
}
|
|
@@ -123,6 +126,7 @@ function buildTSDeclareFunctionVisitor(context, sourceCode, options) {
|
|
|
123
126
|
options: {
|
|
124
127
|
annotationTemplateOverride: options.annotationTemplate,
|
|
125
128
|
autoFixToggle: options.autoFix,
|
|
129
|
+
annotationPlacement: options.annotationPlacement,
|
|
126
130
|
},
|
|
127
131
|
});
|
|
128
132
|
}
|
|
@@ -151,6 +155,7 @@ function buildTSMethodSignatureVisitor(context, sourceCode, options) {
|
|
|
151
155
|
options: {
|
|
152
156
|
annotationTemplateOverride: options.methodAnnotationTemplate ?? options.annotationTemplate,
|
|
153
157
|
autoFixToggle: options.autoFix,
|
|
158
|
+
annotationPlacement: options.annotationPlacement,
|
|
154
159
|
},
|
|
155
160
|
});
|
|
156
161
|
}
|
|
@@ -177,6 +182,7 @@ function buildMethodDefinitionVisitor(context, sourceCode, options) {
|
|
|
177
182
|
options: {
|
|
178
183
|
annotationTemplateOverride: options.methodAnnotationTemplate ?? options.annotationTemplate,
|
|
179
184
|
autoFixToggle: options.autoFix,
|
|
185
|
+
annotationPlacement: options.annotationPlacement,
|
|
180
186
|
},
|
|
181
187
|
});
|
|
182
188
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.determineIsTestFile = determineIsTestFile;
|
|
4
4
|
exports.ensureFileSupportsAnnotation = ensureFileSupportsAnnotation;
|
|
5
5
|
exports.handleCallExpression = handleCallExpression;
|
|
6
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
6
7
|
/**
|
|
7
8
|
* Helper utilities for the require-test-traceability rule.
|
|
8
9
|
*
|
|
@@ -21,6 +21,7 @@ import type { TSESTree } from "@typescript-eslint/utils";
|
|
|
21
21
|
interface CallbackExclusionOptions {
|
|
22
22
|
excludeTestCallbacks?: boolean;
|
|
23
23
|
additionalTestHelperNames?: string[];
|
|
24
|
+
annotationPlacement?: "before" | "inside";
|
|
24
25
|
}
|
|
25
26
|
type TraceabilityNodeWithParent = TSESTree.Node & {
|
|
26
27
|
parent?: TraceabilityNodeWithParent | null;
|
|
@@ -19,7 +19,7 @@ export interface PendingAnnotation {
|
|
|
19
19
|
* boundaries), keeps any annotation tags that appear later in the line, and
|
|
20
20
|
* supports common JSDoc styles such as leading "*".
|
|
21
21
|
*
|
|
22
|
-
* It detects
|
|
22
|
+
* It detects `@story`, `@req`, and `@supports` tags while preserving the rest
|
|
23
23
|
* of the line for downstream logic.
|
|
24
24
|
*/
|
|
25
25
|
export declare function normalizeCommentLine(rawLine: string): string;
|
|
@@ -27,7 +27,7 @@ export declare function normalizeCommentLine(rawLine: string): string;
|
|
|
27
27
|
* Detect whether a normalized comment line starts with a non-traceability JSDoc tag.
|
|
28
28
|
*
|
|
29
29
|
* This is used to distinguish regular JSDoc tags (e.g. @param, @returns) from
|
|
30
|
-
* traceability-related annotations such as
|
|
30
|
+
* traceability-related annotations such as `@story`, `@req`, and `@supports`.
|
|
31
31
|
*
|
|
32
32
|
* Supports coexistence with JSDoc by:
|
|
33
33
|
* - Detecting boundaries between traceability tags and other tags
|
|
@@ -15,7 +15,7 @@ exports.isNonTraceabilityJSDocTagLine = isNonTraceabilityJSDocTagLine;
|
|
|
15
15
|
* boundaries), keeps any annotation tags that appear later in the line, and
|
|
16
16
|
* supports common JSDoc styles such as leading "*".
|
|
17
17
|
*
|
|
18
|
-
* It detects
|
|
18
|
+
* It detects `@story`, `@req`, and `@supports` tags while preserving the rest
|
|
19
19
|
* of the line for downstream logic.
|
|
20
20
|
*/
|
|
21
21
|
function normalizeCommentLine(rawLine) {
|
|
@@ -40,7 +40,7 @@ function normalizeCommentLine(rawLine) {
|
|
|
40
40
|
* Detect whether a normalized comment line starts with a non-traceability JSDoc tag.
|
|
41
41
|
*
|
|
42
42
|
* This is used to distinguish regular JSDoc tags (e.g. @param, @returns) from
|
|
43
|
-
* traceability-related annotations such as
|
|
43
|
+
* traceability-related annotations such as `@story`, `@req`, and `@supports`.
|
|
44
44
|
*
|
|
45
45
|
* Supports coexistence with JSDoc by:
|
|
46
46
|
* - Detecting boundaries between traceability tags and other tags
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* to read while still preserving all existing behavior.
|
|
8
8
|
*
|
|
9
9
|
* The implementation in this module supports:
|
|
10
|
-
* - validation of
|
|
11
|
-
* - validation of
|
|
12
|
-
* - validation of
|
|
10
|
+
* - validation of `@story` annotations
|
|
11
|
+
* - validation of `@req` annotations
|
|
12
|
+
* - validation of `@implements`/`@supports`-style annotations
|
|
13
13
|
* - safe, minimal auto-fixes for certain invalid formats
|
|
14
14
|
*
|
|
15
15
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
import type { ResolvedAnnotationOptions } from "./valid-annotation-options";
|
|
34
34
|
import type { PendingAnnotation } from "./valid-annotation-format-internal";
|
|
35
35
|
/**
|
|
36
|
-
* Report an invalid
|
|
36
|
+
* Report an invalid `@story` annotation without applying a fix.
|
|
37
37
|
*
|
|
38
|
-
* The invalid
|
|
38
|
+
* The invalid `@story` annotation is detected and reported but left unchanged.
|
|
39
39
|
*
|
|
40
40
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
41
41
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
@@ -44,10 +44,10 @@ import type { PendingAnnotation } from "./valid-annotation-format-internal";
|
|
|
44
44
|
*/
|
|
45
45
|
export declare function reportInvalidStoryFormat(context: any, comment: any, collapsed: string, options: ResolvedAnnotationOptions): void;
|
|
46
46
|
/**
|
|
47
|
-
* Compute the text replacement for an invalid
|
|
47
|
+
* Compute the text replacement for an invalid `@story` annotation within a comment.
|
|
48
48
|
*
|
|
49
49
|
* This helper:
|
|
50
|
-
* - finds the
|
|
50
|
+
* - finds the `@story` tag in the raw comment text,
|
|
51
51
|
* - computes the character range of its value,
|
|
52
52
|
* - and returns an ESLint fix that replaces only that range.
|
|
53
53
|
*
|
|
@@ -59,7 +59,7 @@ export declare function reportInvalidStoryFormat(context: any, comment: any, col
|
|
|
59
59
|
*/
|
|
60
60
|
export declare function createStoryFix(context: any, comment: any, fixed: string): null | (() => any);
|
|
61
61
|
/**
|
|
62
|
-
* Report an invalid
|
|
62
|
+
* Report an invalid `@story` annotation and attempt a minimal, safe auto-fix
|
|
63
63
|
* for common path suffix issues by locating and replacing the path text
|
|
64
64
|
* within the original comment.
|
|
65
65
|
*
|
|
@@ -76,10 +76,10 @@ export declare function createStoryFix(context: any, comment: any, fixed: string
|
|
|
76
76
|
*/
|
|
77
77
|
export declare function reportInvalidStoryFormatWithFix(context: any, comment: any, collapsed: string, fixed: string): void;
|
|
78
78
|
/**
|
|
79
|
-
* Validate a
|
|
79
|
+
* Validate a `@story` annotation value and report detailed errors when needed.
|
|
80
80
|
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
81
81
|
*
|
|
82
|
-
* Processing of
|
|
82
|
+
* Processing of `@story` values includes:
|
|
83
83
|
* - trimming whitespace,
|
|
84
84
|
* - collapsing multi-line text,
|
|
85
85
|
* - matching against the configured story regex,
|
|
@@ -97,7 +97,7 @@ export declare function reportInvalidStoryFormatWithFix(context: any, comment: a
|
|
|
97
97
|
*/
|
|
98
98
|
export declare function validateStoryAnnotation(context: any, comment: any, rawValue: string, options: ResolvedAnnotationOptions): void;
|
|
99
99
|
/**
|
|
100
|
-
* Validate a
|
|
100
|
+
* Validate a `@req` annotation value and report detailed errors when needed.
|
|
101
101
|
*
|
|
102
102
|
* This behavior covers:
|
|
103
103
|
* - detecting missing identifiers,
|
|
@@ -115,14 +115,14 @@ export declare function validateStoryAnnotation(context: any, comment: any, rawV
|
|
|
115
115
|
*/
|
|
116
116
|
export declare function validateReqAnnotation(context: any, comment: any, rawValue: string, options: ResolvedAnnotationOptions): void;
|
|
117
117
|
/**
|
|
118
|
-
* Validate an
|
|
118
|
+
* Validate an `@supports` annotation value and report detailed errors when needed.
|
|
119
119
|
*
|
|
120
120
|
* Expected format:
|
|
121
|
-
*
|
|
121
|
+
* `@supports <storyPath> <REQ-ID> [<REQ-ID> ...]`
|
|
122
122
|
*
|
|
123
123
|
* Validation rules:
|
|
124
124
|
* - Value must include at least a story path and one requirement ID.
|
|
125
|
-
* - Story path must match the same storyPattern used for
|
|
125
|
+
* - Story path must match the same storyPattern used for `@story` (no auto-fix).
|
|
126
126
|
* - Each subsequent token must match reqPattern and is validated individually.
|
|
127
127
|
*
|
|
128
128
|
* Story path issues are reported with "invalidImplementsFormat" and
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* to read while still preserving all existing behavior.
|
|
9
9
|
*
|
|
10
10
|
* The implementation in this module supports:
|
|
11
|
-
* - validation of
|
|
12
|
-
* - validation of
|
|
13
|
-
* - validation of
|
|
11
|
+
* - validation of `@story` annotations
|
|
12
|
+
* - validation of `@req` annotations
|
|
13
|
+
* - validation of `@implements`/`@supports`-style annotations
|
|
14
14
|
* - safe, minimal auto-fixes for certain invalid formats
|
|
15
15
|
*
|
|
16
16
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
@@ -43,9 +43,9 @@ const valid_annotation_utils_1 = require("./valid-annotation-utils");
|
|
|
43
43
|
const valid_implements_utils_1 = require("./valid-implements-utils");
|
|
44
44
|
const valid_annotation_options_1 = require("./valid-annotation-options");
|
|
45
45
|
/**
|
|
46
|
-
* Report an invalid
|
|
46
|
+
* Report an invalid `@story` annotation without applying a fix.
|
|
47
47
|
*
|
|
48
|
-
* The invalid
|
|
48
|
+
* The invalid `@story` annotation is detected and reported but left unchanged.
|
|
49
49
|
*
|
|
50
50
|
* @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
51
51
|
* @story docs/stories/008.0-DEV-AUTO-FIX.story.md
|
|
@@ -60,10 +60,10 @@ function reportInvalidStoryFormat(context, comment, collapsed, options) {
|
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
* Compute the text replacement for an invalid
|
|
63
|
+
* Compute the text replacement for an invalid `@story` annotation within a comment.
|
|
64
64
|
*
|
|
65
65
|
* This helper:
|
|
66
|
-
* - finds the
|
|
66
|
+
* - finds the `@story` tag in the raw comment text,
|
|
67
67
|
* - computes the character range of its value,
|
|
68
68
|
* - and returns an ESLint fix that replaces only that range.
|
|
69
69
|
*
|
|
@@ -103,7 +103,7 @@ function createStoryFix(context, comment, fixed) {
|
|
|
103
103
|
return () => (fixer) => fixer.replaceTextRange(fixRange, fixed);
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
106
|
-
* Report an invalid
|
|
106
|
+
* Report an invalid `@story` annotation and attempt a minimal, safe auto-fix
|
|
107
107
|
* for common path suffix issues by locating and replacing the path text
|
|
108
108
|
* within the original comment.
|
|
109
109
|
*
|
|
@@ -136,10 +136,10 @@ function reportInvalidStoryFormatWithFix(context, comment, collapsed, fixed) {
|
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
138
|
/**
|
|
139
|
-
* Validate a
|
|
139
|
+
* Validate a `@story` annotation value and report detailed errors when needed.
|
|
140
140
|
* Where safe and unambiguous, apply an automatic fix for missing suffixes.
|
|
141
141
|
*
|
|
142
|
-
* Processing of
|
|
142
|
+
* Processing of `@story` values includes:
|
|
143
143
|
* - trimming whitespace,
|
|
144
144
|
* - collapsing multi-line text,
|
|
145
145
|
* - matching against the configured story regex,
|
|
@@ -194,7 +194,7 @@ function validateStoryAnnotation(context, comment, rawValue, options) {
|
|
|
194
194
|
reportInvalidStoryFormat(context, comment, collapsed, options);
|
|
195
195
|
}
|
|
196
196
|
/**
|
|
197
|
-
* Validate a
|
|
197
|
+
* Validate a `@req` annotation value and report detailed errors when needed.
|
|
198
198
|
*
|
|
199
199
|
* This behavior covers:
|
|
200
200
|
* - detecting missing identifiers,
|
|
@@ -222,33 +222,42 @@ function validateReqAnnotation(context, comment, rawValue, options) {
|
|
|
222
222
|
});
|
|
223
223
|
return;
|
|
224
224
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// while still validating simple multi-line @req identifiers that collapse
|
|
228
|
-
// to a single token.
|
|
229
|
-
if (collapsed.includes("@supports")) {
|
|
225
|
+
// Allow mixed `@req`/`@supports` lines to pass without additional `@req` validation.
|
|
226
|
+
if (trimmed.includes("@supports")) {
|
|
230
227
|
return;
|
|
231
228
|
}
|
|
232
|
-
const
|
|
229
|
+
const tokens = trimmed.split(/\s+/).filter(Boolean);
|
|
230
|
+
let reqId = tokens[0] || trimmed;
|
|
231
|
+
for (let index = 1; index < tokens.length; index += 1) {
|
|
232
|
+
const token = tokens[index];
|
|
233
|
+
if (token === "-" || token === "–" || token === "—")
|
|
234
|
+
break;
|
|
235
|
+
const candidate = `${reqId}${token}`;
|
|
236
|
+
if (reqId.endsWith("-") || options.reqPattern.test(candidate)) {
|
|
237
|
+
reqId = candidate;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
233
242
|
// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
|
|
234
243
|
// @req REQ-REQ-FORMAT - Flag @req identifiers that do not match the configured pattern
|
|
235
|
-
if (!reqPattern.test(
|
|
244
|
+
if (!options.reqPattern.test(reqId)) {
|
|
236
245
|
context.report({
|
|
237
246
|
node: comment,
|
|
238
247
|
messageId: "invalidReqFormat",
|
|
239
|
-
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("invalid",
|
|
248
|
+
data: { details: (0, valid_annotation_utils_1.buildReqErrorMessage)("invalid", reqId, options) },
|
|
240
249
|
});
|
|
241
250
|
}
|
|
242
251
|
}
|
|
243
252
|
/**
|
|
244
|
-
* Validate an
|
|
253
|
+
* Validate an `@supports` annotation value and report detailed errors when needed.
|
|
245
254
|
*
|
|
246
255
|
* Expected format:
|
|
247
|
-
*
|
|
256
|
+
* `@supports <storyPath> <REQ-ID> [<REQ-ID> ...]`
|
|
248
257
|
*
|
|
249
258
|
* Validation rules:
|
|
250
259
|
* - Value must include at least a story path and one requirement ID.
|
|
251
|
-
* - Story path must match the same storyPattern used for
|
|
260
|
+
* - Story path must match the same storyPattern used for `@story` (no auto-fix).
|
|
252
261
|
* - Each subsequent token must match reqPattern and is validated individually.
|
|
253
262
|
*
|
|
254
263
|
* Story path issues are reported with "invalidImplementsFormat" and
|
|
@@ -5,6 +5,7 @@ exports.collapseAnnotationValue = collapseAnnotationValue;
|
|
|
5
5
|
exports.getFixedStoryPath = getFixedStoryPath;
|
|
6
6
|
exports.buildStoryErrorMessage = buildStoryErrorMessage;
|
|
7
7
|
exports.buildReqErrorMessage = buildReqErrorMessage;
|
|
8
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
8
9
|
const valid_annotation_options_1 = require("./valid-annotation-options");
|
|
9
10
|
/**
|
|
10
11
|
* Shared constants and helpers for annotation-format validation.
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createValidReqReferenceProgramVisitor = createValidReqReferenceProgramVisitor;
|
|
7
|
+
/* eslint-disable traceability/valid-annotation-format */
|
|
7
8
|
/* eslint-env node */
|
|
8
9
|
/**
|
|
9
10
|
* Helper utilities for the "valid-req-reference" rule.
|
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
* @req REQ-CONFIGURABLE-SCOPE - Allow configuration of which exports are checked
|
|
8
8
|
* @req REQ-EXPORT-PRIORITY - Allow configuration of export priority behavior
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* require-story-annotation
|
|
12
|
-
* the function (no inside-function support yet).
|
|
10
|
+
* This rule honors the same `annotationPlacement` semantics as
|
|
11
|
+
* `require-story-annotation` for block-bodied functions and methods.
|
|
13
12
|
*/
|
|
14
13
|
import type { Rule } from "eslint";
|
|
15
14
|
declare const rule: Rule.RuleModule;
|