eslint-plugin-traceability 1.4.12 → 1.5.1

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/index.js CHANGED
@@ -77,7 +77,7 @@ const configs = {
77
77
  "traceability/require-story-annotation": "error",
78
78
  "traceability/require-req-annotation": "error",
79
79
  "traceability/require-branch-annotation": "error",
80
- "traceability/valid-annotation-format": "error",
80
+ "traceability/valid-annotation-format": "warn",
81
81
  "traceability/valid-story-reference": "error",
82
82
  "traceability/valid-req-reference": "error",
83
83
  },
@@ -92,7 +92,7 @@ const configs = {
92
92
  "traceability/require-story-annotation": "error",
93
93
  "traceability/require-req-annotation": "error",
94
94
  "traceability/require-branch-annotation": "error",
95
- "traceability/valid-annotation-format": "error",
95
+ "traceability/valid-annotation-format": "warn",
96
96
  "traceability/valid-story-reference": "error",
97
97
  "traceability/valid-req-reference": "error",
98
98
  },
@@ -22,7 +22,7 @@ exports.default = {
22
22
  recommended: "error",
23
23
  },
24
24
  messages: {
25
- missingReq: "Missing @req annotation",
25
+ missingReq: "Missing @req annotation for function '{{name}}' (REQ-ANNOTATION-REQUIRED)",
26
26
  },
27
27
  schema: [],
28
28
  },
@@ -32,7 +32,6 @@ exports.default = {
32
32
  * @req REQ-FUNCTION-DETECTION - Detect function declarations, expressions, arrow functions, and methods
33
33
  */
34
34
  create(context) {
35
- const sourceCode = context.getSourceCode();
36
35
  return {
37
36
  /**
38
37
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
@@ -40,21 +39,7 @@ exports.default = {
40
39
  * @req REQ-ANNOTATION-REQUIRED - Enforce @req annotation on function declarations
41
40
  */
42
41
  FunctionDeclaration(node) {
43
- const jsdoc = sourceCode.getJSDocComment(node);
44
- if (!jsdoc || !jsdoc.value.includes("@req")) {
45
- context.report({
46
- node,
47
- messageId: "missingReq",
48
- /**
49
- * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
50
- * @req REQ-AUTOFIX - Provide automatic fix to insert @req annotation
51
- * @req REQ-ANNOTATION-REQUIRED - Ensure inserted fix contains @req placeholder
52
- */
53
- fix(fixer) {
54
- return fixer.insertTextBefore(node, "/** @req <REQ-ID> */\n");
55
- },
56
- });
57
- }
42
+ return (0, annotation_checker_1.checkReqAnnotation)(context, node);
58
43
  },
59
44
  /**
60
45
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
@@ -1,10 +1,2 @@
1
- /**
2
- * Rule to validate @story and @req annotation format and syntax
3
- * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
4
- * @req REQ-FORMAT-SPECIFICATION - Define clear format rules for @story and @req annotations
5
- * @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
6
- * @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
7
- * @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
8
- */
9
1
  declare const _default: any;
10
2
  export default _default;
@@ -1,13 +1,187 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const STORY_EXAMPLE_PATH = "docs/stories/005.0-DEV-EXAMPLE.story.md";
3
4
  /**
4
- * Rule to validate @story and @req annotation format and syntax
5
+ * Normalize a raw comment line to make annotation parsing more robust.
6
+ *
7
+ * This function trims whitespace, keeps any annotation tags that appear
8
+ * later in the line, and supports common JSDoc styles such as leading "*".
9
+ *
10
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
11
+ * @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
12
+ */
13
+ function normalizeCommentLine(rawLine) {
14
+ const trimmed = rawLine.trim();
15
+ if (!trimmed) {
16
+ return "";
17
+ }
18
+ const annotationMatch = trimmed.match(/@story\b|@req\b/);
19
+ if (!annotationMatch || annotationMatch.index === undefined) {
20
+ const withoutLeadingStar = trimmed.replace(/^\*\s?/, "");
21
+ return withoutLeadingStar;
22
+ }
23
+ return trimmed.slice(annotationMatch.index);
24
+ }
25
+ /**
26
+ * Collapse internal whitespace in an annotation value so that multi-line
27
+ * annotations are treated as a single logical value.
28
+ *
29
+ * Example:
30
+ * "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md" across
31
+ * multiple lines will be collapsed before validation.
32
+ *
33
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
34
+ * @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
35
+ */
36
+ function collapseAnnotationValue(value) {
37
+ return value.replace(/\s+/g, "");
38
+ }
39
+ /**
40
+ * Build a detailed error message for invalid @story annotations.
41
+ *
42
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
43
+ * @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
44
+ */
45
+ function buildStoryErrorMessage(kind, value) {
46
+ if (kind === "missing") {
47
+ return `Missing story path for @story annotation. Expected a path like "${STORY_EXAMPLE_PATH}".`;
48
+ }
49
+ return `Invalid story path "${value ?? ""}" for @story annotation. Expected a path like "${STORY_EXAMPLE_PATH}".`;
50
+ }
51
+ /**
52
+ * Build a detailed error message for invalid @req annotations.
53
+ *
54
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
55
+ * @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
56
+ */
57
+ function buildReqErrorMessage(kind, value) {
58
+ if (kind === "missing") {
59
+ return 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".';
60
+ }
61
+ return `Invalid requirement ID "${value ?? ""}" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).`;
62
+ }
63
+ /**
64
+ * Validate a @story annotation value and report detailed errors when needed.
65
+ *
5
66
  * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
6
- * @req REQ-FORMAT-SPECIFICATION - Define clear format rules for @story and @req annotations
7
- * @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
8
67
  * @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
68
+ * @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
69
+ */
70
+ function validateStoryAnnotation(context, comment, rawValue) {
71
+ const trimmed = rawValue.trim();
72
+ if (!trimmed) {
73
+ context.report({
74
+ node: comment,
75
+ messageId: "invalidStoryFormat",
76
+ data: { details: buildStoryErrorMessage("missing", null) },
77
+ });
78
+ return;
79
+ }
80
+ const collapsed = collapseAnnotationValue(trimmed);
81
+ const pathPattern = /^docs\/stories\/[0-9]+\.[0-9]+-DEV-[\w-]+\.story\.md$/;
82
+ if (!pathPattern.test(collapsed)) {
83
+ context.report({
84
+ node: comment,
85
+ messageId: "invalidStoryFormat",
86
+ data: { details: buildStoryErrorMessage("invalid", collapsed) },
87
+ });
88
+ }
89
+ }
90
+ /**
91
+ * Validate a @req annotation value and report detailed errors when needed.
92
+ *
93
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
9
94
  * @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
95
+ * @req REQ-ERROR-SPECIFICITY - Provide specific error messages for different format violations
96
+ */
97
+ function validateReqAnnotation(context, comment, rawValue) {
98
+ const trimmed = rawValue.trim();
99
+ if (!trimmed) {
100
+ context.report({
101
+ node: comment,
102
+ messageId: "invalidReqFormat",
103
+ data: { details: buildReqErrorMessage("missing", null) },
104
+ });
105
+ return;
106
+ }
107
+ const collapsed = collapseAnnotationValue(trimmed);
108
+ const reqPattern = /^REQ-[A-Z0-9-]+$/;
109
+ if (!reqPattern.test(collapsed)) {
110
+ context.report({
111
+ node: comment,
112
+ messageId: "invalidReqFormat",
113
+ data: { details: buildReqErrorMessage("invalid", collapsed) },
114
+ });
115
+ }
116
+ }
117
+ /**
118
+ * Process a single comment node and validate any @story/@req annotations it contains.
119
+ *
120
+ * Supports annotations whose values span multiple lines within the same
121
+ * comment block, collapsing whitespace so that the logical value can be
122
+ * validated against the configured patterns.
123
+ *
124
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
125
+ * @req REQ-MULTILINE-SUPPORT - Handle annotations split across multiple lines
126
+ * @req REQ-FLEXIBLE-PARSING - Support reasonable variations in whitespace and formatting
10
127
  */
128
+ function processComment(context, comment) {
129
+ const rawLines = (comment.value || "").split(/\r?\n/);
130
+ let pending = null;
131
+ /**
132
+ * Finalize and validate the currently pending annotation, if any.
133
+ *
134
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
135
+ * @req REQ-SYNTAX-VALIDATION - Validate annotation syntax matches specification
136
+ */
137
+ function finalizePending() {
138
+ if (!pending) {
139
+ return;
140
+ }
141
+ // @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
142
+ // @req REQ-SYNTAX-VALIDATION - Dispatch validation based on annotation type
143
+ if (pending.type === "story") {
144
+ validateStoryAnnotation(context, comment, pending.value);
145
+ }
146
+ else {
147
+ validateReqAnnotation(context, comment, pending.value);
148
+ }
149
+ pending = null;
150
+ }
151
+ rawLines.forEach((rawLine) => {
152
+ const normalized = normalizeCommentLine(rawLine);
153
+ if (!normalized) {
154
+ return;
155
+ }
156
+ const isStory = /@story\b/.test(normalized);
157
+ const isReq = /@req\b/.test(normalized);
158
+ // @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
159
+ // @req REQ-SYNTAX-VALIDATION - Start new pending annotation when a tag is found
160
+ if (isStory || isReq) {
161
+ finalizePending();
162
+ const value = normalized.replace(/^@story\b|^@req\b/, "").trim();
163
+ pending = {
164
+ type: isStory ? "story" : "req",
165
+ value,
166
+ hasValue: value.trim().length > 0,
167
+ };
168
+ return;
169
+ }
170
+ // @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
171
+ // @req REQ-MULTILINE-SUPPORT - Treat subsequent lines as continuation for pending annotation
172
+ if (pending) {
173
+ const continuation = normalized.trim();
174
+ if (!continuation) {
175
+ return;
176
+ }
177
+ pending.value = pending.value
178
+ ? `${pending.value} ${continuation}`
179
+ : continuation;
180
+ pending.hasValue = pending.hasValue || continuation.length > 0;
181
+ }
182
+ });
183
+ finalizePending();
184
+ }
11
185
  exports.default = {
12
186
  meta: {
13
187
  type: "problem",
@@ -16,8 +190,8 @@ exports.default = {
16
190
  recommended: "error",
17
191
  },
18
192
  messages: {
19
- invalidStoryFormat: "Invalid @story annotation format",
20
- invalidReqFormat: "Invalid @req annotation format",
193
+ invalidStoryFormat: "{{details}}",
194
+ invalidReqFormat: "{{details}}",
21
195
  },
22
196
  schema: [],
23
197
  },
@@ -31,6 +205,7 @@ exports.default = {
31
205
  return {
32
206
  /**
33
207
  * Program-level handler that inspects all comments for @story and @req tags
208
+ *
34
209
  * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
35
210
  * @req REQ-PATH-FORMAT - Validate @story paths follow expected patterns
36
211
  * @req REQ-REQ-FORMAT - Validate @req identifiers follow expected patterns
@@ -38,32 +213,7 @@ exports.default = {
38
213
  Program() {
39
214
  const comments = sourceCode.getAllComments() || [];
40
215
  comments.forEach((comment) => {
41
- const lines = comment.value
42
- .split(/\r?\n/)
43
- .map((l) => l.replace(/^[^@]*/, "").trim());
44
- lines.forEach((line) => {
45
- if (line.startsWith("@story")) {
46
- const parts = line.split(/\s+/);
47
- const storyPath = parts[1];
48
- if (!storyPath ||
49
- !/^docs\/stories\/[0-9]+\.[0-9]+-DEV-[\w-]+\.story\.md$/.test(storyPath)) {
50
- context.report({
51
- node: comment,
52
- messageId: "invalidStoryFormat",
53
- });
54
- }
55
- }
56
- if (line.startsWith("@req")) {
57
- const parts = line.split(/\s+/);
58
- const reqId = parts[1];
59
- if (!reqId || !/^REQ-[A-Z0-9-]+$/.test(reqId)) {
60
- context.report({
61
- node: comment,
62
- messageId: "invalidReqFormat",
63
- });
64
- }
65
- }
66
- });
216
+ processComment(context, comment);
67
217
  });
68
218
  },
69
219
  };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkReqAnnotation = checkReqAnnotation;
4
+ const require_story_utils_1 = require("../rules/helpers/require-story-utils");
4
5
  /**
5
6
  * Helper to retrieve the JSDoc comment for a node.
6
7
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
@@ -65,13 +66,20 @@ function createMissingReqFix(node) {
65
66
  }
66
67
  /**
67
68
  * Helper to report a missing @req annotation via the ESLint context API.
69
+ * Uses getNodeName to provide a readable name for the node.
68
70
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
71
+ * @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
69
72
  * @req REQ-ANNOTATION-REPORTING - Report missing @req annotation to context
73
+ * @req REQ-ERROR-SPECIFIC - Provide specific error details including node name
74
+ * @req REQ-ERROR-LOCATION - Include contextual location information in errors
70
75
  */
71
76
  function reportMissing(context, node) {
77
+ const rawName = (0, require_story_utils_1.getNodeName)(node);
78
+ const name = rawName ?? "(anonymous)";
72
79
  context.report({
73
80
  node,
74
81
  messageId: "missingReq",
82
+ data: { name },
75
83
  fix: createMissingReqFix(node),
76
84
  });
77
85
  }
@@ -7,6 +7,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
8
8
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
9
9
  * @req REQ-ANNOTATION-REQUIRED - Verify require-req-annotation rule enforces @req on functions
10
+ * @story docs/stories/007.0-DEV-ERROR-REPORTING.story.md
11
+ * @req REQ-ERROR-SPECIFIC - Verify enhanced, specific error messaging behavior
10
12
  */
11
13
  const eslint_1 = require("eslint");
12
14
  const require_req_annotation_1 = __importDefault(require("../../src/rules/require-req-annotation"));
@@ -48,19 +50,19 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
48
50
  name: "[REQ-ANNOTATION-REQUIRED] missing @req on function without JSDoc",
49
51
  code: `function baz() {}`,
50
52
  output: `/** @req <REQ-ID> */\nfunction baz() {}`,
51
- errors: [{ messageId: "missingReq" }],
53
+ errors: [{ messageId: "missingReq", data: { name: "baz" } }],
52
54
  },
53
55
  {
54
56
  name: "[REQ-ANNOTATION-REQUIRED] missing @req on function with only @story annotation",
55
57
  code: `/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n */\nfunction qux() {}`,
56
58
  output: `/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n */\n/** @req <REQ-ID> */\nfunction qux() {}`,
57
- errors: [{ messageId: "missingReq" }],
59
+ errors: [{ messageId: "missingReq", data: { name: "qux" } }],
58
60
  },
59
61
  {
60
62
  name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSDeclareFunction",
61
63
  code: `declare function baz(): void;`,
62
64
  output: `/** @req <REQ-ID> */\ndeclare function baz(): void;`,
63
- errors: [{ messageId: "missingReq" }],
65
+ errors: [{ messageId: "missingReq", data: { name: "baz" } }],
64
66
  languageOptions: {
65
67
  parser: require("@typescript-eslint/parser"),
66
68
  parserOptions: { ecmaVersion: 2022, sourceType: "module" },
@@ -70,7 +72,7 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
70
72
  name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSMethodSignature",
71
73
  code: `interface I { method(): void; }`,
72
74
  output: `interface I { /** @req <REQ-ID> */\nmethod(): void; }`,
73
- errors: [{ messageId: "missingReq" }],
75
+ errors: [{ messageId: "missingReq", data: { name: "method" } }],
74
76
  languageOptions: {
75
77
  parser: require("@typescript-eslint/parser"),
76
78
  parserOptions: { ecmaVersion: 2022, sourceType: "module" },
@@ -17,41 +17,184 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
17
17
  ruleTester.run("valid-annotation-format", valid_annotation_format_1.default, {
18
18
  valid: [
19
19
  {
20
- name: "[REQ-PATH-FORMAT] valid story annotation format",
20
+ name: "[REQ-PATH-FORMAT] valid story annotation format (single-line)",
21
21
  code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
22
22
  },
23
23
  {
24
- name: "[REQ-REQ-FORMAT] valid req annotation format",
24
+ name: "[REQ-REQ-FORMAT] valid req annotation format (single-line)",
25
25
  code: `// @req REQ-EXAMPLE`,
26
26
  },
27
27
  {
28
- name: "[REQ-FORMAT-SPECIFICATION] valid block annotations",
28
+ name: "[REQ-FORMAT-SPECIFICATION] valid block annotations (single-line values)",
29
29
  code: `/**
30
30
  * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
31
31
  * @req REQ-VALID-EXAMPLE
32
+ */`,
33
+ },
34
+ {
35
+ name: "[REQ-MULTILINE-SUPPORT] valid multi-line @story annotation value in block comment",
36
+ code: `/**
37
+ * @story docs/stories/005.0-
38
+ * DEV-ANNOTATION-VALIDATION.story.md
39
+ */`,
40
+ },
41
+ {
42
+ name: "[REQ-MULTILINE-SUPPORT] valid multi-line @req annotation value in block comment",
43
+ code: `/**
44
+ * @req REQ-
45
+ * EXAMPLE
46
+ */`,
47
+ },
48
+ {
49
+ name: "[REQ-FLEXIBLE-PARSING] valid JSDoc-style comment with leading stars and spacing",
50
+ code: `/**
51
+ * @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md
52
+ * @req REQ-FLEXIBLE-PARSING
32
53
  */`,
33
54
  },
34
55
  ],
35
56
  invalid: [
36
57
  {
37
- name: "[REQ-PATH-FORMAT] missing story path",
58
+ name: "[REQ-PATH-FORMAT] missing story path (single line)",
38
59
  code: `// @story`,
39
- errors: [{ messageId: "invalidStoryFormat" }],
60
+ errors: [
61
+ {
62
+ messageId: "invalidStoryFormat",
63
+ data: {
64
+ details: 'Missing story path for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
65
+ },
66
+ },
67
+ ],
40
68
  },
41
69
  {
42
70
  name: "[REQ-PATH-FORMAT] invalid story file extension",
43
71
  code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story`,
44
- errors: [{ messageId: "invalidStoryFormat" }],
72
+ errors: [
73
+ {
74
+ messageId: "invalidStoryFormat",
75
+ data: {
76
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
77
+ },
78
+ },
79
+ ],
80
+ },
81
+ {
82
+ name: "[REQ-PATH-FORMAT] missing extension in story path",
83
+ code: `// @story docs/stories/005.0-DEV-ANNOTATION-VALIDATION`,
84
+ errors: [
85
+ {
86
+ messageId: "invalidStoryFormat",
87
+ data: {
88
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
89
+ },
90
+ },
91
+ ],
92
+ },
93
+ {
94
+ name: "[REQ-PATH-FORMAT] story path must not use path traversal",
95
+ code: `// @story ../docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md`,
96
+ errors: [
97
+ {
98
+ messageId: "invalidStoryFormat",
99
+ data: {
100
+ details: 'Invalid story path "../docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
101
+ },
102
+ },
103
+ ],
45
104
  },
46
105
  {
47
- name: "[REQ-REQ-FORMAT] missing req id",
106
+ name: "[REQ-REQ-FORMAT] missing req id (single line)",
48
107
  code: `// @req`,
49
- errors: [{ messageId: "invalidReqFormat" }],
108
+ errors: [
109
+ {
110
+ messageId: "invalidReqFormat",
111
+ data: {
112
+ details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
113
+ },
114
+ },
115
+ ],
50
116
  },
51
117
  {
52
- name: "[REQ-REQ-FORMAT] invalid req id format",
118
+ name: "[REQ-REQ-FORMAT] invalid req id format (single line)",
53
119
  code: `// @req invalid-format`,
54
- errors: [{ messageId: "invalidReqFormat" }],
120
+ errors: [
121
+ {
122
+ messageId: "invalidReqFormat",
123
+ data: {
124
+ details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
125
+ },
126
+ },
127
+ ],
128
+ },
129
+ {
130
+ name: "[REQ-REQ-FORMAT] missing req identifier with trailing space",
131
+ code: `// @req `,
132
+ errors: [
133
+ {
134
+ messageId: "invalidReqFormat",
135
+ data: {
136
+ details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
137
+ },
138
+ },
139
+ ],
140
+ },
141
+ {
142
+ name: "[REQ-MULTILINE-SUPPORT] missing story path with multi-line block comment",
143
+ code: `/**
144
+ * @story
145
+ */`,
146
+ errors: [
147
+ {
148
+ messageId: "invalidStoryFormat",
149
+ data: {
150
+ details: 'Missing story path for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
151
+ },
152
+ },
153
+ ],
154
+ },
155
+ {
156
+ name: "[REQ-MULTILINE-SUPPORT] invalid multi-line story path after collapsing whitespace",
157
+ code: `/**
158
+ * @story docs/stories/005.0-
159
+ * DEV-ANNOTATION-VALIDATION.story
160
+ */`,
161
+ errors: [
162
+ {
163
+ messageId: "invalidStoryFormat",
164
+ data: {
165
+ details: 'Invalid story path "docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story" for @story annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
166
+ },
167
+ },
168
+ ],
169
+ },
170
+ {
171
+ name: "[REQ-MULTILINE-SUPPORT] missing req id with multi-line block comment",
172
+ code: `/**
173
+ * @req
174
+ */`,
175
+ errors: [
176
+ {
177
+ messageId: "invalidReqFormat",
178
+ data: {
179
+ details: 'Missing requirement ID for @req annotation. Expected an identifier like "REQ-EXAMPLE".',
180
+ },
181
+ },
182
+ ],
183
+ },
184
+ {
185
+ name: "[REQ-MULTILINE-SUPPORT] invalid multi-line req id after collapsing whitespace",
186
+ code: `/**
187
+ * @req invalid-
188
+ * format
189
+ */`,
190
+ errors: [
191
+ {
192
+ messageId: "invalidReqFormat",
193
+ data: {
194
+ details: 'Invalid requirement ID "invalid-format" for @req annotation. Expected an identifier like "REQ-EXAMPLE" (uppercase letters, numbers, and dashes only).',
195
+ },
196
+ },
197
+ ],
55
198
  },
56
199
  ],
57
200
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-traceability",
3
- "version": "1.4.12",
3
+ "version": "1.5.1",
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",