@atomic-ehr/codegen 0.0.1-canary.20251006092200.fdb4a88 → 0.0.1-canary.20251006094042.7f0be72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +45 -124
- package/dist/index.d.ts +2130 -62
- package/dist/index.js +5865 -84
- package/dist/index.js.map +1 -0
- package/package.json +3 -7
- package/dist/api/builder.d.ts +0 -154
- package/dist/api/builder.js +0 -341
- package/dist/api/generators/base/BaseGenerator.d.ts +0 -186
- package/dist/api/generators/base/BaseGenerator.js +0 -565
- package/dist/api/generators/base/FileManager.d.ts +0 -88
- package/dist/api/generators/base/FileManager.js +0 -202
- package/dist/api/generators/base/PythonTypeMapper.d.ts +0 -16
- package/dist/api/generators/base/PythonTypeMapper.js +0 -71
- package/dist/api/generators/base/TemplateEngine.d.ts +0 -126
- package/dist/api/generators/base/TemplateEngine.js +0 -133
- package/dist/api/generators/base/TypeMapper.d.ts +0 -129
- package/dist/api/generators/base/TypeMapper.js +0 -153
- package/dist/api/generators/base/TypeScriptTypeMapper.d.ts +0 -51
- package/dist/api/generators/base/TypeScriptTypeMapper.js +0 -232
- package/dist/api/generators/base/builders/DirectoryBuilder.d.ts +0 -99
- package/dist/api/generators/base/builders/DirectoryBuilder.js +0 -215
- package/dist/api/generators/base/builders/FileBuilder.d.ts +0 -160
- package/dist/api/generators/base/builders/FileBuilder.js +0 -406
- package/dist/api/generators/base/builders/IndexBuilder.d.ts +0 -126
- package/dist/api/generators/base/builders/IndexBuilder.js +0 -290
- package/dist/api/generators/base/enhanced-errors.d.ts +0 -84
- package/dist/api/generators/base/enhanced-errors.js +0 -259
- package/dist/api/generators/base/error-handler.d.ts +0 -89
- package/dist/api/generators/base/error-handler.js +0 -243
- package/dist/api/generators/base/errors.d.ts +0 -251
- package/dist/api/generators/base/errors.js +0 -692
- package/dist/api/generators/base/index.d.ts +0 -99
- package/dist/api/generators/base/index.js +0 -160
- package/dist/api/generators/base/types.d.ts +0 -433
- package/dist/api/generators/base/types.js +0 -12
- package/dist/api/generators/types.d.ts +0 -53
- package/dist/api/generators/types.js +0 -4
- package/dist/api/generators/typescript.d.ts +0 -190
- package/dist/api/generators/typescript.js +0 -819
- package/dist/api/index.d.ts +0 -51
- package/dist/api/index.js +0 -50
- package/dist/cli/commands/generate/typescript.d.ts +0 -10
- package/dist/cli/commands/generate/typescript.js +0 -52
- package/dist/cli/commands/generate.d.ts +0 -15
- package/dist/cli/commands/generate.js +0 -159
- package/dist/cli/commands/index.d.ts +0 -29
- package/dist/cli/commands/index.js +0 -100
- package/dist/cli/commands/typeschema/generate.d.ts +0 -19
- package/dist/cli/commands/typeschema/generate.js +0 -124
- package/dist/cli/commands/typeschema.d.ts +0 -10
- package/dist/cli/commands/typeschema.js +0 -47
- package/dist/cli/index.d.ts +0 -9
- package/dist/cli/utils/log.d.ts +0 -10
- package/dist/cli/utils/log.js +0 -23
- package/dist/cli/utils/prompts.d.ts +0 -56
- package/dist/cli/utils/prompts.js +0 -202
- package/dist/cli/utils/spinner.d.ts +0 -110
- package/dist/cli/utils/spinner.js +0 -266
- package/dist/config.d.ts +0 -217
- package/dist/config.js +0 -591
- package/dist/logger.d.ts +0 -157
- package/dist/logger.js +0 -281
- package/dist/typeschema/cache.d.ts +0 -80
- package/dist/typeschema/cache.js +0 -239
- package/dist/typeschema/core/binding.d.ts +0 -11
- package/dist/typeschema/core/binding.js +0 -143
- package/dist/typeschema/core/field-builder.d.ts +0 -12
- package/dist/typeschema/core/field-builder.js +0 -123
- package/dist/typeschema/core/identifier.d.ts +0 -13
- package/dist/typeschema/core/identifier.js +0 -94
- package/dist/typeschema/core/nested-types.d.ts +0 -9
- package/dist/typeschema/core/nested-types.js +0 -93
- package/dist/typeschema/core/transformer.d.ts +0 -11
- package/dist/typeschema/core/transformer.js +0 -235
- package/dist/typeschema/generator.d.ts +0 -36
- package/dist/typeschema/generator.js +0 -243
- package/dist/typeschema/index.d.ts +0 -15
- package/dist/typeschema/index.js +0 -15
- package/dist/typeschema/parser.d.ts +0 -79
- package/dist/typeschema/parser.js +0 -274
- package/dist/typeschema/profile/processor.d.ts +0 -14
- package/dist/typeschema/profile/processor.js +0 -261
- package/dist/typeschema/register.d.ts +0 -21
- package/dist/typeschema/register.js +0 -117
- package/dist/typeschema/types.d.ts +0 -240
- package/dist/typeschema/types.js +0 -19
- package/dist/utils/codegen-logger.d.ts +0 -102
- package/dist/utils/codegen-logger.js +0 -196
- package/dist/utils.d.ts +0 -22
- package/dist/utils.js +0 -42
package/dist/typeschema/cache.js
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeSchema Cache System
|
|
3
|
-
*
|
|
4
|
-
* Caching system for TypeSchema documents with both in-memory and persistent file-based storage.
|
|
5
|
-
*/
|
|
6
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
7
|
-
import { readdir, readFile, stat, unlink, writeFile } from "node:fs/promises";
|
|
8
|
-
import { join } from "node:path";
|
|
9
|
-
/**
|
|
10
|
-
* TypeSchema Cache with optional persistent storage
|
|
11
|
-
*/
|
|
12
|
-
export class TypeSchemaCache {
|
|
13
|
-
cache = new Map();
|
|
14
|
-
config;
|
|
15
|
-
cacheDir;
|
|
16
|
-
constructor(config) {
|
|
17
|
-
this.config = {
|
|
18
|
-
enablePersistence: true,
|
|
19
|
-
cacheDir: ".typeschema-cache",
|
|
20
|
-
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
21
|
-
validateCached: true,
|
|
22
|
-
...config,
|
|
23
|
-
};
|
|
24
|
-
if (this.config.enablePersistence && this.config.cacheDir) {
|
|
25
|
-
this.cacheDir = this.config.cacheDir;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Store a schema in the cache
|
|
30
|
-
*/
|
|
31
|
-
async set(schema) {
|
|
32
|
-
const key = this.generateKey(schema.identifier);
|
|
33
|
-
this.cache.set(key, schema);
|
|
34
|
-
// Persist to disk if enabled
|
|
35
|
-
if (this.config.enablePersistence && this.cacheDir) {
|
|
36
|
-
await this.persistSchema(schema);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Retrieve a schema by identifier
|
|
41
|
-
*/
|
|
42
|
-
get(identifier) {
|
|
43
|
-
const key = this.generateKey(identifier);
|
|
44
|
-
return this.cache.get(key) || null;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Retrieve a schema by URL
|
|
48
|
-
*/
|
|
49
|
-
getByUrl(url) {
|
|
50
|
-
for (const schema of this.cache.values()) {
|
|
51
|
-
if (schema.identifier.url === url) {
|
|
52
|
-
return schema;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Check if a schema exists in cache
|
|
59
|
-
*/
|
|
60
|
-
has(identifier) {
|
|
61
|
-
const key = this.generateKey(identifier);
|
|
62
|
-
return this.cache.has(key);
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Check if a schema exists by URL
|
|
66
|
-
*/
|
|
67
|
-
hasByUrl(url) {
|
|
68
|
-
for (const schema of this.cache.values()) {
|
|
69
|
-
if (schema.identifier.url === url) {
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Delete a schema from cache
|
|
77
|
-
*/
|
|
78
|
-
delete(identifier) {
|
|
79
|
-
const key = this.generateKey(identifier);
|
|
80
|
-
return this.cache.delete(key);
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Delete a schema by URL
|
|
84
|
-
*/
|
|
85
|
-
deleteByUrl(url) {
|
|
86
|
-
for (const [key, schema] of this.cache.entries()) {
|
|
87
|
-
if (schema.identifier.url === url) {
|
|
88
|
-
return this.cache.delete(key);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get schemas by package
|
|
95
|
-
*/
|
|
96
|
-
getByPackage(packageName) {
|
|
97
|
-
const results = [];
|
|
98
|
-
for (const schema of this.cache.values()) {
|
|
99
|
-
if (schema.identifier.package === packageName) {
|
|
100
|
-
results.push(schema);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return results;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Get schemas by kind
|
|
107
|
-
*/
|
|
108
|
-
getByKind(kind) {
|
|
109
|
-
const results = [];
|
|
110
|
-
for (const schema of this.cache.values()) {
|
|
111
|
-
if (schema.identifier.kind === kind) {
|
|
112
|
-
results.push(schema);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return results;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Store multiple schemas
|
|
119
|
-
*/
|
|
120
|
-
setMany(schemas) {
|
|
121
|
-
for (const schema of schemas) {
|
|
122
|
-
this.set(schema);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Clear all cached schemas
|
|
127
|
-
*/
|
|
128
|
-
clear() {
|
|
129
|
-
this.cache.clear();
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Generate cache key for identifier
|
|
133
|
-
*/
|
|
134
|
-
generateKey(identifier) {
|
|
135
|
-
return `${identifier.package}:${identifier.version}:${identifier.kind}:${identifier.name}`;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Initialize cache directory if persistence is enabled
|
|
139
|
-
*/
|
|
140
|
-
async initialize() {
|
|
141
|
-
if (this.config.enablePersistence && this.cacheDir) {
|
|
142
|
-
// Ensure cache directory exists
|
|
143
|
-
if (!existsSync(this.cacheDir)) {
|
|
144
|
-
mkdirSync(this.cacheDir, { recursive: true });
|
|
145
|
-
}
|
|
146
|
-
// Load all cached schemas from disk
|
|
147
|
-
await this.loadFromDisk();
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Load all cached schemas from disk
|
|
152
|
-
*/
|
|
153
|
-
async loadFromDisk() {
|
|
154
|
-
if (!this.cacheDir || !existsSync(this.cacheDir)) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
try {
|
|
158
|
-
const files = await readdir(this.cacheDir);
|
|
159
|
-
const schemaFiles = files.filter((f) => f.endsWith(".typeschema.json"));
|
|
160
|
-
for (const file of schemaFiles) {
|
|
161
|
-
const filePath = join(this.cacheDir, file);
|
|
162
|
-
const stats = await stat(filePath);
|
|
163
|
-
// Check if cache is expired
|
|
164
|
-
if (this.config.maxAge) {
|
|
165
|
-
const age = Date.now() - stats.mtimeMs;
|
|
166
|
-
if (age > this.config.maxAge) {
|
|
167
|
-
// Remove expired cache file
|
|
168
|
-
await unlink(filePath);
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
try {
|
|
173
|
-
const content = await readFile(filePath, "utf-8");
|
|
174
|
-
const metadata = JSON.parse(content);
|
|
175
|
-
// Validate cached schema if configured
|
|
176
|
-
if (this.config.validateCached) {
|
|
177
|
-
// Basic validation - check required fields
|
|
178
|
-
if (!metadata.schema?.identifier) {
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
// Add to in-memory cache
|
|
183
|
-
const key = this.generateKey(metadata.schema.identifier);
|
|
184
|
-
this.cache.set(key, metadata.schema);
|
|
185
|
-
}
|
|
186
|
-
catch (error) {
|
|
187
|
-
console.warn(`Failed to load cached schema from ${file}:`, error);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
console.warn("Failed to load cached schemas from disk:", error);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Persist a schema to disk
|
|
197
|
-
*/
|
|
198
|
-
async persistSchema(schema) {
|
|
199
|
-
if (!this.cacheDir) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
// Ensure cache directory exists
|
|
203
|
-
if (!existsSync(this.cacheDir)) {
|
|
204
|
-
mkdirSync(this.cacheDir, { recursive: true });
|
|
205
|
-
}
|
|
206
|
-
const metadata = {
|
|
207
|
-
schema,
|
|
208
|
-
timestamp: Date.now(),
|
|
209
|
-
version: schema.identifier.version,
|
|
210
|
-
};
|
|
211
|
-
// Generate filename from identifier
|
|
212
|
-
const fileName = `${schema.identifier.package}-${schema.identifier.version}-${schema.identifier.kind}-${schema.identifier.name}.typeschema.json`.replace(/[^a-zA-Z0-9.-]/g, "_");
|
|
213
|
-
const filePath = join(this.cacheDir, fileName);
|
|
214
|
-
try {
|
|
215
|
-
await writeFile(filePath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
216
|
-
}
|
|
217
|
-
catch (error) {
|
|
218
|
-
console.warn(`Failed to persist schema to ${filePath}:`, error);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Clear cache directory
|
|
223
|
-
*/
|
|
224
|
-
async clearDisk() {
|
|
225
|
-
if (!this.cacheDir || !existsSync(this.cacheDir)) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
try {
|
|
229
|
-
const files = await readdir(this.cacheDir);
|
|
230
|
-
const schemaFiles = files.filter((f) => f.endsWith(".typeschema.json"));
|
|
231
|
-
for (const file of schemaFiles) {
|
|
232
|
-
await unlink(join(this.cacheDir, file));
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
catch (error) {
|
|
236
|
-
console.warn("Failed to clear cache directory:", error);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Binding and Enum Handling
|
|
3
|
-
*
|
|
4
|
-
* Functions for processing value set bindings and generating enums
|
|
5
|
-
*/
|
|
6
|
-
import type { FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
7
|
-
import type { Register } from "@typeschema/register";
|
|
8
|
-
import type { BindingTypeSchema, CanonicalUrl, Concept, RichFHIRSchema } from "@typeschema/types";
|
|
9
|
-
export declare function extractValueSetConceptsByUrl(register: Register, valueSetUrl: CanonicalUrl): Concept[] | undefined;
|
|
10
|
-
export declare function buildEnum(register: Register, element: FHIRSchemaElement): string[] | undefined;
|
|
11
|
-
export declare function collectBindingSchemas(register: Register, fhirSchema: RichFHIRSchema): BindingTypeSchema[];
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Binding and Enum Handling
|
|
3
|
-
*
|
|
4
|
-
* Functions for processing value set bindings and generating enums
|
|
5
|
-
*/
|
|
6
|
-
import { buildFieldType } from "./field-builder";
|
|
7
|
-
import { dropVersionFromUrl, mkBindingIdentifier, mkValueSetIdentifierByUrl } from "./identifier";
|
|
8
|
-
export function extractValueSetConceptsByUrl(register, valueSetUrl) {
|
|
9
|
-
const cleanUrl = dropVersionFromUrl(valueSetUrl) || valueSetUrl;
|
|
10
|
-
const valueSet = register.resolveVs(cleanUrl);
|
|
11
|
-
if (!valueSet)
|
|
12
|
-
return undefined;
|
|
13
|
-
return extractValueSetConcepts(register, valueSet);
|
|
14
|
-
}
|
|
15
|
-
function extractValueSetConcepts(register, valueSet) {
|
|
16
|
-
if (valueSet.expansion?.contains)
|
|
17
|
-
return valueSet.expansion.contains;
|
|
18
|
-
const concepts = [];
|
|
19
|
-
if (valueSet.compose?.include) {
|
|
20
|
-
for (const include of valueSet.compose.include) {
|
|
21
|
-
if (include.concept) {
|
|
22
|
-
for (const concept of include.concept) {
|
|
23
|
-
concepts.push({
|
|
24
|
-
system: include.system,
|
|
25
|
-
code: concept.code,
|
|
26
|
-
display: concept.display,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
else if (include.system && !include.filter) {
|
|
31
|
-
try {
|
|
32
|
-
const codeSystem = register.resolveAny(include.system);
|
|
33
|
-
if (codeSystem?.concept) {
|
|
34
|
-
const extractConcepts = (conceptList, system) => {
|
|
35
|
-
for (const concept of conceptList) {
|
|
36
|
-
concepts.push({
|
|
37
|
-
system,
|
|
38
|
-
code: concept.code,
|
|
39
|
-
display: concept.display,
|
|
40
|
-
});
|
|
41
|
-
if (concept.concept) {
|
|
42
|
-
extractConcepts(concept.concept, system);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
extractConcepts(codeSystem.concept, include.system);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
// Ignore if we can't resolve the CodeSystem
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return concepts.length > 0 ? concepts : undefined;
|
|
56
|
-
}
|
|
57
|
-
const MAX_ENUM_LENGTH = 100;
|
|
58
|
-
export function buildEnum(register, element) {
|
|
59
|
-
if (!element.binding)
|
|
60
|
-
return undefined;
|
|
61
|
-
const strength = element.binding.strength;
|
|
62
|
-
const valueSetUrl = element.binding.valueSet;
|
|
63
|
-
if (!valueSetUrl)
|
|
64
|
-
return undefined;
|
|
65
|
-
// Enhanced support for more binding strengths and types
|
|
66
|
-
// Generate enum for:
|
|
67
|
-
// 1. Required bindings (always)
|
|
68
|
-
// 2. Extensible bindings on code types (for better type safety)
|
|
69
|
-
// 3. Preferred bindings on code types (for common usage patterns)
|
|
70
|
-
// 4. Extensible bindings on Coding types (broader coverage)
|
|
71
|
-
const shouldGenerateEnum = strength === "required" ||
|
|
72
|
-
(strength === "extensible" && (element.type === "code" || element.type === "Coding")) ||
|
|
73
|
-
(strength === "preferred" && (element.type === "code" || element.type === "Coding"));
|
|
74
|
-
if (!shouldGenerateEnum)
|
|
75
|
-
return undefined;
|
|
76
|
-
const concepts = extractValueSetConceptsByUrl(register, valueSetUrl);
|
|
77
|
-
if (!concepts || concepts.length === 0)
|
|
78
|
-
return undefined;
|
|
79
|
-
const codes = concepts
|
|
80
|
-
.map((c) => c.code)
|
|
81
|
-
.filter((code) => code && typeof code === "string" && code.trim().length > 0);
|
|
82
|
-
if (codes.length > MAX_ENUM_LENGTH) {
|
|
83
|
-
console.warn(`Value set ${valueSetUrl} has more than ${MAX_ENUM_LENGTH} codes, which may cause issues with code generation.`);
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
|
-
return codes.length > 0 ? codes : undefined;
|
|
87
|
-
}
|
|
88
|
-
function generateBindingSchema(register, fhirSchema, path, element) {
|
|
89
|
-
if (!element.binding?.valueSet)
|
|
90
|
-
return undefined;
|
|
91
|
-
const identifier = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
|
|
92
|
-
const fieldType = buildFieldType(register, fhirSchema, element);
|
|
93
|
-
const valueSetIdentifier = mkValueSetIdentifierByUrl(register, element.binding.valueSet);
|
|
94
|
-
const dependencies = [];
|
|
95
|
-
if (fieldType) {
|
|
96
|
-
dependencies.push(fieldType);
|
|
97
|
-
}
|
|
98
|
-
dependencies.push(valueSetIdentifier);
|
|
99
|
-
const enumValues = buildEnum(register, element);
|
|
100
|
-
return {
|
|
101
|
-
identifier,
|
|
102
|
-
type: fieldType,
|
|
103
|
-
valueset: valueSetIdentifier,
|
|
104
|
-
strength: element.binding.strength,
|
|
105
|
-
enum: enumValues,
|
|
106
|
-
dependencies,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
export function collectBindingSchemas(register, fhirSchema) {
|
|
110
|
-
const processedPaths = new Set();
|
|
111
|
-
if (!fhirSchema.elements)
|
|
112
|
-
return [];
|
|
113
|
-
const bindings = [];
|
|
114
|
-
function collectBindings(elements, parentPath) {
|
|
115
|
-
for (const [key, element] of Object.entries(elements)) {
|
|
116
|
-
const path = [...parentPath, key];
|
|
117
|
-
const pathKey = path.join(".");
|
|
118
|
-
if (processedPaths.has(pathKey))
|
|
119
|
-
continue;
|
|
120
|
-
processedPaths.add(pathKey);
|
|
121
|
-
if (element.binding) {
|
|
122
|
-
const binding = generateBindingSchema(register, fhirSchema, path, element);
|
|
123
|
-
if (binding) {
|
|
124
|
-
bindings.push(binding);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (element.elements) {
|
|
128
|
-
collectBindings(element.elements, path);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
collectBindings(fhirSchema.elements, []);
|
|
133
|
-
bindings.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
|
|
134
|
-
const uniqueBindings = [];
|
|
135
|
-
const seenUrls = new Set();
|
|
136
|
-
for (const binding of bindings) {
|
|
137
|
-
if (!seenUrls.has(binding.identifier.url)) {
|
|
138
|
-
seenUrls.add(binding.identifier.url);
|
|
139
|
-
uniqueBindings.push(binding);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return uniqueBindings;
|
|
143
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Field Building Utilities
|
|
3
|
-
*
|
|
4
|
-
* Functions for transforming FHIRSchema elements into TypeSchema fields
|
|
5
|
-
*/
|
|
6
|
-
import type { FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
7
|
-
import type { Register } from "@root/typeschema/register";
|
|
8
|
-
import type { Field, Identifier, RegularField, RichFHIRSchema } from "../types";
|
|
9
|
-
export declare function buildFieldType(register: Register, fhirSchema: RichFHIRSchema, element: FHIRSchemaElement): Identifier | undefined;
|
|
10
|
-
export declare const mkField: (register: Register, fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement) => Field;
|
|
11
|
-
export declare function isNestedElement(element: FHIRSchemaElement): boolean;
|
|
12
|
-
export declare function mkNestedField(register: Register, fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement): RegularField;
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Field Building Utilities
|
|
3
|
-
*
|
|
4
|
-
* Functions for transforming FHIRSchema elements into TypeSchema fields
|
|
5
|
-
*/
|
|
6
|
-
import { buildEnum } from "./binding";
|
|
7
|
-
import { mkBindingIdentifier, mkIdentifier, mkNestedIdentifier } from "./identifier";
|
|
8
|
-
function isRequired(register, fhirSchema, path) {
|
|
9
|
-
const fieldName = path[path.length - 1];
|
|
10
|
-
const parentPath = path.slice(0, -1);
|
|
11
|
-
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs) => {
|
|
12
|
-
if (parentPath.length === 0)
|
|
13
|
-
return fs.required || [];
|
|
14
|
-
if (!fs.elements)
|
|
15
|
-
return [];
|
|
16
|
-
let elem = fs;
|
|
17
|
-
for (const k of parentPath) {
|
|
18
|
-
elem = elem?.elements?.[k];
|
|
19
|
-
}
|
|
20
|
-
return elem?.required || [];
|
|
21
|
-
});
|
|
22
|
-
return new Set(requires).has(fieldName);
|
|
23
|
-
}
|
|
24
|
-
function isExcluded(register, fhirSchema, path) {
|
|
25
|
-
const fieldName = path[path.length - 1];
|
|
26
|
-
if (!fieldName)
|
|
27
|
-
throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
|
|
28
|
-
const parentPath = path.slice(0, -1);
|
|
29
|
-
const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs) => {
|
|
30
|
-
if (parentPath.length === 0)
|
|
31
|
-
return fs.excluded || [];
|
|
32
|
-
if (!fs.elements)
|
|
33
|
-
return [];
|
|
34
|
-
let elem = fs;
|
|
35
|
-
for (const k of parentPath) {
|
|
36
|
-
elem = elem?.elements?.[k];
|
|
37
|
-
}
|
|
38
|
-
return elem?.excluded || [];
|
|
39
|
-
});
|
|
40
|
-
return new Set(requires).has(fieldName);
|
|
41
|
-
}
|
|
42
|
-
const buildReferences = (element, register, _packageInfo) => {
|
|
43
|
-
if (!element.refers)
|
|
44
|
-
return undefined;
|
|
45
|
-
return element.refers.map((ref) => {
|
|
46
|
-
const curl = register.ensureCanonicalUrl(ref);
|
|
47
|
-
const fs = register.resolveFs(curl);
|
|
48
|
-
return mkIdentifier(fs);
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
export function buildFieldType(register, fhirSchema, element) {
|
|
52
|
-
// Handle element reference (for slicing)
|
|
53
|
-
if (element.elementReference) {
|
|
54
|
-
const refPath = element.elementReference
|
|
55
|
-
.filter((_, i) => i % 2 === 1) // Get odd indices (the actual path parts)
|
|
56
|
-
.map((p) => p)
|
|
57
|
-
.filter((p) => p !== "elements"); // Remove 'elements' which is just a container
|
|
58
|
-
// Only return nested identifier if we have a non-empty path
|
|
59
|
-
if (refPath.length > 0) {
|
|
60
|
-
return mkNestedIdentifier(fhirSchema, refPath);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (element.type) {
|
|
64
|
-
const kind = element.type.match(/^[a-z]/) ? "primitive-type" : "complex-type";
|
|
65
|
-
const url = register.ensureCanonicalUrl(element.type);
|
|
66
|
-
const fieldFs = register.resolveFs(url);
|
|
67
|
-
if (!fieldFs) {
|
|
68
|
-
throw new Error(`Could not resolve field '${element.type}'`);
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
kind: kind,
|
|
72
|
-
package: fieldFs.package_meta.name,
|
|
73
|
-
version: fieldFs.package_meta.version,
|
|
74
|
-
name: element.type,
|
|
75
|
-
url: url,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
return undefined;
|
|
79
|
-
}
|
|
80
|
-
export const mkField = (register, fhirSchema, path, element) => {
|
|
81
|
-
let binding;
|
|
82
|
-
let enumValues;
|
|
83
|
-
if (element.binding) {
|
|
84
|
-
binding = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
|
|
85
|
-
if (element.binding.strength === "required" && element.type === "code") {
|
|
86
|
-
enumValues = buildEnum(register, element);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
type: buildFieldType(register, fhirSchema, element),
|
|
91
|
-
required: isRequired(register, fhirSchema, path),
|
|
92
|
-
excluded: isExcluded(register, fhirSchema, path),
|
|
93
|
-
reference: buildReferences(element, register, fhirSchema.package_meta),
|
|
94
|
-
array: element.array || false,
|
|
95
|
-
min: element.min,
|
|
96
|
-
max: element.max,
|
|
97
|
-
choices: element.choices,
|
|
98
|
-
choiceOf: element.choiceOf,
|
|
99
|
-
binding: binding,
|
|
100
|
-
enum: enumValues,
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
|
-
export function isNestedElement(element) {
|
|
104
|
-
const isBackbone = element.type === "BackboneElement";
|
|
105
|
-
const isElement = element.type === "Element" && element.elements !== undefined && Object.keys(element.elements).length > 0;
|
|
106
|
-
// TODO: Observation <- vitalsigns <- bodyweight
|
|
107
|
-
// In Observation we have value[x] with choices
|
|
108
|
-
// In bodyweight we have valueQuantity with additional constaraints on it's elements
|
|
109
|
-
// So we need to build nested type from Quantity for here, but don't do that right now.
|
|
110
|
-
const elementsWithoutType = element.type === undefined &&
|
|
111
|
-
element.choiceOf === undefined &&
|
|
112
|
-
element.elements !== undefined &&
|
|
113
|
-
Object.keys(element.elements).length > 0;
|
|
114
|
-
return isBackbone || isElement || elementsWithoutType;
|
|
115
|
-
}
|
|
116
|
-
export function mkNestedField(register, fhirSchema, path, element) {
|
|
117
|
-
return {
|
|
118
|
-
type: mkNestedIdentifier(fhirSchema, path),
|
|
119
|
-
array: element.array || false,
|
|
120
|
-
required: isRequired(register, fhirSchema, path),
|
|
121
|
-
excluded: isExcluded(register, fhirSchema, path),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Identifier Building Utilities
|
|
3
|
-
*
|
|
4
|
-
* Functions for creating TypeSchema identifiers from FHIRSchema entities
|
|
5
|
-
*/
|
|
6
|
-
import type { FHIRSchema } from "@atomic-ehr/fhirschema";
|
|
7
|
-
import type { BindingIdentifier, CanonicalUrl, Identifier, NestedIdentifier, RichFHIRSchema, ValueSetIdentifier } from "@typeschema/types";
|
|
8
|
-
import type { Register } from "../register";
|
|
9
|
-
export declare function dropVersionFromUrl(url: CanonicalUrl): CanonicalUrl;
|
|
10
|
-
export declare function mkIdentifier(fhirSchema: RichFHIRSchema): Identifier;
|
|
11
|
-
export declare function mkNestedIdentifier(fhirSchema: RichFHIRSchema, path: string[]): NestedIdentifier;
|
|
12
|
-
export declare function mkValueSetIdentifierByUrl(register: Register, fullValueSetUrl: CanonicalUrl): ValueSetIdentifier;
|
|
13
|
-
export declare function mkBindingIdentifier(fhirSchema: FHIRSchema, path: string[], bindingName?: string): BindingIdentifier;
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Identifier Building Utilities
|
|
3
|
-
*
|
|
4
|
-
* Functions for creating TypeSchema identifiers from FHIRSchema entities
|
|
5
|
-
*/
|
|
6
|
-
export function dropVersionFromUrl(url) {
|
|
7
|
-
const baseUrl = url.split("|")[0];
|
|
8
|
-
return baseUrl ? baseUrl : url;
|
|
9
|
-
}
|
|
10
|
-
function getVersionFromUrl(url) {
|
|
11
|
-
const version = url.split("|")[1];
|
|
12
|
-
return version;
|
|
13
|
-
}
|
|
14
|
-
function determineKind(fhirSchema) {
|
|
15
|
-
if (fhirSchema.derivation === "constraint")
|
|
16
|
-
return "profile";
|
|
17
|
-
if (fhirSchema.kind === "primitive-type")
|
|
18
|
-
return "primitive-type";
|
|
19
|
-
if (fhirSchema.kind === "complex-type")
|
|
20
|
-
return "complex-type";
|
|
21
|
-
if (fhirSchema.kind === "resource")
|
|
22
|
-
return "resource";
|
|
23
|
-
return "resource";
|
|
24
|
-
}
|
|
25
|
-
export function mkIdentifier(fhirSchema) {
|
|
26
|
-
return {
|
|
27
|
-
kind: determineKind(fhirSchema),
|
|
28
|
-
package: fhirSchema.package_meta.name,
|
|
29
|
-
version: fhirSchema.package_meta.version,
|
|
30
|
-
name: fhirSchema.name,
|
|
31
|
-
url: fhirSchema.url,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
export function mkNestedIdentifier(fhirSchema, path) {
|
|
35
|
-
const nestedName = path.join(".");
|
|
36
|
-
return {
|
|
37
|
-
kind: "nested",
|
|
38
|
-
package: fhirSchema.package_meta.name,
|
|
39
|
-
version: fhirSchema.package_meta.version,
|
|
40
|
-
name: nestedName,
|
|
41
|
-
url: `${fhirSchema.url}#${nestedName}`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
const getValueSetName = (url) => {
|
|
45
|
-
const urlParts = url.split("/");
|
|
46
|
-
const lastSegment = urlParts[urlParts.length - 1];
|
|
47
|
-
if (lastSegment && lastSegment.length > 0) {
|
|
48
|
-
return lastSegment
|
|
49
|
-
.split(/[-_]/)
|
|
50
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
51
|
-
.join("");
|
|
52
|
-
}
|
|
53
|
-
return url;
|
|
54
|
-
};
|
|
55
|
-
export function mkValueSetIdentifierByUrl(register, fullValueSetUrl) {
|
|
56
|
-
const valueSetUrl = dropVersionFromUrl(fullValueSetUrl);
|
|
57
|
-
const valueSetNameFallback = getValueSetName(valueSetUrl);
|
|
58
|
-
const valuesSetFallback = {
|
|
59
|
-
resourceType: "ValueSet",
|
|
60
|
-
package_meta: {
|
|
61
|
-
name: "missing_valuesets",
|
|
62
|
-
version: getVersionFromUrl(valueSetUrl) || "0.0.0",
|
|
63
|
-
},
|
|
64
|
-
name: valueSetNameFallback,
|
|
65
|
-
id: fullValueSetUrl,
|
|
66
|
-
url: valueSetUrl,
|
|
67
|
-
};
|
|
68
|
-
const valueSet = register.resolveVs(valueSetUrl) || valuesSetFallback;
|
|
69
|
-
// NOTE: ignore valueSet.name due to human name
|
|
70
|
-
const valueSetName = valueSet?.id && !/^[a-zA-Z0-9_-]{20,}$/.test(valueSet.id) ? valueSet.id : valueSetNameFallback;
|
|
71
|
-
return {
|
|
72
|
-
kind: "value-set",
|
|
73
|
-
package: valueSet?.package_meta.name,
|
|
74
|
-
version: valueSet?.package_meta.version,
|
|
75
|
-
name: valueSetName,
|
|
76
|
-
url: valueSetUrl,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
export function mkBindingIdentifier(fhirSchema, path, bindingName) {
|
|
80
|
-
const pathStr = path.join(".");
|
|
81
|
-
// NOTE: if SD specify `bindingName`, the definition should be shared between all
|
|
82
|
-
// packages. So we put it in the dedicated shared package.
|
|
83
|
-
// TODO: provide setting for `shared` package name.
|
|
84
|
-
const [pkg, name, url] = bindingName
|
|
85
|
-
? [{ name: "shared", version: "1.0.0" }, bindingName, `urn:fhir:binding:${bindingName}`]
|
|
86
|
-
: [fhirSchema.package_meta, `${fhirSchema.name}.${pathStr}_binding`, `${fhirSchema.url}#${pathStr}_binding`];
|
|
87
|
-
return {
|
|
88
|
-
kind: "binding",
|
|
89
|
-
package: pkg.name,
|
|
90
|
-
version: pkg.version,
|
|
91
|
-
name: name,
|
|
92
|
-
url: url,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Nested Types (BackboneElement) Handling
|
|
3
|
-
*
|
|
4
|
-
* Functions for extracting and transforming nested types from FHIRSchema
|
|
5
|
-
*/
|
|
6
|
-
import type { Register } from "@root/typeschema/register";
|
|
7
|
-
import type { Identifier, NestedType, RichFHIRSchema } from "../types";
|
|
8
|
-
export declare function mkNestedTypes(register: Register, fhirSchema: RichFHIRSchema): NestedType[] | undefined;
|
|
9
|
-
export declare function extractNestedDependencies(nestedTypes: NestedType[]): Identifier[];
|