eslint-plugin-traceability 1.2.0 → 1.4.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/README.md CHANGED
@@ -132,21 +132,21 @@ Coverage reports will be generated in the `coverage/` directory.
132
132
 
133
133
  ## CLI Integration
134
134
 
135
- The `cli-integration.js` script runs end-to-end CLI integration tests for the plugin, verifying behavior when used via the ESLint CLI. Note: this script lives at the project root.
135
+ Integration tests for the ESLint CLI plugin are included in the Jest test suite under `tests/integration/cli-integration.test.ts`.
136
136
 
137
- Usage:
137
+ To run only the CLI integration tests:
138
138
 
139
139
  ```bash
140
- # Run the CLI integration tests
141
- node ./cli-integration.js
140
+ npm test -- tests/integration/cli-integration.test.ts
142
141
  ```
143
142
 
144
- This script executes tests that:
143
+ Or run the full test suite:
145
144
 
146
- - Report an error when the `@story` annotation is missing.
147
- - Do not report an error when the `@story` annotation is present.
145
+ ```bash
146
+ npm test
147
+ ```
148
148
 
149
- The CLI integration tests are also executed automatically in CI under the `integration-tests` job.
149
+ These tests verify end-to-end behavior of the plugin via the ESLint CLI.
150
150
 
151
151
  ## Documentation Links
152
152
 
@@ -4,9 +4,9 @@
4
4
  * @req REQ-PLUGIN-STRUCTURE - Provide foundational plugin export and registration
5
5
  */
6
6
  export declare const rules: {
7
- "require-story-annotation": any;
7
+ "require-story-annotation": import("eslint").Rule.RuleModule;
8
8
  "require-req-annotation": any;
9
- "require-branch-annotation": any;
9
+ "require-branch-annotation": import("eslint").Rule.RuleModule;
10
10
  "valid-annotation-format": any;
11
11
  "valid-story-reference": import("eslint").Rule.RuleModule;
12
12
  "valid-req-reference": import("eslint").Rule.RuleModule;
@@ -41,9 +41,9 @@ export declare const configs: {
41
41
  };
42
42
  declare const _default: {
43
43
  rules: {
44
- "require-story-annotation": any;
44
+ "require-story-annotation": import("eslint").Rule.RuleModule;
45
45
  "require-req-annotation": any;
46
- "require-branch-annotation": any;
46
+ "require-branch-annotation": import("eslint").Rule.RuleModule;
47
47
  "valid-annotation-format": any;
48
48
  "valid-story-reference": import("eslint").Rule.RuleModule;
49
49
  "valid-req-reference": import("eslint").Rule.RuleModule;
@@ -2,6 +2,8 @@
2
2
  * Rule to enforce @story and @req annotations on significant code branches
3
3
  * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
4
4
  * @req REQ-BRANCH-DETECTION - Detect significant code branches for traceability annotations
5
+ * @req REQ-CONFIGURABLE-SCOPE - Allow configuration of branch types for annotation enforcement
5
6
  */
6
- declare const _default: any;
7
- export default _default;
7
+ import type { Rule } from "eslint";
8
+ declare const rule: Rule.RuleModule;
9
+ export default rule;
@@ -1,84 +1,7 @@
1
1
  "use strict";
2
- /****
3
- * Rule to enforce @story and @req annotations on significant code branches
4
- * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
5
- * @req REQ-BRANCH-DETECTION - Detect significant code branches for traceability annotations
6
- */
7
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
- /**
9
- * Gather leading comments for a node, with fallback for SwitchCase.
10
- * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
11
- * @req REQ-BRANCH-DETECTION - Gather comments including fallback scanning
12
- */
13
- function gatherCommentText(sourceCode, node) {
14
- if (node.type === "SwitchCase") {
15
- const lines = sourceCode.lines;
16
- const startLine = node.loc.start.line;
17
- let i = startLine - 1;
18
- const fallbackComments = [];
19
- while (i > 0) {
20
- const lineText = lines[i - 1];
21
- if (/^\s*(\/\/|\/\*)/.test(lineText)) {
22
- fallbackComments.unshift(lineText.trim());
23
- i--;
24
- }
25
- else if (/^\s*$/.test(lineText)) {
26
- break;
27
- }
28
- else {
29
- break;
30
- }
31
- }
32
- return fallbackComments.join(" ");
33
- }
34
- const comments = sourceCode.getCommentsBefore(node) || [];
35
- return comments.map((c) => c.value).join(" ");
36
- }
37
- /**
38
- * Helper to check a branch AST node for traceability annotations.
39
- * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
40
- * @req REQ-BRANCH-DETECTION - Helper for branch annotation detection
41
- */
42
- function checkBranchNode(sourceCode, context, node) {
43
- const text = gatherCommentText(sourceCode, node);
44
- const missingStory = !/@story\b/.test(text);
45
- const missingReq = !/@req\b/.test(text);
46
- if (missingStory) {
47
- const reportObj = {
48
- node,
49
- messageId: "missingAnnotation",
50
- data: { missing: "@story" },
51
- };
52
- if (node.type !== "CatchClause") {
53
- if (node.type === "SwitchCase") {
54
- const indent = " ".repeat(node.loc.start.column);
55
- reportObj.fix = (fixer) => fixer.insertTextBefore(node, `// @story <story-file>.story.md\n${indent}`);
56
- }
57
- else {
58
- reportObj.fix = (fixer) => fixer.insertTextBefore(node, `// @story <story-file>.story.md\n`);
59
- }
60
- }
61
- context.report(reportObj);
62
- }
63
- if (missingReq) {
64
- const reportObj = {
65
- node,
66
- messageId: "missingAnnotation",
67
- data: { missing: "@req" },
68
- };
69
- if (!missingStory && node.type !== "CatchClause") {
70
- if (node.type === "SwitchCase") {
71
- const indent = " ".repeat(node.loc.start.column);
72
- reportObj.fix = (fixer) => fixer.insertTextBefore(node, `// @req <REQ-ID>\n${indent}`);
73
- }
74
- else {
75
- reportObj.fix = (fixer) => fixer.insertTextBefore(node, `// @req <REQ-ID>\n`);
76
- }
77
- }
78
- context.report(reportObj);
79
- }
80
- }
81
- exports.default = {
3
+ const branch_annotation_helpers_1 = require("../utils/branch-annotation-helpers");
4
+ const rule = {
82
5
  meta: {
83
6
  type: "problem",
84
7
  docs: {
@@ -89,25 +12,43 @@ exports.default = {
89
12
  messages: {
90
13
  missingAnnotation: "Missing {{missing}} annotation on code branch",
91
14
  },
92
- schema: [],
15
+ schema: [
16
+ {
17
+ type: "object",
18
+ properties: {
19
+ branchTypes: {
20
+ type: "array",
21
+ items: { type: "string" },
22
+ uniqueItems: true,
23
+ },
24
+ },
25
+ additionalProperties: false,
26
+ },
27
+ ],
93
28
  },
29
+ /**
30
+ * Create visitor for require-branch-annotation rule.
31
+ * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
32
+ * @req REQ-BRANCH-DETECTION - Detect significant code branches for traceability annotations
33
+ * @req REQ-CONFIGURABLE-SCOPE - Allow configuration of branch types for annotation enforcement
34
+ */
94
35
  create(context) {
95
- const sourceCode = context.getSourceCode();
96
- return {
97
- IfStatement: (node) => checkBranchNode(sourceCode, context, node),
98
- SwitchCase: (node) => {
99
- if (node.test === null) {
36
+ const branchTypesOrListener = (0, branch_annotation_helpers_1.validateBranchTypes)(context);
37
+ if (!Array.isArray(branchTypesOrListener)) {
38
+ return branchTypesOrListener;
39
+ }
40
+ const branchTypes = branchTypesOrListener;
41
+ const storyFixCountRef = { count: 0 };
42
+ const handlers = {};
43
+ branchTypes.forEach((type) => {
44
+ handlers[type] = (node) => {
45
+ if (type === "SwitchCase" && node.test == null) {
100
46
  return;
101
47
  }
102
- return checkBranchNode(sourceCode, context, node);
103
- },
104
- TryStatement: (node) => checkBranchNode(sourceCode, context, node),
105
- CatchClause: (node) => checkBranchNode(sourceCode, context, node),
106
- ForStatement: (node) => checkBranchNode(sourceCode, context, node),
107
- ForOfStatement: (node) => checkBranchNode(sourceCode, context, node),
108
- ForInStatement: (node) => checkBranchNode(sourceCode, context, node),
109
- WhileStatement: (node) => checkBranchNode(sourceCode, context, node),
110
- DoWhileStatement: (node) => checkBranchNode(sourceCode, context, node),
111
- };
48
+ (0, branch_annotation_helpers_1.reportMissingAnnotations)(context, node, storyFixCountRef);
49
+ };
50
+ });
51
+ return handlers;
112
52
  },
113
53
  };
54
+ exports.default = rule;
@@ -1,9 +1,2 @@
1
- /**
2
- * Rule to enforce @req annotation on functions
3
- * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
- * @req REQ-ANNOTATION-REQUIRED - Require @req annotation on functions
5
- * @req REQ-FUNCTION-DETECTION - Detect function declarations, expressions, arrow functions, and methods
6
- * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
7
- */
8
1
  declare const _default: any;
9
2
  export default _default;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
3
+ /****
4
4
  * Rule to enforce @req annotation on functions
5
5
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
6
6
  * @req REQ-ANNOTATION-REQUIRED - Require @req annotation on functions
7
7
  * @req REQ-FUNCTION-DETECTION - Detect function declarations, expressions, arrow functions, and methods
8
8
  * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
9
9
  */
10
+ const annotation_checker_1 = require("../utils/annotation-checker");
10
11
  exports.default = {
11
12
  meta: {
12
13
  type: "problem",
@@ -37,46 +38,14 @@ exports.default = {
37
38
  },
38
39
  /**
39
40
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
40
- * @req REQ-TYPESCRIPT-SUPPORT
41
+ * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
41
42
  */
42
- TSDeclareFunction(node) {
43
- const jsdoc = sourceCode.getJSDocComment(node);
44
- const leading = node.leadingComments || [];
45
- const comments = sourceCode.getCommentsBefore(node) || [];
46
- const all = [...leading, ...comments];
47
- const hasReq = (jsdoc && jsdoc.value.includes("@req")) ||
48
- all.some((c) => c.value.includes("@req"));
49
- if (!hasReq) {
50
- context.report({
51
- node,
52
- messageId: "missingReq",
53
- fix(fixer) {
54
- return fixer.insertTextBefore(node, "/** @req <REQ-ID> */\n");
55
- },
56
- });
57
- }
58
- },
43
+ TSDeclareFunction: (node) => (0, annotation_checker_1.checkReqAnnotation)(context, node),
59
44
  /**
60
45
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
61
- * @req REQ-TYPESCRIPT-SUPPORT
46
+ * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
62
47
  */
63
- TSMethodSignature(node) {
64
- const jsdoc = sourceCode.getJSDocComment(node);
65
- const leading = node.leadingComments || [];
66
- const comments = sourceCode.getCommentsBefore(node) || [];
67
- const all = [...leading, ...comments];
68
- const hasReq = (jsdoc && jsdoc.value.includes("@req")) ||
69
- all.some((c) => c.value.includes("@req"));
70
- if (!hasReq) {
71
- context.report({
72
- node,
73
- messageId: "missingReq",
74
- fix(fixer) {
75
- return fixer.insertTextBefore(node, "/** @req <REQ-ID> */\n");
76
- },
77
- });
78
- }
79
- },
48
+ TSMethodSignature: (node) => (0, annotation_checker_1.checkReqAnnotation)(context, node),
80
49
  };
81
50
  },
82
51
  };
@@ -1,12 +1,3 @@
1
- /**
2
- * Rule to enforce @story annotation on functions, function expressions, arrow functions, and methods
3
- * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
- * @req REQ-ANNOTATION-REQUIRED - Require @story annotation on functions
5
- * @req REQ-OPTIONS-SCOPE - Support configuring which function types to enforce via options
6
- * @req REQ-EXPORT-PRIORITY - Add exportPriority option to target exported or non-exported
7
- * @req REQ-UNIFIED-CHECK - Implement unified checkNode for all supported node types
8
- * @req REQ-FUNCTION-DETECTION - Detect function declarations, expressions, arrow functions, and methods
9
- * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
10
- */
11
- declare const _default: any;
12
- export default _default;
1
+ import type { Rule } from "eslint";
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;