@atomic-ehr/codegen 0.0.1-canary.20251006092200.fdb4a88 → 0.0.1-canary.20251006094042.7f0be72
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/dist/cli/index.js +45 -124
- package/dist/index.d.ts +2130 -62
- package/dist/index.js +5865 -84
- package/dist/index.js.map +1 -0
- package/package.json +3 -7
- package/dist/api/builder.d.ts +0 -154
- package/dist/api/builder.js +0 -341
- package/dist/api/generators/base/BaseGenerator.d.ts +0 -186
- package/dist/api/generators/base/BaseGenerator.js +0 -565
- package/dist/api/generators/base/FileManager.d.ts +0 -88
- package/dist/api/generators/base/FileManager.js +0 -202
- package/dist/api/generators/base/PythonTypeMapper.d.ts +0 -16
- package/dist/api/generators/base/PythonTypeMapper.js +0 -71
- package/dist/api/generators/base/TemplateEngine.d.ts +0 -126
- package/dist/api/generators/base/TemplateEngine.js +0 -133
- package/dist/api/generators/base/TypeMapper.d.ts +0 -129
- package/dist/api/generators/base/TypeMapper.js +0 -153
- package/dist/api/generators/base/TypeScriptTypeMapper.d.ts +0 -51
- package/dist/api/generators/base/TypeScriptTypeMapper.js +0 -232
- package/dist/api/generators/base/builders/DirectoryBuilder.d.ts +0 -99
- package/dist/api/generators/base/builders/DirectoryBuilder.js +0 -215
- package/dist/api/generators/base/builders/FileBuilder.d.ts +0 -160
- package/dist/api/generators/base/builders/FileBuilder.js +0 -406
- package/dist/api/generators/base/builders/IndexBuilder.d.ts +0 -126
- package/dist/api/generators/base/builders/IndexBuilder.js +0 -290
- package/dist/api/generators/base/enhanced-errors.d.ts +0 -84
- package/dist/api/generators/base/enhanced-errors.js +0 -259
- package/dist/api/generators/base/error-handler.d.ts +0 -89
- package/dist/api/generators/base/error-handler.js +0 -243
- package/dist/api/generators/base/errors.d.ts +0 -251
- package/dist/api/generators/base/errors.js +0 -692
- package/dist/api/generators/base/index.d.ts +0 -99
- package/dist/api/generators/base/index.js +0 -160
- package/dist/api/generators/base/types.d.ts +0 -433
- package/dist/api/generators/base/types.js +0 -12
- package/dist/api/generators/types.d.ts +0 -53
- package/dist/api/generators/types.js +0 -4
- package/dist/api/generators/typescript.d.ts +0 -190
- package/dist/api/generators/typescript.js +0 -819
- package/dist/api/index.d.ts +0 -51
- package/dist/api/index.js +0 -50
- package/dist/cli/commands/generate/typescript.d.ts +0 -10
- package/dist/cli/commands/generate/typescript.js +0 -52
- package/dist/cli/commands/generate.d.ts +0 -15
- package/dist/cli/commands/generate.js +0 -159
- package/dist/cli/commands/index.d.ts +0 -29
- package/dist/cli/commands/index.js +0 -100
- package/dist/cli/commands/typeschema/generate.d.ts +0 -19
- package/dist/cli/commands/typeschema/generate.js +0 -124
- package/dist/cli/commands/typeschema.d.ts +0 -10
- package/dist/cli/commands/typeschema.js +0 -47
- package/dist/cli/index.d.ts +0 -9
- package/dist/cli/utils/log.d.ts +0 -10
- package/dist/cli/utils/log.js +0 -23
- package/dist/cli/utils/prompts.d.ts +0 -56
- package/dist/cli/utils/prompts.js +0 -202
- package/dist/cli/utils/spinner.d.ts +0 -110
- package/dist/cli/utils/spinner.js +0 -266
- package/dist/config.d.ts +0 -217
- package/dist/config.js +0 -591
- package/dist/logger.d.ts +0 -157
- package/dist/logger.js +0 -281
- package/dist/typeschema/cache.d.ts +0 -80
- package/dist/typeschema/cache.js +0 -239
- package/dist/typeschema/core/binding.d.ts +0 -11
- package/dist/typeschema/core/binding.js +0 -143
- package/dist/typeschema/core/field-builder.d.ts +0 -12
- package/dist/typeschema/core/field-builder.js +0 -123
- package/dist/typeschema/core/identifier.d.ts +0 -13
- package/dist/typeschema/core/identifier.js +0 -94
- package/dist/typeschema/core/nested-types.d.ts +0 -9
- package/dist/typeschema/core/nested-types.js +0 -93
- package/dist/typeschema/core/transformer.d.ts +0 -11
- package/dist/typeschema/core/transformer.js +0 -235
- package/dist/typeschema/generator.d.ts +0 -36
- package/dist/typeschema/generator.js +0 -243
- package/dist/typeschema/index.d.ts +0 -15
- package/dist/typeschema/index.js +0 -15
- package/dist/typeschema/parser.d.ts +0 -79
- package/dist/typeschema/parser.js +0 -274
- package/dist/typeschema/profile/processor.d.ts +0 -14
- package/dist/typeschema/profile/processor.js +0 -261
- package/dist/typeschema/register.d.ts +0 -21
- package/dist/typeschema/register.js +0 -117
- package/dist/typeschema/types.d.ts +0 -240
- package/dist/typeschema/types.js +0 -19
- package/dist/utils/codegen-logger.d.ts +0 -102
- package/dist/utils/codegen-logger.js +0 -196
- package/dist/utils.d.ts +0 -22
- package/dist/utils.js +0 -42
|
@@ -1,819 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Modern TypeScript Generator built on BaseGenerator
|
|
3
|
-
*
|
|
4
|
-
* This is the new, clean implementation that replaces the monolithic typescript.ts generator.
|
|
5
|
-
* Built using the BaseGenerator architecture with TypeMapper, TemplateEngine, and FileManager.
|
|
6
|
-
*/
|
|
7
|
-
import { isBindingSchema } from "@typeschema/types";
|
|
8
|
-
import { BaseGenerator } from "./base/BaseGenerator";
|
|
9
|
-
import { TypeScriptTypeMapper } from "./base/TypeScriptTypeMapper";
|
|
10
|
-
/**
|
|
11
|
-
* Modern TypeScript Generator
|
|
12
|
-
*
|
|
13
|
-
* Generates clean, type-safe TypeScript interfaces from FHIR TypeSchema documents.
|
|
14
|
-
* Uses the new BaseGenerator architecture for maintainability and extensibility.
|
|
15
|
-
*/
|
|
16
|
-
export class TypeScriptGenerator extends BaseGenerator {
|
|
17
|
-
resourceTypes = new Set();
|
|
18
|
-
collectedValueSets = new Map();
|
|
19
|
-
get tsOptions() {
|
|
20
|
-
return this.options;
|
|
21
|
-
}
|
|
22
|
-
getLanguageName() {
|
|
23
|
-
return "TypeScript";
|
|
24
|
-
}
|
|
25
|
-
getFileExtension() {
|
|
26
|
-
return ".ts";
|
|
27
|
-
}
|
|
28
|
-
createTypeMapper() {
|
|
29
|
-
const options = this.options;
|
|
30
|
-
return new TypeScriptTypeMapper({
|
|
31
|
-
namingConvention: (options.namingConvention ?? "PascalCase") === "PascalCase" ? "PascalCase" : "camelCase",
|
|
32
|
-
moduleFormat: options.moduleFormat === "cjs" ? "commonjs" : "esm",
|
|
33
|
-
preferUndefined: true,
|
|
34
|
-
...options.typeMapperOptions,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
async generateSchemaContent(schema, _context) {
|
|
38
|
-
// Skip unsupported schema types
|
|
39
|
-
if (this.shouldSkipSchema(schema)) {
|
|
40
|
-
return "";
|
|
41
|
-
}
|
|
42
|
-
// Collect resource types for Reference generic
|
|
43
|
-
if (schema.identifier.kind === "resource") {
|
|
44
|
-
this.resourceTypes.add(this.typeMapper.formatTypeName(schema.identifier.name));
|
|
45
|
-
}
|
|
46
|
-
// Update filename for profiles to include proper directory structure
|
|
47
|
-
// if (false) {
|
|
48
|
-
// // Profile support removed - not in core schema
|
|
49
|
-
// const sanitizedPackage = this.sanitizePackageName(
|
|
50
|
-
// schema.identifier.package || "unknown",
|
|
51
|
-
// );
|
|
52
|
-
// const profileFileName = this.typeMapper.formatFileName(
|
|
53
|
-
// schema.identifier.name,
|
|
54
|
-
// );
|
|
55
|
-
// context.filename = `profiles/${sanitizedPackage}/${profileFileName}`;
|
|
56
|
-
// // Track profile for index generation
|
|
57
|
-
// if (!this.profilesByPackage.has(schema.identifier.package || "unknown")) {
|
|
58
|
-
// this.profilesByPackage.set(schema.identifier.package || "unknown", []);
|
|
59
|
-
// }
|
|
60
|
-
// this.profilesByPackage.get(schema.identifier.package || "unknown")?.push({
|
|
61
|
-
// filename: profileFileName,
|
|
62
|
-
// interfaceName: this.typeMapper.formatTypeName(schema.identifier.name),
|
|
63
|
-
// });
|
|
64
|
-
// }
|
|
65
|
-
// Handle Reference type specially
|
|
66
|
-
if (schema.identifier.name === "Reference") {
|
|
67
|
-
return this.generateReferenceInterface(schema);
|
|
68
|
-
}
|
|
69
|
-
// Generate TypeScript content directly (no templates for simplicity)
|
|
70
|
-
const mainInterface = this.generateTypeScriptInterface(schema);
|
|
71
|
-
// Generate nested types if present
|
|
72
|
-
let nestedInterfaces = "";
|
|
73
|
-
if ("nested" in schema && schema.nested && Array.isArray(schema.nested)) {
|
|
74
|
-
const nestedInterfaceStrings = schema.nested.map((nestedType) => this.generateNestedTypeInterface(schema.identifier.name, nestedType));
|
|
75
|
-
nestedInterfaces = nestedInterfaceStrings.join("\n\n");
|
|
76
|
-
}
|
|
77
|
-
// Combine main interface with nested interfaces
|
|
78
|
-
if (nestedInterfaces) {
|
|
79
|
-
return `${mainInterface}\n\n${nestedInterfaces}`;
|
|
80
|
-
}
|
|
81
|
-
return mainInterface;
|
|
82
|
-
}
|
|
83
|
-
filterAndSortSchemas(schemas) {
|
|
84
|
-
// Collect value sets from ALL schemas before filtering
|
|
85
|
-
this.collectedValueSets = this.collectValueSets(schemas);
|
|
86
|
-
return schemas.filter((schema) => !this.shouldSkipSchema(schema));
|
|
87
|
-
}
|
|
88
|
-
async validateContent(content, context) {
|
|
89
|
-
const hasValidExport = /export\s+(interface|class|type|enum)\s+\w+/.test(content);
|
|
90
|
-
const hasValidSyntax = content.includes("{") && content.includes("}");
|
|
91
|
-
if (!hasValidExport) {
|
|
92
|
-
throw new Error(`Generated content for ${context.schema.identifier.name} does not contain valid export statements`);
|
|
93
|
-
}
|
|
94
|
-
if (!hasValidSyntax) {
|
|
95
|
-
throw new Error(`Generated content for ${context.schema.identifier.name} has invalid syntax (missing braces)`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Transform multiple schemas into TypeScript
|
|
100
|
-
*/
|
|
101
|
-
async transformSchemas(schemas) {
|
|
102
|
-
const results = [];
|
|
103
|
-
for (const schema of schemas) {
|
|
104
|
-
const result = await this.transformSchema(schema);
|
|
105
|
-
if (result) {
|
|
106
|
-
results.push(result);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return results;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Transform a single schema into TypeScript
|
|
113
|
-
*/
|
|
114
|
-
async transformSchema(schema) {
|
|
115
|
-
if (this.shouldSkipSchema(schema)) {
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
// Create template context
|
|
119
|
-
const context = {
|
|
120
|
-
schema,
|
|
121
|
-
typeMapper: this.typeMapper,
|
|
122
|
-
filename: this.getFilenameForSchema(schema),
|
|
123
|
-
language: "TypeScript",
|
|
124
|
-
timestamp: new Date().toISOString(),
|
|
125
|
-
};
|
|
126
|
-
// Generate content using template engine
|
|
127
|
-
const content = await this.generateSchemaContent(schema, context);
|
|
128
|
-
if (!content.trim()) {
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
// Extract imports and exports from generated content
|
|
132
|
-
const imports = this.extractImportsFromContent(content, schema);
|
|
133
|
-
const exports = this.extractExportsFromContent(content, schema);
|
|
134
|
-
const filename = this.getFilenameForSchema(schema);
|
|
135
|
-
return {
|
|
136
|
-
content,
|
|
137
|
-
imports,
|
|
138
|
-
exports: Array.from(exports),
|
|
139
|
-
filename,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Check if a binding schema should generate a value set file
|
|
144
|
-
*/
|
|
145
|
-
shouldGenerateValueSet(schema) {
|
|
146
|
-
if (!isBindingSchema(schema) || !schema.enum || !Array.isArray(schema.enum) || schema.enum.length === 0) {
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
// Handle different value set modes
|
|
150
|
-
const mode = this.options.valueSetMode || "required-only";
|
|
151
|
-
switch (mode) {
|
|
152
|
-
case "all":
|
|
153
|
-
return true; // Generate for all binding strengths
|
|
154
|
-
case "required-only":
|
|
155
|
-
return schema.strength === "required";
|
|
156
|
-
case "custom": {
|
|
157
|
-
const strengths = this.options.valueSetStrengths || ["required"];
|
|
158
|
-
return strengths.includes(schema.strength);
|
|
159
|
-
}
|
|
160
|
-
default:
|
|
161
|
-
return schema.strength === "required";
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Collect value sets from schemas that should generate value set files
|
|
166
|
-
*/
|
|
167
|
-
collectValueSets(schemas) {
|
|
168
|
-
const valueSets = new Map();
|
|
169
|
-
for (const schema of schemas) {
|
|
170
|
-
if (this.shouldGenerateValueSet(schema) && isBindingSchema(schema)) {
|
|
171
|
-
const name = this.typeMapper.formatTypeName(schema.identifier.name);
|
|
172
|
-
valueSets.set(name, schema);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return valueSets;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Check if a field binding should use a value set type
|
|
179
|
-
*/
|
|
180
|
-
shouldUseValueSetType(binding) {
|
|
181
|
-
if (!binding) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
// If generateValueSets is false, never use value set types
|
|
185
|
-
if (!this.tsOptions.generateValueSets) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
const valueSetTypeName = this.typeMapper.formatTypeName(binding.name);
|
|
189
|
-
return this.collectedValueSets.has(valueSetTypeName);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Get the TypeScript type name for a binding
|
|
193
|
-
*/
|
|
194
|
-
getValueSetTypeName(binding) {
|
|
195
|
-
return this.typeMapper.formatTypeName(binding.name);
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Check if a field has enum values that should be inlined
|
|
199
|
-
*/
|
|
200
|
-
shouldUseInlineEnum(field) {
|
|
201
|
-
if (!field) {
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
// Only use inline enums when generateValueSets is false
|
|
205
|
-
if (this.tsOptions.generateValueSets) {
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
// Check if field has enum values directly on the field
|
|
209
|
-
return field.enum && Array.isArray(field.enum) && field.enum.length > 0;
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Generate inline enum type from field enum values
|
|
213
|
-
*/
|
|
214
|
-
generateInlineEnumType(field) {
|
|
215
|
-
if (!field.enum || !Array.isArray(field.enum)) {
|
|
216
|
-
return "string"; // fallback
|
|
217
|
-
}
|
|
218
|
-
// Create union type from enum values
|
|
219
|
-
const enumValues = field.enum.map((value) => `'${value}'`).join(" | ");
|
|
220
|
-
return enumValues;
|
|
221
|
-
}
|
|
222
|
-
shouldSkipSchema(schema) {
|
|
223
|
-
if (schema.identifier.kind === "value-set" ||
|
|
224
|
-
schema.identifier.kind === "binding" ||
|
|
225
|
-
schema.identifier.kind === "primitive-type") {
|
|
226
|
-
return true;
|
|
227
|
-
}
|
|
228
|
-
// Profile support removed - not in core schema specification
|
|
229
|
-
// Skip FHIR extensions when includeExtensions is false
|
|
230
|
-
if (!this.tsOptions.includeExtensions) {
|
|
231
|
-
// Check if this is a FHIR extension by looking at the URL pattern
|
|
232
|
-
const url = schema.identifier.url;
|
|
233
|
-
if (url?.includes("StructureDefinition/")) {
|
|
234
|
-
// Extensions typically have URLs like:
|
|
235
|
-
// http://hl7.org/fhir/StructureDefinition/extension-name
|
|
236
|
-
// http://hl7.org/fhir/StructureDefinition/resource-extension
|
|
237
|
-
// Get the part after StructureDefinition/
|
|
238
|
-
const structDefPart = url.split("StructureDefinition/")[1];
|
|
239
|
-
if (structDefPart) {
|
|
240
|
-
// Check if it contains a hyphen (indicating extension pattern)
|
|
241
|
-
// FHIR extensions are profiles with hyphenated names
|
|
242
|
-
const hasHyphenPattern = structDefPart.includes("-");
|
|
243
|
-
const isProfileKind = schema.identifier.kind === "profile";
|
|
244
|
-
// Extensions are profiles with hyphenated StructureDefinition names
|
|
245
|
-
// But we need to exclude core resources that also have hyphens
|
|
246
|
-
if (hasHyphenPattern && isProfileKind) {
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return false;
|
|
253
|
-
}
|
|
254
|
-
getFilenameForSchema(schema) {
|
|
255
|
-
const baseName = this.typeMapper.formatFileName(schema.identifier.name);
|
|
256
|
-
return `${baseName}${this.getFileExtension()}`;
|
|
257
|
-
}
|
|
258
|
-
extractImportsFromContent(content, _schema) {
|
|
259
|
-
const imports = new Map();
|
|
260
|
-
const importRegex = /import\s+(?:type\s+)?{\s*([^}]+)\s*}\s+from\s+['"]([^'"]+)['"];?/g;
|
|
261
|
-
let match;
|
|
262
|
-
while ((match = importRegex.exec(content)) !== null) {
|
|
263
|
-
const symbolsStr = match[1];
|
|
264
|
-
const path = match[2];
|
|
265
|
-
if (!symbolsStr || !path)
|
|
266
|
-
continue;
|
|
267
|
-
const symbols = symbolsStr.split(",").map((s) => s.trim());
|
|
268
|
-
for (const symbol of symbols) {
|
|
269
|
-
imports.set(symbol, path);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return imports;
|
|
273
|
-
}
|
|
274
|
-
extractExportsFromContent(content, schema) {
|
|
275
|
-
const exports = new Set();
|
|
276
|
-
const exportRegex = /export\s+(?:interface|class|enum|type)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
277
|
-
let match;
|
|
278
|
-
while ((match = exportRegex.exec(content)) !== null) {
|
|
279
|
-
if (match[1])
|
|
280
|
-
exports.add(match[1]);
|
|
281
|
-
}
|
|
282
|
-
exports.add(this.typeMapper.formatTypeName(schema.identifier.name));
|
|
283
|
-
return exports;
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Generate special Reference interface with generics
|
|
287
|
-
*/
|
|
288
|
-
generateReferenceInterface(schema) {
|
|
289
|
-
const lines = [];
|
|
290
|
-
const imports = new Set();
|
|
291
|
-
if ("fields" in schema && schema.fields) {
|
|
292
|
-
for (const [, field] of Object.entries(schema.fields)) {
|
|
293
|
-
const importDeps = this.collectFieldImports(field);
|
|
294
|
-
importDeps.forEach((imp) => imports.add(imp));
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
lines.push("import type { ResourceType } from './utilities.js';");
|
|
298
|
-
if (imports.size > 0) {
|
|
299
|
-
const sortedImports = Array.from(imports).sort();
|
|
300
|
-
for (const importName of sortedImports) {
|
|
301
|
-
lines.push(`import type { ${importName} } from './${importName}.js';`);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
lines.push(""); // Add blank line after imports
|
|
305
|
-
// Add JSDoc comment
|
|
306
|
-
if (this.tsOptions.includeDocuments && schema.description) {
|
|
307
|
-
lines.push("/**");
|
|
308
|
-
lines.push(` * ${schema.description}`);
|
|
309
|
-
if (schema.identifier.url) {
|
|
310
|
-
lines.push(` * @see ${schema.identifier.url}`);
|
|
311
|
-
}
|
|
312
|
-
if (schema.identifier.package) {
|
|
313
|
-
lines.push(` * @package ${schema.identifier.package}`);
|
|
314
|
-
}
|
|
315
|
-
lines.push(" * @template T - The resource type being referenced");
|
|
316
|
-
lines.push(" */");
|
|
317
|
-
}
|
|
318
|
-
// Generate generic interface declaration
|
|
319
|
-
lines.push("export interface Reference<T extends ResourceType = ResourceType> {");
|
|
320
|
-
if ("fields" in schema && schema.fields) {
|
|
321
|
-
for (const [fieldName, field] of Object.entries(schema.fields)) {
|
|
322
|
-
if (fieldName === "type") {
|
|
323
|
-
// Special handling for the type field to use the generic parameter
|
|
324
|
-
lines.push(" type?: T;");
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
const fieldLines = this.generateFieldLines(fieldName, field);
|
|
328
|
-
for (const fieldLine of fieldLines) {
|
|
329
|
-
if (fieldLine) {
|
|
330
|
-
lines.push(` ${fieldLine}`);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
lines.push("}");
|
|
337
|
-
return lines.join("\n");
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Generate TypeScript interface directly without templates
|
|
341
|
-
*/
|
|
342
|
-
generateTypeScriptInterface(schema) {
|
|
343
|
-
const lines = [];
|
|
344
|
-
const interfaceName = this.typeMapper.formatTypeName(schema.identifier.name);
|
|
345
|
-
const imports = new Set();
|
|
346
|
-
const valueSetImports = new Set();
|
|
347
|
-
// Collect imports from fields
|
|
348
|
-
if ("fields" in schema && schema.fields) {
|
|
349
|
-
for (const [, field] of Object.entries(schema.fields)) {
|
|
350
|
-
const fieldImports = this.collectFieldImports(field);
|
|
351
|
-
for (const imp of fieldImports) {
|
|
352
|
-
// Check if this is a value set import
|
|
353
|
-
if (this.collectedValueSets.has(imp)) {
|
|
354
|
-
valueSetImports.add(imp);
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
imports.add(imp);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
// Collect imports from nested types
|
|
363
|
-
if ("nested" in schema && schema.nested && Array.isArray(schema.nested)) {
|
|
364
|
-
for (const nestedType of schema.nested) {
|
|
365
|
-
if (nestedType.fields) {
|
|
366
|
-
for (const [, field] of Object.entries(nestedType.fields)) {
|
|
367
|
-
const fieldImports = this.collectFieldImports(field);
|
|
368
|
-
for (const imp of fieldImports) {
|
|
369
|
-
// Check if this is a value set import
|
|
370
|
-
if (this.collectedValueSets.has(imp)) {
|
|
371
|
-
valueSetImports.add(imp);
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
imports.add(imp);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
// Generate regular type imports
|
|
382
|
-
if (imports.size > 0) {
|
|
383
|
-
const sortedImports = Array.from(imports).sort();
|
|
384
|
-
for (const importName of sortedImports) {
|
|
385
|
-
lines.push(`import type { ${importName} } from './${importName}.js';`);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
// Generate value set imports
|
|
389
|
-
if (valueSetImports.size > 0) {
|
|
390
|
-
const sortedValueSetImports = Array.from(valueSetImports).sort();
|
|
391
|
-
const importList = sortedValueSetImports.join(", ");
|
|
392
|
-
lines.push(`import type { ${importList} } from './valuesets/index.js';`);
|
|
393
|
-
}
|
|
394
|
-
if (imports.size > 0 || valueSetImports.size > 0) {
|
|
395
|
-
lines.push(""); // Add blank line after imports
|
|
396
|
-
}
|
|
397
|
-
// Add JSDoc comment if enabled
|
|
398
|
-
if (this.tsOptions.includeDocuments && schema.description) {
|
|
399
|
-
lines.push("/**");
|
|
400
|
-
lines.push(` * ${schema.description}`);
|
|
401
|
-
if (schema.identifier.url) {
|
|
402
|
-
lines.push(` * @see ${schema.identifier.url}`);
|
|
403
|
-
}
|
|
404
|
-
if (schema.identifier.package) {
|
|
405
|
-
lines.push(` * @package ${schema.identifier.package}`);
|
|
406
|
-
}
|
|
407
|
-
lines.push(" */");
|
|
408
|
-
}
|
|
409
|
-
// Generate interface declaration
|
|
410
|
-
lines.push(`export interface ${interfaceName} {`);
|
|
411
|
-
// Add resourceType for FHIR resources
|
|
412
|
-
if (schema.identifier.kind === "resource") {
|
|
413
|
-
lines.push(` resourceType: '${interfaceName}';`);
|
|
414
|
-
}
|
|
415
|
-
// Generate fields (if any)
|
|
416
|
-
if ("fields" in schema && schema.fields) {
|
|
417
|
-
for (const [fieldName, field] of Object.entries(schema.fields)) {
|
|
418
|
-
const fieldLines = this.generateFieldLines(fieldName, field);
|
|
419
|
-
for (const fieldLine of fieldLines) {
|
|
420
|
-
if (fieldLine) {
|
|
421
|
-
lines.push(` ${fieldLine}`);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
lines.push("}");
|
|
427
|
-
return lines.join("\n");
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Collect import dependencies from a field
|
|
431
|
-
*/
|
|
432
|
-
collectFieldImports(field) {
|
|
433
|
-
const imports = [];
|
|
434
|
-
// Skip polymorphic declaration fields (they don't have types to import)
|
|
435
|
-
if ("choices" in field && field.choices && Array.isArray(field.choices)) {
|
|
436
|
-
return imports;
|
|
437
|
-
}
|
|
438
|
-
// Handle value set imports (only when generateValueSets is true)
|
|
439
|
-
if (field.binding && this.shouldUseValueSetType(field.binding)) {
|
|
440
|
-
const valueSetTypeName = this.getValueSetTypeName(field.binding);
|
|
441
|
-
imports.push(valueSetTypeName);
|
|
442
|
-
return imports;
|
|
443
|
-
}
|
|
444
|
-
// Handle all other fields (regular fields and polymorphic instance fields)
|
|
445
|
-
if ("type" in field && field.type) {
|
|
446
|
-
// Handle nested types - they don't need imports as they're in the same file
|
|
447
|
-
if (field.type.kind === "nested") {
|
|
448
|
-
// Nested types are generated in the same file, no import needed
|
|
449
|
-
return imports;
|
|
450
|
-
}
|
|
451
|
-
const languageType = this.typeMapper.mapType(field.type);
|
|
452
|
-
// Only import non-primitive types that are not built-in
|
|
453
|
-
if (!languageType.isPrimitive && languageType.name !== "any") {
|
|
454
|
-
const builtInTypes = ["string", "number", "boolean", "Date", "object", "unknown", "any"];
|
|
455
|
-
if (!builtInTypes.includes(languageType.name)) {
|
|
456
|
-
imports.push(languageType.name);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
return [...new Set(imports)]; // Remove duplicates
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
* Extract resource types from reference field constraints
|
|
464
|
-
*/
|
|
465
|
-
extractReferenceTypes(referenceConstraints) {
|
|
466
|
-
const resourceTypes = [];
|
|
467
|
-
if (!Array.isArray(referenceConstraints)) {
|
|
468
|
-
return resourceTypes;
|
|
469
|
-
}
|
|
470
|
-
for (const constraint of referenceConstraints) {
|
|
471
|
-
if (!constraint || typeof constraint !== "object") {
|
|
472
|
-
continue;
|
|
473
|
-
}
|
|
474
|
-
if (constraint.kind === "resource" && constraint.name) {
|
|
475
|
-
const resourceType = this.typeMapper.formatTypeName(constraint.name);
|
|
476
|
-
resourceTypes.push(resourceType);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
return [...new Set(resourceTypes)]; // Remove duplicates
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Generate nested type interface
|
|
483
|
-
*/
|
|
484
|
-
generateNestedTypeInterface(parentTypeName, nestedType) {
|
|
485
|
-
const lines = [];
|
|
486
|
-
const nestedTypeName = this.typeMapper.formatTypeName(`${parentTypeName}${this.capitalizeFirst(nestedType.identifier.name)}`);
|
|
487
|
-
// Add JSDoc comment if enabled
|
|
488
|
-
if (this.tsOptions.includeDocuments && nestedType.description) {
|
|
489
|
-
lines.push("/**");
|
|
490
|
-
lines.push(` * ${nestedType.description}`);
|
|
491
|
-
if (nestedType.identifier.url) {
|
|
492
|
-
lines.push(` * @see ${nestedType.identifier.url}`);
|
|
493
|
-
}
|
|
494
|
-
lines.push(" */");
|
|
495
|
-
}
|
|
496
|
-
// Generate interface declaration
|
|
497
|
-
lines.push(`export interface ${nestedTypeName} {`);
|
|
498
|
-
// Generate fields
|
|
499
|
-
if (nestedType.fields) {
|
|
500
|
-
for (const [fieldName, field] of Object.entries(nestedType.fields)) {
|
|
501
|
-
const fieldLines = this.generateFieldLines(fieldName, field);
|
|
502
|
-
for (const fieldLine of fieldLines) {
|
|
503
|
-
if (fieldLine) {
|
|
504
|
-
lines.push(` ${fieldLine}`);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
lines.push("}");
|
|
510
|
-
return lines.join("\n");
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* Capitalize first letter of string
|
|
514
|
-
*/
|
|
515
|
-
capitalizeFirst(str) {
|
|
516
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Generate field lines (handles polymorphic fields by expanding them)
|
|
520
|
-
*/
|
|
521
|
-
generateFieldLines(fieldName, field) {
|
|
522
|
-
// Check if this field has choices (polymorphic declaration field)
|
|
523
|
-
if ("choices" in field && field.choices && Array.isArray(field.choices)) {
|
|
524
|
-
// Skip declaration fields - the actual instance fields are generated separately
|
|
525
|
-
// Declaration fields like `{"choices": ["deceasedBoolean", "deceasedDateTime"]}`
|
|
526
|
-
// are just metadata and shouldn't be rendered as actual TypeScript fields
|
|
527
|
-
return [];
|
|
528
|
-
}
|
|
529
|
-
// For all other fields (including polymorphic instance fields with choiceOf), generate normally
|
|
530
|
-
const fieldLine = this.generateFieldLine(fieldName, field);
|
|
531
|
-
return fieldLine ? [fieldLine] : [];
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Generate a single field line
|
|
535
|
-
*/
|
|
536
|
-
generateFieldLine(fieldName, field) {
|
|
537
|
-
let typeString = "any";
|
|
538
|
-
let required = false;
|
|
539
|
-
let isArray = false;
|
|
540
|
-
if ("type" in field && field.type) {
|
|
541
|
-
// Check if field has a binding that we generated a value set for
|
|
542
|
-
if (field.binding && this.shouldUseValueSetType(field.binding)) {
|
|
543
|
-
const valueSetTypeName = this.getValueSetTypeName(field.binding);
|
|
544
|
-
typeString = valueSetTypeName;
|
|
545
|
-
}
|
|
546
|
-
else if (field.binding && this.shouldUseInlineEnum(field)) {
|
|
547
|
-
// Generate inline enum union type when generateValueSets is false
|
|
548
|
-
typeString = this.generateInlineEnumType(field);
|
|
549
|
-
}
|
|
550
|
-
else {
|
|
551
|
-
// Existing type mapping logic
|
|
552
|
-
const languageType = this.typeMapper.mapType(field.type);
|
|
553
|
-
typeString = languageType.name;
|
|
554
|
-
// Handle nested types specially
|
|
555
|
-
if (field.type.kind === "nested") {
|
|
556
|
-
// Extract parent name from URL like "http://hl7.org/fhir/StructureDefinition/Patient#contact"
|
|
557
|
-
const urlParts = field.type.url?.split("#") || [];
|
|
558
|
-
if (urlParts.length === 2) {
|
|
559
|
-
const parentName = urlParts[0].split("/").pop() || "";
|
|
560
|
-
const nestedName = field.type.name;
|
|
561
|
-
typeString = this.typeMapper.formatTypeName(`${parentName}${this.capitalizeFirst(nestedName)}`);
|
|
562
|
-
}
|
|
563
|
-
else {
|
|
564
|
-
typeString = this.typeMapper.formatTypeName(field.type.name);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
else if (typeString === "Reference" && field.reference && Array.isArray(field.reference)) {
|
|
568
|
-
const referenceTypes = this.extractReferenceTypes(field.reference);
|
|
569
|
-
if (referenceTypes.length > 0) {
|
|
570
|
-
referenceTypes.forEach((type) => this.resourceTypes.add(type));
|
|
571
|
-
const unionType = referenceTypes.map((type) => `'${type}'`).join(" | ");
|
|
572
|
-
typeString = `Reference<${unionType}>`;
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
if ("required" in field) {
|
|
578
|
-
required = field.required;
|
|
579
|
-
}
|
|
580
|
-
if ("array" in field) {
|
|
581
|
-
isArray = field.array;
|
|
582
|
-
}
|
|
583
|
-
const optional = required ? "" : "?";
|
|
584
|
-
const arrayType = isArray ? "[]" : "";
|
|
585
|
-
return `${fieldName}${optional}: ${typeString}${arrayType};`;
|
|
586
|
-
}
|
|
587
|
-
// ==========================================
|
|
588
|
-
/**
|
|
589
|
-
* Extract exported symbols from TypeScript content
|
|
590
|
-
*/
|
|
591
|
-
extractExports(content) {
|
|
592
|
-
const exports = [];
|
|
593
|
-
const exportListPattern = /export\s*\{\s*([^}]+)\s*\}/g;
|
|
594
|
-
let match;
|
|
595
|
-
while ((match = exportListPattern.exec(content)) !== null) {
|
|
596
|
-
if (match[1]) {
|
|
597
|
-
const names = match[1]
|
|
598
|
-
.split(",")
|
|
599
|
-
.map((name) => name.trim())
|
|
600
|
-
.filter(Boolean);
|
|
601
|
-
exports.push(...names);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
const directExportPatterns = [
|
|
605
|
-
/export\s+interface\s+(\w+)/g, // export interface Name
|
|
606
|
-
/export\s+type\s+(\w+)/g, // export type Name
|
|
607
|
-
/export\s+class\s+(\w+)/g, // export class Name
|
|
608
|
-
/export\s+enum\s+(\w+)/g, // export enum Name
|
|
609
|
-
/export\s+const\s+(\w+)/g, // export const name
|
|
610
|
-
/export\s+function\s+(\w+)/g, // export function name
|
|
611
|
-
];
|
|
612
|
-
for (const pattern of directExportPatterns) {
|
|
613
|
-
let match;
|
|
614
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
615
|
-
if (match[1]) {
|
|
616
|
-
exports.push(match[1]);
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
return [...new Set(exports)];
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Set output directory for compatibility with API builder
|
|
624
|
-
*/
|
|
625
|
-
setOutputDir(directory) {
|
|
626
|
-
this.options.outputDir = directory;
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Update generator options for compatibility with API builder
|
|
630
|
-
*/
|
|
631
|
-
setOptions(options) {
|
|
632
|
-
this.options = { ...this.options, ...options };
|
|
633
|
-
}
|
|
634
|
-
/**
|
|
635
|
-
* Get current options for compatibility with API builder
|
|
636
|
-
*/
|
|
637
|
-
getOptions() {
|
|
638
|
-
return { ...this.options };
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Override generate to clean directory first
|
|
642
|
-
*/
|
|
643
|
-
async generate(schemas) {
|
|
644
|
-
// Clean output directory before generation
|
|
645
|
-
await this.fileManager.cleanDirectory();
|
|
646
|
-
this.logger.debug("Cleaned output directory before generation");
|
|
647
|
-
// Call parent implementation
|
|
648
|
-
return super.generate(schemas);
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* Run post-generation hooks - generate utility files
|
|
652
|
-
*/
|
|
653
|
-
async runPostGenerationHooks() {
|
|
654
|
-
await super.runPostGenerationHooks();
|
|
655
|
-
await this.generateValueSetFiles();
|
|
656
|
-
await this.generateUtilitiesFile();
|
|
657
|
-
await this.generateMainIndexFile();
|
|
658
|
-
}
|
|
659
|
-
/**
|
|
660
|
-
* Generate utilities.ts file with ResourceType union
|
|
661
|
-
*/
|
|
662
|
-
async generateUtilitiesFile() {
|
|
663
|
-
if (this.resourceTypes.size === 0) {
|
|
664
|
-
this.logger.warn("No resource types found, skipping utilities.ts generation");
|
|
665
|
-
return;
|
|
666
|
-
}
|
|
667
|
-
const lines = [];
|
|
668
|
-
// Add file header comment
|
|
669
|
-
lines.push("/**");
|
|
670
|
-
lines.push(" * FHIR Resource Type Utilities");
|
|
671
|
-
lines.push(" * This file contains utility types for FHIR resources.");
|
|
672
|
-
lines.push(" * ");
|
|
673
|
-
lines.push(" * @generated This file is auto-generated. Do not edit manually.");
|
|
674
|
-
lines.push(" */");
|
|
675
|
-
lines.push("");
|
|
676
|
-
// Generate ResourceType union
|
|
677
|
-
const sortedResourceTypes = Array.from(this.resourceTypes).sort();
|
|
678
|
-
lines.push("/**");
|
|
679
|
-
lines.push(" * Union of all FHIR resource types in this package");
|
|
680
|
-
lines.push(" */");
|
|
681
|
-
lines.push("export type ResourceType =");
|
|
682
|
-
for (let i = 0; i < sortedResourceTypes.length; i++) {
|
|
683
|
-
const isLast = i === sortedResourceTypes.length - 1;
|
|
684
|
-
const separator = isLast ? ";" : "";
|
|
685
|
-
lines.push(` | '${sortedResourceTypes[i]}'${separator}`);
|
|
686
|
-
}
|
|
687
|
-
lines.push("");
|
|
688
|
-
// Generate helper type for Resource references
|
|
689
|
-
lines.push("/**");
|
|
690
|
-
lines.push(" * Helper type for creating typed References");
|
|
691
|
-
lines.push(" * @example Reference<'Patient' | 'Practitioner'> - Reference that can point to Patient or Practitioner");
|
|
692
|
-
lines.push(" */");
|
|
693
|
-
lines.push("export type TypedReference<T extends ResourceType> = {");
|
|
694
|
-
lines.push(" reference?: string;");
|
|
695
|
-
lines.push(" type?: T;");
|
|
696
|
-
lines.push(" identifier?: any; // Simplified for utility");
|
|
697
|
-
lines.push(" display?: string;");
|
|
698
|
-
lines.push("};");
|
|
699
|
-
const content = lines.join("\n");
|
|
700
|
-
// Write the utilities file
|
|
701
|
-
await this.fileManager.writeFile("utilities.ts", content);
|
|
702
|
-
this.logger.info(`Generated utilities.ts with ${this.resourceTypes.size} resource types`);
|
|
703
|
-
}
|
|
704
|
-
/**
|
|
705
|
-
* Generate a complete value set TypeScript file
|
|
706
|
-
*/
|
|
707
|
-
generateValueSetFile(binding) {
|
|
708
|
-
const name = this.typeMapper.formatTypeName(binding.identifier.name);
|
|
709
|
-
const values = binding.enum?.map((v) => ` '${v}'`).join(",\n") || "";
|
|
710
|
-
const lines = [];
|
|
711
|
-
// Add file header comment
|
|
712
|
-
if (this.options.includeDocuments) {
|
|
713
|
-
lines.push("/**");
|
|
714
|
-
lines.push(` * ${binding.identifier.name} value set`);
|
|
715
|
-
if (binding.description) {
|
|
716
|
-
lines.push(` * ${binding.description}`);
|
|
717
|
-
}
|
|
718
|
-
if (binding.valueset?.url) {
|
|
719
|
-
lines.push(` * @see ${binding.valueset.url}`);
|
|
720
|
-
}
|
|
721
|
-
if (binding.identifier.package) {
|
|
722
|
-
lines.push(` * @package ${binding.identifier.package}`);
|
|
723
|
-
}
|
|
724
|
-
lines.push(" * @generated This file is auto-generated. Do not edit manually.");
|
|
725
|
-
lines.push(" */");
|
|
726
|
-
lines.push("");
|
|
727
|
-
}
|
|
728
|
-
// Add values array
|
|
729
|
-
lines.push(`export const ${name}Values = [`);
|
|
730
|
-
if (values) {
|
|
731
|
-
lines.push(values);
|
|
732
|
-
}
|
|
733
|
-
lines.push("] as const;");
|
|
734
|
-
lines.push("");
|
|
735
|
-
// Add union type
|
|
736
|
-
lines.push(`export type ${name} = typeof ${name}Values[number];`);
|
|
737
|
-
// Add helper function if enabled
|
|
738
|
-
if (this.tsOptions.includeValueSetHelpers) {
|
|
739
|
-
lines.push("");
|
|
740
|
-
lines.push(`export const isValid${name} = (value: string): value is ${name} =>`);
|
|
741
|
-
lines.push(` ${name}Values.includes(value as ${name});`);
|
|
742
|
-
}
|
|
743
|
-
return lines.join("\n");
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* Create valuesets directory and generate all value set files
|
|
747
|
-
*/
|
|
748
|
-
async generateValueSetFiles() {
|
|
749
|
-
if (!this.tsOptions.generateValueSets || this.collectedValueSets.size === 0) {
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
// Generate individual value set files in valuesets/
|
|
753
|
-
for (const [name, binding] of this.collectedValueSets) {
|
|
754
|
-
const content = this.generateValueSetFile(binding);
|
|
755
|
-
const fileName = `valuesets/${name}.ts`;
|
|
756
|
-
await this.fileManager.writeFile(fileName, content);
|
|
757
|
-
this.logger.info(`Generated value set: ${fileName}`);
|
|
758
|
-
}
|
|
759
|
-
// Generate index file in valuesets/
|
|
760
|
-
await this.generateValueSetIndexFile();
|
|
761
|
-
}
|
|
762
|
-
/**
|
|
763
|
-
* Generate index.ts file that re-exports all value sets
|
|
764
|
-
*/
|
|
765
|
-
async generateValueSetIndexFile() {
|
|
766
|
-
const lines = [];
|
|
767
|
-
if (this.tsOptions.includeDocuments) {
|
|
768
|
-
lines.push("/**");
|
|
769
|
-
lines.push(" * FHIR Value Sets");
|
|
770
|
-
lines.push(" * This file re-exports all generated value sets.");
|
|
771
|
-
lines.push(" * ");
|
|
772
|
-
lines.push(" * @generated This file is auto-generated. Do not edit manually.");
|
|
773
|
-
lines.push(" */");
|
|
774
|
-
lines.push("");
|
|
775
|
-
}
|
|
776
|
-
// Sort value sets for consistent output
|
|
777
|
-
const sortedValueSets = Array.from(this.collectedValueSets.keys()).sort();
|
|
778
|
-
for (const name of sortedValueSets) {
|
|
779
|
-
lines.push(`export * from './${name}.js';`);
|
|
780
|
-
}
|
|
781
|
-
const content = lines.join("\n");
|
|
782
|
-
await this.fileManager.writeFile("valuesets/index.ts", content);
|
|
783
|
-
this.logger.info(`Generated valuesets/index.ts with ${this.collectedValueSets.size} value sets`);
|
|
784
|
-
}
|
|
785
|
-
/**
|
|
786
|
-
* Generate main types/index.ts file that exports all types and value sets
|
|
787
|
-
*/
|
|
788
|
-
async generateMainIndexFile() {
|
|
789
|
-
if (!this.options.generateIndex) {
|
|
790
|
-
return;
|
|
791
|
-
}
|
|
792
|
-
const lines = [];
|
|
793
|
-
if (this.tsOptions.includeDocuments) {
|
|
794
|
-
lines.push("/**");
|
|
795
|
-
lines.push(" * FHIR R4 TypeScript Types");
|
|
796
|
-
lines.push(" * Generated from FHIR StructureDefinitions");
|
|
797
|
-
lines.push(" * ");
|
|
798
|
-
lines.push(" * @generated This file is auto-generated. Do not edit manually.");
|
|
799
|
-
lines.push(" */");
|
|
800
|
-
lines.push("");
|
|
801
|
-
}
|
|
802
|
-
// Generate exports for all generated files - we'll keep this simple
|
|
803
|
-
// and avoid accessing private fields for now. The key functionality
|
|
804
|
-
// (value set generation and interface type updates) is already working.
|
|
805
|
-
// For now, we'll skip the individual file exports since they're complex
|
|
806
|
-
// and the main functionality is already working. This can be improved later.
|
|
807
|
-
// Export utilities
|
|
808
|
-
lines.push('export * from "./utilities";');
|
|
809
|
-
// Export value sets if any were generated
|
|
810
|
-
if (this.tsOptions.generateValueSets && this.collectedValueSets.size > 0) {
|
|
811
|
-
lines.push("");
|
|
812
|
-
lines.push("// Value Sets");
|
|
813
|
-
lines.push('export * from "./valuesets/index";');
|
|
814
|
-
}
|
|
815
|
-
const content = lines.join("\n");
|
|
816
|
-
await this.fileManager.writeFile("index.ts", content);
|
|
817
|
-
this.logger.info(`Generated index.ts with type exports${this.tsOptions.generateValueSets && this.collectedValueSets.size > 0 ? " and value sets" : ""}`);
|
|
818
|
-
}
|
|
819
|
-
}
|