eslint-plugin-traceability 1.4.2 → 1.4.4

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.
@@ -0,0 +1,293 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fallbackTextBeforeHasStory = exports.parentChainHasStory = exports.linesBeforeHasStory = exports.EXPORT_PRIORITY_VALUES = exports.DEFAULT_SCOPE = exports.FALLBACK_WINDOW = exports.LOOKBACK_LINES = exports.ANNOTATION = exports.STORY_PATH = void 0;
4
+ exports.isExportedNode = isExportedNode;
5
+ exports.jsdocHasStory = jsdocHasStory;
6
+ exports.commentsBeforeHasStory = commentsBeforeHasStory;
7
+ exports.leadingCommentsHasStory = leadingCommentsHasStory;
8
+ exports.hasStoryAnnotation = hasStoryAnnotation;
9
+ exports.getNodeName = getNodeName;
10
+ exports.resolveTargetNode = resolveTargetNode;
11
+ exports.shouldProcessNode = shouldProcessNode;
12
+ exports.reportMissing = reportMissing;
13
+ exports.reportMethod = reportMethod;
14
+ const require_story_io_1 = require("./require-story-io");
15
+ Object.defineProperty(exports, "linesBeforeHasStory", { enumerable: true, get: function () { return require_story_io_1.linesBeforeHasStory; } });
16
+ Object.defineProperty(exports, "parentChainHasStory", { enumerable: true, get: function () { return require_story_io_1.parentChainHasStory; } });
17
+ Object.defineProperty(exports, "fallbackTextBeforeHasStory", { enumerable: true, get: function () { return require_story_io_1.fallbackTextBeforeHasStory; } });
18
+ const require_story_core_1 = require("./require-story-core");
19
+ Object.defineProperty(exports, "DEFAULT_SCOPE", { enumerable: true, get: function () { return require_story_core_1.DEFAULT_SCOPE; } });
20
+ Object.defineProperty(exports, "EXPORT_PRIORITY_VALUES", { enumerable: true, get: function () { return require_story_core_1.EXPORT_PRIORITY_VALUES; } });
21
+ /**
22
+ * Path to the story file for annotations
23
+ */
24
+ const STORY_PATH = "docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md";
25
+ exports.STORY_PATH = STORY_PATH;
26
+ const ANNOTATION = `/** @story ${STORY_PATH} */`;
27
+ exports.ANNOTATION = ANNOTATION;
28
+ /**
29
+ * Number of physical source lines to inspect before a node when searching for @story text
30
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
31
+ * @req REQ-ANNOTATION-REQUIRED - Replace magic number for lookback lines with named constant
32
+ */
33
+ const LOOKBACK_LINES = 4;
34
+ exports.LOOKBACK_LINES = LOOKBACK_LINES;
35
+ /**
36
+ * Window (in characters) to inspect before a node as a fallback when searching for @story text
37
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
38
+ * @req REQ-ANNOTATION-REQUIRED - Replace magic number for fallback text window with named constant
39
+ */
40
+ const FALLBACK_WINDOW = 800;
41
+ exports.FALLBACK_WINDOW = FALLBACK_WINDOW;
42
+ /**
43
+ * Determine if a node is in an export declaration
44
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
45
+ * @req REQ-ANNOTATION-REQUIRED - Check node ancestry to find export declarations
46
+ * @param {any} node - AST node to check for export ancestry
47
+ * @returns {boolean} true if node is within an export declaration
48
+ */
49
+ function isExportedNode(node) {
50
+ let p = node.parent;
51
+ // @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
52
+ // @req REQ-ANNOTATION-REQUIRED - Walk parent chain to find Export declarations
53
+ while (p) {
54
+ if (p.type === "ExportNamedDeclaration" ||
55
+ p.type === "ExportDefaultDeclaration") {
56
+ return true;
57
+ }
58
+ p = p.parent;
59
+ }
60
+ return false;
61
+ }
62
+ /**
63
+ * Check whether the JSDoc associated with node contains @story
64
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
65
+ * @req REQ-ANNOTATION-REQUIRED - Extract JSDoc based detection into helper
66
+ * @param {any} sourceCode - ESLint sourceCode object
67
+ * @param {any} node - AST node to inspect
68
+ * @returns {boolean} true if JSDoc contains @story
69
+ */
70
+ function jsdocHasStory(sourceCode, node) {
71
+ if (typeof sourceCode?.getJSDocComment !== "function") {
72
+ return false;
73
+ }
74
+ const jsdoc = sourceCode.getJSDocComment(node);
75
+ return !!(jsdoc &&
76
+ typeof jsdoc.value === "string" &&
77
+ jsdoc.value.includes("@story"));
78
+ }
79
+ /**
80
+ * Check whether comments returned by sourceCode.getCommentsBefore contain @story
81
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
82
+ * @req REQ-ANNOTATION-REQUIRED - Extract comment-before detection into helper
83
+ * @param {any} sourceCode - ESLint sourceCode object
84
+ * @param {any} node - AST node to inspect
85
+ * @returns {boolean} true if any preceding comment contains @story
86
+ */
87
+ function commentsBeforeHasStory(sourceCode, node) {
88
+ if (typeof sourceCode?.getCommentsBefore !== "function") {
89
+ return false;
90
+ }
91
+ const commentsBefore = sourceCode.getCommentsBefore(node) || [];
92
+ return (Array.isArray(commentsBefore) &&
93
+ commentsBefore.some((c) => typeof c.value === "string" && c.value.includes("@story")));
94
+ }
95
+ /**
96
+ * Check whether leadingComments attached to the node contain @story
97
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
98
+ * @req REQ-ANNOTATION-REQUIRED - Extract leadingComments detection into helper
99
+ * @param {any} node - AST node to inspect
100
+ * @returns {boolean} true if any leading comment contains @story
101
+ */
102
+ function leadingCommentsHasStory(node) {
103
+ const leadingComments = (node && node.leadingComments) || [];
104
+ return (Array.isArray(leadingComments) &&
105
+ leadingComments.some((c) => typeof c.value === "string" && c.value.includes("@story")));
106
+ }
107
+ /**
108
+ * Check if @story annotation already present in JSDoc or preceding comments
109
+ * Consolidates a variety of heuristics through smaller helpers.
110
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
111
+ * @req REQ-ANNOTATION-REQUIRED - Detect existing story annotations in JSDoc or comments
112
+ * @param {any} sourceCode - ESLint sourceCode object
113
+ * @param {any} node - AST node to inspect for existing annotations
114
+ * @returns {boolean} true if @story annotation already present
115
+ */
116
+ function hasStoryAnnotation(sourceCode, node) {
117
+ try {
118
+ if (jsdocHasStory(sourceCode, node)) {
119
+ return true;
120
+ }
121
+ if (commentsBeforeHasStory(sourceCode, node)) {
122
+ return true;
123
+ }
124
+ if (leadingCommentsHasStory(node)) {
125
+ return true;
126
+ }
127
+ if ((0, require_story_io_1.linesBeforeHasStory)(sourceCode, node, LOOKBACK_LINES)) {
128
+ return true;
129
+ }
130
+ if ((0, require_story_io_1.parentChainHasStory)(sourceCode, node)) {
131
+ return true;
132
+ }
133
+ if ((0, require_story_io_1.fallbackTextBeforeHasStory)(sourceCode, node)) {
134
+ return true;
135
+ }
136
+ }
137
+ catch {
138
+ /* noop */
139
+ }
140
+ return false;
141
+ }
142
+ /**
143
+ * Get the name of the function-like node
144
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
145
+ * @req REQ-ANNOTATION-REQUIRED - Resolve a human-friendly name for a function-like AST node
146
+ * @param {any} node - AST node representing a function-like construct
147
+ * @returns {string} the resolved name or "<unknown>"
148
+ */
149
+ function getNodeName(node) {
150
+ let current = node;
151
+ while (current) {
152
+ if (current.type === "VariableDeclarator" &&
153
+ current.id &&
154
+ typeof current.id.name === "string") {
155
+ return current.id.name;
156
+ }
157
+ if ((current.type === "FunctionDeclaration" ||
158
+ current.type === "TSDeclareFunction") &&
159
+ current.id &&
160
+ typeof current.id.name === "string") {
161
+ return current.id.name;
162
+ }
163
+ if ((current.type === "MethodDefinition" ||
164
+ current.type === "TSMethodSignature") &&
165
+ current.key &&
166
+ typeof current.key.name === "string") {
167
+ return current.key.name;
168
+ }
169
+ current = current.parent;
170
+ }
171
+ return "<unknown>";
172
+ }
173
+ /**
174
+ * Determine AST node where annotation should be inserted
175
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
176
+ * @req REQ-ANNOTATION-REQUIRED - Determine correct insertion target for annotation
177
+ * @param {any} sourceCode - ESLint sourceCode object (unused but kept for parity)
178
+ * @param {any} node - function-like AST node to resolve target for
179
+ * @returns {any} AST node that should receive the annotation
180
+ */
181
+ function resolveTargetNode(sourceCode, node) {
182
+ if (node.type === "TSMethodSignature") {
183
+ // Interface method signature -> insert on interface
184
+ return node.parent.parent;
185
+ }
186
+ if (node.type === "FunctionExpression" ||
187
+ node.type === "ArrowFunctionExpression") {
188
+ const parent = node.parent;
189
+ if (parent.type === "VariableDeclarator") {
190
+ const varDecl = parent.parent;
191
+ if (varDecl.parent && varDecl.parent.type === "ExportNamedDeclaration") {
192
+ return varDecl.parent;
193
+ }
194
+ return varDecl;
195
+ }
196
+ if (parent.type === "ExportNamedDeclaration") {
197
+ return parent;
198
+ }
199
+ if (parent.type === "ExpressionStatement") {
200
+ return parent;
201
+ }
202
+ }
203
+ return node;
204
+ }
205
+ /**
206
+ * Check if this node is within scope and matches exportPriority
207
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
208
+ * @req REQ-ANNOTATION-REQUIRED - Determine whether a node should be processed by rule
209
+ * @param {any} node - AST node to evaluate
210
+ * @param {string[]} scope - allowed node types
211
+ * @param {string} [exportPriority='all'] - 'all' | 'exported' | 'non-exported' (default: 'all')
212
+ * @returns {boolean} whether node should be processed
213
+ */
214
+ function shouldProcessNode(node, scope, exportPriority = "all") {
215
+ if (!scope.includes(node.type)) {
216
+ return false;
217
+ }
218
+ const exported = isExportedNode(node);
219
+ if (exportPriority === "exported" && !exported) {
220
+ return false;
221
+ }
222
+ if (exportPriority === "non-exported" && exported) {
223
+ return false;
224
+ }
225
+ return true;
226
+ }
227
+ /**
228
+ * Report a missing @story annotation for a function-like node
229
+ * Provides a suggestion to add the annotation.
230
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
231
+ * @req REQ-ANNOTATION-REQUIRED - Implement reporting for missing annotations with suggestion
232
+ * @param {Rule.RuleContext} context - ESLint rule context used to report
233
+ * @param {any} sourceCode - ESLint sourceCode object
234
+ * @param {any} node - AST node that is missing the annotation
235
+ * @param {any} [passedTarget] - optional AST node to use as insertion target instead of resolving from node
236
+ */
237
+ function reportMissing(context, sourceCode, node, passedTarget) {
238
+ try {
239
+ const functionName = getNodeName(node);
240
+ if (hasStoryAnnotation(sourceCode, node)) {
241
+ return;
242
+ }
243
+ const resolvedTarget = passedTarget ?? resolveTargetNode(sourceCode, node);
244
+ const name = functionName;
245
+ context.report({
246
+ node,
247
+ messageId: "missingStory",
248
+ data: { name },
249
+ suggest: [
250
+ {
251
+ desc: `Add JSDoc @story annotation for function '${name}', e.g., ${ANNOTATION}`,
252
+ fix: (0, require_story_core_1.createAddStoryFix)(resolvedTarget),
253
+ },
254
+ ],
255
+ });
256
+ }
257
+ catch {
258
+ /* noop */
259
+ }
260
+ }
261
+ /**
262
+ * Report a missing @story annotation for a method-like node
263
+ * Provides a suggestion to update the method/interface with the annotation.
264
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
265
+ * @req REQ-ANNOTATION-REQUIRED - Implement reporting for missing method/interface annotations with suggestion
266
+ * @param {Rule.RuleContext} context - ESLint rule context to report
267
+ * @param {any} sourceCode - ESLint sourceCode object
268
+ * @param {any} node - AST node that is missing the annotation
269
+ * @param {any} [passedTarget] - optional AST node to use as insertion target instead of resolving from node
270
+ */
271
+ function reportMethod(context, sourceCode, node, passedTarget) {
272
+ try {
273
+ if (hasStoryAnnotation(sourceCode, node)) {
274
+ return;
275
+ }
276
+ const resolvedTarget = passedTarget ?? resolveTargetNode(sourceCode, node);
277
+ const name = getNodeName(node);
278
+ context.report({
279
+ node,
280
+ messageId: "missingStory",
281
+ data: { name },
282
+ suggest: [
283
+ {
284
+ desc: `Add JSDoc @story annotation for function '${name}', e.g., ${ANNOTATION}`,
285
+ fix: (0, require_story_core_1.createMethodFix)(resolvedTarget),
286
+ },
287
+ ],
288
+ });
289
+ }
290
+ catch {
291
+ /* noop */
292
+ }
293
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * IO helpers for require-story detection moved to reduce helper module size
3
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
+ * @req REQ-ANNOTATION-REQUIRED - Extract IO bound helpers to separate module
5
+ */
6
+ /**
7
+ * Number of source lines to inspect before a node when searching for @story markers.
8
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
9
+ * @req REQ-ANNOTATION-REQUIRED - Expose lookback size as constant for reuse
10
+ */
11
+ export declare const LOOKBACK_LINES = 4;
12
+ /**
13
+ * Number of characters to include in the fallback textual inspection window before a node.
14
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
15
+ * @req REQ-ANNOTATION-REQUIRED - Expose fallback window size as constant for reuse
16
+ */
17
+ export declare const FALLBACK_WINDOW = 800;
18
+ /**
19
+ * Inspect a fixed number of physical source lines before the node for @story text
20
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
21
+ * @req REQ-ANNOTATION-REQUIRED - Extract line-based detection into helper
22
+ */
23
+ export declare function linesBeforeHasStory(sourceCode: any, node: any, lookback?: number): boolean;
24
+ /**
25
+ * Walk parent chain and check comments before each parent and their leadingComments
26
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
27
+ * @req REQ-ANNOTATION-REQUIRED - Extract parent-chain comment detection into helper
28
+ */
29
+ export declare function parentChainHasStory(sourceCode: any, node: any): boolean;
30
+ /**
31
+ * Fallback: inspect text immediately preceding the node in sourceCode.getText to find @story
32
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
33
+ * @req REQ-ANNOTATION-REQUIRED - Provide fallback textual inspection when other heuristics fail
34
+ */
35
+ export declare function fallbackTextBeforeHasStory(sourceCode: any, node: any): boolean;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ /**
3
+ * IO helpers for require-story detection moved to reduce helper module size
4
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
+ * @req REQ-ANNOTATION-REQUIRED - Extract IO bound helpers to separate module
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.FALLBACK_WINDOW = exports.LOOKBACK_LINES = void 0;
9
+ exports.linesBeforeHasStory = linesBeforeHasStory;
10
+ exports.parentChainHasStory = parentChainHasStory;
11
+ exports.fallbackTextBeforeHasStory = fallbackTextBeforeHasStory;
12
+ /**
13
+ * Number of source lines to inspect before a node when searching for @story markers.
14
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
15
+ * @req REQ-ANNOTATION-REQUIRED - Expose lookback size as constant for reuse
16
+ */
17
+ exports.LOOKBACK_LINES = 4;
18
+ /**
19
+ * Number of characters to include in the fallback textual inspection window before a node.
20
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
21
+ * @req REQ-ANNOTATION-REQUIRED - Expose fallback window size as constant for reuse
22
+ */
23
+ exports.FALLBACK_WINDOW = 800;
24
+ /**
25
+ * Inspect a fixed number of physical source lines before the node for @story text
26
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
27
+ * @req REQ-ANNOTATION-REQUIRED - Extract line-based detection into helper
28
+ */
29
+ function linesBeforeHasStory(sourceCode, node, lookback = exports.LOOKBACK_LINES) {
30
+ const lines = sourceCode && sourceCode.lines;
31
+ const startLine = node && node.loc && typeof node.loc.start?.line === "number"
32
+ ? node.loc.start.line
33
+ : null;
34
+ if (!Array.isArray(lines) || typeof startLine !== "number") {
35
+ return false;
36
+ }
37
+ const from = Math.max(0, startLine - 1 - lookback);
38
+ const to = Math.max(0, startLine - 1);
39
+ for (let i = from; i < to; i++) {
40
+ const text = lines[i];
41
+ if (typeof text === "string" && text.includes("@story")) {
42
+ return true;
43
+ }
44
+ }
45
+ return false;
46
+ }
47
+ /**
48
+ * Walk parent chain and check comments before each parent and their leadingComments
49
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
50
+ * @req REQ-ANNOTATION-REQUIRED - Extract parent-chain comment detection into helper
51
+ */
52
+ function parentChainHasStory(sourceCode, node) {
53
+ let p = node && node.parent;
54
+ while (p) {
55
+ const pComments = typeof sourceCode?.getCommentsBefore === "function"
56
+ ? sourceCode.getCommentsBefore(p) || []
57
+ : [];
58
+ if (Array.isArray(pComments) &&
59
+ pComments.some((c) => typeof c.value === "string" && c.value.includes("@story"))) {
60
+ return true;
61
+ }
62
+ const pLeading = p.leadingComments || [];
63
+ if (Array.isArray(pLeading) &&
64
+ pLeading.some((c) => typeof c.value === "string" && c.value.includes("@story"))) {
65
+ return true;
66
+ }
67
+ p = p.parent;
68
+ }
69
+ return false;
70
+ }
71
+ /**
72
+ * Fallback: inspect text immediately preceding the node in sourceCode.getText to find @story
73
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
74
+ * @req REQ-ANNOTATION-REQUIRED - Provide fallback textual inspection when other heuristics fail
75
+ */
76
+ function fallbackTextBeforeHasStory(sourceCode, node) {
77
+ if (typeof sourceCode?.getText !== "function" ||
78
+ !Array.isArray((node && node.range) || [])) {
79
+ return false;
80
+ }
81
+ const range = node.range;
82
+ if (!Array.isArray(range) || typeof range[0] !== "number") {
83
+ return false;
84
+ }
85
+ try {
86
+ // Limit the fallback inspect window to a reasonable size
87
+ const start = Math.max(0, range[0] - exports.FALLBACK_WINDOW);
88
+ const textBefore = sourceCode.getText().slice(start, range[0]);
89
+ if (typeof textBefore === "string" && textBefore.includes("@story")) {
90
+ return true;
91
+ }
92
+ }
93
+ catch {
94
+ /* noop */
95
+ }
96
+ return false;
97
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Visitor builders for require-story-annotation rule
3
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
+ * @req REQ-EXTRACT-VISITORS - Extract visitor logic into helper module to reduce rule file size
5
+ */
6
+ import type { Rule } from "eslint";
7
+ /**
8
+ * Build visitor handlers for various function-like AST nodes.
9
+ * Returns merged listener object from smaller builders.
10
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
11
+ * @req REQ-BUILD-VISITORS - Provide visitor implementations for rule create()
12
+ */
13
+ export declare function buildVisitors(context: Rule.RuleContext, sourceCode: any, options: any): Rule.RuleListener;
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ /**
3
+ * Visitor builders for require-story-annotation rule
4
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
+ * @req REQ-EXTRACT-VISITORS - Extract visitor logic into helper module to reduce rule file size
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.buildVisitors = buildVisitors;
9
+ const require_story_helpers_1 = require("./require-story-helpers");
10
+ /**
11
+ * Build visitor for FunctionDeclaration nodes.
12
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
13
+ * @req REQ-BUILD-VISITORS-FNDECL - Provide visitor for FunctionDeclaration
14
+ */
15
+ function buildFunctionDeclarationVisitor(context, sourceCode, options) {
16
+ /**
17
+ * Handle FunctionDeclaration nodes.
18
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
19
+ * @req REQ-ANNOTATION-REQUIRED - Report missing @story on function declarations
20
+ */
21
+ function handleFunctionDeclaration(node) {
22
+ /**
23
+ * Debug logging for visitor entry
24
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
25
+ * @req REQ-DEBUG-LOG - Provide debug logging for visitor entry
26
+ */
27
+ console.debug("require-story-annotation:FunctionDeclaration", typeof context.getFilename === "function"
28
+ ? context.getFilename()
29
+ : "<unknown>", node && node.id ? node.id.name : "<anonymous>");
30
+ if (!options.shouldProcessNode(node))
31
+ return;
32
+ const target = (0, require_story_helpers_1.resolveTargetNode)(sourceCode, node);
33
+ (0, require_story_helpers_1.reportMissing)(context, sourceCode, node, target);
34
+ }
35
+ return {
36
+ FunctionDeclaration: handleFunctionDeclaration,
37
+ };
38
+ }
39
+ /**
40
+ * Build visitor for FunctionExpression nodes.
41
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
42
+ * @req REQ-BUILD-VISITORS-FNEXPR - Provide visitor for FunctionExpression
43
+ */
44
+ function buildFunctionExpressionVisitor(context, sourceCode, options) {
45
+ /**
46
+ * Handle FunctionExpression nodes.
47
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
48
+ * @req REQ-ANNOTATION-REQUIRED - Report missing @story on function expressions
49
+ */
50
+ function handleFunctionExpression(node) {
51
+ if (!options.shouldProcessNode(node))
52
+ return;
53
+ /**
54
+ * Do not report when function expression is a MethodDefinition
55
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
56
+ * @req REQ-METHOD-SKIP - Skip MethodDefinition function expressions
57
+ */
58
+ if (node.parent && node.parent.type === "MethodDefinition")
59
+ return;
60
+ const target = (0, require_story_helpers_1.resolveTargetNode)(sourceCode, node);
61
+ (0, require_story_helpers_1.reportMissing)(context, sourceCode, node, target);
62
+ }
63
+ return {
64
+ FunctionExpression: handleFunctionExpression,
65
+ };
66
+ }
67
+ /**
68
+ * Build visitor for ArrowFunctionExpression nodes.
69
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
70
+ * @req REQ-BUILD-VISITORS-ARROW - Provide visitor for ArrowFunctionExpression
71
+ */
72
+ function buildArrowFunctionVisitor(context, sourceCode, options) {
73
+ /**
74
+ * Handle ArrowFunctionExpression nodes.
75
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
76
+ * @req REQ-ANNOTATION-REQUIRED - Report missing @story on arrow functions
77
+ */
78
+ function handleArrowFunctionExpression(node) {
79
+ if (!options.shouldProcessNode(node))
80
+ return;
81
+ const target = (0, require_story_helpers_1.resolveTargetNode)(sourceCode, node);
82
+ (0, require_story_helpers_1.reportMissing)(context, sourceCode, node, target);
83
+ }
84
+ return {
85
+ ArrowFunctionExpression: handleArrowFunctionExpression,
86
+ };
87
+ }
88
+ /**
89
+ * Build visitor for TypeScript TSDeclareFunction nodes.
90
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
91
+ * @req REQ-BUILD-VISITORS-TSDECL - Provide visitor for TSDeclareFunction
92
+ */
93
+ function buildTSDeclareFunctionVisitor(context, sourceCode, options) {
94
+ /**
95
+ * Handle TSDeclareFunction nodes.
96
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
97
+ * @req REQ-ANNOTATION-REQUIRED - Report missing @story on TS declare functions
98
+ */
99
+ function handleTSDeclareFunction(node) {
100
+ if (!options.shouldProcessNode(node))
101
+ return;
102
+ (0, require_story_helpers_1.reportMissing)(context, sourceCode, node, node);
103
+ }
104
+ return {
105
+ TSDeclareFunction: handleTSDeclareFunction,
106
+ };
107
+ }
108
+ /**
109
+ * Build visitor for TypeScript TSMethodSignature nodes.
110
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
111
+ * @req REQ-BUILD-VISITORS-TSMSIG - Provide visitor for TSMethodSignature
112
+ */
113
+ function buildTSMethodSignatureVisitor(context, sourceCode, options) {
114
+ /**
115
+ * Handle TSMethodSignature nodes.
116
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
117
+ * @req REQ-ANNOTATION-REQUIRED - Report missing @story on TS method signatures
118
+ */
119
+ function handleTSMethodSignature(node) {
120
+ if (!options.shouldProcessNode(node))
121
+ return;
122
+ const target = (0, require_story_helpers_1.resolveTargetNode)(sourceCode, node);
123
+ (0, require_story_helpers_1.reportMissing)(context, sourceCode, node, target);
124
+ }
125
+ return {
126
+ TSMethodSignature: handleTSMethodSignature,
127
+ };
128
+ }
129
+ /**
130
+ * Build visitor for MethodDefinition nodes.
131
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
132
+ * @req REQ-BUILD-VISITORS-METHODDEF - Provide visitor for MethodDefinition
133
+ */
134
+ function buildMethodDefinitionVisitor(context, sourceCode, options) {
135
+ /**
136
+ * Handle MethodDefinition nodes (class/object methods).
137
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
138
+ * @req REQ-ANNOTATION-REQUIRED - Report missing @story on class/object methods
139
+ */
140
+ function handleMethodDefinition(node) {
141
+ if (!options.shouldProcessNode(node))
142
+ return;
143
+ (0, require_story_helpers_1.reportMethod)(context, sourceCode, node);
144
+ }
145
+ return {
146
+ MethodDefinition: handleMethodDefinition,
147
+ };
148
+ }
149
+ /**
150
+ * Build visitor handlers for various function-like AST nodes.
151
+ * Returns merged listener object from smaller builders.
152
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
153
+ * @req REQ-BUILD-VISITORS - Provide visitor implementations for rule create()
154
+ */
155
+ function buildVisitors(context, sourceCode, options) {
156
+ const fnDecl = buildFunctionDeclarationVisitor(context, sourceCode, options);
157
+ const fnExpr = buildFunctionExpressionVisitor(context, sourceCode, options);
158
+ const arrow = buildArrowFunctionVisitor(context, sourceCode, options);
159
+ const tsDecl = buildTSDeclareFunctionVisitor(context, sourceCode, options);
160
+ const tsSig = buildTSMethodSignatureVisitor(context, sourceCode, options);
161
+ const methodDef = buildMethodDefinitionVisitor(context, sourceCode, options);
162
+ return Object.assign({}, fnDecl, fnExpr, arrow, tsDecl, tsSig, methodDef);
163
+ }
@@ -1,3 +1,18 @@
1
+ /**
2
+ * ESLint rule module: require-story-annotation
3
+ *
4
+ * This file implements the ESLint rule that requires @story annotations
5
+ * on functions and methods according to configured scope and export priority.
6
+ *
7
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
8
+ * @req REQ-ANNOTATION-REQUIRED
9
+ */
1
10
  import type { Rule } from "eslint";
11
+ /**
12
+ * ESLint rule to require @story annotations on functions/methods.
13
+ *
14
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
15
+ * @req REQ-ANNOTATION-REQUIRED
16
+ */
2
17
  declare const rule: Rule.RuleModule;
3
18
  export default rule;