@atomic-ehr/codegen 0.0.4 → 0.0.5-canary.20251226085624.be72273
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/LICENSE +21 -0
- package/README.md +210 -260
- package/assets/api/writer-generator/csharp/Client.cs +333 -0
- package/assets/api/writer-generator/csharp/Helper.cs +19 -0
- package/assets/api/writer-generator/python/requirements.txt +5 -0
- package/assets/api/writer-generator/python/resource_family_validator.py +92 -0
- package/dist/cli/index.js +13 -13
- package/dist/index.d.ts +120 -29
- package/dist/index.js +2062 -574
- package/dist/index.js.map +1 -1
- package/package.json +18 -12
package/dist/index.js
CHANGED
|
@@ -1,17 +1,183 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
1
2
|
import * as fs from 'fs';
|
|
2
3
|
import fs__default, { existsSync } from 'fs';
|
|
3
4
|
import * as afs2 from 'fs/promises';
|
|
4
5
|
import { readFile } from 'fs/promises';
|
|
5
|
-
import * as
|
|
6
|
-
import
|
|
6
|
+
import * as Path from 'path';
|
|
7
|
+
import Path__default, { resolve } from 'path';
|
|
7
8
|
import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import assert3 from 'assert';
|
|
11
|
+
import * as YAML from 'yaml';
|
|
8
12
|
import * as fhirschema from '@atomic-ehr/fhirschema';
|
|
9
13
|
import { isStructureDefinition } from '@atomic-ehr/fhirschema';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
14
|
+
import { spawn } from 'child_process';
|
|
15
|
+
import * as util from 'util';
|
|
16
|
+
import Mustache from 'mustache';
|
|
13
17
|
|
|
14
|
-
// src/
|
|
18
|
+
// src/utils/codegen-logger.ts
|
|
19
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
20
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
21
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
22
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
23
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
24
|
+
LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
|
|
25
|
+
return LogLevel2;
|
|
26
|
+
})(LogLevel || {});
|
|
27
|
+
var parseLogLevel = (level) => {
|
|
28
|
+
switch (level.toUpperCase()) {
|
|
29
|
+
case "DEBUG":
|
|
30
|
+
return 0 /* DEBUG */;
|
|
31
|
+
case "INFO":
|
|
32
|
+
return 1 /* INFO */;
|
|
33
|
+
case "WARN":
|
|
34
|
+
return 2 /* WARN */;
|
|
35
|
+
case "ERROR":
|
|
36
|
+
return 3 /* ERROR */;
|
|
37
|
+
case "SILENT":
|
|
38
|
+
return 4 /* SILENT */;
|
|
39
|
+
default:
|
|
40
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var CodegenLogger = class _CodegenLogger {
|
|
44
|
+
options;
|
|
45
|
+
dryWarnSet = /* @__PURE__ */ new Set();
|
|
46
|
+
constructor(options = {}) {
|
|
47
|
+
this.options = {
|
|
48
|
+
timestamp: false,
|
|
49
|
+
level: 1 /* INFO */,
|
|
50
|
+
...options
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Check if a message at the given level should be logged
|
|
55
|
+
*/
|
|
56
|
+
shouldLog(messageLevel) {
|
|
57
|
+
const currentLevel = this.options.level ?? 1 /* INFO */;
|
|
58
|
+
return messageLevel >= currentLevel;
|
|
59
|
+
}
|
|
60
|
+
static consoleLevelsMap = {
|
|
61
|
+
[1 /* INFO */]: console.log,
|
|
62
|
+
[2 /* WARN */]: console.warn,
|
|
63
|
+
[3 /* ERROR */]: console.error,
|
|
64
|
+
[0 /* DEBUG */]: console.log,
|
|
65
|
+
[4 /* SILENT */]: () => {
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
formatMessage(level, message, color) {
|
|
69
|
+
const timestamp = this.options.timestamp ? `${pc.gray((/* @__PURE__ */ new Date()).toLocaleTimeString())} ` : "";
|
|
70
|
+
const prefix = this.options.prefix ? `${pc.cyan(`[${this.options.prefix}]`)} ` : "";
|
|
71
|
+
return `${timestamp}${color(level)} ${prefix}${message}`;
|
|
72
|
+
}
|
|
73
|
+
isSuppressed(level) {
|
|
74
|
+
return this.options.suppressLoggingLevel === "all" || this.options.suppressLoggingLevel?.includes(level) || false;
|
|
75
|
+
}
|
|
76
|
+
tryWriteToConsole(level, formattedMessage) {
|
|
77
|
+
if (this.isSuppressed(level)) return;
|
|
78
|
+
if (!this.shouldLog(level)) return;
|
|
79
|
+
const logFn = _CodegenLogger.consoleLevelsMap[level] || console.log;
|
|
80
|
+
logFn(formattedMessage);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Success message with checkmark
|
|
84
|
+
*/
|
|
85
|
+
success(message) {
|
|
86
|
+
this.tryWriteToConsole(1 /* INFO */, this.formatMessage("", message, pc.green));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Error message with X mark
|
|
90
|
+
*/
|
|
91
|
+
error(message, error) {
|
|
92
|
+
if (this.isSuppressed(3 /* ERROR */)) return;
|
|
93
|
+
if (!this.shouldLog(3 /* ERROR */)) return;
|
|
94
|
+
console.error(this.formatMessage("X", message, pc.red));
|
|
95
|
+
const showDetails = this.options.level === 0 /* DEBUG */;
|
|
96
|
+
if (error && showDetails) {
|
|
97
|
+
console.error(pc.red(` ${error.message}`));
|
|
98
|
+
if (error.stack) {
|
|
99
|
+
console.error(pc.gray(error.stack));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Warning message with warning sign
|
|
105
|
+
*/
|
|
106
|
+
warn(message) {
|
|
107
|
+
this.tryWriteToConsole(2 /* WARN */, this.formatMessage("!", message, pc.yellow));
|
|
108
|
+
}
|
|
109
|
+
dry_warn(message) {
|
|
110
|
+
if (!this.dryWarnSet.has(message)) {
|
|
111
|
+
this.warn(message);
|
|
112
|
+
this.dryWarnSet.add(message);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Info message with info icon
|
|
117
|
+
*/
|
|
118
|
+
info(message) {
|
|
119
|
+
this.tryWriteToConsole(1 /* INFO */, this.formatMessage("i", message, pc.blue));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Debug message (only shows when log level is DEBUG or verbose is true)
|
|
123
|
+
*/
|
|
124
|
+
debug(message) {
|
|
125
|
+
if (this.shouldLog(0 /* DEBUG */)) {
|
|
126
|
+
this.tryWriteToConsole(0 /* DEBUG */, this.formatMessage("\u{1F41B}", message, pc.magenta));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Step message with rocket
|
|
131
|
+
*/
|
|
132
|
+
step(message) {
|
|
133
|
+
this.tryWriteToConsole(1 /* INFO */, this.formatMessage("\u{1F680}", message, pc.cyan));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Progress message with clock
|
|
137
|
+
*/
|
|
138
|
+
progress(message) {
|
|
139
|
+
this.tryWriteToConsole(1 /* INFO */, this.formatMessage("\u23F3", message, pc.blue));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Plain message (no icon, just colored text)
|
|
143
|
+
*/
|
|
144
|
+
plain(message, color = (s) => s) {
|
|
145
|
+
const timestamp = this.options.timestamp ? `${pc.gray((/* @__PURE__ */ new Date()).toLocaleTimeString())} ` : "";
|
|
146
|
+
const prefix = this.options.prefix ? `${pc.cyan(`[${this.options.prefix}]`)} ` : "";
|
|
147
|
+
this.tryWriteToConsole(1 /* INFO */, `${timestamp}${prefix}${color(message)}`);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Dimmed/gray text for less important info
|
|
151
|
+
*/
|
|
152
|
+
dim(message) {
|
|
153
|
+
this.plain(message, pc.gray);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Create a child logger with a prefix
|
|
157
|
+
*/
|
|
158
|
+
child(prefix) {
|
|
159
|
+
return new _CodegenLogger({
|
|
160
|
+
...this.options,
|
|
161
|
+
prefix: this.options.prefix ? `${this.options.prefix}:${prefix}` : prefix
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Update options
|
|
166
|
+
*/
|
|
167
|
+
configure(options) {
|
|
168
|
+
this.options = { ...this.options, ...options };
|
|
169
|
+
}
|
|
170
|
+
getLevel() {
|
|
171
|
+
return this.options.level ?? 1 /* INFO */;
|
|
172
|
+
}
|
|
173
|
+
setLevel(level) {
|
|
174
|
+
this.options.level = level;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
new CodegenLogger();
|
|
178
|
+
function createLogger(options = {}) {
|
|
179
|
+
return new CodegenLogger(options);
|
|
180
|
+
}
|
|
15
181
|
|
|
16
182
|
// src/api/writer-generator/utils.ts
|
|
17
183
|
var words = (s) => {
|
|
@@ -32,6 +198,9 @@ var camelCase = (s) => {
|
|
|
32
198
|
var pascalCase = (s) => {
|
|
33
199
|
return words(s).map(capitalCase).join("");
|
|
34
200
|
};
|
|
201
|
+
var snakeCase = (s) => {
|
|
202
|
+
return words(s).map((s2) => s2.toLowerCase()).join("_");
|
|
203
|
+
};
|
|
35
204
|
var uppercaseFirstLetter = (str) => {
|
|
36
205
|
if (!str || str.length === 0) return str;
|
|
37
206
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
@@ -78,7 +247,7 @@ var FileSystemWriter = class {
|
|
|
78
247
|
}
|
|
79
248
|
cd(path, gen) {
|
|
80
249
|
const prev = this.currentDir;
|
|
81
|
-
this.currentDir = path.startsWith("/") ?
|
|
250
|
+
this.currentDir = path.startsWith("/") ? Path.join(this.opts.outputDir, path) : Path.join(this.currentDir ?? this.opts.outputDir, path);
|
|
82
251
|
this.onDiskMkDir(this.currentDir);
|
|
83
252
|
this.logger()?.debug(`cd '${this.currentDir}'`);
|
|
84
253
|
gen();
|
|
@@ -87,12 +256,16 @@ var FileSystemWriter = class {
|
|
|
87
256
|
cat(fn, gen) {
|
|
88
257
|
if (this.currentFile) throw new Error("Can't open file when another file is open");
|
|
89
258
|
if (fn.includes("/")) throw new Error(`Change file path separatly: ${fn}`);
|
|
90
|
-
const relPath =
|
|
259
|
+
const relPath = Path.normalize(`${this.currentDir}/${fn}`);
|
|
91
260
|
try {
|
|
92
261
|
const descriptor = this.onDiskOpenFile(relPath);
|
|
93
262
|
this.logger()?.debug(`cat > '${relPath}'`);
|
|
94
263
|
this.currentFile = { descriptor, relPath };
|
|
95
|
-
this.writtenFilesBuffer[this.currentFile.relPath] = {
|
|
264
|
+
this.writtenFilesBuffer[this.currentFile.relPath] = {
|
|
265
|
+
relPath,
|
|
266
|
+
absPath: Path.resolve(relPath),
|
|
267
|
+
tokens: []
|
|
268
|
+
};
|
|
96
269
|
gen();
|
|
97
270
|
} finally {
|
|
98
271
|
if (this.currentFile) this.onDiskCloseFile(this.currentFile.descriptor);
|
|
@@ -106,9 +279,21 @@ var FileSystemWriter = class {
|
|
|
106
279
|
if (!buf) throw new Error("No buffer found");
|
|
107
280
|
buf.tokens.push(str);
|
|
108
281
|
}
|
|
282
|
+
cp(source, destination) {
|
|
283
|
+
if (!this.opts.resolveAssets) throw new Error("resolveAssets is not defined");
|
|
284
|
+
source = Path.resolve(this.opts.resolveAssets(source));
|
|
285
|
+
destination = Path.normalize(`${this.currentDir ?? this.opts.outputDir}/${destination}`);
|
|
286
|
+
const content = fs.readFileSync(source, "utf8");
|
|
287
|
+
this.writtenFilesBuffer[destination] = {
|
|
288
|
+
relPath: destination,
|
|
289
|
+
absPath: Path.resolve(destination),
|
|
290
|
+
tokens: [content]
|
|
291
|
+
};
|
|
292
|
+
fs.cpSync(source, destination);
|
|
293
|
+
}
|
|
109
294
|
writtenFiles() {
|
|
110
295
|
return Object.values(this.writtenFilesBuffer).map(({ relPath, absPath, tokens }) => {
|
|
111
|
-
return { relPath, absPath, content: tokens.join() };
|
|
296
|
+
return { relPath, absPath, content: tokens.join("") };
|
|
112
297
|
}).sort((a, b) => a.relPath.localeCompare(b.relPath));
|
|
113
298
|
}
|
|
114
299
|
};
|
|
@@ -216,15 +401,18 @@ var enrichFHIRSchema = (schema, packageMeta) => {
|
|
|
216
401
|
base: schema.base
|
|
217
402
|
};
|
|
218
403
|
};
|
|
404
|
+
var isResourceIdentifier = (id) => {
|
|
405
|
+
return id?.kind === "resource";
|
|
406
|
+
};
|
|
407
|
+
var isComplexTypeIdentifier = (id) => {
|
|
408
|
+
return id?.kind === "complex-type";
|
|
409
|
+
};
|
|
219
410
|
var isPrimitiveIdentifier = (id) => {
|
|
220
411
|
return id?.kind === "primitive-type";
|
|
221
412
|
};
|
|
222
413
|
var isNestedIdentifier = (id) => {
|
|
223
414
|
return id?.kind === "nested";
|
|
224
415
|
};
|
|
225
|
-
var isComplexTypeIdentifier = (id) => {
|
|
226
|
-
return id?.kind === "complex-type";
|
|
227
|
-
};
|
|
228
416
|
var isProfileIdentifier = (id) => {
|
|
229
417
|
return id?.kind === "profile";
|
|
230
418
|
};
|
|
@@ -260,6 +448,10 @@ var isChoiceDeclarationField = (field) => {
|
|
|
260
448
|
if (!field) return false;
|
|
261
449
|
return field.choices !== void 0;
|
|
262
450
|
};
|
|
451
|
+
var isChoiceInstanceField = (field) => {
|
|
452
|
+
if (!field) return false;
|
|
453
|
+
return field.choiceOf !== void 0;
|
|
454
|
+
};
|
|
263
455
|
var enrichValueSet = (vs, packageMeta) => {
|
|
264
456
|
if (!vs.url) throw new Error("ValueSet must have a URL");
|
|
265
457
|
if (!vs.name) throw new Error("ValueSet must have a name");
|
|
@@ -318,6 +510,15 @@ function formatName(input) {
|
|
|
318
510
|
}
|
|
319
511
|
|
|
320
512
|
// src/api/writer-generator/csharp/csharp.ts
|
|
513
|
+
var resolveCSharpAssets = (fn) => {
|
|
514
|
+
const __filename2 = fileURLToPath(import.meta.url);
|
|
515
|
+
const __dirname = Path__default.dirname(__filename2);
|
|
516
|
+
if (__filename2.endsWith("dist/index.js")) {
|
|
517
|
+
return Path__default.resolve(__dirname, "..", "assets", "api", "writer-generator", "csharp", fn);
|
|
518
|
+
} else {
|
|
519
|
+
return Path__default.resolve(__dirname, "../../../..", "assets", "api", "writer-generator", "csharp", fn);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
321
522
|
var PRIMITIVE_TYPE_MAP = {
|
|
322
523
|
boolean: "bool",
|
|
323
524
|
instant: "string",
|
|
@@ -383,6 +584,7 @@ var CSharp = class extends Writer {
|
|
|
383
584
|
tabSize: 4,
|
|
384
585
|
withDebugComment: false,
|
|
385
586
|
commentLinePrefix: "//",
|
|
587
|
+
resolveAssets: options.resolveAssets ?? resolveCSharpAssets,
|
|
386
588
|
...options
|
|
387
589
|
});
|
|
388
590
|
}
|
|
@@ -488,8 +690,8 @@ var CSharp = class extends Writer {
|
|
|
488
690
|
"CSharpSDK",
|
|
489
691
|
"System.Text.Json",
|
|
490
692
|
"System.Text.Json.Serialization",
|
|
491
|
-
this.opts.
|
|
492
|
-
...packages.map((pkg) => `${this.opts.
|
|
693
|
+
this.opts.rootNamespace,
|
|
694
|
+
...packages.map((pkg) => `${this.opts.rootNamespace}.${pkg}`)
|
|
493
695
|
];
|
|
494
696
|
for (const using of globalUsings) this.lineSM("global", "using", using);
|
|
495
697
|
}
|
|
@@ -498,7 +700,7 @@ var CSharp = class extends Writer {
|
|
|
498
700
|
this.cat("base.cs", () => {
|
|
499
701
|
this.generateDisclaimer();
|
|
500
702
|
this.line();
|
|
501
|
-
this.lineSM("namespace", this.opts.
|
|
703
|
+
this.lineSM("namespace", this.opts.rootNamespace);
|
|
502
704
|
for (const schema of complexTypes) {
|
|
503
705
|
const packageName = formatName(schema.identifier.package);
|
|
504
706
|
this.generateType(schema, packageName);
|
|
@@ -515,7 +717,7 @@ var CSharp = class extends Writer {
|
|
|
515
717
|
this.cat(`${schema.identifier.name}.cs`, () => {
|
|
516
718
|
this.generateDisclaimer();
|
|
517
719
|
this.line();
|
|
518
|
-
this.lineSM("namespace", `${this.opts.
|
|
720
|
+
this.lineSM("namespace", `${this.opts.rootNamespace}.${packageName}`);
|
|
519
721
|
this.line();
|
|
520
722
|
this.generateType(schema, packageName);
|
|
521
723
|
});
|
|
@@ -539,7 +741,7 @@ var CSharp = class extends Writer {
|
|
|
539
741
|
generateEnumFileContent(packageName, enums) {
|
|
540
742
|
this.lineSM("using", "System.ComponentModel");
|
|
541
743
|
this.line();
|
|
542
|
-
this.lineSM(`namespace ${this.opts.
|
|
744
|
+
this.lineSM(`namespace ${this.opts.rootNamespace}.${packageName}`);
|
|
543
745
|
for (const [enumName, values] of Object.entries(enums)) {
|
|
544
746
|
this.generateEnum(enumName, values);
|
|
545
747
|
}
|
|
@@ -561,7 +763,7 @@ var CSharp = class extends Writer {
|
|
|
561
763
|
this.cat(`${packageName}ResourceDictionary.cs`, () => {
|
|
562
764
|
this.generateDisclaimer();
|
|
563
765
|
this.line();
|
|
564
|
-
this.lineSM(`namespace ${this.opts.
|
|
766
|
+
this.lineSM(`namespace ${this.opts.rootNamespace}`);
|
|
565
767
|
this.generateResourceDictionaryClass(packageName, packageResources);
|
|
566
768
|
});
|
|
567
769
|
}
|
|
@@ -579,212 +781,790 @@ var CSharp = class extends Writer {
|
|
|
579
781
|
});
|
|
580
782
|
}
|
|
581
783
|
copyStaticFiles() {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
fs__default.cpSync(sourcePath, this.opts.outputDir, { recursive: true });
|
|
784
|
+
this.cp("Client.cs", "Client.cs");
|
|
785
|
+
this.cp("Helper.cs", "Helper.cs");
|
|
585
786
|
}
|
|
586
787
|
generateHelperFile() {
|
|
587
|
-
|
|
588
|
-
const
|
|
788
|
+
if (this.opts.inMemoryOnly) return;
|
|
789
|
+
const sourceFile = resolveCSharpAssets("Helper.cs");
|
|
790
|
+
const destFile = Path__default.join(this.opts.outputDir, "Helper.cs");
|
|
589
791
|
fs__default.copyFileSync(sourceFile, destFile);
|
|
590
792
|
}
|
|
591
793
|
};
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
// src/fhir-types/hl7-fhir-r4-core/ValueSet.ts
|
|
599
|
-
var isValueSet = (resource) => {
|
|
600
|
-
return resource !== null && typeof resource === "object" && resource.resourceType === "ValueSet";
|
|
601
|
-
};
|
|
602
|
-
|
|
603
|
-
// src/typeschema/register.ts
|
|
604
|
-
var readPackageDependencies = async (manager, packageMeta) => {
|
|
605
|
-
const packageJSON = await manager.packageJson(packageMeta.name);
|
|
606
|
-
const dependencies = packageJSON.dependencies;
|
|
607
|
-
if (dependencies !== void 0) {
|
|
608
|
-
return Object.entries(dependencies).map(([name, version]) => {
|
|
609
|
-
return { name, version };
|
|
610
|
-
});
|
|
794
|
+
var groupByPackages = (typeSchemas) => {
|
|
795
|
+
const grouped = {};
|
|
796
|
+
for (const ts of typeSchemas) {
|
|
797
|
+
const pkgName = ts.identifier.package;
|
|
798
|
+
if (!grouped[pkgName]) grouped[pkgName] = [];
|
|
799
|
+
grouped[pkgName].push(ts);
|
|
611
800
|
}
|
|
612
|
-
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
}
|
|
801
|
+
for (const [packageName, typeSchemas2] of Object.entries(grouped)) {
|
|
802
|
+
const dict = {};
|
|
803
|
+
for (const ts of typeSchemas2) {
|
|
804
|
+
dict[JSON.stringify(ts.identifier)] = ts;
|
|
805
|
+
}
|
|
806
|
+
const tmp = Object.values(dict);
|
|
807
|
+
tmp.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
|
|
808
|
+
grouped[packageName] = tmp;
|
|
809
|
+
}
|
|
810
|
+
return grouped;
|
|
621
811
|
};
|
|
622
|
-
var
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
const index = mkEmptyPkgIndex(pkg);
|
|
627
|
-
for (const resource of await manager.search({ package: pkg })) {
|
|
628
|
-
const rawUrl = resource.url;
|
|
629
|
-
if (!rawUrl) continue;
|
|
630
|
-
if (!(isStructureDefinition(resource) || isValueSet(resource) || isCodeSystem(resource))) continue;
|
|
631
|
-
const url = rawUrl;
|
|
632
|
-
if (index.canonicalResolution[url]) logger?.dry_warn(`Duplicate canonical URL: ${url} at ${pkgId}.`);
|
|
633
|
-
index.canonicalResolution[url] = [{ deep, pkg, pkgId, resource }];
|
|
812
|
+
var buildDependencyGraph = (schemas) => {
|
|
813
|
+
const nameToMap = {};
|
|
814
|
+
for (const schema of schemas) {
|
|
815
|
+
nameToMap[schema.identifier.name] = schema;
|
|
634
816
|
}
|
|
635
|
-
const
|
|
636
|
-
for (const
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
817
|
+
const graph = {};
|
|
818
|
+
for (const schema of schemas) {
|
|
819
|
+
const name = schema.identifier.name;
|
|
820
|
+
const base = schema.base?.name;
|
|
821
|
+
if (!graph[name]) {
|
|
822
|
+
graph[name] = [];
|
|
823
|
+
}
|
|
824
|
+
if (base && nameToMap[base]) {
|
|
825
|
+
graph[name].push(base);
|
|
641
826
|
}
|
|
642
827
|
}
|
|
643
|
-
|
|
644
|
-
resolutionOptions.sort((a, b) => a.deep - b.deep);
|
|
645
|
-
}
|
|
646
|
-
acc[pkgId] = index;
|
|
647
|
-
return index;
|
|
648
|
-
};
|
|
649
|
-
var packageAgnosticResolveCanonical = (resolver, url, _logger) => {
|
|
650
|
-
const options = Object.values(resolver).flatMap((pkg) => pkg.canonicalResolution[url]);
|
|
651
|
-
if (!options) throw new Error(`No canonical resolution found for ${url} in any package`);
|
|
652
|
-
return options[0]?.resource;
|
|
828
|
+
return graph;
|
|
653
829
|
};
|
|
654
|
-
var
|
|
655
|
-
const
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if (!
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const resolition = options[0];
|
|
667
|
-
if (!resolition) throw new Error(`Resource not found`);
|
|
668
|
-
const resource = resolition.resource;
|
|
669
|
-
const resourcePkg = resolition.pkg;
|
|
670
|
-
if (isStructureDefinition(resource)) {
|
|
671
|
-
const rfs = enrichFHIRSchema(
|
|
672
|
-
fhirschema.translate(resource),
|
|
673
|
-
resourcePkg
|
|
674
|
-
);
|
|
675
|
-
counter++;
|
|
676
|
-
resolver[pkgId].fhirSchemas[rfs.url] = rfs;
|
|
677
|
-
}
|
|
678
|
-
if (isValueSet(resource)) {
|
|
679
|
-
const rvs = enrichValueSet(resource, resourcePkg);
|
|
680
|
-
resolver[pkgId].valueSets[rvs.url] = rvs;
|
|
830
|
+
var topologicalSort = (graph) => {
|
|
831
|
+
const sorted = [];
|
|
832
|
+
const visited = {};
|
|
833
|
+
const temp = {};
|
|
834
|
+
const visit = (node) => {
|
|
835
|
+
if (temp[node]) {
|
|
836
|
+
throw new Error(`Graph has cycles ${node}`);
|
|
837
|
+
}
|
|
838
|
+
if (!visited[node]) {
|
|
839
|
+
temp[node] = true;
|
|
840
|
+
for (const neighbor of graph[node] ?? []) {
|
|
841
|
+
visit(neighbor);
|
|
681
842
|
}
|
|
843
|
+
temp[node] = false;
|
|
844
|
+
visited[node] = true;
|
|
845
|
+
sorted.push(node);
|
|
682
846
|
}
|
|
683
|
-
logger?.info(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' completed: ${counter} successful`);
|
|
684
|
-
}
|
|
685
|
-
const resolveFs = (pkg, canonicalUrl) => {
|
|
686
|
-
return resolver[packageMetaToFhir(pkg)]?.fhirSchemas[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.fhirSchemas[canonicalUrl];
|
|
687
847
|
};
|
|
688
|
-
const
|
|
689
|
-
|
|
848
|
+
for (const node in graph) {
|
|
849
|
+
if (!visited[node]) {
|
|
850
|
+
visit(node);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return sorted;
|
|
854
|
+
};
|
|
855
|
+
var sortAsDeclarationSequence = (schemas) => {
|
|
856
|
+
const graph = buildDependencyGraph(schemas);
|
|
857
|
+
const sorted = topologicalSort(graph);
|
|
858
|
+
return sorted.map((name) => schemas.find((schema) => schema.identifier.name === name)).filter(Boolean);
|
|
859
|
+
};
|
|
860
|
+
var resourceRelatives = (schemas) => {
|
|
861
|
+
const regularSchemas = schemas.filter(
|
|
862
|
+
(e) => isResourceTypeSchema(e) || isLogicalTypeSchema(e) || isComplexTypeTypeSchema(e)
|
|
863
|
+
);
|
|
864
|
+
const directPairs = [];
|
|
865
|
+
for (const schema of regularSchemas) {
|
|
866
|
+
if (schema.base) {
|
|
867
|
+
directPairs.push({ parent: schema.base, child: schema.identifier });
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
const allPairs = [...directPairs];
|
|
871
|
+
const findTransitiveRelatives = (parentRef) => {
|
|
872
|
+
const directChildren = directPairs.filter((pair) => pair.parent.name === parentRef.name).map((pair) => pair.child);
|
|
873
|
+
const transitiveChildren = [];
|
|
874
|
+
for (const child of directChildren) {
|
|
875
|
+
transitiveChildren.push(...findTransitiveRelatives(child));
|
|
876
|
+
}
|
|
877
|
+
return [...directChildren, ...transitiveChildren];
|
|
690
878
|
};
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
879
|
+
for (const pair of directPairs) {
|
|
880
|
+
const transitiveChildren = findTransitiveRelatives(pair.child);
|
|
881
|
+
for (const transitiveChild of transitiveChildren) {
|
|
882
|
+
if (!directPairs.some((dp) => dp.parent.name === pair.parent.name && dp.child.name === transitiveChild.name)) {
|
|
883
|
+
allPairs.push({ parent: pair.parent, child: transitiveChild });
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return allPairs;
|
|
888
|
+
};
|
|
889
|
+
var mkTypeSchemaIndex = (schemas, { resolutionTree, logger }) => {
|
|
890
|
+
const index = {};
|
|
891
|
+
const append = (schema) => {
|
|
892
|
+
const url = schema.identifier.url;
|
|
893
|
+
const pkg = schema.identifier.package;
|
|
894
|
+
if (!index[url]) index[url] = {};
|
|
895
|
+
if (index[url][schema.identifier.package] && pkg !== "shared") {
|
|
896
|
+
const r1 = JSON.stringify(schema.identifier, void 0, 2);
|
|
897
|
+
const r2 = JSON.stringify(index[url][pkg]?.identifier, void 0, 2);
|
|
898
|
+
if (r1 !== r2) throw new Error(`Duplicate schema: ${r1} and ${r2}`);
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
index[url][pkg] = schema;
|
|
902
|
+
};
|
|
903
|
+
for (const schema of schemas) {
|
|
904
|
+
append(schema);
|
|
905
|
+
}
|
|
906
|
+
const relations = resourceRelatives(schemas);
|
|
907
|
+
const resolve6 = (id) => index[id.url]?.[id.package];
|
|
908
|
+
const resolveByUrl = (pkgName, url) => {
|
|
909
|
+
if (resolutionTree) {
|
|
910
|
+
const resolution = resolutionTree[pkgName]?.[url]?.[0];
|
|
911
|
+
if (resolution) {
|
|
912
|
+
return index[url]?.[resolution.pkg.name];
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
return index[url]?.[pkgName];
|
|
916
|
+
};
|
|
917
|
+
const resourceChildren = (id) => {
|
|
918
|
+
return relations.filter((relative) => relative.parent.name === id.name).map((relative) => relative.child);
|
|
919
|
+
};
|
|
920
|
+
const tryHierarchy = (schema) => {
|
|
921
|
+
const res = [];
|
|
922
|
+
let cur = schema;
|
|
923
|
+
while (cur) {
|
|
924
|
+
res.push(cur);
|
|
925
|
+
const base = cur.base;
|
|
926
|
+
if (base === void 0) break;
|
|
927
|
+
const resolved = resolve6(base);
|
|
928
|
+
if (!resolved) {
|
|
929
|
+
logger?.warn(
|
|
930
|
+
`Failed to resolve base type: ${res.map((e) => `${e.identifier.url} (${e.identifier.kind})`).join(", ")}`
|
|
703
931
|
);
|
|
704
|
-
|
|
932
|
+
return void 0;
|
|
933
|
+
}
|
|
934
|
+
cur = resolved;
|
|
935
|
+
}
|
|
936
|
+
return res;
|
|
937
|
+
};
|
|
938
|
+
const hierarchy = (schema) => {
|
|
939
|
+
const genealogy = tryHierarchy(schema);
|
|
940
|
+
if (genealogy === void 0) {
|
|
941
|
+
throw new Error(`Failed to resolve base type: ${schema.identifier.url} (${schema.identifier.kind})`);
|
|
705
942
|
}
|
|
706
943
|
return genealogy;
|
|
707
944
|
};
|
|
708
|
-
const
|
|
709
|
-
|
|
945
|
+
const findLastSpecialization = (schema) => {
|
|
946
|
+
const nonConstraintSchema = hierarchy(schema).find((s) => s.identifier.kind !== "profile");
|
|
947
|
+
if (!nonConstraintSchema) {
|
|
948
|
+
throw new Error(`No non-constraint schema found in hierarchy for: ${schema.identifier.name}`);
|
|
949
|
+
}
|
|
950
|
+
return nonConstraintSchema;
|
|
710
951
|
};
|
|
711
|
-
const
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
return elemSnapshot;
|
|
952
|
+
const findLastSpecializationByIdentifier = (id) => {
|
|
953
|
+
const schema = resolve6(id);
|
|
954
|
+
if (!schema) return id;
|
|
955
|
+
return findLastSpecialization(schema).identifier;
|
|
716
956
|
};
|
|
717
|
-
const
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
957
|
+
const flatProfile = (schema) => {
|
|
958
|
+
const hierarchySchemas = hierarchy(schema);
|
|
959
|
+
const constraintSchemas = hierarchySchemas.filter((s) => s.identifier.kind === "profile");
|
|
960
|
+
const nonConstraintSchema = hierarchySchemas.find((s) => s.identifier.kind !== "profile");
|
|
961
|
+
if (!nonConstraintSchema)
|
|
962
|
+
throw new Error(`No non-constraint schema found in hierarchy for ${schema.identifier.name}`);
|
|
963
|
+
const mergedFields = {};
|
|
964
|
+
for (const anySchema of constraintSchemas.slice().reverse()) {
|
|
965
|
+
const schema2 = anySchema;
|
|
966
|
+
if (!schema2.fields) continue;
|
|
967
|
+
for (const [fieldName, fieldConstraints] of Object.entries(schema2.fields)) {
|
|
968
|
+
if (mergedFields[fieldName]) {
|
|
969
|
+
mergedFields[fieldName] = {
|
|
970
|
+
...mergedFields[fieldName],
|
|
971
|
+
...fieldConstraints
|
|
972
|
+
};
|
|
973
|
+
} else {
|
|
974
|
+
mergedFields[fieldName] = { ...fieldConstraints };
|
|
724
975
|
}
|
|
725
976
|
}
|
|
726
977
|
}
|
|
727
|
-
|
|
978
|
+
const deps = {};
|
|
979
|
+
for (const e of constraintSchemas.flatMap((e2) => e2.dependencies ?? [])) {
|
|
980
|
+
deps[e.url] = e;
|
|
981
|
+
}
|
|
982
|
+
const dependencies = Object.values(deps);
|
|
983
|
+
return {
|
|
984
|
+
...schema,
|
|
985
|
+
base: nonConstraintSchema.identifier,
|
|
986
|
+
fields: mergedFields,
|
|
987
|
+
dependencies
|
|
988
|
+
};
|
|
989
|
+
};
|
|
990
|
+
const isWithMetaField = (profile) => {
|
|
991
|
+
const genealogy = tryHierarchy(profile);
|
|
992
|
+
if (!genealogy) return false;
|
|
993
|
+
return genealogy.filter(isSpecializationTypeSchema).some((schema) => {
|
|
994
|
+
return schema.fields?.meta !== void 0;
|
|
995
|
+
});
|
|
996
|
+
};
|
|
997
|
+
const exportTree = async (filename) => {
|
|
998
|
+
const tree = {};
|
|
999
|
+
for (const [pkgId, shemas] of Object.entries(groupByPackages(schemas))) {
|
|
1000
|
+
tree[pkgId] = {
|
|
1001
|
+
"primitive-type": {},
|
|
1002
|
+
"complex-type": {},
|
|
1003
|
+
resource: {},
|
|
1004
|
+
"value-set": {},
|
|
1005
|
+
nested: {},
|
|
1006
|
+
binding: {},
|
|
1007
|
+
profile: {},
|
|
1008
|
+
logical: {}
|
|
1009
|
+
};
|
|
1010
|
+
for (const schema of shemas) {
|
|
1011
|
+
tree[pkgId][schema.identifier.kind][schema.identifier.url] = {};
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
const raw = filename.endsWith(".yaml") ? YAML.stringify(tree) : JSON.stringify(tree, void 0, 2);
|
|
1015
|
+
await afs2.mkdir(Path.dirname(filename), { recursive: true });
|
|
1016
|
+
await afs2.writeFile(filename, raw);
|
|
728
1017
|
};
|
|
729
1018
|
return {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
1019
|
+
_schemaIndex: index,
|
|
1020
|
+
_relations: relations,
|
|
1021
|
+
collectComplexTypes: () => schemas.filter(isComplexTypeTypeSchema),
|
|
1022
|
+
collectResources: () => schemas.filter(isResourceTypeSchema),
|
|
1023
|
+
collectLogicalModels: () => schemas.filter(isLogicalTypeSchema),
|
|
1024
|
+
collectProfiles: () => schemas.filter(isProfileTypeSchema),
|
|
1025
|
+
resolve: resolve6,
|
|
1026
|
+
resolveByUrl,
|
|
1027
|
+
resourceChildren,
|
|
1028
|
+
tryHierarchy,
|
|
1029
|
+
hierarchy,
|
|
1030
|
+
findLastSpecialization,
|
|
1031
|
+
findLastSpecializationByIdentifier,
|
|
1032
|
+
flatProfile,
|
|
1033
|
+
isWithMetaField,
|
|
1034
|
+
exportTree
|
|
1035
|
+
};
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
// src/api/writer-generator/python.ts
|
|
1039
|
+
var PRIMITIVE_TYPE_MAP2 = {
|
|
1040
|
+
boolean: "bool",
|
|
1041
|
+
instant: "str",
|
|
1042
|
+
time: "str",
|
|
1043
|
+
date: "str",
|
|
1044
|
+
dateTime: "str",
|
|
1045
|
+
decimal: "float",
|
|
1046
|
+
integer: "int",
|
|
1047
|
+
unsignedInt: "int",
|
|
1048
|
+
positiveInt: "PositiveInt",
|
|
1049
|
+
integer64: "int",
|
|
1050
|
+
base64Binary: "str",
|
|
1051
|
+
uri: "str",
|
|
1052
|
+
url: "str",
|
|
1053
|
+
canonical: "str",
|
|
1054
|
+
oid: "str",
|
|
1055
|
+
uuid: "str",
|
|
1056
|
+
string: "str",
|
|
1057
|
+
code: "str",
|
|
1058
|
+
markdown: "str",
|
|
1059
|
+
id: "str",
|
|
1060
|
+
xhtml: "str"
|
|
1061
|
+
};
|
|
1062
|
+
var AVAILABLE_STRING_FORMATS = {
|
|
1063
|
+
snake_case: snakeCase,
|
|
1064
|
+
PascalCase: pascalCase,
|
|
1065
|
+
camelCase
|
|
1066
|
+
};
|
|
1067
|
+
var PYTHON_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1068
|
+
"False",
|
|
1069
|
+
"None",
|
|
1070
|
+
"True",
|
|
1071
|
+
"and",
|
|
1072
|
+
"as",
|
|
1073
|
+
"assert",
|
|
1074
|
+
"async",
|
|
1075
|
+
"await",
|
|
1076
|
+
"break",
|
|
1077
|
+
"class",
|
|
1078
|
+
"continue",
|
|
1079
|
+
"def",
|
|
1080
|
+
"del",
|
|
1081
|
+
"elif",
|
|
1082
|
+
"else",
|
|
1083
|
+
"except",
|
|
1084
|
+
"finally",
|
|
1085
|
+
"for",
|
|
1086
|
+
"from",
|
|
1087
|
+
"global",
|
|
1088
|
+
"if",
|
|
1089
|
+
"import",
|
|
1090
|
+
"in",
|
|
1091
|
+
"is",
|
|
1092
|
+
"lambda",
|
|
1093
|
+
"nonlocal",
|
|
1094
|
+
"not",
|
|
1095
|
+
"or",
|
|
1096
|
+
"pass",
|
|
1097
|
+
"raise",
|
|
1098
|
+
"return",
|
|
1099
|
+
"try",
|
|
1100
|
+
"while",
|
|
1101
|
+
"with",
|
|
1102
|
+
"yield",
|
|
1103
|
+
"List"
|
|
1104
|
+
]);
|
|
1105
|
+
var MAX_IMPORT_LINE_LENGTH = 100;
|
|
1106
|
+
var fixReservedWords = (name) => {
|
|
1107
|
+
return PYTHON_KEYWORDS.has(name) ? `${name}_` : name;
|
|
1108
|
+
};
|
|
1109
|
+
var injectSuperClasses = (name) => {
|
|
1110
|
+
return name === "Resource" || name === "Element" ? ["BaseModel"] : [];
|
|
1111
|
+
};
|
|
1112
|
+
var canonicalToName2 = (canonical, dropFragment = true) => {
|
|
1113
|
+
if (!canonical) return void 0;
|
|
1114
|
+
let localName = canonical.split("/").pop();
|
|
1115
|
+
if (!localName) return void 0;
|
|
1116
|
+
if (dropFragment && localName.includes("#")) {
|
|
1117
|
+
localName = localName.split("#")[0];
|
|
1118
|
+
}
|
|
1119
|
+
if (!localName) return void 0;
|
|
1120
|
+
if (/^\d/.test(localName)) {
|
|
1121
|
+
localName = `number_${localName}`;
|
|
1122
|
+
}
|
|
1123
|
+
return snakeCase(localName);
|
|
1124
|
+
};
|
|
1125
|
+
var deriveResourceName = (id) => {
|
|
1126
|
+
if (id.kind === "nested") {
|
|
1127
|
+
const url = id.url;
|
|
1128
|
+
const path = canonicalToName2(url, false);
|
|
1129
|
+
if (!path) return "";
|
|
1130
|
+
const [resourceName, fragment] = path.split("#");
|
|
1131
|
+
const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
|
|
1132
|
+
return pascalCase([resourceName, name].join(""));
|
|
1133
|
+
}
|
|
1134
|
+
return pascalCase(id.name);
|
|
1135
|
+
};
|
|
1136
|
+
var resolvePyAssets = (fn) => {
|
|
1137
|
+
const __dirname = Path.dirname(fileURLToPath(import.meta.url));
|
|
1138
|
+
if (__filename.endsWith("dist/index.js")) {
|
|
1139
|
+
return Path.resolve(__dirname, "..", "assets", "api", "writer-generator", "python", fn);
|
|
1140
|
+
} else {
|
|
1141
|
+
return Path.resolve(__dirname, "../../..", "assets", "api", "writer-generator", "python", fn);
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
var Python = class extends Writer {
|
|
1145
|
+
nameFormatFunction;
|
|
1146
|
+
tsIndex;
|
|
1147
|
+
constructor(options) {
|
|
1148
|
+
super({ ...options, resolveAssets: options.resolveAssets ?? resolvePyAssets });
|
|
1149
|
+
this.nameFormatFunction = this.getFieldFormatFunction(options.fieldFormat);
|
|
1150
|
+
}
|
|
1151
|
+
async generate(tsIndex) {
|
|
1152
|
+
this.tsIndex = tsIndex;
|
|
1153
|
+
const groups = {
|
|
1154
|
+
groupedComplexTypes: groupByPackages(tsIndex.collectComplexTypes()),
|
|
1155
|
+
groupedResources: groupByPackages(tsIndex.collectResources())
|
|
1156
|
+
};
|
|
1157
|
+
this.generateRootPackages(groups);
|
|
1158
|
+
this.generateSDKPackages(groups);
|
|
1159
|
+
}
|
|
1160
|
+
generateRootPackages(groups) {
|
|
1161
|
+
this.generateRootInitFile(groups);
|
|
1162
|
+
this.cp(resolvePyAssets("requirements.txt"), "requirements.txt");
|
|
1163
|
+
}
|
|
1164
|
+
generateSDKPackages(groups) {
|
|
1165
|
+
this.generateComplexTypesPackages(groups.groupedComplexTypes);
|
|
1166
|
+
this.generateResourcePackages(groups);
|
|
1167
|
+
}
|
|
1168
|
+
generateComplexTypesPackages(groupedComplexTypes) {
|
|
1169
|
+
for (const [packageName, packageComplexTypes] of Object.entries(groupedComplexTypes)) {
|
|
1170
|
+
this.cd(`/${snakeCase(packageName)}`, () => {
|
|
1171
|
+
this.generateBasePy(packageComplexTypes);
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
generateResourcePackages(groups) {
|
|
1176
|
+
for (const [packageName, packageResources] of Object.entries(groups.groupedResources)) {
|
|
1177
|
+
this.cd(`/${snakeCase(packageName)}`, () => {
|
|
1178
|
+
this.generateResourcePackageContent(
|
|
1179
|
+
packageName,
|
|
1180
|
+
packageResources,
|
|
1181
|
+
groups.groupedComplexTypes[packageName] || []
|
|
1182
|
+
);
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
generateResourcePackageContent(packageName, packageResources, packageComplexTypes) {
|
|
1187
|
+
const pyPackageName = this.pyFhirPackageByName(packageName);
|
|
1188
|
+
this.generateResourcePackageInit(pyPackageName, packageResources, packageComplexTypes);
|
|
1189
|
+
this.generateResourceFamilies(packageResources);
|
|
1190
|
+
for (const schema of packageResources) {
|
|
1191
|
+
this.generateResourceModule(schema);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
generateRootInitFile(groups) {
|
|
1195
|
+
this.cd("/", () => {
|
|
1196
|
+
this.cat("__init__.py", () => {
|
|
1197
|
+
this.generateDisclaimer();
|
|
1198
|
+
const pydanticModels = this.collectAndImportAllModels(groups);
|
|
1199
|
+
this.generateModelRebuilds(pydanticModels);
|
|
1200
|
+
});
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
collectAndImportAllModels(groups) {
|
|
1204
|
+
const models = [];
|
|
1205
|
+
for (const packageName of Object.keys(groups.groupedResources)) {
|
|
1206
|
+
const fullPyPackageName = this.pyFhirPackageByName(packageName);
|
|
1207
|
+
models.push(...this.importComplexTypes(fullPyPackageName, groups.groupedComplexTypes[packageName]));
|
|
1208
|
+
models.push(...this.importResources(fullPyPackageName, false, groups.groupedResources[packageName]));
|
|
1209
|
+
}
|
|
1210
|
+
this.line();
|
|
1211
|
+
return models;
|
|
1212
|
+
}
|
|
1213
|
+
generateModelRebuilds(models) {
|
|
1214
|
+
for (const modelName of models.sort()) {
|
|
1215
|
+
this.line(`${modelName}.model_rebuild()`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
generateBasePy(packageComplexTypes) {
|
|
1219
|
+
this.cat("base.py", () => {
|
|
1220
|
+
this.generateDisclaimer();
|
|
1221
|
+
this.generateDefaultImports();
|
|
1222
|
+
this.line();
|
|
1223
|
+
this.generateComplexTypes(packageComplexTypes);
|
|
1224
|
+
this.line();
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
generateComplexTypes(complexTypes) {
|
|
1228
|
+
for (const schema of sortAsDeclarationSequence(complexTypes)) {
|
|
1229
|
+
this.generateNestedTypes(schema);
|
|
1230
|
+
this.line();
|
|
1231
|
+
this.generateType(schema);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
generateResourcePackageInit(fullPyPackageName, packageResources, packageComplexTypes) {
|
|
1235
|
+
this.cat("__init__.py", () => {
|
|
1236
|
+
this.generateDisclaimer();
|
|
1237
|
+
this.importComplexTypes(fullPyPackageName, packageComplexTypes);
|
|
1238
|
+
const allResourceNames = this.importResources(fullPyPackageName, true, packageResources);
|
|
1239
|
+
this.line();
|
|
1240
|
+
this.generateExportsDeclaration(packageComplexTypes, allResourceNames);
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
importComplexTypes(fullPyPackageName, packageComplexTypes) {
|
|
1244
|
+
if (!packageComplexTypes || packageComplexTypes.length === 0) return [];
|
|
1245
|
+
const baseTypes = packageComplexTypes.map((t) => t.identifier.name).sort();
|
|
1246
|
+
this.pyImportFrom(`${fullPyPackageName}.base`, ...baseTypes);
|
|
1247
|
+
this.line();
|
|
1248
|
+
return baseTypes;
|
|
1249
|
+
}
|
|
1250
|
+
buildImportLine(remaining, maxImportLineLength) {
|
|
1251
|
+
let line = "";
|
|
1252
|
+
while (remaining.length > 0 && line.length < maxImportLineLength) {
|
|
1253
|
+
const entity = remaining.shift();
|
|
1254
|
+
if (!entity) throw new Error("Unexpected empty entity");
|
|
1255
|
+
if (line.length > 0) {
|
|
1256
|
+
line += ", ";
|
|
765
1257
|
}
|
|
766
|
-
|
|
1258
|
+
line += entity;
|
|
1259
|
+
}
|
|
1260
|
+
if (remaining.length > 0) {
|
|
1261
|
+
line += ", \\";
|
|
1262
|
+
}
|
|
1263
|
+
return line;
|
|
1264
|
+
}
|
|
1265
|
+
importResources(fullPyPackageName, importEmptyResources, packageResources) {
|
|
1266
|
+
if (!packageResources || packageResources.length === 0) return [];
|
|
1267
|
+
const allResourceNames = [];
|
|
1268
|
+
for (const resource of packageResources) {
|
|
1269
|
+
const names = this.importOneResource(resource, fullPyPackageName);
|
|
1270
|
+
if (!importEmptyResources && !resource.fields) continue;
|
|
1271
|
+
allResourceNames.push(...names);
|
|
1272
|
+
}
|
|
1273
|
+
return allResourceNames;
|
|
1274
|
+
}
|
|
1275
|
+
importOneResource(resource, fullPyPackageName) {
|
|
1276
|
+
const moduleName = `${fullPyPackageName}.${snakeCase(resource.identifier.name)}`;
|
|
1277
|
+
const importNames = this.collectResourceImportNames(resource);
|
|
1278
|
+
this.pyImportFrom(moduleName, ...importNames);
|
|
1279
|
+
const names = [...importNames];
|
|
1280
|
+
if (this.shouldImportResourceFamily(resource)) {
|
|
1281
|
+
const familyName = `${resource.identifier.name}Family`;
|
|
1282
|
+
this.pyImportFrom(`${fullPyPackageName}.resource_families`, familyName);
|
|
1283
|
+
}
|
|
1284
|
+
return names;
|
|
1285
|
+
}
|
|
1286
|
+
collectResourceImportNames(resource) {
|
|
1287
|
+
const names = [deriveResourceName(resource.identifier)];
|
|
1288
|
+
for (const nested of resource.nested ?? []) {
|
|
1289
|
+
const nestedName = deriveResourceName(nested.identifier);
|
|
1290
|
+
names.push(nestedName);
|
|
1291
|
+
}
|
|
1292
|
+
return names;
|
|
1293
|
+
}
|
|
1294
|
+
shouldImportResourceFamily(resource) {
|
|
1295
|
+
assert3(this.tsIndex !== void 0);
|
|
1296
|
+
return resource.identifier.kind === "resource" && this.tsIndex.resourceChildren(resource.identifier).length > 0;
|
|
1297
|
+
}
|
|
1298
|
+
generateExportsDeclaration(packageComplexTypes, allResourceNames) {
|
|
1299
|
+
this.squareBlock(["__all__", "="], () => {
|
|
1300
|
+
const allExports = [
|
|
1301
|
+
...(packageComplexTypes || []).map((t) => t.identifier.name),
|
|
1302
|
+
...allResourceNames
|
|
1303
|
+
].sort();
|
|
1304
|
+
for (const schemaName of allExports) {
|
|
1305
|
+
this.line(`'${schemaName}',`);
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
generateResourceModule(schema) {
|
|
1310
|
+
this.cat(`${snakeCase(schema.identifier.name)}.py`, () => {
|
|
1311
|
+
this.generateDisclaimer();
|
|
1312
|
+
this.generateDefaultImports();
|
|
1313
|
+
this.line();
|
|
1314
|
+
this.generateDependenciesImports(schema);
|
|
1315
|
+
this.line();
|
|
1316
|
+
this.generateNestedTypes(schema);
|
|
1317
|
+
this.line();
|
|
1318
|
+
this.generateType(schema);
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
generateType(schema) {
|
|
1322
|
+
const className = deriveResourceName(schema.identifier);
|
|
1323
|
+
const superClasses = this.getSuperClasses(schema);
|
|
1324
|
+
this.line(`class ${className}(${superClasses.join(", ")}):`);
|
|
1325
|
+
this.indentBlock(() => {
|
|
1326
|
+
this.generateClassBody(schema);
|
|
1327
|
+
});
|
|
1328
|
+
this.line();
|
|
1329
|
+
}
|
|
1330
|
+
getSuperClasses(schema) {
|
|
1331
|
+
return [...schema.base ? [schema.base.name] : [], ...injectSuperClasses(schema.identifier.name)];
|
|
1332
|
+
}
|
|
1333
|
+
generateClassBody(schema) {
|
|
1334
|
+
this.generateModelConfig();
|
|
1335
|
+
if (!schema.fields) {
|
|
1336
|
+
this.line("pass");
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
if (schema.identifier.kind === "resource") {
|
|
1340
|
+
this.generateResourceTypeField(schema);
|
|
1341
|
+
}
|
|
1342
|
+
this.generateFields(schema);
|
|
1343
|
+
if (schema.identifier.kind === "resource") {
|
|
1344
|
+
this.generateResourceMethods(schema);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
generateModelConfig() {
|
|
1348
|
+
const extraMode = this.opts.allowExtraFields ? "allow" : "forbid";
|
|
1349
|
+
this.line(`model_config = ConfigDict(validate_by_name=True, serialize_by_alias=True, extra="${extraMode}")`);
|
|
1350
|
+
}
|
|
1351
|
+
generateResourceTypeField(schema) {
|
|
1352
|
+
this.line(`${this.nameFormatFunction("resourceType")}: str = Field(`);
|
|
1353
|
+
this.indentBlock(() => {
|
|
1354
|
+
this.line(`default='${schema.identifier.name}',`);
|
|
1355
|
+
this.line(`alias='resourceType',`);
|
|
1356
|
+
this.line(`serialization_alias='resourceType',`);
|
|
1357
|
+
this.line("frozen=True,");
|
|
1358
|
+
this.line(`pattern='${schema.identifier.name}'`);
|
|
1359
|
+
});
|
|
1360
|
+
this.line(")");
|
|
1361
|
+
}
|
|
1362
|
+
generateFields(schema) {
|
|
1363
|
+
const sortedFields = Object.entries(schema.fields ?? []).sort(([a], [b]) => a.localeCompare(b));
|
|
1364
|
+
for (const [fieldName, field] of sortedFields) {
|
|
1365
|
+
if ("choices" in field && field.choices) continue;
|
|
1366
|
+
const fieldInfo = this.buildFieldInfo(fieldName, field);
|
|
1367
|
+
this.line(`${fieldInfo.name}: ${fieldInfo.type}${fieldInfo.defaultValue}`);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
buildFieldInfo(fieldName, field) {
|
|
1371
|
+
const pyFieldName = fixReservedWords(this.nameFormatFunction(fieldName));
|
|
1372
|
+
const fieldType = this.determineFieldType(field);
|
|
1373
|
+
const defaultValue = this.getFieldDefaultValue(field, fieldName);
|
|
1374
|
+
return {
|
|
1375
|
+
name: pyFieldName,
|
|
1376
|
+
type: fieldType,
|
|
1377
|
+
defaultValue
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
determineFieldType(field) {
|
|
1381
|
+
let fieldType = field ? this.getBaseFieldType(field) : "";
|
|
1382
|
+
if ("enum" in field && field.enum) {
|
|
1383
|
+
const s = field.enum.map((e) => `"${e}"`).join(", ");
|
|
1384
|
+
fieldType = `Literal[${s}]`;
|
|
1385
|
+
}
|
|
1386
|
+
if (field.array) {
|
|
1387
|
+
fieldType = `PyList[${fieldType}]`;
|
|
1388
|
+
}
|
|
1389
|
+
if (!field.required) {
|
|
1390
|
+
fieldType = `${fieldType} | None`;
|
|
1391
|
+
}
|
|
1392
|
+
return fieldType;
|
|
1393
|
+
}
|
|
1394
|
+
getBaseFieldType(field) {
|
|
1395
|
+
if ("type" in field && field.type.kind === "resource") return `${field.type.name}Family`;
|
|
1396
|
+
if ("type" in field && field.type.kind === "nested") return deriveResourceName(field.type);
|
|
1397
|
+
if ("type" in field && field.type.kind === "primitive-type")
|
|
1398
|
+
return PRIMITIVE_TYPE_MAP2[field.type.name] ?? "str";
|
|
1399
|
+
return "type" in field ? field.type.name : "";
|
|
1400
|
+
}
|
|
1401
|
+
getFieldDefaultValue(field, fieldName) {
|
|
1402
|
+
const aliasSpec = `alias="${fieldName}", serialization_alias="${fieldName}"`;
|
|
1403
|
+
if (!field.required) {
|
|
1404
|
+
return ` = Field(None, ${aliasSpec})`;
|
|
1405
|
+
}
|
|
1406
|
+
return ` = Field(${aliasSpec})`;
|
|
1407
|
+
}
|
|
1408
|
+
generateResourceMethods(schema) {
|
|
1409
|
+
const className = schema.identifier.name.toString();
|
|
1410
|
+
this.line();
|
|
1411
|
+
this.line("def to_json(self, indent: int | None = None) -> str:");
|
|
1412
|
+
this.line(" return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent)");
|
|
1413
|
+
this.line();
|
|
1414
|
+
this.line("@classmethod");
|
|
1415
|
+
this.line(`def from_json(cls, json: str) -> ${className}:`);
|
|
1416
|
+
this.line(" return cls.model_validate_json(json)");
|
|
1417
|
+
}
|
|
1418
|
+
generateNestedTypes(schema) {
|
|
1419
|
+
if (!schema.nested) return;
|
|
1420
|
+
this.line();
|
|
1421
|
+
for (const subtype of schema.nested) {
|
|
1422
|
+
this.generateType(subtype);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
generateDefaultImports() {
|
|
1426
|
+
this.pyImportFrom("__future__", "annotations");
|
|
1427
|
+
this.pyImportFrom("pydantic", "BaseModel", "ConfigDict", "Field", "PositiveInt");
|
|
1428
|
+
this.pyImportFrom("typing", "List as PyList", "Literal");
|
|
1429
|
+
}
|
|
1430
|
+
generateDependenciesImports(schema) {
|
|
1431
|
+
if (!schema.dependencies || schema.dependencies.length === 0) return;
|
|
1432
|
+
this.importComplexTypeDependencies(schema.dependencies);
|
|
1433
|
+
this.importResourceDependencies(schema.dependencies);
|
|
1434
|
+
}
|
|
1435
|
+
importComplexTypeDependencies(dependencies) {
|
|
1436
|
+
const complexTypeDeps = dependencies.filter((dep) => dep.kind === "complex-type");
|
|
1437
|
+
const depsByPackage = this.groupDependenciesByPackage(complexTypeDeps);
|
|
1438
|
+
for (const [pyPackage, names] of Object.entries(depsByPackage)) {
|
|
1439
|
+
this.pyImportFrom(pyPackage, ...names.sort());
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
importResourceDependencies(dependencies) {
|
|
1443
|
+
const resourceDeps = dependencies.filter((dep) => dep.kind === "resource");
|
|
1444
|
+
for (const dep of resourceDeps) {
|
|
1445
|
+
this.pyImportType(dep);
|
|
1446
|
+
const familyName = `${pascalCase(dep.name)}Family`;
|
|
1447
|
+
const familyPackage = `${this.pyFhirPackage(dep)}.resource_families`;
|
|
1448
|
+
this.pyImportFrom(familyPackage, familyName);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
groupDependenciesByPackage(dependencies) {
|
|
1452
|
+
const grouped = {};
|
|
1453
|
+
for (const dep of dependencies) {
|
|
1454
|
+
const pyPackage = this.pyPackage(dep);
|
|
1455
|
+
if (!grouped[pyPackage]) {
|
|
1456
|
+
grouped[pyPackage] = [];
|
|
1457
|
+
}
|
|
1458
|
+
grouped[pyPackage].push(dep.name);
|
|
1459
|
+
}
|
|
1460
|
+
return grouped;
|
|
1461
|
+
}
|
|
1462
|
+
pyImportFrom(pyPackage, ...entities) {
|
|
1463
|
+
const oneLine = `from ${pyPackage} import ${entities.join(", ")}`;
|
|
1464
|
+
if (this.shouldUseSingleLineImport(oneLine, entities)) {
|
|
1465
|
+
this.line(oneLine);
|
|
1466
|
+
} else {
|
|
1467
|
+
this.writeMultiLineImport(pyPackage, entities);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
shouldUseSingleLineImport(oneLine, entities) {
|
|
1471
|
+
return oneLine.length <= MAX_IMPORT_LINE_LENGTH || entities.length === 1;
|
|
1472
|
+
}
|
|
1473
|
+
writeMultiLineImport(pyPackage, entities) {
|
|
1474
|
+
this.line(`from ${pyPackage} import (\\`);
|
|
1475
|
+
this.indentBlock(() => {
|
|
1476
|
+
const remaining = [...entities];
|
|
1477
|
+
while (remaining.length > 0) {
|
|
1478
|
+
const line = this.buildImportLine(remaining, MAX_IMPORT_LINE_LENGTH);
|
|
1479
|
+
this.line(line);
|
|
1480
|
+
}
|
|
1481
|
+
});
|
|
1482
|
+
this.line(")");
|
|
1483
|
+
}
|
|
1484
|
+
pyImportType(identifier) {
|
|
1485
|
+
this.pyImportFrom(this.pyPackage(identifier), pascalCase(identifier.name));
|
|
1486
|
+
}
|
|
1487
|
+
generateResourceFamilies(packageResources) {
|
|
1488
|
+
assert3(this.tsIndex !== void 0);
|
|
1489
|
+
const packages = (
|
|
1490
|
+
//this.helper.getPackages(packageResources, this.opts.rootPackageName);
|
|
1491
|
+
Object.keys(groupByPackages(packageResources)).map(
|
|
1492
|
+
(pkgName) => `${this.opts.rootPackageName}.${pkgName.replaceAll(".", "_")}`
|
|
1493
|
+
)
|
|
1494
|
+
);
|
|
1495
|
+
const families = {};
|
|
1496
|
+
for (const resource of this.tsIndex.collectResources()) {
|
|
1497
|
+
const children = this.tsIndex.resourceChildren(resource.identifier).map((c) => c.name);
|
|
1498
|
+
if (children.length > 0) {
|
|
1499
|
+
const familyName = `${resource.identifier.name}Family`;
|
|
1500
|
+
families[familyName] = children;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
const exportList = Object.keys(families);
|
|
1504
|
+
if (exportList.length === 0) return;
|
|
1505
|
+
this.buildResourceFamiliesFile(packages, families, exportList);
|
|
1506
|
+
}
|
|
1507
|
+
buildResourceFamiliesFile(packages, families, exportList) {
|
|
1508
|
+
this.cat("resource_families.py", () => {
|
|
1509
|
+
this.generateDisclaimer();
|
|
1510
|
+
this.includeResourceFamilyValidator();
|
|
1511
|
+
this.line();
|
|
1512
|
+
this.generateFamilyDefinitions(packages, families);
|
|
1513
|
+
this.generateFamilyExports(exportList);
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
includeResourceFamilyValidator() {
|
|
1517
|
+
const content = fs__default.readFileSync(resolvePyAssets("resource_family_validator.py"), "utf-8");
|
|
1518
|
+
this.line(content);
|
|
1519
|
+
}
|
|
1520
|
+
generateFamilyDefinitions(packages, families) {
|
|
1521
|
+
this.line(`packages = [${packages.map((p) => `'${p}'`).join(", ")}]`);
|
|
1522
|
+
this.line();
|
|
1523
|
+
for (const [familyName, resources] of Object.entries(families)) {
|
|
1524
|
+
this.generateFamilyDefinition(familyName, resources);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
generateFamilyDefinition(familyName, resources) {
|
|
1528
|
+
const listName = `${familyName}_resources`;
|
|
1529
|
+
this.line(`${listName} = [${resources.map((r) => `'${r}'`).join(", ")}]`);
|
|
1530
|
+
this.line();
|
|
1531
|
+
this.line(`def validate_and_downcast_${familyName}(v: Any) -> Any:`);
|
|
1532
|
+
this.line(` return validate_and_downcast(v, packages, ${listName})`);
|
|
1533
|
+
this.line();
|
|
1534
|
+
this.line(`type ${familyName} = Annotated[Any, BeforeValidator(validate_and_downcast_${familyName})]`);
|
|
1535
|
+
this.line();
|
|
1536
|
+
}
|
|
1537
|
+
generateFamilyExports(exportList) {
|
|
1538
|
+
this.line(`__all__ = [${exportList.map((e) => `'${e}'`).join(", ")}]`);
|
|
1539
|
+
}
|
|
1540
|
+
buildPyPackageName(packageName) {
|
|
1541
|
+
const parts = packageName ? [snakeCase(packageName)] : [""];
|
|
1542
|
+
return parts.join(".");
|
|
1543
|
+
}
|
|
1544
|
+
pyFhirPackage(identifier) {
|
|
1545
|
+
return this.pyFhirPackageByName(identifier.package);
|
|
1546
|
+
}
|
|
1547
|
+
pyFhirPackageByName(name) {
|
|
1548
|
+
return [this.opts.rootPackageName, this.buildPyPackageName(name)].join(".");
|
|
1549
|
+
}
|
|
1550
|
+
pyPackage(identifier) {
|
|
1551
|
+
if (identifier.kind === "complex-type") {
|
|
1552
|
+
return `${this.pyFhirPackage(identifier)}.base`;
|
|
767
1553
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
var resolveFsElementGenealogy = (genealogy, path) => {
|
|
771
|
-
const [top, ...rest] = path;
|
|
772
|
-
if (top === void 0) return [];
|
|
773
|
-
return genealogy.map((fs4) => {
|
|
774
|
-
if (!fs4.elements) return void 0;
|
|
775
|
-
let elem = fs4.elements?.[top];
|
|
776
|
-
for (const k of rest) {
|
|
777
|
-
elem = elem?.elements?.[k];
|
|
1554
|
+
if (identifier.kind === "resource") {
|
|
1555
|
+
return [this.pyFhirPackage(identifier), snakeCase(identifier.name)].join(".");
|
|
778
1556
|
}
|
|
779
|
-
return
|
|
780
|
-
}
|
|
1557
|
+
return this.pyFhirPackage(identifier);
|
|
1558
|
+
}
|
|
1559
|
+
getFieldFormatFunction(format2) {
|
|
1560
|
+
if (!AVAILABLE_STRING_FORMATS[format2]) {
|
|
1561
|
+
this.logger()?.warn(`Unknown field format '${format2}'. Defaulting to SnakeCase.`);
|
|
1562
|
+
this.logger()?.warn(`Supported formats: ${Object.keys(AVAILABLE_STRING_FORMATS).join(", ")}`);
|
|
1563
|
+
return snakeCase;
|
|
1564
|
+
}
|
|
1565
|
+
return AVAILABLE_STRING_FORMATS[format2];
|
|
1566
|
+
}
|
|
781
1567
|
};
|
|
782
|
-
function fsElementSnapshot(genealogy) {
|
|
783
|
-
const revGenealogy = genealogy.reverse();
|
|
784
|
-
const snapshot = Object.assign({}, ...revGenealogy);
|
|
785
|
-
snapshot.elements = void 0;
|
|
786
|
-
return snapshot;
|
|
787
|
-
}
|
|
788
1568
|
|
|
789
1569
|
// src/typeschema/core/identifier.ts
|
|
790
1570
|
function dropVersionFromUrl(url) {
|
|
@@ -856,7 +1636,7 @@ function mkNestedIdentifier(register, fhirSchema, path, logger) {
|
|
|
856
1636
|
const nestedTypeOrigins = {};
|
|
857
1637
|
if (fhirSchema.derivation === "constraint") {
|
|
858
1638
|
const specializations = register.resolveFsSpecializations(fhirSchema.package_meta, fhirSchema.url);
|
|
859
|
-
const nestedTypeGenealogy = specializations.map((
|
|
1639
|
+
const nestedTypeGenealogy = specializations.map((fs7) => mkNestedTypes(register, fs7, logger)).filter((e) => e !== void 0).flat();
|
|
860
1640
|
for (const nt of nestedTypeGenealogy.reverse()) {
|
|
861
1641
|
nestedTypeOrigins[nt.identifier.name] = nt.identifier.url;
|
|
862
1642
|
}
|
|
@@ -955,10 +1735,10 @@ function isRequired(register, fhirSchema, path) {
|
|
|
955
1735
|
const fieldName = path[path.length - 1];
|
|
956
1736
|
if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
|
|
957
1737
|
const parentPath = path.slice(0, -1);
|
|
958
|
-
const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((
|
|
959
|
-
if (parentPath.length === 0) return
|
|
960
|
-
if (!
|
|
961
|
-
let elem =
|
|
1738
|
+
const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs7) => {
|
|
1739
|
+
if (parentPath.length === 0) return fs7.required || [];
|
|
1740
|
+
if (!fs7.elements) return [];
|
|
1741
|
+
let elem = fs7;
|
|
962
1742
|
for (const k of parentPath) {
|
|
963
1743
|
elem = elem?.elements?.[k];
|
|
964
1744
|
}
|
|
@@ -970,10 +1750,10 @@ function isExcluded(register, fhirSchema, path) {
|
|
|
970
1750
|
const fieldName = path[path.length - 1];
|
|
971
1751
|
if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
|
|
972
1752
|
const parentPath = path.slice(0, -1);
|
|
973
|
-
const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((
|
|
974
|
-
if (parentPath.length === 0) return
|
|
975
|
-
if (!
|
|
976
|
-
let elem =
|
|
1753
|
+
const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs7) => {
|
|
1754
|
+
if (parentPath.length === 0) return fs7.excluded || [];
|
|
1755
|
+
if (!fs7.elements) return [];
|
|
1756
|
+
let elem = fs7;
|
|
977
1757
|
for (const k of parentPath) {
|
|
978
1758
|
elem = elem?.elements?.[k];
|
|
979
1759
|
}
|
|
@@ -985,9 +1765,9 @@ var buildReferences = (register, fhirSchema, element) => {
|
|
|
985
1765
|
if (!element.refers) return void 0;
|
|
986
1766
|
return element.refers.map((ref) => {
|
|
987
1767
|
const curl = register.ensureSpecializationCanonicalUrl(ref);
|
|
988
|
-
const
|
|
989
|
-
if (!
|
|
990
|
-
return mkIdentifier(
|
|
1768
|
+
const fs7 = register.resolveFs(fhirSchema.package_meta, curl);
|
|
1769
|
+
if (!fs7) throw new Error(`Failed to resolve fs for ${curl}`);
|
|
1770
|
+
return mkIdentifier(fs7);
|
|
991
1771
|
});
|
|
992
1772
|
};
|
|
993
1773
|
function buildFieldType(register, fhirSchema, path, element, logger) {
|
|
@@ -1065,7 +1845,7 @@ function extractValueSetConceptsByUrl(register, pkg, valueSetUrl, logger) {
|
|
|
1065
1845
|
function extractValueSetConcepts(register, valueSet, _logger) {
|
|
1066
1846
|
if (valueSet.expansion?.contains) {
|
|
1067
1847
|
return valueSet.expansion.contains.filter((item) => item.code !== void 0).map((item) => {
|
|
1068
|
-
|
|
1848
|
+
assert3(item.code);
|
|
1069
1849
|
return {
|
|
1070
1850
|
code: item.code,
|
|
1071
1851
|
display: item.display,
|
|
@@ -1270,63 +2050,342 @@ function transformFhirSchemaResource(register, fhirSchema, logger) {
|
|
|
1270
2050
|
`Base resource not found '${fhirSchema.base}' for <${fhirSchema.url}> from ${packageMetaToFhir(fhirSchema.package_meta)}`
|
|
1271
2051
|
);
|
|
1272
2052
|
}
|
|
1273
|
-
base = mkIdentifier(baseFs);
|
|
2053
|
+
base = mkIdentifier(baseFs);
|
|
2054
|
+
}
|
|
2055
|
+
const fields = mkFields(register, fhirSchema, [], fhirSchema.elements, logger);
|
|
2056
|
+
const nested = mkNestedTypes(register, fhirSchema, logger);
|
|
2057
|
+
const dependencies = extractDependencies(identifier, base, fields, nested);
|
|
2058
|
+
const typeSchema = {
|
|
2059
|
+
identifier,
|
|
2060
|
+
base,
|
|
2061
|
+
fields,
|
|
2062
|
+
nested,
|
|
2063
|
+
description: fhirSchema.description,
|
|
2064
|
+
dependencies
|
|
2065
|
+
};
|
|
2066
|
+
const bindingSchemas = collectBindingSchemas(register, fhirSchema, logger);
|
|
2067
|
+
return [typeSchema, ...bindingSchemas];
|
|
2068
|
+
}
|
|
2069
|
+
async function transformFhirSchema(register, fhirSchema, logger) {
|
|
2070
|
+
const schemas = transformFhirSchemaResource(register, fhirSchema, logger);
|
|
2071
|
+
if (isExtensionSchema(fhirSchema, mkIdentifier(fhirSchema))) {
|
|
2072
|
+
const schema = schemas[0];
|
|
2073
|
+
if (!schema) throw new Error(`Expected schema to be defined`);
|
|
2074
|
+
schema.metadata = {
|
|
2075
|
+
isExtension: true
|
|
2076
|
+
// Mark as extension for file organization
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2079
|
+
return schemas;
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// src/fhir-types/hl7-fhir-r4-core/CodeSystem.ts
|
|
2083
|
+
var isCodeSystem = (resource) => {
|
|
2084
|
+
return resource !== null && typeof resource === "object" && resource.resourceType === "CodeSystem";
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
// src/fhir-types/hl7-fhir-r4-core/ValueSet.ts
|
|
2088
|
+
var isValueSet = (resource) => {
|
|
2089
|
+
return resource !== null && typeof resource === "object" && resource.resourceType === "ValueSet";
|
|
2090
|
+
};
|
|
2091
|
+
|
|
2092
|
+
// src/typeschema/register.ts
|
|
2093
|
+
var readPackageDependencies = async (manager, packageMeta) => {
|
|
2094
|
+
const packageJSON = await manager.packageJson(packageMeta.name);
|
|
2095
|
+
const dependencies = packageJSON.dependencies;
|
|
2096
|
+
if (dependencies !== void 0) {
|
|
2097
|
+
return Object.entries(dependencies).map(([name, version]) => {
|
|
2098
|
+
return { name, version };
|
|
2099
|
+
});
|
|
2100
|
+
}
|
|
2101
|
+
return [];
|
|
2102
|
+
};
|
|
2103
|
+
var mkEmptyPkgIndex = (pkg) => {
|
|
2104
|
+
return {
|
|
2105
|
+
pkg,
|
|
2106
|
+
canonicalResolution: {},
|
|
2107
|
+
fhirSchemas: {},
|
|
2108
|
+
valueSets: {}
|
|
2109
|
+
};
|
|
2110
|
+
};
|
|
2111
|
+
var mkPackageAwareResolver = async (manager, pkg, deep, acc, logger) => {
|
|
2112
|
+
const pkgId = packageMetaToFhir(pkg);
|
|
2113
|
+
logger?.info(`${" ".repeat(deep * 2)}+ ${pkgId}`);
|
|
2114
|
+
if (acc[pkgId]) return acc[pkgId];
|
|
2115
|
+
const index = mkEmptyPkgIndex(pkg);
|
|
2116
|
+
for (const resource of await manager.search({ package: pkg })) {
|
|
2117
|
+
const rawUrl = resource.url;
|
|
2118
|
+
if (!rawUrl) continue;
|
|
2119
|
+
if (!(isStructureDefinition(resource) || isValueSet(resource) || isCodeSystem(resource))) continue;
|
|
2120
|
+
const url = rawUrl;
|
|
2121
|
+
if (index.canonicalResolution[url]) logger?.dry_warn(`Duplicate canonical URL: ${url} at ${pkgId}.`);
|
|
2122
|
+
index.canonicalResolution[url] = [{ deep, pkg, pkgId, resource }];
|
|
2123
|
+
}
|
|
2124
|
+
const deps = await readPackageDependencies(manager, pkg);
|
|
2125
|
+
for (const depPkg of deps) {
|
|
2126
|
+
const { canonicalResolution } = await mkPackageAwareResolver(manager, depPkg, deep + 1, acc, logger);
|
|
2127
|
+
for (const [surl, resolutions] of Object.entries(canonicalResolution)) {
|
|
2128
|
+
const url = surl;
|
|
2129
|
+
index.canonicalResolution[url] = [...index.canonicalResolution[url] || [], ...resolutions];
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
for (const resolutionOptions of Object.values(index.canonicalResolution)) {
|
|
2133
|
+
resolutionOptions.sort((a, b) => a.deep - b.deep);
|
|
2134
|
+
}
|
|
2135
|
+
acc[pkgId] = index;
|
|
2136
|
+
return index;
|
|
2137
|
+
};
|
|
2138
|
+
var packageAgnosticResolveCanonical = (resolver, url, _logger) => {
|
|
2139
|
+
const options = Object.values(resolver).flatMap((pkg) => pkg.canonicalResolution[url]);
|
|
2140
|
+
if (!options) throw new Error(`No canonical resolution found for ${url} in any package`);
|
|
2141
|
+
return options[0]?.resource;
|
|
2142
|
+
};
|
|
2143
|
+
var registerFromManager = async (manager, { logger, fallbackPackageForNameResolution, focusedPackages }) => {
|
|
2144
|
+
const packages = focusedPackages ?? await manager.packages();
|
|
2145
|
+
const resolver = {};
|
|
2146
|
+
for (const pkg of packages) {
|
|
2147
|
+
await mkPackageAwareResolver(manager, pkg, 0, resolver, logger);
|
|
2148
|
+
}
|
|
2149
|
+
for (const { pkg, canonicalResolution } of Object.values(resolver)) {
|
|
2150
|
+
const pkgId = packageMetaToFhir(pkg);
|
|
2151
|
+
if (!resolver[pkgId]) throw new Error(`Package ${pkgId} not found`);
|
|
2152
|
+
let counter = 0;
|
|
2153
|
+
logger?.info(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' begins...`);
|
|
2154
|
+
for (const [_url, options] of Object.entries(canonicalResolution)) {
|
|
2155
|
+
const resolition = options[0];
|
|
2156
|
+
if (!resolition) throw new Error(`Resource not found`);
|
|
2157
|
+
const resource = resolition.resource;
|
|
2158
|
+
const resourcePkg = resolition.pkg;
|
|
2159
|
+
if (isStructureDefinition(resource)) {
|
|
2160
|
+
const rfs = enrichFHIRSchema(
|
|
2161
|
+
fhirschema.translate(resource),
|
|
2162
|
+
resourcePkg
|
|
2163
|
+
);
|
|
2164
|
+
counter++;
|
|
2165
|
+
resolver[pkgId].fhirSchemas[rfs.url] = rfs;
|
|
2166
|
+
}
|
|
2167
|
+
if (isValueSet(resource)) {
|
|
2168
|
+
const rvs = enrichValueSet(resource, resourcePkg);
|
|
2169
|
+
resolver[pkgId].valueSets[rvs.url] = rvs;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
logger?.info(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' completed: ${counter} successful`);
|
|
2173
|
+
}
|
|
2174
|
+
const resolveFs = (pkg, canonicalUrl) => {
|
|
2175
|
+
return resolver[packageMetaToFhir(pkg)]?.fhirSchemas[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.fhirSchemas[canonicalUrl];
|
|
2176
|
+
};
|
|
2177
|
+
const resolveVs = (pkg, canonicalUrl) => {
|
|
2178
|
+
return resolver[packageMetaToFhir(pkg)]?.valueSets[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.valueSets[canonicalUrl];
|
|
2179
|
+
};
|
|
2180
|
+
const ensureSpecializationCanonicalUrl = (name) => name.match(/^[a-zA-Z0-9]+$/) && `http://hl7.org/fhir/StructureDefinition/${name}` || name;
|
|
2181
|
+
const resolveFsGenealogy = (pkg, canonicalUrl) => {
|
|
2182
|
+
let fs7 = resolveFs(pkg, canonicalUrl);
|
|
2183
|
+
if (fs7 === void 0) throw new Error(`Failed to resolve FHIR Schema: '${canonicalUrl}'`);
|
|
2184
|
+
const genealogy = [fs7];
|
|
2185
|
+
while (fs7?.base) {
|
|
2186
|
+
const pkg2 = fs7.package_meta;
|
|
2187
|
+
const baseUrl = ensureSpecializationCanonicalUrl(fs7.base);
|
|
2188
|
+
fs7 = resolveFs(pkg2, baseUrl);
|
|
2189
|
+
if (fs7 === void 0)
|
|
2190
|
+
throw new Error(
|
|
2191
|
+
`Failed to resolve FHIR Schema base for '${canonicalUrl}'. Problem: '${baseUrl}' from '${packageMetaToFhir(pkg2)}'`
|
|
2192
|
+
);
|
|
2193
|
+
genealogy.push(fs7);
|
|
2194
|
+
}
|
|
2195
|
+
return genealogy;
|
|
2196
|
+
};
|
|
2197
|
+
const resolveFsSpecializations = (pkg, canonicalUrl) => {
|
|
2198
|
+
return resolveFsGenealogy(pkg, canonicalUrl).filter((fs7) => fs7.derivation === "specialization");
|
|
2199
|
+
};
|
|
2200
|
+
const resolveElementSnapshot = (fhirSchema, path) => {
|
|
2201
|
+
const geneology = resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
|
|
2202
|
+
const elemGeneology = resolveFsElementGenealogy(geneology, path);
|
|
2203
|
+
const elemSnapshot = fsElementSnapshot(elemGeneology);
|
|
2204
|
+
return elemSnapshot;
|
|
2205
|
+
};
|
|
2206
|
+
const getAllElementKeys = (elems) => {
|
|
2207
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2208
|
+
for (const [key, elem] of Object.entries(elems)) {
|
|
2209
|
+
keys.add(key);
|
|
2210
|
+
for (const choiceKey of elem?.choices || []) {
|
|
2211
|
+
if (!elems[choiceKey]) {
|
|
2212
|
+
keys.add(choiceKey);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
return Array.from(keys);
|
|
2217
|
+
};
|
|
2218
|
+
return {
|
|
2219
|
+
...manager,
|
|
2220
|
+
testAppendFs(fs7) {
|
|
2221
|
+
const rfs = enrichFHIRSchema(fs7);
|
|
2222
|
+
const pkgId = packageMetaToFhir(rfs.package_meta);
|
|
2223
|
+
if (!resolver[pkgId]) resolver[pkgId] = mkEmptyPkgIndex(rfs.package_meta);
|
|
2224
|
+
resolver[pkgId].fhirSchemas[rfs.url] = rfs;
|
|
2225
|
+
},
|
|
2226
|
+
resolveFs,
|
|
2227
|
+
resolveFsGenealogy,
|
|
2228
|
+
resolveFsSpecializations,
|
|
2229
|
+
ensureSpecializationCanonicalUrl,
|
|
2230
|
+
resolveSd: (_pkg, canonicalUrl) => {
|
|
2231
|
+
const res = packageAgnosticResolveCanonical(resolver, canonicalUrl);
|
|
2232
|
+
if (isStructureDefinition(res)) return res;
|
|
2233
|
+
return void 0;
|
|
2234
|
+
},
|
|
2235
|
+
allFs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.fhirSchemas)),
|
|
2236
|
+
allVs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.valueSets)),
|
|
2237
|
+
resolveVs,
|
|
2238
|
+
resolveAny: (canonicalUrl) => packageAgnosticResolveCanonical(resolver, canonicalUrl),
|
|
2239
|
+
resolveElementSnapshot,
|
|
2240
|
+
getAllElementKeys,
|
|
2241
|
+
resolver,
|
|
2242
|
+
resolutionTree: () => {
|
|
2243
|
+
const res = {};
|
|
2244
|
+
for (const [_pkgId, pkgIndex] of Object.entries(resolver)) {
|
|
2245
|
+
const pkgName = pkgIndex.pkg.name;
|
|
2246
|
+
res[pkgName] = {};
|
|
2247
|
+
for (const [surl, resolutions] of Object.entries(pkgIndex.canonicalResolution)) {
|
|
2248
|
+
const url = surl;
|
|
2249
|
+
res[pkgName][url] = [];
|
|
2250
|
+
for (const resolution of resolutions) {
|
|
2251
|
+
res[pkgName][url].push({ deep: resolution.deep, pkg: resolution.pkg });
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
return res;
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
};
|
|
2259
|
+
var resolveFsElementGenealogy = (genealogy, path) => {
|
|
2260
|
+
const [top, ...rest] = path;
|
|
2261
|
+
if (top === void 0) return [];
|
|
2262
|
+
return genealogy.map((fs7) => {
|
|
2263
|
+
if (!fs7.elements) return void 0;
|
|
2264
|
+
let elem = fs7.elements?.[top];
|
|
2265
|
+
for (const k of rest) {
|
|
2266
|
+
elem = elem?.elements?.[k];
|
|
2267
|
+
}
|
|
2268
|
+
return elem;
|
|
2269
|
+
}).filter((elem) => elem !== void 0);
|
|
2270
|
+
};
|
|
2271
|
+
function fsElementSnapshot(genealogy) {
|
|
2272
|
+
const revGenealogy = genealogy.reverse();
|
|
2273
|
+
const snapshot = Object.assign({}, ...revGenealogy);
|
|
2274
|
+
snapshot.elements = void 0;
|
|
2275
|
+
return snapshot;
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
// src/typeschema/index.ts
|
|
2279
|
+
var codeableReferenceInR4 = "Use CodeableReference which is not provided by FHIR R4.";
|
|
2280
|
+
var availabilityInR4 = "Use Availability which is not provided by FHIR R4.";
|
|
2281
|
+
var skipMe = {
|
|
2282
|
+
"hl7.fhir.uv.extensions.r4#1.0.0": {
|
|
2283
|
+
"http://hl7.org/fhir/StructureDefinition/extended-contact-availability": availabilityInR4,
|
|
2284
|
+
"http://hl7.org/fhir/StructureDefinition/immunization-procedure": codeableReferenceInR4,
|
|
2285
|
+
"http://hl7.org/fhir/StructureDefinition/specimen-additive": codeableReferenceInR4,
|
|
2286
|
+
"http://hl7.org/fhir/StructureDefinition/workflow-barrier": codeableReferenceInR4,
|
|
2287
|
+
"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor": codeableReferenceInR4,
|
|
2288
|
+
"http://hl7.org/fhir/StructureDefinition/workflow-reason": codeableReferenceInR4
|
|
2289
|
+
},
|
|
2290
|
+
"hl7.fhir.r5.core#5.0.0": {
|
|
2291
|
+
"http://hl7.org/fhir/StructureDefinition/shareablecodesystem": "FIXME: CodeSystem.concept.concept defined by ElementReference. FHIR Schema generator output broken value in it, so we just skip it for now."
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
var generateTypeSchemas = async (register, logger) => {
|
|
2295
|
+
const fhirSchemas = [];
|
|
2296
|
+
for (const fhirSchema of register.allFs()) {
|
|
2297
|
+
const pkgId = packageMetaToFhir(fhirSchema.package_meta);
|
|
2298
|
+
if (skipMe[pkgId]?.[fhirSchema.url]) {
|
|
2299
|
+
logger?.dry_warn(`Skip ${fhirSchema.url} from ${pkgId}. Reason: ${skipMe[pkgId]?.[fhirSchema.url]}`);
|
|
2300
|
+
continue;
|
|
2301
|
+
}
|
|
2302
|
+
fhirSchemas.push(...await transformFhirSchema(register, fhirSchema, logger));
|
|
1274
2303
|
}
|
|
1275
|
-
const
|
|
1276
|
-
|
|
1277
|
-
const dependencies = extractDependencies(identifier, base, fields, nested);
|
|
1278
|
-
const typeSchema = {
|
|
1279
|
-
identifier,
|
|
1280
|
-
base,
|
|
1281
|
-
fields,
|
|
1282
|
-
nested,
|
|
1283
|
-
description: fhirSchema.description,
|
|
1284
|
-
dependencies
|
|
1285
|
-
};
|
|
1286
|
-
const bindingSchemas = collectBindingSchemas(register, fhirSchema, logger);
|
|
1287
|
-
return [typeSchema, ...bindingSchemas];
|
|
1288
|
-
}
|
|
1289
|
-
async function transformFhirSchema(register, fhirSchema, logger) {
|
|
1290
|
-
const schemas = transformFhirSchemaResource(register, fhirSchema, logger);
|
|
1291
|
-
if (isExtensionSchema(fhirSchema, mkIdentifier(fhirSchema))) {
|
|
1292
|
-
const schema = schemas[0];
|
|
1293
|
-
if (!schema) throw new Error(`Expected schema to be defined`);
|
|
1294
|
-
schema.metadata = {
|
|
1295
|
-
isExtension: true
|
|
1296
|
-
// Mark as extension for file organization
|
|
1297
|
-
};
|
|
2304
|
+
for (const vsSchema of register.allVs()) {
|
|
2305
|
+
fhirSchemas.push(await transformValueSet(register, vsSchema));
|
|
1298
2306
|
}
|
|
1299
|
-
return
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
const
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
if (
|
|
1308
|
-
|
|
2307
|
+
return fhirSchemas;
|
|
2308
|
+
};
|
|
2309
|
+
var mutableSelectFields = (schema, selectFields) => {
|
|
2310
|
+
const selectedFields = {};
|
|
2311
|
+
const selectPolimorphic = {};
|
|
2312
|
+
for (const fieldName of selectFields) {
|
|
2313
|
+
const field = schema.fields?.[fieldName];
|
|
2314
|
+
if (!schema.fields || !field) throw new Error(`Field ${fieldName} not found`);
|
|
2315
|
+
if (isChoiceDeclarationField(field)) {
|
|
2316
|
+
if (!selectPolimorphic[fieldName]) selectPolimorphic[fieldName] = {};
|
|
2317
|
+
selectPolimorphic[fieldName].declaration = field.choices;
|
|
2318
|
+
} else if (isChoiceInstanceField(field)) {
|
|
2319
|
+
const choiceName = field.choiceOf;
|
|
2320
|
+
if (!selectPolimorphic[choiceName]) selectPolimorphic[choiceName] = {};
|
|
2321
|
+
selectPolimorphic[choiceName].instances = [...selectPolimorphic[choiceName].instances ?? [], fieldName];
|
|
2322
|
+
} else {
|
|
2323
|
+
selectedFields[fieldName] = field;
|
|
2324
|
+
}
|
|
1309
2325
|
}
|
|
1310
|
-
for (const [
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
2326
|
+
for (const [choiceName, { declaration, instances }] of Object.entries(selectPolimorphic)) {
|
|
2327
|
+
const choices = instances ?? declaration;
|
|
2328
|
+
assert3(choices);
|
|
2329
|
+
for (const choiceInstanceName of choices) {
|
|
2330
|
+
const field = schema.fields?.[choiceInstanceName];
|
|
2331
|
+
assert3(field);
|
|
2332
|
+
selectedFields[choiceInstanceName] = field;
|
|
1314
2333
|
}
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
2334
|
+
const decl = schema.fields?.[choiceName];
|
|
2335
|
+
assert3(decl);
|
|
2336
|
+
selectedFields[choiceName] = { ...decl, choices };
|
|
1318
2337
|
}
|
|
1319
|
-
|
|
2338
|
+
schema.fields = selectedFields;
|
|
1320
2339
|
};
|
|
1321
|
-
var
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
if (schema.fields && !schema.fields[fieldName]) throw new Error(`Field ${fieldName} not found`);
|
|
2340
|
+
var mutableIgnoreFields = (schema, ignoreFields) => {
|
|
2341
|
+
for (const fieldName of ignoreFields) {
|
|
2342
|
+
const field = schema.fields?.[fieldName];
|
|
2343
|
+
if (!schema.fields || !field) throw new Error(`Field ${fieldName} not found`);
|
|
1326
2344
|
if (schema.fields) {
|
|
2345
|
+
if (isChoiceDeclarationField(field)) {
|
|
2346
|
+
for (const choiceName of field.choices) {
|
|
2347
|
+
delete schema.fields[choiceName];
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
if (isChoiceInstanceField(field)) {
|
|
2351
|
+
const choiceDeclaration = schema.fields[field.choiceOf];
|
|
2352
|
+
assert3(isChoiceDeclarationField(choiceDeclaration));
|
|
2353
|
+
choiceDeclaration.choices = choiceDeclaration.choices.filter((c) => c !== fieldName);
|
|
2354
|
+
if (choiceDeclaration.choices.length === 0) {
|
|
2355
|
+
delete schema.fields[field.choiceOf];
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
1327
2358
|
delete schema.fields[fieldName];
|
|
1328
2359
|
}
|
|
1329
2360
|
}
|
|
2361
|
+
};
|
|
2362
|
+
var treeShakeTypeSchema = (schema, rule, _logger) => {
|
|
2363
|
+
schema = structuredClone(schema);
|
|
2364
|
+
if (isPrimitiveTypeSchema(schema) || isValueSetTypeSchema(schema) || isBindingSchema(schema)) return schema;
|
|
2365
|
+
if (rule.selectFields) {
|
|
2366
|
+
if (rule.ignoreFields) throw new Error("Cannot use both ignoreFields and selectFields in the same rule");
|
|
2367
|
+
mutableSelectFields(schema, rule.selectFields);
|
|
2368
|
+
}
|
|
2369
|
+
if (rule.ignoreFields) {
|
|
2370
|
+
if (rule.selectFields) throw new Error("Cannot use both ignoreFields and selectFields in the same rule");
|
|
2371
|
+
mutableIgnoreFields(schema, rule.ignoreFields);
|
|
2372
|
+
}
|
|
2373
|
+
if (schema.nested) {
|
|
2374
|
+
const usedTypes = /* @__PURE__ */ new Set();
|
|
2375
|
+
const collectUsedNestedTypes = (s) => {
|
|
2376
|
+
Object.values(s.fields ?? {}).filter(isNotChoiceDeclarationField).filter((f) => isNestedIdentifier(f.type)).forEach((f) => {
|
|
2377
|
+
const url = f.type.url;
|
|
2378
|
+
if (!usedTypes.has(url)) {
|
|
2379
|
+
usedTypes.add(url);
|
|
2380
|
+
const nestedTypeDef = schema.nested?.find((f2) => f2.identifier.url === url);
|
|
2381
|
+
assert3(nestedTypeDef);
|
|
2382
|
+
collectUsedNestedTypes(nestedTypeDef);
|
|
2383
|
+
}
|
|
2384
|
+
});
|
|
2385
|
+
};
|
|
2386
|
+
collectUsedNestedTypes(schema);
|
|
2387
|
+
schema.nested = schema.nested.filter((n) => usedTypes.has(n.identifier.url));
|
|
2388
|
+
}
|
|
1330
2389
|
schema.dependencies = extractDependencies(schema.identifier, schema.base, schema.fields, schema.nested);
|
|
1331
2390
|
return schema;
|
|
1332
2391
|
};
|
|
@@ -1351,7 +2410,10 @@ var treeShake = (tsIndex, treeShake2, { resolutionTree, logger }) => {
|
|
|
1351
2410
|
if (!schema.dependencies) continue;
|
|
1352
2411
|
schema.dependencies.forEach((dep) => {
|
|
1353
2412
|
const depSchema = tsIndex.resolve(dep);
|
|
1354
|
-
if (!depSchema)
|
|
2413
|
+
if (!depSchema)
|
|
2414
|
+
throw new Error(
|
|
2415
|
+
`Dependent schema ${JSON.stringify(dep)} not found for ${JSON.stringify(schema.identifier)}`
|
|
2416
|
+
);
|
|
1355
2417
|
const id = JSON.stringify(depSchema.identifier);
|
|
1356
2418
|
if (!acc[id]) newSchemas.push(depSchema);
|
|
1357
2419
|
});
|
|
@@ -1369,334 +2431,652 @@ var treeShake = (tsIndex, treeShake2, { resolutionTree, logger }) => {
|
|
|
1369
2431
|
const shaked = collectDeps(focusedSchemas, {});
|
|
1370
2432
|
return mkTypeSchemaIndex(shaked, { resolutionTree, logger });
|
|
1371
2433
|
};
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
directPairs.push({ parent: schema.base, child: schema.identifier });
|
|
1378
|
-
}
|
|
2434
|
+
|
|
2435
|
+
// src/api/mustache/generator/DebugMixinProvider.ts
|
|
2436
|
+
var DebugMixinProvider = class {
|
|
2437
|
+
constructor(mode) {
|
|
2438
|
+
this.mode = mode;
|
|
1379
2439
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
2440
|
+
apply(target) {
|
|
2441
|
+
return this._addDebug(target);
|
|
2442
|
+
}
|
|
2443
|
+
_addDebug(value) {
|
|
2444
|
+
if (Array.isArray(value)) {
|
|
2445
|
+
return value.map((v) => this._addDebug(v));
|
|
1386
2446
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
allPairs.push({ parent: pair.parent, child: transitiveChild });
|
|
2447
|
+
if (value !== null && typeof value === "object") {
|
|
2448
|
+
const obj = value;
|
|
2449
|
+
const result = {};
|
|
2450
|
+
const debugString = JSON.stringify(obj, null, this.mode === "FORMATTED" ? 2 : void 0);
|
|
2451
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
2452
|
+
result[key] = this._addDebug(val);
|
|
1394
2453
|
}
|
|
2454
|
+
result.debug = debugString;
|
|
2455
|
+
return result;
|
|
1395
2456
|
}
|
|
2457
|
+
return value;
|
|
1396
2458
|
}
|
|
1397
|
-
return allPairs;
|
|
1398
2459
|
};
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
2460
|
+
|
|
2461
|
+
// src/api/mustache/generator/LambdaMixinProvider.ts
|
|
2462
|
+
var LambdaMixinProvider = class {
|
|
2463
|
+
constructor(nameGenerator) {
|
|
2464
|
+
this.nameGenerator = nameGenerator;
|
|
2465
|
+
this.lambda = {
|
|
2466
|
+
saveTypeName: () => (text, render) => this.nameGenerator.generateType(render(text)),
|
|
2467
|
+
saveEnumValueName: () => (text, render) => this.nameGenerator.generateEnumValue(render(text)),
|
|
2468
|
+
saveFieldName: () => (text, render) => this.nameGenerator.generateField(render(text)),
|
|
2469
|
+
camelCase: () => (text, render) => camelCase(render(text)),
|
|
2470
|
+
snakeCase: () => (text, render) => snakeCase(render(text)),
|
|
2471
|
+
pascalCase: () => (text, render) => pascalCase(render(text)),
|
|
2472
|
+
kebabCase: () => (text, render) => kebabCase(render(text)),
|
|
2473
|
+
lowerCase: () => (text, render) => render(text).toLowerCase(),
|
|
2474
|
+
upperCase: () => (text, render) => render(text).toUpperCase()
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
lambda;
|
|
2478
|
+
apply(target) {
|
|
2479
|
+
return {
|
|
2480
|
+
...target,
|
|
2481
|
+
lambda: this.lambda
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
};
|
|
2485
|
+
|
|
2486
|
+
// src/api/mustache/generator/NameGenerator.ts
|
|
2487
|
+
var NameGenerator = class {
|
|
2488
|
+
constructor(keywords, typeMap, nameTransformations, unsaveCharacterPattern) {
|
|
2489
|
+
this.keywords = keywords;
|
|
2490
|
+
this.typeMap = typeMap;
|
|
2491
|
+
this.nameTransformations = nameTransformations;
|
|
2492
|
+
this.unsaveCharacterPattern = unsaveCharacterPattern;
|
|
2493
|
+
}
|
|
2494
|
+
_replaceUnsaveChars(name) {
|
|
2495
|
+
const pattern = this.unsaveCharacterPattern instanceof RegExp ? this.unsaveCharacterPattern : new RegExp(this.unsaveCharacterPattern, "g");
|
|
2496
|
+
return name.replace(pattern, "_");
|
|
2497
|
+
}
|
|
2498
|
+
_applyNameTransformations(name, transformations) {
|
|
2499
|
+
for (const transformation of this.nameTransformations.common) {
|
|
2500
|
+
name = name.replace(
|
|
2501
|
+
transformation.pattern instanceof RegExp ? transformation.pattern : new RegExp(transformation.pattern, "g"),
|
|
2502
|
+
transformation.format
|
|
2503
|
+
);
|
|
1410
2504
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
2505
|
+
for (const transformation of transformations) {
|
|
2506
|
+
name = name.replace(
|
|
2507
|
+
transformation.pattern instanceof RegExp ? transformation.pattern : new RegExp(transformation.pattern, "g"),
|
|
2508
|
+
transformation.format
|
|
2509
|
+
);
|
|
2510
|
+
}
|
|
2511
|
+
return name;
|
|
1415
2512
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
2513
|
+
_generateTypeName(name) {
|
|
2514
|
+
if (this.typeMap[name]) {
|
|
2515
|
+
name = this.typeMap[name];
|
|
2516
|
+
} else {
|
|
2517
|
+
name = this._applyNameTransformations(name, this.nameTransformations.type);
|
|
2518
|
+
name = name.charAt(0).toUpperCase() + name.slice(1);
|
|
2519
|
+
if (this.keywords.has(name)) {
|
|
2520
|
+
return `_${name}`;
|
|
1423
2521
|
}
|
|
2522
|
+
name = this._replaceUnsaveChars(name);
|
|
1424
2523
|
}
|
|
1425
|
-
return
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
return
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
while (cur) {
|
|
1434
|
-
res.push(cur);
|
|
1435
|
-
const base = cur.base;
|
|
1436
|
-
if (base === void 0) break;
|
|
1437
|
-
const resolved = resolve3(base);
|
|
1438
|
-
if (!resolved) {
|
|
1439
|
-
logger?.warn(
|
|
1440
|
-
`Failed to resolve base type: ${res.map((e) => `${e.identifier.url} (${e.identifier.kind})`).join(", ")}`
|
|
1441
|
-
);
|
|
1442
|
-
return void 0;
|
|
1443
|
-
}
|
|
1444
|
-
cur = resolved;
|
|
2524
|
+
return name;
|
|
2525
|
+
}
|
|
2526
|
+
generateEnumType(name) {
|
|
2527
|
+
return this._generateTypeName(name);
|
|
2528
|
+
}
|
|
2529
|
+
_generateTypeFromTypeRef(typeRef) {
|
|
2530
|
+
if (typeRef.kind === "primitive-type") {
|
|
2531
|
+
return this._generateTypeName(typeRef.name);
|
|
1445
2532
|
}
|
|
1446
|
-
return
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
2533
|
+
return this._generateTypeName(
|
|
2534
|
+
typeRef.url.split("/").pop()?.split("#").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("") ?? "<UNKNOWN>"
|
|
2535
|
+
);
|
|
2536
|
+
}
|
|
2537
|
+
generateFieldType(schema) {
|
|
2538
|
+
if (schema.enum) {
|
|
2539
|
+
return this.generateEnumType(schema.binding?.name ?? schema.type.name);
|
|
1452
2540
|
}
|
|
1453
|
-
return
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
throw new Error(`No non-constraint schema found in hierarchy for: ${schema.identifier.name}`);
|
|
2541
|
+
return this._generateTypeFromTypeRef(schema.type);
|
|
2542
|
+
}
|
|
2543
|
+
generateType(schemaOrRefOrString) {
|
|
2544
|
+
if (typeof schemaOrRefOrString === "string") {
|
|
2545
|
+
return this._generateTypeName(schemaOrRefOrString);
|
|
1459
2546
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
const findLastSpecializationByIdentifier = (id) => {
|
|
1463
|
-
const schema = resolve3(id);
|
|
1464
|
-
if (!schema) return id;
|
|
1465
|
-
return findLastSpecialization(schema).identifier;
|
|
1466
|
-
};
|
|
1467
|
-
const flatProfile = (schema) => {
|
|
1468
|
-
const hierarchySchemas = hierarchy(schema);
|
|
1469
|
-
const constraintSchemas = hierarchySchemas.filter((s) => s.identifier.kind === "profile");
|
|
1470
|
-
const nonConstraintSchema = hierarchySchemas.find((s) => s.identifier.kind !== "profile");
|
|
1471
|
-
if (!nonConstraintSchema)
|
|
1472
|
-
throw new Error(`No non-constraint schema found in hierarchy for ${schema.identifier.name}`);
|
|
1473
|
-
const mergedFields = {};
|
|
1474
|
-
for (const anySchema of constraintSchemas.slice().reverse()) {
|
|
1475
|
-
const schema2 = anySchema;
|
|
1476
|
-
if (!schema2.fields) continue;
|
|
1477
|
-
for (const [fieldName, fieldConstraints] of Object.entries(schema2.fields)) {
|
|
1478
|
-
if (mergedFields[fieldName]) {
|
|
1479
|
-
mergedFields[fieldName] = {
|
|
1480
|
-
...mergedFields[fieldName],
|
|
1481
|
-
...fieldConstraints
|
|
1482
|
-
};
|
|
1483
|
-
} else {
|
|
1484
|
-
mergedFields[fieldName] = { ...fieldConstraints };
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
2547
|
+
if ("url" in schemaOrRefOrString) {
|
|
2548
|
+
return this._generateTypeFromTypeRef(schemaOrRefOrString);
|
|
1487
2549
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
2550
|
+
return this._generateTypeFromTypeRef(schemaOrRefOrString.identifier);
|
|
2551
|
+
}
|
|
2552
|
+
generateField(name) {
|
|
2553
|
+
name = this._applyNameTransformations(name, this.nameTransformations.field);
|
|
2554
|
+
if (this.keywords.has(name)) {
|
|
2555
|
+
return `_${name}`;
|
|
1491
2556
|
}
|
|
1492
|
-
|
|
1493
|
-
return
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
};
|
|
1500
|
-
const isWithMetaField = (profile) => {
|
|
1501
|
-
const genealogy = tryHierarchy(profile);
|
|
1502
|
-
if (!genealogy) return false;
|
|
1503
|
-
return genealogy.filter(isSpecializationTypeSchema).some((schema) => {
|
|
1504
|
-
return schema.fields?.meta !== void 0;
|
|
1505
|
-
});
|
|
1506
|
-
};
|
|
1507
|
-
const exportTree = async (filename) => {
|
|
1508
|
-
const tree = {};
|
|
1509
|
-
for (const [pkgId, shemas] of Object.entries(groupByPackages(schemas))) {
|
|
1510
|
-
tree[pkgId] = {
|
|
1511
|
-
"primitive-type": {},
|
|
1512
|
-
"complex-type": {},
|
|
1513
|
-
resource: {},
|
|
1514
|
-
"value-set": {},
|
|
1515
|
-
nested: {},
|
|
1516
|
-
binding: {},
|
|
1517
|
-
profile: {},
|
|
1518
|
-
logical: {}
|
|
1519
|
-
};
|
|
1520
|
-
for (const schema of shemas) {
|
|
1521
|
-
tree[pkgId][schema.identifier.kind][schema.identifier.url] = {};
|
|
1522
|
-
}
|
|
2557
|
+
name = this._replaceUnsaveChars(name);
|
|
2558
|
+
return name;
|
|
2559
|
+
}
|
|
2560
|
+
generateEnumValue(name) {
|
|
2561
|
+
name = this._applyNameTransformations(name, this.nameTransformations.enumValue);
|
|
2562
|
+
if (this.keywords.has(name)) {
|
|
2563
|
+
return `_${name}`;
|
|
1523
2564
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
};
|
|
1528
|
-
return {
|
|
1529
|
-
_schemaIndex: index,
|
|
1530
|
-
_relations: relations,
|
|
1531
|
-
collectComplexTypes: () => schemas.filter(isComplexTypeTypeSchema),
|
|
1532
|
-
collectResources: () => schemas.filter(isResourceTypeSchema),
|
|
1533
|
-
collectLogicalModels: () => schemas.filter(isLogicalTypeSchema),
|
|
1534
|
-
collectProfiles: () => schemas.filter(isProfileTypeSchema),
|
|
1535
|
-
resolve: resolve3,
|
|
1536
|
-
resolveByUrl,
|
|
1537
|
-
resourceChildren,
|
|
1538
|
-
tryHierarchy,
|
|
1539
|
-
hierarchy,
|
|
1540
|
-
findLastSpecialization,
|
|
1541
|
-
findLastSpecializationByIdentifier,
|
|
1542
|
-
flatProfile,
|
|
1543
|
-
isWithMetaField,
|
|
1544
|
-
exportTree
|
|
1545
|
-
};
|
|
2565
|
+
name = this._replaceUnsaveChars(name).toUpperCase();
|
|
2566
|
+
return name;
|
|
2567
|
+
}
|
|
1546
2568
|
};
|
|
1547
|
-
var
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
constructor(
|
|
1551
|
-
this.
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
2569
|
+
var TemplateFileCache = class {
|
|
2570
|
+
templateBaseDir;
|
|
2571
|
+
templateCache = {};
|
|
2572
|
+
constructor(templateBaseDir) {
|
|
2573
|
+
this.templateBaseDir = Path__default.resolve(templateBaseDir);
|
|
2574
|
+
}
|
|
2575
|
+
_normalizeName(name) {
|
|
2576
|
+
if (name.endsWith(".mustache")) {
|
|
2577
|
+
return name;
|
|
2578
|
+
}
|
|
2579
|
+
return `${name}.mustache`;
|
|
2580
|
+
}
|
|
2581
|
+
read(template) {
|
|
2582
|
+
return this.readTemplate(template.source);
|
|
2583
|
+
}
|
|
2584
|
+
readTemplate(name) {
|
|
2585
|
+
const normalizedName = this._normalizeName(name);
|
|
2586
|
+
if (!this.templateCache[normalizedName]) {
|
|
2587
|
+
this.templateCache[normalizedName] = fs__default.readFileSync(
|
|
2588
|
+
Path__default.join(this.templateBaseDir, normalizedName),
|
|
2589
|
+
"utf-8"
|
|
2590
|
+
);
|
|
2591
|
+
}
|
|
2592
|
+
return this.templateCache[normalizedName];
|
|
1556
2593
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
2594
|
+
};
|
|
2595
|
+
|
|
2596
|
+
// src/api/mustache/generator/ListElementInformationMixinProvider.ts
|
|
2597
|
+
var ListElementInformationMixinProvider = class _ListElementInformationMixinProvider {
|
|
2598
|
+
static _array(value) {
|
|
2599
|
+
return Array.isArray(value) ? value : Array.from(value);
|
|
2600
|
+
}
|
|
2601
|
+
apply(source) {
|
|
2602
|
+
return this._addListElementInformation(source);
|
|
2603
|
+
}
|
|
2604
|
+
_addListElementInformation(value) {
|
|
2605
|
+
if (Array.isArray(value) || value instanceof Set) {
|
|
2606
|
+
return _ListElementInformationMixinProvider._array(value).map((v, index, array) => {
|
|
2607
|
+
if (typeof v === "object" && v !== null) {
|
|
2608
|
+
return {
|
|
2609
|
+
...this._addListElementInformation(v),
|
|
2610
|
+
"-index": index,
|
|
2611
|
+
"-length": array.length,
|
|
2612
|
+
"-first": index === 0,
|
|
2613
|
+
"-last": index === array.length - 1
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
return v;
|
|
2617
|
+
});
|
|
1563
2618
|
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
2619
|
+
if (value !== null && typeof value === "object") {
|
|
2620
|
+
const obj = value;
|
|
2621
|
+
const result = {};
|
|
2622
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
2623
|
+
result[key] = this._addListElementInformation(val);
|
|
2624
|
+
}
|
|
2625
|
+
return result;
|
|
2626
|
+
}
|
|
2627
|
+
return value;
|
|
1569
2628
|
}
|
|
1570
|
-
|
|
1571
|
-
|
|
2629
|
+
};
|
|
2630
|
+
|
|
2631
|
+
// src/api/mustache/types.ts
|
|
2632
|
+
var PRIMITIVE_TYPES = [
|
|
2633
|
+
"boolean",
|
|
2634
|
+
"instant",
|
|
2635
|
+
"time",
|
|
2636
|
+
"date",
|
|
2637
|
+
"dateTime",
|
|
2638
|
+
"decimal",
|
|
2639
|
+
"integer",
|
|
2640
|
+
"unsignedInt",
|
|
2641
|
+
"positiveInt",
|
|
2642
|
+
"integer64",
|
|
2643
|
+
"base64Binary",
|
|
2644
|
+
"uri",
|
|
2645
|
+
"url",
|
|
2646
|
+
"canonical",
|
|
2647
|
+
"oid",
|
|
2648
|
+
"uuid",
|
|
2649
|
+
"string",
|
|
2650
|
+
"code",
|
|
2651
|
+
"markdown",
|
|
2652
|
+
"id",
|
|
2653
|
+
"xhtml"
|
|
2654
|
+
];
|
|
2655
|
+
|
|
2656
|
+
// src/api/mustache/generator/ViewModelFactory.ts
|
|
2657
|
+
var ViewModelFactory = class {
|
|
2658
|
+
constructor(tsIndex, nameGenerator, filterPred) {
|
|
2659
|
+
this.tsIndex = tsIndex;
|
|
2660
|
+
this.nameGenerator = nameGenerator;
|
|
2661
|
+
this.filterPred = filterPred;
|
|
2662
|
+
}
|
|
2663
|
+
arrayMixinProvider = new ListElementInformationMixinProvider();
|
|
2664
|
+
createUtility() {
|
|
2665
|
+
return this._createForRoot();
|
|
2666
|
+
}
|
|
2667
|
+
createComplexType(typeRef, cache = { resourcesByUri: {}, complexTypesByUri: {} }) {
|
|
2668
|
+
const base = this._createForComplexType(typeRef, cache);
|
|
2669
|
+
const parents = this._createParentsFor(base.schema, cache);
|
|
2670
|
+
const children = this._createChildrenFor(typeRef, cache);
|
|
2671
|
+
const inheritedFields = parents.flatMap((p) => p.fields);
|
|
2672
|
+
return this.arrayMixinProvider.apply({
|
|
2673
|
+
...this._createForRoot(),
|
|
2674
|
+
...base,
|
|
2675
|
+
parents,
|
|
2676
|
+
children,
|
|
2677
|
+
inheritedFields,
|
|
2678
|
+
allFields: [...base.fields, ...parents.flatMap((p) => p.fields)],
|
|
2679
|
+
hasChildren: children.length > 0,
|
|
2680
|
+
hasParents: parents.length > 0,
|
|
2681
|
+
hasInheritedFields: inheritedFields.length > 0
|
|
2682
|
+
});
|
|
1572
2683
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
const
|
|
1576
|
-
|
|
2684
|
+
createResource(typeRef, cache = { resourcesByUri: {}, complexTypesByUri: {} }) {
|
|
2685
|
+
const base = this._createForResource(typeRef, cache);
|
|
2686
|
+
const parents = this._createParentsFor(base.schema, cache);
|
|
2687
|
+
const children = this._createChildrenFor(typeRef, cache);
|
|
2688
|
+
const inheritedFields = parents.flatMap((p) => p.fields);
|
|
2689
|
+
return this.arrayMixinProvider.apply({
|
|
2690
|
+
...this._createForRoot(),
|
|
2691
|
+
...base,
|
|
2692
|
+
parents,
|
|
2693
|
+
children,
|
|
2694
|
+
inheritedFields,
|
|
2695
|
+
allFields: [...base.fields, ...inheritedFields],
|
|
2696
|
+
hasChildren: children.length > 0,
|
|
2697
|
+
hasParents: parents.length > 0,
|
|
2698
|
+
hasInheritedFields: inheritedFields.length > 0
|
|
2699
|
+
});
|
|
1577
2700
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
2701
|
+
_createFor(typeRef, cache, nestedIn) {
|
|
2702
|
+
if (typeRef.kind === "complex-type") {
|
|
2703
|
+
return this._createForComplexType(typeRef, cache, nestedIn);
|
|
2704
|
+
}
|
|
2705
|
+
if (typeRef.kind === "resource") {
|
|
2706
|
+
return this._createForResource(typeRef, cache, nestedIn);
|
|
2707
|
+
}
|
|
2708
|
+
throw new Error(`Unknown type ${typeRef.kind}`);
|
|
1583
2709
|
}
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
if (this.isSuppressed(3 /* ERROR */)) return;
|
|
1589
|
-
console.error(this.formatMessage("X", message, pc.red));
|
|
1590
|
-
if (error && this.options.verbose) {
|
|
1591
|
-
console.error(pc.red(` ${error.message}`));
|
|
1592
|
-
if (error.stack) {
|
|
1593
|
-
console.error(pc.gray(error.stack));
|
|
1594
|
-
}
|
|
2710
|
+
_createForComplexType(typeRef, cache, nestedIn) {
|
|
2711
|
+
const type = this.tsIndex.resolve(typeRef);
|
|
2712
|
+
if (!type) {
|
|
2713
|
+
throw new Error(`ComplexType ${typeRef.name} not found`);
|
|
1595
2714
|
}
|
|
2715
|
+
if (!Object.hasOwn(cache.complexTypesByUri, type.identifier.url)) {
|
|
2716
|
+
cache.complexTypesByUri[type.identifier.url] = this._createTypeViewModel(type, cache, nestedIn);
|
|
2717
|
+
}
|
|
2718
|
+
const res = cache.complexTypesByUri[type.identifier.url];
|
|
2719
|
+
if (!res) throw new Error(`ComplexType ${typeRef.name} not found`);
|
|
2720
|
+
return res;
|
|
1596
2721
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
2722
|
+
_createForResource(typeRef, cache, nestedIn) {
|
|
2723
|
+
const type = this.tsIndex.resolve(typeRef);
|
|
2724
|
+
if (!type) {
|
|
2725
|
+
throw new Error(`Resource ${typeRef.name} not found`);
|
|
2726
|
+
}
|
|
2727
|
+
if (!Object.hasOwn(cache.resourcesByUri, type.identifier.url)) {
|
|
2728
|
+
cache.resourcesByUri[type.identifier.url] = this._createTypeViewModel(type, cache, nestedIn);
|
|
2729
|
+
}
|
|
2730
|
+
const res = cache.resourcesByUri[type.identifier.url];
|
|
2731
|
+
if (!res) throw new Error(`Resource ${typeRef.name} not found`);
|
|
2732
|
+
return res;
|
|
1602
2733
|
}
|
|
1603
|
-
|
|
1604
|
-
if (
|
|
1605
|
-
this.
|
|
1606
|
-
|
|
2734
|
+
_createChildrenFor(typeRef, cache, nestedIn) {
|
|
2735
|
+
if (isComplexTypeIdentifier(typeRef)) {
|
|
2736
|
+
return this.tsIndex.resourceChildren(typeRef).filter(isComplexTypeIdentifier).filter(this.filterPred).map((childRef) => this._createFor(childRef, cache, nestedIn));
|
|
2737
|
+
}
|
|
2738
|
+
if (isResourceIdentifier(typeRef)) {
|
|
2739
|
+
return this.tsIndex.resourceChildren(typeRef).filter(isResourceIdentifier).filter(this.filterPred).map((childRef) => this._createFor(childRef, cache, nestedIn));
|
|
2740
|
+
}
|
|
2741
|
+
return [];
|
|
2742
|
+
}
|
|
2743
|
+
_createParentsFor(base, cache) {
|
|
2744
|
+
const parents = [];
|
|
2745
|
+
let parentRef = "base" in base ? base.base : void 0;
|
|
2746
|
+
while (parentRef) {
|
|
2747
|
+
parents.push(this._createFor(parentRef, cache, void 0));
|
|
2748
|
+
const parent = this.tsIndex.resolve(parentRef);
|
|
2749
|
+
parentRef = parent && "base" in parent ? parent.base : void 0;
|
|
1607
2750
|
}
|
|
2751
|
+
return parents;
|
|
1608
2752
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
2753
|
+
_createForNestedType(nested, cache, nestedIn) {
|
|
2754
|
+
const base = this._createTypeViewModel(nested, cache, nestedIn);
|
|
2755
|
+
const parents = this._createParentsFor(nested, cache);
|
|
2756
|
+
const children = this._createChildrenFor(nested.identifier, cache, nestedIn);
|
|
2757
|
+
const inheritedFields = parents.flatMap((p) => p.fields);
|
|
2758
|
+
return {
|
|
2759
|
+
...base,
|
|
2760
|
+
parents,
|
|
2761
|
+
children,
|
|
2762
|
+
inheritedFields,
|
|
2763
|
+
allFields: [...base.fields, ...inheritedFields],
|
|
2764
|
+
hasChildren: children.length > 0,
|
|
2765
|
+
hasParents: parents.length > 0,
|
|
2766
|
+
hasInheritedFields: inheritedFields.length > 0
|
|
2767
|
+
};
|
|
1614
2768
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
2769
|
+
_createTypeViewModel(schema, cache, nestedIn) {
|
|
2770
|
+
const fields = Object.entries(("fields" in schema ? schema.fields : {}) ?? {});
|
|
2771
|
+
const nestedComplexTypes = this._collectNestedComplex(schema, cache);
|
|
2772
|
+
const nestedEnums = this._collectNestedEnums(fields);
|
|
2773
|
+
const dependencies = this._collectDependencies(schema);
|
|
2774
|
+
const name = {
|
|
2775
|
+
name: schema.identifier.name,
|
|
2776
|
+
saveName: this.nameGenerator.generateType(schema)
|
|
2777
|
+
};
|
|
2778
|
+
return {
|
|
2779
|
+
nestedComplexTypes,
|
|
2780
|
+
nestedEnums,
|
|
2781
|
+
dependencies,
|
|
2782
|
+
isNested: !!nestedIn,
|
|
2783
|
+
schema,
|
|
2784
|
+
...name,
|
|
2785
|
+
isResource: this._createIsResource(schema.identifier),
|
|
2786
|
+
isComplexType: this._createIsComplexType(schema.identifier),
|
|
2787
|
+
hasFields: fields.length > 0,
|
|
2788
|
+
hasNestedComplexTypes: nestedComplexTypes.length > 0,
|
|
2789
|
+
hasNestedEnums: nestedEnums.length > 0,
|
|
2790
|
+
fields: fields.filter(([_fieldName, fieldSchema]) => !!fieldSchema.type).sort((a, b) => a[0].localeCompare(b[0])).map(([fieldName, fieldSchema]) => {
|
|
2791
|
+
return {
|
|
2792
|
+
owner: name,
|
|
2793
|
+
schema: fieldSchema,
|
|
2794
|
+
name: fieldName,
|
|
2795
|
+
saveName: this.nameGenerator.generateField(fieldName),
|
|
2796
|
+
typeName: this.nameGenerator.generateFieldType(fieldSchema),
|
|
2797
|
+
isArray: fieldSchema.array,
|
|
2798
|
+
isRequired: fieldSchema.required,
|
|
2799
|
+
isEnum: !!fieldSchema.enum,
|
|
2800
|
+
isSizeConstrained: fieldSchema.min !== void 0 || fieldSchema.max !== void 0,
|
|
2801
|
+
min: fieldSchema.min,
|
|
2802
|
+
max: fieldSchema.max,
|
|
2803
|
+
isResource: this._createIsResource(fieldSchema.type),
|
|
2804
|
+
isComplexType: this._createIsComplexType(fieldSchema.type),
|
|
2805
|
+
isPrimitive: this._createIsPrimitiveType(fieldSchema.type),
|
|
2806
|
+
isCode: fieldSchema.type?.name === "code",
|
|
2807
|
+
isIdentifier: fieldSchema.type?.name === "Identifier",
|
|
2808
|
+
isReference: fieldSchema.type?.name === "Reference"
|
|
2809
|
+
};
|
|
2810
|
+
})
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2813
|
+
_collectDependencies(schema) {
|
|
2814
|
+
const dependencies = {
|
|
2815
|
+
resources: [],
|
|
2816
|
+
complexTypes: []
|
|
2817
|
+
};
|
|
2818
|
+
if ("dependencies" in schema && schema.dependencies) {
|
|
2819
|
+
schema.dependencies.filter((dependency) => dependency.kind === "complex-type").map((dependency) => ({ name: dependency.name, saveName: this.nameGenerator.generateType(dependency) })).forEach((dependency) => {
|
|
2820
|
+
dependencies.complexTypes.push(dependency);
|
|
2821
|
+
});
|
|
2822
|
+
schema.dependencies.filter((dependency) => dependency.kind === "resource").map((dependency) => ({ name: dependency.name, saveName: this.nameGenerator.generateType(dependency) })).forEach((dependency) => {
|
|
2823
|
+
dependencies.resources.push(dependency);
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2826
|
+
if ("nested" in schema && schema.nested) {
|
|
2827
|
+
schema.nested.map((nested) => this._collectDependencies(nested)).forEach((d) => {
|
|
2828
|
+
d.complexTypes.filter(
|
|
2829
|
+
(complexType) => !dependencies.complexTypes.some((dependency) => dependency.name === complexType.name)
|
|
2830
|
+
).forEach((complexType) => {
|
|
2831
|
+
dependencies.complexTypes.push(complexType);
|
|
2832
|
+
});
|
|
2833
|
+
d.resources.filter(
|
|
2834
|
+
(resource) => !dependencies.resources.some((dependency) => dependency.name === resource.name)
|
|
2835
|
+
).forEach((resource) => {
|
|
2836
|
+
dependencies.resources.push(resource);
|
|
2837
|
+
});
|
|
2838
|
+
});
|
|
1621
2839
|
}
|
|
2840
|
+
return dependencies;
|
|
1622
2841
|
}
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
2842
|
+
_createIsResource(typeRef) {
|
|
2843
|
+
if (typeRef.kind !== "resource") {
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2846
|
+
return Object.fromEntries(
|
|
2847
|
+
this.tsIndex.collectResources().map((e) => e.identifier).map((resourceRef) => [
|
|
2848
|
+
`is${resourceRef.name.charAt(0).toUpperCase() + resourceRef.name.slice(1)}`,
|
|
2849
|
+
resourceRef.url === typeRef.url
|
|
2850
|
+
])
|
|
2851
|
+
);
|
|
1628
2852
|
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
2853
|
+
_createIsComplexType(typeRef) {
|
|
2854
|
+
if (typeRef.kind !== "complex-type" && typeRef.kind !== "nested") {
|
|
2855
|
+
return false;
|
|
2856
|
+
}
|
|
2857
|
+
return Object.fromEntries(
|
|
2858
|
+
this.tsIndex.collectComplexTypes().map((e) => e.identifier).map((complexTypeRef) => [
|
|
2859
|
+
`is${complexTypeRef.name.charAt(0).toUpperCase() + complexTypeRef.name.slice(1)}`,
|
|
2860
|
+
complexTypeRef.url === typeRef.url
|
|
2861
|
+
])
|
|
2862
|
+
);
|
|
1634
2863
|
}
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
2864
|
+
_createIsPrimitiveType(typeRef) {
|
|
2865
|
+
if (typeRef.kind !== "primitive-type") {
|
|
2866
|
+
return false;
|
|
2867
|
+
}
|
|
2868
|
+
return Object.fromEntries(
|
|
2869
|
+
PRIMITIVE_TYPES.map((type) => [`is${type.charAt(0).toUpperCase()}${type.slice(1)}`, typeRef.name === type])
|
|
2870
|
+
);
|
|
1642
2871
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
2872
|
+
_collectNestedComplex(schema, cache) {
|
|
2873
|
+
const nested = [];
|
|
2874
|
+
if ("nested" in schema && schema.nested) {
|
|
2875
|
+
schema.nested.map((nested2) => this._createForNestedType(nested2, cache, schema)).forEach((n) => {
|
|
2876
|
+
nested.push(n);
|
|
2877
|
+
});
|
|
2878
|
+
}
|
|
2879
|
+
return nested;
|
|
2880
|
+
}
|
|
2881
|
+
_collectNestedEnums(fields) {
|
|
2882
|
+
const nestedEnumValues = {};
|
|
2883
|
+
fields.forEach(([fieldName, fieldSchema]) => {
|
|
2884
|
+
if ("enum" in fieldSchema && fieldSchema.enum) {
|
|
2885
|
+
const name = ("binding" in fieldSchema && fieldSchema.binding?.name) ?? fieldName;
|
|
2886
|
+
if (typeof name === "string") {
|
|
2887
|
+
nestedEnumValues[name] = nestedEnumValues[name] ?? /* @__PURE__ */ new Set();
|
|
2888
|
+
fieldSchema.enum?.forEach(nestedEnumValues[name].add.bind(nestedEnumValues[name]));
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
});
|
|
2892
|
+
return Object.entries(nestedEnumValues).map(([name, values]) => ({
|
|
2893
|
+
name,
|
|
2894
|
+
saveName: this.nameGenerator.generateEnumType(name),
|
|
2895
|
+
values: Array.from(values).map((value) => ({
|
|
2896
|
+
name: value,
|
|
2897
|
+
saveName: this.nameGenerator.generateEnumValue(value)
|
|
2898
|
+
}))
|
|
2899
|
+
}));
|
|
1648
2900
|
}
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
2901
|
+
_createForRoot() {
|
|
2902
|
+
return this.arrayMixinProvider.apply({
|
|
2903
|
+
complexTypes: this.tsIndex.collectComplexTypes().map((e) => e.identifier).map((typeRef) => ({
|
|
2904
|
+
name: typeRef.name,
|
|
2905
|
+
saveName: this.nameGenerator.generateType(typeRef)
|
|
2906
|
+
})),
|
|
2907
|
+
resources: this.tsIndex.collectResources().map((e) => e.identifier).map((typeRef) => ({
|
|
2908
|
+
name: typeRef.name,
|
|
2909
|
+
saveName: this.nameGenerator.generateType(typeRef)
|
|
2910
|
+
}))
|
|
1656
2911
|
});
|
|
1657
2912
|
}
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
2913
|
+
};
|
|
2914
|
+
function loadMustacheGeneratorConfig(templatePath, logger) {
|
|
2915
|
+
const filePath = Path.resolve(templatePath, "config.json");
|
|
2916
|
+
try {
|
|
2917
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
2918
|
+
const parsed = JSON.parse(raw);
|
|
2919
|
+
if (parsed && typeof parsed === "object") {
|
|
2920
|
+
return parsed;
|
|
2921
|
+
}
|
|
2922
|
+
} catch (_e) {
|
|
1663
2923
|
}
|
|
2924
|
+
return {};
|
|
2925
|
+
}
|
|
2926
|
+
var createGenerator = (templatePath, apiOpts) => {
|
|
2927
|
+
const defaultFileOpts = {
|
|
2928
|
+
debug: "OFF",
|
|
2929
|
+
hooks: {},
|
|
2930
|
+
meta: {},
|
|
2931
|
+
keywords: [],
|
|
2932
|
+
unsaveCharacterPattern: /[^a-zA-Z0-9]/g,
|
|
2933
|
+
nameTransformations: {
|
|
2934
|
+
common: [],
|
|
2935
|
+
enumValue: [],
|
|
2936
|
+
type: [],
|
|
2937
|
+
field: []
|
|
2938
|
+
},
|
|
2939
|
+
renderings: {
|
|
2940
|
+
utility: [],
|
|
2941
|
+
resource: [],
|
|
2942
|
+
complexType: []
|
|
2943
|
+
},
|
|
2944
|
+
shouldRunHooks: true,
|
|
2945
|
+
primitiveTypeMap: {}
|
|
2946
|
+
};
|
|
2947
|
+
const actualFileOpts = loadMustacheGeneratorConfig(templatePath);
|
|
2948
|
+
const mustacheOptions = {
|
|
2949
|
+
...defaultFileOpts,
|
|
2950
|
+
...apiOpts,
|
|
2951
|
+
...actualFileOpts,
|
|
2952
|
+
sources: {
|
|
2953
|
+
staticSource: Path.resolve(templatePath, "static"),
|
|
2954
|
+
templateSource: Path.resolve(templatePath, "templates")
|
|
2955
|
+
}
|
|
2956
|
+
};
|
|
2957
|
+
return new MustacheGenerator(mustacheOptions);
|
|
1664
2958
|
};
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
2959
|
+
function runCommand(cmd, args = [], options = {}) {
|
|
2960
|
+
return new Promise((resolve6, reject) => {
|
|
2961
|
+
const child = spawn(cmd, args, {
|
|
2962
|
+
stdio: "inherit",
|
|
2963
|
+
...options
|
|
2964
|
+
});
|
|
2965
|
+
child.on("error", reject);
|
|
2966
|
+
child.on("close", (code) => {
|
|
2967
|
+
if (code === 0) resolve6(code);
|
|
2968
|
+
else reject(new Error(`Prozess beendet mit Fehlercode ${code}`));
|
|
2969
|
+
});
|
|
2970
|
+
});
|
|
1668
2971
|
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
2972
|
+
var MustacheGenerator = class extends FileSystemWriter {
|
|
2973
|
+
templateFileCache;
|
|
2974
|
+
nameGenerator;
|
|
2975
|
+
lambdaMixinProvider;
|
|
2976
|
+
debugMixinProvider;
|
|
2977
|
+
constructor(opts) {
|
|
2978
|
+
super(opts);
|
|
2979
|
+
this.nameGenerator = new NameGenerator(
|
|
2980
|
+
new Set(opts.keywords),
|
|
2981
|
+
opts.primitiveTypeMap,
|
|
2982
|
+
opts.nameTransformations,
|
|
2983
|
+
opts.unsaveCharacterPattern
|
|
2984
|
+
);
|
|
2985
|
+
this.templateFileCache = new TemplateFileCache(opts.sources.templateSource);
|
|
2986
|
+
this.lambdaMixinProvider = new LambdaMixinProvider(this.nameGenerator);
|
|
2987
|
+
this.debugMixinProvider = opts.debug !== "OFF" ? new DebugMixinProvider(opts.debug) : void 0;
|
|
1684
2988
|
}
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
2989
|
+
async generate(tsIndex) {
|
|
2990
|
+
const modelFactory = new ViewModelFactory(tsIndex, this.nameGenerator, () => true);
|
|
2991
|
+
const cache = {
|
|
2992
|
+
resourcesByUri: {},
|
|
2993
|
+
complexTypesByUri: {}
|
|
2994
|
+
};
|
|
2995
|
+
tsIndex.collectComplexTypes().map((i) => i.identifier).sort((a, b) => a.url.localeCompare(b.url)).map((typeRef) => modelFactory.createComplexType(typeRef, cache)).forEach(this._renderComplexType.bind(this));
|
|
2996
|
+
tsIndex.collectResources().map((i) => i.identifier).sort((a, b) => a.url.localeCompare(b.url)).map((typeRef) => modelFactory.createResource(typeRef, cache)).forEach(this._renderResource.bind(this));
|
|
2997
|
+
this._renderUtility(modelFactory.createUtility());
|
|
2998
|
+
this.copyStaticFiles();
|
|
2999
|
+
if (this.opts.shouldRunHooks) {
|
|
3000
|
+
await this._runHooks(this.opts.hooks.afterGenerate);
|
|
1693
3001
|
}
|
|
1694
|
-
|
|
3002
|
+
return;
|
|
1695
3003
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
3004
|
+
copyStaticFiles() {
|
|
3005
|
+
const staticDir = Path.resolve(this.opts.sources.staticSource);
|
|
3006
|
+
if (!staticDir) {
|
|
3007
|
+
throw new Error("staticDir must be set in subclass.");
|
|
3008
|
+
}
|
|
3009
|
+
fs.cpSync(staticDir, this.opts.outputDir, { recursive: true });
|
|
3010
|
+
}
|
|
3011
|
+
async _runHooks(hooks) {
|
|
3012
|
+
for (const hook of hooks ?? []) {
|
|
3013
|
+
console.info(`Running hook (${this.opts.outputDir}): ${hook.cmd} ${hook.args?.join(" ")}`);
|
|
3014
|
+
await runCommand(hook.cmd, hook.args ?? [], {
|
|
3015
|
+
cwd: this.opts.outputDir
|
|
3016
|
+
});
|
|
3017
|
+
console.info(`Completed hook: ${hook.cmd} ${hook.args?.join(" ")}`);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
_checkRenderingFilter(model, rendering) {
|
|
3021
|
+
if (!rendering.filter?.whitelist?.length && !rendering.filter?.blacklist?.length) {
|
|
3022
|
+
return true;
|
|
3023
|
+
}
|
|
3024
|
+
if ((rendering.filter?.blacklist ?? []).find((v) => model.name.match(v))) {
|
|
3025
|
+
return false;
|
|
3026
|
+
}
|
|
3027
|
+
if ((rendering.filter?.whitelist ?? []).find((v) => model.name.match(v))) {
|
|
3028
|
+
return true;
|
|
3029
|
+
}
|
|
3030
|
+
return !rendering.filter.whitelist?.length;
|
|
3031
|
+
}
|
|
3032
|
+
_renderUtility(model) {
|
|
3033
|
+
this.opts.renderings.utility.forEach((rendering) => {
|
|
3034
|
+
this.cd(rendering.path, () => {
|
|
3035
|
+
this.cat(rendering.fileNameFormat, () => {
|
|
3036
|
+
this.write(this._render(model, rendering));
|
|
3037
|
+
});
|
|
3038
|
+
});
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
_renderResource(model) {
|
|
3042
|
+
this.opts.renderings.resource.filter((rendering) => this._checkRenderingFilter(model, rendering)).forEach((rendering) => {
|
|
3043
|
+
this.cd(rendering.path, () => {
|
|
3044
|
+
this.cat(this._calculateFilename(model, rendering), () => {
|
|
3045
|
+
this.write(this._render(model, rendering));
|
|
3046
|
+
});
|
|
3047
|
+
});
|
|
3048
|
+
});
|
|
3049
|
+
}
|
|
3050
|
+
_renderComplexType(model) {
|
|
3051
|
+
this.opts.renderings.complexType.filter((rendering) => this._checkRenderingFilter(model, rendering)).forEach((rendering) => {
|
|
3052
|
+
this.cd(rendering.path, () => {
|
|
3053
|
+
this.cat(this._calculateFilename(model, rendering), () => {
|
|
3054
|
+
this.write(this._render(model, rendering));
|
|
3055
|
+
});
|
|
3056
|
+
});
|
|
3057
|
+
});
|
|
3058
|
+
}
|
|
3059
|
+
_calculateFilename(model, rendering) {
|
|
3060
|
+
return util.format(rendering.fileNameFormat, model.saveName);
|
|
3061
|
+
}
|
|
3062
|
+
_render(model, rendering) {
|
|
3063
|
+
let view = this.lambdaMixinProvider.apply({
|
|
3064
|
+
meta: {
|
|
3065
|
+
timestamp: this.opts.meta.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3066
|
+
generator: this.opts.meta.generator ?? "@atomic-ehr/codegen mustache generator"
|
|
3067
|
+
},
|
|
3068
|
+
model,
|
|
3069
|
+
properties: rendering.properties ?? {}
|
|
3070
|
+
});
|
|
3071
|
+
if (this.debugMixinProvider) {
|
|
3072
|
+
view = this.debugMixinProvider.apply(view);
|
|
3073
|
+
}
|
|
3074
|
+
return Mustache.render(
|
|
3075
|
+
this.templateFileCache.read(rendering),
|
|
3076
|
+
view,
|
|
3077
|
+
(partialName) => this.templateFileCache.readTemplate(partialName)
|
|
3078
|
+
);
|
|
1698
3079
|
}
|
|
1699
|
-
return fhirSchemas;
|
|
1700
3080
|
};
|
|
1701
3081
|
|
|
1702
3082
|
// src/api/writer-generator/typescript.ts
|
|
@@ -1741,7 +3121,7 @@ var tsModuleFileName = (id) => {
|
|
|
1741
3121
|
var tsModulePath = (id) => {
|
|
1742
3122
|
return `${tsFhirPackageDir(id.package)}/${tsModuleName(id)}`;
|
|
1743
3123
|
};
|
|
1744
|
-
var
|
|
3124
|
+
var canonicalToName3 = (canonical, dropFragment = true) => {
|
|
1745
3125
|
if (!canonical) return void 0;
|
|
1746
3126
|
const localName = extractNameFromCanonical(canonical, dropFragment);
|
|
1747
3127
|
if (!localName) return void 0;
|
|
@@ -1750,7 +3130,7 @@ var canonicalToName2 = (canonical, dropFragment = true) => {
|
|
|
1750
3130
|
var tsResourceName = (id) => {
|
|
1751
3131
|
if (id.kind === "nested") {
|
|
1752
3132
|
const url = id.url;
|
|
1753
|
-
const path =
|
|
3133
|
+
const path = canonicalToName3(url, false);
|
|
1754
3134
|
if (!path) return "";
|
|
1755
3135
|
const [resourceName, fragment] = path.split("#");
|
|
1756
3136
|
const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
|
|
@@ -1816,7 +3196,7 @@ var TypeScript = class extends Writer {
|
|
|
1816
3196
|
});
|
|
1817
3197
|
} else if (isNestedIdentifier(dep)) {
|
|
1818
3198
|
const ndep = { ...dep };
|
|
1819
|
-
ndep.name =
|
|
3199
|
+
ndep.name = canonicalToName3(dep.url);
|
|
1820
3200
|
imports.push({
|
|
1821
3201
|
tsPackage: `../${tsModulePath(ndep)}`,
|
|
1822
3202
|
name: tsResourceName(dep),
|
|
@@ -1869,7 +3249,7 @@ var TypeScript = class extends Writer {
|
|
|
1869
3249
|
name = tsResourceName(schema.identifier);
|
|
1870
3250
|
}
|
|
1871
3251
|
let extendsClause;
|
|
1872
|
-
if (schema.base) extendsClause = `extends ${
|
|
3252
|
+
if (schema.base) extendsClause = `extends ${canonicalToName3(schema.base.url)}`;
|
|
1873
3253
|
this.debugComment(schema.identifier);
|
|
1874
3254
|
if (!schema.fields && !extendsClause && !isResourceTypeSchema(schema)) {
|
|
1875
3255
|
this.lineSM(`export type ${name} = object`);
|
|
@@ -2136,6 +3516,25 @@ var TypeScript = class extends Writer {
|
|
|
2136
3516
|
};
|
|
2137
3517
|
|
|
2138
3518
|
// src/api/builder.ts
|
|
3519
|
+
var prettyReport = (report) => {
|
|
3520
|
+
const { success, filesGenerated, errors, warnings, duration } = report;
|
|
3521
|
+
const errorsStr = errors.length > 0 ? `Errors: ${errors.join(", ")}` : void 0;
|
|
3522
|
+
const warningsStr = warnings.length > 0 ? `Warnings: ${warnings.join(", ")}` : void 0;
|
|
3523
|
+
let allLoc = 0;
|
|
3524
|
+
const files = Object.entries(filesGenerated).map(([path, content]) => {
|
|
3525
|
+
const loc = content.split("\n").length;
|
|
3526
|
+
allLoc += loc;
|
|
3527
|
+
return ` - ${path} (${loc} loc)`;
|
|
3528
|
+
}).join("\n");
|
|
3529
|
+
return [
|
|
3530
|
+
`Generated files (${Math.round(allLoc / 1e3)} kloc):`,
|
|
3531
|
+
files,
|
|
3532
|
+
errorsStr,
|
|
3533
|
+
warningsStr,
|
|
3534
|
+
`Duration: ${Math.round(duration)}ms`,
|
|
3535
|
+
`Status: ${success ? "\u{1F7E9} Success" : "\u{1F7E5} Failure"}`
|
|
3536
|
+
].filter((e) => e).join("\n");
|
|
3537
|
+
};
|
|
2139
3538
|
var normalizeFileName = (str) => {
|
|
2140
3539
|
const res = str.replace(/[^a-zA-Z0-9\-_.@#()]/g, "");
|
|
2141
3540
|
if (res.length === 0) return "unknown";
|
|
@@ -2176,7 +3575,7 @@ var writeTypeSchemasToSeparateFiles = async (typeSchemas, outputDir, logger) =>
|
|
|
2176
3575
|
const pkgPath = normalizeFileName(packageMetaToFhir(pkg));
|
|
2177
3576
|
const name = normalizeFileName(`${ts.identifier.name}(${extractNameFromCanonical(ts.identifier.url)})`);
|
|
2178
3577
|
const json = JSON.stringify(ts, null, 2);
|
|
2179
|
-
const baseName =
|
|
3578
|
+
const baseName = Path.join(outputDir, pkgPath, name);
|
|
2180
3579
|
if (!files[baseName]) files[baseName] = [];
|
|
2181
3580
|
if (!files[baseName]?.some((e) => e === json)) {
|
|
2182
3581
|
files[baseName].push(json);
|
|
@@ -2191,7 +3590,7 @@ var writeTypeSchemasToSeparateFiles = async (typeSchemas, outputDir, logger) =>
|
|
|
2191
3590
|
} else {
|
|
2192
3591
|
fullName = `${baseName}-${index}.typeschema.json`;
|
|
2193
3592
|
}
|
|
2194
|
-
await afs2.mkdir(
|
|
3593
|
+
await afs2.mkdir(Path.dirname(fullName), { recursive: true });
|
|
2195
3594
|
await afs2.writeFile(fullName, json);
|
|
2196
3595
|
})
|
|
2197
3596
|
);
|
|
@@ -2199,7 +3598,7 @@ var writeTypeSchemasToSeparateFiles = async (typeSchemas, outputDir, logger) =>
|
|
|
2199
3598
|
};
|
|
2200
3599
|
var writeTypeSchemasToSingleFile = async (typeSchemas, outputFile, logger) => {
|
|
2201
3600
|
logger.info(`Writing TypeSchema files to: ${outputFile}`);
|
|
2202
|
-
await afs2.mkdir(
|
|
3601
|
+
await afs2.mkdir(Path.dirname(outputFile), { recursive: true });
|
|
2203
3602
|
logger.info(`Writing TypeSchemas to one file ${outputFile}...`);
|
|
2204
3603
|
for (const ts of typeSchemas) {
|
|
2205
3604
|
const json = JSON.stringify(ts, null, 2);
|
|
@@ -2210,7 +3609,7 @@ var writeTypeSchemasToSingleFile = async (typeSchemas, outputFile, logger) => {
|
|
|
2210
3609
|
var tryWriteTypeSchema = async (typeSchemas, opts, logger) => {
|
|
2211
3610
|
if (!opts.typeSchemaOutputDir) return;
|
|
2212
3611
|
try {
|
|
2213
|
-
if (
|
|
3612
|
+
if (Path.extname(opts.typeSchemaOutputDir) === ".ndjson") {
|
|
2214
3613
|
await writeTypeSchemasToSingleFile(typeSchemas, opts.typeSchemaOutputDir, logger);
|
|
2215
3614
|
} else {
|
|
2216
3615
|
await writeTypeSchemasToSeparateFiles(typeSchemas, opts.typeSchemaOutputDir, logger);
|
|
@@ -2227,12 +3626,13 @@ var APIBuilder = class {
|
|
|
2227
3626
|
generators = /* @__PURE__ */ new Map();
|
|
2228
3627
|
logger;
|
|
2229
3628
|
packages = [];
|
|
3629
|
+
localStructurePackages = [];
|
|
3630
|
+
localTgzArchives = [];
|
|
2230
3631
|
progressCallback;
|
|
2231
3632
|
typeSchemaConfig;
|
|
2232
3633
|
constructor(options = {}) {
|
|
2233
3634
|
this.options = {
|
|
2234
3635
|
outputDir: options.outputDir || "./generated",
|
|
2235
|
-
verbose: options.verbose ?? false,
|
|
2236
3636
|
overwrite: options.overwrite ?? true,
|
|
2237
3637
|
cache: options.cache ?? true,
|
|
2238
3638
|
cleanOutput: options.cleanOutput ?? true,
|
|
@@ -2241,12 +3641,13 @@ var APIBuilder = class {
|
|
|
2241
3641
|
throwException: options.throwException || false,
|
|
2242
3642
|
typeSchemaOutputDir: options.typeSchemaOutputDir,
|
|
2243
3643
|
exportTypeTree: options.exportTypeTree,
|
|
2244
|
-
treeShake: options.treeShake
|
|
3644
|
+
treeShake: options.treeShake,
|
|
3645
|
+
registry: options.registry
|
|
2245
3646
|
};
|
|
2246
3647
|
this.typeSchemaConfig = options.typeSchemaConfig;
|
|
2247
3648
|
this.logger = options.logger || createLogger({
|
|
2248
|
-
|
|
2249
|
-
|
|
3649
|
+
prefix: "API",
|
|
3650
|
+
level: options.logLevel
|
|
2250
3651
|
});
|
|
2251
3652
|
}
|
|
2252
3653
|
fromPackage(packageName, version) {
|
|
@@ -2258,6 +3659,22 @@ var APIBuilder = class {
|
|
|
2258
3659
|
this.packages.push(packageRef);
|
|
2259
3660
|
return this;
|
|
2260
3661
|
}
|
|
3662
|
+
/**
|
|
3663
|
+
* Set a custom FHIR package registry URL
|
|
3664
|
+
* @param url The registry URL (default: https://fs.get-ig.org/pkgs/)
|
|
3665
|
+
*/
|
|
3666
|
+
registry(url) {
|
|
3667
|
+
this.options.registry = url;
|
|
3668
|
+
return this;
|
|
3669
|
+
}
|
|
3670
|
+
localStructureDefinitions(config) {
|
|
3671
|
+
this.localStructurePackages.push(config);
|
|
3672
|
+
return this;
|
|
3673
|
+
}
|
|
3674
|
+
localTgzPackage(archivePath) {
|
|
3675
|
+
this.localTgzArchives.push(Path.resolve(archivePath));
|
|
3676
|
+
return this;
|
|
3677
|
+
}
|
|
2261
3678
|
fromSchemas(schemas) {
|
|
2262
3679
|
this.logger.debug(`Adding ${schemas.length} TypeSchemas to generation`);
|
|
2263
3680
|
this.schemas = [...this.schemas, ...schemas];
|
|
@@ -2266,7 +3683,7 @@ var APIBuilder = class {
|
|
|
2266
3683
|
typescript(userOpts) {
|
|
2267
3684
|
const defaultWriterOpts = {
|
|
2268
3685
|
logger: this.logger,
|
|
2269
|
-
outputDir:
|
|
3686
|
+
outputDir: Path.join(this.options.outputDir, "/types"),
|
|
2270
3687
|
tabSize: 4,
|
|
2271
3688
|
withDebugComment: false,
|
|
2272
3689
|
commentLinePrefix: "//",
|
|
@@ -2286,19 +3703,67 @@ var APIBuilder = class {
|
|
|
2286
3703
|
this.logger.debug(`Configured TypeScript generator (${JSON.stringify(opts, void 0, 2)})`);
|
|
2287
3704
|
return this;
|
|
2288
3705
|
}
|
|
2289
|
-
|
|
2290
|
-
const
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
3706
|
+
python(userOptions) {
|
|
3707
|
+
const defaultWriterOpts = {
|
|
3708
|
+
logger: this.logger,
|
|
3709
|
+
outputDir: this.options.outputDir,
|
|
3710
|
+
tabSize: 4,
|
|
3711
|
+
withDebugComment: false,
|
|
3712
|
+
commentLinePrefix: "#"
|
|
3713
|
+
};
|
|
3714
|
+
const defaultPyOpts = {
|
|
3715
|
+
...defaultWriterOpts,
|
|
3716
|
+
rootPackageName: "fhir_types",
|
|
3717
|
+
fieldFormat: "snake_case"
|
|
3718
|
+
};
|
|
3719
|
+
const opts = {
|
|
3720
|
+
...defaultPyOpts,
|
|
3721
|
+
...Object.fromEntries(Object.entries(userOptions).filter(([_, v]) => v !== void 0))
|
|
3722
|
+
};
|
|
3723
|
+
const generator = new Python(opts);
|
|
3724
|
+
this.generators.set("python", generator);
|
|
3725
|
+
this.logger.debug(`Configured python generator`);
|
|
3726
|
+
return this;
|
|
3727
|
+
}
|
|
3728
|
+
mustache(templatePath, userOpts) {
|
|
3729
|
+
const defaultWriterOpts = {
|
|
3730
|
+
logger: this.logger,
|
|
3731
|
+
outputDir: this.options.outputDir
|
|
3732
|
+
};
|
|
3733
|
+
const defaultMustacheOpts = {
|
|
3734
|
+
meta: {
|
|
3735
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3736
|
+
generator: "atomic-codegen"
|
|
3737
|
+
}
|
|
3738
|
+
};
|
|
3739
|
+
const opts = {
|
|
3740
|
+
...defaultWriterOpts,
|
|
3741
|
+
...defaultMustacheOpts,
|
|
3742
|
+
...userOpts
|
|
3743
|
+
};
|
|
3744
|
+
const generator = createGenerator(templatePath, opts);
|
|
3745
|
+
this.generators.set(`mustache[${templatePath}]`, generator);
|
|
3746
|
+
this.logger.debug(`Configured TypeScript generator (${JSON.stringify(opts, void 0, 2)})`);
|
|
3747
|
+
return this;
|
|
3748
|
+
}
|
|
3749
|
+
csharp(userOptions) {
|
|
3750
|
+
const defaultWriterOpts = {
|
|
3751
|
+
logger: this.logger,
|
|
3752
|
+
outputDir: Path.join(this.options.outputDir, "/types"),
|
|
3753
|
+
tabSize: 4,
|
|
3754
|
+
withDebugComment: false,
|
|
3755
|
+
commentLinePrefix: "//"
|
|
3756
|
+
};
|
|
3757
|
+
const defaultCSharpOpts = {
|
|
3758
|
+
...defaultWriterOpts,
|
|
3759
|
+
rootNamespace: "Fhir.Types"
|
|
3760
|
+
};
|
|
3761
|
+
const opts = {
|
|
3762
|
+
...defaultCSharpOpts,
|
|
3763
|
+
...Object.fromEntries(Object.entries(userOptions).filter(([_, v]) => v !== void 0))
|
|
3764
|
+
};
|
|
3765
|
+
const generator = new CSharp(opts);
|
|
3766
|
+
this.generators.set("csharp", generator);
|
|
2302
3767
|
this.logger.debug(`Configured C# generator`);
|
|
2303
3768
|
return this;
|
|
2304
3769
|
}
|
|
@@ -2320,9 +3785,8 @@ var APIBuilder = class {
|
|
|
2320
3785
|
}
|
|
2321
3786
|
return this;
|
|
2322
3787
|
}
|
|
2323
|
-
|
|
2324
|
-
this.
|
|
2325
|
-
this.logger?.configure({ verbose: enabled });
|
|
3788
|
+
setLogLevel(level) {
|
|
3789
|
+
this.logger?.setLevel(typeof level === "string" ? parseLogLevel(level) : level);
|
|
2326
3790
|
return this;
|
|
2327
3791
|
}
|
|
2328
3792
|
throwException(enabled = true) {
|
|
@@ -2350,7 +3814,7 @@ var APIBuilder = class {
|
|
|
2350
3814
|
const result = {
|
|
2351
3815
|
success: false,
|
|
2352
3816
|
outputDir: this.options.outputDir,
|
|
2353
|
-
filesGenerated:
|
|
3817
|
+
filesGenerated: {},
|
|
2354
3818
|
errors: [],
|
|
2355
3819
|
warnings: [],
|
|
2356
3820
|
duration: 0
|
|
@@ -2359,10 +3823,28 @@ var APIBuilder = class {
|
|
|
2359
3823
|
try {
|
|
2360
3824
|
if (this.options.cleanOutput) cleanup(this.options, this.logger);
|
|
2361
3825
|
this.logger.info("Initialize Canonical Manager");
|
|
2362
|
-
const manager = CanonicalManager({
|
|
3826
|
+
const manager = this.options.manager || CanonicalManager({
|
|
2363
3827
|
packages: this.packages,
|
|
2364
|
-
workingDir: ".codegen-cache/canonical-manager-cache"
|
|
3828
|
+
workingDir: ".codegen-cache/canonical-manager-cache",
|
|
3829
|
+
registry: this.options.registry || void 0
|
|
2365
3830
|
});
|
|
3831
|
+
if (this.localStructurePackages.length > 0) {
|
|
3832
|
+
for (const config of this.localStructurePackages) {
|
|
3833
|
+
this.logger.info(
|
|
3834
|
+
`Registering local StructureDefinitions for ${config.package.name}@${config.package.version}`
|
|
3835
|
+
);
|
|
3836
|
+
await manager.addLocalPackage({
|
|
3837
|
+
name: config.package.name,
|
|
3838
|
+
version: config.package.version,
|
|
3839
|
+
path: config.path,
|
|
3840
|
+
dependencies: config.dependencies?.map((dep) => packageMetaToNpm(dep))
|
|
3841
|
+
});
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
for (const archivePath of this.localTgzArchives) {
|
|
3845
|
+
this.logger.info(`Registering local tgz package: ${archivePath}`);
|
|
3846
|
+
await manager.addTgzPackage({ archivePath });
|
|
3847
|
+
}
|
|
2366
3848
|
const ref2meta = await manager.init();
|
|
2367
3849
|
const packageMetas = Object.values(ref2meta);
|
|
2368
3850
|
const register = await registerFromManager(manager, {
|
|
@@ -2401,6 +3883,9 @@ var APIBuilder = class {
|
|
|
2401
3883
|
this.schemas = [];
|
|
2402
3884
|
this.generators.clear();
|
|
2403
3885
|
this.progressCallback = void 0;
|
|
3886
|
+
this.packages = [];
|
|
3887
|
+
this.localStructurePackages = [];
|
|
3888
|
+
this.localTgzArchives = [];
|
|
2404
3889
|
return this;
|
|
2405
3890
|
}
|
|
2406
3891
|
/**
|
|
@@ -2421,7 +3906,9 @@ var APIBuilder = class {
|
|
|
2421
3906
|
try {
|
|
2422
3907
|
await generator.generate(tsIndex);
|
|
2423
3908
|
const fileBuffer = generator.writtenFiles();
|
|
2424
|
-
|
|
3909
|
+
fileBuffer.forEach((buf) => {
|
|
3910
|
+
result.filesGenerated[buf.relPath] = buf.content;
|
|
3911
|
+
});
|
|
2425
3912
|
this.logger.info(`Generating ${type} finished successfully`);
|
|
2426
3913
|
} catch (error) {
|
|
2427
3914
|
result.errors.push(
|
|
@@ -2439,6 +3926,7 @@ var DEFAULT_CONFIG = {
|
|
|
2439
3926
|
validate: true,
|
|
2440
3927
|
cache: true,
|
|
2441
3928
|
cleanOutput: true,
|
|
3929
|
+
registry: "",
|
|
2442
3930
|
typescript: {
|
|
2443
3931
|
moduleFormat: "esm",
|
|
2444
3932
|
generateIndex: true,
|
|
@@ -2945,6 +4433,6 @@ function defineConfig(config) {
|
|
|
2945
4433
|
return config;
|
|
2946
4434
|
}
|
|
2947
4435
|
|
|
2948
|
-
export { APIBuilder, CONFIG_FILE_NAMES, ConfigLoader, ConfigValidator, DEFAULT_CONFIG, configLoader, defineConfig, isConfig, loadConfig };
|
|
4436
|
+
export { APIBuilder, CONFIG_FILE_NAMES, ConfigLoader, ConfigValidator, DEFAULT_CONFIG, LogLevel, configLoader, defineConfig, isConfig, loadConfig, prettyReport };
|
|
2949
4437
|
//# sourceMappingURL=index.js.map
|
|
2950
4438
|
//# sourceMappingURL=index.js.map
|