babelfhir-ts 1.2.1 → 1.2.3
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/out/src/cli/installCommand.js +176 -0
- package/out/src/generator/fhir/corePackageResolver.js +3 -4
- package/out/src/generator/fhir/corePackageResolver.ts +3 -4
- package/out/src/generator/fhir/fallback/r5.json +18377 -0
- package/out/src/generator/index.js +149 -0
- package/out/src/generator/parser/packageParser.js +54 -46
- package/package.json +2 -1
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { generateIntoPackageDirect, 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
|
+
// Keep cache by default — dependency packages are large (hl7.fhir.r4.core ~50 MB)
|
|
98
|
+
// and re-downloading them every run is the single biggest bottleneck.
|
|
99
|
+
// Users can opt in to cache cleanup with --no-cache.
|
|
100
|
+
let generationCleanup;
|
|
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
|
+
resetFetchFailureTracking();
|
|
112
|
+
resetDiagnostics();
|
|
113
|
+
// Generate directly into extracted package — no intermediate archive round-trip
|
|
114
|
+
const { generatedDir, cleanup } = await generateIntoPackageDirect(downloadedPath, generationFlags);
|
|
115
|
+
generationCleanup = cleanup;
|
|
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
|
+
// Verify package.json exists in generated folder
|
|
124
|
+
const pkgJsonPath = path.join(generatedDir, 'package.json');
|
|
125
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
126
|
+
throw new Error(`package.json not found in generated folder: ${generatedDir}`);
|
|
127
|
+
}
|
|
128
|
+
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
|
|
129
|
+
const packageName = pkgJson.name;
|
|
130
|
+
console.log(`Creating package tarball for ${packageName}...`);
|
|
131
|
+
// Ensure ./lib exists for storing the generated tarball
|
|
132
|
+
const libDir = path.join(process.cwd(), 'lib');
|
|
133
|
+
if (!fs.existsSync(libDir)) {
|
|
134
|
+
fs.mkdirSync(libDir, { recursive: true });
|
|
135
|
+
}
|
|
136
|
+
const { create } = await import('tar');
|
|
137
|
+
const tarballName = `${packageName.replace(/[@/]/g, '-')}.tgz`;
|
|
138
|
+
const tarballPath = path.join(libDir, tarballName);
|
|
139
|
+
// npm expects tarballs to have content under a 'package/' root folder
|
|
140
|
+
await create({
|
|
141
|
+
gzip: true,
|
|
142
|
+
file: tarballPath,
|
|
143
|
+
cwd: generatedDir,
|
|
144
|
+
prefix: 'package'
|
|
145
|
+
}, ['.']);
|
|
146
|
+
console.log(`Installing ${packageName}...`);
|
|
147
|
+
await npmInstall(tarballPath);
|
|
148
|
+
// Clean up extracted package tree (but keep the tarball under ./lib)
|
|
149
|
+
generationCleanup();
|
|
150
|
+
generationCleanup = undefined;
|
|
151
|
+
console.log(`✓ Package tarball saved to ./lib: ${path.basename(tarballPath)}`);
|
|
152
|
+
showGenerationWarnings();
|
|
153
|
+
const report = buildQualityReport();
|
|
154
|
+
const summary = formatReportSummary(report);
|
|
155
|
+
if (summary.trim())
|
|
156
|
+
console.log(summary);
|
|
157
|
+
if (generationFlags.noCache) {
|
|
158
|
+
cleanupCache();
|
|
159
|
+
}
|
|
160
|
+
console.log(`\n✓ Package ${packageToInstall} installed and ready to use!`);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
// Clean up extracted package on error
|
|
164
|
+
generationCleanup?.();
|
|
165
|
+
// Clean up temp download directory
|
|
166
|
+
const tempDir = path.join(process.cwd(), '.temp-download');
|
|
167
|
+
if (fs.existsSync(tempDir)) {
|
|
168
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
169
|
+
}
|
|
170
|
+
if (generationFlags.noCache) {
|
|
171
|
+
cleanupCache();
|
|
172
|
+
}
|
|
173
|
+
console.error(`Error: ${error.message}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import fs from 'fs';
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import { getFhirPackagesCacheDir, ensureCacheDir } from '../core/cacheConfig.js';
|
|
16
|
-
import {
|
|
16
|
+
import { downloadFile } from '../core/utils.js';
|
|
17
17
|
import { logger } from '../../logger.js';
|
|
18
18
|
const log = logger.withTag('core-resolver');
|
|
19
19
|
/**
|
|
@@ -58,7 +58,7 @@ export async function ensureCorePackage(corePackageSpec) {
|
|
|
58
58
|
return candidate;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
// Not cached — download from registry
|
|
61
|
+
// Not cached — download from registry (streaming to avoid buffering large packages in RAM)
|
|
62
62
|
ensureCacheDir(configuredCacheDir);
|
|
63
63
|
const packageDir = path.join(configuredCacheDir, dirName);
|
|
64
64
|
let downloaded = false;
|
|
@@ -67,8 +67,7 @@ export async function ensureCorePackage(corePackageSpec) {
|
|
|
67
67
|
const url = `${registry}/${packageName}/${version}`;
|
|
68
68
|
try {
|
|
69
69
|
log.info(`Downloading core package ${corePackageSpec} from ${registry}…`);
|
|
70
|
-
|
|
71
|
-
fs.writeFileSync(tgzPath, Buffer.from(response.data));
|
|
70
|
+
await downloadFile(url, tgzPath);
|
|
72
71
|
downloaded = true;
|
|
73
72
|
break;
|
|
74
73
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import fs from 'fs';
|
|
15
15
|
import path from 'path';
|
|
16
16
|
import { getFhirPackagesCacheDir, ensureCacheDir } from '../core/cacheConfig.js';
|
|
17
|
-
import {
|
|
17
|
+
import { downloadFile } from '../core/utils.js';
|
|
18
18
|
import { logger } from '../../logger.js';
|
|
19
19
|
|
|
20
20
|
const log = logger.withTag('core-resolver');
|
|
@@ -88,7 +88,7 @@ export async function ensureCorePackage(corePackageSpec: string): Promise<string
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
// Not cached — download from registry
|
|
91
|
+
// Not cached — download from registry (streaming to avoid buffering large packages in RAM)
|
|
92
92
|
ensureCacheDir(configuredCacheDir);
|
|
93
93
|
const packageDir = path.join(configuredCacheDir, dirName);
|
|
94
94
|
|
|
@@ -98,8 +98,7 @@ export async function ensureCorePackage(corePackageSpec: string): Promise<string
|
|
|
98
98
|
const url = `${registry}/${packageName}/${version}`;
|
|
99
99
|
try {
|
|
100
100
|
log.info(`Downloading core package ${corePackageSpec} from ${registry}…`);
|
|
101
|
-
|
|
102
|
-
fs.writeFileSync(tgzPath, Buffer.from(response.data));
|
|
101
|
+
await downloadFile(url, tgzPath);
|
|
103
102
|
downloaded = true;
|
|
104
103
|
break;
|
|
105
104
|
} catch (err) {
|