functional-examples 0.0.0-alpha.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/README.md +148 -0
- package/dist/cli/commands/generate.d.ts +10 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +64 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +14 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +95 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/scan.d.ts +20 -0
- package/dist/cli/commands/scan.d.ts.map +1 -0
- package/dist/cli/commands/scan.js +182 -0
- package/dist/cli/commands/scan.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +10 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +65 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/index.d.ts +88 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +43 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/plugin-commands.d.ts +17 -0
- package/dist/cli/plugin-commands.d.ts.map +1 -0
- package/dist/cli/plugin-commands.js +45 -0
- package/dist/cli/plugin-commands.js.map +1 -0
- package/dist/config/index.d.ts +11 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +9 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.spec.d.ts +5 -0
- package/dist/config/index.spec.d.ts.map +1 -0
- package/dist/config/index.spec.js +142 -0
- package/dist/config/index.spec.js.map +1 -0
- package/dist/config/loader.d.ts +7 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +85 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/merger.d.ts +27 -0
- package/dist/config/merger.d.ts.map +1 -0
- package/dist/config/merger.js +41 -0
- package/dist/config/merger.js.map +1 -0
- package/dist/config/resolver.d.ts +28 -0
- package/dist/config/resolver.d.ts.map +1 -0
- package/dist/config/resolver.js +165 -0
- package/dist/config/resolver.js.map +1 -0
- package/dist/config/schema.d.ts +53 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +42 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +17 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validator.d.ts +6 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +17 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/extractors/index.d.ts +9 -0
- package/dist/extractors/index.d.ts.map +1 -0
- package/dist/extractors/index.js +9 -0
- package/dist/extractors/index.js.map +1 -0
- package/dist/extractors/loader.d.ts +19 -0
- package/dist/extractors/loader.d.ts.map +1 -0
- package/dist/extractors/loader.js +120 -0
- package/dist/extractors/loader.js.map +1 -0
- package/dist/extractors/meta-yml-fn.d.ts +19 -0
- package/dist/extractors/meta-yml-fn.d.ts.map +1 -0
- package/dist/extractors/meta-yml-fn.js +66 -0
- package/dist/extractors/meta-yml-fn.js.map +1 -0
- package/dist/extractors/meta-yml.d.ts +24 -0
- package/dist/extractors/meta-yml.d.ts.map +1 -0
- package/dist/extractors/meta-yml.js +65 -0
- package/dist/extractors/meta-yml.js.map +1 -0
- package/dist/extractors/registry.d.ts +58 -0
- package/dist/extractors/registry.d.ts.map +1 -0
- package/dist/extractors/registry.js +114 -0
- package/dist/extractors/registry.js.map +1 -0
- package/dist/extractors/registry.spec.d.ts +2 -0
- package/dist/extractors/registry.spec.d.ts.map +1 -0
- package/dist/extractors/registry.spec.js +102 -0
- package/dist/extractors/registry.spec.js.map +1 -0
- package/dist/extractors/types.d.ts +34 -0
- package/dist/extractors/types.d.ts.map +1 -0
- package/dist/extractors/types.js +8 -0
- package/dist/extractors/types.js.map +1 -0
- package/dist/extractors/yaml-frontmatter-fn.d.ts +18 -0
- package/dist/extractors/yaml-frontmatter-fn.d.ts.map +1 -0
- package/dist/extractors/yaml-frontmatter-fn.js +73 -0
- package/dist/extractors/yaml-frontmatter-fn.js.map +1 -0
- package/dist/extractors/yaml-frontmatter.d.ts +22 -0
- package/dist/extractors/yaml-frontmatter.d.ts.map +1 -0
- package/dist/extractors/yaml-frontmatter.js +83 -0
- package/dist/extractors/yaml-frontmatter.js.map +1 -0
- package/dist/extractors/yaml-frontmatter.spec.d.ts +2 -0
- package/dist/extractors/yaml-frontmatter.spec.d.ts.map +1 -0
- package/dist/extractors/yaml-frontmatter.spec.js +134 -0
- package/dist/extractors/yaml-frontmatter.spec.js.map +1 -0
- package/dist/files/index.d.ts +5 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +5 -0
- package/dist/files/index.js.map +1 -0
- package/dist/files/reader.d.ts +50 -0
- package/dist/files/reader.d.ts.map +1 -0
- package/dist/files/reader.js +62 -0
- package/dist/files/reader.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +4 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/pipeline.d.ts +11 -0
- package/dist/plugins/pipeline.d.ts.map +1 -0
- package/dist/plugins/pipeline.js +24 -0
- package/dist/plugins/pipeline.js.map +1 -0
- package/dist/plugins/registry.d.ts +57 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +93 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/validation.d.ts +64 -0
- package/dist/plugins/validation.d.ts.map +1 -0
- package/dist/plugins/validation.js +55 -0
- package/dist/plugins/validation.js.map +1 -0
- package/dist/regions/index.d.ts +7 -0
- package/dist/regions/index.d.ts.map +1 -0
- package/dist/regions/index.js +6 -0
- package/dist/regions/index.js.map +1 -0
- package/dist/regions/languages.d.ts +15 -0
- package/dist/regions/languages.d.ts.map +1 -0
- package/dist/regions/languages.js +182 -0
- package/dist/regions/languages.js.map +1 -0
- package/dist/regions/parser.d.ts +63 -0
- package/dist/regions/parser.d.ts.map +1 -0
- package/dist/regions/parser.js +175 -0
- package/dist/regions/parser.js.map +1 -0
- package/dist/regions/parser.spec.d.ts +2 -0
- package/dist/regions/parser.spec.d.ts.map +1 -0
- package/dist/regions/parser.spec.js +190 -0
- package/dist/regions/parser.spec.js.map +1 -0
- package/dist/regions/types.d.ts +37 -0
- package/dist/regions/types.d.ts.map +1 -0
- package/dist/regions/types.js +5 -0
- package/dist/regions/types.js.map +1 -0
- package/dist/scanner/candidates.d.ts +24 -0
- package/dist/scanner/candidates.d.ts.map +1 -0
- package/dist/scanner/candidates.js +83 -0
- package/dist/scanner/candidates.js.map +1 -0
- package/dist/scanner/index.d.ts +8 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +6 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/scan.d.ts +40 -0
- package/dist/scanner/scan.d.ts.map +1 -0
- package/dist/scanner/scan.js +44 -0
- package/dist/scanner/scan.js.map +1 -0
- package/dist/scanner/scanner.d.ts +29 -0
- package/dist/scanner/scanner.d.ts.map +1 -0
- package/dist/scanner/scanner.js +296 -0
- package/dist/scanner/scanner.js.map +1 -0
- package/dist/scanner/scanner.spec.d.ts +2 -0
- package/dist/scanner/scanner.spec.d.ts.map +1 -0
- package/dist/scanner/scanner.spec.js +262 -0
- package/dist/scanner/scanner.spec.js.map +1 -0
- package/dist/scanner/types.d.ts +43 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +5 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +4 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/merger.d.ts +35 -0
- package/dist/schema/merger.d.ts.map +1 -0
- package/dist/schema/merger.js +161 -0
- package/dist/schema/merger.js.map +1 -0
- package/dist/schema/typegen.d.ts +13 -0
- package/dist/schema/typegen.d.ts.map +1 -0
- package/dist/schema/typegen.js +125 -0
- package/dist/schema/typegen.js.map +1 -0
- package/dist/schema/validator.d.ts +7 -0
- package/dist/schema/validator.d.ts.map +1 -0
- package/dist/schema/validator.js +32 -0
- package/dist/schema/validator.js.map +1 -0
- package/dist/types/default-map.d.ts +21 -0
- package/dist/types/default-map.d.ts.map +1 -0
- package/dist/types/default-map.js +32 -0
- package/dist/types/default-map.js.map +1 -0
- package/dist/types/extended-iterable.d.ts +197 -0
- package/dist/types/extended-iterable.d.ts.map +1 -0
- package/dist/types/extended-iterable.js +769 -0
- package/dist/types/extended-iterable.js.map +1 -0
- package/dist/types/guards.d.ts +2 -0
- package/dist/types/guards.d.ts.map +1 -0
- package/dist/types/guards.js +2 -0
- package/dist/types/guards.js.map +1 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core scanner that orchestrates multiple extractors
|
|
3
|
+
*/
|
|
4
|
+
import { minimatch } from 'minimatch';
|
|
5
|
+
import * as fs from 'node:fs/promises';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import { createInitialContext, runParsePipeline } from '../plugins/pipeline.js';
|
|
8
|
+
import { validateExampleMetadata } from '../plugins/validation.js';
|
|
9
|
+
import { createSchemaValidator } from '../schema/validator.js';
|
|
10
|
+
import { DefaultMap, iter, } from '../types/index.js';
|
|
11
|
+
import { resolveCandidates } from './candidates.js';
|
|
12
|
+
/**
|
|
13
|
+
* Scan a directory for examples using the provided extractors.
|
|
14
|
+
*
|
|
15
|
+
* The scanner:
|
|
16
|
+
* 1. Runs all extractors in parallel against the root
|
|
17
|
+
* 2. Collects claimed files and detects conflicts
|
|
18
|
+
* 3. Resolves conflicts via path mappings (or errors if unresolved)
|
|
19
|
+
* 4. Applies include/exclude filters AFTER extraction
|
|
20
|
+
* 5. Returns unified results
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { resolveConfig, scanExamples } from 'functional-examples';
|
|
25
|
+
*
|
|
26
|
+
* const config = await resolveConfig({ root: './examples' });
|
|
27
|
+
* const result = await scanExamples(config);
|
|
28
|
+
*
|
|
29
|
+
* for (const example of result.examples) {
|
|
30
|
+
* console.log(example.title);
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export async function scanExamples(config) {
|
|
35
|
+
const startTime = Date.now();
|
|
36
|
+
const { root: configRoot, pathMappings = [], registry, metadata: metadataSchema, } = config;
|
|
37
|
+
const { include, exclude, root: scanRoot } = config.scan;
|
|
38
|
+
const root = scanRoot ?? configRoot;
|
|
39
|
+
console.log({ root, scanRoot, configRoot });
|
|
40
|
+
// Resolve candidates from include/exclude patterns
|
|
41
|
+
// Default to '*' if no include patterns specified (match direct children)
|
|
42
|
+
const candidates = await resolveCandidates(root, include.length > 0 ? include : ['*'], exclude);
|
|
43
|
+
// Collect all extractors from the registry
|
|
44
|
+
const allExtractors = registry.getExtractors();
|
|
45
|
+
if (allExtractors.length === 0) {
|
|
46
|
+
return {
|
|
47
|
+
examples: [],
|
|
48
|
+
errors: [
|
|
49
|
+
{
|
|
50
|
+
path: root,
|
|
51
|
+
message: 'No extractors provided',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
conflicts: [],
|
|
55
|
+
stats: {
|
|
56
|
+
filesClaimed: 0,
|
|
57
|
+
examplesFound: 0,
|
|
58
|
+
conflictsDetected: 0,
|
|
59
|
+
conflictsResolved: 0,
|
|
60
|
+
durationMs: Date.now() - startTime,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Step 1: Run all extractors in parallel
|
|
65
|
+
const extractorResults = await runExtractorsInParallel(allExtractors, candidates, {
|
|
66
|
+
rootPath: root,
|
|
67
|
+
exclude,
|
|
68
|
+
});
|
|
69
|
+
// Step 2: Build file claim map (file -> [extractor names])
|
|
70
|
+
const fileClaimMap = buildFileClaimMap(extractorResults);
|
|
71
|
+
// Step 3: Detect and resolve conflicts
|
|
72
|
+
const { conflicts, resolvedConflicts, unresolvedConflicts } = resolveConflicts(fileClaimMap, pathMappings);
|
|
73
|
+
// Step 4: Filter examples based on conflict resolution
|
|
74
|
+
const allExamples = extractorResults.flatMap((r) => r.examples);
|
|
75
|
+
const filteredExamples = filterExamplesByConflicts(allExamples, unresolvedConflicts, resolvedConflicts);
|
|
76
|
+
// Step 5: No post-extraction filtering - include/exclude only affect candidate resolution
|
|
77
|
+
// Step 6: Convert to ScannedExample (compute displayPath)
|
|
78
|
+
const scannedExamples = filteredExamples.map((example) => ({
|
|
79
|
+
...example,
|
|
80
|
+
displayPath: path.relative(root, example.rootPath) || '.',
|
|
81
|
+
metadata: example.metadata,
|
|
82
|
+
}));
|
|
83
|
+
// Build lookup for examples by ID
|
|
84
|
+
const examplesById = new Map(scannedExamples.map((ex) => [ex.id, ex]));
|
|
85
|
+
// Step 7: Initialize error accumulator (displayPath -> source -> messages[])
|
|
86
|
+
const errorsByPath = new DefaultMap(() => new DefaultMap(() => []));
|
|
87
|
+
// Helper to add errors to the accumulator
|
|
88
|
+
const addError = (displayPath, source, message) => {
|
|
89
|
+
errorsByPath.get(displayPath).get(source).push(message);
|
|
90
|
+
};
|
|
91
|
+
// Collect extractor errors
|
|
92
|
+
for (const result of extractorResults) {
|
|
93
|
+
for (const error of result.errors) {
|
|
94
|
+
const displayPath = path.relative(root, error.path) || error.path;
|
|
95
|
+
addError(displayPath, result.extractorName, error.message);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Collect unresolved conflict errors
|
|
99
|
+
for (const conflict of unresolvedConflicts) {
|
|
100
|
+
const displayPath = path.relative(root, conflict.filePath) || '.';
|
|
101
|
+
addError(displayPath, 'conflict', `File claimed by multiple extractors: ${conflict.claimants.join(', ')}. Add a pathMapping to resolve.`);
|
|
102
|
+
}
|
|
103
|
+
// Step 8: Process file contents through parser pipelines
|
|
104
|
+
for (const example of scannedExamples) {
|
|
105
|
+
for (const file of example.files) {
|
|
106
|
+
const ext = path.extname(file.absolutePath);
|
|
107
|
+
const parsers = registry.getParsersForExtension(ext);
|
|
108
|
+
if (parsers.length > 0) {
|
|
109
|
+
// Load file content if not already loaded
|
|
110
|
+
if (file.raw === undefined) {
|
|
111
|
+
file.raw = await fs.readFile(file.absolutePath, 'utf-8');
|
|
112
|
+
}
|
|
113
|
+
const ctx = createInitialContext(file.absolutePath, file.raw);
|
|
114
|
+
const result = await runParsePipeline(ctx, parsers);
|
|
115
|
+
file.parsed = result.parsed;
|
|
116
|
+
file.hunks = result.hunks;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Step 9: Run plugin metadata validators
|
|
121
|
+
const metadataValidators = registry.getMetadataValidators();
|
|
122
|
+
if (metadataValidators.length > 0) {
|
|
123
|
+
const validationResult = validateExampleMetadata({
|
|
124
|
+
validators: metadataValidators,
|
|
125
|
+
examples: scannedExamples.map((e) => ({
|
|
126
|
+
id: e.id,
|
|
127
|
+
metadata: e.metadata,
|
|
128
|
+
})),
|
|
129
|
+
});
|
|
130
|
+
for (const error of validationResult.errors) {
|
|
131
|
+
const example = examplesById.get(error.exampleId);
|
|
132
|
+
if (example) {
|
|
133
|
+
addError(example.displayPath, error.pluginName, error.message);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Step 10: Run config metadata schema validation (AJV)
|
|
138
|
+
if (metadataSchema) {
|
|
139
|
+
const validateSchema = createSchemaValidator(metadataSchema);
|
|
140
|
+
for (const example of scannedExamples) {
|
|
141
|
+
const result = validateSchema(example.metadata);
|
|
142
|
+
if (!result.success) {
|
|
143
|
+
for (const error of result.errors) {
|
|
144
|
+
addError(example.displayPath, 'config.metadata', `${error.path || '(root)'}: ${error.message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Step 11: Flatten errors into final array
|
|
150
|
+
const errors = iter(errorsByPath.entries())
|
|
151
|
+
.map(([displayPath, sourceErrors]) => ({
|
|
152
|
+
path: displayPath,
|
|
153
|
+
message: iter(sourceErrors.entries())
|
|
154
|
+
.map(([source, msgs]) => iter(msgs)
|
|
155
|
+
.map((msg) => ` ${msg}`)
|
|
156
|
+
.prefix([` [${source}]:`]))
|
|
157
|
+
.flat()
|
|
158
|
+
.join('\n'),
|
|
159
|
+
}))
|
|
160
|
+
.collect();
|
|
161
|
+
// for (const [displayPath, sourceErrors] of errorsByPath.entries()) {
|
|
162
|
+
// const lines: string[] = [];
|
|
163
|
+
// for (const [source, msgs] of sourceErrors.entries()) {
|
|
164
|
+
// lines.push(` [${source}]:`);
|
|
165
|
+
// for (const msg of msgs) {
|
|
166
|
+
// lines.push(` ${msg}`);
|
|
167
|
+
// }
|
|
168
|
+
// }
|
|
169
|
+
// errors.push({ path: displayPath, message: lines.join('\n') });
|
|
170
|
+
// }
|
|
171
|
+
return {
|
|
172
|
+
examples: scannedExamples,
|
|
173
|
+
errors,
|
|
174
|
+
conflicts,
|
|
175
|
+
stats: {
|
|
176
|
+
filesClaimed: fileClaimMap.size,
|
|
177
|
+
examplesFound: scannedExamples.length,
|
|
178
|
+
conflictsDetected: conflicts.length,
|
|
179
|
+
conflictsResolved: resolvedConflicts.length,
|
|
180
|
+
durationMs: Date.now() - startTime,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Run all extractors in parallel
|
|
186
|
+
*/
|
|
187
|
+
async function runExtractorsInParallel(extractors, candidates, options) {
|
|
188
|
+
const results = await Promise.all(extractors.map(async (extractor) => {
|
|
189
|
+
try {
|
|
190
|
+
const result = await extractor.extract(candidates, options);
|
|
191
|
+
return { ...result, extractorName: extractor.name };
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
// Extractor threw unexpectedly - wrap as error result
|
|
195
|
+
return {
|
|
196
|
+
examples: [],
|
|
197
|
+
errors: [
|
|
198
|
+
{
|
|
199
|
+
path: options.rootPath,
|
|
200
|
+
message: `Extractor "${extractor.name}" failed: ${error.message}`,
|
|
201
|
+
cause: error,
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
claimedFiles: new Set(),
|
|
205
|
+
extractorName: extractor.name,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}));
|
|
209
|
+
return results;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Build a map of file path -> extractor names that claimed it
|
|
213
|
+
*/
|
|
214
|
+
function buildFileClaimMap(results) {
|
|
215
|
+
const fileClaimMap = new Map();
|
|
216
|
+
for (const result of results) {
|
|
217
|
+
for (const file of result.claimedFiles) {
|
|
218
|
+
const existing = fileClaimMap.get(file) ?? [];
|
|
219
|
+
existing.push(result.extractorName);
|
|
220
|
+
fileClaimMap.set(file, existing);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return fileClaimMap;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Detect conflicts and attempt resolution via path mappings
|
|
227
|
+
*/
|
|
228
|
+
function resolveConflicts(fileClaimMap, pathMappings) {
|
|
229
|
+
const conflicts = [];
|
|
230
|
+
const resolvedConflicts = [];
|
|
231
|
+
const unresolvedConflicts = [];
|
|
232
|
+
for (const [filePath, claimants] of fileClaimMap) {
|
|
233
|
+
if (claimants.length <= 1)
|
|
234
|
+
continue;
|
|
235
|
+
// This is a conflict - try to resolve via path mappings
|
|
236
|
+
let resolved = false;
|
|
237
|
+
for (const mapping of pathMappings) {
|
|
238
|
+
if (minimatch(filePath, mapping.pattern)) {
|
|
239
|
+
if (claimants.includes(mapping.extractor)) {
|
|
240
|
+
const conflict = {
|
|
241
|
+
filePath,
|
|
242
|
+
claimants,
|
|
243
|
+
resolution: 'path-mapping',
|
|
244
|
+
winner: mapping.extractor,
|
|
245
|
+
};
|
|
246
|
+
conflicts.push(conflict);
|
|
247
|
+
resolvedConflicts.push(conflict);
|
|
248
|
+
resolved = true;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (!resolved) {
|
|
254
|
+
const conflict = {
|
|
255
|
+
filePath,
|
|
256
|
+
claimants,
|
|
257
|
+
resolution: 'error',
|
|
258
|
+
};
|
|
259
|
+
conflicts.push(conflict);
|
|
260
|
+
unresolvedConflicts.push(conflict);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return { conflicts, resolvedConflicts, unresolvedConflicts };
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Filter examples based on conflict resolution.
|
|
267
|
+
* - Remove examples containing files from unresolved conflicts
|
|
268
|
+
* - For resolved conflicts, keep only the winning extractor's examples
|
|
269
|
+
*/
|
|
270
|
+
function filterExamplesByConflicts(examples, unresolvedConflicts, resolvedConflicts) {
|
|
271
|
+
const unresolvedFiles = new Set(unresolvedConflicts.map((c) => c.filePath));
|
|
272
|
+
// Build map of file -> winning extractor for resolved conflicts
|
|
273
|
+
const winnerMap = new Map();
|
|
274
|
+
for (const conflict of resolvedConflicts) {
|
|
275
|
+
if (conflict.winner) {
|
|
276
|
+
winnerMap.set(conflict.filePath, conflict.winner);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return examples.filter((example) => {
|
|
280
|
+
// Check if any file in this example is part of an unresolved conflict
|
|
281
|
+
const hasUnresolvedFile = example.files.some((f) => unresolvedFiles.has(f.absolutePath));
|
|
282
|
+
if (hasUnresolvedFile) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
// Check if any file in this example is part of a resolved conflict
|
|
286
|
+
// where this extractor is NOT the winner
|
|
287
|
+
for (const file of example.files) {
|
|
288
|
+
const winner = winnerMap.get(file.absolutePath);
|
|
289
|
+
if (winner && winner !== example.extractorName) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return true;
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/scanner/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.spec.d.ts","sourceRoot":"","sources":["../../src/scanner/scanner.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { scanExamples } from './scanner.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create a mock extractor for testing
|
|
5
|
+
*/
|
|
6
|
+
function createMockExtractor(name, result) {
|
|
7
|
+
return {
|
|
8
|
+
name,
|
|
9
|
+
extract: vi.fn().mockResolvedValue({
|
|
10
|
+
examples: [],
|
|
11
|
+
errors: [],
|
|
12
|
+
claimedFiles: new Set(),
|
|
13
|
+
...result,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a mock example for testing
|
|
19
|
+
*/
|
|
20
|
+
function createMockExample(id, extractorName, files) {
|
|
21
|
+
return {
|
|
22
|
+
id,
|
|
23
|
+
title: `Example ${id}`,
|
|
24
|
+
rootPath: `/test/${id}`,
|
|
25
|
+
files: files.map((f) => ({
|
|
26
|
+
absolutePath: f,
|
|
27
|
+
relativePath: f.split('/').pop() ?? f,
|
|
28
|
+
})),
|
|
29
|
+
metadata: {},
|
|
30
|
+
extractorName,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
describe('scanExamples', () => {
|
|
34
|
+
describe('basic operation', () => {
|
|
35
|
+
it('returns empty result when no extractors provided', async () => {
|
|
36
|
+
const result = await scanExamples({
|
|
37
|
+
root: '/test',
|
|
38
|
+
extractors: [],
|
|
39
|
+
});
|
|
40
|
+
expect(result.examples).toEqual([]);
|
|
41
|
+
expect(result.errors).toHaveLength(1);
|
|
42
|
+
expect(result.errors[0].message).toBe('No extractors provided');
|
|
43
|
+
});
|
|
44
|
+
it('runs extractors in parallel and collects results', async () => {
|
|
45
|
+
const example1 = createMockExample('ex1', 'extractor-a', ['/test/a.ts']);
|
|
46
|
+
const example2 = createMockExample('ex2', 'extractor-b', ['/test/b.ts']);
|
|
47
|
+
const extractorA = createMockExtractor('extractor-a', {
|
|
48
|
+
examples: [example1],
|
|
49
|
+
claimedFiles: new Set(['/test/a.ts']),
|
|
50
|
+
});
|
|
51
|
+
const extractorB = createMockExtractor('extractor-b', {
|
|
52
|
+
examples: [example2],
|
|
53
|
+
claimedFiles: new Set(['/test/b.ts']),
|
|
54
|
+
});
|
|
55
|
+
const result = await scanExamples({
|
|
56
|
+
root: '/test',
|
|
57
|
+
extractors: [extractorA, extractorB],
|
|
58
|
+
});
|
|
59
|
+
expect(extractorA.extract).toHaveBeenCalledWith('/test', expect.any(Object));
|
|
60
|
+
expect(extractorB.extract).toHaveBeenCalledWith('/test', expect.any(Object));
|
|
61
|
+
expect(result.examples).toHaveLength(2);
|
|
62
|
+
expect(result.examples.map((e) => e.id)).toEqual(['ex1', 'ex2']);
|
|
63
|
+
expect(result.errors).toHaveLength(0);
|
|
64
|
+
expect(result.conflicts).toHaveLength(0);
|
|
65
|
+
});
|
|
66
|
+
it('collects errors from extractors', async () => {
|
|
67
|
+
const extractor = createMockExtractor('extractor-a', {
|
|
68
|
+
errors: [{ path: '/test/bad.ts', message: 'Invalid syntax' }],
|
|
69
|
+
});
|
|
70
|
+
const result = await scanExamples({
|
|
71
|
+
root: '/test',
|
|
72
|
+
extractors: [extractor],
|
|
73
|
+
});
|
|
74
|
+
expect(result.errors).toHaveLength(1);
|
|
75
|
+
expect(result.errors[0].message).toBe('Invalid syntax');
|
|
76
|
+
});
|
|
77
|
+
it('handles extractor exceptions gracefully', async () => {
|
|
78
|
+
const extractor = {
|
|
79
|
+
name: 'failing-extractor',
|
|
80
|
+
extract: vi.fn().mockRejectedValue(new Error('Extractor crashed')),
|
|
81
|
+
};
|
|
82
|
+
const result = await scanExamples({
|
|
83
|
+
root: '/test',
|
|
84
|
+
extractors: [extractor],
|
|
85
|
+
});
|
|
86
|
+
expect(result.errors).toHaveLength(1);
|
|
87
|
+
expect(result.errors[0].message).toContain('Extractor "failing-extractor" failed');
|
|
88
|
+
expect(result.errors[0].message).toContain('Extractor crashed');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('conflict detection', () => {
|
|
92
|
+
it('detects when multiple extractors claim the same file', async () => {
|
|
93
|
+
const sharedFile = '/test/shared.ts';
|
|
94
|
+
const example1 = createMockExample('ex1', 'extractor-a', [sharedFile]);
|
|
95
|
+
const example2 = createMockExample('ex2', 'extractor-b', [sharedFile]);
|
|
96
|
+
const extractorA = createMockExtractor('extractor-a', {
|
|
97
|
+
examples: [example1],
|
|
98
|
+
claimedFiles: new Set([sharedFile]),
|
|
99
|
+
});
|
|
100
|
+
const extractorB = createMockExtractor('extractor-b', {
|
|
101
|
+
examples: [example2],
|
|
102
|
+
claimedFiles: new Set([sharedFile]),
|
|
103
|
+
});
|
|
104
|
+
const result = await scanExamples({
|
|
105
|
+
root: '/test',
|
|
106
|
+
extractors: [extractorA, extractorB],
|
|
107
|
+
});
|
|
108
|
+
expect(result.conflicts).toHaveLength(1);
|
|
109
|
+
expect(result.conflicts[0].filePath).toBe(sharedFile);
|
|
110
|
+
expect(result.conflicts[0].claimants).toEqual(['extractor-a', 'extractor-b']);
|
|
111
|
+
expect(result.conflicts[0].resolution).toBe('error');
|
|
112
|
+
expect(result.stats.conflictsDetected).toBe(1);
|
|
113
|
+
expect(result.stats.conflictsResolved).toBe(0);
|
|
114
|
+
});
|
|
115
|
+
it('adds error for unresolved conflicts', async () => {
|
|
116
|
+
const sharedFile = '/test/shared.ts';
|
|
117
|
+
const extractorA = createMockExtractor('extractor-a', {
|
|
118
|
+
examples: [createMockExample('ex1', 'extractor-a', [sharedFile])],
|
|
119
|
+
claimedFiles: new Set([sharedFile]),
|
|
120
|
+
});
|
|
121
|
+
const extractorB = createMockExtractor('extractor-b', {
|
|
122
|
+
examples: [createMockExample('ex2', 'extractor-b', [sharedFile])],
|
|
123
|
+
claimedFiles: new Set([sharedFile]),
|
|
124
|
+
});
|
|
125
|
+
const result = await scanExamples({
|
|
126
|
+
root: '/test',
|
|
127
|
+
extractors: [extractorA, extractorB],
|
|
128
|
+
});
|
|
129
|
+
expect(result.errors).toHaveLength(1);
|
|
130
|
+
expect(result.errors[0].message).toContain('claimed by multiple extractors');
|
|
131
|
+
expect(result.errors[0].message).toContain('extractor-a');
|
|
132
|
+
expect(result.errors[0].message).toContain('extractor-b');
|
|
133
|
+
});
|
|
134
|
+
it('excludes examples with conflicting files from results', async () => {
|
|
135
|
+
const sharedFile = '/test/shared.ts';
|
|
136
|
+
const extractorA = createMockExtractor('extractor-a', {
|
|
137
|
+
examples: [createMockExample('ex1', 'extractor-a', [sharedFile])],
|
|
138
|
+
claimedFiles: new Set([sharedFile]),
|
|
139
|
+
});
|
|
140
|
+
const extractorB = createMockExtractor('extractor-b', {
|
|
141
|
+
examples: [createMockExample('ex2', 'extractor-b', [sharedFile])],
|
|
142
|
+
claimedFiles: new Set([sharedFile]),
|
|
143
|
+
});
|
|
144
|
+
const result = await scanExamples({
|
|
145
|
+
root: '/test',
|
|
146
|
+
extractors: [extractorA, extractorB],
|
|
147
|
+
});
|
|
148
|
+
// Both examples should be excluded due to unresolved conflict
|
|
149
|
+
expect(result.examples).toHaveLength(0);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('conflict resolution via path mappings', () => {
|
|
153
|
+
it('resolves conflicts using path mappings', async () => {
|
|
154
|
+
const sharedFile = '/test/cli-forge/example.ts';
|
|
155
|
+
const example1 = createMockExample('ex1', 'frontmatter', [sharedFile]);
|
|
156
|
+
const example2 = createMockExample('ex2', 'meta-yml', [sharedFile]);
|
|
157
|
+
const extractorA = createMockExtractor('frontmatter', {
|
|
158
|
+
examples: [example1],
|
|
159
|
+
claimedFiles: new Set([sharedFile]),
|
|
160
|
+
});
|
|
161
|
+
const extractorB = createMockExtractor('meta-yml', {
|
|
162
|
+
examples: [example2],
|
|
163
|
+
claimedFiles: new Set([sharedFile]),
|
|
164
|
+
});
|
|
165
|
+
const result = await scanExamples({
|
|
166
|
+
root: '/test',
|
|
167
|
+
extractors: [extractorA, extractorB],
|
|
168
|
+
pathMappings: [
|
|
169
|
+
{ pattern: '**/cli-forge/**', extractor: 'frontmatter' },
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
expect(result.conflicts).toHaveLength(1);
|
|
173
|
+
expect(result.conflicts[0].resolution).toBe('path-mapping');
|
|
174
|
+
expect(result.conflicts[0].winner).toBe('frontmatter');
|
|
175
|
+
expect(result.stats.conflictsResolved).toBe(1);
|
|
176
|
+
// Only the winning extractor's example should be included
|
|
177
|
+
expect(result.examples).toHaveLength(1);
|
|
178
|
+
expect(result.examples[0].extractorName).toBe('frontmatter');
|
|
179
|
+
});
|
|
180
|
+
it('ignores path mappings that do not match any claimant', async () => {
|
|
181
|
+
const sharedFile = '/test/shared.ts';
|
|
182
|
+
const extractorA = createMockExtractor('extractor-a', {
|
|
183
|
+
examples: [createMockExample('ex1', 'extractor-a', [sharedFile])],
|
|
184
|
+
claimedFiles: new Set([sharedFile]),
|
|
185
|
+
});
|
|
186
|
+
const extractorB = createMockExtractor('extractor-b', {
|
|
187
|
+
examples: [createMockExample('ex2', 'extractor-b', [sharedFile])],
|
|
188
|
+
claimedFiles: new Set([sharedFile]),
|
|
189
|
+
});
|
|
190
|
+
const result = await scanExamples({
|
|
191
|
+
root: '/test',
|
|
192
|
+
extractors: [extractorA, extractorB],
|
|
193
|
+
pathMappings: [
|
|
194
|
+
// This mapping specifies an extractor that didn't claim the file
|
|
195
|
+
{ pattern: '**/*.ts', extractor: 'non-existent' },
|
|
196
|
+
],
|
|
197
|
+
});
|
|
198
|
+
// Conflict remains unresolved
|
|
199
|
+
expect(result.conflicts[0].resolution).toBe('error');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
describe('include/exclude filtering', () => {
|
|
203
|
+
it('excludes examples matching exclude patterns', async () => {
|
|
204
|
+
const example1 = createMockExample('ex1', 'extractor', ['/test/src/a.ts']);
|
|
205
|
+
const example2 = createMockExample('ex2', 'extractor', ['/test/dist/b.ts']);
|
|
206
|
+
example1.rootPath = '/test/src/a.ts';
|
|
207
|
+
example2.rootPath = '/test/dist/b.ts';
|
|
208
|
+
const extractor = createMockExtractor('extractor', {
|
|
209
|
+
examples: [example1, example2],
|
|
210
|
+
claimedFiles: new Set(['/test/src/a.ts', '/test/dist/b.ts']),
|
|
211
|
+
});
|
|
212
|
+
const result = await scanExamples({
|
|
213
|
+
root: '/test',
|
|
214
|
+
extractors: [extractor],
|
|
215
|
+
exclude: ['**/dist/**'],
|
|
216
|
+
});
|
|
217
|
+
expect(result.examples).toHaveLength(1);
|
|
218
|
+
expect(result.examples[0].id).toBe('ex1');
|
|
219
|
+
});
|
|
220
|
+
it('includes only examples matching include patterns', async () => {
|
|
221
|
+
const example1 = createMockExample('ex1', 'extractor', ['/test/examples/a.ts']);
|
|
222
|
+
const example2 = createMockExample('ex2', 'extractor', ['/test/src/b.ts']);
|
|
223
|
+
example1.rootPath = '/test/examples/a.ts';
|
|
224
|
+
example2.rootPath = '/test/src/b.ts';
|
|
225
|
+
const extractor = createMockExtractor('extractor', {
|
|
226
|
+
examples: [example1, example2],
|
|
227
|
+
claimedFiles: new Set(['/test/examples/a.ts', '/test/src/b.ts']),
|
|
228
|
+
});
|
|
229
|
+
const result = await scanExamples({
|
|
230
|
+
root: '/test',
|
|
231
|
+
extractors: [extractor],
|
|
232
|
+
include: ['**/examples/**'],
|
|
233
|
+
});
|
|
234
|
+
expect(result.examples).toHaveLength(1);
|
|
235
|
+
expect(result.examples[0].id).toBe('ex1');
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe('statistics', () => {
|
|
239
|
+
it('reports accurate statistics', async () => {
|
|
240
|
+
const example1 = createMockExample('ex1', 'extractor-a', ['/test/a.ts', '/test/b.ts']);
|
|
241
|
+
const example2 = createMockExample('ex2', 'extractor-b', ['/test/c.ts']);
|
|
242
|
+
const extractorA = createMockExtractor('extractor-a', {
|
|
243
|
+
examples: [example1],
|
|
244
|
+
claimedFiles: new Set(['/test/a.ts', '/test/b.ts']),
|
|
245
|
+
});
|
|
246
|
+
const extractorB = createMockExtractor('extractor-b', {
|
|
247
|
+
examples: [example2],
|
|
248
|
+
claimedFiles: new Set(['/test/c.ts']),
|
|
249
|
+
});
|
|
250
|
+
const result = await scanExamples({
|
|
251
|
+
root: '/test',
|
|
252
|
+
extractors: [extractorA, extractorB],
|
|
253
|
+
});
|
|
254
|
+
expect(result.stats.filesClaimed).toBe(3);
|
|
255
|
+
expect(result.stats.examplesFound).toBe(2);
|
|
256
|
+
expect(result.stats.conflictsDetected).toBe(0);
|
|
257
|
+
expect(result.stats.conflictsResolved).toBe(0);
|
|
258
|
+
expect(result.stats.durationMs).toBeGreaterThanOrEqual(0);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
//# sourceMappingURL=scanner.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.spec.js","sourceRoot":"","sources":["../../src/scanner/scanner.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scanner types for orchestrating extractors
|
|
3
|
+
*/
|
|
4
|
+
import type { ExtractorError, ScannedExample } from '../types/index.js';
|
|
5
|
+
export type { PathMapping } from '../types/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Conflict when multiple extractors claim the same file
|
|
8
|
+
*/
|
|
9
|
+
export interface FileConflict {
|
|
10
|
+
/** The conflicting file path */
|
|
11
|
+
filePath: string;
|
|
12
|
+
/** Extractors that claimed this file */
|
|
13
|
+
claimants: string[];
|
|
14
|
+
/** How the conflict was resolved (if at all) */
|
|
15
|
+
resolution?: 'path-mapping' | 'error';
|
|
16
|
+
/** Winner extractor name (if resolved) */
|
|
17
|
+
winner?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Result of scanning for examples
|
|
21
|
+
*/
|
|
22
|
+
export interface ScanResult<TMetadata = Record<string, unknown>> {
|
|
23
|
+
/** All discovered examples (with computed fields like displayPath) */
|
|
24
|
+
examples: ScannedExample<TMetadata>[];
|
|
25
|
+
/** Errors from all extractors */
|
|
26
|
+
errors: ExtractorError[];
|
|
27
|
+
/** File conflicts (including resolved ones) */
|
|
28
|
+
conflicts: FileConflict[];
|
|
29
|
+
/** Scan statistics */
|
|
30
|
+
stats: {
|
|
31
|
+
/** Total files claimed by extractors */
|
|
32
|
+
filesClaimed: number;
|
|
33
|
+
/** Total examples found */
|
|
34
|
+
examplesFound: number;
|
|
35
|
+
/** Number of conflicts detected */
|
|
36
|
+
conflictsDetected: number;
|
|
37
|
+
/** Number of conflicts resolved */
|
|
38
|
+
conflictsResolved: number;
|
|
39
|
+
/** Duration in milliseconds */
|
|
40
|
+
durationMs: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scanner/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACf,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gDAAgD;IAChD,UAAU,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;IACtC,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7D,sEAAsE;IACtE,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;IACtC,iCAAiC;IACjC,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,+CAA+C;IAC/C,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,sBAAsB;IACtB,KAAK,EAAE;QACL,wCAAwC;QACxC,YAAY,EAAE,MAAM,CAAC;QACrB,2BAA2B;QAC3B,aAAa,EAAE,MAAM,CAAC;QACtB,mCAAmC;QACnC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,mCAAmC;QACnC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,+BAA+B;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/scanner/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|