@atomic-ehr/codegen 0.0.1-canary.20251015064414.0fcee22 → 0.0.1
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 +26 -27
- package/dist/index.d.ts +11 -11
- package/dist/index.js +669 -289
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
import { existsSync, mkdirSync } from 'fs';
|
|
3
|
-
import * as
|
|
2
|
+
import fs__default, { existsSync, mkdirSync } from 'fs';
|
|
3
|
+
import * as afs2 from 'fs/promises';
|
|
4
4
|
import { readdir, stat, unlink, readFile, writeFile, access, mkdir, rm } from 'fs/promises';
|
|
5
|
-
import * as
|
|
6
|
-
import { join, resolve, dirname, relative } from 'path';
|
|
5
|
+
import * as Path4 from 'path';
|
|
6
|
+
import Path4__default, { join, resolve, dirname, relative } from 'path';
|
|
7
7
|
import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
|
|
8
8
|
import * as fhirschema from '@atomic-ehr/fhirschema';
|
|
9
|
+
import { isStructureDefinition } from '@atomic-ehr/fhirschema';
|
|
9
10
|
import pc from 'picocolors';
|
|
10
11
|
|
|
11
12
|
var __defProp = Object.defineProperty;
|
|
@@ -1445,6 +1446,22 @@ var isChoiceDeclarationField = (field) => {
|
|
|
1445
1446
|
if (!field) return false;
|
|
1446
1447
|
return field.choices !== void 0;
|
|
1447
1448
|
};
|
|
1449
|
+
var isValueSet = (res) => {
|
|
1450
|
+
return res.resourceType === "ValueSet";
|
|
1451
|
+
};
|
|
1452
|
+
var isCodeSystem = (res) => {
|
|
1453
|
+
return res.resourceType === "CodeSystem";
|
|
1454
|
+
};
|
|
1455
|
+
var enrichValueSet = (vs, packageMeta) => {
|
|
1456
|
+
if (!vs.url) throw new Error("ValueSet must have a URL");
|
|
1457
|
+
if (!vs.name) throw new Error("ValueSet must have a name");
|
|
1458
|
+
return {
|
|
1459
|
+
...vs,
|
|
1460
|
+
package_meta: vs.package_meta || packageMeta,
|
|
1461
|
+
name: vs.name,
|
|
1462
|
+
url: vs.url
|
|
1463
|
+
};
|
|
1464
|
+
};
|
|
1448
1465
|
|
|
1449
1466
|
// src/typeschema/core/identifier.ts
|
|
1450
1467
|
function dropVersionFromUrl(url) {
|
|
@@ -1479,7 +1496,7 @@ var getValueSetName = (url) => {
|
|
|
1479
1496
|
}
|
|
1480
1497
|
return url;
|
|
1481
1498
|
};
|
|
1482
|
-
function mkValueSetIdentifierByUrl(register, fullValueSetUrl) {
|
|
1499
|
+
function mkValueSetIdentifierByUrl(register, pkg, fullValueSetUrl) {
|
|
1483
1500
|
const valueSetUrl = dropVersionFromUrl(fullValueSetUrl);
|
|
1484
1501
|
const valueSetNameFallback = getValueSetName(valueSetUrl);
|
|
1485
1502
|
const valuesSetFallback = {
|
|
@@ -1488,7 +1505,7 @@ function mkValueSetIdentifierByUrl(register, fullValueSetUrl) {
|
|
|
1488
1505
|
version: getVersionFromUrl(valueSetUrl) || "0.0.0"
|
|
1489
1506
|
},
|
|
1490
1507
|
id: fullValueSetUrl};
|
|
1491
|
-
const valueSet = register.resolveVs(valueSetUrl) || valuesSetFallback;
|
|
1508
|
+
const valueSet = register.resolveVs(pkg, valueSetUrl) || valuesSetFallback;
|
|
1492
1509
|
const valueSetName = valueSet?.id && !/^[a-zA-Z0-9_-]{20,}$/.test(valueSet.id) ? valueSet.id : valueSetNameFallback;
|
|
1493
1510
|
return {
|
|
1494
1511
|
kind: "value-set",
|
|
@@ -1514,8 +1531,8 @@ function mkBindingIdentifier(fhirSchema, path, bindingName) {
|
|
|
1514
1531
|
function mkNestedIdentifier(register, fhirSchema, path, logger) {
|
|
1515
1532
|
const nestedTypeOrigins = {};
|
|
1516
1533
|
if (fhirSchema.derivation === "constraint") {
|
|
1517
|
-
const specializations = register.resolveFsSpecializations(fhirSchema.url);
|
|
1518
|
-
const nestedTypeGenealogy = specializations.map((
|
|
1534
|
+
const specializations = register.resolveFsSpecializations(fhirSchema.package_meta, fhirSchema.url);
|
|
1535
|
+
const nestedTypeGenealogy = specializations.map((fs4) => mkNestedTypes(register, fs4, logger)).filter((e) => e !== void 0).flat();
|
|
1519
1536
|
for (const nt of nestedTypeGenealogy.reverse()) {
|
|
1520
1537
|
nestedTypeOrigins[nt.identifier.name] = nt.identifier.url;
|
|
1521
1538
|
}
|
|
@@ -1575,7 +1592,7 @@ function mkNestedTypes(register, fhirSchema, logger) {
|
|
|
1575
1592
|
package: fhirSchema.package_meta.name,
|
|
1576
1593
|
version: fhirSchema.package_meta.version,
|
|
1577
1594
|
name: baseName,
|
|
1578
|
-
url: register.ensureSpecializationCanonicalUrl(baseName)
|
|
1595
|
+
url: register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, baseName)
|
|
1579
1596
|
};
|
|
1580
1597
|
const fields = transformNestedElements(register, fhirSchema, path, element.elements, logger);
|
|
1581
1598
|
const nestedType = {
|
|
@@ -1610,10 +1627,10 @@ function extractNestedDependencies(nestedTypes) {
|
|
|
1610
1627
|
function isRequired(register, fhirSchema, path) {
|
|
1611
1628
|
const fieldName = path[path.length - 1];
|
|
1612
1629
|
const parentPath = path.slice(0, -1);
|
|
1613
|
-
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((
|
|
1614
|
-
if (parentPath.length === 0) return
|
|
1615
|
-
if (!
|
|
1616
|
-
let elem =
|
|
1630
|
+
const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs4) => {
|
|
1631
|
+
if (parentPath.length === 0) return fs4.required || [];
|
|
1632
|
+
if (!fs4.elements) return [];
|
|
1633
|
+
let elem = fs4;
|
|
1617
1634
|
for (const k of parentPath) {
|
|
1618
1635
|
elem = elem?.elements?.[k];
|
|
1619
1636
|
}
|
|
@@ -1625,10 +1642,10 @@ function isExcluded(register, fhirSchema, path) {
|
|
|
1625
1642
|
const fieldName = path[path.length - 1];
|
|
1626
1643
|
if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
|
|
1627
1644
|
const parentPath = path.slice(0, -1);
|
|
1628
|
-
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((
|
|
1629
|
-
if (parentPath.length === 0) return
|
|
1630
|
-
if (!
|
|
1631
|
-
let elem =
|
|
1645
|
+
const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs4) => {
|
|
1646
|
+
if (parentPath.length === 0) return fs4.excluded || [];
|
|
1647
|
+
if (!fs4.elements) return [];
|
|
1648
|
+
let elem = fs4;
|
|
1632
1649
|
for (const k of parentPath) {
|
|
1633
1650
|
elem = elem?.elements?.[k];
|
|
1634
1651
|
}
|
|
@@ -1636,12 +1653,12 @@ function isExcluded(register, fhirSchema, path) {
|
|
|
1636
1653
|
});
|
|
1637
1654
|
return new Set(requires).has(fieldName);
|
|
1638
1655
|
}
|
|
1639
|
-
var buildReferences = (
|
|
1656
|
+
var buildReferences = (register, fhirSchema, element) => {
|
|
1640
1657
|
if (!element.refers) return void 0;
|
|
1641
1658
|
return element.refers.map((ref) => {
|
|
1642
|
-
const curl = register.ensureSpecializationCanonicalUrl(ref);
|
|
1643
|
-
const
|
|
1644
|
-
return mkIdentifier(
|
|
1659
|
+
const curl = register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, ref);
|
|
1660
|
+
const fs4 = register.resolveFs(fhirSchema.package_meta, curl);
|
|
1661
|
+
return mkIdentifier(fs4);
|
|
1645
1662
|
});
|
|
1646
1663
|
};
|
|
1647
1664
|
function buildFieldType(register, fhirSchema, path, element, logger) {
|
|
@@ -1649,9 +1666,9 @@ function buildFieldType(register, fhirSchema, path, element, logger) {
|
|
|
1649
1666
|
const refPath = element.elementReference.slice(1).filter((_, i) => i % 2 === 1);
|
|
1650
1667
|
return mkNestedIdentifier(register, fhirSchema, refPath, logger);
|
|
1651
1668
|
} else if (element.type) {
|
|
1652
|
-
const url = register.ensureSpecializationCanonicalUrl(element.type);
|
|
1653
|
-
const fieldFs = register.resolveFs(url);
|
|
1654
|
-
if (!fieldFs) throw new Error(`Could not resolve field '${element.type}'`);
|
|
1669
|
+
const url = register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, element.type);
|
|
1670
|
+
const fieldFs = register.resolveFs(fhirSchema.package_meta, url);
|
|
1671
|
+
if (!fieldFs) throw new Error(`Could not resolve field type: '${element.type}'`);
|
|
1655
1672
|
return mkIdentifier(fieldFs);
|
|
1656
1673
|
} else if (element.choices) {
|
|
1657
1674
|
return void 0;
|
|
@@ -1670,14 +1687,14 @@ var mkField = (register, fhirSchema, path, element, logger) => {
|
|
|
1670
1687
|
if (element.binding) {
|
|
1671
1688
|
binding = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
|
|
1672
1689
|
if (element.binding.strength === "required" && element.type === "code") {
|
|
1673
|
-
enumValues = buildEnum(register, element, logger);
|
|
1690
|
+
enumValues = buildEnum(register, fhirSchema, element, logger);
|
|
1674
1691
|
}
|
|
1675
1692
|
}
|
|
1676
1693
|
return {
|
|
1677
1694
|
type: buildFieldType(register, fhirSchema, path, element, logger),
|
|
1678
1695
|
required: isRequired(register, fhirSchema, path),
|
|
1679
1696
|
excluded: isExcluded(register, fhirSchema, path),
|
|
1680
|
-
reference: buildReferences(
|
|
1697
|
+
reference: buildReferences(register, fhirSchema, element),
|
|
1681
1698
|
array: element.array || false,
|
|
1682
1699
|
min: element.min,
|
|
1683
1700
|
max: element.max,
|
|
@@ -1703,9 +1720,9 @@ function mkNestedField(register, fhirSchema, path, element, logger) {
|
|
|
1703
1720
|
}
|
|
1704
1721
|
|
|
1705
1722
|
// src/typeschema/core/binding.ts
|
|
1706
|
-
function extractValueSetConceptsByUrl(register, valueSetUrl, logger) {
|
|
1723
|
+
function extractValueSetConceptsByUrl(register, pkg, valueSetUrl, logger) {
|
|
1707
1724
|
const cleanUrl = dropVersionFromUrl(valueSetUrl) || valueSetUrl;
|
|
1708
|
-
const valueSet = register.resolveVs(cleanUrl);
|
|
1725
|
+
const valueSet = register.resolveVs(pkg, cleanUrl);
|
|
1709
1726
|
if (!valueSet) return void 0;
|
|
1710
1727
|
return extractValueSetConcepts(register, valueSet);
|
|
1711
1728
|
}
|
|
@@ -1748,14 +1765,14 @@ function extractValueSetConcepts(register, valueSet, _logger) {
|
|
|
1748
1765
|
return concepts.length > 0 ? concepts : void 0;
|
|
1749
1766
|
}
|
|
1750
1767
|
var MAX_ENUM_LENGTH = 100;
|
|
1751
|
-
function buildEnum(register, element, logger) {
|
|
1768
|
+
function buildEnum(register, fhirSchema, element, logger) {
|
|
1752
1769
|
if (!element.binding) return void 0;
|
|
1753
1770
|
const strength = element.binding.strength;
|
|
1754
1771
|
const valueSetUrl = element.binding.valueSet;
|
|
1755
1772
|
if (!valueSetUrl) return void 0;
|
|
1756
1773
|
const shouldGenerateEnum = strength === "required" || strength === "extensible" && (element.type === "code" || element.type === "Coding") || strength === "preferred" && (element.type === "code" || element.type === "Coding");
|
|
1757
1774
|
if (!shouldGenerateEnum) return void 0;
|
|
1758
|
-
const concepts = extractValueSetConceptsByUrl(register, valueSetUrl);
|
|
1775
|
+
const concepts = extractValueSetConceptsByUrl(register, fhirSchema.package_meta, valueSetUrl);
|
|
1759
1776
|
if (!concepts || concepts.length === 0) return void 0;
|
|
1760
1777
|
const codes = concepts.map((c) => c.code).filter((code) => code && typeof code === "string" && code.trim().length > 0);
|
|
1761
1778
|
if (codes.length > MAX_ENUM_LENGTH) {
|
|
@@ -1770,13 +1787,17 @@ function generateBindingSchema(register, fhirSchema, path, element, logger) {
|
|
|
1770
1787
|
if (!element.binding?.valueSet) return void 0;
|
|
1771
1788
|
const identifier = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
|
|
1772
1789
|
const fieldType = buildFieldType(register, fhirSchema, path, element, logger);
|
|
1773
|
-
const valueSetIdentifier = mkValueSetIdentifierByUrl(
|
|
1790
|
+
const valueSetIdentifier = mkValueSetIdentifierByUrl(
|
|
1791
|
+
register,
|
|
1792
|
+
fhirSchema.package_meta,
|
|
1793
|
+
element.binding.valueSet
|
|
1794
|
+
);
|
|
1774
1795
|
const dependencies = [];
|
|
1775
1796
|
if (fieldType) {
|
|
1776
1797
|
dependencies.push(fieldType);
|
|
1777
1798
|
}
|
|
1778
1799
|
dependencies.push(valueSetIdentifier);
|
|
1779
|
-
const enumValues = buildEnum(register, element, logger);
|
|
1800
|
+
const enumValues = buildEnum(register, fhirSchema, element, logger);
|
|
1780
1801
|
return {
|
|
1781
1802
|
identifier,
|
|
1782
1803
|
type: fieldType,
|
|
@@ -1877,8 +1898,8 @@ function isExtensionSchema(fhirSchema, _identifier) {
|
|
|
1877
1898
|
}
|
|
1878
1899
|
async function transformValueSet(register, valueSet, logger) {
|
|
1879
1900
|
if (!valueSet.url) throw new Error("ValueSet URL is required");
|
|
1880
|
-
const identifier = mkValueSetIdentifierByUrl(register, valueSet.url);
|
|
1881
|
-
const concept = extractValueSetConceptsByUrl(register, valueSet.url);
|
|
1901
|
+
const identifier = mkValueSetIdentifierByUrl(register, valueSet.package_meta, valueSet.url);
|
|
1902
|
+
const concept = extractValueSetConceptsByUrl(register, valueSet.package_meta, valueSet.url);
|
|
1882
1903
|
return {
|
|
1883
1904
|
identifier,
|
|
1884
1905
|
description: valueSet.description,
|
|
@@ -1964,7 +1985,10 @@ function transformFhirSchemaResource(register, fhirSchema, logger) {
|
|
|
1964
1985
|
const identifier = mkIdentifier(fhirSchema);
|
|
1965
1986
|
let base;
|
|
1966
1987
|
if (fhirSchema.base && fhirSchema.type !== "Element") {
|
|
1967
|
-
const baseFs = register.resolveFs(
|
|
1988
|
+
const baseFs = register.resolveFs(
|
|
1989
|
+
fhirSchema.package_meta,
|
|
1990
|
+
register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, fhirSchema.base)
|
|
1991
|
+
);
|
|
1968
1992
|
if (!baseFs) {
|
|
1969
1993
|
throw new Error(`Base resource not found '${fhirSchema.base}' for '${fhirSchema.url}'`);
|
|
1970
1994
|
}
|
|
@@ -2336,120 +2360,129 @@ new CodegenLogger();
|
|
|
2336
2360
|
function createLogger(options = {}) {
|
|
2337
2361
|
return new CodegenLogger(options);
|
|
2338
2362
|
}
|
|
2339
|
-
var
|
|
2340
|
-
const
|
|
2341
|
-
const
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
const pkg = (await manager.resolveEntry(url)).package;
|
|
2351
|
-
if (!pkg) throw new Error(`Can't resolve package for ${url}`);
|
|
2352
|
-
if (!canonicalToPackages[url]) canonicalToPackages[url] = [];
|
|
2353
|
-
canonicalToPackages[url].push(pkg);
|
|
2354
|
-
flatRawIndex[url] = res;
|
|
2355
|
-
}
|
|
2356
|
-
const collisions = Object.entries(canonicalToPackages).filter(([_, e]) => e.length > 1).map(([url, pkgs]) => `${url}: ${pkgs.map((p) => `${p.name}@${p.version}`).join(", ")}`).join("\n");
|
|
2357
|
-
logger?.warn(`Duplicated canonicals: ${collisions}`);
|
|
2358
|
-
const packageToResources = {};
|
|
2359
|
-
const packageToPackageMeta = {};
|
|
2360
|
-
for (const [url, _pkgs] of Object.entries(canonicalToPackages)) {
|
|
2361
|
-
const pkg = (await manager.resolveEntry(url)).package;
|
|
2362
|
-
if (!pkg) throw new Error(`Can't find package for ${url}`);
|
|
2363
|
-
const pkgId = packageMetaToFhir(pkg);
|
|
2364
|
-
packageToPackageMeta[pkgId] = pkg;
|
|
2365
|
-
const res = await manager.resolve(url);
|
|
2366
|
-
if (!packageToResources[pkgId]) {
|
|
2367
|
-
packageToResources[pkgId] = {};
|
|
2368
|
-
}
|
|
2369
|
-
const index = packageToResources[pkgId];
|
|
2370
|
-
if (!index) throw new Error(`Can't find index for ${pkg.name}@${pkg.version}`);
|
|
2371
|
-
index[url] = res;
|
|
2372
|
-
}
|
|
2373
|
-
const indexByPackages = [];
|
|
2374
|
-
for (const [pkgId, index] of Object.entries(packageToResources)) {
|
|
2375
|
-
indexByPackages.push({
|
|
2376
|
-
package_meta: packageToPackageMeta[pkgId],
|
|
2377
|
-
index
|
|
2363
|
+
var readPackageJSON = async (workDir, packageMeta) => {
|
|
2364
|
+
const packageJSONFileName = Path4.join(workDir, "node_modules", packageMeta.name, "package.json");
|
|
2365
|
+
const packageJSON = JSON.parse(await afs2.readFile(packageJSONFileName, "utf8"));
|
|
2366
|
+
return packageJSON;
|
|
2367
|
+
};
|
|
2368
|
+
var readPackageDependencies = async (workDir, packageMeta) => {
|
|
2369
|
+
const packageJSON = await readPackageJSON(workDir, packageMeta);
|
|
2370
|
+
const dependencies = packageJSON.dependencies;
|
|
2371
|
+
if (dependencies !== void 0) {
|
|
2372
|
+
return Object.entries(dependencies).map(([name, version]) => {
|
|
2373
|
+
return { name, version };
|
|
2378
2374
|
});
|
|
2379
2375
|
}
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2376
|
+
return [];
|
|
2377
|
+
};
|
|
2378
|
+
var mkEmptyPkgIndex = (pkg) => {
|
|
2379
|
+
return { pkg, nameResolution: {}, canonicalResolution: {}, fhirSchemas: {}, valueSets: {} };
|
|
2380
|
+
};
|
|
2381
|
+
var mkPackageAwareResolver = async (manager, pkg, deep = 0, _logger) => {
|
|
2382
|
+
const options = {};
|
|
2383
|
+
const deps = await readPackageDependencies("tmp/fhir", pkg);
|
|
2384
|
+
for (const dep of deps) {
|
|
2385
|
+
const depOptions = mkPackageAwareResolver(manager, dep, deep);
|
|
2386
|
+
Object.assign(options, depOptions);
|
|
2387
|
+
}
|
|
2388
|
+
const pkgId = packageMetaToFhir(pkg);
|
|
2389
|
+
if (!options[pkgId]) options[pkgId] = mkEmptyPkgIndex(pkg);
|
|
2390
|
+
for (const resource of await manager.search({ package: pkg })) {
|
|
2391
|
+
const rawUrl = resource.url;
|
|
2392
|
+
if (!rawUrl) continue;
|
|
2393
|
+
if (!(isStructureDefinition(resource) || isValueSet(resource) || isCodeSystem(resource))) continue;
|
|
2394
|
+
const url = rawUrl;
|
|
2395
|
+
if (!options[pkgId].canonicalResolution[url]) {
|
|
2396
|
+
options[pkgId].canonicalResolution[url] = [];
|
|
2397
|
+
for (const [depPkgId, { canonicalResolution }] of Object.entries(options)) {
|
|
2398
|
+
if (pkgId === depPkgId) continue;
|
|
2399
|
+
if (!canonicalResolution[url]) continue;
|
|
2400
|
+
for (const deepRes of canonicalResolution[url]) {
|
|
2401
|
+
options[pkgId].canonicalResolution[url].push({
|
|
2402
|
+
deep: deepRes.deep + 1,
|
|
2403
|
+
resource: deepRes.resource,
|
|
2404
|
+
packageMeta: deepRes.packageMeta
|
|
2405
|
+
});
|
|
2399
2406
|
}
|
|
2400
|
-
vsIndex[resource.url] = resource;
|
|
2401
2407
|
}
|
|
2402
2408
|
}
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
if (!specNameToCanonicals[name]) specNameToCanonicals[name] = {};
|
|
2412
|
-
specNameToCanonicals[name][rfs.package_meta.name] = rfs.url;
|
|
2413
|
-
}
|
|
2414
|
-
const specNameToCanonical = {};
|
|
2415
|
-
for (const [sname, canonicals] of Object.entries(specNameToCanonicals)) {
|
|
2416
|
-
const name = sname;
|
|
2417
|
-
const canonicalValues = Object.values(canonicals);
|
|
2418
|
-
if (canonicalValues.length === 1) {
|
|
2419
|
-
const url = canonicalValues[0];
|
|
2420
|
-
specNameToCanonical[name] = url;
|
|
2421
|
-
} else {
|
|
2422
|
-
for (const pname of packageNameResolver) {
|
|
2423
|
-
if (canonicals[pname]) {
|
|
2424
|
-
specNameToCanonical[name] = canonicals[pname];
|
|
2425
|
-
break;
|
|
2426
|
-
}
|
|
2409
|
+
options[pkgId].canonicalResolution[url].push({ deep, packageMeta: pkg, resource });
|
|
2410
|
+
options[pkgId].canonicalResolution[url].sort((a, b) => a.deep - b.deep);
|
|
2411
|
+
const name = resource.name;
|
|
2412
|
+
if (name && isStructureDefinition(resource) && (resource.derivation === "specialization" || resource.derivation === void 0)) {
|
|
2413
|
+
if (!options[pkgId].nameResolution[name]) {
|
|
2414
|
+
options[pkgId].nameResolution[name] = resource.url;
|
|
2415
|
+
} else {
|
|
2416
|
+
throw new Error(`Duplicate name ${name} in package ${pkgId}`);
|
|
2427
2417
|
}
|
|
2428
|
-
if (specNameToCanonical[name] === void 0) throw new Error(`No canonical URL found for ${name}`);
|
|
2429
2418
|
}
|
|
2430
2419
|
}
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2420
|
+
return options;
|
|
2421
|
+
};
|
|
2422
|
+
var packageAwareResolveName = (resolver, pkg, name) => {
|
|
2423
|
+
const pkgId = packageMetaToFhir(pkg);
|
|
2424
|
+
if (!resolver[pkgId]) throw new Error(`Package ${pkgId} not found`);
|
|
2425
|
+
const resource = resolver[pkgId].nameResolution[name];
|
|
2426
|
+
return resource;
|
|
2427
|
+
};
|
|
2428
|
+
var packageAgnosticResolveCanonical = (resolver, url, logger) => {
|
|
2429
|
+
const options = Object.values(resolver).flatMap((pkg) => pkg.canonicalResolution[url]);
|
|
2430
|
+
if (!options) throw new Error(`No canonical resolution found for ${url} in any package`);
|
|
2431
|
+
if (options.length > 1)
|
|
2432
|
+
logger?.dry_warn(
|
|
2433
|
+
`Multiple canonical resolutions found for ${url} in: ${JSON.stringify(options, void 0, 2)}`
|
|
2434
|
+
);
|
|
2435
|
+
return options[0]?.resource;
|
|
2436
|
+
};
|
|
2437
|
+
var registerFromManager = async (manager, { logger, fallbackPackageForNameResolution }) => {
|
|
2438
|
+
const packages = await manager.packages();
|
|
2439
|
+
const resolver = {};
|
|
2440
|
+
for (const pkg of packages) {
|
|
2441
|
+
Object.assign(resolver, await mkPackageAwareResolver(manager, pkg));
|
|
2442
|
+
}
|
|
2443
|
+
for (const { pkg, canonicalResolution } of Object.values(resolver)) {
|
|
2444
|
+
const pkgId = packageMetaToFhir(pkg);
|
|
2445
|
+
if (!resolver[pkgId]) throw new Error(`Package ${pkgId} not found`);
|
|
2446
|
+
let counter = 0;
|
|
2447
|
+
logger?.info(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' begins...`);
|
|
2448
|
+
for (const [_url, options] of Object.entries(canonicalResolution)) {
|
|
2449
|
+
const resource = options[0]?.resource;
|
|
2450
|
+
if (!resource) throw new Error(`Resource not found`);
|
|
2451
|
+
if (isStructureDefinition(resource)) {
|
|
2452
|
+
const rfs = enrichFHIRSchema(fhirschema.translate(resource), pkg);
|
|
2453
|
+
counter++;
|
|
2454
|
+
resolver[pkgId].fhirSchemas[rfs.url] = rfs;
|
|
2455
|
+
}
|
|
2456
|
+
if (isValueSet(resource)) {
|
|
2457
|
+
const rvs = enrichValueSet(resource, pkg);
|
|
2458
|
+
resolver[pkgId].valueSets[rvs.url] = rvs;
|
|
2459
|
+
}
|
|
2435
2460
|
}
|
|
2461
|
+
logger?.success(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' completed: ${counter} successful`);
|
|
2436
2462
|
}
|
|
2437
|
-
const
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2463
|
+
const resolveFs = (pkg, canonicalUrl) => {
|
|
2464
|
+
return resolver[packageMetaToFhir(pkg)]?.fhirSchemas[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.fhirSchemas[canonicalUrl];
|
|
2465
|
+
};
|
|
2466
|
+
const resolveVs = (pkg, canonicalUrl) => {
|
|
2467
|
+
return resolver[packageMetaToFhir(pkg)]?.valueSets[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.valueSets[canonicalUrl];
|
|
2468
|
+
};
|
|
2469
|
+
const ensureSpecializationCanonicalUrl = (pkg, name) => packageAwareResolveName(resolver, pkg, name) || fallbackPackageForNameResolution && packageAwareResolveName(resolver, fallbackPackageForNameResolution, name) || name;
|
|
2470
|
+
const resolveFsGenealogy = (pkg, canonicalUrl) => {
|
|
2471
|
+
let fs4 = resolveFs(pkg, canonicalUrl);
|
|
2472
|
+
if (fs4 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
2473
|
+
const genealogy = [fs4];
|
|
2474
|
+
while (fs4?.base) {
|
|
2475
|
+
fs4 = resolveFs(fs4.package_meta, fs4.base) || resolveFs(fs4.package_meta, ensureSpecializationCanonicalUrl(fs4.package_meta, fs4.base));
|
|
2476
|
+
if (fs4 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
2477
|
+
genealogy.push(fs4);
|
|
2445
2478
|
}
|
|
2446
2479
|
return genealogy;
|
|
2447
2480
|
};
|
|
2448
|
-
const resolveFsSpecializations = (canonicalUrl) => {
|
|
2449
|
-
return resolveFsGenealogy(canonicalUrl).filter((
|
|
2481
|
+
const resolveFsSpecializations = (pkg, canonicalUrl) => {
|
|
2482
|
+
return resolveFsGenealogy(pkg, canonicalUrl).filter((fs4) => fs4.derivation === "specialization");
|
|
2450
2483
|
};
|
|
2451
2484
|
const resolveElementSnapshot = (fhirSchema, path) => {
|
|
2452
|
-
const geneology = resolveFsGenealogy(fhirSchema.url);
|
|
2485
|
+
const geneology = resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
|
|
2453
2486
|
const elemGeneology = resolveFsElementGenealogy(geneology, path);
|
|
2454
2487
|
const elemSnapshot = fsElementSnapshot(elemGeneology);
|
|
2455
2488
|
return elemSnapshot;
|
|
@@ -2468,22 +2501,26 @@ var registerFromManager = async (manager, conf) => {
|
|
|
2468
2501
|
};
|
|
2469
2502
|
return {
|
|
2470
2503
|
...manager,
|
|
2471
|
-
|
|
2472
|
-
const rfs = enrichFHIRSchema(
|
|
2473
|
-
|
|
2474
|
-
|
|
2504
|
+
unsafeAppendFs(fs4) {
|
|
2505
|
+
const rfs = enrichFHIRSchema(fs4);
|
|
2506
|
+
const pkgId = packageMetaToFhir(rfs.package_meta);
|
|
2507
|
+
if (!resolver[pkgId]) resolver[pkgId] = mkEmptyPkgIndex(rfs.package_meta);
|
|
2508
|
+
resolver[pkgId].nameResolution[rfs.name] = rfs.url;
|
|
2509
|
+
resolver[pkgId].fhirSchemas[rfs.url] = rfs;
|
|
2475
2510
|
},
|
|
2476
|
-
resolveFs
|
|
2511
|
+
resolveFs,
|
|
2477
2512
|
resolveFsGenealogy,
|
|
2478
2513
|
resolveFsSpecializations,
|
|
2479
|
-
ensureSpecializationCanonicalUrl
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2514
|
+
ensureSpecializationCanonicalUrl,
|
|
2515
|
+
resolveSd: (_pkg, canonicalUrl) => {
|
|
2516
|
+
const res = packageAgnosticResolveCanonical(resolver, canonicalUrl, logger);
|
|
2517
|
+
if (isStructureDefinition(res)) return res;
|
|
2518
|
+
return void 0;
|
|
2519
|
+
},
|
|
2520
|
+
allFs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.fhirSchemas)),
|
|
2521
|
+
allVs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.valueSets)),
|
|
2522
|
+
resolveVs,
|
|
2523
|
+
resolveAny: (canonicalUrl) => packageAgnosticResolveCanonical(resolver, canonicalUrl, logger),
|
|
2487
2524
|
resolveElementSnapshot,
|
|
2488
2525
|
getAllElementKeys
|
|
2489
2526
|
};
|
|
@@ -2491,9 +2528,9 @@ var registerFromManager = async (manager, conf) => {
|
|
|
2491
2528
|
var resolveFsElementGenealogy = (genealogy, path) => {
|
|
2492
2529
|
const [top, ...rest] = path;
|
|
2493
2530
|
if (top === void 0) return [];
|
|
2494
|
-
return genealogy.map((
|
|
2495
|
-
if (!
|
|
2496
|
-
let elem =
|
|
2531
|
+
return genealogy.map((fs4) => {
|
|
2532
|
+
if (!fs4.elements) return void 0;
|
|
2533
|
+
let elem = fs4.elements?.[top];
|
|
2497
2534
|
for (const k of rest) {
|
|
2498
2535
|
elem = elem?.elements?.[k];
|
|
2499
2536
|
}
|
|
@@ -2501,7 +2538,8 @@ var resolveFsElementGenealogy = (genealogy, path) => {
|
|
|
2501
2538
|
}).filter((elem) => elem !== void 0);
|
|
2502
2539
|
};
|
|
2503
2540
|
function fsElementSnapshot(genealogy) {
|
|
2504
|
-
const
|
|
2541
|
+
const revGenealogy = genealogy.reverse();
|
|
2542
|
+
const snapshot = Object.assign({}, ...revGenealogy);
|
|
2505
2543
|
snapshot.elements = void 0;
|
|
2506
2544
|
return snapshot;
|
|
2507
2545
|
}
|
|
@@ -2532,7 +2570,7 @@ var TypeSchemaGenerator = class {
|
|
|
2532
2570
|
const packageNames = packageMetas.map((meta) => `${meta.name}${meta.version}`);
|
|
2533
2571
|
this.logger?.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
|
|
2534
2572
|
await this.manager.init();
|
|
2535
|
-
return registerFromManager(this.manager);
|
|
2573
|
+
return registerFromManager(this.manager, {});
|
|
2536
2574
|
}
|
|
2537
2575
|
generateFhirSchemas(structureDefinitions) {
|
|
2538
2576
|
this.logger?.progress(`Converting ${structureDefinitions.length} StructureDefinitions to FHIRSchemas`);
|
|
@@ -2606,7 +2644,7 @@ var TypeSchemaGenerator = class {
|
|
|
2606
2644
|
};
|
|
2607
2645
|
const register = await this.registerFromPackageMetas([packageInfo]);
|
|
2608
2646
|
const valueSets = await this.generateValueSetSchemas(register.allVs(), logger);
|
|
2609
|
-
const fhirSchemas = (await Promise.all(register.allFs().map(async (
|
|
2647
|
+
const fhirSchemas = (await Promise.all(register.allFs().map(async (fs4) => await transformFhirSchema(register, fs4, logger)))).flat();
|
|
2610
2648
|
const allSchemas = [...fhirSchemas, ...valueSets];
|
|
2611
2649
|
if (this.cache) {
|
|
2612
2650
|
for (const schema of allSchemas) {
|
|
@@ -3029,6 +3067,451 @@ function deepEqual(obj1, obj2) {
|
|
|
3029
3067
|
if (keys1.length !== keys2.length) return false;
|
|
3030
3068
|
return keys1.every((key) => keys2.includes(key) && deepEqual(obj1[key], obj2[key]));
|
|
3031
3069
|
}
|
|
3070
|
+
var FileSystemWriter = class {
|
|
3071
|
+
opts;
|
|
3072
|
+
currentDir;
|
|
3073
|
+
currentFileDescriptor;
|
|
3074
|
+
writtenFilesSet = /* @__PURE__ */ new Set();
|
|
3075
|
+
constructor(opts) {
|
|
3076
|
+
this.opts = opts;
|
|
3077
|
+
this.currentDir = opts.outputDir;
|
|
3078
|
+
}
|
|
3079
|
+
logger() {
|
|
3080
|
+
return this.opts.logger;
|
|
3081
|
+
}
|
|
3082
|
+
cd(path, gen) {
|
|
3083
|
+
this.currentDir = path.startsWith("/") ? Path4.join(this.opts.outputDir, path) : Path4.join(this.currentDir, path);
|
|
3084
|
+
if (!fs.existsSync(this.currentDir)) {
|
|
3085
|
+
fs.mkdirSync(this.currentDir, { recursive: true });
|
|
3086
|
+
}
|
|
3087
|
+
this.logger()?.debug(`cd '${this.currentDir}'`);
|
|
3088
|
+
gen();
|
|
3089
|
+
}
|
|
3090
|
+
cat(fn, gen) {
|
|
3091
|
+
if (this.currentFileDescriptor) throw new Error("Can't open file in file");
|
|
3092
|
+
if (fn.includes("/")) throw new Error(`Change file path separatly: ${fn}`);
|
|
3093
|
+
const fullFn = `${this.currentDir}/${fn}`;
|
|
3094
|
+
try {
|
|
3095
|
+
this.currentFileDescriptor = fs.openSync(fullFn, "w");
|
|
3096
|
+
this.writtenFilesSet.add(fn);
|
|
3097
|
+
this.logger()?.debug(`cat > '${fullFn}'`);
|
|
3098
|
+
gen();
|
|
3099
|
+
} finally {
|
|
3100
|
+
if (this.currentFileDescriptor) {
|
|
3101
|
+
fs.closeSync(this.currentFileDescriptor);
|
|
3102
|
+
}
|
|
3103
|
+
this.currentFileDescriptor = void 0;
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
write(str) {
|
|
3107
|
+
if (!this.currentFileDescriptor) throw new Error("No file opened");
|
|
3108
|
+
fs.writeSync(this.currentFileDescriptor, str);
|
|
3109
|
+
}
|
|
3110
|
+
generate(_tsIndex) {
|
|
3111
|
+
throw new Error("Not implemented");
|
|
3112
|
+
}
|
|
3113
|
+
writtenFiles() {
|
|
3114
|
+
return Array.from(this.writtenFilesSet);
|
|
3115
|
+
}
|
|
3116
|
+
};
|
|
3117
|
+
var Writer = class extends FileSystemWriter {
|
|
3118
|
+
currentIndent = 0;
|
|
3119
|
+
indent() {
|
|
3120
|
+
this.currentIndent += this.opts.tabSize;
|
|
3121
|
+
}
|
|
3122
|
+
deindent() {
|
|
3123
|
+
this.currentIndent -= this.opts.tabSize;
|
|
3124
|
+
}
|
|
3125
|
+
writeIndent() {
|
|
3126
|
+
this.write(" ".repeat(this.currentIndent));
|
|
3127
|
+
}
|
|
3128
|
+
line(...tokens) {
|
|
3129
|
+
if (tokens.length === 0) {
|
|
3130
|
+
this.write("\n");
|
|
3131
|
+
} else {
|
|
3132
|
+
this.writeIndent();
|
|
3133
|
+
this.write(`${tokens.join(" ")}
|
|
3134
|
+
`);
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
lineSM(...tokens) {
|
|
3138
|
+
this.writeIndent();
|
|
3139
|
+
this.write(`${tokens.join(" ")};
|
|
3140
|
+
`);
|
|
3141
|
+
}
|
|
3142
|
+
comment(...tokens) {
|
|
3143
|
+
const lines = tokens.join(" ").split("\n");
|
|
3144
|
+
for (const line of lines) {
|
|
3145
|
+
this.line(this.opts.commentLinePrefix, line);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
debugComment(...tokens) {
|
|
3149
|
+
if (this.opts.withDebugComment) {
|
|
3150
|
+
tokens = tokens.map((token) => {
|
|
3151
|
+
if (typeof token === "string") {
|
|
3152
|
+
return token;
|
|
3153
|
+
} else {
|
|
3154
|
+
return JSON.stringify(token, null, 2);
|
|
3155
|
+
}
|
|
3156
|
+
});
|
|
3157
|
+
this.comment(...tokens);
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
disclaimer() {
|
|
3161
|
+
return [
|
|
3162
|
+
"WARNING: This file is autogenerated by @atomic-ehr/codegen.",
|
|
3163
|
+
"GitHub: https://github.com/orgs/atomic-ehr/repositories",
|
|
3164
|
+
"Any manual changes made to this file may be overwritten."
|
|
3165
|
+
];
|
|
3166
|
+
}
|
|
3167
|
+
generateDisclaimer() {
|
|
3168
|
+
this.disclaimer().forEach((e) => this.comment(e));
|
|
3169
|
+
this.line();
|
|
3170
|
+
}
|
|
3171
|
+
indentBlock(gencontent) {
|
|
3172
|
+
this.indent();
|
|
3173
|
+
gencontent();
|
|
3174
|
+
this.deindent();
|
|
3175
|
+
}
|
|
3176
|
+
curlyBlock(tokens, gencontent, endTokens) {
|
|
3177
|
+
this.line(`${tokens.filter(Boolean).join(" ")} {`);
|
|
3178
|
+
this.indent();
|
|
3179
|
+
gencontent();
|
|
3180
|
+
this.deindent();
|
|
3181
|
+
this.line(`}${endTokens?.filter(Boolean).join(" ") ?? ""}`);
|
|
3182
|
+
}
|
|
3183
|
+
squareBlock(tokens, gencontent, endTokens) {
|
|
3184
|
+
this.line(`${tokens.filter(Boolean).join(" ")} [`);
|
|
3185
|
+
this.indent();
|
|
3186
|
+
gencontent();
|
|
3187
|
+
this.deindent();
|
|
3188
|
+
this.line(`]${endTokens?.filter(Boolean).join(" ") ?? ""}`);
|
|
3189
|
+
}
|
|
3190
|
+
};
|
|
3191
|
+
|
|
3192
|
+
// src/api/writer-generator/csharp/formatHelper.ts
|
|
3193
|
+
var ops = {
|
|
3194
|
+
"!": "Not",
|
|
3195
|
+
"<=": "LessOrEqual",
|
|
3196
|
+
">=": "GreaterOrEqual",
|
|
3197
|
+
"<": "Less",
|
|
3198
|
+
">": "Greater",
|
|
3199
|
+
"=": "Equal",
|
|
3200
|
+
"-": "Dash",
|
|
3201
|
+
"+": "Plus",
|
|
3202
|
+
"*": "Asterisk",
|
|
3203
|
+
"/": "Slash",
|
|
3204
|
+
"%": "Percent",
|
|
3205
|
+
"&": "And",
|
|
3206
|
+
"|": "Or",
|
|
3207
|
+
"^": "Xor",
|
|
3208
|
+
"~": "Tilde",
|
|
3209
|
+
"?": "Question",
|
|
3210
|
+
".": "Dot"
|
|
3211
|
+
};
|
|
3212
|
+
function formatEnumDashHandle(entry) {
|
|
3213
|
+
return entry.split("-").map((part) => uppercaseFirstLetter(part)).join("-");
|
|
3214
|
+
}
|
|
3215
|
+
function formatEnumEntryOperation(entry) {
|
|
3216
|
+
let res = entry;
|
|
3217
|
+
for (const op in ops) res = res.replaceAll(op, ops[op] ?? "");
|
|
3218
|
+
return res;
|
|
3219
|
+
}
|
|
3220
|
+
function formatEnumNumber(entry) {
|
|
3221
|
+
const num = Number(entry[0]);
|
|
3222
|
+
if (Number.isInteger(num) && !Number.isNaN(num)) {
|
|
3223
|
+
return `_${entry}`;
|
|
3224
|
+
}
|
|
3225
|
+
return entry;
|
|
3226
|
+
}
|
|
3227
|
+
function formatEnumEntry(entry) {
|
|
3228
|
+
let res = formatEnumDashHandle(entry);
|
|
3229
|
+
res = formatEnumNumber(res);
|
|
3230
|
+
res = formatEnumEntryOperation(res);
|
|
3231
|
+
res = uppercaseFirstLetter(res);
|
|
3232
|
+
return res;
|
|
3233
|
+
}
|
|
3234
|
+
function formatName(input) {
|
|
3235
|
+
return uppercaseFirstLetter(camelCase(input.replaceAll(".", "-")));
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
// src/api/writer-generator/csharp/csharp.ts
|
|
3239
|
+
var PRIMITIVE_TYPE_MAP = {
|
|
3240
|
+
boolean: "bool",
|
|
3241
|
+
instant: "string",
|
|
3242
|
+
time: "string",
|
|
3243
|
+
date: "string",
|
|
3244
|
+
dateTime: "string",
|
|
3245
|
+
decimal: "decimal",
|
|
3246
|
+
integer: "int",
|
|
3247
|
+
unsignedInt: "long",
|
|
3248
|
+
positiveInt: "long",
|
|
3249
|
+
integer64: "long",
|
|
3250
|
+
base64Binary: "string",
|
|
3251
|
+
uri: "string",
|
|
3252
|
+
url: "string",
|
|
3253
|
+
canonical: "string",
|
|
3254
|
+
oid: "string",
|
|
3255
|
+
uuid: "string",
|
|
3256
|
+
string: "string",
|
|
3257
|
+
code: "string",
|
|
3258
|
+
markdown: "string",
|
|
3259
|
+
id: "string",
|
|
3260
|
+
xhtml: "string"
|
|
3261
|
+
};
|
|
3262
|
+
var RESERVED_TYPE_NAMES = ["Reference", "Expression"];
|
|
3263
|
+
var getFieldModifiers = (field) => {
|
|
3264
|
+
return field.required ? ["required"] : [];
|
|
3265
|
+
};
|
|
3266
|
+
var formatClassName = (schema) => {
|
|
3267
|
+
const name = prefixReservedTypeName(getResourceName(schema.identifier));
|
|
3268
|
+
return uppercaseFirstLetter(name);
|
|
3269
|
+
};
|
|
3270
|
+
var formatBaseClass = (schema) => {
|
|
3271
|
+
return schema.base ? `: ${schema.base.name}` : "";
|
|
3272
|
+
};
|
|
3273
|
+
var canonicalToName = (canonical, dropFragment = true) => {
|
|
3274
|
+
if (!canonical) return void 0;
|
|
3275
|
+
let localName = canonical.split("/").pop();
|
|
3276
|
+
if (!localName) return void 0;
|
|
3277
|
+
if (dropFragment && localName.includes("#")) localName = localName.split("#")[0];
|
|
3278
|
+
if (!localName) return void 0;
|
|
3279
|
+
if (/^\d/.test(localName)) {
|
|
3280
|
+
localName = `number_${localName}`;
|
|
3281
|
+
}
|
|
3282
|
+
return formatName(localName);
|
|
3283
|
+
};
|
|
3284
|
+
var getResourceName = (id) => {
|
|
3285
|
+
if (id.kind === "nested") {
|
|
3286
|
+
const url = id.url;
|
|
3287
|
+
const path = canonicalToName(url, false);
|
|
3288
|
+
if (!path) return "";
|
|
3289
|
+
const [resourceName, fragment] = path.split("#");
|
|
3290
|
+
const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
|
|
3291
|
+
return formatName([resourceName, name].join(""));
|
|
3292
|
+
}
|
|
3293
|
+
return formatName(id.name);
|
|
3294
|
+
};
|
|
3295
|
+
var isReservedTypeName = (name) => RESERVED_TYPE_NAMES.includes(name);
|
|
3296
|
+
var prefixReservedTypeName = (name) => isReservedTypeName(name) ? `Resource${name}` : name;
|
|
3297
|
+
var CSharp = class extends Writer {
|
|
3298
|
+
enums = {};
|
|
3299
|
+
staticSourceDir;
|
|
3300
|
+
targetNamespace;
|
|
3301
|
+
constructor(options) {
|
|
3302
|
+
super({
|
|
3303
|
+
outputDir: options.outputDir,
|
|
3304
|
+
tabSize: 4,
|
|
3305
|
+
withDebugComment: false,
|
|
3306
|
+
commentLinePrefix: "//",
|
|
3307
|
+
logger: options.logger
|
|
3308
|
+
});
|
|
3309
|
+
this.staticSourceDir = options.staticSourceDir;
|
|
3310
|
+
this.targetNamespace = options.targetNamespace;
|
|
3311
|
+
}
|
|
3312
|
+
generate(typeSchemaIndex) {
|
|
3313
|
+
const complexTypes = typeSchemaIndex.collectComplexTypes();
|
|
3314
|
+
const resources = typeSchemaIndex.collectResources();
|
|
3315
|
+
const packages = Array.from(new Set(resources.map((r) => formatName(r.identifier.package))));
|
|
3316
|
+
this.generateAllFiles(complexTypes, resources, packages);
|
|
3317
|
+
this.copyStaticFiles();
|
|
3318
|
+
}
|
|
3319
|
+
generateAllFiles(complexTypes, resources, packages) {
|
|
3320
|
+
this.generateUsingFile(packages);
|
|
3321
|
+
this.generateBaseTypes(complexTypes);
|
|
3322
|
+
this.generateResources(resources);
|
|
3323
|
+
this.generateEnumFiles(packages);
|
|
3324
|
+
this.generateResourceDictionaries(resources, packages);
|
|
3325
|
+
this.generateHelperFile();
|
|
3326
|
+
}
|
|
3327
|
+
generateType(schema, packageName) {
|
|
3328
|
+
const className = formatClassName(schema);
|
|
3329
|
+
const baseClass = formatBaseClass(schema);
|
|
3330
|
+
this.curlyBlock(["public", "class", className, baseClass], () => {
|
|
3331
|
+
this.generateFields(schema, packageName);
|
|
3332
|
+
this.generateNestedTypes(schema, packageName);
|
|
3333
|
+
this.line();
|
|
3334
|
+
this.includeHelperMethods();
|
|
3335
|
+
});
|
|
3336
|
+
this.line();
|
|
3337
|
+
}
|
|
3338
|
+
generateFields(schema, packageName) {
|
|
3339
|
+
if (!schema.fields) return;
|
|
3340
|
+
const sortedFields = Object.entries(schema.fields).sort(([a], [b]) => a.localeCompare(b));
|
|
3341
|
+
for (const [fieldName, field] of sortedFields) {
|
|
3342
|
+
this.generateField(fieldName, field, packageName);
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
generateNestedTypes(schema, packageName) {
|
|
3346
|
+
if (!("nested" in schema) || !schema.nested) return;
|
|
3347
|
+
this.line();
|
|
3348
|
+
for (const subtype of schema.nested) {
|
|
3349
|
+
this.generateType(subtype, packageName);
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
generateField(fieldName, field, packageName) {
|
|
3353
|
+
try {
|
|
3354
|
+
if (isChoiceDeclarationField(field)) return;
|
|
3355
|
+
const fieldDeclaration = this.buildFieldDeclaration(fieldName, field, packageName);
|
|
3356
|
+
this.line(...fieldDeclaration);
|
|
3357
|
+
} catch (error) {
|
|
3358
|
+
this.logger()?.error(`Error processing field ${fieldName}: ${error.message}`);
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
buildFieldDeclaration(fieldName, field, packageName) {
|
|
3362
|
+
const fieldType = this.determineFieldType(fieldName, field, packageName);
|
|
3363
|
+
const modifiers = getFieldModifiers(field);
|
|
3364
|
+
const propertyName = pascalCase(fieldName);
|
|
3365
|
+
const accessors = "{ get; set; }";
|
|
3366
|
+
return ["public", ...modifiers, fieldType, propertyName, accessors].filter(Boolean);
|
|
3367
|
+
}
|
|
3368
|
+
determineFieldType(fieldName, field, packageName) {
|
|
3369
|
+
let typeName = this.getBaseTypeName(field);
|
|
3370
|
+
if ("enum" in field && field.enum) {
|
|
3371
|
+
typeName = this.registerAndGetEnumType(fieldName, field, packageName);
|
|
3372
|
+
}
|
|
3373
|
+
typeName = prefixReservedTypeName(typeName);
|
|
3374
|
+
const baseNamespacePrefix = "";
|
|
3375
|
+
const nullable = field.required ? "" : "?";
|
|
3376
|
+
const arraySpecifier = field.array ? "[]" : "";
|
|
3377
|
+
return `${baseNamespacePrefix}${typeName}${arraySpecifier}${nullable}`;
|
|
3378
|
+
}
|
|
3379
|
+
getBaseTypeName(field) {
|
|
3380
|
+
if ("type" in field) {
|
|
3381
|
+
let typeName = field.type.name.toString();
|
|
3382
|
+
if (field.type.kind === "nested") {
|
|
3383
|
+
typeName = getResourceName(field.type);
|
|
3384
|
+
} else if (field.type.kind === "primitive-type") typeName = PRIMITIVE_TYPE_MAP[field.type.name] ?? "string";
|
|
3385
|
+
return typeName;
|
|
3386
|
+
}
|
|
3387
|
+
return "";
|
|
3388
|
+
}
|
|
3389
|
+
registerAndGetEnumType(fieldName, field, packageName) {
|
|
3390
|
+
const enumName = formatName(field.binding?.name ?? fieldName);
|
|
3391
|
+
const enumTypeName = `${enumName}Enum`;
|
|
3392
|
+
if (!this.enums[packageName]) this.enums[packageName] = {};
|
|
3393
|
+
if (field.enum) this.enums[packageName][enumTypeName] = field.enum;
|
|
3394
|
+
return enumTypeName;
|
|
3395
|
+
}
|
|
3396
|
+
includeHelperMethods() {
|
|
3397
|
+
this.line("public override string ToString() => ");
|
|
3398
|
+
this.line(" JsonSerializer.Serialize(this, Helper.JsonSerializerOptions);");
|
|
3399
|
+
this.line();
|
|
3400
|
+
}
|
|
3401
|
+
generateUsingFile(packages) {
|
|
3402
|
+
this.cd("/", async () => {
|
|
3403
|
+
this.cat("Usings.cs", () => {
|
|
3404
|
+
this.generateDisclaimer();
|
|
3405
|
+
this.generateGlobalUsings(packages);
|
|
3406
|
+
});
|
|
3407
|
+
});
|
|
3408
|
+
}
|
|
3409
|
+
generateGlobalUsings(packages) {
|
|
3410
|
+
const globalUsings = [
|
|
3411
|
+
"CSharpSDK",
|
|
3412
|
+
"System.Text.Json",
|
|
3413
|
+
"System.Text.Json.Serialization",
|
|
3414
|
+
this.targetNamespace,
|
|
3415
|
+
...packages.map((pkg) => `${this.targetNamespace}.${pkg}`)
|
|
3416
|
+
];
|
|
3417
|
+
for (const using of globalUsings) this.lineSM("global", "using", using);
|
|
3418
|
+
}
|
|
3419
|
+
generateBaseTypes(complexTypes) {
|
|
3420
|
+
this.cd("/", async () => {
|
|
3421
|
+
this.cat("base.cs", () => {
|
|
3422
|
+
this.generateDisclaimer();
|
|
3423
|
+
this.line();
|
|
3424
|
+
this.lineSM("namespace", this.targetNamespace);
|
|
3425
|
+
for (const schema of complexTypes) {
|
|
3426
|
+
const packageName = formatName(schema.identifier.package);
|
|
3427
|
+
this.generateType(schema, packageName);
|
|
3428
|
+
}
|
|
3429
|
+
});
|
|
3430
|
+
});
|
|
3431
|
+
}
|
|
3432
|
+
generateResources(resources) {
|
|
3433
|
+
for (const schema of resources) this.generateResourceFile(schema);
|
|
3434
|
+
}
|
|
3435
|
+
generateResourceFile(schema) {
|
|
3436
|
+
const packageName = formatName(schema.identifier.package);
|
|
3437
|
+
this.cd(`/${packageName}`, async () => {
|
|
3438
|
+
this.cat(`${schema.identifier.name}.cs`, () => {
|
|
3439
|
+
this.generateDisclaimer();
|
|
3440
|
+
this.line();
|
|
3441
|
+
this.lineSM("namespace", `${this.targetNamespace}.${packageName}`);
|
|
3442
|
+
this.line();
|
|
3443
|
+
this.generateType(schema, packageName);
|
|
3444
|
+
});
|
|
3445
|
+
});
|
|
3446
|
+
}
|
|
3447
|
+
generateEnumFiles(packages) {
|
|
3448
|
+
for (const packageName of packages) {
|
|
3449
|
+
this.generatePackageEnums(packageName);
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
generatePackageEnums(packageName) {
|
|
3453
|
+
const packageEnums = this.enums[packageName];
|
|
3454
|
+
if (!packageEnums || Object.keys(packageEnums).length === 0) return;
|
|
3455
|
+
this.cd(`/${packageName}`, async () => {
|
|
3456
|
+
this.cat(`${packageName}Enums.cs`, () => {
|
|
3457
|
+
this.generateDisclaimer();
|
|
3458
|
+
this.generateEnumFileContent(packageName, packageEnums);
|
|
3459
|
+
});
|
|
3460
|
+
});
|
|
3461
|
+
}
|
|
3462
|
+
generateEnumFileContent(packageName, enums) {
|
|
3463
|
+
this.lineSM("using", "System.ComponentModel");
|
|
3464
|
+
this.line();
|
|
3465
|
+
this.lineSM(`namespace ${this.targetNamespace}.${packageName}`);
|
|
3466
|
+
for (const [enumName, values] of Object.entries(enums)) {
|
|
3467
|
+
this.generateEnum(enumName, values);
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
generateEnum(enumName, values) {
|
|
3471
|
+
this.curlyBlock(["public", "enum", enumName], () => {
|
|
3472
|
+
for (const value of values) {
|
|
3473
|
+
this.line(`[Description("${value}")]`);
|
|
3474
|
+
this.line(`${formatEnumEntry(value)},`);
|
|
3475
|
+
}
|
|
3476
|
+
});
|
|
3477
|
+
this.line();
|
|
3478
|
+
}
|
|
3479
|
+
generateResourceDictionaries(resources, packages) {
|
|
3480
|
+
this.cd("/", async () => {
|
|
3481
|
+
for (const packageName of packages) {
|
|
3482
|
+
const packageResources = resources.filter((r) => formatName(r.identifier.package) === packageName);
|
|
3483
|
+
if (packageResources.length === 0) return;
|
|
3484
|
+
this.cat(`${packageName}ResourceDictionary.cs`, () => {
|
|
3485
|
+
this.generateDisclaimer();
|
|
3486
|
+
this.line();
|
|
3487
|
+
this.lineSM(`namespace ${this.targetNamespace}`);
|
|
3488
|
+
this.generateResourceDictionaryClass(packageName, packageResources);
|
|
3489
|
+
});
|
|
3490
|
+
}
|
|
3491
|
+
});
|
|
3492
|
+
}
|
|
3493
|
+
generateResourceDictionaryClass(packageName, resources) {
|
|
3494
|
+
this.curlyBlock(["public", "static", "class", "ResourceDictionary"], () => {
|
|
3495
|
+
this.curlyBlock(["public static readonly Dictionary<Type, string> Map = new()"], () => {
|
|
3496
|
+
for (const schema of resources) {
|
|
3497
|
+
const typeName = schema.identifier.name;
|
|
3498
|
+
this.line(`{ typeof(${packageName}.${typeName}), "${typeName}" },`);
|
|
3499
|
+
}
|
|
3500
|
+
});
|
|
3501
|
+
this.lineSM();
|
|
3502
|
+
});
|
|
3503
|
+
}
|
|
3504
|
+
copyStaticFiles() {
|
|
3505
|
+
if (!this.staticSourceDir) return;
|
|
3506
|
+
const sourcePath = Path4__default.resolve(this.staticSourceDir);
|
|
3507
|
+
fs__default.cpSync(sourcePath, this.opts.outputDir, { recursive: true });
|
|
3508
|
+
}
|
|
3509
|
+
generateHelperFile() {
|
|
3510
|
+
const sourceFile = "src/api/writer-generator/csharp/Helper.cs";
|
|
3511
|
+
const destFile = Path4__default.join(this.opts.outputDir, "Helper.cs");
|
|
3512
|
+
fs__default.copyFileSync(sourceFile, destFile);
|
|
3513
|
+
}
|
|
3514
|
+
};
|
|
3032
3515
|
|
|
3033
3516
|
// src/typeschema/utils.ts
|
|
3034
3517
|
var groupByPackages = (typeSchemas) => {
|
|
@@ -5205,127 +5688,6 @@ ${nestedInterfaces}`;
|
|
|
5205
5688
|
);
|
|
5206
5689
|
}
|
|
5207
5690
|
};
|
|
5208
|
-
var FileSystemWriter = class {
|
|
5209
|
-
opts;
|
|
5210
|
-
currentDir;
|
|
5211
|
-
currentFileDescriptor;
|
|
5212
|
-
writtenFilesSet = /* @__PURE__ */ new Set();
|
|
5213
|
-
constructor(opts) {
|
|
5214
|
-
this.opts = opts;
|
|
5215
|
-
this.currentDir = opts.outputDir;
|
|
5216
|
-
}
|
|
5217
|
-
logger() {
|
|
5218
|
-
return this.opts.logger;
|
|
5219
|
-
}
|
|
5220
|
-
cd(path, gen) {
|
|
5221
|
-
this.currentDir = path.startsWith("/") ? Path2.join(this.opts.outputDir, path) : Path2.join(this.currentDir, path);
|
|
5222
|
-
if (!fs.existsSync(this.currentDir)) {
|
|
5223
|
-
fs.mkdirSync(this.currentDir, { recursive: true });
|
|
5224
|
-
}
|
|
5225
|
-
this.logger()?.debug(`cd '${this.currentDir}'`);
|
|
5226
|
-
gen();
|
|
5227
|
-
}
|
|
5228
|
-
cat(fn, gen) {
|
|
5229
|
-
if (this.currentFileDescriptor) throw new Error("Can't open file in file");
|
|
5230
|
-
if (fn.includes("/")) throw new Error(`Change file path separatly: ${fn}`);
|
|
5231
|
-
const fullFn = `${this.currentDir}/${fn}`;
|
|
5232
|
-
try {
|
|
5233
|
-
this.currentFileDescriptor = fs.openSync(fullFn, "w");
|
|
5234
|
-
this.writtenFilesSet.add(fn);
|
|
5235
|
-
this.logger()?.debug(`cat > '${fullFn}'`);
|
|
5236
|
-
gen();
|
|
5237
|
-
} finally {
|
|
5238
|
-
if (this.currentFileDescriptor) {
|
|
5239
|
-
fs.closeSync(this.currentFileDescriptor);
|
|
5240
|
-
}
|
|
5241
|
-
this.currentFileDescriptor = void 0;
|
|
5242
|
-
}
|
|
5243
|
-
}
|
|
5244
|
-
write(str) {
|
|
5245
|
-
if (!this.currentFileDescriptor) throw new Error("No file opened");
|
|
5246
|
-
fs.writeSync(this.currentFileDescriptor, str);
|
|
5247
|
-
}
|
|
5248
|
-
generate(_tsIndex) {
|
|
5249
|
-
throw new Error("Not implemented");
|
|
5250
|
-
}
|
|
5251
|
-
writtenFiles() {
|
|
5252
|
-
return Array.from(this.writtenFilesSet);
|
|
5253
|
-
}
|
|
5254
|
-
};
|
|
5255
|
-
var Writer = class extends FileSystemWriter {
|
|
5256
|
-
currentIndent = 0;
|
|
5257
|
-
indent() {
|
|
5258
|
-
this.currentIndent += this.opts.tabSize;
|
|
5259
|
-
}
|
|
5260
|
-
deindent() {
|
|
5261
|
-
this.currentIndent -= this.opts.tabSize;
|
|
5262
|
-
}
|
|
5263
|
-
writeIndent() {
|
|
5264
|
-
this.write(" ".repeat(this.currentIndent));
|
|
5265
|
-
}
|
|
5266
|
-
line(...tokens) {
|
|
5267
|
-
if (tokens.length === 0) {
|
|
5268
|
-
this.write("\n");
|
|
5269
|
-
} else {
|
|
5270
|
-
this.writeIndent();
|
|
5271
|
-
this.write(`${tokens.join(" ")}
|
|
5272
|
-
`);
|
|
5273
|
-
}
|
|
5274
|
-
}
|
|
5275
|
-
lineSM(...tokens) {
|
|
5276
|
-
this.writeIndent();
|
|
5277
|
-
this.write(`${tokens.join(" ")};
|
|
5278
|
-
`);
|
|
5279
|
-
}
|
|
5280
|
-
comment(...tokens) {
|
|
5281
|
-
const lines = tokens.join(" ").split("\n");
|
|
5282
|
-
for (const line of lines) {
|
|
5283
|
-
this.line(this.opts.commentLinePrefix, line);
|
|
5284
|
-
}
|
|
5285
|
-
}
|
|
5286
|
-
debugComment(...tokens) {
|
|
5287
|
-
if (this.opts.withDebugComment) {
|
|
5288
|
-
tokens = tokens.map((token) => {
|
|
5289
|
-
if (typeof token === "string") {
|
|
5290
|
-
return token;
|
|
5291
|
-
} else {
|
|
5292
|
-
return JSON.stringify(token, null, 2);
|
|
5293
|
-
}
|
|
5294
|
-
});
|
|
5295
|
-
this.comment(...tokens);
|
|
5296
|
-
}
|
|
5297
|
-
}
|
|
5298
|
-
disclaimer() {
|
|
5299
|
-
return [
|
|
5300
|
-
"WARNING: This file is autogenerated by @atomic-ehr/codegen.",
|
|
5301
|
-
"GitHub: https://github.com/orgs/atomic-ehr/repositories",
|
|
5302
|
-
"Any manual changes made to this file may be overwritten."
|
|
5303
|
-
];
|
|
5304
|
-
}
|
|
5305
|
-
generateDisclaimer() {
|
|
5306
|
-
this.disclaimer().forEach((e) => this.comment(e));
|
|
5307
|
-
this.line();
|
|
5308
|
-
}
|
|
5309
|
-
indentBlock(gencontent) {
|
|
5310
|
-
this.indent();
|
|
5311
|
-
gencontent();
|
|
5312
|
-
this.deindent();
|
|
5313
|
-
}
|
|
5314
|
-
curlyBlock(tokens, gencontent, endTokens) {
|
|
5315
|
-
this.line(`${tokens.filter(Boolean).join(" ")} {`);
|
|
5316
|
-
this.indent();
|
|
5317
|
-
gencontent();
|
|
5318
|
-
this.deindent();
|
|
5319
|
-
this.line(`}${endTokens?.filter(Boolean).join(" ") ?? ""}`);
|
|
5320
|
-
}
|
|
5321
|
-
squareBlock(tokens, gencontent, endTokens) {
|
|
5322
|
-
this.line(`${tokens.filter(Boolean).join(" ")} [`);
|
|
5323
|
-
this.indent();
|
|
5324
|
-
gencontent();
|
|
5325
|
-
this.deindent();
|
|
5326
|
-
this.line(`]${endTokens?.filter(Boolean).join(" ") ?? ""}`);
|
|
5327
|
-
}
|
|
5328
|
-
};
|
|
5329
5691
|
|
|
5330
5692
|
// src/api/writer-generator/typescript.ts
|
|
5331
5693
|
var primitiveType2tsType = {
|
|
@@ -5366,7 +5728,7 @@ var tsModuleName = (id) => {
|
|
|
5366
5728
|
var tsModuleFileName = (id) => {
|
|
5367
5729
|
return `${tsModuleName(id)}.ts`;
|
|
5368
5730
|
};
|
|
5369
|
-
var
|
|
5731
|
+
var canonicalToName2 = (canonical, dropFragment = true) => {
|
|
5370
5732
|
if (!canonical) return void 0;
|
|
5371
5733
|
let localName = canonical.split("/").pop();
|
|
5372
5734
|
if (!localName) return void 0;
|
|
@@ -5382,7 +5744,7 @@ var canonicalToName = (canonical, dropFragment = true) => {
|
|
|
5382
5744
|
var tsResourceName = (id) => {
|
|
5383
5745
|
if (id.kind === "nested") {
|
|
5384
5746
|
const url = id.url;
|
|
5385
|
-
const path =
|
|
5747
|
+
const path = canonicalToName2(url, false);
|
|
5386
5748
|
if (!path) return "";
|
|
5387
5749
|
const [resourceName, fragment] = path.split("#");
|
|
5388
5750
|
const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
|
|
@@ -5436,7 +5798,7 @@ var TypeScript = class extends Writer {
|
|
|
5436
5798
|
});
|
|
5437
5799
|
} else if (isNestedIdentifier(dep)) {
|
|
5438
5800
|
imports.push({
|
|
5439
|
-
tsPackage: `../${kebabCase(dep.package)}/${pascalCase(
|
|
5801
|
+
tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName2(dep.url) ?? "")}`,
|
|
5440
5802
|
name: tsResourceName(dep)
|
|
5441
5803
|
});
|
|
5442
5804
|
} else {
|
|
@@ -5481,7 +5843,7 @@ var TypeScript = class extends Writer {
|
|
|
5481
5843
|
name = tsResourceName(schema.identifier);
|
|
5482
5844
|
}
|
|
5483
5845
|
let extendsClause;
|
|
5484
|
-
if (schema.base) extendsClause = `extends ${
|
|
5846
|
+
if (schema.base) extendsClause = `extends ${canonicalToName2(schema.base.url)}`;
|
|
5485
5847
|
this.debugComment(schema.identifier);
|
|
5486
5848
|
this.curlyBlock(["export", "interface", name, extendsClause], () => {
|
|
5487
5849
|
if (isResourceTypeSchema(schema)) {
|
|
@@ -5721,7 +6083,7 @@ var writerToGenerator = (writerGen) => {
|
|
|
5721
6083
|
const getGeneratedFiles = () => {
|
|
5722
6084
|
return writerGen.writtenFiles().map((fn) => {
|
|
5723
6085
|
return {
|
|
5724
|
-
path:
|
|
6086
|
+
path: Path4.normalize(Path4.join(writerGen.opts.outputDir, fn)),
|
|
5725
6087
|
filename: fn.replace(/^.*[\\/]/, ""),
|
|
5726
6088
|
content: "",
|
|
5727
6089
|
exports: [],
|
|
@@ -5821,7 +6183,7 @@ var APIBuilder = class _APIBuilder {
|
|
|
5821
6183
|
}
|
|
5822
6184
|
typescript2(opts) {
|
|
5823
6185
|
const writerOpts = {
|
|
5824
|
-
outputDir:
|
|
6186
|
+
outputDir: Path4.join(this.options.outputDir, "/types"),
|
|
5825
6187
|
tabSize: 4,
|
|
5826
6188
|
withDebugComment: false,
|
|
5827
6189
|
commentLinePrefix: "//"
|
|
@@ -5832,6 +6194,24 @@ var APIBuilder = class _APIBuilder {
|
|
|
5832
6194
|
this.logger.debug(`Configured TypeScript2 generator (${JSON.stringify(effectiveOpts, void 0, 2)})`);
|
|
5833
6195
|
return this;
|
|
5834
6196
|
}
|
|
6197
|
+
csharp(namespace, staticSourceDir) {
|
|
6198
|
+
const generator = writerToGenerator(
|
|
6199
|
+
new CSharp({
|
|
6200
|
+
outputDir: Path4.join(this.options.outputDir, "/types"),
|
|
6201
|
+
staticSourceDir: staticSourceDir ?? void 0,
|
|
6202
|
+
targetNamespace: namespace,
|
|
6203
|
+
logger: new CodegenLogger({
|
|
6204
|
+
prefix: "C#",
|
|
6205
|
+
timestamp: true,
|
|
6206
|
+
verbose: true,
|
|
6207
|
+
suppressLoggingLevel: []
|
|
6208
|
+
})
|
|
6209
|
+
})
|
|
6210
|
+
);
|
|
6211
|
+
this.generators.set("C#", generator);
|
|
6212
|
+
this.logger.debug(`Configured C# generator`);
|
|
6213
|
+
return this;
|
|
6214
|
+
}
|
|
5835
6215
|
/**
|
|
5836
6216
|
* Set a progress callback for monitoring generation
|
|
5837
6217
|
*/
|
|
@@ -5870,22 +6250,22 @@ var APIBuilder = class _APIBuilder {
|
|
|
5870
6250
|
return this;
|
|
5871
6251
|
}
|
|
5872
6252
|
static async isIdenticalTo(path, tsJSON) {
|
|
5873
|
-
if (!await
|
|
5874
|
-
const json = await
|
|
6253
|
+
if (!await afs2.exists(path)) return false;
|
|
6254
|
+
const json = await afs2.readFile(path);
|
|
5875
6255
|
const ts1 = JSON.parse(json.toString());
|
|
5876
6256
|
const ts2 = JSON.parse(tsJSON);
|
|
5877
6257
|
return deepEqual(ts1, ts2);
|
|
5878
6258
|
}
|
|
5879
6259
|
async writeTypeSchemasToSeparateFiles(typeSchemas, outputDir) {
|
|
5880
6260
|
if (this.options.cleanOutput) fs.rmSync(outputDir, { recursive: true, force: true });
|
|
5881
|
-
await
|
|
6261
|
+
await afs2.mkdir(outputDir, { recursive: true });
|
|
5882
6262
|
const usedNames = {};
|
|
5883
6263
|
this.logger.info(`Writing TypeSchema files to ${outputDir}...`);
|
|
5884
6264
|
for (const ts of typeSchemas) {
|
|
5885
6265
|
const package_name = camelCase(ts.identifier.package.replaceAll("/", "-"));
|
|
5886
6266
|
const name = normalizeFileName(ts.identifier.name.toString());
|
|
5887
6267
|
const json = JSON.stringify(ts, null, 2);
|
|
5888
|
-
const baseName =
|
|
6268
|
+
const baseName = Path4.join(outputDir, package_name, name);
|
|
5889
6269
|
let fullName;
|
|
5890
6270
|
if (usedNames[baseName] !== void 0) {
|
|
5891
6271
|
usedNames[baseName]++;
|
|
@@ -5895,24 +6275,24 @@ var APIBuilder = class _APIBuilder {
|
|
|
5895
6275
|
fullName = `${baseName}.typeschema.json`;
|
|
5896
6276
|
}
|
|
5897
6277
|
if (await _APIBuilder.isIdenticalTo(fullName, json)) continue;
|
|
5898
|
-
await
|
|
5899
|
-
await
|
|
6278
|
+
await afs2.mkdir(Path4.dirname(fullName), { recursive: true });
|
|
6279
|
+
await afs2.writeFile(fullName, json);
|
|
5900
6280
|
}
|
|
5901
6281
|
}
|
|
5902
6282
|
async writeTypeSchemasToSingleFile(typeSchemas, outputFile) {
|
|
5903
6283
|
if (this.options.cleanOutput && fs.existsSync(outputFile)) fs.rmSync(outputFile);
|
|
5904
|
-
await
|
|
6284
|
+
await afs2.mkdir(Path4.dirname(outputFile), { recursive: true });
|
|
5905
6285
|
this.logger.info(`Writing TypeSchemas to one file ${outputFile}...`);
|
|
5906
6286
|
for (const ts of typeSchemas) {
|
|
5907
6287
|
const json = JSON.stringify(ts, null, 2);
|
|
5908
|
-
await
|
|
6288
|
+
await afs2.appendFile(outputFile, json + "\n");
|
|
5909
6289
|
}
|
|
5910
6290
|
}
|
|
5911
6291
|
async tryWriteTypeSchema(typeSchemas) {
|
|
5912
6292
|
if (!this.options.typeSchemaOutputDir) return;
|
|
5913
6293
|
try {
|
|
5914
6294
|
this.logger.info(`Starting writing TypeSchema files.`);
|
|
5915
|
-
if (
|
|
6295
|
+
if (Path4.extname(this.options.typeSchemaOutputDir) === ".ndjson")
|
|
5916
6296
|
await this.writeTypeSchemasToSingleFile(typeSchemas, this.options.typeSchemaOutputDir);
|
|
5917
6297
|
else await this.writeTypeSchemasToSeparateFiles(typeSchemas, this.options.typeSchemaOutputDir);
|
|
5918
6298
|
this.logger.info(`Finished writing TypeSchema files.`);
|