eslint-plugin-traceability 1.21.0 → 1.22.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 +7 -2
- package/README.md +6 -6
- package/lib/src/maintenance/batch.js +0 -1
- package/lib/src/maintenance/cli.js +8 -10
- package/lib/src/maintenance/commands.d.ts +2 -2
- package/lib/src/maintenance/commands.js +2 -2
- package/lib/src/maintenance/detect.js +7 -7
- package/lib/src/maintenance/report.js +2 -2
- package/lib/src/maintenance/storyParser.d.ts +16 -0
- package/lib/src/maintenance/storyParser.js +167 -0
- package/lib/src/rules/helpers/pattern-validators.d.ts +42 -0
- package/lib/src/rules/helpers/pattern-validators.js +65 -0
- package/lib/src/rules/helpers/prefer-implements-inline.d.ts +16 -0
- package/lib/src/rules/helpers/prefer-implements-inline.js +146 -0
- package/lib/src/rules/helpers/require-story-comment-detection.d.ts +47 -0
- package/lib/src/rules/helpers/require-story-comment-detection.js +141 -0
- package/lib/src/rules/helpers/require-story-core.d.ts +6 -6
- package/lib/src/rules/helpers/require-story-core.js +10 -10
- package/lib/src/rules/helpers/require-story-helpers.d.ts +5 -63
- package/lib/src/rules/helpers/require-story-helpers.js +29 -337
- package/lib/src/rules/helpers/require-story-io.js +1 -0
- package/lib/src/rules/helpers/require-story-name-extraction.d.ts +35 -0
- package/lib/src/rules/helpers/require-story-name-extraction.js +107 -0
- package/lib/src/rules/helpers/require-story-node-utils.d.ts +43 -0
- package/lib/src/rules/helpers/require-story-node-utils.js +115 -0
- package/lib/src/rules/helpers/require-test-traceability-helpers.js +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 +13 -5
- 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-options.d.ts +0 -10
- package/lib/src/rules/helpers/valid-annotation-options.js +22 -92
- package/lib/src/rules/helpers/valid-annotation-utils.js +1 -0
- package/lib/src/rules/helpers/valid-req-reference-helpers.js +1 -1
- package/lib/src/rules/no-redundant-annotation.js +4 -238
- package/lib/src/rules/prefer-implements-annotation.d.ts +12 -0
- package/lib/src/rules/prefer-implements-annotation.js +9 -164
- package/lib/src/rules/require-traceability.d.ts +8 -0
- package/lib/src/rules/require-traceability.js +8 -0
- package/lib/src/rules/valid-annotation-format.js +14 -10
- package/lib/src/utils/annotation-checker.d.ts +3 -2
- package/lib/src/utils/annotation-checker.js +4 -2
- package/lib/src/utils/branch-annotation-catch-helpers.d.ts +22 -0
- package/lib/src/utils/branch-annotation-catch-helpers.js +70 -0
- package/lib/src/utils/branch-annotation-helpers.js +11 -187
- package/lib/src/utils/branch-annotation-if-helpers.d.ts +1 -0
- package/lib/src/utils/branch-annotation-if-helpers.js +59 -0
- package/lib/src/utils/branch-annotation-indent-helpers.d.ts +1 -1
- package/lib/src/utils/branch-annotation-switch-helpers.d.ts +8 -2
- package/lib/src/utils/branch-annotation-switch-helpers.js +10 -4
- package/lib/src/utils/branch-validation.d.ts +9 -0
- package/lib/src/utils/branch-validation.js +58 -0
- package/lib/src/utils/comment-text-helpers.d.ts +31 -0
- package/lib/src/utils/comment-text-helpers.js +54 -0
- package/lib/src/utils/redundancy-detector.d.ts +85 -0
- package/lib/src/utils/redundancy-detector.js +235 -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 +1 -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-test-callbacks.integration.test.js +1 -0
- package/lib/tests/maintenance/detect-isolated.test.js +1 -0
- package/lib/tests/maintenance/storyParser.test.d.ts +8 -0
- package/lib/tests/maintenance/storyParser.test.js +505 -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/no-redundant-annotation.test.js +1 -0
- package/lib/tests/rules/require-story-helpers.test.js +3 -2
- package/lib/tests/rules/require-test-traceability.test.js +1 -0
- package/lib/tests/rules/valid-req-reference.test.js +2 -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 +18 -10
- package/user-docs/api-reference.md +2 -2
|
@@ -1,16 +1,8 @@
|
|
|
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.
|
|
3
|
+
exports.fallbackTextBeforeHasStory = exports.parentChainHasStory = exports.linesBeforeHasStory = exports.EXPORT_PRIORITY_VALUES = exports.DEFAULT_SCOPE = exports.resolveTargetNode = exports.extractName = exports.hasStoryAnnotationWithPlacement = exports.hasStoryAnnotation = exports.leadingCommentsHasStory = exports.commentsBeforeHasStory = exports.jsdocHasStory = exports.isExportedNode = exports.STORY_PATH = void 0;
|
|
4
4
|
exports.getAnnotationTemplate = getAnnotationTemplate;
|
|
5
5
|
exports.shouldApplyAutoFix = shouldApplyAutoFix;
|
|
6
|
-
exports.isExportedNode = isExportedNode;
|
|
7
|
-
exports.jsdocHasStory = jsdocHasStory;
|
|
8
|
-
exports.commentsBeforeHasStory = commentsBeforeHasStory;
|
|
9
|
-
exports.leadingCommentsHasStory = leadingCommentsHasStory;
|
|
10
|
-
exports.hasStoryAnnotation = hasStoryAnnotation;
|
|
11
|
-
exports.hasStoryAnnotationWithPlacement = hasStoryAnnotationWithPlacement;
|
|
12
|
-
exports.extractName = extractName;
|
|
13
|
-
exports.resolveTargetNode = resolveTargetNode;
|
|
14
6
|
exports.shouldProcessNode = shouldProcessNode;
|
|
15
7
|
exports.reportMissing = reportMissing;
|
|
16
8
|
exports.reportMethod = reportMethod;
|
|
@@ -18,14 +10,22 @@ const require_story_io_1 = require("./require-story-io");
|
|
|
18
10
|
Object.defineProperty(exports, "linesBeforeHasStory", { enumerable: true, get: function () { return require_story_io_1.linesBeforeHasStory; } });
|
|
19
11
|
Object.defineProperty(exports, "parentChainHasStory", { enumerable: true, get: function () { return require_story_io_1.parentChainHasStory; } });
|
|
20
12
|
Object.defineProperty(exports, "fallbackTextBeforeHasStory", { enumerable: true, get: function () { return require_story_io_1.fallbackTextBeforeHasStory; } });
|
|
21
|
-
const require_story_utils_1 = require("./require-story-utils");
|
|
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");
|
|
24
13
|
const require_story_core_1 = require("./require-story-core");
|
|
25
14
|
Object.defineProperty(exports, "DEFAULT_SCOPE", { enumerable: true, get: function () { return require_story_core_1.DEFAULT_SCOPE; } });
|
|
26
15
|
Object.defineProperty(exports, "EXPORT_PRIORITY_VALUES", { enumerable: true, get: function () { return require_story_core_1.EXPORT_PRIORITY_VALUES; } });
|
|
27
16
|
Object.defineProperty(exports, "STORY_PATH", { enumerable: true, get: function () { return require_story_core_1.STORY_PATH; } });
|
|
28
17
|
const test_callback_exclusion_1 = require("./test-callback-exclusion");
|
|
18
|
+
const require_story_name_extraction_1 = require("./require-story-name-extraction");
|
|
19
|
+
Object.defineProperty(exports, "extractName", { enumerable: true, get: function () { return require_story_name_extraction_1.extractName; } });
|
|
20
|
+
const require_story_node_utils_1 = require("./require-story-node-utils");
|
|
21
|
+
Object.defineProperty(exports, "isExportedNode", { enumerable: true, get: function () { return require_story_node_utils_1.isExportedNode; } });
|
|
22
|
+
Object.defineProperty(exports, "resolveTargetNode", { enumerable: true, get: function () { return require_story_node_utils_1.resolveTargetNode; } });
|
|
23
|
+
const require_story_comment_detection_1 = require("./require-story-comment-detection");
|
|
24
|
+
Object.defineProperty(exports, "jsdocHasStory", { enumerable: true, get: function () { return require_story_comment_detection_1.jsdocHasStory; } });
|
|
25
|
+
Object.defineProperty(exports, "commentsBeforeHasStory", { enumerable: true, get: function () { return require_story_comment_detection_1.commentsBeforeHasStory; } });
|
|
26
|
+
Object.defineProperty(exports, "leadingCommentsHasStory", { enumerable: true, get: function () { return require_story_comment_detection_1.leadingCommentsHasStory; } });
|
|
27
|
+
Object.defineProperty(exports, "hasStoryAnnotation", { enumerable: true, get: function () { return require_story_comment_detection_1.hasStoryAnnotation; } });
|
|
28
|
+
Object.defineProperty(exports, "hasStoryAnnotationWithPlacement", { enumerable: true, get: function () { return require_story_comment_detection_1.hasStoryAnnotationWithPlacement; } });
|
|
29
29
|
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
30
30
|
function getAnnotationTemplate(override, _options) {
|
|
31
31
|
if (typeof override === "string" && override.trim().length > 0) {
|
|
@@ -55,49 +55,6 @@ function buildTemplateConfig(options) {
|
|
|
55
55
|
});
|
|
56
56
|
return { effectiveTemplate, allowFix };
|
|
57
57
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Determine whether a node represents an anonymous arrow function expression
|
|
60
|
-
* where the parent variable declarator has no explicit Identifier name.
|
|
61
|
-
*
|
|
62
|
-
* @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-ARROW-FUNCTION-EXCLUDED
|
|
63
|
-
*/
|
|
64
|
-
function isAnonymousArrowFunction(node) {
|
|
65
|
-
return !!node && node.type === "ArrowFunctionExpression";
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Determine whether a function-like node is nested within another function.
|
|
69
|
-
*
|
|
70
|
-
* @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-NESTED-FUNCTION-INHERITANCE
|
|
71
|
-
*/
|
|
72
|
-
function isNestedFunction(node) {
|
|
73
|
-
let current = node?.parent;
|
|
74
|
-
while (current) {
|
|
75
|
-
if (current.type === "FunctionDeclaration" ||
|
|
76
|
-
current.type === "FunctionExpression" ||
|
|
77
|
-
current.type === "ArrowFunctionExpression" ||
|
|
78
|
-
current.type === "MethodDefinition" ||
|
|
79
|
-
current.type === "TSDeclareFunction" ||
|
|
80
|
-
current.type === "TSMethodSignature") {
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
current = current.parent;
|
|
84
|
-
}
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Determine whether a function-like node is effectively anonymous for the
|
|
89
|
-
* purposes of nested-function inheritance. Named functions must always carry
|
|
90
|
-
* their own annotations, while anonymous nested functions may inherit.
|
|
91
|
-
*
|
|
92
|
-
* @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-NESTED-FUNCTION-INHERITANCE
|
|
93
|
-
*/
|
|
94
|
-
function isEffectivelyAnonymousFunction(node) {
|
|
95
|
-
const name = getContainerKeyOrIdName(node) ?? getDirectIdentifierName(node);
|
|
96
|
-
if (typeof name === "string" && name.length > 0 && name !== "(anonymous)") {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
58
|
/**
|
|
102
59
|
* Determine whether a function node is required to carry its own annotation
|
|
103
60
|
* according to Story 004.0-DEV-BRANCH-ANNOTATIONS rules.
|
|
@@ -117,249 +74,16 @@ function requiresOwnFunctionAnnotation(node, options) {
|
|
|
117
74
|
}
|
|
118
75
|
// Anonymous arrow functions used as callbacks are excluded from function-level
|
|
119
76
|
// requirements when they are nested inside another function or method.
|
|
120
|
-
if (isAnonymousArrowFunction(node) &&
|
|
121
|
-
isNestedFunction(node) &&
|
|
122
|
-
isEffectivelyAnonymousFunction(node)) {
|
|
77
|
+
if ((0, require_story_node_utils_1.isAnonymousArrowFunction)(node) &&
|
|
78
|
+
(0, require_story_node_utils_1.isNestedFunction)(node) &&
|
|
79
|
+
(0, require_story_node_utils_1.isEffectivelyAnonymousFunction)(node)) {
|
|
123
80
|
return false;
|
|
124
81
|
}
|
|
125
|
-
if (isNestedFunction(node) && isEffectivelyAnonymousFunction(node)) {
|
|
82
|
+
if ((0, require_story_node_utils_1.isNestedFunction)(node) && (0, require_story_node_utils_1.isEffectivelyAnonymousFunction)(node)) {
|
|
126
83
|
return false;
|
|
127
84
|
}
|
|
128
85
|
return true;
|
|
129
86
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Determine if a node is in an export declaration
|
|
132
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
133
|
-
* @req REQ-ANNOTATION-REQUIRED - Check node ancestry to find export declarations
|
|
134
|
-
*/
|
|
135
|
-
function isExportedNode(node) {
|
|
136
|
-
let p = node.parent;
|
|
137
|
-
while (p) {
|
|
138
|
-
if (p.type === "ExportNamedDeclaration" ||
|
|
139
|
-
p.type === "ExportDefaultDeclaration") {
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
p = p.parent;
|
|
143
|
-
}
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Check whether the JSDoc associated with node contains @story
|
|
148
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
149
|
-
* @req REQ-ANNOTATION-REQUIRED - Extract JSDoc based detection into helper
|
|
150
|
-
*/
|
|
151
|
-
function jsdocHasStory(sourceCode, node) {
|
|
152
|
-
if (typeof sourceCode?.getJSDocComment !== "function") {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
const jsdoc = sourceCode.getJSDocComment(node);
|
|
156
|
-
return !!(jsdoc &&
|
|
157
|
-
typeof jsdoc.value === "string" &&
|
|
158
|
-
jsdoc.value.includes("@story"));
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Check whether comments returned by sourceCode.getCommentsBefore contain @story
|
|
162
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
163
|
-
* @req REQ-ANNOTATION-REQUIRED - Extract comment-before detection into helper
|
|
164
|
-
*/
|
|
165
|
-
function commentsBeforeHasStory(sourceCode, node) {
|
|
166
|
-
if (typeof sourceCode?.getCommentsBefore !== "function") {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
const commentsBefore = sourceCode.getCommentsBefore(node) || [];
|
|
170
|
-
return (Array.isArray(commentsBefore) &&
|
|
171
|
-
commentsBefore.some((c) => typeof c.value === "string" && c.value.includes("@story")));
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Check whether leadingComments attached to the node contain @story
|
|
175
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
176
|
-
* @req REQ-ANNOTATION-REQUIRED - Extract leadingComments detection into helper
|
|
177
|
-
*/
|
|
178
|
-
function leadingCommentsHasStory(node) {
|
|
179
|
-
const leadingComments = (node && node.leadingComments) || [];
|
|
180
|
-
return (Array.isArray(leadingComments) &&
|
|
181
|
-
leadingComments.some((c) => typeof c.value === "string" && c.value.includes("@story")));
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Check if @story annotation already present in JSDoc or preceding comments
|
|
185
|
-
* Consolidates a variety of heuristics through smaller helpers.
|
|
186
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
187
|
-
* @req REQ-ANNOTATION-REQUIRED - Detect existing story annotations in JSDoc or comments
|
|
188
|
-
*/
|
|
189
|
-
function hasStoryAnnotation(sourceCode, node) {
|
|
190
|
-
try {
|
|
191
|
-
// Direct, node-local checks always apply first.
|
|
192
|
-
if (jsdocHasStory(sourceCode, node)) {
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
if (commentsBeforeHasStory(sourceCode, node)) {
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
if (leadingCommentsHasStory(node)) {
|
|
199
|
-
return true;
|
|
200
|
-
}
|
|
201
|
-
if (!isNestedFunction(node) && (0, require_story_io_1.linesBeforeHasStory)(sourceCode, node)) {
|
|
202
|
-
return true;
|
|
203
|
-
}
|
|
204
|
-
const canInherit = isNestedFunction(node) && isEffectivelyAnonymousFunction(node);
|
|
205
|
-
// Only nodes that are allowed to inherit annotations (e.g., nested anonymous
|
|
206
|
-
// callbacks) may treat parent-chain comments or broad fallback text as
|
|
207
|
-
// satisfying the annotation requirement.
|
|
208
|
-
if (canInherit && (0, require_story_io_1.parentChainHasStory)(sourceCode, node)) {
|
|
209
|
-
return true;
|
|
210
|
-
}
|
|
211
|
-
if (canInherit && (0, require_story_io_1.fallbackTextBeforeHasStory)(sourceCode, node)) {
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
if (canInherit) {
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
catch (error) {
|
|
219
|
-
if (process.env.TRACEABILITY_DEBUG === "1") {
|
|
220
|
-
console.error("[traceability] hasStoryAnnotation failed for node", error?.message ?? error);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
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
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Determine AST node where annotation should be inserted
|
|
270
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
271
|
-
* @req REQ-ANNOTATION-REQUIRED - Determine correct insertion target for annotation
|
|
272
|
-
*/
|
|
273
|
-
function resolveTargetNode(sourceCode, node) {
|
|
274
|
-
if (node.type === "TSMethodSignature") {
|
|
275
|
-
// Interface method signature -> insert on interface
|
|
276
|
-
return node.parent.parent;
|
|
277
|
-
}
|
|
278
|
-
if (node.type === "FunctionExpression" ||
|
|
279
|
-
node.type === "ArrowFunctionExpression") {
|
|
280
|
-
const parent = node.parent;
|
|
281
|
-
if (parent.type === "VariableDeclarator") {
|
|
282
|
-
const varDecl = parent.parent;
|
|
283
|
-
if (varDecl.parent && varDecl.parent.type === "ExportNamedDeclaration") {
|
|
284
|
-
return varDecl.parent;
|
|
285
|
-
}
|
|
286
|
-
return varDecl;
|
|
287
|
-
}
|
|
288
|
-
if (parent.type === "ExportNamedDeclaration") {
|
|
289
|
-
return parent;
|
|
290
|
-
}
|
|
291
|
-
if (parent.type === "ExpressionStatement") {
|
|
292
|
-
return parent;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return node;
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Extract a direct Identifier name when available on the given node.
|
|
299
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
300
|
-
* @req REQ-ANNOTATION-REQUIRED - Extract direct Identifier-based names from nodes
|
|
301
|
-
*/
|
|
302
|
-
function getDirectIdentifierName(node) {
|
|
303
|
-
if (node &&
|
|
304
|
-
node.type === "Identifier" &&
|
|
305
|
-
typeof node.name === "string" &&
|
|
306
|
-
node.name.length > 0) {
|
|
307
|
-
return node.name;
|
|
308
|
-
}
|
|
309
|
-
return null;
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Normalize container nodes that expose names via id/key properties.
|
|
313
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
314
|
-
* @req REQ-ANNOTATION-REQUIRED - Normalize container id/key-based names into a single helper
|
|
315
|
-
*/
|
|
316
|
-
function getContainerKeyOrIdName(node) {
|
|
317
|
-
if (!node) {
|
|
318
|
-
return null;
|
|
319
|
-
}
|
|
320
|
-
if (node.id) {
|
|
321
|
-
const idName = (0, require_story_utils_1.getNodeName)(node.id);
|
|
322
|
-
if (typeof idName === "string" && idName.length > 0) {
|
|
323
|
-
return idName;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
if (node.key) {
|
|
327
|
-
const keyName = (0, require_story_utils_1.getNodeName)(node.key);
|
|
328
|
-
if (typeof keyName === "string" && keyName.length > 0) {
|
|
329
|
-
return keyName;
|
|
330
|
-
}
|
|
331
|
-
if (node.key.type === "Literal" &&
|
|
332
|
-
typeof node.key.value === "string" &&
|
|
333
|
-
node.key.value.length > 0) {
|
|
334
|
-
return node.key.value;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Small utility to walk the node and its parents to extract an Identifier or key name.
|
|
341
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
342
|
-
* @req REQ-ANNOTATION-REQUIRED - Walk node and parents to find Identifier/Key name
|
|
343
|
-
*/
|
|
344
|
-
function extractName(node) {
|
|
345
|
-
let current = node;
|
|
346
|
-
while (current) {
|
|
347
|
-
const directIdentifierName = getDirectIdentifierName(current);
|
|
348
|
-
if (directIdentifierName) {
|
|
349
|
-
return directIdentifierName;
|
|
350
|
-
}
|
|
351
|
-
const containerName = getContainerKeyOrIdName(current);
|
|
352
|
-
if (containerName) {
|
|
353
|
-
return containerName;
|
|
354
|
-
}
|
|
355
|
-
const directName = current.name;
|
|
356
|
-
if (typeof directName === "string" && directName.length > 0) {
|
|
357
|
-
return directName;
|
|
358
|
-
}
|
|
359
|
-
current = current.parent;
|
|
360
|
-
}
|
|
361
|
-
return "(anonymous)";
|
|
362
|
-
}
|
|
363
87
|
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
364
88
|
function shouldProcessNode(node, scope, exportPriority = "all", options) {
|
|
365
89
|
if (node &&
|
|
@@ -372,7 +96,7 @@ function shouldProcessNode(node, scope, exportPriority = "all", options) {
|
|
|
372
96
|
if (!scope.includes(node.type)) {
|
|
373
97
|
return false;
|
|
374
98
|
}
|
|
375
|
-
const exported = isExportedNode(node);
|
|
99
|
+
const exported = (0, require_story_node_utils_1.isExportedNode)(node);
|
|
376
100
|
if (exportPriority === "exported" && !exported) {
|
|
377
101
|
return false;
|
|
378
102
|
}
|
|
@@ -381,48 +105,16 @@ function shouldProcessNode(node, scope, exportPriority = "all", options) {
|
|
|
381
105
|
}
|
|
382
106
|
return true;
|
|
383
107
|
}
|
|
384
|
-
/**
|
|
385
|
-
* Resolve the effective function name to report for a node.
|
|
386
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
387
|
-
* @req REQ-ANNOTATION-REQUIRED - Centralize reported function name resolution
|
|
388
|
-
*/
|
|
389
|
-
function getReportedFunctionName(node) {
|
|
390
|
-
const candidate = node && (node.id || node.key) ? node.id || node.key : node;
|
|
391
|
-
return extractName(candidate);
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Determine the most appropriate AST node to anchor error location for a report.
|
|
395
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
396
|
-
* @req REQ-ANNOTATION-REQUIRED - Normalize name node selection for error reporting
|
|
397
|
-
*/
|
|
398
|
-
function getNameNodeForReport(node) {
|
|
399
|
-
if (node?.id?.type === "Identifier") {
|
|
400
|
-
return node.id;
|
|
401
|
-
}
|
|
402
|
-
if (node?.key?.type === "Identifier") {
|
|
403
|
-
return node.key;
|
|
404
|
-
}
|
|
405
|
-
return node;
|
|
406
|
-
}
|
|
407
|
-
/**
|
|
408
|
-
* Resolve the node that should receive the @story annotation,
|
|
409
|
-
* respecting an explicitly passed target when provided.
|
|
410
|
-
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
411
|
-
* @req REQ-ANNOTATION-REQUIRED - Centralize annotation target node resolution
|
|
412
|
-
*/
|
|
413
|
-
function resolveAnnotationTargetNode(sourceCode, node, passedTarget) {
|
|
414
|
-
return passedTarget ?? resolveTargetNode(sourceCode, node);
|
|
415
|
-
}
|
|
416
108
|
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
417
109
|
function reportMissing(context, sourceCode, config) {
|
|
418
110
|
(0, require_story_core_1.coreReportMissing)({
|
|
419
|
-
hasStoryAnnotation,
|
|
420
|
-
hasStoryAnnotationWithPlacement,
|
|
421
|
-
getReportedFunctionName,
|
|
422
|
-
resolveAnnotationTargetNode,
|
|
423
|
-
getNameNodeForReport,
|
|
111
|
+
hasStoryAnnotation: require_story_comment_detection_1.hasStoryAnnotation,
|
|
112
|
+
hasStoryAnnotationWithPlacement: require_story_comment_detection_1.hasStoryAnnotationWithPlacement,
|
|
113
|
+
getReportedFunctionName: require_story_name_extraction_1.getReportedFunctionName,
|
|
114
|
+
resolveAnnotationTargetNode: require_story_node_utils_1.resolveAnnotationTargetNode,
|
|
115
|
+
getNameNodeForReport: require_story_name_extraction_1.getNameNodeForReport,
|
|
424
116
|
buildTemplateConfig,
|
|
425
|
-
extractName,
|
|
117
|
+
extractName: require_story_name_extraction_1.extractName,
|
|
426
118
|
getAnnotationTemplate,
|
|
427
119
|
shouldApplyAutoFix,
|
|
428
120
|
createAddStoryFix: require_story_core_1.createAddStoryFix,
|
|
@@ -432,13 +124,13 @@ function reportMissing(context, sourceCode, config) {
|
|
|
432
124
|
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
433
125
|
function reportMethod(context, sourceCode, config) {
|
|
434
126
|
(0, require_story_core_1.coreReportMethod)({
|
|
435
|
-
hasStoryAnnotation,
|
|
436
|
-
hasStoryAnnotationWithPlacement,
|
|
437
|
-
getReportedFunctionName,
|
|
438
|
-
resolveAnnotationTargetNode,
|
|
439
|
-
getNameNodeForReport,
|
|
127
|
+
hasStoryAnnotation: require_story_comment_detection_1.hasStoryAnnotation,
|
|
128
|
+
hasStoryAnnotationWithPlacement: require_story_comment_detection_1.hasStoryAnnotationWithPlacement,
|
|
129
|
+
getReportedFunctionName: require_story_name_extraction_1.getReportedFunctionName,
|
|
130
|
+
resolveAnnotationTargetNode: require_story_node_utils_1.resolveAnnotationTargetNode,
|
|
131
|
+
getNameNodeForReport: require_story_name_extraction_1.getNameNodeForReport,
|
|
440
132
|
buildTemplateConfig,
|
|
441
|
-
extractName,
|
|
133
|
+
extractName: require_story_name_extraction_1.extractName,
|
|
442
134
|
getAnnotationTemplate,
|
|
443
135
|
shouldApplyAutoFix,
|
|
444
136
|
createAddStoryFix: require_story_core_1.createAddStoryFix,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract a direct Identifier name when available on the given node.
|
|
3
|
+
*
|
|
4
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
5
|
+
* @req REQ-ANNOTATION-REQUIRED - Extract direct Identifier-based names from nodes
|
|
6
|
+
*/
|
|
7
|
+
export declare function getDirectIdentifierName(node: any): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Normalize container nodes that expose names via id/key properties.
|
|
10
|
+
*
|
|
11
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
12
|
+
* @req REQ-ANNOTATION-REQUIRED - Normalize container id/key-based names into a single helper
|
|
13
|
+
*/
|
|
14
|
+
export declare function getContainerKeyOrIdName(node: any): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Small utility to walk the node and its parents to extract an Identifier or key name.
|
|
17
|
+
*
|
|
18
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
19
|
+
* @req REQ-ANNOTATION-REQUIRED - Walk node and parents to find Identifier/Key name
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractName(node: any): string;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the effective function name to report for a node.
|
|
24
|
+
*
|
|
25
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
26
|
+
* @req REQ-ANNOTATION-REQUIRED - Centralize reported function name resolution
|
|
27
|
+
*/
|
|
28
|
+
export declare function getReportedFunctionName(node: any): string;
|
|
29
|
+
/**
|
|
30
|
+
* Determine the most appropriate AST node to anchor error location for a report.
|
|
31
|
+
*
|
|
32
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
33
|
+
* @req REQ-ANNOTATION-REQUIRED - Normalize name node selection for error reporting
|
|
34
|
+
*/
|
|
35
|
+
export declare function getNameNodeForReport(node: any): any;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDirectIdentifierName = getDirectIdentifierName;
|
|
4
|
+
exports.getContainerKeyOrIdName = getContainerKeyOrIdName;
|
|
5
|
+
exports.extractName = extractName;
|
|
6
|
+
exports.getReportedFunctionName = getReportedFunctionName;
|
|
7
|
+
exports.getNameNodeForReport = getNameNodeForReport;
|
|
8
|
+
/**
|
|
9
|
+
* Name extraction utilities for require-story rule
|
|
10
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
11
|
+
* @req REQ-ANNOTATION-REQUIRED - File-level header for name extraction utilities
|
|
12
|
+
*/
|
|
13
|
+
const require_story_utils_1 = require("./require-story-utils");
|
|
14
|
+
/**
|
|
15
|
+
* Extract a direct Identifier name when available on the given node.
|
|
16
|
+
*
|
|
17
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
18
|
+
* @req REQ-ANNOTATION-REQUIRED - Extract direct Identifier-based names from nodes
|
|
19
|
+
*/
|
|
20
|
+
function getDirectIdentifierName(node) {
|
|
21
|
+
if (node &&
|
|
22
|
+
node.type === "Identifier" &&
|
|
23
|
+
typeof node.name === "string" &&
|
|
24
|
+
node.name.length > 0) {
|
|
25
|
+
return node.name;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Normalize container nodes that expose names via id/key properties.
|
|
31
|
+
*
|
|
32
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
33
|
+
* @req REQ-ANNOTATION-REQUIRED - Normalize container id/key-based names into a single helper
|
|
34
|
+
*/
|
|
35
|
+
function getContainerKeyOrIdName(node) {
|
|
36
|
+
if (!node) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (node.id) {
|
|
40
|
+
const idName = (0, require_story_utils_1.getNodeName)(node.id);
|
|
41
|
+
if (typeof idName === "string" && idName.length > 0) {
|
|
42
|
+
return idName;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (node.key) {
|
|
46
|
+
const keyName = (0, require_story_utils_1.getNodeName)(node.key);
|
|
47
|
+
if (typeof keyName === "string" && keyName.length > 0) {
|
|
48
|
+
return keyName;
|
|
49
|
+
}
|
|
50
|
+
if (node.key.type === "Literal" &&
|
|
51
|
+
typeof node.key.value === "string" &&
|
|
52
|
+
node.key.value.length > 0) {
|
|
53
|
+
return node.key.value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Small utility to walk the node and its parents to extract an Identifier or key name.
|
|
60
|
+
*
|
|
61
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
62
|
+
* @req REQ-ANNOTATION-REQUIRED - Walk node and parents to find Identifier/Key name
|
|
63
|
+
*/
|
|
64
|
+
function extractName(node) {
|
|
65
|
+
let current = node;
|
|
66
|
+
while (current) {
|
|
67
|
+
const directIdentifierName = getDirectIdentifierName(current);
|
|
68
|
+
if (directIdentifierName) {
|
|
69
|
+
return directIdentifierName;
|
|
70
|
+
}
|
|
71
|
+
const containerName = getContainerKeyOrIdName(current);
|
|
72
|
+
if (containerName) {
|
|
73
|
+
return containerName;
|
|
74
|
+
}
|
|
75
|
+
const directName = current.name;
|
|
76
|
+
if (typeof directName === "string" && directName.length > 0) {
|
|
77
|
+
return directName;
|
|
78
|
+
}
|
|
79
|
+
current = current.parent;
|
|
80
|
+
}
|
|
81
|
+
return "(anonymous)";
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Resolve the effective function name to report for a node.
|
|
85
|
+
*
|
|
86
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
87
|
+
* @req REQ-ANNOTATION-REQUIRED - Centralize reported function name resolution
|
|
88
|
+
*/
|
|
89
|
+
function getReportedFunctionName(node) {
|
|
90
|
+
const candidate = node && (node.id || node.key) ? node.id || node.key : node;
|
|
91
|
+
return extractName(candidate);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Determine the most appropriate AST node to anchor error location for a report.
|
|
95
|
+
*
|
|
96
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
97
|
+
* @req REQ-ANNOTATION-REQUIRED - Normalize name node selection for error reporting
|
|
98
|
+
*/
|
|
99
|
+
function getNameNodeForReport(node) {
|
|
100
|
+
if (node?.id?.type === "Identifier") {
|
|
101
|
+
return node.id;
|
|
102
|
+
}
|
|
103
|
+
if (node?.key?.type === "Identifier") {
|
|
104
|
+
return node.key;
|
|
105
|
+
}
|
|
106
|
+
return node;
|
|
107
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determine whether a node represents an anonymous arrow function expression
|
|
3
|
+
* where the parent variable declarator has no explicit Identifier name.
|
|
4
|
+
*
|
|
5
|
+
* @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-ARROW-FUNCTION-EXCLUDED
|
|
6
|
+
*/
|
|
7
|
+
export declare function isAnonymousArrowFunction(node: any): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Determine whether a function-like node is nested within another function.
|
|
10
|
+
*
|
|
11
|
+
* @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-NESTED-FUNCTION-INHERITANCE
|
|
12
|
+
*/
|
|
13
|
+
export declare function isNestedFunction(node: any): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Determine whether a function-like node is effectively anonymous for the
|
|
16
|
+
* purposes of nested-function inheritance. Named functions must always carry
|
|
17
|
+
* their own annotations, while anonymous nested functions may inherit.
|
|
18
|
+
*
|
|
19
|
+
* @supports docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md REQ-NESTED-FUNCTION-INHERITANCE
|
|
20
|
+
*/
|
|
21
|
+
export declare function isEffectivelyAnonymousFunction(node: any): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Determine if a node is in an export declaration
|
|
24
|
+
*
|
|
25
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
26
|
+
* @req REQ-ANNOTATION-REQUIRED - Check node ancestry to find export declarations
|
|
27
|
+
*/
|
|
28
|
+
export declare function isExportedNode(node: any): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Determine AST node where annotation should be inserted
|
|
31
|
+
*
|
|
32
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
33
|
+
* @req REQ-ANNOTATION-REQUIRED - Determine correct insertion target for annotation
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveTargetNode(sourceCode: any, node: any): any;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the node that should receive the `@story` annotation,
|
|
38
|
+
* respecting an explicitly passed target when provided.
|
|
39
|
+
*
|
|
40
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
41
|
+
* @req REQ-ANNOTATION-REQUIRED - Centralize annotation target node resolution
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveAnnotationTargetNode(sourceCode: any, node: any, passedTarget: any): any;
|