babelfhir-ts 1.2.0 → 1.2.2

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.
@@ -0,0 +1,208 @@
1
+ import { generateIntoPackage, resetFetchFailureTracking, getFetchFailureWarning } from "../generator/index.js";
2
+ import { getCacheConfig, clearAllCaches } from "../generator/core/cacheConfig.js";
3
+ import { buildQualityReport, formatReportSummary, resetDiagnostics } from "../generator/core/sdDiagnostics.js";
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { spawn } from 'child_process';
7
+ /** Display all generation warnings (fetch failures, incomplete extension slices, etc.) */
8
+ function showGenerationWarnings() {
9
+ let hasWarnings = false;
10
+ const fetchWarning = getFetchFailureWarning();
11
+ if (fetchWarning) {
12
+ console.warn(fetchWarning);
13
+ hasWarnings = true;
14
+ }
15
+ return hasWarnings;
16
+ }
17
+ function cleanupCache() {
18
+ const cacheConfig = getCacheConfig();
19
+ if (fs.existsSync(cacheConfig.rootDir)) {
20
+ console.log('Cleaning up cache directory...');
21
+ clearAllCaches();
22
+ console.log('Cache cleaned.');
23
+ }
24
+ }
25
+ /** Detect the package manager used in the current working directory */
26
+ function detectPackageManager() {
27
+ const cwd = process.cwd();
28
+ const isWin = process.platform === 'win32';
29
+ if (fs.existsSync(path.join(cwd, 'bun.lock')) || fs.existsSync(path.join(cwd, 'bun.lockb'))) {
30
+ return { cmd: isWin ? 'bun.exe' : 'bun', args: ['add'] };
31
+ }
32
+ if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) {
33
+ return { cmd: isWin ? 'pnpm.cmd' : 'pnpm', args: ['add'] };
34
+ }
35
+ if (fs.existsSync(path.join(cwd, 'yarn.lock'))) {
36
+ return { cmd: isWin ? 'yarn.cmd' : 'yarn', args: ['add'] };
37
+ }
38
+ return { cmd: isWin ? 'npm.cmd' : 'npm', args: ['install'] };
39
+ }
40
+ function npmInstall(packagePath) {
41
+ return new Promise((resolve, reject) => {
42
+ const pm = detectPackageManager();
43
+ const pmName = path.basename(pm.cmd).replace(/\.(cmd|exe)$/, '');
44
+ // Check if the package already exists in package.json to avoid dependency loops.
45
+ const projectPkgPath = path.join(process.cwd(), 'package.json');
46
+ let useInstallOnly = false;
47
+ if (fs.existsSync(projectPkgPath)) {
48
+ try {
49
+ const tgzRelPath = './' + path.relative(process.cwd(), packagePath).replace(/\\/g, '/');
50
+ const projectPkg = JSON.parse(fs.readFileSync(projectPkgPath, 'utf8'));
51
+ const deps = projectPkg.dependencies || {};
52
+ for (const [name, value] of Object.entries(deps)) {
53
+ if (typeof value === 'string' && (value === tgzRelPath || value === packagePath)) {
54
+ console.log(`Package ${name} already in dependencies, running ${pmName} install`);
55
+ useInstallOnly = true;
56
+ break;
57
+ }
58
+ }
59
+ if (!useInstallOnly) {
60
+ const tgzBaseName = path.basename(packagePath, '.tgz').replace(/^-/, '');
61
+ for (const name of Object.keys(deps)) {
62
+ if (name.replace(/[@/]/g, '-') === tgzBaseName) {
63
+ deps[name] = tgzRelPath;
64
+ projectPkg.dependencies = deps;
65
+ fs.writeFileSync(projectPkgPath, JSON.stringify(projectPkg, null, 2) + '\n');
66
+ console.log(`Updated ${name} dependency to ${tgzRelPath}`);
67
+ useInstallOnly = true;
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ }
73
+ catch { /* ignore, fall through to normal add */ }
74
+ }
75
+ const args = useInstallOnly ? ['install'] : [...pm.args, packagePath];
76
+ console.log(`Installing package with ${pmName}...`);
77
+ const child = spawn(pm.cmd, args, {
78
+ stdio: 'inherit',
79
+ shell: true
80
+ });
81
+ child.on('exit', (code) => {
82
+ if (code === 0) {
83
+ console.log(`✓ Package installed successfully`);
84
+ resolve();
85
+ }
86
+ else {
87
+ reject(new Error(`${pmName} install failed with exit code ${code}`));
88
+ }
89
+ });
90
+ child.on('error', (err) => {
91
+ reject(new Error(`Failed to run ${pmName} install: ${err.message}`));
92
+ });
93
+ });
94
+ }
95
+ export async function handleInstallCommand(opts) {
96
+ const { packageToInstall, registry, generationFlags, downloadPackage } = opts;
97
+ // Default to cleaning cache for install command
98
+ if (!generationFlags.noCache) {
99
+ generationFlags.noCache = true;
100
+ }
101
+ try {
102
+ let downloadedPath;
103
+ if (fs.existsSync(packageToInstall) && (packageToInstall.endsWith('.tgz') || packageToInstall.endsWith('.zip'))) {
104
+ console.log(`Using local package: ${packageToInstall}`);
105
+ downloadedPath = path.resolve(packageToInstall);
106
+ }
107
+ else {
108
+ downloadedPath = await downloadPackage(packageToInstall, registry);
109
+ }
110
+ console.log(`Processing package...`);
111
+ const baseName = path.basename(downloadedPath, path.extname(downloadedPath));
112
+ const outputArchive = path.join(process.cwd(), `${baseName}.with-generated.tgz`);
113
+ resetFetchFailureTracking();
114
+ resetDiagnostics();
115
+ await generateIntoPackage(downloadedPath, outputArchive, generationFlags);
116
+ // Clean up temp directory only if we downloaded from registry (not for local files)
117
+ if (!fs.existsSync(packageToInstall) || !(packageToInstall.endsWith('.tgz') || packageToInstall.endsWith('.zip'))) {
118
+ const tempDir = path.join(process.cwd(), '.temp-download');
119
+ if (fs.existsSync(tempDir)) {
120
+ fs.rmSync(tempDir, { recursive: true, force: true });
121
+ }
122
+ }
123
+ console.log(`✓ Package processed successfully: ${path.basename(outputArchive)}`);
124
+ // Extract the archive to access generated folder
125
+ console.log(`Extracting generated code...`);
126
+ const { extract } = await import('tar');
127
+ const extractDir = path.join(process.cwd(), '.temp-install');
128
+ if (!fs.existsSync(extractDir)) {
129
+ fs.mkdirSync(extractDir, { recursive: true });
130
+ }
131
+ await extract({ cwd: extractDir, file: outputArchive });
132
+ // Look for generated folder - could be at root or under 'package' subfolder
133
+ let generatedDir = path.join(extractDir, 'generated');
134
+ if (!fs.existsSync(generatedDir)) {
135
+ generatedDir = path.join(extractDir, 'package', 'generated');
136
+ }
137
+ if (!fs.existsSync(generatedDir)) {
138
+ throw new Error('Generated folder not found in package archive');
139
+ }
140
+ // Verify package.json exists
141
+ const pkgJsonPath = path.join(generatedDir, 'package.json');
142
+ if (!fs.existsSync(pkgJsonPath)) {
143
+ throw new Error(`package.json not found in generated folder: ${generatedDir}`);
144
+ }
145
+ // Create a tarball from the generated folder to avoid symlink issues on Windows
146
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
147
+ const packageName = pkgJson.name;
148
+ console.log(`Creating package tarball for ${packageName}...`);
149
+ // Ensure ./lib exists for storing the generated tarball
150
+ const libDir = path.join(process.cwd(), 'lib');
151
+ if (!fs.existsSync(libDir)) {
152
+ fs.mkdirSync(libDir, { recursive: true });
153
+ }
154
+ const { create } = await import('tar');
155
+ const tarballName = `${packageName.replace(/[@/]/g, '-')}.tgz`;
156
+ const tarballPath = path.join(libDir, tarballName);
157
+ // npm expects tarballs to have content under a 'package/' root folder
158
+ await create({
159
+ gzip: true,
160
+ file: tarballPath,
161
+ cwd: generatedDir,
162
+ prefix: 'package'
163
+ }, ['.']);
164
+ console.log(`Installing ${packageName}...`);
165
+ await npmInstall(tarballPath);
166
+ // Clean up temporary files (but keep the tarball that npm references in package.json under ./lib)
167
+ console.log(`Cleaning up temporary files...`);
168
+ if (fs.existsSync(extractDir)) {
169
+ fs.rmSync(extractDir, { recursive: true, force: true });
170
+ }
171
+ if (fs.existsSync(outputArchive)) {
172
+ fs.unlinkSync(outputArchive);
173
+ console.log(`✓ Removed ${path.basename(outputArchive)}`);
174
+ }
175
+ console.log(`✓ Package tarball saved to ./lib: ${path.basename(tarballPath)}`);
176
+ showGenerationWarnings();
177
+ const report = buildQualityReport();
178
+ const summary = formatReportSummary(report);
179
+ if (summary.trim())
180
+ console.log(summary);
181
+ if (generationFlags.noCache) {
182
+ cleanupCache();
183
+ }
184
+ console.log(`\n✓ Package ${packageToInstall} installed and ready to use!`);
185
+ }
186
+ catch (error) {
187
+ // Clean up temporary files on error
188
+ for (const dir of ['.temp-download', '.temp-install']) {
189
+ const fullPath = path.join(process.cwd(), dir);
190
+ if (fs.existsSync(fullPath)) {
191
+ fs.rmSync(fullPath, { recursive: true, force: true });
192
+ }
193
+ }
194
+ // Clean up any leftover archive
195
+ const baseName = packageToInstall.includes('@')
196
+ ? packageToInstall.replace('@', '-').replace(/\//g, '-')
197
+ : path.basename(packageToInstall, path.extname(packageToInstall));
198
+ const outputArchive = path.join(process.cwd(), `${baseName}.with-generated.tgz`);
199
+ if (fs.existsSync(outputArchive)) {
200
+ fs.unlinkSync(outputArchive);
201
+ }
202
+ if (generationFlags.noCache) {
203
+ cleanupCache();
204
+ }
205
+ console.error(`Error: ${error.message}`);
206
+ process.exit(1);
207
+ }
208
+ }
@@ -5,7 +5,7 @@ import { versionSlug } from '../../fhir/versionContext.js';
5
5
  import { buildRequiredConstraints, buildMaxCardinalityConstraints, buildForbiddenFieldConstraintEntries, buildPatternValidations, } from './validatorConstraintBuilders.js';
6
6
  import { buildNestedRequiredValidations, buildFixedValueValidations, buildProhibitedFieldValidations, buildPrimitiveFormatValidations, } from './validatorFieldBuilders.js';
7
7
  import { buildBindingValidations } from './validatorBindingBuilder.js';
8
- import { generateBundleRefValidation, generateExtensionStructuralValidation } from './validatorTemplates.js';
8
+ import { generateBundleRefValidation, generateContainedRefValidation, generateExtensionStructuralValidation } from './validatorTemplates.js';
9
9
  const log = logger.withTag('validator');
10
10
  /**
11
11
  * Returns the content of ValidatorOptions.ts — the shared runtime options type
@@ -146,6 +146,7 @@ export function generateValidateProfileFunction(interfaceName, fields, valueSets
146
146
  });
147
147
  const primitiveFormatValidations = buildPrimitiveFormatValidations(fields);
148
148
  const bundleRefValidation = generateBundleRefValidation(baseResourceType);
149
+ const containedRefValidation = generateContainedRefValidation(baseResourceType);
149
150
  const extensionStructuralValidation = generateExtensionStructuralValidation();
150
151
  // ── Deduplicate & filter constraints ────────────────────────────────────
151
152
  const uniqueConstraints = Array.from(new Map(constraintsWithContext.map((item) => [item.constraint.expression + "|" + item.fieldPath, item])).values());
@@ -229,7 +230,7 @@ export async function validate${interfaceName}(resource: ${interfaceName}, optio
229
230
  const errors: string[] = [];
230
231
  const warnings: string[] = [];
231
232
  void options;
232
- ${extensionStructuralValidation}
233
+ ${extensionStructuralValidation}${containedRefValidation}
233
234
  return { errors, warnings };
234
235
  }`,
235
236
  valueSetImports
@@ -265,7 +266,7 @@ ${extensionStructuralValidation}
265
266
  const errors: string[] = [];
266
267
  const warnings: string[] = [];
267
268
  ${fhirpathOptionsBlock}
268
- ${validationLogic}${fixedPatternValidations.join('')}${nestedRequiredValidations.join('')}${fixedValueValidations.join('')}${(bindingValidations.length > 0 || prohibitedFieldValidations.length > 0 || primitiveFormatValidations.length > 0) ? `\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const _bRes = resource as Record<string, any>;` : ''}${prohibitedFieldValidations.join('')}${bindingValidations.join('')}${primitiveFormatValidations.join('')}${sliceValidations.join('')}${extensionStructuralValidation}${bundleRefValidation}
269
+ ${validationLogic}${fixedPatternValidations.join('')}${nestedRequiredValidations.join('')}${fixedValueValidations.join('')}${(bindingValidations.length > 0 || prohibitedFieldValidations.length > 0 || primitiveFormatValidations.length > 0) ? `\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const _bRes = resource as Record<string, any>;` : ''}${prohibitedFieldValidations.join('')}${bindingValidations.join('')}${primitiveFormatValidations.join('')}${sliceValidations.join('')}${extensionStructuralValidation}${containedRefValidation}${bundleRefValidation}
269
270
  return { errors, warnings };
270
271
  }`,
271
272
  valueSetImports
@@ -31,7 +31,7 @@ export function generateBundleRefValidation(baseResourceType) {
31
31
  const ref = rec.reference as string;
32
32
  if (ref.startsWith('urn:uuid:') || ref.startsWith('urn:oid:')) {
33
33
  if (!_fullUrls.has(ref)) {
34
- errors.push('Bundled or contained reference not found within the bundle/resource ' + ref);
34
+ errors.push('Bundle reference not found: ' + ref);
35
35
  }
36
36
  } else if (/^[A-Za-z]+\\//.test(ref)) {
37
37
  if (!_resIds.has(ref)) {
@@ -40,7 +40,7 @@ export function generateBundleRefValidation(baseResourceType) {
40
40
  if (_fu.endsWith('/' + ref) || _fu.endsWith(ref)) { _found = true; break; }
41
41
  }
42
42
  if (!_found) {
43
- errors.push('Bundled or contained reference not found within the bundle/resource ' + ref);
43
+ errors.push('Bundle reference not found: ' + ref);
44
44
  }
45
45
  }
46
46
  }
@@ -56,6 +56,46 @@ export function generateBundleRefValidation(baseResourceType) {
56
56
  }
57
57
  `;
58
58
  }
59
+ /**
60
+ * Generate standalone contained reference resolution validation code.
61
+ * For non-Bundle resources, verifies that #fragment references resolve to contained[] entries.
62
+ * Bundle validation is handled separately by generateBundleRefValidation.
63
+ */
64
+ export function generateContainedRefValidation(baseResourceType) {
65
+ // Bundle resources have their own reference resolution check; skip them here
66
+ if (baseResourceType === 'Bundle')
67
+ return '';
68
+ return `
69
+ // Standalone contained reference resolution: verify #id references resolve to contained[] entries
70
+ {
71
+ const _res = resource as unknown as Record<string, unknown>;
72
+ const _containedIds = new Set<string>();
73
+ if (Array.isArray(_res.contained)) {
74
+ for (const _c of _res.contained as Array<Record<string, unknown>>) {
75
+ if (_c && typeof _c.id === 'string') _containedIds.add(_c.id);
76
+ }
77
+ }
78
+ const _checkContainedRef = (obj: unknown): void => {
79
+ if (!obj || typeof obj !== 'object') return;
80
+ if (Array.isArray(obj)) { obj.forEach(_checkContainedRef); return; }
81
+ const _rec = obj as Record<string, unknown>;
82
+ if (typeof _rec.reference === 'string') {
83
+ const _ref = _rec.reference as string;
84
+ if (_ref.startsWith('#')) {
85
+ const _id = _ref.substring(1);
86
+ if (_id && !_containedIds.has(_id)) {
87
+ errors.push('Contained reference not found: ' + _ref);
88
+ }
89
+ }
90
+ }
91
+ for (const [_k, _v] of Object.entries(_rec)) {
92
+ if (_k !== 'contained') _checkContainedRef(_v);
93
+ }
94
+ };
95
+ _checkContainedRef(_res);
96
+ }
97
+ `;
98
+ }
59
99
  /**
60
100
  * Generate extension structural validation code.
61
101
  * Checks extension.url required, ext-1 constraint, empty objects.
@@ -1,7 +1,7 @@
1
1
  import path from 'path';
2
2
  import fs from 'fs';
3
3
  import { fileURLToPath } from 'url';
4
- import { extractPackage, readStructureDefinitionsFromDir, createPackageFromDir, readValueSetCodesWithDependencies, readValueSetsFromDir, detectFhirVersion, ensureDependenciesDownloaded } from './parser/packageParser.js';
4
+ import { extractPackage, readStructureDefinitionsFromDir, readStructureDefinitionsFromDependencies, createPackageFromDir, readValueSetCodesWithDependencies, readValueSetsFromDir, detectFhirVersion, ensureDependenciesDownloaded } from './parser/packageParser.js';
5
5
  import { fetchStructureDefinitions, fetchStructureDefinition, registerLocalStructureDefinitions, clearLocalStructureDefinitions, collectValueSetBindingUrls } from './parser/sdParser.js';
6
6
  import { ensureDirectoryExists, downloadFile } from './core/utils.js';
7
7
  import { getFhirPackagesCacheDir } from './core/cacheConfig.js';
@@ -65,6 +65,7 @@ async function compileTypeScriptToJS(dir) {
65
65
  allowSyntheticDefaultImports: true,
66
66
  strict: false,
67
67
  resolveJsonModule: true,
68
+ typeRoots: [path.join(dir, 'node_modules', '@types')],
68
69
  types: ['node']
69
70
  },
70
71
  include: [`${dir}/**/*.ts`],
@@ -235,6 +236,9 @@ export async function generate(fhirSource, outputDir, flags) {
235
236
  structureDefinitions = readStructureDefinitionsFromDir(extracted);
236
237
  // Ensure dependency packages are downloaded before loading ValueSets
237
238
  await ensureDependenciesDownloaded(extracted);
239
+ // Register SDs from dependency packages so external profile resolution can find them
240
+ const depSDs = readStructureDefinitionsFromDependencies(extracted);
241
+ registerLocalStructureDefinitions(depSDs);
238
242
  // Load ValueSets from package AND its dependencies (for binding resolution)
239
243
  valueSetCodesMap = readValueSetCodesWithDependencies(extracted);
240
244
  valueSets = readValueSetsFromDir(extracted);
@@ -326,6 +330,9 @@ export async function generateIntoPackage(packageArchivePath, outArchivePath, fl
326
330
  const { existingStructureDefinitions, profileIdToName, profileUrlToName } = buildProfileRegistries(structureDefinitions, fhirInterfaceNames);
327
331
  // Register all local StructureDefinitions for resolution before HTTP fetches
328
332
  registerLocalStructureDefinitions(structureDefinitions);
333
+ // Register SDs from dependency packages so external profile resolution can find them
334
+ const depSDs = readStructureDefinitionsFromDependencies(extractedRoot);
335
+ registerLocalStructureDefinitions(depSDs);
329
336
  for (const sd of structureDefinitions) {
330
337
  await processStructureDefinition(sd, { outputDir, fhirSourceHint: '', valueSetCodesMap, valueSets, existingStructureDefinitions, profileIdToName, profileUrlToName, flags });
331
338
  }
@@ -390,11 +397,21 @@ export async function generateIntoPackage(packageArchivePath, outArchivePath, fl
390
397
  // Install fhirpath type stub so tsc can resolve validator imports
391
398
  const { installFhirpathStub, removeFhirpathStub } = await import('./emitters/validator/fhirpathStubInstaller.js');
392
399
  installFhirpathStub(outputDir);
400
+ // Install minimal @types/node stub so tsc can resolve `import { createRequire } from 'module'`
401
+ const nodeTypesDir = path.join(outputDir, 'node_modules', '@types', 'node');
402
+ fs.mkdirSync(nodeTypesDir, { recursive: true });
403
+ fs.writeFileSync(path.join(nodeTypesDir, 'index.d.ts'), `declare module 'module' {\n export function createRequire(filename: string | URL): NodeRequire;\n}\n`);
404
+ fs.writeFileSync(path.join(nodeTypesDir, 'package.json'), JSON.stringify({ name: '@types/node', version: '0.0.0-stub', types: 'index.d.ts' }));
393
405
  // Compile TypeScript to JavaScript
394
406
  logger.log('Compiling TypeScript to JavaScript...');
395
407
  await compileTypeScriptToJS(outputDir);
396
408
  // Remove fhirpath stub — the real package is a peer dependency
397
409
  removeFhirpathStub(outputDir);
410
+ // Remove @types/node stub — only needed for compilation
411
+ try {
412
+ fs.rmSync(path.join(outputDir, 'node_modules', '@types'), { recursive: true, force: true });
413
+ }
414
+ catch { /* ignore */ }
398
415
  // Remove base client type stubs — they were only needed for tsc to resolve
399
416
  // @babelfhir-ts/client-<version> imports during compilation. The real package is
400
417
  // installed by the consumer via npm.
@@ -467,6 +484,9 @@ export async function generateForDirectory(inputDir, outputDir, flags) {
467
484
  const valueSets = readValueSetsFromDir(inputDir);
468
485
  // Ensure dependency packages are downloaded before loading ValueSets
469
486
  await ensureDependenciesDownloaded(inputDir);
487
+ // Register SDs from dependency packages so external profile resolution can find them
488
+ const depSDs = readStructureDefinitionsFromDependencies(inputDir);
489
+ registerLocalStructureDefinitions(depSDs);
470
490
  const valueSetCodesMap = readValueSetCodesWithDependencies(inputDir);
471
491
  logger.log(`Loaded ${valueSets.size} ValueSets from ${inputDir} (${Array.from(valueSets.values()).filter(vs => vs.isSmall).length} suitable for union types)`);
472
492
  const entries = fs.readdirSync(inputDir);
@@ -521,6 +521,52 @@ export async function ensureDependenciesDownloaded(extractedRoot) {
521
521
  }
522
522
  await walkDeps(extractedRoot);
523
523
  }
524
+ /**
525
+ * Reads StructureDefinitions from all dependency packages (recursively).
526
+ * Returns SDs from dependencies only — the main package SDs are loaded separately.
527
+ * This allows external profile resolution to find extension SDs from dependency packages
528
+ * (e.g., hl7.fhir.uv.extensions) without HTTP fetching.
529
+ */
530
+ export function readStructureDefinitionsFromDependencies(extractedRoot) {
531
+ const cacheDir = getFhirPackagesCacheDir();
532
+ const visited = new Set();
533
+ const allSDs = [];
534
+ function walkDeps(pkgDir, isRoot) {
535
+ const pkgDirNorm = path.normalize(pkgDir);
536
+ if (visited.has(pkgDirNorm))
537
+ return;
538
+ visited.add(pkgDirNorm);
539
+ // Read SDs from this package (skip the root — those are loaded separately)
540
+ if (!isRoot) {
541
+ const sds = readStructureDefinitionsFromDir(pkgDir);
542
+ allSDs.push(...sds);
543
+ }
544
+ // Find package.json and recurse into dependencies
545
+ const packageJsonPath = path.join(pkgDir, 'package', 'package.json');
546
+ const altPath = path.join(pkgDir, 'package.json');
547
+ const pkgJsonPath = fs.existsSync(packageJsonPath) ? packageJsonPath
548
+ : fs.existsSync(altPath) ? altPath : null;
549
+ if (!pkgJsonPath)
550
+ return;
551
+ try {
552
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
553
+ const deps = pkgJson.dependencies || {};
554
+ for (const [depName, depVersion] of Object.entries(deps)) {
555
+ for (const sep of ['@', '#']) {
556
+ const depDir = path.join(cacheDir, `${depName}${sep}${depVersion}`);
557
+ if (fs.existsSync(depDir)) {
558
+ walkDeps(depDir, false);
559
+ break;
560
+ }
561
+ }
562
+ }
563
+ }
564
+ catch { /* skip */ }
565
+ }
566
+ walkDeps(extractedRoot, true);
567
+ log.info(`Loaded ${allSDs.length} StructureDefinitions from dependency packages`);
568
+ return allSDs;
569
+ }
524
570
  /**
525
571
  * Reads ValueSet codes from a package and all its dependencies (recursively).
526
572
  * Looks for dependency packages in the FHIR package cache directory.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babelfhir-ts",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "BabelFHIR-TS: generate TypeScript interfaces, validators, and helper classes from FHIR R4/R4B StructureDefinitions (profiles) directly inside package archives.",
5
5
  "type": "module",
6
6
  "main": "out/src/main.js",
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "out/src/generator/",
12
+ "out/src/cli/",
12
13
  "out/src/main.js",
13
14
  "out/src/logger.js",
14
15
  "out/fhir-r4.d.ts",