eslint-plugin-traceability 1.19.1 → 1.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -3
- package/lib/src/utils/branch-annotation-helpers.js +106 -128
- package/lib/src/utils/branch-annotation-if-helpers.d.ts +12 -0
- package/lib/src/utils/branch-annotation-if-helpers.js +137 -0
- package/lib/src/utils/branch-annotation-report-helpers.js +2 -1
- package/lib/src/utils/branch-annotation-switch-helpers.d.ts +11 -0
- package/lib/src/utils/branch-annotation-switch-helpers.js +68 -0
- package/lib/tests/integration/annotation-placement-inside-prettier.integration.test.d.ts +1 -0
- package/lib/tests/integration/annotation-placement-inside-prettier.integration.test.js +132 -0
- package/lib/tests/integration/catch-annotation-prettier.integration.test.js +4 -15
- package/lib/tests/integration/else-if-annotation-prettier.integration.test.js +3 -14
- package/lib/tests/integration/prettier-test-helpers.d.ts +9 -0
- package/lib/tests/integration/prettier-test-helpers.js +34 -0
- package/lib/tests/rules/require-branch-annotation.test.js +147 -14
- package/lib/tests/utils/branch-annotation-else-if-insert-position.test.js +6 -5
- package/lib/tests/utils/branch-annotation-helpers.test.js +224 -9
- package/package.json +1 -1
- package/user-docs/api-reference.md +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
## [1.19.
|
|
1
|
+
## [1.19.3](https://github.com/voder-ai/eslint-plugin-traceability/compare/v1.19.2...v1.19.3) (2025-12-18)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
*
|
|
7
|
-
* honor inside placement for catch clauses in branch annotation rule ([0e7a8e0](https://github.com/voder-ai/eslint-plugin-traceability/commit/0e7a8e01505bfa1e37e013dfda00e866f975ad33))
|
|
6
|
+
* support inside placement for switch cases in branch helpers ([3fd08d1](https://github.com/voder-ai/eslint-plugin-traceability/commit/3fd08d1314085a7aa9894f6248dbb7f42a07bda0))
|
|
8
7
|
|
|
9
8
|
# Changelog
|
|
10
9
|
|
|
@@ -9,7 +9,8 @@ exports.reportMissingReq = reportMissingReq;
|
|
|
9
9
|
const branch_annotation_report_helpers_1 = require("./branch-annotation-report-helpers");
|
|
10
10
|
Object.defineProperty(exports, "reportMissingAnnotations", { enumerable: true, get: function () { return branch_annotation_report_helpers_1.reportMissingAnnotations; } });
|
|
11
11
|
const branch_annotation_loop_helpers_1 = require("./branch-annotation-loop-helpers");
|
|
12
|
-
const
|
|
12
|
+
const branch_annotation_if_helpers_1 = require("./branch-annotation-if-helpers");
|
|
13
|
+
const branch_annotation_switch_helpers_1 = require("./branch-annotation-switch-helpers");
|
|
13
14
|
/**
|
|
14
15
|
* Valid branch types for require-branch-annotation rule.
|
|
15
16
|
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
@@ -153,14 +154,6 @@ function scanCommentLinesInRange(lines, startIndex, endIndexInclusive) {
|
|
|
153
154
|
}
|
|
154
155
|
return comments.join(" ");
|
|
155
156
|
}
|
|
156
|
-
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
157
|
-
function isElseIfBranch(node, parent) {
|
|
158
|
-
return (node &&
|
|
159
|
-
node.type === "IfStatement" &&
|
|
160
|
-
parent &&
|
|
161
|
-
parent.type === "IfStatement" &&
|
|
162
|
-
parent.alternate === node);
|
|
163
|
-
}
|
|
164
157
|
function getInsideCatchCommentText(sourceCode, node) {
|
|
165
158
|
const getCommentsInside = sourceCode.getCommentsInside;
|
|
166
159
|
if (node.body && typeof getCommentsInside === "function") {
|
|
@@ -186,6 +179,30 @@ function getInsideCatchCommentText(sourceCode, node) {
|
|
|
186
179
|
}
|
|
187
180
|
return "";
|
|
188
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Gather comment text from the first contiguous comment lines inside a TryStatement block body.
|
|
184
|
+
* @supports docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md REQ-INSIDE-BRACE-PLACEMENT REQ-PLACEMENT-CONFIG
|
|
185
|
+
*/
|
|
186
|
+
function getInsideTryBlockCommentText(sourceCode, node) {
|
|
187
|
+
const block = node && node.block;
|
|
188
|
+
if (!block ||
|
|
189
|
+
block.type !== "BlockStatement" ||
|
|
190
|
+
!block.loc ||
|
|
191
|
+
!block.loc.start ||
|
|
192
|
+
!block.loc.end ||
|
|
193
|
+
typeof block.loc.start.line !== "number" ||
|
|
194
|
+
typeof block.loc.end.line !== "number") {
|
|
195
|
+
return "";
|
|
196
|
+
}
|
|
197
|
+
const lines = sourceCode.lines;
|
|
198
|
+
const startIndex = block.loc.start.line - 1;
|
|
199
|
+
const endIndex = block.loc.end.line - 1;
|
|
200
|
+
const insideText = scanCommentLinesInRange(lines, startIndex + 1, endIndex);
|
|
201
|
+
if (insideText) {
|
|
202
|
+
return insideText;
|
|
203
|
+
}
|
|
204
|
+
return "";
|
|
205
|
+
}
|
|
189
206
|
/**
|
|
190
207
|
* Gather annotation text for CatchClause nodes, supporting both before-catch and inside-catch positions.
|
|
191
208
|
* @story docs/stories/025.0-DEV-CATCH-ANNOTATION-POSITION.story.md
|
|
@@ -260,144 +277,105 @@ function gatherSimpleIfCommentText(sourceCode, node, annotationPlacement, before
|
|
|
260
277
|
}
|
|
261
278
|
return "";
|
|
262
279
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
let scanned = 0;
|
|
273
|
-
while (i >= 0 && scanned < PRE_COMMENT_OFFSET) {
|
|
274
|
-
const commentText = getCommentTextAtLine(lines, i);
|
|
275
|
-
if (!commentText) {
|
|
276
|
-
break;
|
|
280
|
+
function handleTryCatchBranch(sourceCode, node, context) {
|
|
281
|
+
const { annotationPlacement, beforeText } = context;
|
|
282
|
+
if (node.type === "TryStatement") {
|
|
283
|
+
if (annotationPlacement === "inside") {
|
|
284
|
+
const insideText = getInsideTryBlockCommentText(sourceCode, node);
|
|
285
|
+
if (insideText) {
|
|
286
|
+
return insideText;
|
|
287
|
+
}
|
|
288
|
+
return "";
|
|
277
289
|
}
|
|
278
|
-
|
|
279
|
-
i--;
|
|
280
|
-
scanned++;
|
|
290
|
+
return beforeText;
|
|
281
291
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
285
|
-
function hasValidElseIfBlockLoc(node) {
|
|
286
|
-
const hasBlockConsequent = node.consequent &&
|
|
287
|
-
node.consequent.type === "BlockStatement" &&
|
|
288
|
-
node.consequent.loc &&
|
|
289
|
-
node.consequent.loc.start;
|
|
290
|
-
return !!(node.test &&
|
|
291
|
-
node.test.loc &&
|
|
292
|
-
node.test.loc.end &&
|
|
293
|
-
hasBlockConsequent);
|
|
294
|
-
}
|
|
295
|
-
/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */
|
|
296
|
-
function scanElseIfBetweenConditionAndBody(sourceCode, node) {
|
|
297
|
-
const lines = sourceCode.lines;
|
|
298
|
-
const conditionEndLine = node.test.loc.end.line;
|
|
299
|
-
const consequentStartLine = node.consequent.loc.start.line;
|
|
300
|
-
// Lines in sourceCode are 0-based indexes, but loc.line values are 1-based.
|
|
301
|
-
// We want to scan comments strictly between the condition and the
|
|
302
|
-
// consequent body, so we start at the line after the condition's end and
|
|
303
|
-
// stop at the line immediately before the consequent's starting line.
|
|
304
|
-
const startIndex = conditionEndLine; // already the next logical line index when 0-based
|
|
305
|
-
const endIndexExclusive = consequentStartLine - 1;
|
|
306
|
-
if (endIndexExclusive <= startIndex) {
|
|
307
|
-
return "";
|
|
292
|
+
if (node.type === "CatchClause") {
|
|
293
|
+
return gatherCatchClauseCommentText(sourceCode, node, annotationPlacement, beforeText);
|
|
308
294
|
}
|
|
309
|
-
return
|
|
295
|
+
return null;
|
|
310
296
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
let lineIndex = consequentStartLine;
|
|
320
|
-
while (lineIndex < lines.length) {
|
|
321
|
-
if (!collectCommentLine(lines, lineIndex, comments)) {
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
324
|
-
lineIndex++;
|
|
297
|
+
function handleLoopBranch(sourceCode, node, context) {
|
|
298
|
+
const { annotationPlacement, beforeText } = context;
|
|
299
|
+
if (node.type === "ForStatement" ||
|
|
300
|
+
node.type === "ForInStatement" ||
|
|
301
|
+
node.type === "ForOfStatement" ||
|
|
302
|
+
node.type === "WhileStatement" ||
|
|
303
|
+
node.type === "DoWhileStatement") {
|
|
304
|
+
return (0, branch_annotation_loop_helpers_1.gatherLoopCommentText)(sourceCode, node, annotationPlacement, beforeText);
|
|
325
305
|
}
|
|
326
|
-
return
|
|
306
|
+
return null;
|
|
327
307
|
}
|
|
328
308
|
/**
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
* @
|
|
333
|
-
* @
|
|
334
|
-
* @supports REQ-
|
|
309
|
+
* Helper that gathers comment text for non-IfStatement branch types using
|
|
310
|
+
* straightforward behavior (SwitchCase, CatchClause, and loop statements).
|
|
311
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
312
|
+
* @supports REQ-COMMENT-ASSOCIATION
|
|
313
|
+
* @story docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md
|
|
314
|
+
* @supports REQ-PLACEMENT-CONFIG
|
|
335
315
|
*/
|
|
336
|
-
function
|
|
337
|
-
if (
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
/@supports\b/.test(beforeText))) {
|
|
341
|
-
return beforeText;
|
|
342
|
-
}
|
|
343
|
-
if (!isElseIfBranch(node, parent)) {
|
|
344
|
-
return beforeText;
|
|
345
|
-
}
|
|
346
|
-
const beforeElseText = scanElseIfPrecedingComments(sourceCode, node);
|
|
347
|
-
if (beforeElseText &&
|
|
348
|
-
(/@story\b/.test(beforeElseText) ||
|
|
349
|
-
/@req\b/.test(beforeElseText) ||
|
|
350
|
-
/@supports\b/.test(beforeElseText))) {
|
|
351
|
-
return beforeElseText;
|
|
352
|
-
}
|
|
353
|
-
if (!hasValidElseIfBlockLoc(node)) {
|
|
354
|
-
return beforeText;
|
|
355
|
-
}
|
|
356
|
-
const betweenText = scanElseIfBetweenConditionAndBody(sourceCode, node);
|
|
357
|
-
if (betweenText) {
|
|
358
|
-
return betweenText;
|
|
316
|
+
function gatherNonIfBranchCommentText(sourceCode, node, context) {
|
|
317
|
+
if (node.type === "SwitchCase") {
|
|
318
|
+
const { annotationPlacement, beforeText } = context;
|
|
319
|
+
return (0, branch_annotation_switch_helpers_1.gatherSwitchCaseCommentText)(sourceCode, node, annotationPlacement, beforeText);
|
|
359
320
|
}
|
|
360
|
-
const
|
|
361
|
-
if (
|
|
362
|
-
return
|
|
321
|
+
const tryCatchResult = handleTryCatchBranch(sourceCode, node, context);
|
|
322
|
+
if (tryCatchResult != null) {
|
|
323
|
+
return tryCatchResult;
|
|
363
324
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
function gatherSwitchCaseCommentText(sourceCode, node) {
|
|
368
|
-
const lines = sourceCode.lines;
|
|
369
|
-
const startLine = node.loc.start.line;
|
|
370
|
-
let i = startLine - PRE_COMMENT_OFFSET;
|
|
371
|
-
const comments = [];
|
|
372
|
-
while (i >= 0 && /^\s*(\/\/|\/\*)/.test(lines[i])) {
|
|
373
|
-
comments.unshift(lines[i].trim());
|
|
374
|
-
i--;
|
|
325
|
+
const loopResult = handleLoopBranch(sourceCode, node, context);
|
|
326
|
+
if (loopResult != null) {
|
|
327
|
+
return loopResult;
|
|
375
328
|
}
|
|
376
|
-
return
|
|
329
|
+
return null;
|
|
377
330
|
}
|
|
378
|
-
|
|
331
|
+
/**
|
|
332
|
+
* Helper that gathers comment text for IfStatement branches, including both
|
|
333
|
+
* simple if and else-if specific logic.
|
|
334
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
335
|
+
* @supports REQ-COMMENT-ASSOCIATION
|
|
336
|
+
* @story docs/stories/026.0-DEV-ELSE-IF-ANNOTATION-POSITION.story.md
|
|
337
|
+
* @supports REQ-DUAL-POSITION-DETECTION
|
|
338
|
+
* @story docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md
|
|
339
|
+
* @supports REQ-PLACEMENT-CONFIG
|
|
340
|
+
* @supports REQ-DEFAULT-BACKWARD-COMPAT
|
|
341
|
+
*/
|
|
342
|
+
function gatherIfBranchCommentText(sourceCode, node, parent, context) {
|
|
379
343
|
const { annotationPlacement, beforeText } = context;
|
|
380
|
-
if (node.type
|
|
381
|
-
return
|
|
344
|
+
if (node.type !== "IfStatement") {
|
|
345
|
+
return null;
|
|
382
346
|
}
|
|
383
|
-
if (node
|
|
384
|
-
return
|
|
347
|
+
if ((0, branch_annotation_if_helpers_1.isElseIfBranch)(node, parent)) {
|
|
348
|
+
return (0, branch_annotation_if_helpers_1.gatherElseIfCommentText)(sourceCode, node, parent, {
|
|
349
|
+
annotationPlacement,
|
|
350
|
+
beforeText,
|
|
351
|
+
});
|
|
385
352
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
353
|
+
return gatherSimpleIfCommentText(sourceCode, node, annotationPlacement, beforeText);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Internal helper that performs type-based dispatch for gathering branch comment text.
|
|
357
|
+
* This keeps the public gatherBranchCommentTextByType wrapper small for ESLint limits.
|
|
358
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
359
|
+
* @supports REQ-COMMENT-ASSOCIATION
|
|
360
|
+
* @story docs/stories/026.0-DEV-ELSE-IF-ANNOTATION-POSITION.story.md
|
|
361
|
+
* @supports REQ-DUAL-POSITION-DETECTION
|
|
362
|
+
* @story docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md
|
|
363
|
+
* @supports REQ-PLACEMENT-CONFIG
|
|
364
|
+
*/
|
|
365
|
+
function gatherBranchCommentTextByTypeInternal(sourceCode, node, parent, context) {
|
|
366
|
+
const nonIfResult = gatherNonIfBranchCommentText(sourceCode, node, context);
|
|
367
|
+
if (nonIfResult != null) {
|
|
368
|
+
return nonIfResult;
|
|
391
369
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
node.type === "WhileStatement" ||
|
|
396
|
-
node.type === "DoWhileStatement") {
|
|
397
|
-
return (0, branch_annotation_loop_helpers_1.gatherLoopCommentText)(sourceCode, node, annotationPlacement, beforeText);
|
|
370
|
+
const ifResult = gatherIfBranchCommentText(sourceCode, node, parent, context);
|
|
371
|
+
if (ifResult != null) {
|
|
372
|
+
return ifResult;
|
|
398
373
|
}
|
|
399
374
|
return null;
|
|
400
375
|
}
|
|
376
|
+
function gatherBranchCommentTextByType(sourceCode, node, parent, context) {
|
|
377
|
+
return gatherBranchCommentTextByTypeInternal(sourceCode, node, parent, context);
|
|
378
|
+
}
|
|
401
379
|
/**
|
|
402
380
|
* Gather leading comment text for a branch node.
|
|
403
381
|
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
import type { AnnotationPlacement } from "./branch-annotation-helpers";
|
|
3
|
+
export declare function isElseIfBranch(node: any, parent: any | undefined): boolean;
|
|
4
|
+
export declare function hasValidElseIfBlockLoc(node: any): boolean;
|
|
5
|
+
export declare function scanElseIfPrecedingComments(sourceCode: ReturnType<Rule.RuleContext["getSourceCode"]>, node: any): string;
|
|
6
|
+
export declare function scanElseIfBetweenConditionAndBody(sourceCode: ReturnType<Rule.RuleContext["getSourceCode"]>, node: any): string;
|
|
7
|
+
export declare function scanElseIfInsideBlockComments(sourceCode: ReturnType<Rule.RuleContext["getSourceCode"]>, node: any): string;
|
|
8
|
+
export declare function getInsideElseIfCommentText(sourceCode: ReturnType<Rule.RuleContext["getSourceCode"]>, node: any): string;
|
|
9
|
+
export declare function gatherElseIfCommentText(sourceCode: ReturnType<Rule.RuleContext["getSourceCode"]>, node: any, parent: any | undefined, options: {
|
|
10
|
+
annotationPlacement: AnnotationPlacement;
|
|
11
|
+
beforeText: string;
|
|
12
|
+
}): string;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isElseIfBranch = isElseIfBranch;
|
|
4
|
+
exports.hasValidElseIfBlockLoc = hasValidElseIfBlockLoc;
|
|
5
|
+
exports.scanElseIfPrecedingComments = scanElseIfPrecedingComments;
|
|
6
|
+
exports.scanElseIfBetweenConditionAndBody = scanElseIfBetweenConditionAndBody;
|
|
7
|
+
exports.scanElseIfInsideBlockComments = scanElseIfInsideBlockComments;
|
|
8
|
+
exports.getInsideElseIfCommentText = getInsideElseIfCommentText;
|
|
9
|
+
exports.gatherElseIfCommentText = gatherElseIfCommentText;
|
|
10
|
+
const branch_annotation_helpers_1 = require("./branch-annotation-helpers");
|
|
11
|
+
/**
|
|
12
|
+
* Small shared helpers for IfStatement/else-if specific annotation handling.
|
|
13
|
+
* Extracted from branch-annotation-helpers to keep that file within ESLint
|
|
14
|
+
* max-lines limits while preserving behaviour.
|
|
15
|
+
*
|
|
16
|
+
* @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
|
|
17
|
+
* @story docs/stories/026.0-DEV-ELSE-IF-ANNOTATION-POSITION.story.md
|
|
18
|
+
* @story docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md
|
|
19
|
+
*/
|
|
20
|
+
const PRE_COMMENT_OFFSET = 2; // kept in sync with main helpers
|
|
21
|
+
function getCommentTextAtLine(lines, index) {
|
|
22
|
+
const line = lines[index];
|
|
23
|
+
if (!line || !line.trim()) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (!/^\s*(\/\/|\/\*)/.test(line)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return line.trim();
|
|
30
|
+
}
|
|
31
|
+
function isElseIfBranch(node, parent) {
|
|
32
|
+
return (node &&
|
|
33
|
+
node.type === "IfStatement" &&
|
|
34
|
+
parent &&
|
|
35
|
+
parent.type === "IfStatement" &&
|
|
36
|
+
parent.alternate === node);
|
|
37
|
+
}
|
|
38
|
+
function hasValidElseIfBlockLoc(node) {
|
|
39
|
+
const hasBlockConsequent = node.consequent &&
|
|
40
|
+
node.consequent.type === "BlockStatement" &&
|
|
41
|
+
node.consequent.loc &&
|
|
42
|
+
node.consequent.loc.start;
|
|
43
|
+
return !!(node.test &&
|
|
44
|
+
node.test.loc &&
|
|
45
|
+
node.test.loc.end &&
|
|
46
|
+
hasBlockConsequent);
|
|
47
|
+
}
|
|
48
|
+
function scanElseIfPrecedingComments(sourceCode, node) {
|
|
49
|
+
const lines = sourceCode.lines;
|
|
50
|
+
if (!node.loc || !node.loc.start || typeof node.loc.start.line !== "number") {
|
|
51
|
+
return "";
|
|
52
|
+
}
|
|
53
|
+
const startLine = node.loc.start.line - 1;
|
|
54
|
+
const comments = [];
|
|
55
|
+
let i = startLine - 1;
|
|
56
|
+
let scanned = 0;
|
|
57
|
+
while (i >= 0 && scanned < PRE_COMMENT_OFFSET) {
|
|
58
|
+
const commentText = getCommentTextAtLine(lines, i);
|
|
59
|
+
if (!commentText) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
comments.unshift(commentText);
|
|
63
|
+
i--;
|
|
64
|
+
scanned++;
|
|
65
|
+
}
|
|
66
|
+
return comments.join(" ");
|
|
67
|
+
}
|
|
68
|
+
function scanElseIfBetweenConditionAndBody(sourceCode, node) {
|
|
69
|
+
const lines = sourceCode.lines;
|
|
70
|
+
const conditionEndLine = node.test.loc.end.line;
|
|
71
|
+
const consequentStartLine = node.consequent.loc.start.line;
|
|
72
|
+
const startIndex = conditionEndLine;
|
|
73
|
+
const endIndexExclusive = consequentStartLine - 1;
|
|
74
|
+
if (endIndexExclusive <= startIndex) {
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
77
|
+
return (0, branch_annotation_helpers_1.scanCommentLinesInRange)(lines, startIndex, endIndexExclusive - 1);
|
|
78
|
+
}
|
|
79
|
+
function scanElseIfInsideBlockComments(sourceCode, node) {
|
|
80
|
+
const lines = sourceCode.lines;
|
|
81
|
+
const consequentStartLine = node.consequent.loc.start.line;
|
|
82
|
+
const comments = [];
|
|
83
|
+
let lineIndex = consequentStartLine;
|
|
84
|
+
while (lineIndex < lines.length) {
|
|
85
|
+
const lineText = getCommentTextAtLine(lines, lineIndex);
|
|
86
|
+
if (!lineText) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
comments.push(lineText);
|
|
90
|
+
lineIndex++;
|
|
91
|
+
}
|
|
92
|
+
return comments.join(" ");
|
|
93
|
+
}
|
|
94
|
+
function getInsideElseIfCommentText(sourceCode, node) {
|
|
95
|
+
if (!hasValidElseIfBlockLoc(node)) {
|
|
96
|
+
return "";
|
|
97
|
+
}
|
|
98
|
+
const insideText = scanElseIfInsideBlockComments(sourceCode, node);
|
|
99
|
+
if (insideText) {
|
|
100
|
+
return insideText;
|
|
101
|
+
}
|
|
102
|
+
return "";
|
|
103
|
+
}
|
|
104
|
+
function gatherElseIfCommentText(sourceCode, node, parent, options) {
|
|
105
|
+
const { annotationPlacement, beforeText } = options;
|
|
106
|
+
if (!isElseIfBranch(node, parent)) {
|
|
107
|
+
return beforeText;
|
|
108
|
+
}
|
|
109
|
+
if (annotationPlacement === "inside") {
|
|
110
|
+
return getInsideElseIfCommentText(sourceCode, node);
|
|
111
|
+
}
|
|
112
|
+
if (beforeText &&
|
|
113
|
+
(/@story\b/.test(beforeText) ||
|
|
114
|
+
/@req\b/.test(beforeText) ||
|
|
115
|
+
/@supports\b/.test(beforeText))) {
|
|
116
|
+
return beforeText;
|
|
117
|
+
}
|
|
118
|
+
const beforeElseText = scanElseIfPrecedingComments(sourceCode, node);
|
|
119
|
+
if (beforeElseText &&
|
|
120
|
+
(/@story\b/.test(beforeElseText) ||
|
|
121
|
+
/@req\b/.test(beforeElseText) ||
|
|
122
|
+
/@supports\b/.test(beforeElseText))) {
|
|
123
|
+
return beforeElseText;
|
|
124
|
+
}
|
|
125
|
+
if (!hasValidElseIfBlockLoc(node)) {
|
|
126
|
+
return beforeText;
|
|
127
|
+
}
|
|
128
|
+
const betweenText = scanElseIfBetweenConditionAndBody(sourceCode, node);
|
|
129
|
+
if (betweenText) {
|
|
130
|
+
return betweenText;
|
|
131
|
+
}
|
|
132
|
+
const insideText = scanElseIfInsideBlockComments(sourceCode, node);
|
|
133
|
+
if (insideText) {
|
|
134
|
+
return insideText;
|
|
135
|
+
}
|
|
136
|
+
return beforeText;
|
|
137
|
+
}
|
|
@@ -83,7 +83,8 @@ function getIfStatementIndentAndInsertPos(sourceCode, node, options, context) {
|
|
|
83
83
|
}
|
|
84
84
|
const isElseIf = isElseIfBranchForInsert(node, parent);
|
|
85
85
|
const isSimpleIfInsidePlacement = annotationPlacement === "inside" && !isElseIf;
|
|
86
|
-
if (
|
|
86
|
+
if (annotationPlacement === "inside" &&
|
|
87
|
+
(isSimpleIfInsidePlacement || isElseIf)) {
|
|
87
88
|
const commentLine = node.consequent.loc.start.line + 1;
|
|
88
89
|
const commentLineInfo = getIndentAndInsertPosForLine(sourceCode, commentLine, indent);
|
|
89
90
|
indent = commentLineInfo.indent;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
import { type AnnotationPlacement } from "./branch-annotation-helpers";
|
|
3
|
+
/**
|
|
4
|
+
* Gather annotation text for SwitchCase branches, honoring the configured placement
|
|
5
|
+
* while preserving legacy before-branch behavior in the default mode.
|
|
6
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
7
|
+
* @story docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md
|
|
8
|
+
* @supports REQ-PLACEMENT-CONFIG
|
|
9
|
+
* @supports REQ-INSIDE-BRACE-PLACEMENT
|
|
10
|
+
*/
|
|
11
|
+
export declare function gatherSwitchCaseCommentText(sourceCode: ReturnType<Rule.RuleContext["getSourceCode"]>, node: any, annotationPlacement: AnnotationPlacement, beforeText: string): string;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gatherSwitchCaseCommentText = gatherSwitchCaseCommentText;
|
|
4
|
+
const branch_annotation_helpers_1 = require("./branch-annotation-helpers");
|
|
5
|
+
/**
|
|
6
|
+
* Gather comment text from the first contiguous comment lines "inside" a SwitchCase body.
|
|
7
|
+
* Prefers a BlockStatement consequent when present, with a fallback to the entire case range.
|
|
8
|
+
* @story docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md
|
|
9
|
+
* @supports REQ-INSIDE-BRACE-PLACEMENT
|
|
10
|
+
* @supports REQ-PLACEMENT-CONFIG
|
|
11
|
+
*/
|
|
12
|
+
function getInsideSwitchCaseCommentText(sourceCode, node) {
|
|
13
|
+
const lines = sourceCode.lines;
|
|
14
|
+
const firstConsequent = node.consequent && node.consequent[0];
|
|
15
|
+
if (firstConsequent &&
|
|
16
|
+
firstConsequent.type === "BlockStatement" &&
|
|
17
|
+
firstConsequent.loc &&
|
|
18
|
+
firstConsequent.loc.start &&
|
|
19
|
+
firstConsequent.loc.end &&
|
|
20
|
+
typeof firstConsequent.loc.start.line === "number" &&
|
|
21
|
+
typeof firstConsequent.loc.end.line === "number") {
|
|
22
|
+
const startIndex = firstConsequent.loc.start.line - 1;
|
|
23
|
+
const endIndex = firstConsequent.loc.end.line - 1;
|
|
24
|
+
const insideText = (0, branch_annotation_helpers_1.scanCommentLinesInRange)(lines, startIndex + 1, endIndex);
|
|
25
|
+
if (insideText) {
|
|
26
|
+
return insideText;
|
|
27
|
+
}
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
if (node.loc &&
|
|
31
|
+
node.loc.start &&
|
|
32
|
+
node.loc.end &&
|
|
33
|
+
typeof node.loc.start.line === "number" &&
|
|
34
|
+
typeof node.loc.end.line === "number") {
|
|
35
|
+
const startIndex = node.loc.start.line - 1;
|
|
36
|
+
const endIndex = node.loc.end.line - 1;
|
|
37
|
+
const insideText = (0, branch_annotation_helpers_1.scanCommentLinesInRange)(lines, startIndex + 1, endIndex);
|
|
38
|
+
if (insideText) {
|
|
39
|
+
return insideText;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Gather annotation text for SwitchCase branches, honoring the configured placement
|
|
46
|
+
* while preserving legacy before-branch behavior in the default mode.
|
|
47
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
48
|
+
* @story docs/stories/028.0-DEV-ANNOTATION-PLACEMENT-STANDARDIZATION.story.md
|
|
49
|
+
* @supports REQ-PLACEMENT-CONFIG
|
|
50
|
+
* @supports REQ-INSIDE-BRACE-PLACEMENT
|
|
51
|
+
*/
|
|
52
|
+
function gatherSwitchCaseCommentText(sourceCode, node, annotationPlacement, beforeText) {
|
|
53
|
+
if (annotationPlacement === "inside") {
|
|
54
|
+
const insideText = getInsideSwitchCaseCommentText(sourceCode, node);
|
|
55
|
+
if (insideText) {
|
|
56
|
+
return insideText;
|
|
57
|
+
}
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
if (/@story\b/.test(beforeText) ||
|
|
61
|
+
/@req\b/.test(beforeText) ||
|
|
62
|
+
/@supports\b/.test(beforeText)) {
|
|
63
|
+
return beforeText;
|
|
64
|
+
}
|
|
65
|
+
// In before-placement mode, rely on the caller's beforeText and any
|
|
66
|
+
// configured PRE_COMMENT_OFFSET logic in the main helpers module.
|
|
67
|
+
return beforeText;
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|