eslint-plugin-traceability 1.4.4 → 1.4.6
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/lib/src/rules/helpers/require-story-io.js +12 -2
- package/lib/src/rules/valid-req-reference.js +9 -0
- package/lib/src/rules/valid-story-reference.js +4 -0
- package/lib/tests/rules/require-story-core.branches.test.d.ts +1 -0
- package/lib/tests/rules/require-story-core.branches.test.js +69 -0
- package/lib/tests/rules/require-story-core.test.d.ts +1 -0
- package/lib/tests/rules/require-story-core.test.js +58 -0
- package/lib/tests/rules/require-story-helpers.branches.test.d.ts +6 -0
- package/lib/tests/rules/require-story-helpers.branches.test.js +79 -0
- package/lib/tests/rules/require-story-io.branches.test.d.ts +6 -0
- package/lib/tests/rules/require-story-io.branches.test.js +50 -0
- package/lib/tests/rules/require-story-visitors.branches.test.d.ts +6 -0
- package/lib/tests/rules/require-story-visitors.branches.test.js +26 -0
- package/package.json +5 -1
|
@@ -56,12 +56,22 @@ function parentChainHasStory(sourceCode, node) {
|
|
|
56
56
|
? sourceCode.getCommentsBefore(p) || []
|
|
57
57
|
: [];
|
|
58
58
|
if (Array.isArray(pComments) &&
|
|
59
|
-
pComments.some(
|
|
59
|
+
pComments.some(
|
|
60
|
+
/**
|
|
61
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
62
|
+
* @req REQ-ANNOTATION-REQUIRED - Detect @story in parent comments via value inspection
|
|
63
|
+
*/
|
|
64
|
+
(c) => typeof c.value === "string" && c.value.includes("@story"))) {
|
|
60
65
|
return true;
|
|
61
66
|
}
|
|
62
67
|
const pLeading = p.leadingComments || [];
|
|
63
68
|
if (Array.isArray(pLeading) &&
|
|
64
|
-
pLeading.some(
|
|
69
|
+
pLeading.some(
|
|
70
|
+
/**
|
|
71
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
72
|
+
* @req REQ-ANNOTATION-REQUIRED - Detect @story in parent leadingComments via value inspection
|
|
73
|
+
*/
|
|
74
|
+
(c) => typeof c.value === "string" && c.value.includes("@story"))) {
|
|
65
75
|
return true;
|
|
66
76
|
}
|
|
67
77
|
p = p.parent;
|
|
@@ -162,6 +162,15 @@ function programListener(context) {
|
|
|
162
162
|
let rawStoryPath = null;
|
|
163
163
|
return function Program() {
|
|
164
164
|
const comments = sourceCode.getAllComments() || [];
|
|
165
|
+
/**
|
|
166
|
+
* Process each comment to handle story and requirement annotations.
|
|
167
|
+
*
|
|
168
|
+
* @story docs/stories/010.0-DEV-DEEP-VALIDATION.story.md
|
|
169
|
+
* @req REQ-DEEP-PARSE - Parse annotations from comment blocks
|
|
170
|
+
* @req REQ-DEEP-MATCH - Validate @req references found in comments
|
|
171
|
+
* @req REQ-DEEP-CACHE - Use cache for parsed story files to avoid repeated IO
|
|
172
|
+
* @req REQ-DEEP-PATH - Enforce path validation when resolving story files
|
|
173
|
+
*/
|
|
165
174
|
comments.forEach((comment) => {
|
|
166
175
|
rawStoryPath = handleComment({
|
|
167
176
|
comment,
|
|
@@ -94,6 +94,10 @@ function handleComment(opts) {
|
|
|
94
94
|
const { commentNode, context, cwd, storyDirs, allowAbsolute, requireExt } = opts;
|
|
95
95
|
const lines = commentNode.value
|
|
96
96
|
.split(/\r?\n/)
|
|
97
|
+
/**
|
|
98
|
+
* @story docs/stories/006.0-DEV-FILE-VALIDATION.story.md
|
|
99
|
+
* @req REQ-ANNOTATION-VALIDATION - Ensure each annotation line is parsed
|
|
100
|
+
*/
|
|
97
101
|
.map((l) => l.replace(/^[^@]*/, "").trim());
|
|
98
102
|
for (const line of lines) {
|
|
99
103
|
if (line.startsWith("@story")) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Branch tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
5
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
6
|
+
* @req REQ-AUTOFIX - Cover additional branch cases in require-story-core (addStoryFixer/reportMissing)
|
|
7
|
+
*/
|
|
8
|
+
const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
|
|
9
|
+
const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
|
|
10
|
+
describe("Require Story Core branches (Story 003.0)", () => {
|
|
11
|
+
test("createAddStoryFix falls back to 0 when target is falsy", () => {
|
|
12
|
+
const fixer = {
|
|
13
|
+
insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
|
|
14
|
+
};
|
|
15
|
+
const fixFn = (0, require_story_core_1.createAddStoryFix)(null);
|
|
16
|
+
const res = fixFn(fixer);
|
|
17
|
+
expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
|
|
18
|
+
const args = fixer.insertTextBeforeRange.mock.calls[0];
|
|
19
|
+
expect(args[0]).toEqual([0, 0]);
|
|
20
|
+
expect(args[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
|
|
21
|
+
expect(res).toEqual({ r: [0, 0], t: `${require_story_helpers_1.ANNOTATION}\n` });
|
|
22
|
+
});
|
|
23
|
+
test("createAddStoryFix uses target.range when parent not export and parent.range missing", () => {
|
|
24
|
+
const target = {
|
|
25
|
+
type: "FunctionDeclaration",
|
|
26
|
+
range: [21, 33],
|
|
27
|
+
parent: { type: "ClassBody" },
|
|
28
|
+
};
|
|
29
|
+
const fixer = {
|
|
30
|
+
insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
|
|
31
|
+
};
|
|
32
|
+
const fixFn = (0, require_story_core_1.createAddStoryFix)(target);
|
|
33
|
+
const res = fixFn(fixer);
|
|
34
|
+
expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([21, 21]);
|
|
35
|
+
expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
|
|
36
|
+
expect(res).toEqual({ r: [21, 21], t: `${require_story_helpers_1.ANNOTATION}\n` });
|
|
37
|
+
});
|
|
38
|
+
test("createAddStoryFix prefers ExportDefaultDeclaration parent.range when present", () => {
|
|
39
|
+
const target = {
|
|
40
|
+
type: "FunctionDeclaration",
|
|
41
|
+
range: [50, 70],
|
|
42
|
+
parent: { type: "ExportDefaultDeclaration", range: [5, 100] },
|
|
43
|
+
};
|
|
44
|
+
const fixer = {
|
|
45
|
+
insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
|
|
46
|
+
};
|
|
47
|
+
const fixFn = (0, require_story_core_1.createAddStoryFix)(target);
|
|
48
|
+
const res = fixFn(fixer);
|
|
49
|
+
expect(fixer.insertTextBeforeRange.mock.calls[0][0]).toEqual([5, 5]);
|
|
50
|
+
expect(fixer.insertTextBeforeRange.mock.calls[0][1]).toBe(`${require_story_helpers_1.ANNOTATION}\n`);
|
|
51
|
+
expect(res).toEqual({ r: [5, 5], t: `${require_story_helpers_1.ANNOTATION}\n` });
|
|
52
|
+
});
|
|
53
|
+
test("reportMissing uses context.getSourceCode fallback when sourceCode not provided and still reports", () => {
|
|
54
|
+
const node = {
|
|
55
|
+
type: "FunctionDeclaration",
|
|
56
|
+
id: { name: "fnX" },
|
|
57
|
+
range: [0, 10],
|
|
58
|
+
};
|
|
59
|
+
const fakeSource = {
|
|
60
|
+
/* intentionally missing getJSDocComment to exercise branch */ getText: () => "",
|
|
61
|
+
};
|
|
62
|
+
const context = { getSourceCode: () => fakeSource, report: jest.fn() };
|
|
63
|
+
(0, require_story_core_1.reportMissing)(context, undefined, node, node);
|
|
64
|
+
expect(context.report).toHaveBeenCalledTimes(1);
|
|
65
|
+
const call = context.report.mock.calls[0][0];
|
|
66
|
+
expect(call.node).toBe(node);
|
|
67
|
+
expect(call.messageId).toBe("missingStory");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
5
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
6
|
+
* @req REQ-AUTOFIX - Verify createMethodFix and reportMethod behaviors
|
|
7
|
+
*/
|
|
8
|
+
const require_story_core_1 = require("../../src/rules/helpers/require-story-core");
|
|
9
|
+
const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
|
|
10
|
+
describe("Require Story Core (Story 003.0)", () => {
|
|
11
|
+
test("createMethodFix uses parent range start when parent is export", () => {
|
|
12
|
+
const node = {
|
|
13
|
+
type: "MethodDefinition",
|
|
14
|
+
range: [30, 60],
|
|
15
|
+
parent: { type: "ExportNamedDeclaration", range: [12, 90] },
|
|
16
|
+
};
|
|
17
|
+
const fixer = {
|
|
18
|
+
insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
|
|
19
|
+
};
|
|
20
|
+
const fixFn = (0, require_story_core_1.createMethodFix)(node);
|
|
21
|
+
const result = fixFn(fixer);
|
|
22
|
+
expect(fixer.insertTextBeforeRange).toHaveBeenCalledTimes(1);
|
|
23
|
+
const calledArgs = fixer.insertTextBeforeRange.mock.calls[0];
|
|
24
|
+
expect(calledArgs[0]).toEqual([12, 12]);
|
|
25
|
+
expect(calledArgs[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n `);
|
|
26
|
+
expect(result).toEqual({ r: [12, 12], t: `${require_story_helpers_1.ANNOTATION}\n ` });
|
|
27
|
+
});
|
|
28
|
+
test("reportMethod calls context.report with proper data and suggest.fix works", () => {
|
|
29
|
+
const node = {
|
|
30
|
+
type: "MethodDefinition",
|
|
31
|
+
key: { name: "myMethod" },
|
|
32
|
+
range: [40, 80],
|
|
33
|
+
parent: { type: "ClassBody" },
|
|
34
|
+
};
|
|
35
|
+
const fakeSource = { getText: () => "" };
|
|
36
|
+
const context = {
|
|
37
|
+
getSourceCode: () => fakeSource,
|
|
38
|
+
report: jest.fn(),
|
|
39
|
+
};
|
|
40
|
+
(0, require_story_core_1.reportMethod)(context, fakeSource, node, node);
|
|
41
|
+
expect(context.report).toHaveBeenCalledTimes(1);
|
|
42
|
+
const call = context.report.mock.calls[0][0];
|
|
43
|
+
expect(call.messageId).toBe("missingStory");
|
|
44
|
+
expect(call.data).toEqual({ name: "myMethod" });
|
|
45
|
+
// The suggest fix should be a function; exercise it with a mock fixer
|
|
46
|
+
expect(Array.isArray(call.suggest)).toBe(true);
|
|
47
|
+
expect(typeof call.suggest[0].fix).toBe("function");
|
|
48
|
+
const fixer = {
|
|
49
|
+
insertTextBeforeRange: jest.fn((r, t) => ({ r, t })),
|
|
50
|
+
};
|
|
51
|
+
const fixResult = call.suggest[0].fix(fixer);
|
|
52
|
+
expect(fixer.insertTextBeforeRange).toHaveBeenCalled();
|
|
53
|
+
const args = fixer.insertTextBeforeRange.mock.calls[0];
|
|
54
|
+
expect(args[0]).toEqual([40, 40]);
|
|
55
|
+
expect(args[1]).toBe(`${require_story_helpers_1.ANNOTATION}\n `);
|
|
56
|
+
expect(fixResult).toEqual({ r: [40, 40], t: `${require_story_helpers_1.ANNOTATION}\n ` });
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
4
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
5
|
+
* @req REQ-COVERAGE-HELPERS - Additional tests to exercise edge branches in require-story-helpers.ts
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const require_story_helpers_1 = require("../../src/rules/helpers/require-story-helpers");
|
|
9
|
+
describe("Require Story Helpers - additional branch coverage (Story 003.0)", () => {
|
|
10
|
+
test("jsdocHasStory returns false when JSDoc exists but value is not a string", () => {
|
|
11
|
+
const fakeSource = { getJSDocComment: () => ({ value: 123 }) };
|
|
12
|
+
const res = (0, require_story_helpers_1.jsdocHasStory)(fakeSource, {});
|
|
13
|
+
expect(res).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
test("commentsBeforeHasStory returns false when comments exist but value is not a string", () => {
|
|
16
|
+
const fakeSource = { getCommentsBefore: () => [{ value: 123 }] };
|
|
17
|
+
const res = (0, require_story_helpers_1.commentsBeforeHasStory)(fakeSource, {});
|
|
18
|
+
expect(res).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
test("leadingCommentsHasStory detects @story in leadingComments array", () => {
|
|
21
|
+
const node = {
|
|
22
|
+
leadingComments: [
|
|
23
|
+
{ type: "Block", value: "some other text" },
|
|
24
|
+
{
|
|
25
|
+
type: "Block",
|
|
26
|
+
value: "@story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
expect((0, require_story_helpers_1.leadingCommentsHasStory)(node)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
test("resolveTargetNode returns ExpressionStatement parent for FunctionExpression", () => {
|
|
33
|
+
const fakeSource = { getText: () => "" };
|
|
34
|
+
const node = {
|
|
35
|
+
type: "FunctionExpression",
|
|
36
|
+
parent: { type: "ExpressionStatement" },
|
|
37
|
+
};
|
|
38
|
+
const resolved = (0, require_story_helpers_1.resolveTargetNode)(fakeSource, node);
|
|
39
|
+
expect(resolved).toBe(node.parent);
|
|
40
|
+
});
|
|
41
|
+
test("shouldProcessNode respects exportPriority 'exported' and 'non-exported'", () => {
|
|
42
|
+
const exportedNode = {
|
|
43
|
+
type: "FunctionDeclaration",
|
|
44
|
+
parent: { parent: { type: "ExportNamedDeclaration" } },
|
|
45
|
+
};
|
|
46
|
+
const nonExportedNode = {
|
|
47
|
+
type: "FunctionDeclaration",
|
|
48
|
+
parent: { parent: { type: "SomeOther" } },
|
|
49
|
+
};
|
|
50
|
+
expect((0, require_story_helpers_1.shouldProcessNode)(exportedNode, require_story_helpers_1.DEFAULT_SCOPE, "exported")).toBe(true);
|
|
51
|
+
expect((0, require_story_helpers_1.shouldProcessNode)(nonExportedNode, require_story_helpers_1.DEFAULT_SCOPE, "exported")).toBe(false);
|
|
52
|
+
// non-exported should reject exported nodes
|
|
53
|
+
expect((0, require_story_helpers_1.shouldProcessNode)(exportedNode, require_story_helpers_1.DEFAULT_SCOPE, "non-exported")).toBe(false);
|
|
54
|
+
expect((0, require_story_helpers_1.shouldProcessNode)(nonExportedNode, require_story_helpers_1.DEFAULT_SCOPE, "non-exported")).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
test("reportMissing does not report when linesBeforeHasStory finds a preceding @story", () => {
|
|
57
|
+
const jsdoc = "/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n */\n";
|
|
58
|
+
const rest = "function fnA() {}\n";
|
|
59
|
+
const full = jsdoc + rest;
|
|
60
|
+
const fakeSource = {
|
|
61
|
+
getText: () => full,
|
|
62
|
+
getJSDocComment: () => null,
|
|
63
|
+
lines: full.split(/\r?\n/),
|
|
64
|
+
getCommentsBefore: () => [],
|
|
65
|
+
};
|
|
66
|
+
const node = {
|
|
67
|
+
type: "FunctionDeclaration",
|
|
68
|
+
range: [full.indexOf("function"), full.length],
|
|
69
|
+
loc: {
|
|
70
|
+
start: {
|
|
71
|
+
line: fakeSource.lines.findIndex((l) => l.includes("function fnA() {}")) + 1,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
const context = { getSourceCode: () => fakeSource, report: jest.fn() };
|
|
76
|
+
(0, require_story_helpers_1.reportMissing)(context, fakeSource, node, node);
|
|
77
|
+
expect(context.report).not.toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
4
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
5
|
+
* @req REQ-COVERAGE-IO - Additional tests to exercise uncovered branches in require-story-io.ts
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const require_story_io_1 = require("../../src/rules/helpers/require-story-io");
|
|
9
|
+
describe("Require Story IO helpers - branch coverage (Story 003.0)", () => {
|
|
10
|
+
test("parentChainHasStory returns false when sourceCode.getCommentsBefore is not a function", () => {
|
|
11
|
+
const fakeSource = {}; // no getCommentsBefore function
|
|
12
|
+
const node = { parent: { parent: null } };
|
|
13
|
+
expect((0, require_story_io_1.parentChainHasStory)(fakeSource, node)).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
test("parentChainHasStory returns false when getCommentsBefore returns comments but none contain @story", () => {
|
|
16
|
+
const fakeSource = {
|
|
17
|
+
getCommentsBefore: () => [{ value: 123 }, { value: "no story here" }],
|
|
18
|
+
};
|
|
19
|
+
const node = { parent: { leadingComments: [], parent: null } };
|
|
20
|
+
expect((0, require_story_io_1.parentChainHasStory)(fakeSource, node)).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
test("parentChainHasStory returns true when ancestor leadingComments contain @story", () => {
|
|
23
|
+
const fakeSource = { getCommentsBefore: () => [] };
|
|
24
|
+
const node = {
|
|
25
|
+
parent: {
|
|
26
|
+
leadingComments: [
|
|
27
|
+
{
|
|
28
|
+
value: "@story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
parent: null,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
expect((0, require_story_io_1.parentChainHasStory)(fakeSource, node)).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
test("fallbackTextBeforeHasStory returns false when node.range[0] is not a number", () => {
|
|
37
|
+
const fakeSource = { getText: () => "some text without story" };
|
|
38
|
+
const node = { range: ["a", 10] };
|
|
39
|
+
expect((0, require_story_io_1.fallbackTextBeforeHasStory)(fakeSource, node)).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
test("fallbackTextBeforeHasStory detects @story in text before node.range", () => {
|
|
42
|
+
const story = "@story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md";
|
|
43
|
+
const pre = `/* ${story} */\n`;
|
|
44
|
+
const rest = "function y() {}";
|
|
45
|
+
const full = pre + rest;
|
|
46
|
+
const fakeSource = { getText: () => full };
|
|
47
|
+
const node = { range: [full.indexOf("function"), full.length] };
|
|
48
|
+
expect((0, require_story_io_1.fallbackTextBeforeHasStory)(fakeSource, node)).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
4
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
5
|
+
* @req REQ-COVERAGE-VISITORS - Tests to cover visitors branches in require-story-visitors.ts
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const require_story_visitors_1 = require("../../src/rules/helpers/require-story-visitors");
|
|
9
|
+
describe("Require Story Visitors - branch coverage (Story 003.0)", () => {
|
|
10
|
+
test("build visitors returns handlers for FunctionDeclaration and ArrowFunctionExpression", () => {
|
|
11
|
+
const fakeContext = { getFilename: () => "file.ts" };
|
|
12
|
+
const fakeSource = { getText: () => "" };
|
|
13
|
+
const options = { shouldProcessNode: () => true };
|
|
14
|
+
const visitors = (0, require_story_visitors_1.buildVisitors)(fakeContext, fakeSource, options);
|
|
15
|
+
expect(typeof visitors.FunctionDeclaration).toBe("function");
|
|
16
|
+
expect(typeof visitors.ArrowFunctionExpression).toBe("function");
|
|
17
|
+
});
|
|
18
|
+
test("FunctionDeclaration handler uses context.getFilename and doesn't throw when node lacks id", () => {
|
|
19
|
+
const fakeContext = { getFilename: () => "file.ts" };
|
|
20
|
+
const fakeSource = { getText: () => "" };
|
|
21
|
+
const options = { shouldProcessNode: () => true };
|
|
22
|
+
const visitors = (0, require_story_visitors_1.buildVisitors)(fakeContext, fakeSource, options);
|
|
23
|
+
const handler = visitors.FunctionDeclaration;
|
|
24
|
+
expect(() => handler({})).not.toThrow();
|
|
25
|
+
});
|
|
26
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-traceability",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.6",
|
|
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",
|
|
@@ -16,8 +16,12 @@
|
|
|
16
16
|
"build": "tsc -p tsconfig.json",
|
|
17
17
|
"type-check": "tsc --noEmit -p tsconfig.json",
|
|
18
18
|
"check:traceability": "node scripts/traceability-check.js",
|
|
19
|
+
"lint-plugin-check": "npm run build && node scripts/lint-plugin-check.js",
|
|
20
|
+
"lint:require-built-plugin": "npm run lint-plugin-check",
|
|
19
21
|
"lint": "eslint --config eslint.config.js \"src/**/*.{js,ts}\" \"tests/**/*.{js,ts}\" --max-warnings=0",
|
|
20
22
|
"test": "jest --ci --bail",
|
|
23
|
+
"ci-verify": "npm run type-check && npm run lint && npm run format:check && npm run duplication && npm run check:traceability && npm test && npm run audit:ci && npm run safety:deps",
|
|
24
|
+
"ci-verify:fast": "npm run lint-plugin-check && npm run type-check && npm run check:traceability && npm run duplication && jest --ci --bail --passWithNoTests --testPathPatterns 'tests/(unit|fast)'",
|
|
21
25
|
"format": "prettier --write .",
|
|
22
26
|
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
23
27
|
"duplication": "jscpd src tests --reporters console --threshold 3 --ignore tests/utils/**",
|