eslint-plugin-traceability 1.6.5 → 1.7.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.
Files changed (38) hide show
  1. package/README.md +38 -1
  2. package/lib/src/index.d.ts +28 -25
  3. package/lib/src/index.js +49 -31
  4. package/lib/src/maintenance/cli.d.ts +12 -0
  5. package/lib/src/maintenance/cli.js +279 -0
  6. package/lib/src/maintenance/detect.js +27 -12
  7. package/lib/src/maintenance/update.js +42 -34
  8. package/lib/src/maintenance/utils.js +30 -30
  9. package/lib/src/rules/helpers/require-story-io.js +51 -15
  10. package/lib/src/rules/helpers/valid-annotation-options.d.ts +118 -0
  11. package/lib/src/rules/helpers/valid-annotation-options.js +167 -0
  12. package/lib/src/rules/helpers/valid-annotation-utils.d.ts +68 -0
  13. package/lib/src/rules/helpers/valid-annotation-utils.js +103 -0
  14. package/lib/src/rules/helpers/valid-story-reference-helpers.d.ts +67 -0
  15. package/lib/src/rules/helpers/valid-story-reference-helpers.js +92 -0
  16. package/lib/src/rules/valid-annotation-format.js +168 -180
  17. package/lib/src/rules/valid-req-reference.js +139 -29
  18. package/lib/src/rules/valid-story-reference.d.ts +7 -0
  19. package/lib/src/rules/valid-story-reference.js +38 -80
  20. package/lib/src/utils/annotation-checker.js +2 -145
  21. package/lib/src/utils/branch-annotation-helpers.js +12 -3
  22. package/lib/src/utils/reqAnnotationDetection.d.ts +6 -0
  23. package/lib/src/utils/reqAnnotationDetection.js +152 -0
  24. package/lib/tests/maintenance/cli.test.d.ts +1 -0
  25. package/lib/tests/maintenance/cli.test.js +172 -0
  26. package/lib/tests/rules/require-branch-annotation.test.js +3 -2
  27. package/lib/tests/rules/require-req-annotation.test.js +57 -68
  28. package/lib/tests/rules/require-story-annotation.test.js +13 -28
  29. package/lib/tests/rules/require-story-core-edgecases.test.js +3 -58
  30. package/lib/tests/rules/require-story-core.autofix.test.js +5 -41
  31. package/lib/tests/rules/valid-annotation-format.test.js +328 -51
  32. package/lib/tests/utils/annotation-checker.test.d.ts +23 -0
  33. package/lib/tests/utils/annotation-checker.test.js +24 -17
  34. package/lib/tests/utils/require-story-core-test-helpers.d.ts +10 -0
  35. package/lib/tests/utils/require-story-core-test-helpers.js +75 -0
  36. package/lib/tests/utils/ts-language-options.d.ts +22 -0
  37. package/lib/tests/utils/ts-language-options.js +27 -0
  38. package/package.json +12 -3
@@ -1,13 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAnnotationCheckerTests = runAnnotationCheckerTests;
3
4
  /**
4
5
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
6
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
6
7
  * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
8
+ * @req REQ-TEST-UTILS-TS-LANG - Shared TS RuleTester language options helper
7
9
  */
8
10
  const eslint_1 = require("eslint");
9
11
  const annotation_checker_1 = require("../../src/utils/annotation-checker");
12
+ const ts_language_options_1 = require("./ts-language-options");
10
13
  const ruleTester = new eslint_1.RuleTester();
14
+ const withTsAnnotationCheckerOptions = (test) => ({
15
+ ...test,
16
+ languageOptions: ts_language_options_1.tsRuleTesterLanguageOptions,
17
+ });
18
+ /**
19
+ * Shared helper for running tests that exercise the annotation-checker logic
20
+ * for TypeScript constructs.
21
+ *
22
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
23
+ * @req REQ-TYPESCRIPT-SUPPORT - Support TypeScript-specific function syntax
24
+ * @req REQ-TEST-UTILS-TS-LANG - Shared TS RuleTester language options helper
25
+ */
26
+ function runAnnotationCheckerTests(ruleName, config) {
27
+ const { rule, valid, invalid } = config;
28
+ ruleTester.run(ruleName, rule, {
29
+ valid: valid.map(withTsAnnotationCheckerOptions),
30
+ invalid: invalid.map(withTsAnnotationCheckerOptions),
31
+ });
32
+ }
11
33
  const rule = {
12
34
  meta: {
13
35
  type: "problem",
@@ -35,23 +57,16 @@ const rule = {
35
57
  },
36
58
  };
37
59
  describe("annotation-checker helper", () => {
38
- ruleTester.run("annotation-checker", rule, {
60
+ runAnnotationCheckerTests("annotation-checker", {
61
+ rule,
39
62
  valid: [
40
63
  {
41
64
  name: "[REQ-TYPESCRIPT-SUPPORT] valid TSDeclareFunction with @req",
42
65
  code: `/** @req REQ-TEST */\ndeclare function foo(): void;`,
43
- languageOptions: {
44
- parser: require("@typescript-eslint/parser"),
45
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
46
- },
47
66
  },
48
67
  {
49
68
  name: "[REQ-TYPESCRIPT-SUPPORT] valid TSMethodSignature with @req",
50
69
  code: `interface I { /** @req REQ-TEST */ method(): void; }`,
51
- languageOptions: {
52
- parser: require("@typescript-eslint/parser"),
53
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
54
- },
55
70
  },
56
71
  ],
57
72
  invalid: [
@@ -60,20 +75,12 @@ describe("annotation-checker helper", () => {
60
75
  code: `declare function foo(): void;`,
61
76
  output: `/** @req <REQ-ID> */\ndeclare function foo(): void;`,
62
77
  errors: [{ messageId: "missingReq" }],
63
- languageOptions: {
64
- parser: require("@typescript-eslint/parser"),
65
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
66
- },
67
78
  },
68
79
  {
69
80
  name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSMethodSignature",
70
81
  code: `interface I { method(): void; }`,
71
82
  output: `interface I { /** @req <REQ-ID> */\nmethod(): void; }`,
72
83
  errors: [{ messageId: "missingReq" }],
73
- languageOptions: {
74
- parser: require("@typescript-eslint/parser"),
75
- parserOptions: { ecmaVersion: 2022, sourceType: "module" },
76
- },
77
84
  },
78
85
  ],
79
86
  });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared test helpers for require-story-core branch coverage.
3
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
+ * @req REQ-AUTOFIX - Provide reusable helpers to exercise autofix branches
5
+ */
6
+ interface ExerciseOptions {
7
+ annotationText?: string;
8
+ }
9
+ export declare function exerciseCreateAddStoryFixBranches(createAddStoryFix: any, options?: ExerciseOptions): void;
10
+ export {};
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ /**
3
+ * Shared test helpers for require-story-core branch coverage.
4
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
5
+ * @req REQ-AUTOFIX - Provide reusable helpers to exercise autofix branches
6
+ */
7
+ /* global jest, expect */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.exerciseCreateAddStoryFixBranches = exerciseCreateAddStoryFixBranches;
10
+ const RANGE_ONE_START = 21;
11
+ const RANGE_ONE_END = 33;
12
+ const RANGE_TWO_START = 50;
13
+ const RANGE_TWO_END = 70;
14
+ const RANGE_PARENT_START = 5;
15
+ const RANGE_PARENT_END = 100;
16
+ const DEFAULT_ANNOTATION = "/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\n";
17
+ function baseFixer() {
18
+ return {
19
+ insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
20
+ };
21
+ }
22
+ function exerciseBranch1(createAddStoryFix, annotation) {
23
+ const fixer = baseFixer();
24
+ const fixFn = createAddStoryFix(null);
25
+ const res = fixFn(fixer);
26
+ expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
27
+ const args = fixer.insertTextBeforeRange.mock.calls[0];
28
+ expect(args[0]).toEqual([0, 0]);
29
+ expect(args[1]).toBe(annotation);
30
+ expect(res).toEqual({
31
+ r: [0, 0],
32
+ t: annotation,
33
+ });
34
+ }
35
+ function exerciseBranch2(createAddStoryFix, annotation) {
36
+ const target = {
37
+ type: "FunctionDeclaration",
38
+ range: [RANGE_ONE_START, RANGE_ONE_END],
39
+ parent: { type: "ClassBody" },
40
+ };
41
+ const fixer = baseFixer();
42
+ const fixFn = createAddStoryFix(target);
43
+ const res = fixFn(fixer);
44
+ expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([RANGE_ONE_START, RANGE_ONE_START]);
45
+ expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(annotation);
46
+ expect(res).toEqual({
47
+ r: [RANGE_ONE_START, RANGE_ONE_START],
48
+ t: annotation,
49
+ });
50
+ }
51
+ function exerciseBranch3(createAddStoryFix, annotation) {
52
+ const target = {
53
+ type: "FunctionDeclaration",
54
+ range: [RANGE_TWO_START, RANGE_TWO_END],
55
+ parent: {
56
+ type: "ExportDefaultDeclaration",
57
+ range: [RANGE_PARENT_START, RANGE_PARENT_END],
58
+ },
59
+ };
60
+ const fixer = baseFixer();
61
+ const fixFn = createAddStoryFix(target);
62
+ const res = fixFn(fixer);
63
+ expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([RANGE_PARENT_START, RANGE_PARENT_START]);
64
+ expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(annotation);
65
+ expect(res).toEqual({
66
+ r: [RANGE_PARENT_START, RANGE_PARENT_START],
67
+ t: annotation,
68
+ });
69
+ }
70
+ function exerciseCreateAddStoryFixBranches(createAddStoryFix, options = {}) {
71
+ const annotation = options.annotationText ?? DEFAULT_ANNOTATION;
72
+ exerciseBranch1(createAddStoryFix, annotation);
73
+ exerciseBranch2(createAddStoryFix, annotation);
74
+ exerciseBranch3(createAddStoryFix, annotation);
75
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared TypeScript RuleTester language options for traceability tests.
3
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
4
+ * @req REQ-TYPESCRIPT-SUPPORT - Provide reusable TypeScript parser setup for tests
5
+ */
6
+ export declare const tsRuleTesterLanguageOptions: {
7
+ readonly parser: any;
8
+ readonly parserOptions: {
9
+ readonly ecmaVersion: 2022;
10
+ readonly sourceType: "module";
11
+ };
12
+ };
13
+ /**
14
+ * Attach shared TypeScript RuleTester language options to a test case definition.
15
+ * This helper allows tests to avoid repeating the languageOptions assignment.
16
+ *
17
+ * @param testCase A RuleTester valid/invalid test case object
18
+ * @returns The same test case with TypeScript language options applied
19
+ */
20
+ export declare function withTsLanguageOptions<T extends Record<string, unknown>>(testCase: T): T & {
21
+ languageOptions: typeof tsRuleTesterLanguageOptions;
22
+ };
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tsRuleTesterLanguageOptions = void 0;
4
+ exports.withTsLanguageOptions = withTsLanguageOptions;
5
+ /**
6
+ * Shared TypeScript RuleTester language options for traceability tests.
7
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
8
+ * @req REQ-TYPESCRIPT-SUPPORT - Provide reusable TypeScript parser setup for tests
9
+ */
10
+ exports.tsRuleTesterLanguageOptions = {
11
+ parser: require("@typescript-eslint/parser"),
12
+ // eslint-disable-next-line no-magic-numbers -- ECMAScript version constant
13
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" },
14
+ };
15
+ /**
16
+ * Attach shared TypeScript RuleTester language options to a test case definition.
17
+ * This helper allows tests to avoid repeating the languageOptions assignment.
18
+ *
19
+ * @param testCase A RuleTester valid/invalid test case object
20
+ * @returns The same test case with TypeScript language options applied
21
+ */
22
+ function withTsLanguageOptions(testCase) {
23
+ return {
24
+ ...testCase,
25
+ languageOptions: exports.tsRuleTesterLanguageOptions,
26
+ };
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-traceability",
3
- "version": "1.6.5",
3
+ "version": "1.7.0",
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",
@@ -12,8 +12,12 @@
12
12
  "directories": {
13
13
  "doc": "docs"
14
14
  },
15
+ "bin": {
16
+ "traceability-maint": "lib/src/maintenance/cli.js"
17
+ },
15
18
  "scripts": {
16
19
  "build": "tsc -p tsconfig.json",
20
+ "prepare": "husky install",
17
21
  "type-check": "tsc --noEmit -p tsconfig.json",
18
22
  "check:traceability": "node scripts/traceability-check.js",
19
23
  "lint-plugin-check": "node scripts/lint-plugin-check.js",
@@ -26,10 +30,12 @@
26
30
  "ci-verify:fast": "npm run type-check && npm run check:traceability && npm run duplication && jest --ci --bail --passWithNoTests --testPathPatterns 'tests/(unit|fast)'",
27
31
  "format": "prettier --write .",
28
32
  "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
33
+ "lint-staged": "lint-staged",
29
34
  "duplication": "jscpd src tests --reporters console --threshold 3 --ignore tests/utils/**",
30
35
  "audit:dev-high": "node scripts/generate-dev-deps-audit.js",
31
36
  "safety:deps": "node scripts/ci-safety-deps.js",
32
37
  "audit:ci": "node scripts/ci-audit.js",
38
+ "security:secrets": "secretlint \"**/*\" --no-color",
33
39
  "smoke-test": "./scripts/smoke-test.sh"
34
40
  },
35
41
  "lint-staged": {
@@ -65,6 +71,7 @@
65
71
  "@typescript-eslint/parser": "^8.46.4",
66
72
  "@typescript-eslint/utils": "^8.46.4",
67
73
  "actionlint": "^2.0.6",
74
+ "dry-aged-deps": "^2.3.1",
68
75
  "eslint": "^9.39.1",
69
76
  "husky": "^9.1.7",
70
77
  "jest": "^30.2.0",
@@ -73,13 +80,15 @@
73
80
  "prettier": "^3.6.2",
74
81
  "semantic-release": "^21.1.2",
75
82
  "ts-jest": "^29.4.5",
76
- "typescript": "^5.9.3"
83
+ "typescript": "^5.9.3",
84
+ "secretlint": "11.2.5",
85
+ "@secretlint/secretlint-rule-preset-recommend": "11.2.5"
77
86
  },
78
87
  "peerDependencies": {
79
88
  "eslint": "^9.0.0"
80
89
  },
81
90
  "engines": {
82
- "node": ">=14"
91
+ "node": ">=18.18.0"
83
92
  },
84
93
  "overrides": {
85
94
  "glob": "12.0.0",