@vibe-validate/extractors 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -9
- package/dist/ava-extractor.d.ts +24 -0
- package/dist/ava-extractor.d.ts.map +1 -0
- package/dist/ava-extractor.js +367 -0
- package/dist/ava-extractor.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/jasmine-extractor.d.ts +23 -0
- package/dist/jasmine-extractor.d.ts.map +1 -0
- package/dist/jasmine-extractor.js +254 -0
- package/dist/jasmine-extractor.js.map +1 -0
- package/dist/jest-extractor.d.ts +29 -0
- package/dist/jest-extractor.d.ts.map +1 -0
- package/dist/jest-extractor.js +115 -0
- package/dist/jest-extractor.js.map +1 -0
- package/dist/junit-extractor.d.ts +24 -0
- package/dist/junit-extractor.d.ts.map +1 -0
- package/dist/junit-extractor.js +264 -0
- package/dist/junit-extractor.js.map +1 -0
- package/dist/mocha-extractor.d.ts +23 -0
- package/dist/mocha-extractor.d.ts.map +1 -0
- package/dist/mocha-extractor.js +263 -0
- package/dist/mocha-extractor.js.map +1 -0
- package/dist/playwright-extractor.d.ts +38 -0
- package/dist/playwright-extractor.d.ts.map +1 -0
- package/dist/playwright-extractor.js +230 -0
- package/dist/playwright-extractor.js.map +1 -0
- package/dist/smart-extractor.d.ts +9 -0
- package/dist/smart-extractor.d.ts.map +1 -1
- package/dist/smart-extractor.js +25 -0
- package/dist/smart-extractor.js.map +1 -1
- package/dist/tap-extractor.d.ts +24 -0
- package/dist/tap-extractor.d.ts.map +1 -0
- package/dist/tap-extractor.js +227 -0
- package/dist/tap-extractor.js.map +1 -0
- package/dist/types.d.ts +21 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vitest-extractor.d.ts +9 -1
- package/dist/vitest-extractor.d.ts.map +1 -1
- package/dist/vitest-extractor.js +112 -16
- package/dist/vitest-extractor.js.map +1 -1
- package/package.json +3 -5
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Test Error Extractor
|
|
3
|
+
*
|
|
4
|
+
* Extracts error information from Playwright test output.
|
|
5
|
+
*
|
|
6
|
+
* Output format:
|
|
7
|
+
* ```
|
|
8
|
+
* Running N tests using M workers
|
|
9
|
+
*
|
|
10
|
+
* ✘ 1 test.spec.ts:10:5 › Describe › test name (100ms)
|
|
11
|
+
* ✓ 2 test.spec.ts:20:5 › passing test (50ms)
|
|
12
|
+
*
|
|
13
|
+
* 1) test.spec.ts:10:5 › Describe › test name
|
|
14
|
+
*
|
|
15
|
+
* Error: expect(received).toBe(expected)
|
|
16
|
+
*
|
|
17
|
+
* Expected: "foo"
|
|
18
|
+
* Received: "bar"
|
|
19
|
+
*
|
|
20
|
+
* 10 | test('test name', async () => {
|
|
21
|
+
* 11 | const value = 'bar';
|
|
22
|
+
* > 12 | expect(value).toBe('foo');
|
|
23
|
+
* | ^
|
|
24
|
+
* 13 | });
|
|
25
|
+
*
|
|
26
|
+
* at test.spec.ts:12:21
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import { stripAnsiCodes } from './utils.js';
|
|
30
|
+
/**
|
|
31
|
+
* Extract errors from Playwright test output
|
|
32
|
+
*/
|
|
33
|
+
export function extractPlaywrightErrors(output) {
|
|
34
|
+
const errors = [];
|
|
35
|
+
const issues = [];
|
|
36
|
+
// Strip ANSI codes for clean parsing
|
|
37
|
+
const cleanOutput = stripAnsiCodes(output);
|
|
38
|
+
// Split into lines for processing
|
|
39
|
+
const lines = cleanOutput.split('\n');
|
|
40
|
+
// Parse numbered failure blocks: " 1) tests/path/test.spec.ts:10:5 › test name"
|
|
41
|
+
let i = 0;
|
|
42
|
+
while (i < lines.length) {
|
|
43
|
+
const line = lines[i];
|
|
44
|
+
// Match numbered failure header: " 1) tests/path/test.spec.ts:10:5 › test name"
|
|
45
|
+
// File path can include directories: "tests/playwright/test.spec.ts" or just "test.spec.ts"
|
|
46
|
+
// Allow trailing whitespace
|
|
47
|
+
const failureMatch = line.match(/^\s+(\d+)\)\s+(.*\.spec\.ts):(\d+):(\d+)\s+›\s+(.+?)\s*$/);
|
|
48
|
+
if (failureMatch) {
|
|
49
|
+
const [, , file, , , testName] = failureMatch;
|
|
50
|
+
// Extract error block (everything until next numbered failure or end)
|
|
51
|
+
const errorLines = [];
|
|
52
|
+
i++;
|
|
53
|
+
while (i < lines.length) {
|
|
54
|
+
const nextLine = lines[i];
|
|
55
|
+
// Stop at next numbered failure
|
|
56
|
+
if (nextLine.match(/^\s+\d+\)\s+/)) {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
errorLines.push(nextLine);
|
|
60
|
+
i++;
|
|
61
|
+
}
|
|
62
|
+
// Parse the error block
|
|
63
|
+
const errorBlock = errorLines.join('\n');
|
|
64
|
+
// Extract error message (first Error: line and subsequent details)
|
|
65
|
+
const errorMessageMatch = errorBlock.match(/Error:\s*(.+?)(?:\n\n|\n(?=\s+at\s))/s);
|
|
66
|
+
const errorMessage = errorMessageMatch ? errorMessageMatch[1].trim() : testName;
|
|
67
|
+
// Extract file location from stack trace (last line with "at file:line:col")
|
|
68
|
+
const stackMatch = errorBlock.match(/at\s+(.*\.spec\.ts):(\d+):(\d+)/);
|
|
69
|
+
let errorFile = file;
|
|
70
|
+
let errorLine = 0;
|
|
71
|
+
let errorColumn = 0;
|
|
72
|
+
if (stackMatch) {
|
|
73
|
+
errorFile = stackMatch[1];
|
|
74
|
+
errorLine = parseInt(stackMatch[2], 10);
|
|
75
|
+
errorColumn = parseInt(stackMatch[3], 10);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// No stack trace found - track as an issue
|
|
79
|
+
issues.push(`No stack trace found for failure: ${testName}`);
|
|
80
|
+
}
|
|
81
|
+
// Normalize file path (remove absolute path prefix if present, keep relative paths)
|
|
82
|
+
// If it's an absolute path, extract just the tests/... part or the filename
|
|
83
|
+
if (errorFile.includes('/') && !errorFile.startsWith('tests')) {
|
|
84
|
+
// Absolute path - extract relative part
|
|
85
|
+
const testsMatch = errorFile.match(/(tests?\/.+\.spec\.ts)/i);
|
|
86
|
+
if (testsMatch) {
|
|
87
|
+
errorFile = testsMatch[1];
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Just keep filename if no tests/ path found
|
|
91
|
+
errorFile = errorFile.replace(/^.*\/([^/]+\.spec\.ts)$/i, '$1');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// If it already starts with tests/ or is just a filename, keep it as-is
|
|
95
|
+
// Detect error type
|
|
96
|
+
const type = detectErrorType(errorMessage, errorBlock);
|
|
97
|
+
// Generate guidance
|
|
98
|
+
const guidance = generateGuidance(type, errorMessage);
|
|
99
|
+
// Build complete error message
|
|
100
|
+
const completeMessage = `${testName}\n${errorMessage}`;
|
|
101
|
+
errors.push({
|
|
102
|
+
file: errorFile,
|
|
103
|
+
line: errorLine,
|
|
104
|
+
column: errorColumn,
|
|
105
|
+
message: completeMessage,
|
|
106
|
+
context: testName,
|
|
107
|
+
guidance,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
i++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Calculate quality metadata
|
|
115
|
+
const metadata = calculateQualityMetadata(errors, issues);
|
|
116
|
+
// Generate summary
|
|
117
|
+
const summary = errors.length > 0
|
|
118
|
+
? `${errors.length} test(s) failed`
|
|
119
|
+
: '0 test(s) failed';
|
|
120
|
+
// Generate guidance
|
|
121
|
+
const guidance = errors.length > 0
|
|
122
|
+
? 'Review test failures and fix the underlying issues. Check assertions, selectors, and test logic.'
|
|
123
|
+
: '';
|
|
124
|
+
// Generate clean output
|
|
125
|
+
const formattedOutput = errors
|
|
126
|
+
.map(e => {
|
|
127
|
+
const location = e.file && e.line ? `${e.file}:${e.line}` : e.file || 'unknown';
|
|
128
|
+
return `${location}: ${e.message}`;
|
|
129
|
+
})
|
|
130
|
+
.join('\n');
|
|
131
|
+
return {
|
|
132
|
+
errors,
|
|
133
|
+
summary,
|
|
134
|
+
totalCount: errors.length,
|
|
135
|
+
guidance,
|
|
136
|
+
cleanOutput: formattedOutput,
|
|
137
|
+
metadata,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Detect error type from error message and block
|
|
142
|
+
*/
|
|
143
|
+
function detectErrorType(message, block) {
|
|
144
|
+
// Element not found (waiting for locator with timeout)
|
|
145
|
+
// Check this BEFORE generic timeout to avoid false positives
|
|
146
|
+
if (block.includes('waiting for locator') && (message.includes('timeout') || message.includes('exceeded'))) {
|
|
147
|
+
return 'element-not-found';
|
|
148
|
+
}
|
|
149
|
+
// Navigation errors
|
|
150
|
+
if (message.includes('net::ERR') || message.includes('page.goto:')) {
|
|
151
|
+
return 'navigation-error';
|
|
152
|
+
}
|
|
153
|
+
// Timeout errors (generic)
|
|
154
|
+
if (message.includes('timeout') || message.includes('exceeded')) {
|
|
155
|
+
return 'timeout';
|
|
156
|
+
}
|
|
157
|
+
// Assertion errors (expect())
|
|
158
|
+
if (message.includes('expect(') || message.includes('toBe') || message.includes('toContain') || message.includes('toBeVisible') || message.includes('toHaveValue') || message.includes('toHaveCount')) {
|
|
159
|
+
return 'assertion-error';
|
|
160
|
+
}
|
|
161
|
+
// Generic error
|
|
162
|
+
return 'error';
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Generate guidance for common error types
|
|
166
|
+
*/
|
|
167
|
+
function generateGuidance(type, _message) {
|
|
168
|
+
switch (type) {
|
|
169
|
+
case 'assertion-error':
|
|
170
|
+
return 'Check the assertion expectation and ensure the actual value matches. Review the test logic and the application state.';
|
|
171
|
+
case 'timeout':
|
|
172
|
+
return 'The operation exceeded the timeout limit. Consider increasing the timeout, checking for slow operations, or verifying the application is responding correctly.';
|
|
173
|
+
case 'element-not-found':
|
|
174
|
+
return 'The element was not found on the page. Verify the selector is correct, the element exists, and it is rendered when expected.';
|
|
175
|
+
case 'navigation-error':
|
|
176
|
+
return 'Failed to navigate to the page. Check the URL is correct, the server is running, and the page exists.';
|
|
177
|
+
default:
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Calculate quality metadata
|
|
183
|
+
*/
|
|
184
|
+
function calculateQualityMetadata(errors, issues) {
|
|
185
|
+
if (errors.length === 0 && issues.length === 0) {
|
|
186
|
+
// No errors and no issues = perfect extraction (or no failures)
|
|
187
|
+
return {
|
|
188
|
+
confidence: 100,
|
|
189
|
+
completeness: 100,
|
|
190
|
+
issues: [],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Calculate completeness: % of errors with file + line + message
|
|
194
|
+
const completeErrors = errors.filter(e => e.file &&
|
|
195
|
+
e.line !== undefined &&
|
|
196
|
+
e.line > 0 &&
|
|
197
|
+
e.message).length;
|
|
198
|
+
const completeness = errors.length > 0
|
|
199
|
+
? Math.round((completeErrors / errors.length) * 100)
|
|
200
|
+
: 100;
|
|
201
|
+
// Calculate confidence based on pattern matching quality
|
|
202
|
+
let confidence = 90; // Base confidence for Playwright (distinctive format)
|
|
203
|
+
// Reduce confidence if we have issues
|
|
204
|
+
if (issues.length > 0) {
|
|
205
|
+
confidence -= Math.min(issues.length * 10, 40);
|
|
206
|
+
}
|
|
207
|
+
// Reduce confidence if completeness is low
|
|
208
|
+
if (completeness < 80) {
|
|
209
|
+
confidence -= (100 - completeness) / 2;
|
|
210
|
+
}
|
|
211
|
+
confidence = Math.max(0, Math.min(100, confidence));
|
|
212
|
+
return {
|
|
213
|
+
confidence: Math.round(confidence),
|
|
214
|
+
completeness,
|
|
215
|
+
issues,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Check if output is from Playwright
|
|
220
|
+
*/
|
|
221
|
+
export function isPlaywrightOutput(output) {
|
|
222
|
+
// Look for distinctive Playwright markers
|
|
223
|
+
const cleanOutput = stripAnsiCodes(output);
|
|
224
|
+
// Playwright uses ✘ symbol and .spec.ts files
|
|
225
|
+
const hasPlaywrightMarker = cleanOutput.includes('✘') && cleanOutput.includes('.spec.ts');
|
|
226
|
+
// Or has numbered failures with › separator
|
|
227
|
+
const hasNumberedFailures = /^\s+\d+\)\s+.+\.spec\.ts:\d+:\d+\s+›/.test(cleanOutput);
|
|
228
|
+
return hasPlaywrightMarker || hasNumberedFailures;
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=playwright-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-extractor.js","sourceRoot":"","sources":["../src/playwright-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,9 @@ import type { ErrorExtractorResult } from './types.js';
|
|
|
12
12
|
* Auto-detection rules:
|
|
13
13
|
* - TypeScript: Step name contains "TypeScript" or "typecheck"
|
|
14
14
|
* - ESLint: Step name contains "ESLint" or "lint"
|
|
15
|
+
* - JUnit XML: Output contains JUnit XML format (<?xml + <testsuite)
|
|
16
|
+
* - Jasmine: Output contains "Failures:" header
|
|
17
|
+
* - Mocha: Output contains "X passing" or "X failing" format
|
|
15
18
|
* - Vitest/Jest: Step name contains "test" (but not "OpenAPI")
|
|
16
19
|
* - OpenAPI: Step name contains "OpenAPI"
|
|
17
20
|
* - Generic: Fallback for unknown step types
|
|
@@ -27,6 +30,12 @@ import type { ErrorExtractorResult } from './types.js';
|
|
|
27
30
|
*
|
|
28
31
|
* const result2 = extractByStepName('ESLint', eslintOutput);
|
|
29
32
|
* // Uses extractESLintErrors automatically
|
|
33
|
+
*
|
|
34
|
+
* const result3 = extractByStepName('Test', junitXmlOutput);
|
|
35
|
+
* // Auto-detects JUnit XML and uses extractJUnitErrors
|
|
36
|
+
*
|
|
37
|
+
* const result4 = extractByStepName('Test', mochaOutput);
|
|
38
|
+
* // Auto-detects Mocha format and uses extractMochaErrors
|
|
30
39
|
* ```
|
|
31
40
|
*/
|
|
32
41
|
export declare function extractByStepName(stepName: string, output: string): ErrorExtractorResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-extractor.d.ts","sourceRoot":"","sources":["../src/smart-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"smart-extractor.d.ts","sourceRoot":"","sources":["../src/smart-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAUvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAoCxF"}
|
package/dist/smart-extractor.js
CHANGED
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
import { extractTypeScriptErrors } from './typescript-extractor.js';
|
|
9
9
|
import { extractESLintErrors } from './eslint-extractor.js';
|
|
10
10
|
import { extractVitestErrors } from './vitest-extractor.js';
|
|
11
|
+
import { extractJUnitErrors } from './junit-extractor.js';
|
|
12
|
+
import { extractMochaErrors } from './mocha-extractor.js';
|
|
13
|
+
import { extractJasmineErrors } from './jasmine-extractor.js';
|
|
11
14
|
import { extractOpenAPIErrors } from './openapi-extractor.js';
|
|
12
15
|
import { extractGenericErrors } from './generic-extractor.js';
|
|
13
16
|
/**
|
|
@@ -16,6 +19,9 @@ import { extractGenericErrors } from './generic-extractor.js';
|
|
|
16
19
|
* Auto-detection rules:
|
|
17
20
|
* - TypeScript: Step name contains "TypeScript" or "typecheck"
|
|
18
21
|
* - ESLint: Step name contains "ESLint" or "lint"
|
|
22
|
+
* - JUnit XML: Output contains JUnit XML format (<?xml + <testsuite)
|
|
23
|
+
* - Jasmine: Output contains "Failures:" header
|
|
24
|
+
* - Mocha: Output contains "X passing" or "X failing" format
|
|
19
25
|
* - Vitest/Jest: Step name contains "test" (but not "OpenAPI")
|
|
20
26
|
* - OpenAPI: Step name contains "OpenAPI"
|
|
21
27
|
* - Generic: Fallback for unknown step types
|
|
@@ -31,6 +37,12 @@ import { extractGenericErrors } from './generic-extractor.js';
|
|
|
31
37
|
*
|
|
32
38
|
* const result2 = extractByStepName('ESLint', eslintOutput);
|
|
33
39
|
* // Uses extractESLintErrors automatically
|
|
40
|
+
*
|
|
41
|
+
* const result3 = extractByStepName('Test', junitXmlOutput);
|
|
42
|
+
* // Auto-detects JUnit XML and uses extractJUnitErrors
|
|
43
|
+
*
|
|
44
|
+
* const result4 = extractByStepName('Test', mochaOutput);
|
|
45
|
+
* // Auto-detects Mocha format and uses extractMochaErrors
|
|
34
46
|
* ```
|
|
35
47
|
*/
|
|
36
48
|
export function extractByStepName(stepName, output) {
|
|
@@ -41,6 +53,19 @@ export function extractByStepName(stepName, output) {
|
|
|
41
53
|
if (lowerStepName.includes('eslint') || lowerStepName.includes('lint')) {
|
|
42
54
|
return extractESLintErrors(output);
|
|
43
55
|
}
|
|
56
|
+
// Auto-detect JUnit XML format (before test keyword check)
|
|
57
|
+
if (output.includes('<?xml') && output.includes('<testsuite')) {
|
|
58
|
+
return extractJUnitErrors(output);
|
|
59
|
+
}
|
|
60
|
+
// Auto-detect Jasmine format (distinctive "Failures:" header)
|
|
61
|
+
if (output.includes('Failures:') && output.match(/^\d+\)\s+/m)) {
|
|
62
|
+
return extractJasmineErrors(output);
|
|
63
|
+
}
|
|
64
|
+
// Auto-detect Mocha format (distinctive "X passing"/"X failing" pattern)
|
|
65
|
+
if ((output.includes(' passing') || output.includes(' failing')) &&
|
|
66
|
+
output.match(/\s+\d+\)\s+/)) {
|
|
67
|
+
return extractMochaErrors(output);
|
|
68
|
+
}
|
|
44
69
|
if (lowerStepName.includes('test') && !lowerStepName.includes('openapi')) {
|
|
45
70
|
return extractVitestErrors(output);
|
|
46
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-extractor.js","sourceRoot":"","sources":["../src/smart-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,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,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D
|
|
1
|
+
{"version":3,"file":"smart-extractor.js","sourceRoot":"","sources":["../src/smart-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,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,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;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IAChE,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAE7C,IAAI,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACjH,OAAO,uBAAuB,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACvE,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,2DAA2D;IAC3D,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9D,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,8DAA8D;IAC9D,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/D,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,yEAAyE;IACzE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;QAChC,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzE,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TAP Error Extractor
|
|
3
|
+
*
|
|
4
|
+
* Parses TAP (Test Anything Protocol) test output and formats failures for LLM consumption.
|
|
5
|
+
* Supports TAP version 13 and compatible test frameworks (tape, node-tap, etc.)
|
|
6
|
+
*
|
|
7
|
+
* @package @vibe-validate/extractors
|
|
8
|
+
*/
|
|
9
|
+
import type { ErrorExtractorResult } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Extract errors from TAP test output
|
|
12
|
+
*
|
|
13
|
+
* @param output - TAP text output
|
|
14
|
+
* @returns Structured error information
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const tapOutput = execSync('tape tests/**\/*.test.js', { encoding: 'utf-8' });
|
|
19
|
+
* const result = extractTAPErrors(tapOutput);
|
|
20
|
+
* console.log(result.summary); // "5 test(s) failed"
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractTAPErrors(output: string): ErrorExtractorResult;
|
|
24
|
+
//# sourceMappingURL=tap-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tap-extractor.d.ts","sourceRoot":"","sources":["../src/tap-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAsC,MAAM,YAAY,CAAC;AAG3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAmErE"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TAP Error Extractor
|
|
3
|
+
*
|
|
4
|
+
* Parses TAP (Test Anything Protocol) test output and formats failures for LLM consumption.
|
|
5
|
+
* Supports TAP version 13 and compatible test frameworks (tape, node-tap, etc.)
|
|
6
|
+
*
|
|
7
|
+
* @package @vibe-validate/extractors
|
|
8
|
+
*/
|
|
9
|
+
import { stripAnsiCodes } from './utils.js';
|
|
10
|
+
/**
|
|
11
|
+
* Extract errors from TAP test output
|
|
12
|
+
*
|
|
13
|
+
* @param output - TAP text output
|
|
14
|
+
* @returns Structured error information
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const tapOutput = execSync('tape tests/**\/*.test.js', { encoding: 'utf-8' });
|
|
19
|
+
* const result = extractTAPErrors(tapOutput);
|
|
20
|
+
* console.log(result.summary); // "5 test(s) failed"
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function extractTAPErrors(output) {
|
|
24
|
+
const cleanOutput = stripAnsiCodes(output);
|
|
25
|
+
// Extract all failures
|
|
26
|
+
const failures = extractFailures(cleanOutput);
|
|
27
|
+
if (failures.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
summary: '0 test(s) failed',
|
|
30
|
+
errors: [],
|
|
31
|
+
totalCount: 0,
|
|
32
|
+
cleanOutput: '',
|
|
33
|
+
guidance: '',
|
|
34
|
+
metadata: {
|
|
35
|
+
confidence: 100,
|
|
36
|
+
completeness: 100,
|
|
37
|
+
issues: []
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const errors = [];
|
|
42
|
+
let completeCount = 0;
|
|
43
|
+
for (const failure of failures) {
|
|
44
|
+
const file = failure.file || undefined;
|
|
45
|
+
const message = failure.message || 'Test failed';
|
|
46
|
+
const context = failure.testName || '';
|
|
47
|
+
const isComplete = file && failure.line && message;
|
|
48
|
+
if (isComplete) {
|
|
49
|
+
completeCount++;
|
|
50
|
+
}
|
|
51
|
+
errors.push({
|
|
52
|
+
file,
|
|
53
|
+
line: failure.line,
|
|
54
|
+
message,
|
|
55
|
+
context,
|
|
56
|
+
guidance: failure.guidance
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Generate summary
|
|
60
|
+
const summary = `${failures.length} test(s) failed`;
|
|
61
|
+
// Generate guidance
|
|
62
|
+
const guidance = generateGuidance(failures);
|
|
63
|
+
// Calculate quality metadata
|
|
64
|
+
const completeness = failures.length > 0 ? (completeCount / failures.length) * 100 : 100;
|
|
65
|
+
const confidence = failures.length > 0 ? 95 : 100; // High confidence for TAP
|
|
66
|
+
const metadata = {
|
|
67
|
+
confidence,
|
|
68
|
+
completeness,
|
|
69
|
+
issues: []
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
summary,
|
|
73
|
+
errors,
|
|
74
|
+
totalCount: failures.length,
|
|
75
|
+
cleanOutput: formatCleanOutput(errors),
|
|
76
|
+
guidance,
|
|
77
|
+
metadata
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Extract all failures from TAP output
|
|
82
|
+
*/
|
|
83
|
+
function extractFailures(output) {
|
|
84
|
+
const failures = [];
|
|
85
|
+
const lines = output.split('\n');
|
|
86
|
+
let currentTestName = '';
|
|
87
|
+
let i = 0;
|
|
88
|
+
while (i < lines.length) {
|
|
89
|
+
const line = lines[i];
|
|
90
|
+
// Track test names from comments
|
|
91
|
+
if (line.trim().startsWith('#')) {
|
|
92
|
+
currentTestName = line.trim().substring(1).trim();
|
|
93
|
+
i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
// Look for failures: "not ok N message"
|
|
97
|
+
const failureMatch = line.match(/^not ok\s+\d+\s+(.+)$/);
|
|
98
|
+
if (failureMatch) {
|
|
99
|
+
const message = failureMatch[1].trim();
|
|
100
|
+
const failure = {
|
|
101
|
+
message,
|
|
102
|
+
testName: currentTestName
|
|
103
|
+
};
|
|
104
|
+
// Look for YAML diagnostic block (starts with " ---")
|
|
105
|
+
if (i + 1 < lines.length && lines[i + 1].trim() === '---') {
|
|
106
|
+
i += 2; // Skip "not ok" line and "---" line
|
|
107
|
+
// Parse YAML block until we hit "..."
|
|
108
|
+
while (i < lines.length && !lines[i].trim().startsWith('...')) {
|
|
109
|
+
const yamlLine = lines[i];
|
|
110
|
+
// Extract location from "at:" field
|
|
111
|
+
// Format: "at: Test.<anonymous> (file:///path/to/file.js:line:col)"
|
|
112
|
+
// or: "at: file.js:line:col"
|
|
113
|
+
const atMatch = yamlLine.match(/^\s+at:\s+(.+)$/);
|
|
114
|
+
if (atMatch) {
|
|
115
|
+
const location = atMatch[1];
|
|
116
|
+
const { file, line } = parseLocation(location);
|
|
117
|
+
if (file)
|
|
118
|
+
failure.file = file;
|
|
119
|
+
if (line)
|
|
120
|
+
failure.line = line;
|
|
121
|
+
}
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Detect error type and add guidance
|
|
126
|
+
const errorType = detectErrorType(message);
|
|
127
|
+
failure.errorType = errorType;
|
|
128
|
+
failure.guidance = getErrorGuidance(errorType);
|
|
129
|
+
failures.push(failure);
|
|
130
|
+
}
|
|
131
|
+
i++;
|
|
132
|
+
}
|
|
133
|
+
return failures;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Parse location string to extract file and line number
|
|
137
|
+
*
|
|
138
|
+
* Handles formats:
|
|
139
|
+
* - Test.<anonymous> (file:///path/to/file.js:28:5)
|
|
140
|
+
* - Test.<anonymous> (./path/to/file.js:28:5)
|
|
141
|
+
* - file.js:28:5
|
|
142
|
+
*/
|
|
143
|
+
function parseLocation(location) {
|
|
144
|
+
// Try to extract from parentheses first: (file:///path:line:col) or (path:line:col)
|
|
145
|
+
const parenMatch = location.match(/\(([^)]+)\)/);
|
|
146
|
+
const pathString = parenMatch ? parenMatch[1] : location;
|
|
147
|
+
// Remove file:// protocol if present
|
|
148
|
+
const cleanPath = pathString.replace(/^file:\/\//, '');
|
|
149
|
+
// Extract file path and line number
|
|
150
|
+
// Format: /path/to/file.js:line:col or path/to/file.js:line:col
|
|
151
|
+
const match = cleanPath.match(/^(.+):(\d+):\d+$/);
|
|
152
|
+
if (match) {
|
|
153
|
+
return {
|
|
154
|
+
file: match[1],
|
|
155
|
+
line: parseInt(match[2], 10)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return {};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Detect error type from message
|
|
162
|
+
*/
|
|
163
|
+
function detectErrorType(message) {
|
|
164
|
+
const lowerMessage = message.toLowerCase();
|
|
165
|
+
if (lowerMessage.includes('timeout') || lowerMessage.includes('timed out')) {
|
|
166
|
+
return 'timeout';
|
|
167
|
+
}
|
|
168
|
+
if (lowerMessage.includes('enoent') || lowerMessage.includes('no such file')) {
|
|
169
|
+
return 'file-not-found';
|
|
170
|
+
}
|
|
171
|
+
if (lowerMessage.includes('cannot read properties') || lowerMessage.includes('typeerror')) {
|
|
172
|
+
return 'type-error';
|
|
173
|
+
}
|
|
174
|
+
if (lowerMessage.includes('expected') || lowerMessage.includes('should')) {
|
|
175
|
+
return 'assertion';
|
|
176
|
+
}
|
|
177
|
+
return 'unknown';
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get guidance for a specific error type
|
|
181
|
+
*/
|
|
182
|
+
function getErrorGuidance(errorType) {
|
|
183
|
+
const guidanceMap = {
|
|
184
|
+
assertion: 'Review the assertion logic and expected vs actual values',
|
|
185
|
+
timeout: 'Increase timeout limit or optimize async operations',
|
|
186
|
+
'file-not-found': 'Verify file path exists and permissions are correct',
|
|
187
|
+
'type-error': 'Check for null/undefined values before accessing properties'
|
|
188
|
+
};
|
|
189
|
+
return guidanceMap[errorType];
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Generate overall guidance from all failures
|
|
193
|
+
*/
|
|
194
|
+
function generateGuidance(failures) {
|
|
195
|
+
if (failures.length === 0) {
|
|
196
|
+
return '';
|
|
197
|
+
}
|
|
198
|
+
const errorTypes = new Set(failures.map(f => f.errorType).filter(Boolean));
|
|
199
|
+
if (errorTypes.has('assertion')) {
|
|
200
|
+
return 'Review failing assertions - check expected vs actual values';
|
|
201
|
+
}
|
|
202
|
+
if (errorTypes.has('timeout')) {
|
|
203
|
+
return 'Tests are timing out - consider increasing timeout or optimizing async code';
|
|
204
|
+
}
|
|
205
|
+
if (errorTypes.has('type-error')) {
|
|
206
|
+
return 'Runtime type errors detected - add null checks before property access';
|
|
207
|
+
}
|
|
208
|
+
return 'Review test failures and error messages above';
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Format clean output for LLM consumption
|
|
212
|
+
*/
|
|
213
|
+
function formatCleanOutput(errors) {
|
|
214
|
+
if (errors.length === 0) {
|
|
215
|
+
return '';
|
|
216
|
+
}
|
|
217
|
+
return errors
|
|
218
|
+
.map(error => {
|
|
219
|
+
const location = error.file
|
|
220
|
+
? `${error.file}${error.line ? `:${error.line}` : ''}`
|
|
221
|
+
: 'unknown location';
|
|
222
|
+
const context = error.context ? `[${error.context}] ` : '';
|
|
223
|
+
return `${location}: ${context}${error.message}`;
|
|
224
|
+
})
|
|
225
|
+
.join('\n');
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=tap-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tap-extractor.js","sourceRoot":"","sources":["../src/tap-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAE3C,uBAAuB;IACvB,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE9C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,OAAO,EAAE,kBAAkB;YAC3B,MAAM,EAAE,EAAE;YACV,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,EAAE;YACf,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE;gBACR,UAAU,EAAE,GAAG;gBACf,YAAY,EAAE,GAAG;gBACjB,MAAM,EAAE,EAAE;aACX;SACF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,aAAa,CAAC;QACjD,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;QAEvC,MAAM,UAAU,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC;QACnD,IAAI,UAAU,EAAE,CAAC;YACf,aAAa,EAAE,CAAC;QAClB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO;YACP,OAAO;YACP,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,mBAAmB;IACnB,MAAM,OAAO,GAAG,GAAG,QAAQ,CAAC,MAAM,iBAAiB,CAAC;IAEpD,oBAAoB;IACpB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE5C,6BAA6B;IAC7B,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACzF,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,0BAA0B;IAE7E,MAAM,QAAQ,GAAuB;QACnC,UAAU;QACV,YAAY;QACZ,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,OAAO;QACL,OAAO;QACP,MAAM;QACN,UAAU,EAAE,QAAQ,CAAC,MAAM;QAC3B,WAAW,EAAE,iBAAiB,CAAC,MAAM,CAAC;QACtC,QAAQ;QACR,QAAQ;KACT,CAAC;AACJ,CAAC;AAcD;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,eAAe,GAAG,EAAE,CAAC;IACzB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtB,iCAAiC;QACjC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,eAAe,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAClD,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QAED,wCAAwC;QACxC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACzD,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACvC,MAAM,OAAO,GAAgB;gBAC3B,OAAO;gBACP,QAAQ,EAAE,eAAe;aAC1B,CAAC;YAEF,uDAAuD;YACvD,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1D,CAAC,IAAI,CAAC,CAAC,CAAC,oCAAoC;gBAE5C,sCAAsC;gBACtC,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBAE1B,oCAAoC;oBACpC,oEAAoE;oBACpE,6BAA6B;oBAC7B,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;oBAClD,IAAI,OAAO,EAAE,CAAC;wBACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;wBAC5B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;wBAC/C,IAAI,IAAI;4BAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;wBAC9B,IAAI,IAAI;4BAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;oBAChC,CAAC;oBAED,CAAC,EAAE,CAAC;gBACN,CAAC;YACH,CAAC;YAED,qCAAqC;YACrC,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YAC3C,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;YAC9B,OAAO,CAAC,QAAQ,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAE/C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QAED,CAAC,EAAE,CAAC;IACN,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,QAAgB;IACrC,oFAAoF;IACpF,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEzD,qCAAqC;IACrC,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAEvD,oCAAoC;IACpC,gEAAgE;IAChE,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YACd,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;SAC7B,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAE3C,IAAI,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3E,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAC7E,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,CAAC,wBAAwB,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1F,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzE,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,SAAiB;IACzC,MAAM,WAAW,GAA2B;QAC1C,SAAS,EAAE,0DAA0D;QACrE,OAAO,EAAE,qDAAqD;QAC9D,gBAAgB,EAAE,qDAAqD;QACvE,YAAY,EAAE,6DAA6D;KAC5E,CAAC;IAEF,OAAO,WAAW,CAAC,SAAS,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAuB;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAE3E,IAAI,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,6DAA6D,CAAC;IACvE,CAAC;IACD,IAAI,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,OAAO,6EAA6E,CAAC;IACvF,CAAC;IACD,IAAI,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,uEAAuE,CAAC;IACjF,CAAC;IAED,OAAO,+CAA+C,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,MAAwB;IACjD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,MAAM;SACV,GAAG,CAAC,KAAK,CAAC,EAAE;QACX,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI;YACzB,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YACtD,CAAC,CAAC,kBAAkB,CAAC;QAEvB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,OAAO,GAAG,QAAQ,KAAK,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IACnD,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* Structured error information extracted from validation output
|
|
10
10
|
*/
|
|
11
11
|
export interface FormattedError {
|
|
12
|
-
/** File path where the error occurred */
|
|
13
|
-
file
|
|
12
|
+
/** File path where the error occurred (undefined if location cannot be determined) */
|
|
13
|
+
file?: string;
|
|
14
14
|
/** Line number (1-indexed) */
|
|
15
15
|
line?: number;
|
|
16
16
|
/** Column number (1-indexed) */
|
|
@@ -23,6 +23,23 @@ export interface FormattedError {
|
|
|
23
23
|
severity?: 'error' | 'warning';
|
|
24
24
|
/** Additional context (surrounding code, stack trace excerpt) */
|
|
25
25
|
context?: string;
|
|
26
|
+
/** Guidance for fixing the error */
|
|
27
|
+
guidance?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Metadata about extraction quality (what the extractor knows about its own extraction)
|
|
31
|
+
*
|
|
32
|
+
* Note: Extractor doesn't know expected count - test infrastructure compares against ground truth
|
|
33
|
+
*/
|
|
34
|
+
export interface ExtractionMetadata {
|
|
35
|
+
/** Extraction confidence (0-100) based on pattern match quality */
|
|
36
|
+
confidence: number;
|
|
37
|
+
/** Percentage of extracted errors with complete data (file + line + message) */
|
|
38
|
+
completeness: number;
|
|
39
|
+
/** Issues encountered during extraction (e.g., "ambiguous patterns", "missing line numbers") */
|
|
40
|
+
issues: string[];
|
|
41
|
+
/** Suggestions for improving extraction quality (only included when developerFeedback: true) */
|
|
42
|
+
suggestions?: string[];
|
|
26
43
|
}
|
|
27
44
|
/**
|
|
28
45
|
* Result of error extraction operation
|
|
@@ -38,6 +55,8 @@ export interface ErrorExtractorResult {
|
|
|
38
55
|
guidance?: string;
|
|
39
56
|
/** Clean, formatted output for YAML/JSON embedding */
|
|
40
57
|
cleanOutput: string;
|
|
58
|
+
/** Extraction quality metadata (only included when developerFeedback: true) */
|
|
59
|
+
metadata?: ExtractionMetadata;
|
|
41
60
|
}
|
|
42
61
|
/**
|
|
43
62
|
* Error extractor interface for specific tool/format
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAEhB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAE/B,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IAEnB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IAErB,gGAAgG;IAChG,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB,gGAAgG;IAChG,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,MAAM,EAAE,cAAc,EAAE,CAAC;IAEzB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAEhB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IAEnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IAEpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAAC;CAC/C"}
|