@vibe-validate/extractors 0.17.4 → 0.17.5-rc.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.
Files changed (134) hide show
  1. package/dist/extractor-registry.d.ts.map +1 -1
  2. package/dist/extractor-registry.js +8 -8
  3. package/dist/extractor-registry.js.map +1 -1
  4. package/dist/extractors/ava/index.d.ts.map +1 -1
  5. package/dist/extractors/ava/index.js +15 -14
  6. package/dist/extractors/ava/index.js.map +1 -1
  7. package/dist/extractors/ava/index.test.js +30 -20
  8. package/dist/extractors/ava/index.test.js.map +1 -1
  9. package/dist/extractors/eslint/index.d.ts.map +1 -1
  10. package/dist/extractors/eslint/index.js +1 -1
  11. package/dist/extractors/eslint/index.js.map +1 -1
  12. package/dist/extractors/eslint/index.test.js.map +1 -1
  13. package/dist/extractors/generic/index.test.js.map +1 -1
  14. package/dist/extractors/jasmine/index.test.js.map +1 -1
  15. package/dist/extractors/jest/index.d.ts.map +1 -1
  16. package/dist/extractors/jest/index.js.map +1 -1
  17. package/dist/extractors/jest/index.test.js.map +1 -1
  18. package/dist/extractors/junit/index.d.ts.map +1 -1
  19. package/dist/extractors/junit/index.js +5 -5
  20. package/dist/extractors/junit/index.js.map +1 -1
  21. package/dist/extractors/junit/index.test.js.map +1 -1
  22. package/dist/extractors/maven-checkstyle/index.d.ts.map +1 -1
  23. package/dist/extractors/maven-checkstyle/index.js +1 -1
  24. package/dist/extractors/maven-checkstyle/index.js.map +1 -1
  25. package/dist/extractors/maven-checkstyle/index.test.js +2 -2
  26. package/dist/extractors/maven-checkstyle/index.test.js.map +1 -1
  27. package/dist/extractors/maven-compiler/index.d.ts.map +1 -1
  28. package/dist/extractors/maven-compiler/index.js +1 -1
  29. package/dist/extractors/maven-compiler/index.js.map +1 -1
  30. package/dist/extractors/maven-compiler/index.test.js +1 -1
  31. package/dist/extractors/maven-compiler/index.test.js.map +1 -1
  32. package/dist/extractors/maven-surefire/index.d.ts.map +1 -1
  33. package/dist/extractors/maven-surefire/index.js.map +1 -1
  34. package/dist/extractors/maven-surefire/index.test.js.map +1 -1
  35. package/dist/extractors/mocha/index.test.js.map +1 -1
  36. package/dist/extractors/playwright/index.test.js.map +1 -1
  37. package/dist/extractors/tap/index.test.js +2 -2
  38. package/dist/extractors/tap/index.test.js.map +1 -1
  39. package/dist/extractors/typescript/index.d.ts.map +1 -1
  40. package/dist/extractors/typescript/index.js +16 -19
  41. package/dist/extractors/typescript/index.js.map +1 -1
  42. package/dist/extractors/typescript/index.test.js.map +1 -1
  43. package/dist/extractors/vitest/index.d.ts.map +1 -1
  44. package/dist/extractors/vitest/index.js +16 -7
  45. package/dist/extractors/vitest/index.js.map +1 -1
  46. package/dist/extractors/vitest/index.test.js +38 -0
  47. package/dist/extractors/vitest/index.test.js.map +1 -1
  48. package/dist/plugin-loader.d.ts.map +1 -1
  49. package/dist/plugin-loader.js +1 -1
  50. package/dist/plugin-loader.js.map +1 -1
  51. package/dist/result-schema-export.d.ts.map +1 -1
  52. package/dist/result-schema-export.js.map +1 -1
  53. package/dist/result-schema.d.ts.map +1 -1
  54. package/dist/result-schema.js +1 -1
  55. package/dist/result-schema.js.map +1 -1
  56. package/dist/sandboxed-extractor.d.ts +1 -1
  57. package/dist/sandboxed-extractor.d.ts.map +1 -1
  58. package/dist/sandboxed-extractor.js.map +1 -1
  59. package/dist/scripts/generate-result-schema.js +1 -1
  60. package/dist/scripts/generate-result-schema.js.map +1 -1
  61. package/dist/smart-extractor.d.ts.map +1 -1
  62. package/dist/smart-extractor.js.map +1 -1
  63. package/dist/utils/guidance-generator.d.ts.map +1 -1
  64. package/dist/utils/guidance-generator.js +4 -7
  65. package/dist/utils/guidance-generator.js.map +1 -1
  66. package/dist/utils/test-framework-utils.d.ts.map +1 -1
  67. package/dist/utils/test-framework-utils.js.map +1 -1
  68. package/dist/utils.js +1 -1
  69. package/dist/utils.js.map +1 -1
  70. package/package.json +8 -8
  71. package/dist/ava-extractor.d.ts +0 -24
  72. package/dist/ava-extractor.d.ts.map +0 -1
  73. package/dist/ava-extractor.js +0 -343
  74. package/dist/ava-extractor.js.map +0 -1
  75. package/dist/eslint-extractor.d.ts +0 -25
  76. package/dist/eslint-extractor.d.ts.map +0 -1
  77. package/dist/eslint-extractor.js +0 -145
  78. package/dist/eslint-extractor.js.map +0 -1
  79. package/dist/generic-extractor.d.ts +0 -35
  80. package/dist/generic-extractor.d.ts.map +0 -1
  81. package/dist/generic-extractor.js +0 -128
  82. package/dist/generic-extractor.js.map +0 -1
  83. package/dist/jasmine-extractor.d.ts +0 -23
  84. package/dist/jasmine-extractor.d.ts.map +0 -1
  85. package/dist/jasmine-extractor.js +0 -151
  86. package/dist/jasmine-extractor.js.map +0 -1
  87. package/dist/jest-extractor.d.ts +0 -29
  88. package/dist/jest-extractor.d.ts.map +0 -1
  89. package/dist/jest-extractor.js +0 -174
  90. package/dist/jest-extractor.js.map +0 -1
  91. package/dist/junit-extractor.d.ts +0 -24
  92. package/dist/junit-extractor.d.ts.map +0 -1
  93. package/dist/junit-extractor.js +0 -193
  94. package/dist/junit-extractor.js.map +0 -1
  95. package/dist/maven-checkstyle-extractor.d.ts +0 -20
  96. package/dist/maven-checkstyle-extractor.d.ts.map +0 -1
  97. package/dist/maven-checkstyle-extractor.js +0 -208
  98. package/dist/maven-checkstyle-extractor.js.map +0 -1
  99. package/dist/maven-compiler-extractor.d.ts +0 -20
  100. package/dist/maven-compiler-extractor.d.ts.map +0 -1
  101. package/dist/maven-compiler-extractor.js +0 -218
  102. package/dist/maven-compiler-extractor.js.map +0 -1
  103. package/dist/maven-surefire-extractor.d.ts +0 -20
  104. package/dist/maven-surefire-extractor.d.ts.map +0 -1
  105. package/dist/maven-surefire-extractor.js +0 -228
  106. package/dist/maven-surefire-extractor.js.map +0 -1
  107. package/dist/mocha-extractor.d.ts +0 -23
  108. package/dist/mocha-extractor.d.ts.map +0 -1
  109. package/dist/mocha-extractor.js +0 -160
  110. package/dist/mocha-extractor.js.map +0 -1
  111. package/dist/playwright-extractor.d.ts +0 -38
  112. package/dist/playwright-extractor.d.ts.map +0 -1
  113. package/dist/playwright-extractor.js +0 -239
  114. package/dist/playwright-extractor.js.map +0 -1
  115. package/dist/sandbox.test.d.ts +0 -8
  116. package/dist/sandbox.test.d.ts.map +0 -1
  117. package/dist/sandbox.test.js +0 -395
  118. package/dist/sandbox.test.js.map +0 -1
  119. package/dist/sandboxed-extractor.test.d.ts +0 -5
  120. package/dist/sandboxed-extractor.test.d.ts.map +0 -1
  121. package/dist/sandboxed-extractor.test.js +0 -346
  122. package/dist/sandboxed-extractor.test.js.map +0 -1
  123. package/dist/tap-extractor.d.ts +0 -24
  124. package/dist/tap-extractor.d.ts.map +0 -1
  125. package/dist/tap-extractor.js +0 -217
  126. package/dist/tap-extractor.js.map +0 -1
  127. package/dist/typescript-extractor.d.ts +0 -25
  128. package/dist/typescript-extractor.d.ts.map +0 -1
  129. package/dist/typescript-extractor.js +0 -96
  130. package/dist/typescript-extractor.js.map +0 -1
  131. package/dist/vitest-extractor.d.ts +0 -38
  132. package/dist/vitest-extractor.d.ts.map +0 -1
  133. package/dist/vitest-extractor.js +0 -540
  134. package/dist/vitest-extractor.js.map +0 -1
@@ -1,96 +0,0 @@
1
- /**
2
- * TypeScript Error Extractor
3
- *
4
- * Parses and formats TypeScript compiler (tsc) error output for LLM consumption.
5
- *
6
- * @package @vibe-validate/extractors
7
- */
8
- import { MAX_ERRORS_IN_ARRAY } from './result-schema.js';
9
- /**
10
- * Format TypeScript compiler errors
11
- *
12
- * Parses tsc output format: `file(line,col): error TSxxxx: message`
13
- *
14
- * @param output - Raw tsc command output
15
- * @returns Structured error information with TypeScript-specific guidance
16
- *
17
- * @example
18
- * ```typescript
19
- * const result = extractTypeScriptErrors(tscOutput);
20
- * console.log(result.summary); // "3 type error(s), 0 warning(s)"
21
- * console.log(result.guidance); // "Type mismatch - check variable/parameter types"
22
- * ```
23
- */
24
- export function extractTypeScriptErrors(output) {
25
- const errors = [];
26
- // TypeScript error patterns - support both old and new formats:
27
- // Old: file(line,col): error TSxxxx: message
28
- // New: file:line:col - error TSxxxx: message
29
- // eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses TypeScript compiler output (controlled tool output), not user input
30
- const oldPattern = /^(.+?)\((\d+),(\d+)\):\s*(error|warning)\s+(TS\d+):\s+(.+)$/gm;
31
- // eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses TypeScript compiler output (controlled tool output), not user input
32
- const newPattern = /^(.+?):(\d+):(\d+)\s+-\s*(error|warning)\s+(TS\d+):\s+(.+)$/gm;
33
- // Try new format first (more common in modern tsc)
34
- let match;
35
- while ((match = newPattern.exec(output)) !== null) {
36
- errors.push({
37
- file: match[1].trim(),
38
- line: Number.parseInt(match[2]),
39
- column: Number.parseInt(match[3]),
40
- severity: match[4],
41
- code: match[5],
42
- message: match[6].trim()
43
- });
44
- }
45
- // Try old format if no matches yet
46
- if (errors.length === 0) {
47
- while ((match = oldPattern.exec(output)) !== null) {
48
- errors.push({
49
- file: match[1].trim(),
50
- line: Number.parseInt(match[2]),
51
- column: Number.parseInt(match[3]),
52
- severity: match[4],
53
- code: match[5],
54
- message: match[6].trim()
55
- });
56
- }
57
- }
58
- const errorCount = errors.filter(e => e.severity === 'error').length;
59
- const warningCount = errors.filter(e => e.severity === 'warning').length;
60
- // Build error summary (limit to MAX_ERRORS_IN_ARRAY for token efficiency)
61
- const errorSummary = errors
62
- .slice(0, MAX_ERRORS_IN_ARRAY)
63
- .map(e => `${e.file}:${e.line}:${e.column} - ${e.code}: ${e.message}`)
64
- .join('\n');
65
- return {
66
- errors: errors.slice(0, MAX_ERRORS_IN_ARRAY),
67
- summary: `${errorCount} type error(s), ${warningCount} warning(s)`,
68
- totalErrors: errors.length,
69
- guidance: getTypeScriptGuidance(errors),
70
- errorSummary
71
- };
72
- }
73
- /**
74
- * Generate TypeScript-specific guidance based on error codes
75
- *
76
- * @param errors - Parsed TypeScript errors
77
- * @returns Actionable guidance string
78
- */
79
- function getTypeScriptGuidance(errors) {
80
- const errorCodes = new Set(errors.map(e => e.code));
81
- const guidance = [];
82
- if (errorCodes.has('TS2322')) {
83
- guidance.push('Type mismatch - check variable/parameter types');
84
- }
85
- if (errorCodes.has('TS2304')) {
86
- guidance.push('Cannot find name - check imports and type definitions');
87
- }
88
- if (errorCodes.has('TS2345')) {
89
- guidance.push('Argument type mismatch - check function signatures');
90
- }
91
- if (guidance.length === 0) {
92
- return 'Fix TypeScript type errors in listed files';
93
- }
94
- return guidance.join('. ');
95
- }
96
- //# sourceMappingURL=typescript-extractor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"typescript-extractor.js","sourceRoot":"","sources":["../src/typescript-extractor.ts"],"names":[],"mappings":"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"}
@@ -1,38 +0,0 @@
1
- /**
2
- * Vitest/Jest Error Extractor
3
- *
4
- * Parses and formats Vitest (and Jest) test failure output for LLM consumption.
5
- *
6
- * @package @vibe-validate/extractors
7
- */
8
- import type { ErrorExtractorResult } from './types.js';
9
- /**
10
- * Options for error extraction
11
- */
12
- export interface ExtractorOptions {
13
- /** Include quality metadata and suggestions for improving extraction */
14
- developerFeedback?: boolean;
15
- }
16
- /**
17
- * Format Vitest test failures
18
- *
19
- * Extracts:
20
- * - Test file and location (file:line:column)
21
- * - Test hierarchy (describe blocks > test name)
22
- * - Assertion error message
23
- * - Source code line that failed
24
- * - Expected vs actual values (when available)
25
- *
26
- * @param output - Raw Vitest/Jest command output
27
- * @param options - Extraction options (e.g., developerFeedback for quality metadata)
28
- * @returns Structured error information with test-specific guidance
29
- *
30
- * @example
31
- * ```typescript
32
- * const result = extractVitestErrors(vitestOutput);
33
- * console.log(result.summary); // "3 test failure(s)"
34
- * console.log(result.guidance); // "Fix each failing test individually..."
35
- * ```
36
- */
37
- export declare function extractVitestErrors(output: string, options?: ExtractorOptions): ErrorExtractorResult;
38
- //# sourceMappingURL=vitest-extractor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vitest-extractor.d.ts","sourceRoot":"","sources":["../src/vitest-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,YAAY,CAAC;AAG3E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAmZD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,gBAAgB,GACzB,oBAAoB,CA8HtB"}
@@ -1,540 +0,0 @@
1
- /**
2
- * Vitest/Jest Error Extractor
3
- *
4
- * Parses and formats Vitest (and Jest) test failure output for LLM consumption.
5
- *
6
- * @package @vibe-validate/extractors
7
- */
8
- import { MAX_ERRORS_IN_ARRAY } from './result-schema.js';
9
- /**
10
- * Parse failure line to determine format and extract initial data
11
- *
12
- * @param line - Current line being parsed
13
- * @param currentFile - File path from Format 2 header
14
- * @param hasFormat2 - Whether Format 2 has been detected
15
- * @returns Partial failure object or null if no match
16
- *
17
- * @internal
18
- */
19
- function parseFailureLine(line, currentFile, hasFormat2) {
20
- // Match Format 1: FAIL file.test.ts > test hierarchy
21
- // BUT: Skip if we've seen Format 2 headers (to avoid processing duplicate FAIL lines)
22
- const format1Match = !hasFormat2 && /(?:FAIL|❌|×)\s+([^\s]+\.test\.ts)\s*>\s*(.+)/.exec(line);
23
- if (format1Match) {
24
- return {
25
- file: format1Match[1],
26
- testHierarchy: format1Match[2].trim(),
27
- errorMessage: '',
28
- sourceLine: '',
29
- location: ''
30
- };
31
- }
32
- // Match Format 2: × test hierarchy (without file path)
33
- // eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Vitest test framework output (controlled output), limited line length
34
- const format2Match = /(?:×)\s+(.+?)(?:\s+\d+ms)?$/.exec(line);
35
- if (format2Match && currentFile) {
36
- return {
37
- file: currentFile,
38
- testHierarchy: format2Match[1].trim(),
39
- errorMessage: '',
40
- sourceLine: '',
41
- location: ''
42
- };
43
- }
44
- return null;
45
- }
46
- /**
47
- * Extract initial error message from line
48
- *
49
- * @param line - Line to extract error from
50
- * @returns Extracted error message
51
- *
52
- * @internal
53
- */
54
- function extractErrorMessage(line) {
55
- const errorMatch = /((?:AssertionError|Error):\s*.+)/.exec(line);
56
- if (errorMatch) {
57
- return errorMatch[1].trim();
58
- }
59
- const format2ErrorMatch = /→\s+(.+)/.exec(line);
60
- if (format2ErrorMatch) {
61
- return format2ErrorMatch[1].trim();
62
- }
63
- return line.trim();
64
- }
65
- /**
66
- * Check if line is a stop marker for error continuation
67
- *
68
- * @param line - Trimmed line to check
69
- * @returns True if this line marks end of error message
70
- *
71
- * @internal
72
- */
73
- function isStopMarker(line) {
74
- return (line.startsWith('❯') ||
75
- /^\d+\|/.test(line) ||
76
- line.startsWith('FAIL') ||
77
- line.startsWith('✓') ||
78
- line.startsWith('❌') ||
79
- line.startsWith('×') ||
80
- line.startsWith('⎯') ||
81
- line.startsWith('at '));
82
- }
83
- /**
84
- * Append continuation line to error message
85
- *
86
- * @param errorMessage - Current error message
87
- * @param line - Raw line (with indentation)
88
- * @param trimmedLine - Trimmed version of line
89
- * @param isSnapshotError - Whether handling snapshot error
90
- * @returns Updated error message
91
- *
92
- * @internal
93
- */
94
- function appendContinuationLine(errorMessage, line, trimmedLine, isSnapshotError) {
95
- if (isSnapshotError) {
96
- return errorMessage + '\n' + line; // Preserve indentation for diffs
97
- }
98
- return errorMessage + ' ' + trimmedLine; // Compact for normal errors
99
- }
100
- /**
101
- * Handle truncation logic for non-snapshot errors
102
- *
103
- * @param errorMessage - Current error message
104
- * @param nextLine - Next trimmed line
105
- * @param isSnapshotError - Whether handling snapshot error
106
- * @param linesConsumed - Number of lines consumed so far
107
- * @param maxLines - Maximum continuation lines allowed
108
- * @returns Object with updated message and whether to stop
109
- *
110
- * @internal
111
- */
112
- function handleTruncation(errorMessage, nextLine, isSnapshotError, linesConsumed, maxLines) {
113
- if (isSnapshotError || linesConsumed < maxLines) {
114
- return { errorMessage, shouldStop: false };
115
- }
116
- const updatedMessage = nextLine ? errorMessage + ' ...(truncated)' : errorMessage;
117
- return { errorMessage: updatedMessage, shouldStop: true };
118
- }
119
- /**
120
- * Parse error message with continuation line handling
121
- *
122
- * @param lines - All output lines
123
- * @param startIndex - Index where error message starts
124
- * @param isSnapshotError - Whether this is a snapshot error (different continuation rules)
125
- * @returns Error message and index of last consumed line
126
- *
127
- * @internal
128
- */
129
- function parseErrorMessage(lines, startIndex, isSnapshotError) {
130
- let errorMessage = extractErrorMessage(lines[startIndex]);
131
- const MAX_CONTINUATION_LINES = 5;
132
- let j = startIndex + 1;
133
- let linesConsumed = 0;
134
- while (j < lines.length) {
135
- const nextLine = lines[j].trim();
136
- if (isStopMarker(nextLine)) {
137
- break;
138
- }
139
- // Check truncation limit for non-snapshot errors
140
- const truncation = handleTruncation(errorMessage, nextLine, isSnapshotError, linesConsumed, MAX_CONTINUATION_LINES);
141
- if (truncation.shouldStop) {
142
- errorMessage = truncation.errorMessage;
143
- break;
144
- }
145
- // For non-snapshot errors, stop at blank lines
146
- if (!nextLine && !isSnapshotError) {
147
- break;
148
- }
149
- // Add line to error message
150
- if (nextLine || isSnapshotError) {
151
- errorMessage = appendContinuationLine(errorMessage, lines[j], nextLine, isSnapshotError);
152
- if (!isSnapshotError) {
153
- linesConsumed++;
154
- }
155
- }
156
- j++;
157
- }
158
- return { errorMessage, lastIndex: j - 1 };
159
- }
160
- /**
161
- * Parse location from vitest marker or stack trace
162
- *
163
- * @param line - Line to parse
164
- * @returns Location string (file:line:column) or null
165
- *
166
- * @internal
167
- */
168
- function parseLocation(line) {
169
- // Try vitest location marker first
170
- // eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Vitest test framework location markers (controlled output), not user input
171
- const vitestLocation = /❯\s*(.+\.test\.ts):(\d+):(\d+)/.exec(line);
172
- if (vitestLocation) {
173
- return `${vitestLocation[1]}:${vitestLocation[2]}:${vitestLocation[3]}`;
174
- }
175
- // Try stack trace pattern
176
- // eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Vitest test framework stack traces (controlled output), not user input
177
- const stackLocation = /at\s+.+\(([^\s]+\.test\.ts):(\d+):(\d+)\)/.exec(line);
178
- if (stackLocation) {
179
- return `${stackLocation[1]}:${stackLocation[2]}:${stackLocation[3]}`;
180
- }
181
- return null;
182
- }
183
- /**
184
- * Format failures into clean output
185
- *
186
- * @param failures - Extracted test failures
187
- * @param expected - Expected value (if present)
188
- * @param actual - Actual value (if present)
189
- * @returns Formatted output string
190
- *
191
- * @internal
192
- */
193
- function formatFailuresOutput(failures, expected, actual) {
194
- return failures
195
- .slice(0, MAX_ERRORS_IN_ARRAY)
196
- .map((f, idx) => {
197
- const parts = [
198
- `[Test ${idx + 1}/${failures.length}] ${f.location ?? f.file}`,
199
- '',
200
- `Test: ${f.testHierarchy}`,
201
- `Error: ${f.errorMessage}`,
202
- ];
203
- if (expected && actual) {
204
- parts.push(`Expected: ${expected}`, `Actual: ${actual}`);
205
- }
206
- if (f.sourceLine) {
207
- parts.push('', f.sourceLine);
208
- }
209
- return parts.filter(p => p).join('\n');
210
- })
211
- .join('\n\n');
212
- }
213
- /**
214
- * Generate LLM-friendly guidance based on failures
215
- *
216
- * @param failureCount - Number of failures
217
- * @param expected - Expected value (if present)
218
- * @param actual - Actual value (if present)
219
- * @param hasTimeout - Whether any failures are due to timeout
220
- * @returns Guidance text
221
- *
222
- * @internal
223
- */
224
- function generateGuidanceText(failureCount, expected, actual, hasTimeout) {
225
- let guidance = `${failureCount} test(s) failed. `;
226
- // Timeout-specific guidance
227
- if (hasTimeout) {
228
- guidance += 'Test(s) timed out. ';
229
- if (failureCount === 1) {
230
- guidance += 'Options: 1) Increase timeout with test.timeout() or testTimeout config, ';
231
- guidance += '2) Optimize test to run faster, ';
232
- guidance += '3) Mock slow operations (API calls, file I/O, child processes). ';
233
- }
234
- else {
235
- guidance += 'Multiple tests timing out suggests resource constraints. ';
236
- guidance += 'Try: 1) Run tests individually to identify slow tests, ';
237
- guidance += '2) Increase testTimeout config, ';
238
- guidance += '3) Reduce parallel test workers (--pool-workers=2). ';
239
- }
240
- guidance += 'Run: npm test -- <test-file> to verify the fix.';
241
- return guidance;
242
- }
243
- // Standard assertion failure guidance
244
- if (failureCount === 1) {
245
- guidance += 'Fix the assertion in the test file at the location shown. ';
246
- if (expected && actual) {
247
- guidance += `The test expected "${expected}" but got "${actual}". `;
248
- }
249
- guidance += 'Run: npm test -- <test-file> to verify the fix.';
250
- }
251
- else {
252
- guidance += 'Fix each failing test individually. Run: npm test -- <test-file> to test each file.';
253
- }
254
- return guidance;
255
- }
256
- /**
257
- * Extract runtime errors (Unhandled Rejection, ENOENT, etc.)
258
- *
259
- * @param output - Full test output
260
- * @returns Test failure object if runtime error found
261
- */
262
- function extractRuntimeError(output) {
263
- // Look for "Unhandled Rejection" section
264
- // eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Vitest test framework runtime errors (controlled output), not user input
265
- const unhandledMatch = /⎯+\s*Unhandled Rejection\s*⎯+\s*\n\s*(Error:[^\n]+(?:\n\s*[^\n❯⎯]+)?)/.exec(output);
266
- if (!unhandledMatch) {
267
- return null;
268
- }
269
- // Error message may span multiple lines (e.g., path on next line)
270
- const errorMessage = unhandledMatch[1].trim().replace(/\n\s+/g, ' ');
271
- // Extract location from stack trace (❯ function file:line:col)
272
- // File path may contain colons (e.g., node:internal/fs/promises), so match ❯ function filepath:number:number
273
- const locationMatch = /❯\s+\S+\s+([\w:/.]+):(\d+):(\d+)/.exec(output);
274
- let file = 'unknown';
275
- let location = '';
276
- if (locationMatch) {
277
- file = locationMatch[1];
278
- location = `${locationMatch[1]}:${locationMatch[2]}:${locationMatch[3]}`;
279
- }
280
- return {
281
- file,
282
- location,
283
- testHierarchy: 'Runtime Error',
284
- errorMessage,
285
- sourceLine: ''
286
- };
287
- }
288
- /**
289
- * Extract coverage threshold failures
290
- *
291
- * @param output - Full test output
292
- * @returns Test failure object if coverage threshold error found
293
- */
294
- function extractCoverageThresholdError(output) {
295
- // Look for: "ERROR: Coverage for functions (86.47%) does not meet global threshold (87%)"
296
- const coverageMatch = /ERROR:\s+Coverage for (\w+) \(([\d.]+)%\) does not meet (?:global )?threshold \(([\d.]+)%\)/.exec(output);
297
- if (!coverageMatch) {
298
- return null;
299
- }
300
- const [, metric, actual, expected] = coverageMatch;
301
- return {
302
- file: 'vitest.config.ts',
303
- location: '',
304
- testHierarchy: 'Coverage Threshold',
305
- errorMessage: `Coverage for ${metric} (${actual}%) does not meet threshold (${expected}%)`,
306
- sourceLine: ''
307
- };
308
- }
309
- /**
310
- * Extract Vitest worker timeout errors
311
- *
312
- * These occur when Vitest worker threads timeout during test execution,
313
- * often due to system resource constraints or competing processes.
314
- *
315
- * @param output - Full test output
316
- * @returns Test failure object if worker timeout error found
317
- */
318
- function extractVitestWorkerTimeoutError(output) {
319
- // Look for: "⎯⎯⎯⎯⎯⎯ Unhandled Error(s) ⎯⎯⎯⎯⎯⎯⎯\nError: [vitest-worker]: Timeout calling..."
320
- // Handles both singular "Unhandled Error" and plural "Unhandled Errors"
321
- // eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Vitest test framework error output (controlled output), not user input
322
- const timeoutMatch = /⎯+\s*Unhandled Errors?\s*⎯+\s*\n\s*Error:\s*\[vitest-worker\]:\s*(Timeout[^\n]+)/.exec(output);
323
- if (!timeoutMatch) {
324
- return null;
325
- }
326
- const errorMessage = timeoutMatch[1].trim();
327
- return {
328
- file: 'vitest.config.ts',
329
- location: '',
330
- testHierarchy: 'Vitest Worker Timeout',
331
- errorMessage: `${errorMessage}. This is usually caused by system resource constraints or competing processes. Try: 1) Kill background processes, 2) Reduce --pool-workers, 3) Increase --test-timeout`,
332
- sourceLine: ''
333
- };
334
- }
335
- /**
336
- * Format Vitest test failures
337
- *
338
- * Extracts:
339
- * - Test file and location (file:line:column)
340
- * - Test hierarchy (describe blocks > test name)
341
- * - Assertion error message
342
- * - Source code line that failed
343
- * - Expected vs actual values (when available)
344
- *
345
- * @param output - Raw Vitest/Jest command output
346
- * @param options - Extraction options (e.g., developerFeedback for quality metadata)
347
- * @returns Structured error information with test-specific guidance
348
- *
349
- * @example
350
- * ```typescript
351
- * const result = extractVitestErrors(vitestOutput);
352
- * console.log(result.summary); // "3 test failure(s)"
353
- * console.log(result.guidance); // "Fix each failing test individually..."
354
- * ```
355
- */
356
- // eslint-disable-next-line sonarjs/cognitive-complexity -- Complexity 29 acceptable for Vitest output parsing (down from 97) - main parsing loop coordinates multiple format detection and state tracking
357
- export function extractVitestErrors(output, options) {
358
- const lines = output.split('\n');
359
- const failures = [];
360
- let currentFailure = null;
361
- let currentFile = ''; // Track file from ❯ lines for Format 2
362
- let hasFormat2 = false; // Track if we found Format 2 file headers
363
- // First, check for runtime errors (Unhandled Rejection, ENOENT, etc.)
364
- const runtimeError = extractRuntimeError(output);
365
- if (runtimeError) {
366
- failures.push(runtimeError);
367
- }
368
- // Check for coverage threshold failures
369
- const coverageError = extractCoverageThresholdError(output);
370
- if (coverageError) {
371
- failures.push(coverageError);
372
- }
373
- // Check for Vitest worker timeout errors
374
- const timeoutError = extractVitestWorkerTimeoutError(output);
375
- if (timeoutError) {
376
- failures.push(timeoutError);
377
- }
378
- let i = -1;
379
- while (i < lines.length - 1) {
380
- i++; // Increment at start so 'continue' statements don't bypass it
381
- const line = lines[i];
382
- // Check for Format 2 file header
383
- const fileHeaderMatch = /❯\s+([^\s]+\.test\.ts)\s+\(/.exec(line);
384
- if (fileHeaderMatch) {
385
- currentFile = fileHeaderMatch[1];
386
- hasFormat2 = true;
387
- continue;
388
- }
389
- // Try to parse as failure line (Format 1 or Format 2)
390
- const parsedFailure = parseFailureLine(line, currentFile, hasFormat2);
391
- if (parsedFailure) {
392
- if (currentFailure?.file) {
393
- failures.push(currentFailure);
394
- }
395
- currentFailure = parsedFailure;
396
- continue;
397
- }
398
- // Parse error message if we have a current failure
399
- if (currentFailure && !currentFailure.errorMessage) {
400
- const snapshotMatch = /Snapshot\s+`([^`]+)`\s+mismatched/.exec(line);
401
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Need to check truthy regex matches, not just null/undefined
402
- const hasError = /((?:AssertionError|Error):\s*.+)/.exec(line) || /→\s+(.+)/.exec(line) || snapshotMatch;
403
- if (hasError) {
404
- const isSnapshotError = !!snapshotMatch;
405
- const { errorMessage, lastIndex } = parseErrorMessage(lines, i, isSnapshotError);
406
- currentFailure.errorMessage = errorMessage;
407
- i = lastIndex;
408
- }
409
- continue;
410
- }
411
- // Parse location if we have a current failure
412
- if (currentFailure && !currentFailure.location) {
413
- const location = parseLocation(line);
414
- if (location) {
415
- currentFailure.location = location;
416
- continue;
417
- }
418
- }
419
- // Parse source line
420
- if (currentFailure && /^\s*\d+\|\s+/.exec(line)) {
421
- const sourceMatch = /^\s*(\d+)\|\s*(.+)/.exec(line);
422
- if (sourceMatch) {
423
- currentFailure.sourceLine = `${sourceMatch[1]}| ${sourceMatch[2].trim()}`;
424
- }
425
- }
426
- }
427
- // Add last failure
428
- if (currentFailure?.file) {
429
- failures.push(currentFailure);
430
- }
431
- // Detect timeout failures
432
- const hasTimeout = failures.some(f => f.errorMessage.includes('Test timed out'));
433
- // Extract expected/actual values and format output
434
- const { expected, actual } = extractExpectedActual(output);
435
- const errorSummary = formatFailuresOutput(failures, expected, actual);
436
- const guidance = generateGuidanceText(failures.length, expected, actual, hasTimeout);
437
- const result = {
438
- errors: failures.slice(0, MAX_ERRORS_IN_ARRAY).map(f => {
439
- // Parse line:column from end of location string (file paths may contain colons)
440
- let line;
441
- let column;
442
- if (f.location) {
443
- const parts = f.location.split(':');
444
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Need to filter empty strings for parseInt, not just null/undefined
445
- column = Number.parseInt(parts.pop() || '');
446
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Need to filter empty strings for parseInt, not just null/undefined
447
- line = Number.parseInt(parts.pop() || '');
448
- }
449
- return {
450
- file: f.file,
451
- line: line !== undefined && !Number.isNaN(line) ? line : undefined,
452
- column: column !== undefined && !Number.isNaN(column) ? column : undefined,
453
- message: f.errorMessage
454
- };
455
- }),
456
- summary: `${failures.length} test failure(s)`,
457
- totalErrors: failures.length,
458
- guidance,
459
- errorSummary
460
- };
461
- // Add quality metadata if developer feedback enabled
462
- if (options?.developerFeedback) {
463
- result.metadata = calculateExtractionQuality(failures, options);
464
- }
465
- return result;
466
- }
467
- /**
468
- * Calculate extraction quality metadata
469
- *
470
- * Reports what the extractor knows about its own extraction quality.
471
- * Does NOT know expected count - test infrastructure does the comparison.
472
- *
473
- * @param failures - Extracted test failures
474
- * @param options - Extractor options
475
- * @returns Quality metadata
476
- */
477
- function calculateExtractionQuality(failures, options) {
478
- const withFile = failures.filter(f => f.file && f.file !== 'unknown').length;
479
- const withLocation = failures.filter(f => f.location).length;
480
- const withMessage = failures.filter(f => f.errorMessage).length;
481
- // Completeness: percentage with file + location + message
482
- const complete = failures.filter(f => f.file && f.file !== 'unknown' && f.location && f.errorMessage).length;
483
- const completeness = failures.length > 0
484
- ? Math.round((complete / failures.length) * 100)
485
- : 100;
486
- // Confidence: based on how well patterns matched
487
- // High confidence if most failures have complete data
488
- let confidence;
489
- if (completeness >= 80) {
490
- confidence = 90;
491
- }
492
- else if (completeness >= 50) {
493
- confidence = 70;
494
- }
495
- else {
496
- confidence = 50;
497
- }
498
- // Issues encountered
499
- const issues = [];
500
- if (withFile < failures.length) {
501
- issues.push(`${failures.length - withFile} failure(s) missing file path`);
502
- }
503
- if (withLocation < failures.length) {
504
- issues.push(`${failures.length - withLocation} failure(s) missing line numbers`);
505
- }
506
- if (withMessage < failures.length) {
507
- issues.push(`${failures.length - withMessage} failure(s) missing error messages`);
508
- }
509
- // Suggestions (only if developer feedback enabled)
510
- const suggestions = [];
511
- if (options.developerFeedback) {
512
- if (completeness < 80) {
513
- suggestions.push('Try running Vitest with --reporter=verbose for more complete output');
514
- }
515
- if (failures.length > 20) {
516
- suggestions.push(`Extracted ${failures.length} failures - verify this matches actual test output`);
517
- }
518
- }
519
- return {
520
- confidence,
521
- completeness,
522
- issues,
523
- ...(suggestions.length > 0 && { suggestions })
524
- };
525
- }
526
- /**
527
- * Extract expected/actual values from test output
528
- *
529
- * @param output - Full test output
530
- * @returns Expected and actual values (if found)
531
- */
532
- function extractExpectedActual(fullOutput) {
533
- const expectedMatch = /- Expected[^\n]*\n[^\n]*\n- (.+)/.exec(fullOutput);
534
- const actualMatch = /\+ Received[^\n]*\n[^\n]*\n\+ (.+)/.exec(fullOutput);
535
- return {
536
- expected: expectedMatch ? expectedMatch[1].trim() : undefined,
537
- actual: actualMatch ? actualMatch[1].trim() : undefined
538
- };
539
- }
540
- //# sourceMappingURL=vitest-extractor.js.map