eslint-plugin-traceability 1.4.1 → 1.4.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.
@@ -50,15 +50,36 @@ function updateAnnotationReferences(codebasePath, oldPath, newPath) {
50
50
  const escapedOldPath = oldPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
51
51
  const regex = new RegExp(`(@story\\s*)${escapedOldPath}`, "g");
52
52
  const files = (0, utils_1.getAllFiles)(codebasePath);
53
+ /**
54
+ * Iterate over all files and replace annotation references
55
+ * @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
56
+ * @req REQ-MAINT-UPDATE
57
+ */
53
58
  for (const fullPath of files) {
54
59
  const stat = fs.statSync(fullPath);
60
+ /**
61
+ * Skip non-files in iteration
62
+ * @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
63
+ * @req REQ-MAINT-UPDATE
64
+ */
55
65
  if (!stat.isFile())
56
66
  continue;
57
67
  const content = fs.readFileSync(fullPath, "utf8");
58
- const newContent = content.replace(regex, (match, p1) => {
68
+ const newContent = content.replace(regex,
69
+ /**
70
+ * Replacement callback to update annotation references
71
+ * @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
72
+ * @req REQ-MAINT-UPDATE
73
+ */
74
+ (match, p1) => {
59
75
  replacementCount++;
60
76
  return `${p1}${newPath}`;
61
77
  });
78
+ /**
79
+ * Write file only if content changed
80
+ * @story docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md
81
+ * @req REQ-MAINT-UPDATE
82
+ */
62
83
  if (newContent !== content) {
63
84
  fs.writeFileSync(fullPath, newContent, "utf8");
64
85
  }
@@ -242,6 +242,12 @@ const rule = {
242
242
  }
243
243
  reportMissing(context, sourceCode, node, target);
244
244
  },
245
+ /**
246
+ * Handle FunctionExpression nodes
247
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
248
+ * @req REQ-ANNOTATION-REQUIRED
249
+ * @param {any} node - FunctionExpression AST node
250
+ */
245
251
  FunctionExpression(node) {
246
252
  if (!shouldProcessNode(node, scope, exportPriority))
247
253
  return;
@@ -250,23 +256,47 @@ const rule = {
250
256
  const target = resolveTargetNode(sourceCode, node);
251
257
  reportMissing(context, sourceCode, node, target);
252
258
  },
259
+ /**
260
+ * Handle ArrowFunctionExpression nodes
261
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
262
+ * @req REQ-ANNOTATION-REQUIRED
263
+ * @param {any} node - ArrowFunctionExpression AST node
264
+ */
253
265
  ArrowFunctionExpression(node) {
254
266
  if (!shouldProcessNode(node, scope, exportPriority))
255
267
  return;
256
268
  const target = resolveTargetNode(sourceCode, node);
257
269
  reportMissing(context, sourceCode, node, target);
258
270
  },
271
+ /**
272
+ * Handle TSDeclareFunction nodes
273
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
274
+ * @req REQ-ANNOTATION-REQUIRED
275
+ * @param {any} node - TSDeclareFunction AST node
276
+ */
259
277
  TSDeclareFunction(node) {
260
278
  if (!shouldProcessNode(node, scope, exportPriority))
261
279
  return;
262
280
  reportMissing(context, sourceCode, node, node);
263
281
  },
282
+ /**
283
+ * Handle TSMethodSignature nodes
284
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
285
+ * @req REQ-ANNOTATION-REQUIRED
286
+ * @param {any} node - TSMethodSignature AST node
287
+ */
264
288
  TSMethodSignature(node) {
265
289
  if (!shouldProcessNode(node, scope, exportPriority))
266
290
  return;
267
291
  const target = resolveTargetNode(sourceCode, node);
268
292
  reportMissing(context, sourceCode, node, target);
269
293
  },
294
+ /**
295
+ * Handle MethodDefinition nodes
296
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
297
+ * @req REQ-ANNOTATION-REQUIRED
298
+ * @param {any} node - MethodDefinition AST node
299
+ */
270
300
  MethodDefinition(node) {
271
301
  if (!shouldProcessNode(node, scope, exportPriority))
272
302
  return;
@@ -32,10 +32,19 @@ exports.DEFAULT_BRANCH_TYPES = [
32
32
  function validateBranchTypes(context) {
33
33
  const options = context.options[0] || {};
34
34
  if (Array.isArray(options.branchTypes)) {
35
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
36
+ // @req REQ-TRACEABILITY-FILTER-CALLBACK - Trace filter callback for invalid branch type detection
35
37
  const invalidTypes = options.branchTypes.filter((t) => !exports.DEFAULT_BRANCH_TYPES.includes(t));
36
38
  if (invalidTypes.length > 0) {
39
+ /**
40
+ * Program listener produced when configuration is invalid.
41
+ * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
42
+ * @req REQ-TRACEABILITY-PROGRAM-LISTENER - Trace Program listener reporting invalid config values
43
+ */
37
44
  return {
38
45
  Program(node) {
46
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
47
+ // @req REQ-TRACEABILITY-FOR-EACH-CALLBACK - Trace reporting for each invalid type
39
48
  invalidTypes.forEach((t) => {
40
49
  context.report({
41
50
  node,
@@ -61,6 +70,8 @@ function gatherBranchCommentText(sourceCode, node) {
61
70
  const startLine = node.loc.start.line;
62
71
  let i = startLine - PRE_COMMENT_OFFSET;
63
72
  const comments = [];
73
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
74
+ // @req REQ-TRACEABILITY-WHILE - Trace while loop that collects preceding comments for SwitchCase
64
75
  while (i >= 0 && /^\s*(\/\/|\/\*)/.test(lines[i])) {
65
76
  comments.unshift(lines[i].trim());
66
77
  i--;
@@ -68,6 +79,8 @@ function gatherBranchCommentText(sourceCode, node) {
68
79
  return comments.join(" ");
69
80
  }
70
81
  const comments = sourceCode.getCommentsBefore(node) || [];
82
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
83
+ // @req REQ-TRACEABILITY-MAP-CALLBACK - Trace mapping of comment nodes to their text values
71
84
  return comments.map((c) => c.value).join(" ");
72
85
  }
73
86
  /**
@@ -82,7 +95,10 @@ function reportMissingStory(context, node, options) {
82
95
  node,
83
96
  messageId: "missingAnnotation",
84
97
  data: { missing: "@story" },
85
- fix: (fixer) => fixer.insertTextBeforeRange([insertPos, insertPos], `${indent}// @story <story-file>.story.md\n`),
98
+ fix:
99
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
100
+ // @req REQ-TRACEABILITY-FIX-ARROW - Trace fixer arrow function used to insert missing @story
101
+ (fixer) => fixer.insertTextBeforeRange([insertPos, insertPos], `${indent}// @story <story-file>.story.md\n`),
86
102
  });
87
103
  storyFixCountRef.count++;
88
104
  }
@@ -106,7 +122,10 @@ function reportMissingReq(context, node, options) {
106
122
  node,
107
123
  messageId: "missingAnnotation",
108
124
  data: { missing: "@req" },
109
- fix: (fixer) => fixer.insertTextBeforeRange([insertPos, insertPos], `${indent}// @req <REQ-ID>\n`),
125
+ fix:
126
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
127
+ // @req REQ-TRACEABILITY-FIX-ARROW - Trace fixer arrow function used to insert missing @req
128
+ (fixer) => fixer.insertTextBeforeRange([insertPos, insertPos], `${indent}// @req <REQ-ID>\n`),
110
129
  });
111
130
  }
112
131
  else {
@@ -144,5 +163,10 @@ function reportMissingAnnotations(context, node, storyFixCountRef) {
144
163
  args: [context, node, { indent, insertPos, missingStory }],
145
164
  },
146
165
  ];
147
- actions.forEach(({ missing, fn, args }) => missing && fn(...args));
166
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
167
+ // @req REQ-TRACEABILITY-ACTIONS-FOREACH - Trace processing of actions array to report missing annotations
168
+ actions.forEach(({ missing, fn, args }) =>
169
+ // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
170
+ // @req REQ-TRACEABILITY-FOR-EACH-CALLBACK - Trace callback handling for each action item
171
+ missing && fn(...args));
148
172
  }
@@ -87,11 +87,24 @@ describe("detectStaleAnnotations isolated (Story 009.0-DEV-MAINTENANCE-TOOLS)",
87
87
  `;
88
88
  fs.writeFileSync(filePath, content, "utf8");
89
89
  // Remove read permission
90
- fs.chmodSync(dir, 0o000);
91
- expect(() => (0, detect_1.detectStaleAnnotations)(tmpDir2)).toThrow();
92
- // Restore permissions
93
- fs.chmodSync(dir, 0o700);
94
- // Cleanup temporary directory
95
- fs.rmSync(tmpDir2, { recursive: true, force: true });
90
+ try {
91
+ fs.chmodSync(dir, 0o000);
92
+ expect(() => (0, detect_1.detectStaleAnnotations)(tmpDir2)).toThrow();
93
+ }
94
+ finally {
95
+ // Restore permissions and cleanup temporary directory, ignoring errors during cleanup
96
+ try {
97
+ fs.chmodSync(dir, 0o700);
98
+ }
99
+ catch {
100
+ // ignore
101
+ }
102
+ try {
103
+ fs.rmSync(tmpDir2, { recursive: true, force: true });
104
+ }
105
+ catch {
106
+ // ignore
107
+ }
108
+ }
96
109
  });
97
110
  });
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- // @ts-nocheck
7
6
  /**
8
7
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
9
8
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-traceability",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "A customizable ESLint plugin that enforces traceability annotations in your code, ensuring each implementation is linked to its requirement or test case.",
5
5
  "main": "lib/src/index.js",
6
6
  "types": "lib/src/index.d.ts",