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.
Files changed (202) hide show
  1. package/README.md +148 -0
  2. package/dist/cli/commands/generate.d.ts +10 -0
  3. package/dist/cli/commands/generate.d.ts.map +1 -0
  4. package/dist/cli/commands/generate.js +64 -0
  5. package/dist/cli/commands/generate.js.map +1 -0
  6. package/dist/cli/commands/init.d.ts +14 -0
  7. package/dist/cli/commands/init.d.ts.map +1 -0
  8. package/dist/cli/commands/init.js +95 -0
  9. package/dist/cli/commands/init.js.map +1 -0
  10. package/dist/cli/commands/scan.d.ts +20 -0
  11. package/dist/cli/commands/scan.d.ts.map +1 -0
  12. package/dist/cli/commands/scan.js +182 -0
  13. package/dist/cli/commands/scan.js.map +1 -0
  14. package/dist/cli/commands/validate.d.ts +10 -0
  15. package/dist/cli/commands/validate.d.ts.map +1 -0
  16. package/dist/cli/commands/validate.js +65 -0
  17. package/dist/cli/commands/validate.js.map +1 -0
  18. package/dist/cli/index.d.ts +88 -0
  19. package/dist/cli/index.d.ts.map +1 -0
  20. package/dist/cli/index.js +43 -0
  21. package/dist/cli/index.js.map +1 -0
  22. package/dist/cli/plugin-commands.d.ts +17 -0
  23. package/dist/cli/plugin-commands.d.ts.map +1 -0
  24. package/dist/cli/plugin-commands.js +45 -0
  25. package/dist/cli/plugin-commands.js.map +1 -0
  26. package/dist/config/index.d.ts +11 -0
  27. package/dist/config/index.d.ts.map +1 -0
  28. package/dist/config/index.js +9 -0
  29. package/dist/config/index.js.map +1 -0
  30. package/dist/config/index.spec.d.ts +5 -0
  31. package/dist/config/index.spec.d.ts.map +1 -0
  32. package/dist/config/index.spec.js +142 -0
  33. package/dist/config/index.spec.js.map +1 -0
  34. package/dist/config/loader.d.ts +7 -0
  35. package/dist/config/loader.d.ts.map +1 -0
  36. package/dist/config/loader.js +85 -0
  37. package/dist/config/loader.js.map +1 -0
  38. package/dist/config/merger.d.ts +27 -0
  39. package/dist/config/merger.d.ts.map +1 -0
  40. package/dist/config/merger.js +41 -0
  41. package/dist/config/merger.js.map +1 -0
  42. package/dist/config/resolver.d.ts +28 -0
  43. package/dist/config/resolver.d.ts.map +1 -0
  44. package/dist/config/resolver.js +165 -0
  45. package/dist/config/resolver.js.map +1 -0
  46. package/dist/config/schema.d.ts +53 -0
  47. package/dist/config/schema.d.ts.map +1 -0
  48. package/dist/config/schema.js +42 -0
  49. package/dist/config/schema.js.map +1 -0
  50. package/dist/config/types.d.ts +17 -0
  51. package/dist/config/types.d.ts.map +1 -0
  52. package/dist/config/types.js +5 -0
  53. package/dist/config/types.js.map +1 -0
  54. package/dist/config/validator.d.ts +6 -0
  55. package/dist/config/validator.d.ts.map +1 -0
  56. package/dist/config/validator.js +17 -0
  57. package/dist/config/validator.js.map +1 -0
  58. package/dist/extractors/index.d.ts +9 -0
  59. package/dist/extractors/index.d.ts.map +1 -0
  60. package/dist/extractors/index.js +9 -0
  61. package/dist/extractors/index.js.map +1 -0
  62. package/dist/extractors/loader.d.ts +19 -0
  63. package/dist/extractors/loader.d.ts.map +1 -0
  64. package/dist/extractors/loader.js +120 -0
  65. package/dist/extractors/loader.js.map +1 -0
  66. package/dist/extractors/meta-yml-fn.d.ts +19 -0
  67. package/dist/extractors/meta-yml-fn.d.ts.map +1 -0
  68. package/dist/extractors/meta-yml-fn.js +66 -0
  69. package/dist/extractors/meta-yml-fn.js.map +1 -0
  70. package/dist/extractors/meta-yml.d.ts +24 -0
  71. package/dist/extractors/meta-yml.d.ts.map +1 -0
  72. package/dist/extractors/meta-yml.js +65 -0
  73. package/dist/extractors/meta-yml.js.map +1 -0
  74. package/dist/extractors/registry.d.ts +58 -0
  75. package/dist/extractors/registry.d.ts.map +1 -0
  76. package/dist/extractors/registry.js +114 -0
  77. package/dist/extractors/registry.js.map +1 -0
  78. package/dist/extractors/registry.spec.d.ts +2 -0
  79. package/dist/extractors/registry.spec.d.ts.map +1 -0
  80. package/dist/extractors/registry.spec.js +102 -0
  81. package/dist/extractors/registry.spec.js.map +1 -0
  82. package/dist/extractors/types.d.ts +34 -0
  83. package/dist/extractors/types.d.ts.map +1 -0
  84. package/dist/extractors/types.js +8 -0
  85. package/dist/extractors/types.js.map +1 -0
  86. package/dist/extractors/yaml-frontmatter-fn.d.ts +18 -0
  87. package/dist/extractors/yaml-frontmatter-fn.d.ts.map +1 -0
  88. package/dist/extractors/yaml-frontmatter-fn.js +73 -0
  89. package/dist/extractors/yaml-frontmatter-fn.js.map +1 -0
  90. package/dist/extractors/yaml-frontmatter.d.ts +22 -0
  91. package/dist/extractors/yaml-frontmatter.d.ts.map +1 -0
  92. package/dist/extractors/yaml-frontmatter.js +83 -0
  93. package/dist/extractors/yaml-frontmatter.js.map +1 -0
  94. package/dist/extractors/yaml-frontmatter.spec.d.ts +2 -0
  95. package/dist/extractors/yaml-frontmatter.spec.d.ts.map +1 -0
  96. package/dist/extractors/yaml-frontmatter.spec.js +134 -0
  97. package/dist/extractors/yaml-frontmatter.spec.js.map +1 -0
  98. package/dist/files/index.d.ts +5 -0
  99. package/dist/files/index.d.ts.map +1 -0
  100. package/dist/files/index.js +5 -0
  101. package/dist/files/index.js.map +1 -0
  102. package/dist/files/reader.d.ts +50 -0
  103. package/dist/files/reader.d.ts.map +1 -0
  104. package/dist/files/reader.js +62 -0
  105. package/dist/files/reader.js.map +1 -0
  106. package/dist/index.d.ts +29 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +22 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/plugins/index.d.ts +4 -0
  111. package/dist/plugins/index.d.ts.map +1 -0
  112. package/dist/plugins/index.js +4 -0
  113. package/dist/plugins/index.js.map +1 -0
  114. package/dist/plugins/pipeline.d.ts +11 -0
  115. package/dist/plugins/pipeline.d.ts.map +1 -0
  116. package/dist/plugins/pipeline.js +24 -0
  117. package/dist/plugins/pipeline.js.map +1 -0
  118. package/dist/plugins/registry.d.ts +57 -0
  119. package/dist/plugins/registry.d.ts.map +1 -0
  120. package/dist/plugins/registry.js +93 -0
  121. package/dist/plugins/registry.js.map +1 -0
  122. package/dist/plugins/validation.d.ts +64 -0
  123. package/dist/plugins/validation.d.ts.map +1 -0
  124. package/dist/plugins/validation.js +55 -0
  125. package/dist/plugins/validation.js.map +1 -0
  126. package/dist/regions/index.d.ts +7 -0
  127. package/dist/regions/index.d.ts.map +1 -0
  128. package/dist/regions/index.js +6 -0
  129. package/dist/regions/index.js.map +1 -0
  130. package/dist/regions/languages.d.ts +15 -0
  131. package/dist/regions/languages.d.ts.map +1 -0
  132. package/dist/regions/languages.js +182 -0
  133. package/dist/regions/languages.js.map +1 -0
  134. package/dist/regions/parser.d.ts +63 -0
  135. package/dist/regions/parser.d.ts.map +1 -0
  136. package/dist/regions/parser.js +175 -0
  137. package/dist/regions/parser.js.map +1 -0
  138. package/dist/regions/parser.spec.d.ts +2 -0
  139. package/dist/regions/parser.spec.d.ts.map +1 -0
  140. package/dist/regions/parser.spec.js +190 -0
  141. package/dist/regions/parser.spec.js.map +1 -0
  142. package/dist/regions/types.d.ts +37 -0
  143. package/dist/regions/types.d.ts.map +1 -0
  144. package/dist/regions/types.js +5 -0
  145. package/dist/regions/types.js.map +1 -0
  146. package/dist/scanner/candidates.d.ts +24 -0
  147. package/dist/scanner/candidates.d.ts.map +1 -0
  148. package/dist/scanner/candidates.js +83 -0
  149. package/dist/scanner/candidates.js.map +1 -0
  150. package/dist/scanner/index.d.ts +8 -0
  151. package/dist/scanner/index.d.ts.map +1 -0
  152. package/dist/scanner/index.js +6 -0
  153. package/dist/scanner/index.js.map +1 -0
  154. package/dist/scanner/scan.d.ts +40 -0
  155. package/dist/scanner/scan.d.ts.map +1 -0
  156. package/dist/scanner/scan.js +44 -0
  157. package/dist/scanner/scan.js.map +1 -0
  158. package/dist/scanner/scanner.d.ts +29 -0
  159. package/dist/scanner/scanner.d.ts.map +1 -0
  160. package/dist/scanner/scanner.js +296 -0
  161. package/dist/scanner/scanner.js.map +1 -0
  162. package/dist/scanner/scanner.spec.d.ts +2 -0
  163. package/dist/scanner/scanner.spec.d.ts.map +1 -0
  164. package/dist/scanner/scanner.spec.js +262 -0
  165. package/dist/scanner/scanner.spec.js.map +1 -0
  166. package/dist/scanner/types.d.ts +43 -0
  167. package/dist/scanner/types.d.ts.map +1 -0
  168. package/dist/scanner/types.js +5 -0
  169. package/dist/scanner/types.js.map +1 -0
  170. package/dist/schema/index.d.ts +4 -0
  171. package/dist/schema/index.d.ts.map +1 -0
  172. package/dist/schema/index.js +4 -0
  173. package/dist/schema/index.js.map +1 -0
  174. package/dist/schema/merger.d.ts +35 -0
  175. package/dist/schema/merger.d.ts.map +1 -0
  176. package/dist/schema/merger.js +161 -0
  177. package/dist/schema/merger.js.map +1 -0
  178. package/dist/schema/typegen.d.ts +13 -0
  179. package/dist/schema/typegen.d.ts.map +1 -0
  180. package/dist/schema/typegen.js +125 -0
  181. package/dist/schema/typegen.js.map +1 -0
  182. package/dist/schema/validator.d.ts +7 -0
  183. package/dist/schema/validator.d.ts.map +1 -0
  184. package/dist/schema/validator.js +32 -0
  185. package/dist/schema/validator.js.map +1 -0
  186. package/dist/types/default-map.d.ts +21 -0
  187. package/dist/types/default-map.d.ts.map +1 -0
  188. package/dist/types/default-map.js +32 -0
  189. package/dist/types/default-map.js.map +1 -0
  190. package/dist/types/extended-iterable.d.ts +197 -0
  191. package/dist/types/extended-iterable.d.ts.map +1 -0
  192. package/dist/types/extended-iterable.js +769 -0
  193. package/dist/types/extended-iterable.js.map +1 -0
  194. package/dist/types/guards.d.ts +2 -0
  195. package/dist/types/guards.d.ts.map +1 -0
  196. package/dist/types/guards.js +2 -0
  197. package/dist/types/guards.js.map +1 -0
  198. package/dist/types/index.d.ts +11 -0
  199. package/dist/types/index.d.ts.map +1 -0
  200. package/dist/types/index.js +10 -0
  201. package/dist/types/index.js.map +1 -0
  202. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # functional-examples
2
+
3
+ A language-agnostic library for treating code examples as first-class citizens.
4
+
5
+ ## Features
6
+
7
+ - **Pluggable metadata extraction**: YAML frontmatter and meta.yml built-in
8
+ - **Language-aware region parsing**: Extracts code regions with comment-style detection
9
+ - **Flexible scanning**: Directory-based and file-based example discovery
10
+ - **Type-safe API**: Full TypeScript support with generic metadata types
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install functional-examples
16
+ # or
17
+ pnpm add functional-examples
18
+ # or
19
+ yarn add functional-examples
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### Scanning for Examples
25
+
26
+ ```typescript
27
+ import { scanExamples } from 'functional-examples';
28
+
29
+ const { examples, errors } = await scanExamples('./examples');
30
+
31
+ for (const example of examples) {
32
+ console.log(example.metadata.title);
33
+ console.log(example.files.map(f => f.path));
34
+ }
35
+ ```
36
+
37
+ ### Extracting Code Regions
38
+
39
+ ```typescript
40
+ import { extractRegion, parseRegions } from 'functional-examples';
41
+
42
+ // Extract a specific region
43
+ const setupCode = extractRegion(code, 'setup', { extension: 'ts' });
44
+
45
+ // Get all regions
46
+ const regions = parseRegions(code, { extension: 'py' });
47
+ console.log(regions['main']?.content);
48
+ ```
49
+
50
+ ## Example Formats
51
+
52
+ ### Directory-based (meta.yml)
53
+
54
+ ```
55
+ examples/
56
+ my-example/
57
+ meta.yml
58
+ main.ts
59
+ helper.ts
60
+ ```
61
+
62
+ **meta.yml:**
63
+ ```yaml
64
+ id: my-example
65
+ title: My Example
66
+ description: Demonstrates something useful
67
+ entryPoint: main.ts
68
+ ```
69
+
70
+ ### File-based (YAML frontmatter)
71
+
72
+ ```typescript
73
+ // ---
74
+ // title: My Example
75
+ // description: A single-file example
76
+ // ---
77
+
78
+ console.log('Hello, world!');
79
+ ```
80
+
81
+ ## Region Markers
82
+
83
+ Mark regions in your code for extraction:
84
+
85
+ ```typescript
86
+ // #region setup
87
+ const db = createDatabase();
88
+ // #endregion setup
89
+
90
+ // #region main
91
+ await db.query('SELECT * FROM users');
92
+ // #endregion main
93
+ ```
94
+
95
+ Supports 30+ languages with automatic comment syntax detection.
96
+
97
+ ## Custom Extractors
98
+
99
+ ```typescript
100
+ import { ExtractorRegistry, MetadataExtractor } from 'functional-examples';
101
+
102
+ class TomlExtractor implements MetadataExtractor {
103
+ readonly name = 'toml';
104
+
105
+ canExtract(context) {
106
+ return context.entries?.includes('meta.toml') ?? false;
107
+ }
108
+
109
+ async extract(context) {
110
+ // Custom extraction logic
111
+ }
112
+ }
113
+
114
+ const registry = new ExtractorRegistry()
115
+ .register(new TomlExtractor());
116
+
117
+ const scanner = new ExampleScanner({ extractors: registry });
118
+ ```
119
+
120
+ ## API Reference
121
+
122
+ ### Scanner
123
+
124
+ - `scanExamples(directory, options?)` - Scan a directory for examples
125
+ - `ExampleScanner` - Class for customized scanning
126
+
127
+ ### Extractors
128
+
129
+ - `createDefaultRegistry()` - Create registry with built-in extractors
130
+ - `YamlFrontmatterExtractor` - Single-file YAML frontmatter
131
+ - `MetaYmlExtractor` - Directory-based meta.yml
132
+
133
+ ### Regions
134
+
135
+ - `parseRegions(code, options?)` - Parse all regions
136
+ - `extractRegion(code, regionId, options?)` - Extract single region
137
+ - `stripRegionMarkers(code, options?)` - Remove all markers
138
+ - `listRegions(code, options?)` - List region IDs
139
+ - `LANGUAGE_CONFIGS` - Language comment syntax mappings
140
+
141
+ ### File Helpers
142
+
143
+ - `readExampleFile(path, options?)` - Read file with optional region
144
+ - `readExampleFiles(directory, files)` - Read multiple files
145
+
146
+ ## License
147
+
148
+ MIT
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Generate command - create JSON Schema and TypeScript types
3
+ */
4
+ export declare const generateCommand: import("cli-forge").CLI<{
5
+ unmatched: string[];
6
+ '--'?: string[];
7
+ } & {
8
+ output?: string;
9
+ } & {}, Promise<void>, {}, undefined>;
10
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,eAAO,MAAM,eAAe;;;;;qCAwE1B,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Generate command - create JSON Schema and TypeScript types
3
+ */
4
+ import { cli } from 'cli-forge';
5
+ import { mkdir, writeFile } from 'node:fs/promises';
6
+ import path from 'node:path';
7
+ import { mergeConfigSchema, mergeMetadataSchemas, } from '../../schema/merger.js';
8
+ import { generateMetadataTypes } from '../../schema/typegen.js';
9
+ const DEFAULT_OUTPUT_DIR = '.functional-examples';
10
+ export const generateCommand = cli('generate', {
11
+ description: 'Generate JSON Schema and TypeScript types from config and plugins',
12
+ builder: (cmd) => cmd.option('output', {
13
+ type: 'string',
14
+ alias: ['o'],
15
+ description: 'Output directory',
16
+ default: DEFAULT_OUTPUT_DIR,
17
+ }),
18
+ handler: async (options) => {
19
+ try {
20
+ // Load and resolve config
21
+ const opts = options;
22
+ const resolved = opts.resolvedConfig;
23
+ // Get schemas from all plugins
24
+ const pluginSchemas = resolved.registry.getSchemas();
25
+ // Determine output directory
26
+ const outputDir = path.resolve(resolved.root, options.output ?? resolved.generate?.outputDir ?? DEFAULT_OUTPUT_DIR);
27
+ await mkdir(outputDir, { recursive: true });
28
+ // Generate config schema (for IDE autocomplete of config file)
29
+ const configSchema = mergeConfigSchema({ pluginSchemas });
30
+ const schemaPath = path.join(outputDir, 'schema.json');
31
+ await writeFile(schemaPath, JSON.stringify(configSchema, null, 2));
32
+ console.log(`✓ Generated ${schemaPath}`);
33
+ // Merge metadata schemas (config takes priority over plugins)
34
+ const mergedMetadataSchema = mergeMetadataSchemas({
35
+ configSchema: resolved.metadata,
36
+ pluginSchemas,
37
+ });
38
+ // Generate metadata types from merged schema
39
+ const metadataTypes = generateMetadataTypes({
40
+ mergedSchema: mergedMetadataSchema,
41
+ });
42
+ const typesPath = path.join(outputDir, 'metadata.d.ts');
43
+ await writeFile(typesPath, metadataTypes);
44
+ console.log(`✓ Generated ${typesPath}`);
45
+ // Also output the merged metadata schema for reference
46
+ const metadataSchemaPath = path.join(outputDir, 'metadata.schema.json');
47
+ await writeFile(metadataSchemaPath, JSON.stringify(mergedMetadataSchema, null, 2));
48
+ console.log(`✓ Generated ${metadataSchemaPath}`);
49
+ const outputDirName = options.output ?? DEFAULT_OUTPUT_DIR;
50
+ console.log('\nDone! To enable type-safe metadata:');
51
+ console.log('');
52
+ console.log('1. Add to your tsconfig.json include:');
53
+ console.log(` "${outputDirName}/**/*.d.ts"`);
54
+ console.log('');
55
+ console.log('2. Add to your config file for IDE autocomplete:');
56
+ console.log(` "$schema": "./${outputDirName}/schema.json"`);
57
+ }
58
+ catch (error) {
59
+ console.error('Error:', error instanceof Error ? error.message : String(error));
60
+ process.exit(1);
61
+ }
62
+ },
63
+ });
64
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Init command - create a configuration file
3
+ */
4
+ export declare const initCommand: import("cli-forge").CLI<{
5
+ unmatched: string[];
6
+ '--'?: string[];
7
+ } & {
8
+ format?: "ts" | "json";
9
+ } & {} & {
10
+ output?: string;
11
+ } & {} & {
12
+ force?: boolean;
13
+ } & {}, Promise<void>, {}, undefined>;
14
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AA2CH,eAAO,MAAM,WAAW;;;;;;;;;qCAuDtB,CAAC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Init command - create a configuration file
3
+ */
4
+ import { cli } from 'cli-forge';
5
+ import { existsSync } from 'node:fs';
6
+ import { writeFile } from 'node:fs/promises';
7
+ import path from 'node:path';
8
+ import { findConfigFile } from '../../config/loader.js';
9
+ const TS_CONFIG_TEMPLATE = `import type { Config } from 'functional-examples';
10
+
11
+ const config: Config = {
12
+ // Extractors to use (auto-detected if not specified)
13
+ // extractors: [
14
+ // '@functional-examples/extractor-frontmatter',
15
+ // '@functional-examples/yaml-manifest',
16
+ // ],
17
+
18
+ // Scan configuration
19
+ scan: {
20
+ // Include patterns (applied after extraction)
21
+ // include: ['*'],
22
+ // Exclude patterns
23
+ // exclude: ['**/node_modules/**', '**/dist/**', '**/.git/**'],
24
+ },
25
+
26
+ // Path mappings for conflict resolution
27
+ // pathMappings: [
28
+ // { pattern: 'legacy/**', extractor: 'frontmatter' },
29
+ // ],
30
+ };
31
+
32
+ export default config;
33
+ `;
34
+ const JSON_CONFIG_TEMPLATE = `{
35
+ "$schema": "./.functional-examples/schema.json",
36
+ "scan": {
37
+ // "include": ["**/*"],
38
+ // "exclude": ["**/node_modules/**", "**/dist/**", "**/.git/**"]
39
+ }
40
+ }
41
+ `;
42
+ export const initCommand = cli('init', {
43
+ description: 'Create a new configuration file',
44
+ builder: (cmd) => cmd
45
+ .option('format', {
46
+ type: 'string',
47
+ alias: ['f'],
48
+ description: 'Output format',
49
+ choices: ['ts', 'json'],
50
+ default: 'ts',
51
+ })
52
+ .option('output', {
53
+ type: 'string',
54
+ alias: ['o'],
55
+ description: 'Output file path (auto-generated if not specified)',
56
+ })
57
+ .option('force', {
58
+ type: 'boolean',
59
+ description: 'Overwrite existing config file',
60
+ default: false,
61
+ }),
62
+ handler: async (options) => {
63
+ const outputPath = options.output ?? getDefaultOutputPath(options.format);
64
+ const absolutePath = path.resolve(outputPath);
65
+ if (!options.force) {
66
+ const existingConfig = await findConfigFile();
67
+ if (existingConfig) {
68
+ console.log(`Configuration file already exists: ${existingConfig}`);
69
+ console.log('Use --force to overwrite.');
70
+ process.exit(1);
71
+ }
72
+ if (existsSync(absolutePath)) {
73
+ console.log(`File already exists: ${absolutePath}`);
74
+ console.log('Use --force to overwrite.');
75
+ process.exit(1);
76
+ }
77
+ }
78
+ const content = options.format === 'ts' ? TS_CONFIG_TEMPLATE : JSON_CONFIG_TEMPLATE;
79
+ await writeFile(absolutePath, content, 'utf-8');
80
+ console.log(`Created configuration file: ${outputPath}`);
81
+ console.log('');
82
+ console.log('Next steps:');
83
+ console.log(' 1. Install extractors:');
84
+ console.log(' pnpm add @functional-examples/extractor-frontmatter');
85
+ console.log(' pnpm add @functional-examples/yaml-manifest');
86
+ console.log('');
87
+ console.log(' 2. Run the scanner:');
88
+ console.log(' functional-examples scan ./examples');
89
+ },
90
+ });
91
+ function getDefaultOutputPath(format) {
92
+ const ext = format === 'ts' ? '.ts' : '.json';
93
+ return `functional-examples.config${ext}`;
94
+ }
95
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Scan command - discover examples in a directory
3
+ */
4
+ export declare const scanCommand: import("cli-forge").CLI<{
5
+ unmatched: string[];
6
+ '--'?: string[];
7
+ } & {
8
+ directory?: string;
9
+ } & {} & {
10
+ config?: string;
11
+ } & {} & {
12
+ format?: "yaml" | "json" | "table";
13
+ } & {} & {
14
+ output?: string;
15
+ } & {} & {
16
+ include?: string[];
17
+ } & {} & {
18
+ exclude?: string[];
19
+ } & {}, Promise<void>, {}, undefined>;
20
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/scan.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;qCAiFtB,CAAC"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Scan command - discover examples in a directory
3
+ */
4
+ import { cli } from 'cli-forge';
5
+ import { writeFile } from 'node:fs/promises';
6
+ import path from 'node:path';
7
+ import { scanExamples } from '../../scanner/index.js';
8
+ export const scanCommand = cli('scan', {
9
+ description: 'Scan a directory for code examples',
10
+ builder: (cmd) => cmd
11
+ .option('directory', {
12
+ type: 'string',
13
+ description: 'Directory to scan',
14
+ required: true,
15
+ default: '.',
16
+ })
17
+ .option('config', {
18
+ type: 'string',
19
+ alias: ['c'],
20
+ description: 'Path to config file',
21
+ })
22
+ .option('format', {
23
+ type: 'string',
24
+ alias: ['f'],
25
+ description: 'Output format',
26
+ choices: ['table', 'json', 'yaml'],
27
+ default: 'table',
28
+ })
29
+ .option('output', {
30
+ type: 'string',
31
+ alias: ['o'],
32
+ description: 'Write output to file',
33
+ })
34
+ .option('include', {
35
+ type: 'array',
36
+ items: 'string',
37
+ description: 'Include pattern (can be repeated)',
38
+ default: [],
39
+ })
40
+ .option('exclude', {
41
+ type: 'array',
42
+ items: 'string',
43
+ description: 'Exclude pattern (can be repeated)',
44
+ default: [],
45
+ }),
46
+ handler: async (options) => {
47
+ const directory = options.directory ?? '.';
48
+ const opts = options;
49
+ const config = opts.resolvedConfig;
50
+ if (config.extractors.length === 0) {
51
+ console.error('No extractors available.');
52
+ console.error('Install an extractor package:');
53
+ console.error(' pnpm add @functional-examples/extractor-frontmatter');
54
+ console.error(' pnpm add @functional-examples/yaml-manifest');
55
+ process.exit(1);
56
+ }
57
+ // Use config root when scanning from '.' (default), otherwise use specified directory
58
+ const scanRoot = directory === '.' ? config.root : path.resolve(config.root, directory);
59
+ const result = await scanExamples({
60
+ ...config,
61
+ root: scanRoot,
62
+ scan: {
63
+ ...config.scan,
64
+ include: options.include.length > 0 ? options.include : config.scan.include,
65
+ exclude: options.exclude.length > 0 ? options.exclude : config.scan.exclude,
66
+ },
67
+ });
68
+ const output = formatOutput(result, options.format);
69
+ if (options.output) {
70
+ await writeFile(options.output, output);
71
+ console.log(`Results written to ${options.output}`);
72
+ }
73
+ else {
74
+ console.log(output);
75
+ }
76
+ if (result.errors.length > 0) {
77
+ process.exit(1);
78
+ }
79
+ },
80
+ });
81
+ function formatOutput(result, format) {
82
+ switch (format) {
83
+ case 'json':
84
+ return JSON.stringify({
85
+ examples: result.examples.map(serializeExample),
86
+ errors: result.errors,
87
+ stats: result.stats,
88
+ }, null, 2);
89
+ case 'yaml':
90
+ return formatYaml(result);
91
+ case 'table':
92
+ default:
93
+ return formatTable(result);
94
+ }
95
+ }
96
+ function serializeExample(example) {
97
+ return {
98
+ id: example.id,
99
+ title: example.title,
100
+ description: example.description,
101
+ rootPath: example.rootPath,
102
+ files: example.files.map((f) => f.relativePath),
103
+ extractorName: example.extractorName,
104
+ metadata: example.metadata,
105
+ };
106
+ }
107
+ function formatTable(result) {
108
+ const lines = [];
109
+ lines.push(`Found ${result.examples.length} example(s)`);
110
+ lines.push('');
111
+ if (result.examples.length > 0) {
112
+ lines.push(padRight('ID', 30) +
113
+ padRight('Title', 40) +
114
+ padRight('Files', 10) +
115
+ 'Extractor');
116
+ lines.push('-'.repeat(90));
117
+ for (const example of result.examples) {
118
+ lines.push(padRight(truncate(example.id, 28), 30) +
119
+ padRight(truncate(example.title, 38), 40) +
120
+ padRight(String(example.files.length), 10) +
121
+ example.extractorName);
122
+ }
123
+ }
124
+ if (result.errors.length > 0) {
125
+ lines.push('');
126
+ lines.push(`Errors (${result.errors.length}):`);
127
+ for (const error of result.errors) {
128
+ lines.push(` - ${error.path}: ${error.message}`);
129
+ }
130
+ }
131
+ if (result.conflicts.length > 0) {
132
+ lines.push('');
133
+ lines.push(`Conflicts (${result.conflicts.length}):`);
134
+ for (const conflict of result.conflicts) {
135
+ const status = conflict.resolution === 'path-mapping' ? '(resolved)' : '(ERROR)';
136
+ lines.push(` - ${conflict.filePath}: claimed by ${conflict.claimants.join(', ')} ${status}`);
137
+ }
138
+ }
139
+ lines.push('');
140
+ lines.push(`Scan completed in ${result.stats.durationMs}ms`);
141
+ return lines.join('\n');
142
+ }
143
+ function formatYaml(result) {
144
+ const lines = [];
145
+ lines.push('examples:');
146
+ for (const example of result.examples) {
147
+ lines.push(` - id: ${example.id}`);
148
+ lines.push(` title: "${example.title}"`);
149
+ if (example.description) {
150
+ lines.push(` description: "${example.description}"`);
151
+ }
152
+ lines.push(` rootPath: ${example.rootPath}`);
153
+ lines.push(` extractor: ${example.extractorName}`);
154
+ lines.push(` files:`);
155
+ for (const file of example.files) {
156
+ lines.push(` - ${file.relativePath}`);
157
+ }
158
+ }
159
+ if (result.errors.length > 0) {
160
+ lines.push('');
161
+ lines.push('errors:');
162
+ for (const error of result.errors) {
163
+ lines.push(` - path: ${error.path}`);
164
+ lines.push(` message: "${error.message}"`);
165
+ }
166
+ }
167
+ lines.push('');
168
+ lines.push('stats:');
169
+ lines.push(` examplesFound: ${result.stats.examplesFound}`);
170
+ lines.push(` filesClaimed: ${result.stats.filesClaimed}`);
171
+ lines.push(` durationMs: ${result.stats.durationMs}`);
172
+ return lines.join('\n');
173
+ }
174
+ function padRight(str, width) {
175
+ return str + ' '.repeat(Math.max(0, width - str.length));
176
+ }
177
+ function truncate(str, maxLength) {
178
+ if (str.length <= maxLength)
179
+ return str;
180
+ return str.slice(0, maxLength - 2) + '..';
181
+ }
182
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/cli/commands/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Validate command - validate configuration file
3
+ */
4
+ export declare const validateCommand: import("cli-forge").CLI<{
5
+ unmatched: string[];
6
+ '--'?: string[];
7
+ } & {
8
+ strict?: boolean;
9
+ } & {}, Promise<void>, {}, undefined>;
10
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/validate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,eAAO,MAAM,eAAe;;;;;qCAkE1B,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Validate command - validate configuration file
3
+ */
4
+ import { cli } from 'cli-forge';
5
+ import { resolveConfig } from '../../config/resolver.js';
6
+ import { validateConfig } from '../../config/validator.js';
7
+ export const validateCommand = cli('validate', {
8
+ description: 'Validate the configuration file',
9
+ builder: (cmd) => cmd.option('strict', {
10
+ type: 'boolean',
11
+ description: 'Treat warnings as errors',
12
+ default: false,
13
+ }),
14
+ handler: async (options) => {
15
+ const opts = options;
16
+ const config = opts.resolvedConfig;
17
+ const configPath = config.root;
18
+ if (!configPath) {
19
+ console.log('No configuration file found.');
20
+ console.log('Run "functional-examples init" to create one.');
21
+ process.exit(0);
22
+ }
23
+ console.log(`Validating: ${configPath}`);
24
+ console.log('');
25
+ const errors = validateConfig(config);
26
+ if (errors.length > 0) {
27
+ console.error('Configuration errors:');
28
+ for (const error of errors) {
29
+ console.error(` - ${error.path}: ${error.message}`);
30
+ }
31
+ process.exit(1);
32
+ }
33
+ try {
34
+ const resolved = await resolveConfig(config);
35
+ console.log('Configuration is valid!');
36
+ console.log('');
37
+ console.log(`Extractors: ${resolved.extractors.length}`);
38
+ for (const extractor of resolved.extractors) {
39
+ console.log(` - ${extractor.name}`);
40
+ }
41
+ if (resolved.pathMappings.length > 0) {
42
+ console.log('');
43
+ console.log(`Path mappings: ${resolved.pathMappings.length}`);
44
+ for (const mapping of resolved.pathMappings) {
45
+ console.log(` - ${mapping.pattern} -> ${mapping.extractor}`);
46
+ }
47
+ }
48
+ console.log('');
49
+ console.log('Scan config:');
50
+ console.log(` include: ${resolved.scan.include.join(', ') || '(all)'}`);
51
+ console.log(` exclude: ${resolved.scan.exclude.join(', ') || '(none)'}`);
52
+ if (resolved.extractors.length === 0 && options.strict) {
53
+ console.error('');
54
+ console.error('Warning: No extractors could be loaded.');
55
+ process.exit(1);
56
+ }
57
+ }
58
+ catch (error) {
59
+ console.error('Failed to resolve configuration:');
60
+ console.error(` ${error.message}`);
61
+ process.exit(1);
62
+ }
63
+ },
64
+ });
65
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/cli/commands/validate.ts"],"names":[],"mappings":"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"}