babelfhir-ts 1.2.1 → 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
+ }
@@ -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`],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babelfhir-ts",
3
- "version": "1.2.1",
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",