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 +8 -8
- package/lib/src/index.d.ts +4 -4
- package/lib/src/rules/require-branch-annotation.d.ts +4 -2
- package/lib/src/rules/require-branch-annotation.js +36 -95
- package/lib/src/rules/require-req-annotation.d.ts +0 -7
- package/lib/src/rules/require-req-annotation.js +6 -37
- package/lib/src/rules/require-story-annotation.d.ts +3 -12
- package/lib/src/rules/require-story-annotation.js +153 -170
- package/lib/src/utils/annotation-checker.d.ts +6 -0
- package/lib/src/utils/annotation-checker.js +26 -0
- package/lib/src/utils/branch-annotation-helpers.d.ts +46 -0
- package/lib/src/utils/branch-annotation-helpers.js +145 -0
- package/lib/tests/integration/cli-integration.test.js +3 -5
- package/lib/tests/maintenance/index.test.d.ts +1 -0
- package/lib/tests/maintenance/index.test.js +25 -0
- package/lib/tests/rules/error-reporting.test.d.ts +1 -0
- package/lib/tests/rules/error-reporting.test.js +47 -0
- package/lib/tests/rules/require-branch-annotation.test.js +38 -0
- package/lib/tests/rules/require-story-annotation.test.js +101 -25
- package/lib/tests/utils/annotation-checker.test.d.ts +1 -0
- package/lib/tests/utils/annotation-checker.test.js +80 -0
- package/lib/tests/utils/branch-annotation-helpers.test.d.ts +1 -0
- package/lib/tests/utils/branch-annotation-helpers.test.js +46 -0
- package/package.json +2 -2
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
|
-
|
|
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
|
-
|
|
137
|
+
To run only the CLI integration tests:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
|
-
|
|
141
|
-
node ./cli-integration.js
|
|
140
|
+
npm test -- tests/integration/cli-integration.test.ts
|
|
142
141
|
```
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
Or run the full test suite:
|
|
145
144
|
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
```bash
|
|
146
|
+
npm test
|
|
147
|
+
```
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
These tests verify end-to-end behavior of the plugin via the ESLint CLI.
|
|
150
150
|
|
|
151
151
|
## Documentation Links
|
|
152
152
|
|
package/lib/src/index.d.ts
CHANGED
|
@@ -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":
|
|
7
|
+
"require-story-annotation": import("eslint").Rule.RuleModule;
|
|
8
8
|
"require-req-annotation": any;
|
|
9
|
-
"require-branch-annotation":
|
|
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":
|
|
44
|
+
"require-story-annotation": import("eslint").Rule.RuleModule;
|
|
45
45
|
"require-req-annotation": any;
|
|
46
|
-
"require-branch-annotation":
|
|
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
|
-
|
|
7
|
-
|
|
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
|
-
|
|
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
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
3
|
-
|
|
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;
|