@pithyjs/codex 0.1.0-beta.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/LICENSE +21 -0
- package/README.md +4401 -0
- package/dist/annotations.d.ts +106 -0
- package/dist/annotations.js +306 -0
- package/dist/apply.d.ts +2 -0
- package/dist/apply.js +80 -0
- package/dist/changed-scope.d.ts +23 -0
- package/dist/changed-scope.js +31 -0
- package/dist/check.d.ts +2 -0
- package/dist/check.js +117 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +67 -0
- package/dist/env.d.ts +5 -0
- package/dist/env.js +35 -0
- package/dist/extract-cli.d.ts +23 -0
- package/dist/extract-cli.js +192 -0
- package/dist/extraction/breaking-changes.d.ts +66 -0
- package/dist/extraction/breaking-changes.js +352 -0
- package/dist/extraction/example-extractor.d.ts +55 -0
- package/dist/extraction/example-extractor.js +272 -0
- package/dist/extraction/index.d.ts +27 -0
- package/dist/extraction/index.js +31 -0
- package/dist/extraction/jsdoc-parser.d.ts +43 -0
- package/dist/extraction/jsdoc-parser.js +274 -0
- package/dist/extraction/pipeline.d.ts +54 -0
- package/dist/extraction/pipeline.js +526 -0
- package/dist/extraction/readme-sync.d.ts +108 -0
- package/dist/extraction/readme-sync.js +592 -0
- package/dist/extraction/snapshot-store.d.ts +40 -0
- package/dist/extraction/snapshot-store.js +153 -0
- package/dist/extraction/source-linker.d.ts +80 -0
- package/dist/extraction/source-linker.js +316 -0
- package/dist/extraction/test-example-extractor.d.ts +69 -0
- package/dist/extraction/test-example-extractor.js +400 -0
- package/dist/extraction/test-pattern-extractor.d.ts +68 -0
- package/dist/extraction/test-pattern-extractor.js +261 -0
- package/dist/extraction/testing-pyramid.d.ts +44 -0
- package/dist/extraction/testing-pyramid.js +163 -0
- package/dist/extraction/type-extractor.d.ts +34 -0
- package/dist/extraction/type-extractor.js +494 -0
- package/dist/extraction/types.d.ts +401 -0
- package/dist/extraction/types.js +34 -0
- package/dist/indexer.d.ts +1 -0
- package/dist/indexer.js +107 -0
- package/dist/llm.d.ts +8 -0
- package/dist/llm.js +75 -0
- package/dist/readme-sync-cli.d.ts +20 -0
- package/dist/readme-sync-cli.js +167 -0
- package/dist/review.d.ts +2 -0
- package/dist/review.js +93 -0
- package/dist/scan.d.ts +29 -0
- package/dist/scan.js +221 -0
- package/dist/schema.d.ts +169 -0
- package/dist/schema.js +70 -0
- package/dist/snapshot-cli.d.ts +45 -0
- package/dist/snapshot-cli.js +217 -0
- package/dist/sync-cli.d.ts +22 -0
- package/dist/sync-cli.js +154 -0
- package/dist/sync-pipeline.d.ts +58 -0
- package/dist/sync-pipeline.js +104 -0
- package/dist/sync.d.ts +2 -0
- package/dist/sync.js +318 -0
- package/dist/validate-cli.d.ts +20 -0
- package/dist/validate-cli.js +144 -0
- package/dist/validate.d.ts +76 -0
- package/dist/validate.js +183 -0
- package/dist/watch-cli.d.ts +21 -0
- package/dist/watch-cli.js +220 -0
- package/package.json +62 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @codex
|
|
3
|
+
* {
|
|
4
|
+
* "id": "pithy.codex.extraction.test-example-extractor",
|
|
5
|
+
* "title": "Test Example Extractor",
|
|
6
|
+
* "category": "compiler"
|
|
7
|
+
* }
|
|
8
|
+
*
|
|
9
|
+
* Extracts examples from test files marked with @codex:example
|
|
10
|
+
* and tracks test status from vitest/jest output.
|
|
11
|
+
*/
|
|
12
|
+
import { normalize } from 'node:path';
|
|
13
|
+
/**
|
|
14
|
+
* Marker pattern for identifying codex examples in test files
|
|
15
|
+
*
|
|
16
|
+
* Supports formats:
|
|
17
|
+
* - @codex:example pithy.signals.effect
|
|
18
|
+
* - @codex:example("pithy.signals.effect")
|
|
19
|
+
* - @codex:example { entry: "pithy.signals.effect" }
|
|
20
|
+
*/
|
|
21
|
+
const CODEX_EXAMPLE_MARKER = /@codex:example\s*(?:\(\s*["']([^"']+)["']\s*\)|{[^}]*entry:\s*["']([^"']+)["'][^}]*}|([\w-]+(?:\.[\w-]+)+))/g;
|
|
22
|
+
/**
|
|
23
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-example-extractor","name":"extractTestExamples","stability":"stable","signature":"(content: string, filePath: string) => TestExample[]"}
|
|
24
|
+
*
|
|
25
|
+
* Extracts examples marked with @codex:example from a test file
|
|
26
|
+
* @param content - Test file content
|
|
27
|
+
* @param filePath - Path to the test file
|
|
28
|
+
* @returns Array of extracted test examples
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // In a test file:
|
|
33
|
+
* // @codex:example pithy.signals.effect
|
|
34
|
+
* it("creates an effect that tracks dependencies", () => {
|
|
35
|
+
* const count = signal(0);
|
|
36
|
+
* let runCount = 0;
|
|
37
|
+
* effect(() => { count(); runCount++; });
|
|
38
|
+
* expect(runCount).toBe(1);
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function extractTestExamples(content, filePath) {
|
|
43
|
+
const examples = [];
|
|
44
|
+
const lines = content.split('\n');
|
|
45
|
+
// Find all @codex:example markers
|
|
46
|
+
for (let i = 0; i < lines.length; i++) {
|
|
47
|
+
const line = lines[i];
|
|
48
|
+
CODEX_EXAMPLE_MARKER.lastIndex = 0;
|
|
49
|
+
const match = CODEX_EXAMPLE_MARKER.exec(line);
|
|
50
|
+
if (match) {
|
|
51
|
+
// Extract entry ID from any of the capture groups
|
|
52
|
+
const entryId = match[1] || match[2] || match[3];
|
|
53
|
+
if (!entryId)
|
|
54
|
+
continue;
|
|
55
|
+
// Look for the next it/test/describe block
|
|
56
|
+
const testBlock = findNextTestBlock(lines, i + 1);
|
|
57
|
+
if (!testBlock)
|
|
58
|
+
continue;
|
|
59
|
+
examples.push({
|
|
60
|
+
entryId: entryId.trim(),
|
|
61
|
+
name: testBlock.name,
|
|
62
|
+
code: testBlock.code,
|
|
63
|
+
location: {
|
|
64
|
+
file: filePath,
|
|
65
|
+
line: testBlock.startLine + 1, // 1-indexed
|
|
66
|
+
endLine: testBlock.endLine + 1,
|
|
67
|
+
},
|
|
68
|
+
testFile: filePath,
|
|
69
|
+
status: 'unknown',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return examples;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Counts brace depth change for a line, skipping braces inside strings,
|
|
77
|
+
* template literals, and comments (including multi-line block comments).
|
|
78
|
+
*
|
|
79
|
+
* @param line - The line to scan
|
|
80
|
+
* @param inBlockComment - Whether we are currently inside a multi-line block comment
|
|
81
|
+
* @returns Brace counts and updated block comment state
|
|
82
|
+
*/
|
|
83
|
+
function countBraces(line, inBlockComment = false) {
|
|
84
|
+
let open = 0;
|
|
85
|
+
let close = 0;
|
|
86
|
+
let i = 0;
|
|
87
|
+
while (i < line.length) {
|
|
88
|
+
// If inside a multi-line block comment, scan for closing */
|
|
89
|
+
if (inBlockComment) {
|
|
90
|
+
const end = line.indexOf('*/', i);
|
|
91
|
+
if (end === -1) {
|
|
92
|
+
// Entire remaining line is still inside the comment
|
|
93
|
+
return { open, close, inBlockComment: true };
|
|
94
|
+
}
|
|
95
|
+
inBlockComment = false;
|
|
96
|
+
i = end + 2;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const ch = line[i];
|
|
100
|
+
// Skip single-line comments
|
|
101
|
+
if (ch === '/' && line[i + 1] === '/')
|
|
102
|
+
break;
|
|
103
|
+
// Block comment opening
|
|
104
|
+
if (ch === '/' && line[i + 1] === '*') {
|
|
105
|
+
const end = line.indexOf('*/', i + 2);
|
|
106
|
+
if (end === -1) {
|
|
107
|
+
// Block comment spans to subsequent lines
|
|
108
|
+
return { open, close, inBlockComment: true };
|
|
109
|
+
}
|
|
110
|
+
i = end + 2;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Skip string/template literals
|
|
114
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
115
|
+
const quote = ch;
|
|
116
|
+
i++;
|
|
117
|
+
while (i < line.length) {
|
|
118
|
+
if (line[i] === '\\') {
|
|
119
|
+
i += 2; // skip escaped character
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (line[i] === quote) {
|
|
123
|
+
i++;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
i++;
|
|
127
|
+
}
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (ch === '{')
|
|
131
|
+
open++;
|
|
132
|
+
else if (ch === '}')
|
|
133
|
+
close++;
|
|
134
|
+
i++;
|
|
135
|
+
}
|
|
136
|
+
return { open, close, inBlockComment };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Finds the next test block (it/test/describe) starting from a given line
|
|
140
|
+
*/
|
|
141
|
+
function findNextTestBlock(lines, startLine) {
|
|
142
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
143
|
+
const line = lines[i];
|
|
144
|
+
// Match it/test/describe patterns (handles escaped quotes in test names)
|
|
145
|
+
const testMatch = line.match(/(?:it|test|describe)\s*\(\s*(['"`])((?:\\.|(?!\1).)+)\1/);
|
|
146
|
+
if (testMatch) {
|
|
147
|
+
const name = testMatch[2];
|
|
148
|
+
const blockStart = i;
|
|
149
|
+
// Find the closing of this block using context-aware brace counting
|
|
150
|
+
let depth = 0;
|
|
151
|
+
let foundFirstBrace = false;
|
|
152
|
+
let blockEnd = i;
|
|
153
|
+
let commentState = false;
|
|
154
|
+
for (let j = i; j < lines.length; j++) {
|
|
155
|
+
const result = countBraces(lines[j], commentState);
|
|
156
|
+
commentState = result.inBlockComment;
|
|
157
|
+
if (result.open > 0)
|
|
158
|
+
foundFirstBrace = true;
|
|
159
|
+
depth += result.open - result.close;
|
|
160
|
+
if (foundFirstBrace && depth <= 0) {
|
|
161
|
+
blockEnd = j;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const code = lines.slice(blockStart, blockEnd + 1).join('\n');
|
|
166
|
+
return {
|
|
167
|
+
name,
|
|
168
|
+
code,
|
|
169
|
+
startLine: blockStart,
|
|
170
|
+
endLine: blockEnd,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-example-extractor","name":"parseVitestOutput","stability":"stable","signature":"(output: string) => TestStatus[]"}
|
|
178
|
+
*
|
|
179
|
+
* Parses vitest JSON output to extract test statuses
|
|
180
|
+
* @param output - JSON string from vitest --reporter=json
|
|
181
|
+
* @returns Array of test statuses
|
|
182
|
+
*/
|
|
183
|
+
export function parseVitestOutput(output) {
|
|
184
|
+
const statuses = [];
|
|
185
|
+
try {
|
|
186
|
+
const json = JSON.parse(output);
|
|
187
|
+
// Handle vitest JSON output format
|
|
188
|
+
if (json.testResults) {
|
|
189
|
+
for (const fileResult of json.testResults) {
|
|
190
|
+
const file = fileResult.name || fileResult.file;
|
|
191
|
+
if (!file)
|
|
192
|
+
continue;
|
|
193
|
+
for (const testResult of fileResult.assertionResults || []) {
|
|
194
|
+
const testName = testResult.fullName || testResult.title;
|
|
195
|
+
if (!testName)
|
|
196
|
+
continue;
|
|
197
|
+
statuses.push({
|
|
198
|
+
file,
|
|
199
|
+
testName,
|
|
200
|
+
status: mapVitestStatus(testResult.status),
|
|
201
|
+
duration: testResult.duration,
|
|
202
|
+
error: testResult.failureMessages?.join('\n'),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Also handle the top-level format
|
|
208
|
+
if (json.success !== undefined && json.results) {
|
|
209
|
+
for (const result of json.results) {
|
|
210
|
+
const file = result.file;
|
|
211
|
+
if (!file)
|
|
212
|
+
continue;
|
|
213
|
+
for (const task of flattenTasks(result.tasks || [])) {
|
|
214
|
+
if (!task?.name)
|
|
215
|
+
continue;
|
|
216
|
+
statuses.push({
|
|
217
|
+
file,
|
|
218
|
+
testName: task.name,
|
|
219
|
+
status: mapTaskResult(task.result?.state),
|
|
220
|
+
duration: task.result?.duration,
|
|
221
|
+
error: task.result?.error?.message,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
if (output.trim().length > 0 && process.env.NODE_ENV === 'development') {
|
|
229
|
+
console.warn('[codex] Failed to parse vitest output:', err instanceof Error ? err.message : String(err));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return statuses;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Flattens nested task structure from vitest
|
|
236
|
+
*/
|
|
237
|
+
function flattenTasks(tasks, parentName = '') {
|
|
238
|
+
const flat = [];
|
|
239
|
+
for (const task of tasks) {
|
|
240
|
+
const fullName = parentName ? `${parentName} > ${task.name}` : task.name;
|
|
241
|
+
if (task.type === 'test') {
|
|
242
|
+
flat.push({
|
|
243
|
+
name: fullName,
|
|
244
|
+
result: task.result,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (task.tasks && Array.isArray(task.tasks)) {
|
|
248
|
+
flat.push(...flattenTasks(task.tasks, fullName));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return flat;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Maps vitest status to our status format
|
|
255
|
+
*/
|
|
256
|
+
function mapVitestStatus(status) {
|
|
257
|
+
switch (status?.toLowerCase()) {
|
|
258
|
+
case 'passed':
|
|
259
|
+
return 'passed';
|
|
260
|
+
case 'failed':
|
|
261
|
+
return 'failed';
|
|
262
|
+
case 'pending':
|
|
263
|
+
case 'skipped':
|
|
264
|
+
case 'todo':
|
|
265
|
+
return 'skipped';
|
|
266
|
+
default:
|
|
267
|
+
return 'skipped';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Maps vitest task result state to our status format
|
|
272
|
+
*/
|
|
273
|
+
function mapTaskResult(state) {
|
|
274
|
+
switch (state?.toLowerCase()) {
|
|
275
|
+
case 'pass':
|
|
276
|
+
return 'passed';
|
|
277
|
+
case 'fail':
|
|
278
|
+
return 'failed';
|
|
279
|
+
case 'skip':
|
|
280
|
+
case 'todo':
|
|
281
|
+
return 'skipped';
|
|
282
|
+
default:
|
|
283
|
+
return 'skipped';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-example-extractor","name":"matchExamplesToStatuses","stability":"stable","signature":"(examples: TestExample[], statuses: TestStatus[]) => TestExample[]"}
|
|
288
|
+
*
|
|
289
|
+
* Matches extracted examples to test statuses by test name
|
|
290
|
+
* @param examples - Extracted test examples
|
|
291
|
+
* @param statuses - Test statuses from vitest output
|
|
292
|
+
* @returns Examples with updated status information
|
|
293
|
+
*/
|
|
294
|
+
export function matchExamplesToStatuses(examples, statuses) {
|
|
295
|
+
return examples.map(example => {
|
|
296
|
+
// Find matching status by normalized file path and test name
|
|
297
|
+
const normalizedExample = normalize(example.testFile);
|
|
298
|
+
const matchingStatus = statuses.find(status => {
|
|
299
|
+
const normalizedStatus = normalize(status.file);
|
|
300
|
+
// Prefer normalized path suffix matching to avoid cross-package collisions.
|
|
301
|
+
// Both paths are normalized so separator differences are handled.
|
|
302
|
+
const fileMatch = normalizedStatus.endsWith(normalizedExample) ||
|
|
303
|
+
normalizedExample.endsWith(normalizedStatus);
|
|
304
|
+
// Prefer exact name match; fall back to substring only if one
|
|
305
|
+
// is a full "describe > test" path containing the other.
|
|
306
|
+
const nameMatch = status.testName === example.name ||
|
|
307
|
+
status.testName.endsWith(` > ${example.name}`) ||
|
|
308
|
+
status.testName.startsWith(`${example.name} > `);
|
|
309
|
+
return fileMatch && nameMatch;
|
|
310
|
+
});
|
|
311
|
+
if (matchingStatus) {
|
|
312
|
+
return {
|
|
313
|
+
...example,
|
|
314
|
+
status: matchingStatus.status === 'passed'
|
|
315
|
+
? 'passing'
|
|
316
|
+
: matchingStatus.status === 'failed'
|
|
317
|
+
? 'failing'
|
|
318
|
+
: 'skipped',
|
|
319
|
+
error: matchingStatus.error,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
return example;
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-example-extractor","name":"generateExampleReport","stability":"stable","signature":"(examples: TestExample[]) => string"}
|
|
327
|
+
*
|
|
328
|
+
* Generates a markdown report of test examples with their statuses
|
|
329
|
+
* @param examples - Test examples to report
|
|
330
|
+
* @returns Markdown formatted report
|
|
331
|
+
*/
|
|
332
|
+
export function generateExampleReport(examples) {
|
|
333
|
+
const byEntry = new Map();
|
|
334
|
+
// Group by entry ID
|
|
335
|
+
for (const example of examples) {
|
|
336
|
+
const existing = byEntry.get(example.entryId) || [];
|
|
337
|
+
existing.push(example);
|
|
338
|
+
byEntry.set(example.entryId, existing);
|
|
339
|
+
}
|
|
340
|
+
const lines = ['# Test Examples Report', ''];
|
|
341
|
+
for (const [entryId, entryExamples] of byEntry) {
|
|
342
|
+
lines.push(`## ${entryId}`);
|
|
343
|
+
lines.push('');
|
|
344
|
+
for (const example of entryExamples) {
|
|
345
|
+
const statusIcon = example.status === 'passing'
|
|
346
|
+
? '✅'
|
|
347
|
+
: example.status === 'failing'
|
|
348
|
+
? '❌'
|
|
349
|
+
: example.status === 'skipped'
|
|
350
|
+
? '⏭️'
|
|
351
|
+
: '❓';
|
|
352
|
+
lines.push(`### ${statusIcon} ${example.name}`);
|
|
353
|
+
lines.push('');
|
|
354
|
+
lines.push(`Location: \`${example.testFile}:${example.location.line}\``);
|
|
355
|
+
lines.push('');
|
|
356
|
+
lines.push('```typescript');
|
|
357
|
+
lines.push(example.code);
|
|
358
|
+
lines.push('```');
|
|
359
|
+
lines.push('');
|
|
360
|
+
if (example.error) {
|
|
361
|
+
lines.push('**Error:**');
|
|
362
|
+
lines.push('```');
|
|
363
|
+
lines.push(example.error);
|
|
364
|
+
lines.push('```');
|
|
365
|
+
lines.push('');
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// Summary
|
|
370
|
+
const passing = examples.filter(e => e.status === 'passing').length;
|
|
371
|
+
const failing = examples.filter(e => e.status === 'failing').length;
|
|
372
|
+
const unknown = examples.filter(e => e.status === 'unknown' || e.status === 'skipped').length;
|
|
373
|
+
lines.push('## Summary');
|
|
374
|
+
lines.push('');
|
|
375
|
+
lines.push(`- ✅ Passing: ${passing}`);
|
|
376
|
+
lines.push(`- ❌ Failing: ${failing}`);
|
|
377
|
+
lines.push(`- ❓ Unknown/Skipped: ${unknown}`);
|
|
378
|
+
return lines.join('\n');
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-example-extractor","name":"validateTestExamples","stability":"experimental","signature":"(examples: TestExample[]) => { valid: TestExample[]; invalid: TestExample[] }"}
|
|
382
|
+
*
|
|
383
|
+
* Validates that test examples are working by checking their status
|
|
384
|
+
* @param examples - Test examples to validate
|
|
385
|
+
* @returns Object with valid and invalid examples
|
|
386
|
+
*/
|
|
387
|
+
export function validateTestExamples(examples) {
|
|
388
|
+
const valid = [];
|
|
389
|
+
const invalid = [];
|
|
390
|
+
for (const example of examples) {
|
|
391
|
+
if (example.status === 'passing') {
|
|
392
|
+
valid.push(example);
|
|
393
|
+
}
|
|
394
|
+
else if (example.status === 'failing') {
|
|
395
|
+
invalid.push(example);
|
|
396
|
+
}
|
|
397
|
+
// Unknown/skipped are neither valid nor invalid
|
|
398
|
+
}
|
|
399
|
+
return { valid, invalid };
|
|
400
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @codex
|
|
3
|
+
* {
|
|
4
|
+
* "id": "pithy.codex.extraction.test-pattern-extractor",
|
|
5
|
+
* "title": "Test Pattern Extractor",
|
|
6
|
+
* "category": "compiler"
|
|
7
|
+
* }
|
|
8
|
+
*/
|
|
9
|
+
import type { ExtractedTestCase, TestFileAnalysis, TestReference } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Extracts test cases from a single test file
|
|
12
|
+
* @param content - Test file content
|
|
13
|
+
* @param filePath - Path to the test file
|
|
14
|
+
* @returns Array of extracted test cases
|
|
15
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-pattern-extractor","name":"extractTestCases","stability":"stable","signature":"(content: string, filePath: string) => ExtractedTestCase[]"}
|
|
16
|
+
*/
|
|
17
|
+
export declare function extractTestCases(content: string, filePath: string): ExtractedTestCase[];
|
|
18
|
+
/**
|
|
19
|
+
* Extracts imports from a test file to identify tested modules
|
|
20
|
+
* @param content - Test file content
|
|
21
|
+
* @returns Array of import paths
|
|
22
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-pattern-extractor","name":"extractTestImports","stability":"stable","signature":"(content: string) => string[]"}
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractTestImports(content: string): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Identifies which APIs are likely covered by a test file
|
|
27
|
+
* @param content - Test file content
|
|
28
|
+
* @param knownApis - List of known API names to look for
|
|
29
|
+
* @returns Array of covered API identifiers
|
|
30
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-pattern-extractor","name":"identifyCoveredApis","stability":"stable","signature":"(content: string, knownApis: string[]) => string[]"}
|
|
31
|
+
*/
|
|
32
|
+
export declare function identifyCoveredApis(content: string, knownApis: string[]): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Analyzes a test file and returns structured analysis
|
|
35
|
+
* @param content - Test file content
|
|
36
|
+
* @param filePath - Path to the test file
|
|
37
|
+
* @param knownApis - Optional list of known API names
|
|
38
|
+
* @returns Test file analysis
|
|
39
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-pattern-extractor","name":"analyzeTestFile","stability":"stable","signature":"(content: string, filePath: string, knownApis?: string[]) => TestFileAnalysis"}
|
|
40
|
+
*/
|
|
41
|
+
export declare function analyzeTestFile(content: string, filePath: string, knownApis?: string[]): TestFileAnalysis;
|
|
42
|
+
/**
|
|
43
|
+
* Converts test cases to test references for linking to codex entries
|
|
44
|
+
* @param testCases - Extracted test cases
|
|
45
|
+
* @param filePath - Path to the test file
|
|
46
|
+
* @returns Array of test references
|
|
47
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-pattern-extractor","name":"testCasesToReferences","stability":"stable","signature":"(testCases: ExtractedTestCase[], filePath: string) => TestReference[]"}
|
|
48
|
+
*/
|
|
49
|
+
export declare function testCasesToReferences(testCases: ExtractedTestCase[], filePath: string): TestReference[];
|
|
50
|
+
/**
|
|
51
|
+
* Matches test files to codex entry IDs based on naming conventions
|
|
52
|
+
* @param testFilePath - Path to the test file
|
|
53
|
+
* @param entryIds - List of codex entry IDs
|
|
54
|
+
* @returns Matched entry ID or undefined
|
|
55
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-pattern-extractor","name":"matchTestToEntry","stability":"stable","signature":"(testFilePath: string, entryIds: string[]) => string | undefined"}
|
|
56
|
+
*/
|
|
57
|
+
export declare function matchTestToEntry(testFilePath: string, entryIds: string[]): string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Generates a test coverage summary for display
|
|
60
|
+
* @param analyses - Array of test file analyses
|
|
61
|
+
* @returns Formatted coverage summary
|
|
62
|
+
* @codexApi {"parent":"pithy.codex.extraction.test-pattern-extractor","name":"generateCoverageSummary","stability":"stable","signature":"(analyses: TestFileAnalysis[]) => { totalTests: number; byType: Record<string, number>; coveredApis: string[] }"}
|
|
63
|
+
*/
|
|
64
|
+
export declare function generateCoverageSummary(analyses: TestFileAnalysis[]): {
|
|
65
|
+
totalTests: number;
|
|
66
|
+
byType: Record<string, number>;
|
|
67
|
+
coveredApis: string[];
|
|
68
|
+
};
|