@atomic-ehr/codegen 0.0.1-canary.20250822114054.4ca1428 → 0.0.1-canary.20250822150706.c3b8669

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 (120) hide show
  1. package/dist/api/builder.d.ts +3 -3
  2. package/dist/api/builder.d.ts.map +1 -1
  3. package/dist/api/builder.js +374 -0
  4. package/dist/api/generators/base/BaseGenerator.d.ts +4 -4
  5. package/dist/api/generators/base/BaseGenerator.d.ts.map +1 -1
  6. package/dist/api/generators/base/BaseGenerator.js +572 -0
  7. package/dist/api/generators/base/FileManager.d.ts +2 -2
  8. package/dist/api/generators/base/FileManager.d.ts.map +1 -1
  9. package/dist/api/generators/base/FileManager.js +204 -0
  10. package/dist/api/generators/base/PythonTypeMapper.d.ts +2 -2
  11. package/dist/api/generators/base/PythonTypeMapper.d.ts.map +1 -1
  12. package/dist/api/generators/base/PythonTypeMapper.js +71 -0
  13. package/dist/api/generators/base/TemplateEngine.d.ts +1 -1
  14. package/dist/api/generators/base/TemplateEngine.d.ts.map +1 -1
  15. package/dist/api/generators/base/TemplateEngine.js +133 -0
  16. package/dist/api/generators/base/TypeMapper.js +153 -0
  17. package/dist/api/generators/base/TypeScriptTypeMapper.d.ts +1 -1
  18. package/dist/api/generators/base/TypeScriptTypeMapper.d.ts.map +1 -1
  19. package/dist/api/generators/base/TypeScriptTypeMapper.js +232 -0
  20. package/dist/api/generators/base/builders/DirectoryBuilder.d.ts +4 -4
  21. package/dist/api/generators/base/builders/DirectoryBuilder.d.ts.map +1 -1
  22. package/dist/api/generators/base/builders/DirectoryBuilder.js +215 -0
  23. package/dist/api/generators/base/builders/FileBuilder.d.ts +2 -2
  24. package/dist/api/generators/base/builders/FileBuilder.d.ts.map +1 -1
  25. package/dist/api/generators/base/builders/FileBuilder.js +408 -0
  26. package/dist/api/generators/base/builders/IndexBuilder.d.ts +2 -2
  27. package/dist/api/generators/base/builders/IndexBuilder.d.ts.map +1 -1
  28. package/dist/api/generators/base/builders/IndexBuilder.js +290 -0
  29. package/dist/api/generators/base/enhanced-errors.d.ts +2 -2
  30. package/dist/api/generators/base/enhanced-errors.d.ts.map +1 -1
  31. package/dist/api/generators/base/enhanced-errors.js +259 -0
  32. package/dist/api/generators/base/error-handler.d.ts +1 -1
  33. package/dist/api/generators/base/error-handler.d.ts.map +1 -1
  34. package/dist/api/generators/base/error-handler.js +243 -0
  35. package/dist/api/generators/base/errors.d.ts +2 -2
  36. package/dist/api/generators/base/errors.d.ts.map +1 -1
  37. package/dist/api/generators/base/errors.js +694 -0
  38. package/dist/api/generators/base/index.d.ts +22 -22
  39. package/dist/api/generators/base/index.d.ts.map +1 -1
  40. package/dist/api/generators/base/index.js +161 -0
  41. package/dist/api/generators/base/types.d.ts +2 -2
  42. package/dist/api/generators/base/types.d.ts.map +1 -1
  43. package/dist/api/generators/base/types.js +12 -0
  44. package/dist/api/generators/rest-client.d.ts +2 -2
  45. package/dist/api/generators/rest-client.d.ts.map +1 -1
  46. package/dist/api/generators/rest-client.js +847 -0
  47. package/dist/api/generators/search-parameter-enhancer.d.ts +1 -1
  48. package/dist/api/generators/search-parameter-enhancer.d.ts.map +1 -1
  49. package/dist/api/generators/search-parameter-enhancer.js +801 -0
  50. package/dist/api/generators/types.js +4 -0
  51. package/dist/api/generators/typescript.d.ts +3 -3
  52. package/dist/api/generators/typescript.d.ts.map +1 -1
  53. package/dist/api/generators/typescript.js +537 -0
  54. package/dist/api/generators/validation-generator.js +632 -0
  55. package/dist/api/index.d.ts +10 -10
  56. package/dist/api/index.d.ts.map +1 -1
  57. package/dist/api/index.js +51 -0
  58. package/dist/cli/commands/generate/typescript.d.ts +1 -1
  59. package/dist/cli/commands/generate/typescript.d.ts.map +1 -1
  60. package/dist/cli/commands/generate/typescript.js +52 -0
  61. package/dist/cli/commands/generate.d.ts +5 -12
  62. package/dist/cli/commands/generate.d.ts.map +1 -1
  63. package/dist/cli/commands/generate.js +158 -0
  64. package/dist/cli/commands/index.d.ts +2 -1
  65. package/dist/cli/commands/index.d.ts.map +1 -1
  66. package/dist/cli/commands/index.js +100 -0
  67. package/dist/cli/commands/typeschema/generate.js +130 -0
  68. package/dist/cli/commands/typeschema.js +48 -0
  69. package/dist/cli/index.js +12 -8664
  70. package/dist/cli/utils/log.d.ts +2 -2
  71. package/dist/cli/utils/log.d.ts.map +1 -1
  72. package/dist/cli/utils/log.js +23 -0
  73. package/dist/cli/utils/prompts.js +224 -0
  74. package/dist/cli/utils/spinner.js +270 -0
  75. package/dist/config.js +703 -0
  76. package/dist/index.d.ts +2 -2
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +84 -40
  79. package/dist/logger.js +290 -0
  80. package/dist/typeschema/cache.d.ts +2 -2
  81. package/dist/typeschema/cache.d.ts.map +1 -1
  82. package/dist/typeschema/cache.js +285 -0
  83. package/dist/typeschema/core/binding.d.ts +1 -1
  84. package/dist/typeschema/core/binding.d.ts.map +1 -1
  85. package/dist/typeschema/core/binding.js +187 -0
  86. package/dist/typeschema/core/field-builder.d.ts +1 -1
  87. package/dist/typeschema/core/field-builder.d.ts.map +1 -1
  88. package/dist/typeschema/core/field-builder.js +259 -0
  89. package/dist/typeschema/core/identifier.js +117 -0
  90. package/dist/typeschema/core/nested-types.d.ts +1 -1
  91. package/dist/typeschema/core/nested-types.d.ts.map +1 -1
  92. package/dist/typeschema/core/nested-types.js +111 -0
  93. package/dist/typeschema/core/transformer.d.ts +2 -2
  94. package/dist/typeschema/core/transformer.d.ts.map +1 -1
  95. package/dist/typeschema/core/transformer.js +345 -0
  96. package/dist/typeschema/generator.d.ts +3 -3
  97. package/dist/typeschema/generator.d.ts.map +1 -1
  98. package/dist/typeschema/generator.js +352 -0
  99. package/dist/typeschema/index.d.ts +14 -14
  100. package/dist/typeschema/index.d.ts.map +1 -1
  101. package/dist/typeschema/index.js +92 -0
  102. package/dist/typeschema/parser.d.ts +2 -2
  103. package/dist/typeschema/parser.d.ts.map +1 -1
  104. package/dist/typeschema/parser.js +310 -0
  105. package/dist/typeschema/profile/processor.d.ts +1 -1
  106. package/dist/typeschema/profile/processor.d.ts.map +1 -1
  107. package/dist/typeschema/profile/processor.js +268 -0
  108. package/dist/typeschema/schema.js +456 -0
  109. package/dist/typeschema/type-schema.types.js +39 -0
  110. package/dist/typeschema/types.js +4 -0
  111. package/dist/typeschema/utils.d.ts +1 -1
  112. package/dist/typeschema/utils.d.ts.map +1 -1
  113. package/dist/typeschema/utils.js +13 -0
  114. package/dist/typeschema/value-set/processor.d.ts +1 -1
  115. package/dist/typeschema/value-set/processor.d.ts.map +1 -1
  116. package/dist/typeschema/value-set/processor.js +168 -0
  117. package/dist/utils/codegen-logger.js +204 -0
  118. package/dist/utils.js +42 -0
  119. package/package.json +15 -4
  120. package/dist/index-fgcebdva.js +0 -8515
@@ -0,0 +1,572 @@
1
+ /**
2
+ * Abstract base generator class
3
+ *
4
+ * This is the foundation of the generator system. All language-specific generators
5
+ * extend this class to inherit common functionality while implementing their own
6
+ * specific logic for type mapping, content generation, and validation.
7
+ */
8
+ import { createLogger } from "../../../utils/codegen-logger.js";
9
+ import { ErrorHandler, GeneratorErrorBoundary } from "./error-handler.js";
10
+ import { ConfigurationError, SchemaValidationError } from "./errors.js";
11
+ import { FileManager } from "./FileManager.js";
12
+ /**
13
+ * Abstract base generator class with comprehensive functionality
14
+ *
15
+ * Provides common functionality for all generators including:
16
+ * - Schema validation and processing
17
+ * - File management with fluent API
18
+ * - Template processing
19
+ * - Error handling and recovery
20
+ * - Progress monitoring
21
+ * - Performance optimization
22
+ */
23
+ export class BaseGenerator {
24
+ /** Validated and merged options */
25
+ options;
26
+ /** Logger instance for this generator */
27
+ logger;
28
+ /** File manager for all file operations */
29
+ fileManager;
30
+ /** Template engine for content generation (optional) */
31
+ templateEngine;
32
+ /** Language-specific type mapper */
33
+ typeMapper;
34
+ /** Enhanced error handler for comprehensive error reporting */
35
+ errorHandler;
36
+ /** Error boundary for catching and handling all generator errors */
37
+ errorBoundary;
38
+ /** Progress callback if provided */
39
+ progressCallback;
40
+ /** Generated files tracking */
41
+ generatedFiles = [];
42
+ /** Generation start time for performance metrics */
43
+ generationStartTime = 0;
44
+ /** Cache for expensive operations */
45
+ cache = new Map();
46
+ constructor(options) {
47
+ // Validate configuration first
48
+ const validation = this.validateConfiguration(options);
49
+ if (!validation.isValid) {
50
+ throw new ConfigurationError(`Invalid generator configuration: ${validation.errors.join(", ")}`, "configuration", options);
51
+ }
52
+ // Merge with defaults and store
53
+ this.options = this.mergeWithDefaults(options);
54
+ // Initialize logger
55
+ this.logger =
56
+ options.logger ||
57
+ createLogger({
58
+ prefix: this.getLanguageName(),
59
+ verbose: this.options.verbose || false,
60
+ });
61
+ // Initialize core components
62
+ this.fileManager = this.createFileManager();
63
+ this.templateEngine = this.createTemplateEngine();
64
+ this.typeMapper = this.createTypeMapper();
65
+ // Initialize enhanced error handling
66
+ this.errorHandler = new ErrorHandler({
67
+ logger: this.logger,
68
+ verbose: this.options.verbose || false,
69
+ beginnerMode: this.options.beginnerMode || false,
70
+ outputFormat: this.options.errorFormat || "console",
71
+ });
72
+ this.errorBoundary = new GeneratorErrorBoundary(this.errorHandler);
73
+ this.logger.debug(`${this.getLanguageName()} generator initialized`);
74
+ // Log any configuration warnings
75
+ if (validation.warnings.length > 0) {
76
+ validation.warnings.forEach((warning) => {
77
+ this.logger.warn(`Configuration warning: ${warning}`);
78
+ });
79
+ }
80
+ }
81
+ // ==========================================
82
+ // Optional Abstract Methods - Can be overridden
83
+ // ==========================================
84
+ /**
85
+ * Get generator capabilities - can be overridden for introspection
86
+ */
87
+ getCapabilities() {
88
+ return {
89
+ language: this.getLanguageName(),
90
+ fileExtensions: [this.getFileExtension()],
91
+ supportsTemplates: true,
92
+ supportsCustomTypeMapping: true,
93
+ supportsIncrementalGeneration: false,
94
+ supportsValidation: true,
95
+ supportedSchemaKinds: ["resource", "complex-type", "profile", "logical"],
96
+ version: "1.0.0",
97
+ };
98
+ }
99
+ /**
100
+ * Create file manager instance - can be overridden for custom file handling
101
+ */
102
+ createFileManager() {
103
+ return new FileManager({
104
+ outputDir: this.options.outputDir,
105
+ logger: this.logger.child("FileManager"),
106
+ overwrite: this.options.overwrite,
107
+ });
108
+ }
109
+ /**
110
+ * Create template engine instance - can be overridden for custom templates
111
+ * Returns undefined if template engine is not needed
112
+ */
113
+ createTemplateEngine() {
114
+ // Default implementation returns undefined (no template engine)
115
+ // Subclasses can override to provide template engine if needed
116
+ return undefined;
117
+ }
118
+ // ==========================================
119
+ // Public API - Main entry points
120
+ // ==========================================
121
+ /**
122
+ * Generate code from TypeSchema documents
123
+ * This is the main method that orchestrates the entire generation process
124
+ * @param schemas - Array of TypeSchema documents
125
+ */
126
+ async generate(schemas) {
127
+ return this.errorBoundary.withErrorBoundary(async () => {
128
+ this.generationStartTime = performance.now();
129
+ this.generatedFiles = [];
130
+ this.logger.info(`Starting ${this.getLanguageName()} generation for ${schemas.length} schemas`);
131
+ // Phase 1: Schema validation
132
+ this.reportProgress("validation", 0, schemas.length, "Validating schemas...");
133
+ await this.validateSchemas(schemas);
134
+ // Phase 2: Schema processing and filtering
135
+ this.reportProgress("generation", 0, schemas.length, "Processing schemas...");
136
+ const processedSchemas = this.filterAndSortSchemas(schemas);
137
+ this.logger.debug(`Filtered to ${processedSchemas.length} schemas for generation`);
138
+ // Phase 3: Content generation
139
+ await this.generateFiles(processedSchemas);
140
+ // Phase 4: Post-generation hooks
141
+ await this.runPostGenerationHooks();
142
+ this.reportProgress("complete", schemas.length, schemas.length, "Generation complete");
143
+ const duration = performance.now() - this.generationStartTime;
144
+ this.logger.info(`Generated ${this.generatedFiles.length} files in ${duration.toFixed(2)}ms ` +
145
+ `(avg ${(duration / this.generatedFiles.length).toFixed(2)}ms per file)`);
146
+ return this.generatedFiles;
147
+ }, { operationName: "generate" });
148
+ }
149
+ /**
150
+ * Generate and return content without writing files (useful for testing)
151
+ * @param schemas - Array of TypeSchema documents
152
+ */
153
+ async build(schemas) {
154
+ // Temporarily disable file writing by mocking the writeFile method
155
+ const originalWriteFile = this.fileManager.writeFile;
156
+ const mockWriteResults = new Map();
157
+ this.fileManager.writeFile = async (path, content) => {
158
+ const result = {
159
+ path: `${this.options.outputDir}/${path}`,
160
+ size: Buffer.byteLength(content, "utf-8"),
161
+ writeTime: 0,
162
+ };
163
+ mockWriteResults.set(path, result);
164
+ return result;
165
+ };
166
+ try {
167
+ const result = await this.generate(schemas);
168
+ // Update file paths to reflect what would have been written
169
+ result.forEach((file) => {
170
+ const mockResult = mockWriteResults.get(file.filename);
171
+ if (mockResult) {
172
+ file.path = mockResult.path;
173
+ file.size = mockResult.size;
174
+ }
175
+ });
176
+ return result;
177
+ }
178
+ finally {
179
+ // Restore original file writing function
180
+ this.fileManager.writeFile = originalWriteFile;
181
+ }
182
+ }
183
+ // ==========================================
184
+ // Fluent API - Builder pattern methods
185
+ // ==========================================
186
+ /**
187
+ * Create a file builder for fluent file generation
188
+ * @param filename - Name of the file to create
189
+ */
190
+ file(filename) {
191
+ if (!this.templateEngine) {
192
+ throw new Error("Template engine is required for fluent file generation. Override createTemplateEngine() in your generator.");
193
+ }
194
+ const { FileBuilder } = require("./builders/FileBuilder");
195
+ return new FileBuilder({
196
+ filename: this.ensureFileExtension(filename),
197
+ fileManager: this.fileManager,
198
+ templateEngine: this.templateEngine,
199
+ typeMapper: this.typeMapper,
200
+ logger: this.logger.child("FileBuilder"),
201
+ });
202
+ }
203
+ /**
204
+ * Create a directory builder for batch operations
205
+ * @param path - Directory path relative to output directory
206
+ */
207
+ directory(path) {
208
+ const { DirectoryBuilder } = require("./builders/DirectoryBuilder");
209
+ return new DirectoryBuilder({
210
+ path,
211
+ fileManager: this.fileManager,
212
+ logger: this.logger.child("DirectoryBuilder"),
213
+ });
214
+ }
215
+ /**
216
+ * Create an index file builder
217
+ * @param directory - Directory to create index for
218
+ */
219
+ index(directory = ".") {
220
+ if (!this.templateEngine) {
221
+ throw new Error("Template engine is required for index file generation. Override createTemplateEngine() in your generator.");
222
+ }
223
+ const { IndexBuilder } = require("./builders/IndexBuilder");
224
+ return new IndexBuilder({
225
+ directory,
226
+ fileManager: this.fileManager,
227
+ templateEngine: this.templateEngine,
228
+ logger: this.logger.child("IndexBuilder"),
229
+ });
230
+ }
231
+ /**
232
+ * Set progress callback for monitoring generation
233
+ * @param callback - Progress callback function
234
+ */
235
+ onProgress(callback) {
236
+ this.progressCallback = callback;
237
+ return this;
238
+ }
239
+ // ==========================================
240
+ // Configuration and Validation
241
+ // ==========================================
242
+ /**
243
+ * Validate generator configuration
244
+ */
245
+ validateConfiguration(options) {
246
+ const errors = [];
247
+ const warnings = [];
248
+ const suggestions = [];
249
+ // Required options validation
250
+ if (!options.outputDir) {
251
+ errors.push("outputDir is required");
252
+ suggestions.push("Provide a valid output directory path");
253
+ }
254
+ // Type validation
255
+ if (options.outputDir && typeof options.outputDir !== "string") {
256
+ errors.push("outputDir must be a string");
257
+ }
258
+ if (options.overwrite !== undefined &&
259
+ typeof options.overwrite !== "boolean") {
260
+ errors.push("overwrite must be a boolean");
261
+ }
262
+ if (options.validate !== undefined &&
263
+ typeof options.validate !== "boolean") {
264
+ errors.push("validate must be a boolean");
265
+ }
266
+ // Warnings for suboptimal configuration
267
+ if (options.outputDir &&
268
+ !require("node:path").isAbsolute(options.outputDir)) {
269
+ warnings.push("Using relative path for outputDir - consider using absolute path");
270
+ suggestions.push("Use path.resolve() to convert to absolute path");
271
+ }
272
+ if (options.validate === false) {
273
+ warnings.push("Validation is disabled - this may lead to invalid generated code");
274
+ suggestions.push("Consider enabling validation for better code quality");
275
+ }
276
+ return {
277
+ isValid: errors.length === 0,
278
+ errors,
279
+ warnings,
280
+ suggestions,
281
+ };
282
+ }
283
+ /**
284
+ * Merge options with defaults
285
+ */
286
+ mergeWithDefaults(options) {
287
+ return {
288
+ overwrite: true,
289
+ validate: true,
290
+ verbose: false,
291
+ beginnerMode: false,
292
+ errorFormat: "console",
293
+ ...options,
294
+ };
295
+ }
296
+ // ==========================================
297
+ // Schema Processing
298
+ // ==========================================
299
+ /**
300
+ * Validate schemas before processing
301
+ */
302
+ async validateSchemas(schemas) {
303
+ if (!this.options.validate) {
304
+ this.logger.debug("Schema validation disabled");
305
+ return;
306
+ }
307
+ this.logger.info(`🔍 Starting schema validation for ${schemas.length} schemas`);
308
+ this.logger.debug("Schema validation enabled - performing comprehensive validation");
309
+ const operations = schemas.map((schema) => () => this.errorBoundary.withErrorBoundary(async () => {
310
+ await this.validateSchema(schema);
311
+ this.reportProgress("validation", schemas.indexOf(schema) + 1, schemas.length, `Validated ${schema.identifier?.name || "schema"}`);
312
+ }, { schema, operationName: "validateSchema" }));
313
+ await this.errorBoundary.withBatchErrorBoundary(operations, {
314
+ operationName: "validateSchemas",
315
+ });
316
+ this.logger.debug(`Successfully validated ${schemas.length} schemas`);
317
+ }
318
+ /**
319
+ * Validate individual schema
320
+ */
321
+ async validateSchema(schema) {
322
+ const errors = [];
323
+ const schemaName = schema.identifier?.name || "unknown";
324
+ this.logger.debug(`🔍 Validating schema: ${schemaName} (kind: ${schema.identifier?.kind})`);
325
+ // Basic structure validation
326
+ if (!schema.identifier) {
327
+ errors.push("Schema missing identifier");
328
+ this.logger.warn(`❌ Schema missing identifier: ${JSON.stringify(schema, null, 2).substring(0, 200)}...`);
329
+ }
330
+ else {
331
+ if (!schema.identifier.name) {
332
+ errors.push("Schema identifier missing name");
333
+ }
334
+ if (!schema.identifier.kind) {
335
+ errors.push("Schema identifier missing kind");
336
+ }
337
+ else {
338
+ const validKinds = [
339
+ "resource",
340
+ "complex-type",
341
+ "profile",
342
+ "primitive-type",
343
+ "logical",
344
+ "value-set",
345
+ "binding",
346
+ "extension",
347
+ ];
348
+ if (!validKinds.includes(schema.identifier.kind)) {
349
+ errors.push(`Schema identifier.kind must be one of: ${validKinds.join(", ")}`);
350
+ }
351
+ }
352
+ }
353
+ // Field validation
354
+ if ("fields" in schema && schema.fields) {
355
+ for (const [fieldName, field] of Object.entries(schema.fields)) {
356
+ if (!fieldName.trim()) {
357
+ errors.push("Field name cannot be empty");
358
+ }
359
+ if (!field) {
360
+ errors.push(`Field '${fieldName}' is null or undefined`);
361
+ }
362
+ // Add more field-specific validation as needed
363
+ }
364
+ }
365
+ // Circular reference detection (make it a warning, not an error for FHIR schemas)
366
+ if (await this.detectCircularReferences(schema)) {
367
+ this.logger.warn(`⚠️ Circular reference detected in schema '${schemaName}' - this may be expected for FHIR primitive types`);
368
+ // Don't add to errors - FHIR schemas often have legitimate circular references
369
+ }
370
+ if (errors.length > 0) {
371
+ this.logger.error(`❌ Schema validation failed for '${schemaName}': ${errors.join(", ")}`);
372
+ this.logger.debug(`Schema details: ${JSON.stringify(schema, null, 2)}`);
373
+ throw new SchemaValidationError(`Schema validation failed for '${schema.identifier?.name || "unknown"}'`, schema, errors);
374
+ }
375
+ this.logger.debug(`✅ Schema validation passed for '${schemaName}'`);
376
+ }
377
+ /**
378
+ * Detect circular references in schema dependencies
379
+ */
380
+ async detectCircularReferences(schema) {
381
+ // Simple implementation - can be enhanced for complex cases
382
+ const visited = new Set();
383
+ const visiting = new Set();
384
+ const checkCircular = (currentSchema) => {
385
+ const name = currentSchema.identifier?.name;
386
+ if (!name)
387
+ return false;
388
+ if (visiting.has(name)) {
389
+ return true; // Circular reference found
390
+ }
391
+ if (visited.has(name)) {
392
+ return false; // Already processed
393
+ }
394
+ visiting.add(name);
395
+ // Check field references
396
+ if ("fields" in currentSchema && currentSchema.fields) {
397
+ for (const field of Object.values(currentSchema.fields)) {
398
+ if (field?.type?.name === name) {
399
+ return true; // Self-reference
400
+ }
401
+ // Add more complex reference checking as needed
402
+ }
403
+ }
404
+ visiting.delete(name);
405
+ visited.add(name);
406
+ return false;
407
+ };
408
+ return checkCircular(schema);
409
+ }
410
+ // ==========================================
411
+ // File Generation
412
+ // ==========================================
413
+ /**
414
+ * Generate files from processed schemas
415
+ */
416
+ async generateFiles(schemas) {
417
+ const operations = schemas.map((schema, index) => () => this.errorBoundary.withErrorBoundary(async () => {
418
+ const file = await this.generateFileForSchema(schema, index, schemas.length);
419
+ this.generatedFiles.push(file);
420
+ return file;
421
+ }, { schema, operationName: "generateFile" }));
422
+ await this.errorBoundary.withBatchErrorBoundary(operations, {
423
+ operationName: "generateFiles",
424
+ });
425
+ this.logger.debug(`Generated ${this.generatedFiles.length} files`);
426
+ }
427
+ /**
428
+ * Generate a single file from a schema
429
+ */
430
+ async generateFileForSchema(schema, index, total) {
431
+ const fileStartTime = performance.now();
432
+ // Create template context
433
+ const context = {
434
+ schema,
435
+ typeMapper: this.typeMapper,
436
+ filename: this.typeMapper.formatFileName(schema.identifier?.name || "unknown"),
437
+ language: this.getLanguageName(),
438
+ timestamp: new Date().toISOString(),
439
+ imports: new Map(),
440
+ exports: new Set(),
441
+ };
442
+ // Generate content
443
+ const content = await this.generateSchemaContent(schema, context);
444
+ // Validate content if enabled
445
+ if (this.options.validate) {
446
+ await this.validateContent(content, context);
447
+ }
448
+ // Write file
449
+ const filename = context.filename + this.getFileExtension();
450
+ const writeResult = await this.fileManager.writeFile(filename, content);
451
+ const generationTime = performance.now() - fileStartTime;
452
+ // Report progress
453
+ this.reportProgress("writing", index + 1, total, `Generated ${filename} (${writeResult.size} bytes)`);
454
+ // Create GeneratedFile result
455
+ const generatedFile = {
456
+ path: writeResult.path,
457
+ filename,
458
+ content,
459
+ exports: this.extractExports(content),
460
+ size: writeResult.size,
461
+ timestamp: new Date(),
462
+ metadata: {
463
+ generationTime,
464
+ schemaCount: 1,
465
+ templateName: context.templateName?.toString(),
466
+ warnings: [],
467
+ },
468
+ };
469
+ return generatedFile;
470
+ }
471
+ // ==========================================
472
+ // Helper Methods
473
+ // ==========================================
474
+ /**
475
+ * Ensure filename has correct extension
476
+ */
477
+ ensureFileExtension(filename) {
478
+ const extension = this.getFileExtension();
479
+ return filename.endsWith(extension) ? filename : `${filename}${extension}`;
480
+ }
481
+ /**
482
+ * Extract exported symbols from generated content
483
+ * Can be overridden by language-specific implementations
484
+ */
485
+ extractExports(content) {
486
+ const exports = [];
487
+ // Handle export { name1, name2 } syntax
488
+ const exportListRegex = /export\s*\{\s*([^}]+)\s*\}/g;
489
+ let match;
490
+ while ((match = exportListRegex.exec(content)) !== null) {
491
+ if (match[1]) {
492
+ const names = match[1]
493
+ .split(",")
494
+ .map((name) => name.trim())
495
+ .filter(Boolean);
496
+ exports.push(...names);
497
+ }
498
+ }
499
+ // Handle direct export declarations
500
+ const directExportRegex = /export\s+(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/g;
501
+ while ((match = directExportRegex.exec(content)) !== null) {
502
+ if (match[1]) {
503
+ exports.push(match[1]);
504
+ }
505
+ }
506
+ // Remove duplicates
507
+ return [...new Set(exports)];
508
+ }
509
+ /**
510
+ * Report progress to callback if provided
511
+ */
512
+ reportProgress(phase, current, total, message, schema) {
513
+ if (this.progressCallback) {
514
+ this.progressCallback(phase, current, total, message, schema);
515
+ }
516
+ if (message && this.options.verbose) {
517
+ this.logger.debug(`[${phase}] ${message} (${current}/${total})`);
518
+ }
519
+ }
520
+ /**
521
+ * Run post-generation hooks
522
+ * Can be overridden to add custom post-processing
523
+ */
524
+ async runPostGenerationHooks() {
525
+ // Default implementation does nothing
526
+ // Subclasses can override to add custom logic
527
+ }
528
+ /**
529
+ * Get cached value or compute and cache it
530
+ */
531
+ getCachedOrCompute(key, computeFn) {
532
+ if (this.cache.has(key)) {
533
+ return this.cache.get(key);
534
+ }
535
+ const result = computeFn();
536
+ if (result instanceof Promise) {
537
+ return result.then((value) => {
538
+ this.cache.set(key, value);
539
+ return value;
540
+ });
541
+ }
542
+ else {
543
+ this.cache.set(key, result);
544
+ return result;
545
+ }
546
+ }
547
+ /**
548
+ * Clear internal cache
549
+ */
550
+ clearCache() {
551
+ this.cache.clear();
552
+ }
553
+ /**
554
+ * Get generation statistics
555
+ */
556
+ getGenerationStats() {
557
+ const totalSize = this.generatedFiles.reduce((sum, file) => sum + file.size, 0);
558
+ const generationTime = performance.now() - this.generationStartTime;
559
+ return {
560
+ filesGenerated: this.generatedFiles.length,
561
+ totalSize,
562
+ averageFileSize: this.generatedFiles.length > 0
563
+ ? totalSize / this.generatedFiles.length
564
+ : 0,
565
+ generationTime,
566
+ averageTimePerFile: this.generatedFiles.length > 0
567
+ ? generationTime / this.generatedFiles.length
568
+ : 0,
569
+ cacheHitRate: 0, // TODO: Implement cache hit tracking
570
+ };
571
+ }
572
+ }
@@ -4,8 +4,8 @@
4
4
  * This replaces scattered writeFile calls with a comprehensive file management
5
5
  * system that provides better error handling, performance, and maintainability.
6
6
  */
7
- import type { CodegenLogger } from "../../../utils/codegen-logger";
8
- import type { FileStats } from "./types";
7
+ import type { CodegenLogger } from "../../../utils/codegen-logger.js";
8
+ import type { FileStats } from "./types.js";
9
9
  export interface FileManagerOptions {
10
10
  outputDir: string;
11
11
  logger: CodegenLogger;
@@ -1 +1 @@
1
- {"version":3,"file":"FileManager.d.ts","sourceRoot":"","sources":["../../../../src/api/generators/base/FileManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,OAAO,EAAE,kBAAkB;IASvC;;;;;OAKG;IACG,SAAS,CACd,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO,GAC9D,OAAO,CAAC,eAAe,CAAC;IAyD3B;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAyBxE;;;OAGG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBrD;;;OAGG;IACG,cAAc,CAAC,YAAY,GAAE,MAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB/D;;;;OAIG;IACH,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAe/D;;;OAGG;IACG,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU5D;;;OAGG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAcnE;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,YAAY,IAAI,MAAM;CAGtB"}
1
+ {"version":3,"file":"FileManager.d.ts","sourceRoot":"","sources":["../../../../src/api/generators/base/FileManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,OAAO,EAAE,kBAAkB;IASvC;;;;;OAKG;IACG,SAAS,CACd,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO,GAC9D,OAAO,CAAC,eAAe,CAAC;IAyD3B;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAyBxE;;;OAGG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBrD;;;OAGG;IACG,cAAc,CAAC,YAAY,GAAE,MAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB/D;;;;OAIG;IACH,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAe/D;;;OAGG;IACG,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU5D;;;OAGG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAcnE;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,YAAY,IAAI,MAAM;CAGtB"}