@vibe-validate/extractors 0.14.2 → 0.15.0-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.
- package/dist/ava-extractor.js +35 -39
- package/dist/ava-extractor.js.map +1 -1
- package/dist/eslint-extractor.d.ts.map +1 -1
- package/dist/eslint-extractor.js +16 -14
- package/dist/eslint-extractor.js.map +1 -1
- package/dist/generic-extractor.d.ts +16 -10
- package/dist/generic-extractor.d.ts.map +1 -1
- package/dist/generic-extractor.js +106 -29
- package/dist/generic-extractor.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/jasmine-extractor.d.ts.map +1 -1
- package/dist/jasmine-extractor.js +25 -20
- package/dist/jasmine-extractor.js.map +1 -1
- package/dist/jest-extractor.d.ts.map +1 -1
- package/dist/jest-extractor.js +118 -64
- package/dist/jest-extractor.js.map +1 -1
- package/dist/junit-extractor.d.ts.map +1 -1
- package/dist/junit-extractor.js +41 -50
- package/dist/junit-extractor.js.map +1 -1
- package/dist/mocha-extractor.d.ts.map +1 -1
- package/dist/mocha-extractor.js +26 -21
- package/dist/mocha-extractor.js.map +1 -1
- package/dist/playwright-extractor.d.ts.map +1 -1
- package/dist/playwright-extractor.js +24 -14
- package/dist/playwright-extractor.js.map +1 -1
- package/dist/result-schema-export.d.ts +29 -0
- package/dist/result-schema-export.d.ts.map +1 -0
- package/dist/result-schema-export.js +37 -0
- package/dist/result-schema-export.js.map +1 -0
- package/dist/result-schema.d.ts +349 -0
- package/dist/result-schema.d.ts.map +1 -0
- package/dist/result-schema.js +139 -0
- package/dist/result-schema.js.map +1 -0
- package/dist/scripts/generate-result-schema.d.ts +10 -0
- package/dist/scripts/generate-result-schema.d.ts.map +1 -0
- package/dist/scripts/generate-result-schema.js +20 -0
- package/dist/scripts/generate-result-schema.js.map +1 -0
- package/dist/smart-extractor.d.ts +17 -20
- package/dist/smart-extractor.d.ts.map +1 -1
- package/dist/smart-extractor.js +116 -80
- package/dist/smart-extractor.js.map +1 -1
- package/dist/tap-extractor.js +18 -13
- package/dist/tap-extractor.js.map +1 -1
- package/dist/types.d.ts +18 -65
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/dist/typescript-extractor.d.ts.map +1 -1
- package/dist/typescript-extractor.js +13 -10
- package/dist/typescript-extractor.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -1
- package/dist/utils.js.map +1 -1
- package/dist/vitest-extractor.d.ts.map +1 -1
- package/dist/vitest-extractor.js +310 -163
- package/dist/vitest-extractor.js.map +1 -1
- package/error-extractor-result.schema.json +134 -0
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -17,12 +17,14 @@
|
|
|
17
17
|
* const result = autoDetectAndExtract('TypeScript Type Checking', tscOutput);
|
|
18
18
|
* console.log(result.summary); // "3 type error(s), 0 warning(s)"
|
|
19
19
|
* console.log(result.guidance); // "Type mismatch - check variable/parameter types"
|
|
20
|
-
* console.log(result.
|
|
20
|
+
* console.log(result.errorSummary); // Clean, formatted error list
|
|
21
21
|
* ```
|
|
22
22
|
*
|
|
23
23
|
* @package @vibe-validate/extractors
|
|
24
24
|
* @version 0.1.0
|
|
25
25
|
*/
|
|
26
|
+
// Zod schemas for runtime validation
|
|
27
|
+
export { FormattedErrorSchema, ErrorExtractorResultSchema, DetectionMetadataSchema, ExtractionMetadataSchema, safeValidateExtractorResult, validateExtractorResult, } from './result-schema.js';
|
|
26
28
|
// Individual extractors (for direct use)
|
|
27
29
|
export { extractTypeScriptErrors } from './typescript-extractor.js';
|
|
28
30
|
export { extractESLintErrors } from './eslint-extractor.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAaH,qCAAqC;AACrC,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAE5B,yCAAyC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,iDAAiD;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,YAAY;AACZ,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jasmine-extractor.d.ts","sourceRoot":"","sources":["../src/jasmine-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAsC,MAAM,YAAY,CAAC;AAE3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,
|
|
1
|
+
{"version":3,"file":"jasmine-extractor.d.ts","sourceRoot":"","sources":["../src/jasmine-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAsC,MAAM,YAAY,CAAC;AAE3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAuFzE"}
|
|
@@ -25,8 +25,8 @@ export function extractJasmineErrors(output) {
|
|
|
25
25
|
return {
|
|
26
26
|
summary: 'Unable to parse Jasmine output - invalid format',
|
|
27
27
|
errors: [],
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
totalErrors: 0,
|
|
29
|
+
errorSummary: output.trim(),
|
|
30
30
|
guidance: 'Ensure the input is valid Jasmine test output',
|
|
31
31
|
metadata: {
|
|
32
32
|
confidence: 0,
|
|
@@ -36,14 +36,15 @@ export function extractJasmineErrors(output) {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
// Extract failure count
|
|
39
|
-
|
|
40
|
-
const
|
|
39
|
+
// eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Jasmine test framework summary (controlled output), not user input
|
|
40
|
+
const failureMatch = /(\d+) spec(?:s)?, (\d+) failure(?:s)?/.exec(output);
|
|
41
|
+
const failureCount = failureMatch ? Number.parseInt(failureMatch[2], 10) : 0;
|
|
41
42
|
if (failureCount === 0) {
|
|
42
43
|
return {
|
|
43
44
|
summary: '0 test(s) failed',
|
|
44
45
|
errors: [],
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
totalErrors: 0,
|
|
47
|
+
errorSummary: '',
|
|
47
48
|
guidance: '',
|
|
48
49
|
metadata: {
|
|
49
50
|
confidence: 100,
|
|
@@ -57,9 +58,9 @@ export function extractJasmineErrors(output) {
|
|
|
57
58
|
const errors = [];
|
|
58
59
|
let completeCount = 0;
|
|
59
60
|
for (const failure of failures) {
|
|
60
|
-
const file = failure.file
|
|
61
|
-
const message = failure.message
|
|
62
|
-
const context = failure.testName
|
|
61
|
+
const file = failure.file ?? 'unknown';
|
|
62
|
+
const message = failure.message ?? 'Test failed';
|
|
63
|
+
const context = failure.testName ?? '';
|
|
63
64
|
const isComplete = file !== 'unknown' && failure.line && message;
|
|
64
65
|
if (isComplete) {
|
|
65
66
|
completeCount++;
|
|
@@ -86,8 +87,8 @@ export function extractJasmineErrors(output) {
|
|
|
86
87
|
return {
|
|
87
88
|
summary,
|
|
88
89
|
errors,
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
totalErrors: failures.length,
|
|
91
|
+
errorSummary: formatCleanOutput(errors),
|
|
91
92
|
guidance,
|
|
92
93
|
metadata
|
|
93
94
|
};
|
|
@@ -95,6 +96,7 @@ export function extractJasmineErrors(output) {
|
|
|
95
96
|
/**
|
|
96
97
|
* Extract failure information from Jasmine output
|
|
97
98
|
*/
|
|
99
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- Complexity 28 acceptable for Jasmine output parsing (handles numbered failures, message extraction, and stack trace parsing)
|
|
98
100
|
function extractFailures(output) {
|
|
99
101
|
const failures = [];
|
|
100
102
|
const lines = output.split('\n');
|
|
@@ -102,7 +104,8 @@ function extractFailures(output) {
|
|
|
102
104
|
while (i < lines.length) {
|
|
103
105
|
const line = lines[i];
|
|
104
106
|
// Look for numbered failure markers (e.g., "1) Test name")
|
|
105
|
-
|
|
107
|
+
// eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Jasmine test framework output (controlled output), not user input
|
|
108
|
+
const failureMatch = /^(\d+)\)\s+(.+)$/.exec(line);
|
|
106
109
|
if (failureMatch) {
|
|
107
110
|
// failureMatch[1] contains the failure number (not used - line number extracted from stack trace instead)
|
|
108
111
|
const testName = failureMatch[2].trim();
|
|
@@ -115,7 +118,7 @@ function extractFailures(output) {
|
|
|
115
118
|
while (j < lines.length && j < i + 30) {
|
|
116
119
|
const nextLine = lines[j];
|
|
117
120
|
// Stop if we hit the next failure
|
|
118
|
-
if (
|
|
121
|
+
if (/^\d+\)\s+/.exec(nextLine)) {
|
|
119
122
|
break;
|
|
120
123
|
}
|
|
121
124
|
// Extract message (comes after " Message:" line)
|
|
@@ -133,7 +136,7 @@ function extractFailures(output) {
|
|
|
133
136
|
}
|
|
134
137
|
message = messageLines.join(' ').trim();
|
|
135
138
|
// Extract error type if present (e.g., "TypeError:", "Error:")
|
|
136
|
-
const errorMatch =
|
|
139
|
+
const errorMatch = /^([A-Za-z]*Error):\s*/.exec(message);
|
|
137
140
|
if (errorMatch) {
|
|
138
141
|
errorType = errorMatch[1];
|
|
139
142
|
}
|
|
@@ -146,24 +149,25 @@ function extractFailures(output) {
|
|
|
146
149
|
while (j < lines.length && j < i + 40) {
|
|
147
150
|
const stackLine = lines[j];
|
|
148
151
|
// Stop if we hit the next failure or empty section
|
|
149
|
-
if (
|
|
152
|
+
if (/^\d+\)\s+/.exec(stackLine) || (stackLine.trim() === '' && /^\d+\)\s+/.exec(lines[j + 1] ?? ''))) {
|
|
150
153
|
break;
|
|
151
154
|
}
|
|
152
155
|
// Extract file from UserContext.<anonymous> stack lines
|
|
153
156
|
if (stackLine.includes('UserContext.<anonymous>')) {
|
|
154
|
-
const locationMatch =
|
|
157
|
+
const locationMatch = /UserContext\.<anonymous> \(([^:)]+):(\d+)(?::(\d+))?\)/.exec(stackLine);
|
|
155
158
|
if (locationMatch) {
|
|
156
159
|
file = locationMatch[1];
|
|
157
|
-
lineNumber = parseInt(locationMatch[2], 10);
|
|
160
|
+
lineNumber = Number.parseInt(locationMatch[2], 10);
|
|
158
161
|
break;
|
|
159
162
|
}
|
|
160
163
|
}
|
|
161
164
|
// Also try Object.* patterns
|
|
162
165
|
if (!file && stackLine.includes(' (') && stackLine.includes('.js:')) {
|
|
163
|
-
|
|
166
|
+
// eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Jasmine test framework stack traces (controlled output), not user input
|
|
167
|
+
const altMatch = /\(([^:)]+):(\d+)(?::(\d+))?\)/.exec(stackLine);
|
|
164
168
|
if (altMatch) {
|
|
165
169
|
file = altMatch[1];
|
|
166
|
-
lineNumber = parseInt(altMatch[2], 10);
|
|
170
|
+
lineNumber = Number.parseInt(altMatch[2], 10);
|
|
167
171
|
break;
|
|
168
172
|
}
|
|
169
173
|
}
|
|
@@ -191,11 +195,12 @@ function extractFailures(output) {
|
|
|
191
195
|
/**
|
|
192
196
|
* Generate guidance based on failure types
|
|
193
197
|
*/
|
|
198
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- Complexity 16 acceptable for guidance generation (categorizes multiple error types and generates actionable suggestions)
|
|
194
199
|
function generateGuidance(failures) {
|
|
195
200
|
const guidances = [];
|
|
196
201
|
const seen = new Set();
|
|
197
202
|
for (const failure of failures) {
|
|
198
|
-
const message = failure.message
|
|
203
|
+
const message = failure.message ?? '';
|
|
199
204
|
const errorType = failure.errorType;
|
|
200
205
|
// Assertion errors
|
|
201
206
|
if (message.includes('Expected') || message.includes('expected')) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jasmine-extractor.js","sourceRoot":"","sources":["../src/jasmine-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,gEAAgE;IAEhE,0CAA0C;IAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9D,OAAO;YACL,OAAO,EAAE,iDAAiD;YAC1D,MAAM,EAAE,EAAE;YACV,
|
|
1
|
+
{"version":3,"file":"jasmine-extractor.js","sourceRoot":"","sources":["../src/jasmine-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jest-extractor.d.ts","sourceRoot":"","sources":["../src/jest-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"jest-extractor.d.ts","sourceRoot":"","sources":["../src/jest-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA0IvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAoDtE"}
|
package/dist/jest-extractor.js
CHANGED
|
@@ -5,6 +5,109 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @package @vibe-validate/extractors
|
|
7
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* Match FAIL line and extract file path
|
|
10
|
+
*/
|
|
11
|
+
function matchFailLine(line) {
|
|
12
|
+
const failMatch = /^\s*FAIL\s+(?:[\w-]+\s+)?([\w/-]+\.test\.\w+)/.exec(line);
|
|
13
|
+
return failMatch ? failMatch[1] : null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Match inline failure (✕) and extract test name
|
|
17
|
+
*/
|
|
18
|
+
function matchInlineFailure(line) {
|
|
19
|
+
// eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Jest test framework output (controlled output), not user input
|
|
20
|
+
const failureMatch = /^\s+✕\s+(.+?)(?:\s+\(\d+\s*ms\))?$/.exec(line);
|
|
21
|
+
return failureMatch ? failureMatch[1].trim() : null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Match detailed test format (●) and extract hierarchy
|
|
25
|
+
*/
|
|
26
|
+
function matchDetailedTest(line) {
|
|
27
|
+
// eslint-disable-next-line sonarjs/slow-regex -- Safe: only parses Jest test framework output (controlled output), not user input
|
|
28
|
+
const detailedTestMatch = /^\s*●\s+(.+)$/.exec(line);
|
|
29
|
+
return detailedTestMatch ? detailedTestMatch[1].trim() : null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Match test suite line and extract suite info
|
|
33
|
+
*/
|
|
34
|
+
function matchSuiteLine(line) {
|
|
35
|
+
const suiteMatch = /^\s+([A-Z][\w\s›-]+)$/.exec(line);
|
|
36
|
+
if (!suiteMatch || line.includes('✕') || line.includes('✓') || line.includes('ms)')) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const indentMatch = /^(\s*)/.exec(line);
|
|
40
|
+
const indent = indentMatch ? indentMatch[1].length : 0;
|
|
41
|
+
return { name: suiteMatch[1].trim(), indent };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Adjust hierarchy stack based on indentation level
|
|
45
|
+
*/
|
|
46
|
+
function adjustHierarchyForIndent(hierarchyStack, indent) {
|
|
47
|
+
while (hierarchyStack.length > 0 && indent <= hierarchyStack.length * 2) {
|
|
48
|
+
hierarchyStack.pop();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Process a single line of Jest output
|
|
53
|
+
*/
|
|
54
|
+
function processLine(line, currentFile, hierarchyStack) {
|
|
55
|
+
const result = {};
|
|
56
|
+
// Check for FAIL line
|
|
57
|
+
const newFile = matchFailLine(line);
|
|
58
|
+
if (newFile) {
|
|
59
|
+
result.newFile = newFile;
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
// Skip lines before we have a file
|
|
63
|
+
if (!currentFile) {
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
// Check for inline failure (✕)
|
|
67
|
+
const inlineTest = matchInlineFailure(line);
|
|
68
|
+
if (inlineTest) {
|
|
69
|
+
const fullHierarchy = hierarchyStack.length > 0
|
|
70
|
+
? [...hierarchyStack, inlineTest].join(' › ')
|
|
71
|
+
: inlineTest;
|
|
72
|
+
result.failure = {
|
|
73
|
+
file: currentFile,
|
|
74
|
+
location: currentFile,
|
|
75
|
+
testHierarchy: fullHierarchy,
|
|
76
|
+
errorMessage: 'Test failed'
|
|
77
|
+
};
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
// Check for detailed test format (●)
|
|
81
|
+
const detailedHierarchy = matchDetailedTest(line);
|
|
82
|
+
if (detailedHierarchy) {
|
|
83
|
+
result.failure = {
|
|
84
|
+
file: currentFile,
|
|
85
|
+
location: currentFile,
|
|
86
|
+
testHierarchy: detailedHierarchy,
|
|
87
|
+
errorMessage: 'Test failed'
|
|
88
|
+
};
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
// Check for suite line
|
|
92
|
+
const suiteInfo = matchSuiteLine(line);
|
|
93
|
+
if (suiteInfo) {
|
|
94
|
+
result.newSuite = suiteInfo;
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Format failures into clean output string
|
|
100
|
+
*/
|
|
101
|
+
function formatJestFailures(failures) {
|
|
102
|
+
const errorSummaryLines = [];
|
|
103
|
+
for (const failure of failures) {
|
|
104
|
+
errorSummaryLines.push(`● ${failure.testHierarchy}`);
|
|
105
|
+
errorSummaryLines.push(` ${failure.errorMessage}`);
|
|
106
|
+
errorSummaryLines.push(` Location: ${failure.location}`);
|
|
107
|
+
errorSummaryLines.push('');
|
|
108
|
+
}
|
|
109
|
+
return errorSummaryLines.join('\n');
|
|
110
|
+
}
|
|
8
111
|
/**
|
|
9
112
|
* Extract Jest test failures
|
|
10
113
|
*
|
|
@@ -29,70 +132,28 @@ export function extractJestErrors(output) {
|
|
|
29
132
|
const lines = output.split('\n');
|
|
30
133
|
const failures = [];
|
|
31
134
|
let currentFile = '';
|
|
32
|
-
const hierarchyStack = [];
|
|
33
|
-
for (
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const failMatch = line.match(/^\s*FAIL\s+(?:[\w-]+\s+)?([\w/-]+\.test\.\w+)/);
|
|
39
|
-
if (failMatch) {
|
|
40
|
-
currentFile = failMatch[1];
|
|
41
|
-
hierarchyStack.length = 0; // Reset hierarchy for new file
|
|
135
|
+
const hierarchyStack = [];
|
|
136
|
+
for (const line of lines) {
|
|
137
|
+
const result = processLine(line, currentFile, hierarchyStack);
|
|
138
|
+
if (result.newFile) {
|
|
139
|
+
currentFile = result.newFile;
|
|
140
|
+
hierarchyStack.length = 0;
|
|
42
141
|
continue;
|
|
43
142
|
}
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
// Calculate indentation level (number of leading spaces)
|
|
47
|
-
const indentMatch = line.match(/^(\s*)/);
|
|
48
|
-
const indent = indentMatch ? indentMatch[1].length : 0;
|
|
49
|
-
// Match: ✕ test name (6 ms) - inline failure
|
|
50
|
-
const failureMatch = line.match(/^\s+✕\s+(.+?)(?:\s+\(\d+\s*ms\))?$/);
|
|
51
|
-
if (failureMatch) {
|
|
52
|
-
const testName = failureMatch[1].trim();
|
|
53
|
-
// Build full hierarchy: parent suites + test name
|
|
54
|
-
const fullHierarchy = hierarchyStack.length > 0
|
|
55
|
-
? [...hierarchyStack, testName].join(' › ')
|
|
56
|
-
: testName;
|
|
57
|
-
failures.push({
|
|
58
|
-
file: currentFile,
|
|
59
|
-
location: currentFile,
|
|
60
|
-
testHierarchy: fullHierarchy,
|
|
61
|
-
errorMessage: 'Test failed'
|
|
62
|
-
});
|
|
143
|
+
if (result.failure) {
|
|
144
|
+
failures.push(result.failure);
|
|
63
145
|
continue;
|
|
64
146
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const fullHierarchy = detailedTestMatch[1].trim();
|
|
69
|
-
failures.push({
|
|
70
|
-
file: currentFile,
|
|
71
|
-
location: currentFile,
|
|
72
|
-
testHierarchy: fullHierarchy,
|
|
73
|
-
errorMessage: 'Test failed'
|
|
74
|
-
});
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
// Track test suite hierarchy (lines that are just text, no symbols)
|
|
78
|
-
// These are describe blocks like "Vibe-Validate Integration Failures"
|
|
79
|
-
const suiteMatch = line.match(/^\s+([A-Z][\w\s›-]+)$/);
|
|
80
|
-
if (suiteMatch && !line.includes('✕') && !line.includes('✓') && !line.includes('ms)')) {
|
|
81
|
-
const suiteName = suiteMatch[1].trim();
|
|
82
|
-
// Adjust hierarchy stack based on indentation
|
|
83
|
-
// If indent decreased, pop suites until we're at the right level
|
|
84
|
-
while (hierarchyStack.length > 0 && indent <= hierarchyStack.length * 2) {
|
|
85
|
-
hierarchyStack.pop();
|
|
86
|
-
}
|
|
87
|
-
// Add this suite to the stack
|
|
88
|
-
hierarchyStack.push(suiteName);
|
|
147
|
+
if (result.newSuite) {
|
|
148
|
+
adjustHierarchyForIndent(hierarchyStack, result.newSuite.indent);
|
|
149
|
+
hierarchyStack.push(result.newSuite.name);
|
|
89
150
|
}
|
|
90
151
|
}
|
|
91
152
|
// Build formatted errors
|
|
92
153
|
const errors = failures.map(f => ({
|
|
93
154
|
file: f.file,
|
|
94
|
-
line: parseInt(f.location.split(':')[1] || '0'),
|
|
95
|
-
column: parseInt(f.location.split(':')[2] || '0'),
|
|
155
|
+
line: Number.parseInt(f.location.split(':')[1] || '0'),
|
|
156
|
+
column: Number.parseInt(f.location.split(':')[2] || '0'),
|
|
96
157
|
message: `${f.testHierarchy}: ${f.errorMessage}`,
|
|
97
158
|
severity: 'error'
|
|
98
159
|
}));
|
|
@@ -102,19 +163,12 @@ export function extractJestErrors(output) {
|
|
|
102
163
|
const guidance = failures.length > 0
|
|
103
164
|
? 'Fix each failing test individually. Check test setup, mocks, and assertions.'
|
|
104
165
|
: '';
|
|
105
|
-
const cleanOutputLines = [];
|
|
106
|
-
for (const failure of failures) {
|
|
107
|
-
cleanOutputLines.push(`● ${failure.testHierarchy}`);
|
|
108
|
-
cleanOutputLines.push(` ${failure.errorMessage}`);
|
|
109
|
-
cleanOutputLines.push(` Location: ${failure.location}`);
|
|
110
|
-
cleanOutputLines.push('');
|
|
111
|
-
}
|
|
112
166
|
return {
|
|
113
167
|
errors,
|
|
114
168
|
summary,
|
|
115
|
-
|
|
169
|
+
totalErrors: failures.length,
|
|
116
170
|
guidance,
|
|
117
|
-
|
|
171
|
+
errorSummary: formatJestFailures(failures)
|
|
118
172
|
};
|
|
119
173
|
}
|
|
120
174
|
//# sourceMappingURL=jest-extractor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jest-extractor.js","sourceRoot":"","sources":["../src/jest-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"jest-extractor.js","sourceRoot":"","sources":["../src/jest-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"junit-extractor.d.ts","sourceRoot":"","sources":["../src/junit-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAsC,MAAM,YAAY,CAAC;AAE3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,
|
|
1
|
+
{"version":3,"file":"junit-extractor.d.ts","sourceRoot":"","sources":["../src/junit-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAsC,MAAM,YAAY,CAAC;AAE3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAgGvE"}
|
package/dist/junit-extractor.js
CHANGED
|
@@ -27,12 +27,13 @@ export function extractJUnitErrors(output) {
|
|
|
27
27
|
// Simple XML parsing - look for <testsuite> and <testcase> elements
|
|
28
28
|
isValidXml = parseSimpleXML(output);
|
|
29
29
|
}
|
|
30
|
-
catch (
|
|
30
|
+
catch (error) {
|
|
31
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
31
32
|
return {
|
|
32
|
-
summary:
|
|
33
|
+
summary: `Unable to parse JUnit XML - invalid format: ${errorMsg}`,
|
|
33
34
|
errors: [],
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
totalErrors: 0,
|
|
36
|
+
errorSummary: output.trim(),
|
|
36
37
|
guidance: 'Ensure the input is valid JUnit XML format',
|
|
37
38
|
metadata: {
|
|
38
39
|
confidence: 0,
|
|
@@ -45,8 +46,8 @@ export function extractJUnitErrors(output) {
|
|
|
45
46
|
return {
|
|
46
47
|
summary: '0 test(s) failed',
|
|
47
48
|
errors: [],
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
totalErrors: 0,
|
|
50
|
+
errorSummary: '',
|
|
50
51
|
guidance: '',
|
|
51
52
|
metadata: {
|
|
52
53
|
confidence: 100,
|
|
@@ -60,10 +61,10 @@ export function extractJUnitErrors(output) {
|
|
|
60
61
|
const errors = [];
|
|
61
62
|
let completeCount = 0;
|
|
62
63
|
for (const failure of failures) {
|
|
63
|
-
const file = failure.file
|
|
64
|
-
const location = failure.location
|
|
65
|
-
const message = failure.message
|
|
66
|
-
const context = failure.testName
|
|
64
|
+
const file = failure.file ?? 'unknown';
|
|
65
|
+
const location = failure.location ?? `${file}:0`;
|
|
66
|
+
const message = failure.message ?? 'Test failed';
|
|
67
|
+
const context = failure.testName ?? '';
|
|
67
68
|
const isComplete = file !== 'unknown' && failure.location && message;
|
|
68
69
|
if (isComplete) {
|
|
69
70
|
completeCount++;
|
|
@@ -72,7 +73,7 @@ export function extractJUnitErrors(output) {
|
|
|
72
73
|
let line;
|
|
73
74
|
if (location) {
|
|
74
75
|
const locationParts = location.split(':');
|
|
75
|
-
line = locationParts[1] ? parseInt(locationParts[1], 10) : undefined;
|
|
76
|
+
line = locationParts[1] ? Number.parseInt(locationParts[1], 10) : undefined;
|
|
76
77
|
}
|
|
77
78
|
errors.push({
|
|
78
79
|
file,
|
|
@@ -97,8 +98,8 @@ export function extractJUnitErrors(output) {
|
|
|
97
98
|
return {
|
|
98
99
|
summary,
|
|
99
100
|
errors,
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
totalErrors: failures.length,
|
|
102
|
+
errorSummary: formatCleanOutput(errors),
|
|
102
103
|
guidance,
|
|
103
104
|
metadata
|
|
104
105
|
};
|
|
@@ -119,66 +120,55 @@ function parseSimpleXML(xml) {
|
|
|
119
120
|
// Return that XML is valid
|
|
120
121
|
return true;
|
|
121
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Extract attribute value from XML tag
|
|
125
|
+
*/
|
|
126
|
+
function extractXmlAttribute(tag, attrName) {
|
|
127
|
+
const idx = tag.indexOf(`${attrName}="`);
|
|
128
|
+
if (idx === -1)
|
|
129
|
+
return undefined;
|
|
130
|
+
const start = idx + `${attrName}="`.length;
|
|
131
|
+
const end = tag.indexOf('"', start);
|
|
132
|
+
return tag.substring(start, end);
|
|
133
|
+
}
|
|
122
134
|
function extractFailures(xml) {
|
|
123
135
|
const failures = [];
|
|
124
|
-
// Match all <testcase> elements with <failure> children
|
|
125
136
|
const testcasePattern = /<testcase[^>]*>([\s\S]*?)<\/testcase>/g;
|
|
126
137
|
let testcaseMatch;
|
|
127
138
|
while ((testcaseMatch = testcasePattern.exec(xml)) !== null) {
|
|
128
139
|
const testcaseContent = testcaseMatch[0];
|
|
129
140
|
const testcaseInner = testcaseMatch[1];
|
|
130
|
-
//
|
|
141
|
+
// Skip passing tests
|
|
131
142
|
if (!testcaseInner.includes('<failure')) {
|
|
132
|
-
continue;
|
|
143
|
+
continue;
|
|
133
144
|
}
|
|
134
|
-
// Extract
|
|
135
|
-
const testcaseTagMatch =
|
|
145
|
+
// Extract testcase tag attributes
|
|
146
|
+
const testcaseTagMatch = /<testcase([^>]*)>/.exec(testcaseContent);
|
|
136
147
|
const testcaseTag = testcaseTagMatch ? testcaseTagMatch[1] : '';
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const classnameIdx = testcaseTag.indexOf('classname="');
|
|
140
|
-
if (classnameIdx !== -1) {
|
|
141
|
-
const start = classnameIdx + 'classname="'.length;
|
|
142
|
-
const end = testcaseTag.indexOf('"', start);
|
|
143
|
-
file = testcaseTag.substring(start, end);
|
|
144
|
-
}
|
|
145
|
-
// Extract name (test hierarchy) similarly
|
|
146
|
-
let testName;
|
|
147
|
-
const nameIdx = testcaseTag.indexOf('name="');
|
|
148
|
-
if (nameIdx !== -1) {
|
|
149
|
-
const start = nameIdx + 'name="'.length;
|
|
150
|
-
const end = testcaseTag.indexOf('"', start);
|
|
151
|
-
testName = testcaseTag.substring(start, end);
|
|
152
|
-
}
|
|
148
|
+
const file = extractXmlAttribute(testcaseTag, 'classname');
|
|
149
|
+
const testName = extractXmlAttribute(testcaseTag, 'name');
|
|
153
150
|
// Extract failure element
|
|
154
151
|
const failurePattern = /<failure[^>]*>([\s\S]*?)<\/failure>/;
|
|
155
|
-
const failureMatch =
|
|
152
|
+
const failureMatch = failurePattern.exec(testcaseInner);
|
|
156
153
|
if (!failureMatch) {
|
|
157
154
|
continue;
|
|
158
155
|
}
|
|
159
156
|
const failureContent = failureMatch[0];
|
|
160
157
|
const failureText = failureMatch[1];
|
|
161
|
-
// Extract
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
// Extract error type
|
|
165
|
-
const typeMatch = failureContent.match(/type="([^"]+)"/);
|
|
166
|
-
const errorType = typeMatch ? typeMatch[1] : undefined;
|
|
158
|
+
// Extract failure attributes
|
|
159
|
+
const message = extractXmlAttribute(failureContent, 'message');
|
|
160
|
+
const errorType = extractXmlAttribute(failureContent, 'type');
|
|
167
161
|
// Extract location from failure text (❯ file:line:column)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const locationPattern = /❯\s+([\w/._-]+):(\d+)(?::\d+)?/;
|
|
171
|
-
const locationMatch = failureText.match(locationPattern);
|
|
162
|
+
const locationPattern = /❯\s+([\w/.-]+):(\d+)(?::\d+)?/;
|
|
163
|
+
const locationMatch = locationPattern.exec(failureText);
|
|
172
164
|
let location;
|
|
173
165
|
let extractedFile;
|
|
174
166
|
if (locationMatch) {
|
|
175
167
|
extractedFile = locationMatch[1];
|
|
176
|
-
|
|
177
|
-
location = `${extractedFile}:${line}`;
|
|
168
|
+
location = `${extractedFile}:${locationMatch[2]}`;
|
|
178
169
|
}
|
|
179
|
-
// No fallback - if no location found in failure text, leave location undefined
|
|
180
170
|
failures.push({
|
|
181
|
-
file: extractedFile
|
|
171
|
+
file: extractedFile ?? file,
|
|
182
172
|
location,
|
|
183
173
|
message,
|
|
184
174
|
testName,
|
|
@@ -201,11 +191,12 @@ function decodeHtmlEntities(text) {
|
|
|
201
191
|
/**
|
|
202
192
|
* Generate guidance based on failure types
|
|
203
193
|
*/
|
|
194
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- Complexity 16 acceptable for guidance generation (categorizes multiple error types and generates actionable suggestions)
|
|
204
195
|
function generateGuidance(failures) {
|
|
205
196
|
const guidances = [];
|
|
206
197
|
const seen = new Set();
|
|
207
198
|
for (const failure of failures) {
|
|
208
|
-
const message = failure.message
|
|
199
|
+
const message = failure.message ?? '';
|
|
209
200
|
const errorType = failure.errorType;
|
|
210
201
|
// Assertion errors
|
|
211
202
|
if (errorType === 'AssertionError' || message.includes('expected')) {
|