@atomic-ehr/codegen 0.0.1-canary.20251006094042.7f0be72 → 0.0.1-canary.20251007094146.5297616
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 +22 -19
- package/dist/index.d.ts +246 -255
- package/dist/index.js +787 -576
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
|
|
2
|
+
import * as fhirschema from '@atomic-ehr/fhirschema';
|
|
3
|
+
import * as fs from 'fs';
|
|
1
4
|
import { existsSync, mkdirSync } from 'fs';
|
|
2
5
|
import { readdir, stat, unlink, readFile, writeFile, access, mkdir, rm } from 'fs/promises';
|
|
6
|
+
import * as Path2 from 'path';
|
|
3
7
|
import { join, resolve, dirname, relative } from 'path';
|
|
4
|
-
import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
|
|
5
|
-
import * as fhirschema from '@atomic-ehr/fhirschema';
|
|
6
8
|
import pc from 'picocolors';
|
|
7
9
|
|
|
8
10
|
var __defProp = Object.defineProperty;
|
|
@@ -1391,424 +1393,127 @@ var init_IndexBuilder = __esm({
|
|
|
1391
1393
|
};
|
|
1392
1394
|
}
|
|
1393
1395
|
});
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
cacheDir: ".typeschema-cache",
|
|
1402
|
-
maxAge: 24 * 60 * 60 * 1e3,
|
|
1403
|
-
// 24 hours
|
|
1404
|
-
validateCached: true,
|
|
1405
|
-
...config
|
|
1406
|
-
};
|
|
1407
|
-
if (this.config.enablePersistence && this.config.cacheDir) {
|
|
1408
|
-
this.cacheDir = this.config.cacheDir;
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
/**
|
|
1412
|
-
* Store a schema in the cache
|
|
1413
|
-
*/
|
|
1414
|
-
async set(schema) {
|
|
1415
|
-
const key = this.generateKey(schema.identifier);
|
|
1416
|
-
this.cache.set(key, schema);
|
|
1417
|
-
if (this.config.enablePersistence && this.cacheDir) {
|
|
1418
|
-
await this.persistSchema(schema);
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
/**
|
|
1422
|
-
* Retrieve a schema by identifier
|
|
1423
|
-
*/
|
|
1424
|
-
get(identifier) {
|
|
1425
|
-
const key = this.generateKey(identifier);
|
|
1426
|
-
return this.cache.get(key) || null;
|
|
1427
|
-
}
|
|
1428
|
-
/**
|
|
1429
|
-
* Retrieve a schema by URL
|
|
1430
|
-
*/
|
|
1431
|
-
getByUrl(url) {
|
|
1432
|
-
for (const schema of this.cache.values()) {
|
|
1433
|
-
if (schema.identifier.url === url) {
|
|
1434
|
-
return schema;
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
return null;
|
|
1438
|
-
}
|
|
1439
|
-
/**
|
|
1440
|
-
* Check if a schema exists in cache
|
|
1441
|
-
*/
|
|
1442
|
-
has(identifier) {
|
|
1443
|
-
const key = this.generateKey(identifier);
|
|
1444
|
-
return this.cache.has(key);
|
|
1445
|
-
}
|
|
1446
|
-
/**
|
|
1447
|
-
* Check if a schema exists by URL
|
|
1448
|
-
*/
|
|
1449
|
-
hasByUrl(url) {
|
|
1450
|
-
for (const schema of this.cache.values()) {
|
|
1451
|
-
if (schema.identifier.url === url) {
|
|
1452
|
-
return true;
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
return false;
|
|
1456
|
-
}
|
|
1457
|
-
/**
|
|
1458
|
-
* Delete a schema from cache
|
|
1459
|
-
*/
|
|
1460
|
-
delete(identifier) {
|
|
1461
|
-
const key = this.generateKey(identifier);
|
|
1462
|
-
return this.cache.delete(key);
|
|
1463
|
-
}
|
|
1464
|
-
/**
|
|
1465
|
-
* Delete a schema by URL
|
|
1466
|
-
*/
|
|
1467
|
-
deleteByUrl(url) {
|
|
1468
|
-
for (const [key, schema] of this.cache.entries()) {
|
|
1469
|
-
if (schema.identifier.url === url) {
|
|
1470
|
-
return this.cache.delete(key);
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
return false;
|
|
1474
|
-
}
|
|
1475
|
-
/**
|
|
1476
|
-
* Get schemas by package
|
|
1477
|
-
*/
|
|
1478
|
-
getByPackage(packageName) {
|
|
1479
|
-
const results = [];
|
|
1480
|
-
for (const schema of this.cache.values()) {
|
|
1481
|
-
if (schema.identifier.package === packageName) {
|
|
1482
|
-
results.push(schema);
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
return results;
|
|
1486
|
-
}
|
|
1487
|
-
/**
|
|
1488
|
-
* Get schemas by kind
|
|
1489
|
-
*/
|
|
1490
|
-
getByKind(kind) {
|
|
1491
|
-
const results = [];
|
|
1492
|
-
for (const schema of this.cache.values()) {
|
|
1493
|
-
if (schema.identifier.kind === kind) {
|
|
1494
|
-
results.push(schema);
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
return results;
|
|
1498
|
-
}
|
|
1499
|
-
/**
|
|
1500
|
-
* Store multiple schemas
|
|
1501
|
-
*/
|
|
1502
|
-
setMany(schemas) {
|
|
1503
|
-
for (const schema of schemas) {
|
|
1504
|
-
this.set(schema);
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
/**
|
|
1508
|
-
* Clear all cached schemas
|
|
1509
|
-
*/
|
|
1510
|
-
clear() {
|
|
1511
|
-
this.cache.clear();
|
|
1512
|
-
}
|
|
1513
|
-
/**
|
|
1514
|
-
* Generate cache key for identifier
|
|
1515
|
-
*/
|
|
1516
|
-
generateKey(identifier) {
|
|
1517
|
-
return `${identifier.package}:${identifier.version}:${identifier.kind}:${identifier.name}`;
|
|
1396
|
+
|
|
1397
|
+
// src/typeschema/types.ts
|
|
1398
|
+
var packageMetaToFhir = (packageMeta) => `${packageMeta.name}#${packageMeta.version}`;
|
|
1399
|
+
var packageMetaToNpm = (packageMeta) => `${packageMeta.name}@${packageMeta.version}`;
|
|
1400
|
+
var enrichFHIRSchema = (schema, packageMeta) => {
|
|
1401
|
+
if (!packageMeta) {
|
|
1402
|
+
packageMeta = { name: "undefined", version: "undefined" };
|
|
1518
1403
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1404
|
+
return {
|
|
1405
|
+
...schema,
|
|
1406
|
+
package_meta: schema.package_meta || packageMeta,
|
|
1407
|
+
name: schema.name,
|
|
1408
|
+
url: schema.url,
|
|
1409
|
+
base: schema.base
|
|
1410
|
+
};
|
|
1411
|
+
};
|
|
1412
|
+
function isBindingSchema(schema) {
|
|
1413
|
+
return schema.identifier.kind === "binding";
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/typeschema/register.ts
|
|
1417
|
+
var registerFromManager = async (manager, logger) => {
|
|
1418
|
+
const packages = await manager.packages();
|
|
1419
|
+
const flatRawIndex = {};
|
|
1420
|
+
const indexByPackages = [];
|
|
1421
|
+
for (const pkg of packages) {
|
|
1422
|
+
const resources = await manager.search({ package: pkg });
|
|
1423
|
+
const index = {};
|
|
1424
|
+
for (const resource of resources) {
|
|
1425
|
+
const url = resource.url;
|
|
1426
|
+
if (!url) continue;
|
|
1427
|
+
index[url] = resource;
|
|
1428
|
+
flatRawIndex[url] = resource;
|
|
1528
1429
|
}
|
|
1430
|
+
indexByPackages.push({
|
|
1431
|
+
package_meta: pkg,
|
|
1432
|
+
index
|
|
1433
|
+
});
|
|
1529
1434
|
}
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
const
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
const stats = await stat(filePath);
|
|
1543
|
-
if (this.config.maxAge) {
|
|
1544
|
-
const age = Date.now() - stats.mtimeMs;
|
|
1545
|
-
if (age > this.config.maxAge) {
|
|
1546
|
-
await unlink(filePath);
|
|
1547
|
-
continue;
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1435
|
+
const sdIndex = {};
|
|
1436
|
+
const vsIndex = {};
|
|
1437
|
+
const fsIndex = {};
|
|
1438
|
+
const nameToCanonical = {};
|
|
1439
|
+
let [fsSuccess, fsFailed] = [0, 0];
|
|
1440
|
+
for (const resourcesByPackage of indexByPackages) {
|
|
1441
|
+
const packageMeta = resourcesByPackage.package_meta;
|
|
1442
|
+
for (const [surl, resource] of Object.entries(resourcesByPackage.index)) {
|
|
1443
|
+
const url = surl;
|
|
1444
|
+
if (resource.resourceType === "StructureDefinition") {
|
|
1445
|
+
const sd = resource;
|
|
1446
|
+
sdIndex[url] = sd;
|
|
1550
1447
|
try {
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
continue;
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
const key = this.generateKey(metadata.schema.identifier);
|
|
1559
|
-
this.cache.set(key, metadata.schema);
|
|
1448
|
+
const rfs = enrichFHIRSchema(fhirschema.translate(sd), packageMeta);
|
|
1449
|
+
fsIndex[rfs.url] = rfs;
|
|
1450
|
+
nameToCanonical[rfs.name] = rfs.url;
|
|
1451
|
+
fsSuccess++;
|
|
1560
1452
|
} catch (error) {
|
|
1561
|
-
|
|
1453
|
+
logger?.warn(
|
|
1454
|
+
`Failed to convert StructureDefinition ${sd.name || sd.id}: ${error instanceof Error ? error.message : String(error)}`
|
|
1455
|
+
);
|
|
1456
|
+
fsFailed++;
|
|
1562
1457
|
}
|
|
1563
1458
|
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
*/
|
|
1571
|
-
async persistSchema(schema) {
|
|
1572
|
-
if (!this.cacheDir) {
|
|
1573
|
-
return;
|
|
1574
|
-
}
|
|
1575
|
-
if (!existsSync(this.cacheDir)) {
|
|
1576
|
-
mkdirSync(this.cacheDir, { recursive: true });
|
|
1459
|
+
if (resource.resourceType === "ValueSet") {
|
|
1460
|
+
if (!resource.package_meta) {
|
|
1461
|
+
resource.package_meta = packageMeta;
|
|
1462
|
+
}
|
|
1463
|
+
vsIndex[resource.url] = resource;
|
|
1464
|
+
}
|
|
1577
1465
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
timestamp: Date.now(),
|
|
1581
|
-
version: schema.identifier.version
|
|
1582
|
-
};
|
|
1583
|
-
const fileName = `${schema.identifier.package}-${schema.identifier.version}-${schema.identifier.kind}-${schema.identifier.name}.typeschema.json`.replace(
|
|
1584
|
-
/[^a-zA-Z0-9.-]/g,
|
|
1585
|
-
"_"
|
|
1466
|
+
logger?.success(
|
|
1467
|
+
`FHIR Schema conversion for '${packageMetaToFhir(packageMeta)}' completed: ${fsSuccess} successful, ${fsFailed} failed`
|
|
1586
1468
|
);
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1469
|
+
}
|
|
1470
|
+
const complexTypes = {};
|
|
1471
|
+
for (const fs2 of Object.values(fsIndex)) {
|
|
1472
|
+
if (fs2.kind === "complex-type") {
|
|
1473
|
+
complexTypes[fs2.url] = fs2;
|
|
1592
1474
|
}
|
|
1593
1475
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1476
|
+
const resolveFsGenealogy = (canonicalUrl) => {
|
|
1477
|
+
let fs2 = fsIndex[canonicalUrl];
|
|
1478
|
+
if (fs2 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
1479
|
+
const genealogy = [fs2];
|
|
1480
|
+
while (fs2?.base) {
|
|
1481
|
+
fs2 = fsIndex[fs2.base] || fsIndex[nameToCanonical[fs2.base]];
|
|
1482
|
+
genealogy.push(fs2);
|
|
1483
|
+
if (fs2 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
1600
1484
|
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1485
|
+
return genealogy;
|
|
1486
|
+
};
|
|
1487
|
+
return {
|
|
1488
|
+
...manager,
|
|
1489
|
+
appendFs(fs2) {
|
|
1490
|
+
const rfs = enrichFHIRSchema(fs2);
|
|
1491
|
+
fsIndex[rfs.url] = rfs;
|
|
1492
|
+
nameToCanonical[rfs.name] = rfs.url;
|
|
1493
|
+
},
|
|
1494
|
+
resolveFs: (canonicalUrl) => fsIndex[canonicalUrl],
|
|
1495
|
+
resolveFsGenealogy,
|
|
1496
|
+
ensureCanonicalUrl: (name) => nameToCanonical[name] || name,
|
|
1497
|
+
allSd: () => Object.values(sdIndex),
|
|
1498
|
+
resolveSd: (canonicalUrl) => sdIndex[canonicalUrl],
|
|
1499
|
+
allFs: () => Object.values(fsIndex),
|
|
1500
|
+
allVs: () => Object.values(vsIndex),
|
|
1501
|
+
resolveVs: (canonicalUrl) => vsIndex[canonicalUrl],
|
|
1502
|
+
complexTypeDict: () => complexTypes,
|
|
1503
|
+
resolveAny: (canonicalUrl) => flatRawIndex[canonicalUrl]
|
|
1504
|
+
};
|
|
1505
|
+
};
|
|
1506
|
+
var resolveFsElementGenealogy = (genealogy, path) => {
|
|
1507
|
+
const [top, ...rest] = path;
|
|
1508
|
+
if (top === void 0) return [];
|
|
1509
|
+
return genealogy.map((fs2) => {
|
|
1510
|
+
if (!fs2.elements) return void 0;
|
|
1511
|
+
let elem = fs2.elements?.[top];
|
|
1512
|
+
for (const k of rest) {
|
|
1513
|
+
elem = elem?.elements?.[k];
|
|
1609
1514
|
}
|
|
1610
|
-
|
|
1611
|
-
};
|
|
1612
|
-
var CodegenLogger = class _CodegenLogger {
|
|
1613
|
-
options;
|
|
1614
|
-
constructor(options = {}) {
|
|
1615
|
-
this.options = {
|
|
1616
|
-
timestamp: false,
|
|
1617
|
-
verbose: false,
|
|
1618
|
-
...options
|
|
1619
|
-
};
|
|
1620
|
-
}
|
|
1621
|
-
formatMessage(level, message, color) {
|
|
1622
|
-
const timestamp = this.options.timestamp ? `${pc.gray((/* @__PURE__ */ new Date()).toLocaleTimeString())} ` : "";
|
|
1623
|
-
const prefix = this.options.prefix ? `${pc.cyan(`[${this.options.prefix}]`)} ` : "";
|
|
1624
|
-
return `${timestamp}${color(level)} ${prefix}${message}`;
|
|
1625
|
-
}
|
|
1626
|
-
/**
|
|
1627
|
-
* Success message with checkmark
|
|
1628
|
-
*/
|
|
1629
|
-
success(message) {
|
|
1630
|
-
console.log(this.formatMessage("\u2705", message, pc.green));
|
|
1631
|
-
}
|
|
1632
|
-
/**
|
|
1633
|
-
* Error message with X mark
|
|
1634
|
-
*/
|
|
1635
|
-
error(message, error) {
|
|
1636
|
-
console.error(this.formatMessage("\u274C", message, pc.red));
|
|
1637
|
-
if (error && this.options.verbose) {
|
|
1638
|
-
console.error(pc.red(` ${error.message}`));
|
|
1639
|
-
if (error.stack) {
|
|
1640
|
-
console.error(pc.gray(error.stack));
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
/**
|
|
1645
|
-
* Warning message with warning sign
|
|
1646
|
-
*/
|
|
1647
|
-
warn(message) {
|
|
1648
|
-
console.warn(this.formatMessage("\u26A0\uFE0F", message, pc.yellow));
|
|
1649
|
-
}
|
|
1650
|
-
/**
|
|
1651
|
-
* Info message with info icon
|
|
1652
|
-
*/
|
|
1653
|
-
info(message) {
|
|
1654
|
-
console.log(this.formatMessage("\u2139\uFE0F", message, pc.blue));
|
|
1655
|
-
}
|
|
1656
|
-
/**
|
|
1657
|
-
* Debug message (only shows in verbose mode)
|
|
1658
|
-
*/
|
|
1659
|
-
debug(message) {
|
|
1660
|
-
if (this.options.verbose) {
|
|
1661
|
-
console.log(this.formatMessage("\u{1F41B}", message, pc.magenta));
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
/**
|
|
1665
|
-
* Step message with rocket
|
|
1666
|
-
*/
|
|
1667
|
-
step(message) {
|
|
1668
|
-
console.log(this.formatMessage("\u{1F680}", message, pc.cyan));
|
|
1669
|
-
}
|
|
1670
|
-
/**
|
|
1671
|
-
* Progress message with clock
|
|
1672
|
-
*/
|
|
1673
|
-
progress(message) {
|
|
1674
|
-
console.log(this.formatMessage("\u23F3", message, pc.blue));
|
|
1675
|
-
}
|
|
1676
|
-
/**
|
|
1677
|
-
* Plain message (no icon, just colored text)
|
|
1678
|
-
*/
|
|
1679
|
-
plain(message, color = (s) => s) {
|
|
1680
|
-
const timestamp = this.options.timestamp ? `${pc.gray((/* @__PURE__ */ new Date()).toLocaleTimeString())} ` : "";
|
|
1681
|
-
const prefix = this.options.prefix ? `${pc.cyan(`[${this.options.prefix}]`)} ` : "";
|
|
1682
|
-
console.log(`${timestamp}${prefix}${color(message)}`);
|
|
1683
|
-
}
|
|
1684
|
-
/**
|
|
1685
|
-
* Dimmed/gray text for less important info
|
|
1686
|
-
*/
|
|
1687
|
-
dim(message) {
|
|
1688
|
-
this.plain(message, pc.gray);
|
|
1689
|
-
}
|
|
1690
|
-
/**
|
|
1691
|
-
* Create a child logger with a prefix
|
|
1692
|
-
*/
|
|
1693
|
-
child(prefix) {
|
|
1694
|
-
return new _CodegenLogger({
|
|
1695
|
-
...this.options,
|
|
1696
|
-
prefix: this.options.prefix ? `${this.options.prefix}:${prefix}` : prefix
|
|
1697
|
-
});
|
|
1698
|
-
}
|
|
1699
|
-
/**
|
|
1700
|
-
* Update options
|
|
1701
|
-
*/
|
|
1702
|
-
configure(options) {
|
|
1703
|
-
this.options = { ...this.options, ...options };
|
|
1704
|
-
}
|
|
1705
|
-
};
|
|
1706
|
-
new CodegenLogger();
|
|
1707
|
-
function createLogger(options = {}) {
|
|
1708
|
-
return new CodegenLogger(options);
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
// src/typeschema/types.ts
|
|
1712
|
-
var enrichFHIRSchema = (schema, packageMeta) => {
|
|
1713
|
-
if (!packageMeta) {
|
|
1714
|
-
packageMeta = { name: "undefined", version: "undefined" };
|
|
1715
|
-
}
|
|
1716
|
-
return {
|
|
1717
|
-
...schema,
|
|
1718
|
-
package_meta: schema.package_meta || packageMeta,
|
|
1719
|
-
name: schema.name,
|
|
1720
|
-
url: schema.url,
|
|
1721
|
-
base: schema.base
|
|
1722
|
-
};
|
|
1723
|
-
};
|
|
1724
|
-
function isBindingSchema(schema) {
|
|
1725
|
-
return schema.identifier.kind === "binding";
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
// src/typeschema/register.ts
|
|
1729
|
-
var registerFromManager = async (manager, logger, packageInfo) => {
|
|
1730
|
-
const resources = await manager.search({});
|
|
1731
|
-
const any = {};
|
|
1732
|
-
for (const resource of resources) {
|
|
1733
|
-
const url = resource.url;
|
|
1734
|
-
if (!url) continue;
|
|
1735
|
-
any[url] = resource;
|
|
1736
|
-
}
|
|
1737
|
-
const structureDefinitions = {};
|
|
1738
|
-
for (const resource of resources) {
|
|
1739
|
-
if (resource.resourceType === "StructureDefinition") {
|
|
1740
|
-
const url = resource.url;
|
|
1741
|
-
structureDefinitions[url] = resource;
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
const fhirSchemas = {};
|
|
1745
|
-
const nameDict = {};
|
|
1746
|
-
let [success] = [0, 0];
|
|
1747
|
-
for (const sd of Object.values(structureDefinitions)) {
|
|
1748
|
-
try {
|
|
1749
|
-
const rfs = enrichFHIRSchema(fhirschema.translate(sd), packageInfo);
|
|
1750
|
-
fhirSchemas[rfs.url] = rfs;
|
|
1751
|
-
nameDict[rfs.name] = rfs.url;
|
|
1752
|
-
success++;
|
|
1753
|
-
} catch (error) {
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
const valueSets = {};
|
|
1757
|
-
for (const resource of resources) {
|
|
1758
|
-
if (resource.resourceType === "ValueSet") {
|
|
1759
|
-
if (!resource.package_meta) {
|
|
1760
|
-
resource.package_meta = packageInfo;
|
|
1761
|
-
}
|
|
1762
|
-
valueSets[resource.url] = resource;
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
const complexTypes = {};
|
|
1766
|
-
for (const fs of Object.values(fhirSchemas)) {
|
|
1767
|
-
if (fs.kind === "complex-type") {
|
|
1768
|
-
complexTypes[fs.url] = fs;
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
const resolveFsGenealogy = (canonicalUrl) => {
|
|
1772
|
-
let fs = fhirSchemas[canonicalUrl];
|
|
1773
|
-
if (fs === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
1774
|
-
const genealogy = [fs];
|
|
1775
|
-
while (fs?.base) {
|
|
1776
|
-
fs = fhirSchemas[fs.base] || fhirSchemas[nameDict[fs.base]];
|
|
1777
|
-
genealogy.push(fs);
|
|
1778
|
-
if (fs === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
1779
|
-
}
|
|
1780
|
-
return genealogy;
|
|
1781
|
-
};
|
|
1782
|
-
return {
|
|
1783
|
-
...manager,
|
|
1784
|
-
appendFs(fs) {
|
|
1785
|
-
const rfs = enrichFHIRSchema(fs);
|
|
1786
|
-
fhirSchemas[rfs.url] = rfs;
|
|
1787
|
-
nameDict[rfs.name] = rfs.url;
|
|
1788
|
-
},
|
|
1789
|
-
resolveFs: (canonicalUrl) => fhirSchemas[canonicalUrl],
|
|
1790
|
-
resolveFsGenealogy,
|
|
1791
|
-
ensureCanonicalUrl: (name) => nameDict[name] || name,
|
|
1792
|
-
allSd: () => Object.values(structureDefinitions),
|
|
1793
|
-
resolveSd: (canonicalUrl) => structureDefinitions[canonicalUrl],
|
|
1794
|
-
allFs: () => Object.values(fhirSchemas),
|
|
1795
|
-
allVs: () => Object.values(valueSets),
|
|
1796
|
-
resolveVs: (canonicalUrl) => valueSets[canonicalUrl],
|
|
1797
|
-
complexTypeDict: () => complexTypes,
|
|
1798
|
-
resolveAny: (canonicalUrl) => any[canonicalUrl]
|
|
1799
|
-
};
|
|
1800
|
-
};
|
|
1801
|
-
var resolveFsElementGenealogy = (genealogy, path) => {
|
|
1802
|
-
const [top, ...rest] = path;
|
|
1803
|
-
if (top === void 0) return [];
|
|
1804
|
-
return genealogy.map((fs) => {
|
|
1805
|
-
if (!fs.elements) return void 0;
|
|
1806
|
-
let elem = fs.elements?.[top];
|
|
1807
|
-
for (const k of rest) {
|
|
1808
|
-
elem = elem?.elements?.[k];
|
|
1809
|
-
}
|
|
1810
|
-
return elem;
|
|
1811
|
-
}).filter((elem) => elem !== void 0);
|
|
1515
|
+
return elem;
|
|
1516
|
+
}).filter((elem) => elem !== void 0);
|
|
1812
1517
|
};
|
|
1813
1518
|
function fsElementSnapshot(genealogy) {
|
|
1814
1519
|
const snapshot = genealogy.reverse().reduce((snapshot2, elem) => ({ ...snapshot2, ...elem }), {});
|
|
@@ -1872,8 +1577,8 @@ function mkValueSetIdentifierByUrl(register, fullValueSetUrl) {
|
|
|
1872
1577
|
const valueSetName = valueSet?.id && !/^[a-zA-Z0-9_-]{20,}$/.test(valueSet.id) ? valueSet.id : valueSetNameFallback;
|
|
1873
1578
|
return {
|
|
1874
1579
|
kind: "value-set",
|
|
1875
|
-
package: valueSet
|
|
1876
|
-
version: valueSet
|
|
1580
|
+
package: valueSet.package_meta.name,
|
|
1581
|
+
version: valueSet.package_meta.version,
|
|
1877
1582
|
name: valueSetName,
|
|
1878
1583
|
url: valueSetUrl
|
|
1879
1584
|
};
|
|
@@ -2062,10 +1767,10 @@ function extractValidationRules(fhirSchema) {
|
|
|
2062
1767
|
function isRequired(register, fhirSchema, path) {
|
|
2063
1768
|
const fieldName = path[path.length - 1];
|
|
2064
1769
|
const parentPath = path.slice(0, -1);
|
|
2065
|
-
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((
|
|
2066
|
-
if (parentPath.length === 0) return
|
|
2067
|
-
if (!
|
|
2068
|
-
let elem =
|
|
1770
|
+
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs2) => {
|
|
1771
|
+
if (parentPath.length === 0) return fs2.required || [];
|
|
1772
|
+
if (!fs2.elements) return [];
|
|
1773
|
+
let elem = fs2;
|
|
2069
1774
|
for (const k of parentPath) {
|
|
2070
1775
|
elem = elem?.elements?.[k];
|
|
2071
1776
|
}
|
|
@@ -2077,10 +1782,10 @@ function isExcluded(register, fhirSchema, path) {
|
|
|
2077
1782
|
const fieldName = path[path.length - 1];
|
|
2078
1783
|
if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
|
|
2079
1784
|
const parentPath = path.slice(0, -1);
|
|
2080
|
-
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((
|
|
2081
|
-
if (parentPath.length === 0) return
|
|
2082
|
-
if (!
|
|
2083
|
-
let elem =
|
|
1785
|
+
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs2) => {
|
|
1786
|
+
if (parentPath.length === 0) return fs2.excluded || [];
|
|
1787
|
+
if (!fs2.elements) return [];
|
|
1788
|
+
let elem = fs2;
|
|
2084
1789
|
for (const k of parentPath) {
|
|
2085
1790
|
elem = elem?.elements?.[k];
|
|
2086
1791
|
}
|
|
@@ -2092,8 +1797,8 @@ var buildReferences = (element, register, _packageInfo) => {
|
|
|
2092
1797
|
if (!element.refers) return void 0;
|
|
2093
1798
|
return element.refers.map((ref) => {
|
|
2094
1799
|
const curl = register.ensureCanonicalUrl(ref);
|
|
2095
|
-
const
|
|
2096
|
-
return mkIdentifier(
|
|
1800
|
+
const fs2 = register.resolveFs(curl);
|
|
1801
|
+
return mkIdentifier(fs2);
|
|
2097
1802
|
});
|
|
2098
1803
|
};
|
|
2099
1804
|
function buildFieldType(register, fhirSchema, element) {
|
|
@@ -2216,7 +1921,7 @@ function buildEnum(register, element) {
|
|
|
2216
1921
|
const codes = concepts.map((c) => c.code).filter((code) => code && typeof code === "string" && code.trim().length > 0);
|
|
2217
1922
|
if (codes.length > MAX_ENUM_LENGTH) {
|
|
2218
1923
|
console.warn(
|
|
2219
|
-
`Value set ${valueSetUrl} has more than ${MAX_ENUM_LENGTH} codes, which may cause issues with code generation.`
|
|
1924
|
+
`Value set ${valueSetUrl} has ${codes.length} which is more than ${MAX_ENUM_LENGTH} codes, which may cause issues with code generation.`
|
|
2220
1925
|
);
|
|
2221
1926
|
return void 0;
|
|
2222
1927
|
}
|
|
@@ -2483,75 +2188,391 @@ async function transformExtension(fhirSchema, register, _packageInfo) {
|
|
|
2483
2188
|
extensionSchema.dependencies.push(...extractFieldDependencies(fields));
|
|
2484
2189
|
}
|
|
2485
2190
|
}
|
|
2486
|
-
const nestedTypes = mkNestedTypes(register, fhirSchema);
|
|
2487
|
-
if (nestedTypes && nestedTypes.length > 0) {
|
|
2488
|
-
extensionSchema.nested = nestedTypes;
|
|
2489
|
-
extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
|
|
2490
|
-
}
|
|
2491
|
-
extensionSchema.dependencies = deduplicateDependencies(extensionSchema.dependencies);
|
|
2492
|
-
extensionSchema.dependencies = extensionSchema.dependencies.filter((dep) => dep.url !== identifier.url);
|
|
2493
|
-
return extensionSchema;
|
|
2494
|
-
} catch (error) {
|
|
2495
|
-
console.warn(`Failed to transform extension ${fhirSchema.name}: ${error}`);
|
|
2496
|
-
return null;
|
|
2191
|
+
const nestedTypes = mkNestedTypes(register, fhirSchema);
|
|
2192
|
+
if (nestedTypes && nestedTypes.length > 0) {
|
|
2193
|
+
extensionSchema.nested = nestedTypes;
|
|
2194
|
+
extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
|
|
2195
|
+
}
|
|
2196
|
+
extensionSchema.dependencies = deduplicateDependencies(extensionSchema.dependencies);
|
|
2197
|
+
extensionSchema.dependencies = extensionSchema.dependencies.filter((dep) => dep.url !== identifier.url);
|
|
2198
|
+
return extensionSchema;
|
|
2199
|
+
} catch (error) {
|
|
2200
|
+
console.warn(`Failed to transform extension ${fhirSchema.name}: ${error}`);
|
|
2201
|
+
return null;
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
function extractDependencies(identifier, base, fields, nestedTypes) {
|
|
2205
|
+
const deps = [];
|
|
2206
|
+
if (base) deps.push(base);
|
|
2207
|
+
if (fields) deps.push(...extractFieldDependencies(fields));
|
|
2208
|
+
if (nestedTypes) deps.push(...extractNestedDependencies(nestedTypes));
|
|
2209
|
+
const uniqDeps = {};
|
|
2210
|
+
for (const dep of deps) {
|
|
2211
|
+
if (dep.url === identifier.url) continue;
|
|
2212
|
+
uniqDeps[dep.url] = dep;
|
|
2213
|
+
}
|
|
2214
|
+
const localNestedTypeUrls = new Set(nestedTypes?.map((nt) => nt.identifier.url));
|
|
2215
|
+
const result = Object.values(uniqDeps).filter((e) => !(e.kind === "nested" && localNestedTypeUrls.has(e.url))).sort((a, b) => a.url.localeCompare(b.url));
|
|
2216
|
+
return result.length > 0 ? result : void 0;
|
|
2217
|
+
}
|
|
2218
|
+
function transformFhirSchemaResource(register, fhirSchema) {
|
|
2219
|
+
const identifier = mkIdentifier(fhirSchema);
|
|
2220
|
+
let base;
|
|
2221
|
+
if (fhirSchema.base && fhirSchema.type !== "Element") {
|
|
2222
|
+
const baseFs = register.resolveFs(register.ensureCanonicalUrl(fhirSchema.base));
|
|
2223
|
+
if (!baseFs) {
|
|
2224
|
+
throw new Error(`Base resource not found '${fhirSchema.base}' for '${fhirSchema.url}'`);
|
|
2225
|
+
}
|
|
2226
|
+
base = mkIdentifier(baseFs);
|
|
2227
|
+
}
|
|
2228
|
+
const fields = mkFields(register, fhirSchema, [], fhirSchema.elements);
|
|
2229
|
+
const nested = mkNestedTypes(register, fhirSchema);
|
|
2230
|
+
const dependencies = extractDependencies(identifier, base, fields, nested);
|
|
2231
|
+
const typeSchema = {
|
|
2232
|
+
identifier,
|
|
2233
|
+
base,
|
|
2234
|
+
fields,
|
|
2235
|
+
nested,
|
|
2236
|
+
description: fhirSchema.description,
|
|
2237
|
+
dependencies
|
|
2238
|
+
};
|
|
2239
|
+
const bindingSchemas = collectBindingSchemas(register, fhirSchema);
|
|
2240
|
+
return [typeSchema, ...bindingSchemas];
|
|
2241
|
+
}
|
|
2242
|
+
async function transformFhirSchema(register, fhirSchema) {
|
|
2243
|
+
const results = [];
|
|
2244
|
+
const identifier = mkIdentifier(fhirSchema);
|
|
2245
|
+
if (identifier.kind === "profile") {
|
|
2246
|
+
const profileSchema = await transformProfile(register, fhirSchema);
|
|
2247
|
+
results.push(profileSchema);
|
|
2248
|
+
const bindingSchemas = collectBindingSchemas(register, fhirSchema);
|
|
2249
|
+
results.push(...bindingSchemas);
|
|
2250
|
+
return results;
|
|
2251
|
+
}
|
|
2252
|
+
if (isExtensionSchema(fhirSchema)) {
|
|
2253
|
+
const extensionSchema = await transformExtension(fhirSchema, register, fhirSchema.package_meta);
|
|
2254
|
+
if (extensionSchema) {
|
|
2255
|
+
results.push(extensionSchema);
|
|
2256
|
+
}
|
|
2257
|
+
return results;
|
|
2258
|
+
}
|
|
2259
|
+
return transformFhirSchemaResource(register, fhirSchema);
|
|
2260
|
+
}
|
|
2261
|
+
var TypeSchemaCache = class {
|
|
2262
|
+
cache = /* @__PURE__ */ new Map();
|
|
2263
|
+
config;
|
|
2264
|
+
cacheDir;
|
|
2265
|
+
constructor(config) {
|
|
2266
|
+
this.config = {
|
|
2267
|
+
enablePersistence: true,
|
|
2268
|
+
cacheDir: ".typeschema-cache",
|
|
2269
|
+
maxAge: 24 * 60 * 60 * 1e3,
|
|
2270
|
+
// 24 hours
|
|
2271
|
+
validateCached: true,
|
|
2272
|
+
...config
|
|
2273
|
+
};
|
|
2274
|
+
if (this.config.enablePersistence && this.config.cacheDir) {
|
|
2275
|
+
this.cacheDir = this.config.cacheDir;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
/**
|
|
2279
|
+
* Store a schema in the cache
|
|
2280
|
+
*/
|
|
2281
|
+
async set(schema) {
|
|
2282
|
+
const key = this.generateKey(schema.identifier);
|
|
2283
|
+
this.cache.set(key, schema);
|
|
2284
|
+
if (this.config.enablePersistence && this.cacheDir) {
|
|
2285
|
+
await this.persistSchema(schema);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Retrieve a schema by identifier
|
|
2290
|
+
*/
|
|
2291
|
+
get(identifier) {
|
|
2292
|
+
const key = this.generateKey(identifier);
|
|
2293
|
+
return this.cache.get(key) || null;
|
|
2294
|
+
}
|
|
2295
|
+
/**
|
|
2296
|
+
* Retrieve a schema by URL
|
|
2297
|
+
*/
|
|
2298
|
+
getByUrl(url) {
|
|
2299
|
+
for (const schema of this.cache.values()) {
|
|
2300
|
+
if (schema.identifier.url === url) {
|
|
2301
|
+
return schema;
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
return null;
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2307
|
+
* Check if a schema exists in cache
|
|
2308
|
+
*/
|
|
2309
|
+
has(identifier) {
|
|
2310
|
+
const key = this.generateKey(identifier);
|
|
2311
|
+
return this.cache.has(key);
|
|
2312
|
+
}
|
|
2313
|
+
/**
|
|
2314
|
+
* Check if a schema exists by URL
|
|
2315
|
+
*/
|
|
2316
|
+
hasByUrl(url) {
|
|
2317
|
+
for (const schema of this.cache.values()) {
|
|
2318
|
+
if (schema.identifier.url === url) {
|
|
2319
|
+
return true;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
return false;
|
|
2323
|
+
}
|
|
2324
|
+
/**
|
|
2325
|
+
* Delete a schema from cache
|
|
2326
|
+
*/
|
|
2327
|
+
delete(identifier) {
|
|
2328
|
+
const key = this.generateKey(identifier);
|
|
2329
|
+
return this.cache.delete(key);
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Delete a schema by URL
|
|
2333
|
+
*/
|
|
2334
|
+
deleteByUrl(url) {
|
|
2335
|
+
for (const [key, schema] of this.cache.entries()) {
|
|
2336
|
+
if (schema.identifier.url === url) {
|
|
2337
|
+
return this.cache.delete(key);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
return false;
|
|
2341
|
+
}
|
|
2342
|
+
/**
|
|
2343
|
+
* Get schemas by package
|
|
2344
|
+
*/
|
|
2345
|
+
getByPackage(packageName) {
|
|
2346
|
+
const results = [];
|
|
2347
|
+
for (const schema of this.cache.values()) {
|
|
2348
|
+
if (schema.identifier.package === packageName) {
|
|
2349
|
+
results.push(schema);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
return results;
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Get schemas by kind
|
|
2356
|
+
*/
|
|
2357
|
+
getByKind(kind) {
|
|
2358
|
+
const results = [];
|
|
2359
|
+
for (const schema of this.cache.values()) {
|
|
2360
|
+
if (schema.identifier.kind === kind) {
|
|
2361
|
+
results.push(schema);
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
return results;
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* Store multiple schemas
|
|
2368
|
+
*/
|
|
2369
|
+
setMany(schemas) {
|
|
2370
|
+
for (const schema of schemas) {
|
|
2371
|
+
this.set(schema);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
/**
|
|
2375
|
+
* Clear all cached schemas
|
|
2376
|
+
*/
|
|
2377
|
+
clear() {
|
|
2378
|
+
this.cache.clear();
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Generate cache key for identifier
|
|
2382
|
+
*/
|
|
2383
|
+
generateKey(identifier) {
|
|
2384
|
+
return `${identifier.package}:${identifier.version}:${identifier.kind}:${identifier.name}`;
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2387
|
+
* Initialize cache directory if persistence is enabled
|
|
2388
|
+
*/
|
|
2389
|
+
async initialize() {
|
|
2390
|
+
if (this.config.enablePersistence && this.cacheDir) {
|
|
2391
|
+
if (!existsSync(this.cacheDir)) {
|
|
2392
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
2393
|
+
}
|
|
2394
|
+
await this.loadFromDisk();
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Load all cached schemas from disk
|
|
2399
|
+
*/
|
|
2400
|
+
async loadFromDisk() {
|
|
2401
|
+
if (!this.cacheDir || !existsSync(this.cacheDir)) {
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
try {
|
|
2405
|
+
const files = await readdir(this.cacheDir);
|
|
2406
|
+
const schemaFiles = files.filter((f) => f.endsWith(".typeschema.json"));
|
|
2407
|
+
for (const file of schemaFiles) {
|
|
2408
|
+
const filePath = join(this.cacheDir, file);
|
|
2409
|
+
const stats = await stat(filePath);
|
|
2410
|
+
if (this.config.maxAge) {
|
|
2411
|
+
const age = Date.now() - stats.mtimeMs;
|
|
2412
|
+
if (age > this.config.maxAge) {
|
|
2413
|
+
await unlink(filePath);
|
|
2414
|
+
continue;
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
try {
|
|
2418
|
+
const content = await readFile(filePath, "utf-8");
|
|
2419
|
+
const metadata = JSON.parse(content);
|
|
2420
|
+
if (this.config.validateCached) {
|
|
2421
|
+
if (!metadata.schema?.identifier) {
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
const key = this.generateKey(metadata.schema.identifier);
|
|
2426
|
+
this.cache.set(key, metadata.schema);
|
|
2427
|
+
} catch (error) {
|
|
2428
|
+
console.warn(`Failed to load cached schema from ${file}:`, error);
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
} catch (error) {
|
|
2432
|
+
console.warn("Failed to load cached schemas from disk:", error);
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
/**
|
|
2436
|
+
* Persist a schema to disk
|
|
2437
|
+
*/
|
|
2438
|
+
async persistSchema(schema) {
|
|
2439
|
+
if (!this.cacheDir) {
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
if (!existsSync(this.cacheDir)) {
|
|
2443
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
2444
|
+
}
|
|
2445
|
+
const metadata = {
|
|
2446
|
+
schema,
|
|
2447
|
+
timestamp: Date.now(),
|
|
2448
|
+
version: schema.identifier.version
|
|
2449
|
+
};
|
|
2450
|
+
const fileName = `${schema.identifier.package}-${schema.identifier.version}-${schema.identifier.kind}-${schema.identifier.name}.typeschema.json`.replace(
|
|
2451
|
+
/[^a-zA-Z0-9.-]/g,
|
|
2452
|
+
"_"
|
|
2453
|
+
);
|
|
2454
|
+
const filePath = join(this.cacheDir, fileName);
|
|
2455
|
+
try {
|
|
2456
|
+
await writeFile(filePath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
2457
|
+
} catch (error) {
|
|
2458
|
+
console.warn(`Failed to persist schema to ${filePath}:`, error);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
/**
|
|
2462
|
+
* Clear cache directory
|
|
2463
|
+
*/
|
|
2464
|
+
async clearDisk() {
|
|
2465
|
+
if (!this.cacheDir || !existsSync(this.cacheDir)) {
|
|
2466
|
+
return;
|
|
2467
|
+
}
|
|
2468
|
+
try {
|
|
2469
|
+
const files = await readdir(this.cacheDir);
|
|
2470
|
+
const schemaFiles = files.filter((f) => f.endsWith(".typeschema.json"));
|
|
2471
|
+
for (const file of schemaFiles) {
|
|
2472
|
+
await unlink(join(this.cacheDir, file));
|
|
2473
|
+
}
|
|
2474
|
+
} catch (error) {
|
|
2475
|
+
console.warn("Failed to clear cache directory:", error);
|
|
2476
|
+
}
|
|
2497
2477
|
}
|
|
2498
|
-
}
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
uniqDeps[dep.url] = dep;
|
|
2478
|
+
};
|
|
2479
|
+
var CodegenLogger = class _CodegenLogger {
|
|
2480
|
+
options;
|
|
2481
|
+
constructor(options = {}) {
|
|
2482
|
+
this.options = {
|
|
2483
|
+
timestamp: false,
|
|
2484
|
+
verbose: false,
|
|
2485
|
+
...options
|
|
2486
|
+
};
|
|
2508
2487
|
}
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
}
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2488
|
+
formatMessage(level, message, color) {
|
|
2489
|
+
const timestamp = this.options.timestamp ? `${pc.gray((/* @__PURE__ */ new Date()).toLocaleTimeString())} ` : "";
|
|
2490
|
+
const prefix = this.options.prefix ? `${pc.cyan(`[${this.options.prefix}]`)} ` : "";
|
|
2491
|
+
return `${timestamp}${color(level)} ${prefix}${message}`;
|
|
2492
|
+
}
|
|
2493
|
+
/**
|
|
2494
|
+
* Success message with checkmark
|
|
2495
|
+
*/
|
|
2496
|
+
success(message) {
|
|
2497
|
+
console.log(this.formatMessage("\u2705", message, pc.green));
|
|
2498
|
+
}
|
|
2499
|
+
/**
|
|
2500
|
+
* Error message with X mark
|
|
2501
|
+
*/
|
|
2502
|
+
error(message, error) {
|
|
2503
|
+
console.error(this.formatMessage("\u274C", message, pc.red));
|
|
2504
|
+
if (error && this.options.verbose) {
|
|
2505
|
+
console.error(pc.red(` ${error.message}`));
|
|
2506
|
+
if (error.stack) {
|
|
2507
|
+
console.error(pc.gray(error.stack));
|
|
2508
|
+
}
|
|
2520
2509
|
}
|
|
2521
|
-
base = mkIdentifier(baseFs);
|
|
2522
2510
|
}
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
base,
|
|
2529
|
-
fields,
|
|
2530
|
-
nested,
|
|
2531
|
-
description: fhirSchema.description,
|
|
2532
|
-
dependencies
|
|
2533
|
-
};
|
|
2534
|
-
const bindingSchemas = collectBindingSchemas(register, fhirSchema);
|
|
2535
|
-
return [typeSchema, ...bindingSchemas];
|
|
2536
|
-
}
|
|
2537
|
-
async function transformFhirSchema(register, fhirSchema) {
|
|
2538
|
-
const results = [];
|
|
2539
|
-
const identifier = mkIdentifier(fhirSchema);
|
|
2540
|
-
if (identifier.kind === "profile") {
|
|
2541
|
-
const profileSchema = await transformProfile(register, fhirSchema);
|
|
2542
|
-
results.push(profileSchema);
|
|
2543
|
-
const bindingSchemas = collectBindingSchemas(register, fhirSchema);
|
|
2544
|
-
results.push(...bindingSchemas);
|
|
2545
|
-
return results;
|
|
2511
|
+
/**
|
|
2512
|
+
* Warning message with warning sign
|
|
2513
|
+
*/
|
|
2514
|
+
warn(message) {
|
|
2515
|
+
console.warn(this.formatMessage("\u26A0\uFE0F", message, pc.yellow));
|
|
2546
2516
|
}
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2517
|
+
/**
|
|
2518
|
+
* Info message with info icon
|
|
2519
|
+
*/
|
|
2520
|
+
info(message) {
|
|
2521
|
+
console.log(this.formatMessage("\u2139\uFE0F", message, pc.blue));
|
|
2522
|
+
}
|
|
2523
|
+
/**
|
|
2524
|
+
* Debug message (only shows in verbose mode)
|
|
2525
|
+
*/
|
|
2526
|
+
debug(message) {
|
|
2527
|
+
if (this.options.verbose) {
|
|
2528
|
+
console.log(this.formatMessage("\u{1F41B}", message, pc.magenta));
|
|
2551
2529
|
}
|
|
2552
|
-
return results;
|
|
2553
2530
|
}
|
|
2554
|
-
|
|
2531
|
+
/**
|
|
2532
|
+
* Step message with rocket
|
|
2533
|
+
*/
|
|
2534
|
+
step(message) {
|
|
2535
|
+
console.log(this.formatMessage("\u{1F680}", message, pc.cyan));
|
|
2536
|
+
}
|
|
2537
|
+
/**
|
|
2538
|
+
* Progress message with clock
|
|
2539
|
+
*/
|
|
2540
|
+
progress(message) {
|
|
2541
|
+
console.log(this.formatMessage("\u23F3", message, pc.blue));
|
|
2542
|
+
}
|
|
2543
|
+
/**
|
|
2544
|
+
* Plain message (no icon, just colored text)
|
|
2545
|
+
*/
|
|
2546
|
+
plain(message, color = (s) => s) {
|
|
2547
|
+
const timestamp = this.options.timestamp ? `${pc.gray((/* @__PURE__ */ new Date()).toLocaleTimeString())} ` : "";
|
|
2548
|
+
const prefix = this.options.prefix ? `${pc.cyan(`[${this.options.prefix}]`)} ` : "";
|
|
2549
|
+
console.log(`${timestamp}${prefix}${color(message)}`);
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Dimmed/gray text for less important info
|
|
2553
|
+
*/
|
|
2554
|
+
dim(message) {
|
|
2555
|
+
this.plain(message, pc.gray);
|
|
2556
|
+
}
|
|
2557
|
+
/**
|
|
2558
|
+
* Create a child logger with a prefix
|
|
2559
|
+
*/
|
|
2560
|
+
child(prefix) {
|
|
2561
|
+
return new _CodegenLogger({
|
|
2562
|
+
...this.options,
|
|
2563
|
+
prefix: this.options.prefix ? `${this.options.prefix}:${prefix}` : prefix
|
|
2564
|
+
});
|
|
2565
|
+
}
|
|
2566
|
+
/**
|
|
2567
|
+
* Update options
|
|
2568
|
+
*/
|
|
2569
|
+
configure(options) {
|
|
2570
|
+
this.options = { ...this.options, ...options };
|
|
2571
|
+
}
|
|
2572
|
+
};
|
|
2573
|
+
new CodegenLogger();
|
|
2574
|
+
function createLogger(options = {}) {
|
|
2575
|
+
return new CodegenLogger(options);
|
|
2555
2576
|
}
|
|
2556
2577
|
|
|
2557
2578
|
// src/typeschema/generator.ts
|
|
@@ -2606,10 +2627,11 @@ var TypeSchemaGenerator = class {
|
|
|
2606
2627
|
);
|
|
2607
2628
|
return fhirSchemas;
|
|
2608
2629
|
}
|
|
2609
|
-
async generateValueSetSchemas(valueSets
|
|
2630
|
+
async generateValueSetSchemas(valueSets) {
|
|
2610
2631
|
if (valueSets.length > 0) {
|
|
2611
2632
|
this.logger.debug(`${valueSets.length} ValueSets available for enum extraction`);
|
|
2612
2633
|
}
|
|
2634
|
+
const register = await registerFromManager(this.manager);
|
|
2613
2635
|
const valueSetSchemas = [];
|
|
2614
2636
|
if (valueSets.length > 0) {
|
|
2615
2637
|
this.logger.progress(`Converting ${valueSets.length} ValueSets to TypeSchema`);
|
|
@@ -2617,7 +2639,7 @@ var TypeSchemaGenerator = class {
|
|
|
2617
2639
|
let valueSetFailedCount = 0;
|
|
2618
2640
|
for (const vs of valueSets) {
|
|
2619
2641
|
try {
|
|
2620
|
-
const valueSetSchema = await transformValueSet(
|
|
2642
|
+
const valueSetSchema = await transformValueSet(register, vs);
|
|
2621
2643
|
if (valueSetSchema) {
|
|
2622
2644
|
valueSetSchemas.push(valueSetSchema);
|
|
2623
2645
|
valueSetConvertedCount++;
|
|
@@ -2652,10 +2674,10 @@ var TypeSchemaGenerator = class {
|
|
|
2652
2674
|
version: packageVersion || "latest"
|
|
2653
2675
|
};
|
|
2654
2676
|
const register = await this.registerFromPackageMetas([packageInfo]);
|
|
2655
|
-
const
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2677
|
+
const valueSets = await this.generateValueSetSchemas(register.allVs());
|
|
2678
|
+
const fhirSchemas = (await Promise.all(register.allFs().map(async (fs2) => await transformFhirSchema(register, fs2)))).flat();
|
|
2679
|
+
const allSchemas = [...fhirSchemas, ...valueSets];
|
|
2680
|
+
console.debug(111);
|
|
2659
2681
|
if (this.cache) {
|
|
2660
2682
|
for (const schema of allSchemas) {
|
|
2661
2683
|
await this.cache.set(schema);
|
|
@@ -3022,6 +3044,18 @@ var TypeSchemaParser = class {
|
|
|
3022
3044
|
}
|
|
3023
3045
|
};
|
|
3024
3046
|
|
|
3047
|
+
// src/typeschema/index.ts
|
|
3048
|
+
var generateTypeSchemas = async (register) => {
|
|
3049
|
+
const fhirSchemas = [];
|
|
3050
|
+
for (const fhirSchema of register.allFs()) {
|
|
3051
|
+
fhirSchemas.push(...await transformFhirSchema(register, fhirSchema));
|
|
3052
|
+
}
|
|
3053
|
+
for (const vsSchema of register.allVs()) {
|
|
3054
|
+
fhirSchemas.push(await transformValueSet(register, vsSchema));
|
|
3055
|
+
}
|
|
3056
|
+
return fhirSchemas;
|
|
3057
|
+
};
|
|
3058
|
+
|
|
3025
3059
|
// src/api/generators/base/error-handler.ts
|
|
3026
3060
|
init_errors();
|
|
3027
3061
|
var ErrorHandler = class {
|
|
@@ -5046,26 +5080,249 @@ ${nestedInterfaces}`;
|
|
|
5046
5080
|
}
|
|
5047
5081
|
};
|
|
5048
5082
|
|
|
5083
|
+
// src/api/writer-generator/utils.ts
|
|
5084
|
+
var words = (s) => {
|
|
5085
|
+
return s.split(/(?<=[a-z])(?=[A-Z])|[-_.\s]/).filter(Boolean);
|
|
5086
|
+
};
|
|
5087
|
+
var kebabCase = (s) => {
|
|
5088
|
+
return words(s).map((s2) => s2.toLowerCase()).join("-");
|
|
5089
|
+
};
|
|
5090
|
+
var capitalCase = (s) => {
|
|
5091
|
+
if (s.length === 0) throw new Error("Empty string");
|
|
5092
|
+
return s[0]?.toUpperCase() + s.substring(1).toLowerCase();
|
|
5093
|
+
};
|
|
5094
|
+
var pascalCase = (s) => {
|
|
5095
|
+
return words(s).map(capitalCase).join("");
|
|
5096
|
+
};
|
|
5097
|
+
var FileSystemWriter = class {
|
|
5098
|
+
opts;
|
|
5099
|
+
currentDir;
|
|
5100
|
+
currentFileDescriptor;
|
|
5101
|
+
writtenFilesSet = /* @__PURE__ */ new Set();
|
|
5102
|
+
constructor(opts) {
|
|
5103
|
+
this.opts = opts;
|
|
5104
|
+
this.currentDir = opts.outputDir;
|
|
5105
|
+
}
|
|
5106
|
+
logger() {
|
|
5107
|
+
return this.opts.logger;
|
|
5108
|
+
}
|
|
5109
|
+
cd(path, gen) {
|
|
5110
|
+
this.currentDir = path.startsWith("/") ? Path2.join(this.opts.outputDir, path) : Path2.join(this.currentDir, path);
|
|
5111
|
+
if (!fs.existsSync(this.currentDir)) {
|
|
5112
|
+
fs.mkdirSync(this.currentDir, { recursive: true });
|
|
5113
|
+
}
|
|
5114
|
+
this.logger()?.debug(`cd '${this.currentDir}'`);
|
|
5115
|
+
gen();
|
|
5116
|
+
}
|
|
5117
|
+
cat(fn, gen) {
|
|
5118
|
+
if (this.currentFileDescriptor) throw new Error("Can't open file in file");
|
|
5119
|
+
if (fn.includes("/")) throw new Error(`Change file path separatly: ${fn}`);
|
|
5120
|
+
const fullFn = `${this.currentDir}/${fn}`;
|
|
5121
|
+
try {
|
|
5122
|
+
this.currentFileDescriptor = fs.openSync(fn, "w");
|
|
5123
|
+
this.writtenFilesSet.add(fn);
|
|
5124
|
+
this.logger()?.debug(`cat > '${fullFn}'`);
|
|
5125
|
+
gen();
|
|
5126
|
+
} finally {
|
|
5127
|
+
if (this.currentFileDescriptor) {
|
|
5128
|
+
fs.closeSync(this.currentFileDescriptor);
|
|
5129
|
+
}
|
|
5130
|
+
this.currentFileDescriptor = void 0;
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
write(str) {
|
|
5134
|
+
if (!this.currentFileDescriptor) throw new Error("No file opened");
|
|
5135
|
+
fs.writeSync(this.currentFileDescriptor, str);
|
|
5136
|
+
}
|
|
5137
|
+
generate(_schemas) {
|
|
5138
|
+
throw new Error("Not implemented");
|
|
5139
|
+
}
|
|
5140
|
+
writtenFiles() {
|
|
5141
|
+
return Array.from(this.writtenFilesSet);
|
|
5142
|
+
}
|
|
5143
|
+
};
|
|
5144
|
+
var Writer = class extends FileSystemWriter {
|
|
5145
|
+
currentIndent = 0;
|
|
5146
|
+
indent() {
|
|
5147
|
+
this.currentIndent += this.opts.tabSize;
|
|
5148
|
+
}
|
|
5149
|
+
deindent() {
|
|
5150
|
+
this.currentIndent -= this.opts.tabSize;
|
|
5151
|
+
}
|
|
5152
|
+
writeIndent() {
|
|
5153
|
+
this.write(" ".repeat(this.currentIndent));
|
|
5154
|
+
}
|
|
5155
|
+
line(...tokens) {
|
|
5156
|
+
this.writeIndent();
|
|
5157
|
+
this.write(`${tokens.join(" ")}
|
|
5158
|
+
`);
|
|
5159
|
+
}
|
|
5160
|
+
lineSM(...tokens) {
|
|
5161
|
+
this.writeIndent();
|
|
5162
|
+
this.write(`${tokens.join(" ")};
|
|
5163
|
+
`);
|
|
5164
|
+
}
|
|
5165
|
+
comment(...tokens) {
|
|
5166
|
+
const lines = tokens.join(" ").split("\n");
|
|
5167
|
+
for (const line of lines) {
|
|
5168
|
+
this.line(this.opts.commentLinePrefix, line);
|
|
5169
|
+
}
|
|
5170
|
+
}
|
|
5171
|
+
debugComment(...tokens) {
|
|
5172
|
+
if (this.opts.withDebugComment) {
|
|
5173
|
+
tokens = tokens.map((token) => {
|
|
5174
|
+
if (typeof token === "string") {
|
|
5175
|
+
return token;
|
|
5176
|
+
} else {
|
|
5177
|
+
return JSON.stringify(token, null, 2);
|
|
5178
|
+
}
|
|
5179
|
+
});
|
|
5180
|
+
this.comment(...tokens);
|
|
5181
|
+
}
|
|
5182
|
+
}
|
|
5183
|
+
curlyBlock(tokens, gencontent, endTokens) {
|
|
5184
|
+
this.line(`${tokens.filter(Boolean).join(" ")} {`);
|
|
5185
|
+
this.indent();
|
|
5186
|
+
gencontent();
|
|
5187
|
+
this.deindent();
|
|
5188
|
+
this.line(`}${endTokens?.filter(Boolean).join(" ") ?? ""}`);
|
|
5189
|
+
}
|
|
5190
|
+
squareBlock(tokens, gencontent, endTokens) {
|
|
5191
|
+
this.line(`${tokens.filter(Boolean).join(" ")} [`);
|
|
5192
|
+
this.indent();
|
|
5193
|
+
gencontent();
|
|
5194
|
+
this.deindent();
|
|
5195
|
+
this.line(`]${endTokens?.filter(Boolean).join(" ") ?? ""}`);
|
|
5196
|
+
}
|
|
5197
|
+
};
|
|
5198
|
+
|
|
5199
|
+
// src/api/writer-generator/typescript.ts
|
|
5200
|
+
var collectComplexTypes = (tss) => tss.filter((t) => t.identifier.kind === "complex-type");
|
|
5201
|
+
var collectResources = (tss) => tss.filter((t) => t.identifier.kind === "resource");
|
|
5202
|
+
var groupByPackages = (typeSchemas) => {
|
|
5203
|
+
const grouped = {};
|
|
5204
|
+
for (const ts of typeSchemas) {
|
|
5205
|
+
const packageName = ts.identifier.package;
|
|
5206
|
+
if (!grouped[packageName]) {
|
|
5207
|
+
grouped[packageName] = [];
|
|
5208
|
+
}
|
|
5209
|
+
grouped[packageName].push(ts);
|
|
5210
|
+
}
|
|
5211
|
+
for (const [_packageName, typeSchemas2] of Object.entries(grouped)) {
|
|
5212
|
+
typeSchemas2.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
|
|
5213
|
+
}
|
|
5214
|
+
return grouped;
|
|
5215
|
+
};
|
|
5216
|
+
var fileNameStem = (id) => {
|
|
5217
|
+
return pascalCase(id.name);
|
|
5218
|
+
};
|
|
5219
|
+
var normalizeName = (n) => {
|
|
5220
|
+
if (n === "extends") {
|
|
5221
|
+
return "extends_";
|
|
5222
|
+
}
|
|
5223
|
+
return n.replace(/[- ]/g, "_");
|
|
5224
|
+
};
|
|
5225
|
+
var resourceName = (id) => {
|
|
5226
|
+
return normalizeName(id.name);
|
|
5227
|
+
};
|
|
5228
|
+
var TypeScript = class extends Writer {
|
|
5229
|
+
tsImportFrom(tsPackage, ...entities) {
|
|
5230
|
+
this.lineSM(`import { ${entities.join(", ")} } from '${tsPackage}'`);
|
|
5231
|
+
}
|
|
5232
|
+
generatePackageIndexFile(schemas) {
|
|
5233
|
+
this.cat("index.ts", () => {
|
|
5234
|
+
let exports = schemas.map((schema) => ({
|
|
5235
|
+
identifier: schema.identifier,
|
|
5236
|
+
fileName: fileNameStem(schema.identifier),
|
|
5237
|
+
name: resourceName(schema.identifier)
|
|
5238
|
+
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
5239
|
+
exports = Array.from(new Map(exports.map((exp) => [exp.name.toLowerCase(), exp])).values()).sort(
|
|
5240
|
+
(a, b) => a.name.localeCompare(b.name)
|
|
5241
|
+
);
|
|
5242
|
+
for (const exp of exports) {
|
|
5243
|
+
this.debugComment(exp.identifier);
|
|
5244
|
+
this.tsImportFrom(`./${exp.fileName}`, exp.name);
|
|
5245
|
+
}
|
|
5246
|
+
this.lineSM(`export { ${exports.map((e) => e.name).join(", ")} }`);
|
|
5247
|
+
this.line("");
|
|
5248
|
+
this.curlyBlock(["export type ResourceTypeMap = "], () => {
|
|
5249
|
+
this.lineSM("User: Record<string, any>");
|
|
5250
|
+
exports.forEach((exp) => {
|
|
5251
|
+
this.debugComment(exp.identifier);
|
|
5252
|
+
this.lineSM(`${exp.name}: ${exp.name}`);
|
|
5253
|
+
});
|
|
5254
|
+
});
|
|
5255
|
+
this.lineSM("export type ResourceType = keyof ResourceTypeMap");
|
|
5256
|
+
this.squareBlock(["export const resourceList: readonly ResourceType[] = "], () => {
|
|
5257
|
+
exports.forEach((exp) => {
|
|
5258
|
+
this.debugComment(exp.identifier);
|
|
5259
|
+
this.line(`'${exp.name}', `);
|
|
5260
|
+
});
|
|
5261
|
+
});
|
|
5262
|
+
});
|
|
5263
|
+
}
|
|
5264
|
+
generate(schemas) {
|
|
5265
|
+
const typesToGenerate = [
|
|
5266
|
+
...collectComplexTypes(schemas),
|
|
5267
|
+
...collectResources(schemas)
|
|
5268
|
+
// ...collectLogicalModels(typeSchemas),
|
|
5269
|
+
// ...collectProfiles(typeSchemas),
|
|
5270
|
+
];
|
|
5271
|
+
const grouped = groupByPackages(typesToGenerate);
|
|
5272
|
+
this.cd("/", () => {
|
|
5273
|
+
for (const [packageName, packageSchemas] of Object.entries(grouped)) {
|
|
5274
|
+
const tsPackageName = kebabCase(packageName);
|
|
5275
|
+
this.cd(tsPackageName, () => {
|
|
5276
|
+
this.generatePackageIndexFile(packageSchemas);
|
|
5277
|
+
});
|
|
5278
|
+
}
|
|
5279
|
+
});
|
|
5280
|
+
}
|
|
5281
|
+
};
|
|
5282
|
+
|
|
5049
5283
|
// src/api/builder.ts
|
|
5284
|
+
var writerToGenerator = (writerGen) => {
|
|
5285
|
+
const getGeneratedFiles = () => {
|
|
5286
|
+
return writerGen.writtenFiles().map((fn) => {
|
|
5287
|
+
return {
|
|
5288
|
+
path: Path2.normalize(Path2.join(writerGen.opts.outputDir, fn)),
|
|
5289
|
+
filename: fn.replace(/^.*[\\/]/, ""),
|
|
5290
|
+
content: "",
|
|
5291
|
+
exports: [],
|
|
5292
|
+
size: 0,
|
|
5293
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
5294
|
+
};
|
|
5295
|
+
});
|
|
5296
|
+
};
|
|
5297
|
+
return {
|
|
5298
|
+
generate: async (schemas) => {
|
|
5299
|
+
writerGen.generate(schemas);
|
|
5300
|
+
return getGeneratedFiles();
|
|
5301
|
+
},
|
|
5302
|
+
setOutputDir: (outputDir) => writerGen.opts.outputDir = outputDir,
|
|
5303
|
+
build: async (_schemas) => getGeneratedFiles()
|
|
5304
|
+
};
|
|
5305
|
+
};
|
|
5050
5306
|
var APIBuilder = class {
|
|
5051
5307
|
schemas = [];
|
|
5052
5308
|
options;
|
|
5053
5309
|
generators = /* @__PURE__ */ new Map();
|
|
5054
|
-
progressCallback;
|
|
5055
5310
|
cache;
|
|
5056
5311
|
pendingOperations = [];
|
|
5057
5312
|
typeSchemaGenerator;
|
|
5058
5313
|
logger;
|
|
5314
|
+
packages = [];
|
|
5315
|
+
progressCallback;
|
|
5059
5316
|
typeSchemaConfig;
|
|
5060
5317
|
constructor(options = {}) {
|
|
5061
5318
|
this.options = {
|
|
5062
5319
|
outputDir: options.outputDir || "./generated",
|
|
5063
5320
|
verbose: options.verbose ?? false,
|
|
5064
5321
|
overwrite: options.overwrite ?? true,
|
|
5065
|
-
validate: options.validate ?? true,
|
|
5066
5322
|
cache: options.cache ?? true,
|
|
5067
5323
|
typeSchemaConfig: options.typeSchemaConfig,
|
|
5068
|
-
manager: options.manager || null
|
|
5324
|
+
manager: options.manager || null,
|
|
5325
|
+
throwException: options.throwException || false
|
|
5069
5326
|
};
|
|
5070
5327
|
this.typeSchemaConfig = options.typeSchemaConfig;
|
|
5071
5328
|
this.logger = options.logger || createLogger({
|
|
@@ -5076,13 +5333,8 @@ var APIBuilder = class {
|
|
|
5076
5333
|
this.cache = new TypeSchemaCache(this.typeSchemaConfig);
|
|
5077
5334
|
}
|
|
5078
5335
|
}
|
|
5079
|
-
/**
|
|
5080
|
-
* Load TypeSchema from a FHIR package
|
|
5081
|
-
*/
|
|
5082
5336
|
fromPackage(packageName, version) {
|
|
5083
|
-
this.
|
|
5084
|
-
const operation = this.loadFromPackage(packageName, version);
|
|
5085
|
-
this.pendingOperations.push(operation);
|
|
5337
|
+
this.packages.push(packageMetaToNpm({ name: packageName, version: version || "latest" }));
|
|
5086
5338
|
return this;
|
|
5087
5339
|
}
|
|
5088
5340
|
/**
|
|
@@ -5102,9 +5354,6 @@ var APIBuilder = class {
|
|
|
5102
5354
|
this.schemas = [...this.schemas, ...schemas];
|
|
5103
5355
|
return this;
|
|
5104
5356
|
}
|
|
5105
|
-
/**
|
|
5106
|
-
* Configure TypeScript generation
|
|
5107
|
-
*/
|
|
5108
5357
|
typescript(options = {}) {
|
|
5109
5358
|
const typesOutputDir = `${this.options.outputDir}/types`;
|
|
5110
5359
|
const generator = new TypeScriptGenerator({
|
|
@@ -5130,6 +5379,19 @@ var APIBuilder = class {
|
|
|
5130
5379
|
this.logger.debug(`Configured TypeScript generator (${options.moduleFormat || "esm"})`);
|
|
5131
5380
|
return this;
|
|
5132
5381
|
}
|
|
5382
|
+
typescript2(opts) {
|
|
5383
|
+
const writerOpts = {
|
|
5384
|
+
outputDir: Path2.join(this.options.outputDir, "/types"),
|
|
5385
|
+
tabSize: 2,
|
|
5386
|
+
withDebugComment: true,
|
|
5387
|
+
commentLinePrefix: "//"
|
|
5388
|
+
};
|
|
5389
|
+
const effectiveOpts = { logger: this.logger, ...writerOpts, ...opts };
|
|
5390
|
+
const generator = writerToGenerator(new TypeScript(effectiveOpts));
|
|
5391
|
+
this.generators.set("typescript2", generator);
|
|
5392
|
+
this.logger.debug(`Configured TypeScript2 generator (${JSON.stringify(effectiveOpts, void 0, 2)})`);
|
|
5393
|
+
return this;
|
|
5394
|
+
}
|
|
5133
5395
|
/**
|
|
5134
5396
|
* Set a progress callback for monitoring generation
|
|
5135
5397
|
*/
|
|
@@ -5150,23 +5412,15 @@ var APIBuilder = class {
|
|
|
5150
5412
|
}
|
|
5151
5413
|
return this;
|
|
5152
5414
|
}
|
|
5153
|
-
/**
|
|
5154
|
-
* Enable/disable verbose logging
|
|
5155
|
-
*/
|
|
5156
5415
|
verbose(enabled = true) {
|
|
5157
5416
|
this.options.verbose = enabled;
|
|
5417
|
+
this.logger?.configure({ verbose: enabled });
|
|
5158
5418
|
return this;
|
|
5159
5419
|
}
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
*/
|
|
5163
|
-
validate(enabled = true) {
|
|
5164
|
-
this.options.validate = enabled;
|
|
5420
|
+
throwException(enabled = true) {
|
|
5421
|
+
this.options.throwException = enabled;
|
|
5165
5422
|
return this;
|
|
5166
5423
|
}
|
|
5167
|
-
/**
|
|
5168
|
-
* Execute the generation process
|
|
5169
|
-
*/
|
|
5170
5424
|
async generate() {
|
|
5171
5425
|
const startTime = performance.now();
|
|
5172
5426
|
const result = {
|
|
@@ -5179,35 +5433,33 @@ var APIBuilder = class {
|
|
|
5179
5433
|
};
|
|
5180
5434
|
this.logger.debug(`Starting generation with ${this.generators.size} generators`);
|
|
5181
5435
|
try {
|
|
5182
|
-
this.
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
}
|
|
5191
|
-
this.reportProgress("Generating", 2, 4, "Generating code...");
|
|
5436
|
+
this.logger.info("Initialize Canonical Manager");
|
|
5437
|
+
const manager = CanonicalManager({
|
|
5438
|
+
packages: this.packages,
|
|
5439
|
+
workingDir: "tmp/fhir"
|
|
5440
|
+
});
|
|
5441
|
+
await manager.init();
|
|
5442
|
+
const register = await registerFromManager(manager, this.logger);
|
|
5443
|
+
const typeSchemas = await generateTypeSchemas(register);
|
|
5192
5444
|
this.logger.debug(`Executing ${this.generators.size} generators`);
|
|
5193
|
-
await this.executeGenerators(result);
|
|
5194
|
-
this.
|
|
5445
|
+
await this.executeGenerators(result, typeSchemas);
|
|
5446
|
+
this.logger.info("Generation completed successfully");
|
|
5195
5447
|
result.success = result.errors.length === 0;
|
|
5196
5448
|
this.logger.debug(`Generation completed: ${result.filesGenerated.length} files`);
|
|
5197
5449
|
} catch (error) {
|
|
5198
5450
|
this.logger.error("Code generation failed", error instanceof Error ? error : new Error(String(error)));
|
|
5199
5451
|
result.errors.push(error instanceof Error ? error.message : String(error));
|
|
5200
|
-
result.success = false;
|
|
5201
|
-
} finally {
|
|
5202
|
-
result.duration = performance.now() - startTime;
|
|
5203
5452
|
}
|
|
5204
|
-
return
|
|
5453
|
+
return {
|
|
5454
|
+
...result,
|
|
5455
|
+
success: result.errors.length === 0,
|
|
5456
|
+
duration: performance.now() - startTime
|
|
5457
|
+
};
|
|
5205
5458
|
}
|
|
5206
5459
|
/**
|
|
5207
5460
|
* Generate and return the results without writing to files
|
|
5208
5461
|
*/
|
|
5209
5462
|
async build() {
|
|
5210
|
-
await this.resolveSchemas();
|
|
5211
5463
|
const results = {};
|
|
5212
5464
|
for (const [type, generator] of this.generators.entries()) {
|
|
5213
5465
|
if (generator.build) {
|
|
@@ -5237,24 +5489,6 @@ var APIBuilder = class {
|
|
|
5237
5489
|
getGenerators() {
|
|
5238
5490
|
return Array.from(this.generators.keys());
|
|
5239
5491
|
}
|
|
5240
|
-
// Private implementation methods
|
|
5241
|
-
async loadFromPackage(packageName, version) {
|
|
5242
|
-
const generator = new TypeSchemaGenerator(
|
|
5243
|
-
{
|
|
5244
|
-
verbose: this.options.verbose,
|
|
5245
|
-
logger: this.logger.child("Schema"),
|
|
5246
|
-
treeshake: this.typeSchemaConfig?.treeshake,
|
|
5247
|
-
manager: this.options.manager
|
|
5248
|
-
},
|
|
5249
|
-
this.typeSchemaConfig
|
|
5250
|
-
);
|
|
5251
|
-
this.typeSchemaGenerator = generator;
|
|
5252
|
-
const schemas = await generator.generateFromPackage(packageName, version);
|
|
5253
|
-
this.schemas = [...this.schemas, ...schemas];
|
|
5254
|
-
if (this.cache) {
|
|
5255
|
-
this.cache.setMany(schemas);
|
|
5256
|
-
}
|
|
5257
|
-
}
|
|
5258
5492
|
async loadFromFiles(filePaths) {
|
|
5259
5493
|
if (!this.typeSchemaGenerator) {
|
|
5260
5494
|
this.typeSchemaGenerator = new TypeSchemaGenerator(
|
|
@@ -5267,8 +5501,7 @@ var APIBuilder = class {
|
|
|
5267
5501
|
);
|
|
5268
5502
|
}
|
|
5269
5503
|
const parser = new TypeSchemaParser({
|
|
5270
|
-
format: "auto"
|
|
5271
|
-
validate: this.options.validate
|
|
5504
|
+
format: "auto"
|
|
5272
5505
|
});
|
|
5273
5506
|
const schemas = await parser.parseFromFiles(filePaths);
|
|
5274
5507
|
this.schemas = [...this.schemas, ...schemas];
|
|
@@ -5276,37 +5509,18 @@ var APIBuilder = class {
|
|
|
5276
5509
|
this.cache.setMany(schemas);
|
|
5277
5510
|
}
|
|
5278
5511
|
}
|
|
5279
|
-
async
|
|
5280
|
-
if (this.pendingOperations.length > 0) {
|
|
5281
|
-
await Promise.all(this.pendingOperations);
|
|
5282
|
-
this.pendingOperations = [];
|
|
5283
|
-
}
|
|
5284
|
-
}
|
|
5285
|
-
async validateSchemas(_result) {
|
|
5286
|
-
return;
|
|
5287
|
-
}
|
|
5288
|
-
async executeGenerators(result) {
|
|
5289
|
-
const generatorCount = this.generators.size;
|
|
5290
|
-
let current = 0;
|
|
5512
|
+
async executeGenerators(result, typeSchemas) {
|
|
5291
5513
|
for (const [type, generator] of this.generators.entries()) {
|
|
5292
|
-
this.
|
|
5514
|
+
this.logger.info(`Generating ${type}...`);
|
|
5293
5515
|
try {
|
|
5294
|
-
const files = await generator.generate(
|
|
5516
|
+
const files = await generator.generate(typeSchemas);
|
|
5295
5517
|
result.filesGenerated.push(...files.map((f) => f.path || f.filename));
|
|
5518
|
+
this.logger.info(`Generating ${type} finished successfully`);
|
|
5296
5519
|
} catch (error) {
|
|
5297
5520
|
result.errors.push(
|
|
5298
5521
|
`${type} generator failed: ${error instanceof Error ? error.message : String(error)}`
|
|
5299
5522
|
);
|
|
5300
5523
|
}
|
|
5301
|
-
current++;
|
|
5302
|
-
}
|
|
5303
|
-
}
|
|
5304
|
-
reportProgress(phase, current, total, message) {
|
|
5305
|
-
if (this.progressCallback) {
|
|
5306
|
-
this.progressCallback(phase, current, total, message);
|
|
5307
|
-
}
|
|
5308
|
-
if (this.options.verbose && message) {
|
|
5309
|
-
this.logger.debug(`[${phase}] ${message}`);
|
|
5310
5524
|
}
|
|
5311
5525
|
}
|
|
5312
5526
|
};
|
|
@@ -5318,7 +5532,6 @@ function createAPIFromConfig(config) {
|
|
|
5318
5532
|
outputDir: config.outputDir,
|
|
5319
5533
|
verbose: config.verbose,
|
|
5320
5534
|
overwrite: config.overwrite,
|
|
5321
|
-
validate: config.validate,
|
|
5322
5535
|
cache: config.cache,
|
|
5323
5536
|
typeSchemaConfig: config.typeSchema
|
|
5324
5537
|
});
|
|
@@ -5338,15 +5551,13 @@ function createAPIFromConfig(config) {
|
|
|
5338
5551
|
async function generateTypesFromPackage(packageName, outputDir, options = {}) {
|
|
5339
5552
|
return createAPI({
|
|
5340
5553
|
outputDir,
|
|
5341
|
-
verbose: options.verbose
|
|
5342
|
-
validate: options.validate
|
|
5554
|
+
verbose: options.verbose
|
|
5343
5555
|
}).fromPackage(packageName, options.version).typescript().generate();
|
|
5344
5556
|
}
|
|
5345
5557
|
async function generateTypesFromFiles(inputFiles, outputDir, options = {}) {
|
|
5346
5558
|
return createAPI({
|
|
5347
5559
|
outputDir,
|
|
5348
|
-
verbose: options.verbose
|
|
5349
|
-
validate: options.validate
|
|
5560
|
+
verbose: options.verbose
|
|
5350
5561
|
}).fromFiles(...inputFiles).typescript().generate();
|
|
5351
5562
|
}
|
|
5352
5563
|
var DEFAULT_CONFIG = {
|