@atomic-ehr/codegen 0.0.14 → 0.0.15
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/assets/api/writer-generator/typescript/profile-helpers.ts +36 -0
- package/dist/cli/index.js +10 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.js +228 -146
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -92,6 +92,42 @@ export const applySliceMatch = <T extends object>(input: Partial<T>, match: Part
|
|
|
92
92
|
return result as T;
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
+
const mergeFixedArray = (current: unknown[], fixed: unknown[]): unknown[] => {
|
|
96
|
+
const result = [...current];
|
|
97
|
+
for (const fixedItem of fixed) {
|
|
98
|
+
const existingIndex = result.findIndex((item) => matchesValue(item, fixedItem));
|
|
99
|
+
if (existingIndex === -1) {
|
|
100
|
+
result.push(fixedItem);
|
|
101
|
+
} else {
|
|
102
|
+
result[existingIndex] = mergeFixedValue(result[existingIndex], fixedItem);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const mergeFixedValue = (current: unknown, fixed: unknown): unknown => {
|
|
109
|
+
if (Array.isArray(current) && Array.isArray(fixed)) {
|
|
110
|
+
return mergeFixedArray(current, fixed);
|
|
111
|
+
}
|
|
112
|
+
if (isRecord(current) && isRecord(fixed)) {
|
|
113
|
+
const result: Record<string, unknown> = { ...current };
|
|
114
|
+
for (const [key, fixedValue] of Object.entries(fixed)) {
|
|
115
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
result[key] = mergeFixedValue(result[key], fixedValue);
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
return fixed;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/** Apply a generated fixed/profile value while preserving compatible existing data. */
|
|
126
|
+
export const applyFixedValue = <T extends object>(resource: T, field: string, fixed: unknown): void => {
|
|
127
|
+
const rec = resource as Record<string, unknown>;
|
|
128
|
+
rec[field] = mergeFixedValue(rec[field], fixed);
|
|
129
|
+
};
|
|
130
|
+
|
|
95
131
|
/**
|
|
96
132
|
* Recursively test whether `value` structurally contains everything in
|
|
97
133
|
* `match`. Arrays are matched with "every match item has a corresponding
|
package/dist/cli/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import F from'picocolors';import Ft from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import Ne from'assert';import {createHash}from'crypto';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as he from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var ie=e=>{console.log(),console.log(F.cyan(F.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));},re=(e,t,i)=>{let n=e;if(t&&(n+=` ${F.gray(`(${t}ms)`)}`),console.log(`${F.green("")} ${n}`),i)for(let[r,o]of Object.entries(i))console.log(F.gray(` ${r}: ${o}`));},T=(e,t="\u2022")=>{for(let i of e)console.log(F.gray(` ${t} ${i}`));};var oe={DEBUG:0,INFO:1,WARN:2,ERROR:3,SILENT:4};function k(e={}){let t=e.prefix??"",i=new Set(e.suppressTags??[]),n={},r=[],o=new Set,a=e.level??"INFO",c=p=>oe[p]>=oe[a],l={DEBUG:p=>p,INFO:p=>p,WARN:F.yellow,ERROR:F.red,SILENT:p=>p},s=(p,m,f,y)=>{let h=t?`${t}: `:"",S=y?` ${F.dim(`(${y})`)}`:"";return l[p](`${m} ${h}${f}`)+S},d=(p,m,f,y=false)=>{r.push({level:p,tag:f,message:m,suppressed:y,prefix:t,timestamp:Date.now()});},u=(p,m,f,y=false)=>(...h)=>{let S=h.length===2?h[0]:void 0,x=h.length===2?h[1]:h[0];S&&(n[S]=(n[S]??0)+1);let C=S!==void 0&&i.has(S);if(d(p,x,S,C),!C&&c(p)){if(y){let P=`${p}::${S??""}::${x}`;if(o.has(P))return;o.add(P);}f(s(p,m,x,S));}},g={warn:u("WARN","!",console.warn),dryWarn:u("WARN","!",console.warn,true),info:u("INFO","i",console.log),error:u("ERROR","X",console.error),debug:u("DEBUG","D",console.log),fork(p,m){let f=t?`${t}/${p}`:p,y=[...i,...m?.suppressTags??[]];return k({prefix:f,suppressTags:y,level:m?.level??a})},as(){return g},tagCounts(){return n},printTagSummary(){let p=Object.entries(n);if(p.length===0)return;let m=t?`${t}: `:"",f=p.filter(([h])=>!i.has(h)),y=p.filter(([h])=>i.has(h));if(f.length>0){let h=f.reduce((x,[,C])=>x+C,0),S=f.map(([x,C])=>`${x}: ${C}`).join(", ");console.warn(F.yellow(`! ${m}${h} warnings (${S})`));}if(y.length>0){let h=y.reduce((x,[,C])=>x+C,0),S=y.map(([x,C])=>`${x}: ${C}`).join(", ");console.log(F.dim(`i ${m}${h} suppressed (${S})`));}},buffer(){return r},bufferClear(){r.length=0;}};return g}var b="Use CodeableReference which is not provided by FHIR R4.",Ve="Use Availability which is not provided by FHIR R4.",A={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-manipulation":b,"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-processing":b,"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":Ve,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":b,"http://hl7.org/fhir/StructureDefinition/specimen-additive":b,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":b,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":b,"http://hl7.org/fhir/StructureDefinition/workflow-reason":b},"hl7.fhir.r5.core#5.0.0":{"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.","http://hl7.org/fhir/StructureDefinition/publishablecodesystem":"Uses R5-only base types not available in R4 generation."}};function v(e,t){let i=`${e.name}#${e.version}`,n=A[i]?.[t];if(n)return {shouldSkip:true,reason:n};let r=A[e.name]?.[t];return r?{shouldSkip:true,reason:r}:{shouldSkip:false}}var R=e=>`${e.name}#${e.version}`,ae=e=>`${e.name}@${e.version}`,se=e=>{let t=JSON.stringify(e);return createHash("sha256").update(t).digest("hex").slice(0,16)},ce=(e,t)=>{let i=e.derivation==="constraint"?"constraint":"specialization";return {...e,derivation:i,kind:e.kind,package_meta:e.package_meta||t,name:e.name,url:e.url,base:e.base}};var G=e=>e?.kind==="nested";var E=(...e)=>{let t=e.filter(n=>n!==void 0).flatMap(n=>n.map(r=>[r.url,r]));return t.length===0?void 0:Object.values(Object.fromEntries(t)).sort((n,r)=>n.url.localeCompare(r.url))};var le=e=>[...e.valueFieldTypes??[],...e.profile?[e.profile]:[],...e.subExtensions?.flatMap(t=>t.valueFieldType?[t.valueFieldType]:[])??[]];var pe=(e,t)=>{if(!e.url)throw new Error("ValueSet must have a URL");if(!e.name)throw new Error("ValueSet must have a name");return {...e,package_meta:e.package_meta||t,name:e.name,url:e.url}};function z(e){let t=e.split("|")[0];return t||e}function Oe(e){return e.split("|")[1]}var je=e=>({package:e.package_meta.name,version:e.package_meta.version,name:e.name,url:e.url});function I(e){let t=je(e);return e.derivation==="constraint"?{kind:"profile",...t}:e.kind==="primitive-type"?{kind:"primitive-type",...t}:e.kind==="complex-type"?{kind:"complex-type",...t}:e.kind==="resource"?{kind:"resource",...t}:e.kind==="logical"?{kind:"logical",...t}:{kind:"resource",...t}}var Me=e=>{let t=e.split("/"),i=t[t.length-1];return i&&i.length>0?i.split(/[-_]/).map(n=>n.charAt(0).toUpperCase()+n.slice(1).toLowerCase()).join(""):e};function H(e,t,i){let n=z(i),r=Me(n),o={package_meta:{name:"missing_valuesets",version:Oe(n)||"0.0.0"},id:i},a=e.resolveVs(t,n)||o,c=a?.id&&!/^[a-zA-Z0-9_-]{20,}$/.test(a.id)?a.id:r;return {kind:"value-set",package:a.package_meta.name,version:a.package_meta.version,name:c,url:n}}function L(e,t,i){let n=i.binding?.bindingName,r=t.join("."),[o,a,c]=n?[{name:"shared",version:"1.0.0"},n,`urn:fhir:binding:${n}`]:[e.package_meta,`${e.name}.${r}_binding`,`${e.url}#${r}_binding`];return {kind:"binding",package:o.name,version:o.version,name:a,url:c}}function q(e,t,i,n){let r=z(i)||i,o=e.resolveVs(t,r);if(o)return Ae(e,o)}function Ae(e,t,i){if(t.expansion?.contains)return t.expansion.contains.filter(r=>r.code!==void 0).map(r=>(Ne(r.code),{code:r.code,display:r.display,system:r.system}));let n=[];if(t.compose?.include){for(let r of t.compose.include)if(r.concept)for(let o of r.concept)n.push({system:r.system,code:o.code,display:o.display});else if(r.system&&!r.filter)try{let o=e.resolveAny(r.system);if(o?.concept){let a=(c,l)=>{for(let s of c)n.push({system:l,code:s.code,display:s.display}),s.concept&&a(s.concept,l);};a(o.concept,r.system);}}catch{}}return n.length>0?n:void 0}var de=100,W=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function K(e,t,i,n){if(!i.binding)return;let r=i.binding.strength,o=i.binding.valueSet;if(!o)return;if(!W.has(i.type??"")){n?.dryWarn("#binding",`eld-11: Binding on non-bindable type '${i.type}' (valueSet: ${o})`);return}if(!(r==="required"||r==="extensible"||r==="preferred"))return;let c=q(e,t.package_meta,o);if(!c||c.length===0)return;let l=c.map(s=>s.code).filter(s=>s&&typeof s=="string"&&s.trim().length>0);if(l.length>de){n?.dryWarn("#largeValueSet",`Value set ${o} has ${l.length} which is more than ${de} codes, which may cause issues with code generation.`);return}if(l.length!==0)return {isOpen:r!=="required",values:l}}function Ge(e,t,i,n,r){if(!n.binding?.valueSet)return;let o=L(t,i,n),a=H(e,t.package_meta,n.binding.valueSet),c=K(e,t,n,r);return {identifier:o,valueset:a,strength:n.binding.strength,enum:c,dependencies:[a]}}function me(e,t,i){let n=new Set;if(!t.elements)return [];let r=[];function o(l,s){for(let[d,u]of Object.entries(l)){let g=[...s,d],p=g.join("."),m=e.resolveElementSnapshot(t,g);if(!n.has(p)){if(n.add(p),m.binding){let f=Ge(e,t,g,m,i);f&&r.push(f);}u.elements&&o(u.elements,g);}}}o(t.elements,[]),r.sort((l,s)=>l.identifier.name.localeCompare(s.identifier.name));let a=[],c=new Set;for(let l of r)c.has(l.identifier.url)||(c.add(l.identifier.url),a.push(l));return a}var ze=e=>e.split(/(?<=[a-z])(?=[A-Z])|[-_.\s]/).filter(Boolean);var qe=e=>{if(e.length===0)throw new Error("Empty string");return e[0]?.toUpperCase()+e.substring(1).toLowerCase()},ue=e=>{if(e.length===0)throw new Error("Empty string");let[t,...i]=ze(e);return [t?.toLowerCase(),...i.map(qe)].join("")};var Y=e=>!e||e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1);var We=e=>{let t=e.replace(/\[x\]/g,"").replace(/[- :.]/g,"_");return t?Y(t):""},w=e=>{let t=e.replace(/\[x\]/g,"").replace(/:/g,"_");return t?Y(ue(t)):""},Ke=(e,t)=>{let i=w(e)||"Extension",n=t.split(".").filter(a=>a&&a!=="extension").join("_"),o=`${n?w(n):""}${i}`;return [i,o,`${o}Extension`]},Ye=(e,t)=>{let i=We(t)||"Slice",r=`${w(e)||"Field"}${i}`;return [i,r,`${r}Slice`]},Je=(e,t,i)=>e.reduce((n,r)=>{let o=r.candidates[t]??"";return n[o]=(n[o]??0)+1,i.has(o)&&(n[o]=(n[o]??0)+1),n},{}),Ze=(e,t)=>{let i=e[0]?.candidates.length??0,n=(r,o)=>{if(r.length===0||o>=i)return {};let a=Je(r,o,t),c=o>=i-1,[l,s]=r.reduce(([d,u],g)=>{let p=g.candidates[o]??"";return (a[p]??0)>1&&!c?[d,[...u,g]]:[{...d,[g.key]:p},u]},[{},[]]);return {...l,...n(s,o+1)}};return n(e,0)},fe=e=>({candidates:Ke(e.name,e.path),recommended:""}),ge=(e,t)=>({candidates:Ye(e,t),recommended:""}),ye=e=>{let t=(e.extensions??[]).filter(a=>a.url).map(a=>({key:`ext:${a.url}:${a.path}`,candidates:a.nameCandidates.candidates})),i=Object.entries(e.fields??{}).flatMap(([a,c])=>!("slicing"in c)||!c.slicing?.slices?[]:Object.entries(c.slicing.slices).map(([l,s])=>({key:`slice:${a}:${l}`,candidates:s.nameCandidates.candidates}))),n=new Set(Object.keys(e.fields??{}).map(w)),r=[...t,...i];if(r.length===0)return;let o=Ze(r,n);for(let a of e.extensions??[]){if(!a.url)continue;let c=`ext:${a.url}:${a.path}`;o[c]&&(a.nameCandidates.recommended=o[c]);}for(let[a,c]of Object.entries(e.fields??{}))if(!(!("slicing"in c)||!c.slicing?.slices))for(let[l,s]of Object.entries(c.slicing.slices)){let d=`slice:${a}:${l}`;o[d]&&(s.nameCandidates.recommended=o[d]);}};var J=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var U=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var Xe=async(e,t)=>{let i=await e.packageJson(t.name);if(!i)return [];let n=i.dependencies;return n!==void 0?Object.entries(n).map(([r,o])=>({name:r,version:o})):[]},Se=e=>({pkg:e,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),Re=async(e,t,i,n,r)=>{let o=R(t);if(r?.info(`${" ".repeat(i*2)}+ ${o}`),n[o])return n[o];let a=Se(t);for(let l of await e.search({package:t})){let s=l.url;if(!s||!(isStructureDefinition(l)||U(l)||J(l)))continue;let d=s;a.canonicalResolution[d]&&r?.dryWarn("#duplicateCanonical",`Duplicate canonical URL: ${d} at ${o}.`),a.canonicalResolution[d]=[{deep:i,pkg:t,pkgId:o,resource:l}];}let c=await Xe(e,t);for(let l of c){let{canonicalResolution:s}=await Re(e,l,i+1,n,r);for(let[d,u]of Object.entries(s)){let g=d;a.canonicalResolution[g]=[...a.canonicalResolution[g]||[],...u];}}for(let l of Object.values(a.canonicalResolution))l.sort((s,d)=>s.deep-d.deep);return n[o]=a,a},et=(e,t)=>{for(let{pkg:i,canonicalResolution:n}of Object.values(e)){let r=R(i);if(!e[r])throw new Error(`Package ${r} not found`);let o=0;t?.info(`FHIR Schema conversion for '${R(i)}' begins...`);for(let[a,c]of Object.entries(n)){let l=c[0];if(!l)throw new Error("Resource not found");let s=l.resource,d=l.pkg;if(isStructureDefinition(s)){let u=he.translate(s),g=ce(u,d);o++,e[r].fhirSchemas[g.url]=g;}if(U(s)){let u=pe(s,d);e[r].valueSets[u.url]=u;}}t?.info(`FHIR Schema conversion for '${R(i)}' completed: ${o} successful`);}},tt=(e,t,i)=>{let n=Object.values(e).flatMap(r=>r.canonicalResolution[t]);if(!n)throw new Error(`No canonical resolution found for ${t} in any package`);return n[0]?.resource},nt=async(e,{logger:t,focusedPackages:i})=>{let n=i??await e.packages(),r={};for(let p of n)await Re(e,p,0,r,t);et(r,t);let o=(p,m)=>{let f=r[R(p)];if(f){let y=f.canonicalResolution[m]?.[0];if(y)return r[y.pkgId]?.fhirSchemas[m]}for(let y of Object.values(r)){let h=y.fhirSchemas[m];if(h&&h.package_meta.name===p.name)return h}for(let y of Object.values(r)){let h=y.fhirSchemas[m];if(h)return h}},a=(p,m)=>{let f=r[R(p)];if(f){let y=f.canonicalResolution[m]?.[0];if(y)return r[y.pkgId]?.valueSets[m]}for(let y of Object.values(r)){let h=y.valueSets[m];if(h&&h.package_meta.name===p.name)return h}for(let y of Object.values(r)){let h=y.valueSets[m];if(h)return h}},c=p=>(p.includes("|")&&(p=p.split("|")[0]),p.match(/^[a-zA-Z0-9]+$/)?`http://hl7.org/fhir/StructureDefinition/${p}`:p),l=(p,m)=>{let f=o(p,m);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${m}'`);let y=[f];for(;f?.base;){let h=f.package_meta,S=c(f.base);if(f=o(h,S),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${m}'. Problem: '${S}' from '${R(h)}'`);y.push(f);}return y},s=(p,m)=>l(p,m).filter(f=>f.derivation==="specialization"),d=(p,m)=>{let f=l(p.package_meta,p.url),y=V(f,m);return Z(y)},u=p=>{let m=new Set;for(let[f,y]of Object.entries(p)){m.add(f);for(let h of y?.choices||[])p[h]||m.add(h);}return Array.from(m)},g;return {testAppendFs(p){let m=R(p.package_meta);r[m]||(r[m]=Se(p.package_meta)),r[m].fhirSchemas[p.url]=p,g=void 0;},resolveFs:o,resolveFsGenealogy:l,resolveFsSpecializations:s,ensureSpecializationCanonicalUrl:c,resolveSd:(p,m)=>{let f=r[R(p)]?.canonicalResolution[m]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(r).flatMap(p=>Object.values(p.canonicalResolution).flatMap(m=>m.map(f=>{let y=f.resource;return y.package_name?y:{...y,package_name:p.pkg.name,package_version:p.pkg.version}}))).filter(p=>isStructureDefinition(p)).sort((p,m)=>p.url.localeCompare(m.url)),allFs:()=>Object.values(r).flatMap(p=>Object.values(p.fhirSchemas)),allVs:()=>Object.values(r).flatMap(p=>Object.values(p.valueSets)),resolveVs:a,resolveAny:p=>tt(r,p),resolveElementSnapshot:d,getAllElementKeys:u,resolver:r,resolutionTree:()=>{if(g)return g;let p={};for(let[m,f]of Object.entries(r)){let y=f.pkg.name;p[y]={};for(let[h,S]of Object.entries(f.canonicalResolution)){let x=h;p[y][x]=[];for(let C of S)p[y][x].push({deep:C.deep,pkg:C.pkg});}}return g=p,p}}},xe=async(e,t)=>{let i=e.map(ae);t?.logger?.info(`Loading FHIR packages: ${i.join(", ")}`);let n=CanonicalManager({packages:i,workingDir:".codegen-cache/canonical-manager-cache",registry:t.registry||void 0});return await n.init(),await nt(n,{...t,focusedPackages:e})},V=(e,t)=>{let[i,...n]=t;return i===void 0?[]:e.map(r=>{if(!r.elements)return;let o=r.elements?.[i];for(let a of n)o=o?.elements?.[a];return o}).filter(r=>r!==void 0)};function Z(e){let t=e.reverse(),i=Object.assign({},...t);return i.elements=void 0,i}var Ce=(e,t,i)=>{let n=e.resolveFsSpecializations(t.package_meta,t.url),r=V(n,i),o=Z(r).type,a;if(o){let c=e.ensureSpecializationCanonicalUrl(o),s=e.resolveFsGenealogy(t.package_meta,c).flatMap(d=>Object.keys(d.elements??{}));s.length>0&&(a=new Set(s));}for(let c of r)if(!(!c.elements||Object.keys(c.elements).length===0)&&!(a&&!Object.keys(c.elements).some(l=>!a.has(l))))return true;return false},Q=(e,t,i,n,r)=>n.type==="BackboneElement"?true:!r?.elements||r.choiceOf!==void 0?false:Ce(e,t,i),it=e=>e.elements?new Set(X(e,[],e.elements).filter(([t,i])=>i.elements&&Object.keys(i.elements).length>0).map(([t])=>t.join("."))):new Set;function B(e,t,i){let n={},r=t.derivation==="constraint"?e.resolveFsSpecializations(t.package_meta,t.url):e.resolveFsGenealogy(t.package_meta,t.url);for(let d of [...r].reverse()){let u=it(d);for(let g of u)n[g]=`${d.url}#${g}`;}let o=i.join("."),a=n[o]??`${t.url}#${o}`,c=a.split("#")[0],s=e.resolveFs(t.package_meta,c)?.package_meta??t.package_meta;return {kind:"nested",package:s.name,version:s.version,name:o,url:a}}function X(e,t,i){let n=[];for(let[r,o]of Object.entries(i)){let a=[...t,r];o.elements&&o.choiceOf===void 0&&n.push([a,o]),o.elements&&n.push(...X(e,a,o.elements));}return n}function rt(e,t,i,n,r){let o={},a=e.resolveFsGenealogy(t.package_meta,t.url),c=V(a,i),l=new Set;for(let s of c)if(s.elements)for(let d of Object.keys(s.elements))l.add(d);for(let s of l){let d=[...i,s],u=e.resolveElementSnapshot(t,d);Q(e,t,d,u,n[s])?o[s]=j(e,t,d,u):o[s]=O(e,t,d,u,r);}return o}function ke(e,t,i){if(!t.elements)return;let n=X(t,[],t.elements).filter(([o,a])=>!a.elements||Object.keys(a.elements).length===0?false:a.type!=="BackboneElement"?Ce(e,t,o):true),r=[];for(let[o,a]of n){let c=B(e,t,o),l;a.type==="BackboneElement"||!a.type?l="BackboneElement":l=a.type;let s=e.ensureSpecializationCanonicalUrl(l),d=e.resolveFs(t.package_meta,s);if(!d)throw new Error(`Could not resolve base type ${l}`);let u={kind:"complex-type",package:d.package_meta.name,version:d.package_meta.version,name:l,url:s},g=rt(e,t,o,a.elements??{},i),p={identifier:c,base:u,fields:g};r.push(p);}return r.sort((o,a)=>o.identifier.url.localeCompare(a.identifier.url)),r.length===0?void 0:r}function Ie(e){let t=[];for(let i of e){i.base&&t.push(i.base);for(let n of Object.values(i.fields||{}))"type"in n&&n.type&&t.push(n.type),"binding"in n&&n.binding&&t.push(n.binding);}return t}var ot=new Set(["Availability","CodeableReference","ExtendedContactDetail","MonetaryComponent","RatioRange","VirtualServiceDetail"]),at=(e,t)=>{let i=e.resolver[R(t)];if(!i)return false;for(let n of Object.values(i.canonicalResolution))for(let r of n)if(r.pkg.name==="hl7.fhir.r4.core")return true;return false},st=(e,t,i)=>!ot.has(i)||!at(e,t)?"":`
|
|
2
|
+
import T from'picocolors';import vn from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import Pe from'assert';import {createHash}from'crypto';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as he from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var ie=e=>{console.log(),console.log(T.cyan(T.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));},re=(e,n,i)=>{let t=e;if(n&&(t+=` ${T.gray(`(${n}ms)`)}`),console.log(`${T.green("")} ${t}`),i)for(let[r,o]of Object.entries(i))console.log(T.gray(` ${r}: ${o}`));},F=(e,n="\u2022")=>{for(let i of e)console.log(T.gray(` ${n} ${i}`));};var oe={DEBUG:0,INFO:1,WARN:2,ERROR:3,SILENT:4};function k(e={}){let n=e.prefix??"",i=new Set(e.suppressTags??[]),t={},r=[],o=new Set,a=e.level??"INFO",s=p=>oe[p]>=oe[a],c={DEBUG:p=>p,INFO:p=>p,WARN:T.yellow,ERROR:T.red,SILENT:p=>p},l=(p,m,f,y)=>{let h=n?`${n}: `:"",S=y?` ${T.dim(`(${y})`)}`:"";return c[p](`${m} ${h}${f}`)+S},d=(p,m,f,y=false)=>{r.push({level:p,tag:f,message:m,suppressed:y,prefix:n,timestamp:Date.now()});},u=(p,m,f,y=false)=>(...h)=>{let S=h.length===2?h[0]:void 0,x=h.length===2?h[1]:h[0];S&&(t[S]=(t[S]??0)+1);let C=S!==void 0&&i.has(S);if(d(p,x,S,C),!C&&s(p)){if(y){let N=`${p}::${S??""}::${x}`;if(o.has(N))return;o.add(N);}f(l(p,m,x,S));}},g={warn:u("WARN","!",console.warn),dryWarn:u("WARN","!",console.warn,true),info:u("INFO","i",console.log),error:u("ERROR","X",console.error),debug:u("DEBUG","D",console.log),fork(p,m){let f=n?`${n}/${p}`:p,y=[...i,...m?.suppressTags??[]];return k({prefix:f,suppressTags:y,level:m?.level??a})},as(){return g},tagCounts(){return t},printTagSummary(){let p=Object.entries(t);if(p.length===0)return;let m=n?`${n}: `:"",f=p.filter(([h])=>!i.has(h)),y=p.filter(([h])=>i.has(h));if(f.length>0){let h=f.reduce((x,[,C])=>x+C,0),S=f.map(([x,C])=>`${x}: ${C}`).join(", ");console.warn(T.yellow(`! ${m}${h} warnings (${S})`));}if(y.length>0){let h=y.reduce((x,[,C])=>x+C,0),S=y.map(([x,C])=>`${x}: ${C}`).join(", ");console.log(T.dim(`i ${m}${h} suppressed (${S})`));}},buffer(){return r},bufferClear(){r.length=0;}};return g}var b="Use CodeableReference which is not provided by FHIR R4.",Ve="Use Availability which is not provided by FHIR R4.",A={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-manipulation":b,"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-processing":b,"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":Ve,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":b,"http://hl7.org/fhir/StructureDefinition/specimen-additive":b,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":b,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":b,"http://hl7.org/fhir/StructureDefinition/workflow-reason":b},"hl7.fhir.r5.core#5.0.0":{"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.","http://hl7.org/fhir/StructureDefinition/publishablecodesystem":"Uses R5-only base types not available in R4 generation."}};function v(e,n){let i=`${e.name}#${e.version}`,t=A[i]?.[n];if(t)return {shouldSkip:true,reason:t};let r=A[e.name]?.[n];return r?{shouldSkip:true,reason:r}:{shouldSkip:false}}var R=e=>`${e.name}#${e.version}`,ae=e=>`${e.name}@${e.version}`,se=e=>{let n=JSON.stringify(e);return createHash("sha256").update(n).digest("hex").slice(0,16)},ce=(e,n)=>{let i=e.derivation==="constraint"?"constraint":"specialization";return {...e,derivation:i,kind:e.kind,package_meta:e.package_meta||n,name:e.name,url:e.url,base:e.base}};var G=e=>e?.kind==="nested";var E=(...e)=>{let n=e.filter(t=>t!==void 0).flatMap(t=>t.map(r=>[r.url,r]));return n.length===0?void 0:Object.values(Object.fromEntries(n)).sort((t,r)=>t.url.localeCompare(r.url))};var le=e=>[...e.valueFieldTypes??[],...e.profile?[e.profile]:[],...e.subExtensions?.flatMap(n=>n.valueFieldType?[n.valueFieldType]:[])??[]];var pe=(e,n)=>{if(!e.url)throw new Error("ValueSet must have a URL");if(!e.name)throw new Error("ValueSet must have a name");return {...e,package_meta:e.package_meta||n,name:e.name,url:e.url}};function z(e){let n=e.split("|")[0];return n||e}function Be(e){return e.split("|")[1]}var Me=e=>({package:e.package_meta.name,version:e.package_meta.version,name:e.name,url:e.url});function I(e){let n=Me(e);return e.derivation==="constraint"?{kind:"profile",...n}:e.kind==="primitive-type"?{kind:"primitive-type",...n}:e.kind==="complex-type"?{kind:"complex-type",...n}:e.kind==="resource"?{kind:"resource",...n}:e.kind==="logical"?{kind:"logical",...n}:{kind:"resource",...n}}var je=e=>{let n=e.split("/"),i=n[n.length-1];return i&&i.length>0?i.split(/[-_]/).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join(""):e};function L(e,n,i){let t=z(i),r=je(t),o={package_meta:{name:"missing_valuesets",version:Be(t)||"0.0.0"},id:i},a=e.resolveVs(n,t)||o,s=a?.id&&!/^[a-zA-Z0-9_-]{20,}$/.test(a.id)?a.id:r;return {kind:"value-set",package:a.package_meta.name,version:a.package_meta.version,name:s,url:t}}function H(e,n,i){let t=i.binding?.bindingName,r=n.join("."),[o,a,s]=t?[{name:"shared",version:"1.0.0"},t,`urn:fhir:binding:${t}`]:[e.package_meta,`${e.name}.${r}_binding`,`${e.url}#${r}_binding`];return {kind:"binding",package:o.name,version:o.version,name:a,url:s}}function q(e,n,i,t){let r=z(i)||i,o=e.resolveVs(n,r);if(o)return Ae(e,o)}function Ae(e,n,i){if(n.expansion?.contains)return n.expansion.contains.filter(r=>r.code!==void 0).map(r=>(Pe(r.code),{code:r.code,display:r.display,system:r.system}));let t=[];if(n.compose?.include){for(let r of n.compose.include)if(r.concept)for(let o of r.concept)t.push({system:r.system,code:o.code,display:o.display});else if(r.system&&!r.filter)try{let o=e.resolveAny(r.system);if(o?.concept){let a=(s,c)=>{for(let l of s)t.push({system:c,code:l.code,display:l.display}),l.concept&&a(l.concept,c);};a(o.concept,r.system);}}catch{}}return t.length>0?t:void 0}var de=100,Ge=new Set(["UNK"]),W=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function K(e,n,i,t){if(!i.binding)return;let r=i.binding.strength,o=i.binding.valueSet;if(!o)return;if(!W.has(i.type??"")){t?.dryWarn("#binding",`eld-11: Binding on non-bindable type '${i.type}' (valueSet: ${o})`);return}if(!(r==="required"||r==="extensible"||r==="preferred"))return;let s=q(e,n.package_meta,o);if(!s||s.length===0)return;let c=s.map(d=>d.code).filter(d=>d&&typeof d=="string"&&d.trim().length>0),l=c.length===1?c[0]:void 0;if(l&&Ge.has(l)){t?.dryWarn("#placeholderValueSet",`Value set ${o} only expands to placeholder code '${l}'; skipping enum generation.`);return}if(c.length>de){t?.dryWarn("#largeValueSet",`Value set ${o} has ${c.length} which is more than ${de} codes, which may cause issues with code generation.`);return}if(c.length!==0)return {isOpen:r!=="required",values:c}}function ze(e,n,i,t,r){if(!t.binding?.valueSet)return;let o=H(n,i,t),a=L(e,n.package_meta,t.binding.valueSet),s=K(e,n,t,r);return {identifier:o,valueset:a,strength:t.binding.strength,enum:s,dependencies:[a]}}function me(e,n,i){let t=new Set;if(!n.elements)return [];let r=[];function o(c,l){for(let[d,u]of Object.entries(c)){let g=[...l,d],p=g.join("."),m=e.resolveElementSnapshot(n,g);if(!t.has(p)){if(t.add(p),m.binding){let f=ze(e,n,g,m,i);f&&r.push(f);}u.elements&&o(u.elements,g);}}}o(n.elements,[]),r.sort((c,l)=>c.identifier.name.localeCompare(l.identifier.name));let a=[],s=new Set;for(let c of r)s.has(c.identifier.url)||(s.add(c.identifier.url),a.push(c));return a}var qe=e=>e.split(/(?<=[a-z])(?=[A-Z])|[-_.\s]/).filter(Boolean);var We=e=>{if(e.length===0)throw new Error("Empty string");return e[0]?.toUpperCase()+e.substring(1).toLowerCase()},ue=e=>{if(e.length===0)throw new Error("Empty string");let[n,...i]=qe(e);return [n?.toLowerCase(),...i.map(We)].join("")};var Y=e=>!e||e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1);var Ke=e=>{let n=e.replace(/\[x\]/g,"").replace(/[- :.]/g,"_");return n?Y(n):""},w=e=>{let n=e.replace(/\[x\]/g,"").replace(/:/g,"_");return n?Y(ue(n)):""},Ye=(e,n)=>{let i=w(e)||"Extension",t=n.split(".").filter(a=>a&&a!=="extension").join("_"),o=`${t?w(t):""}${i}`;return [i,o,`${o}Extension`]},Je=(e,n)=>{let i=Ke(n)||"Slice",r=`${w(e)||"Field"}${i}`;return [i,r,`${r}Slice`]},Ze=(e,n,i)=>e.reduce((t,r)=>{let o=r.candidates[n]??"";return t[o]=(t[o]??0)+1,i.has(o)&&(t[o]=(t[o]??0)+1),t},{}),Qe=(e,n)=>{let i=e[0]?.candidates.length??0,t=(r,o)=>{if(r.length===0||o>=i)return {};let a=Ze(r,o,n),s=o>=i-1,[c,l]=r.reduce(([d,u],g)=>{let p=g.candidates[o]??"";return (a[p]??0)>1&&!s?[d,[...u,g]]:[{...d,[g.key]:p},u]},[{},[]]);return {...c,...t(l,o+1)}};return t(e,0)},fe=e=>({candidates:Ye(e.name,e.path),recommended:""}),ge=(e,n)=>({candidates:Je(e,n),recommended:""}),ye=e=>{let n=(e.extensions??[]).filter(a=>a.url).map(a=>({key:`ext:${a.url}:${a.path}`,candidates:a.nameCandidates.candidates})),i=Object.entries(e.fields??{}).flatMap(([a,s])=>!("slicing"in s)||!s.slicing?.slices?[]:Object.entries(s.slicing.slices).map(([c,l])=>({key:`slice:${a}:${c}`,candidates:l.nameCandidates.candidates}))),t=new Set(Object.keys(e.fields??{}).map(w)),r=[...n,...i];if(r.length===0)return;let o=Qe(r,t);for(let a of e.extensions??[]){if(!a.url)continue;let s=`ext:${a.url}:${a.path}`;o[s]&&(a.nameCandidates.recommended=o[s]);}for(let[a,s]of Object.entries(e.fields??{}))if(!(!("slicing"in s)||!s.slicing?.slices))for(let[c,l]of Object.entries(s.slicing.slices)){let d=`slice:${a}:${c}`;o[d]&&(l.nameCandidates.recommended=o[d]);}};var J=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var U=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var en=async(e,n)=>{let i=await e.packageJson(n.name);if(!i)return [];let t=i.dependencies;return t!==void 0?Object.entries(t).map(([r,o])=>({name:r,version:o})):[]},Se=e=>({pkg:e,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),Re=async(e,n,i,t,r)=>{let o=R(n);if(r?.info(`${" ".repeat(i*2)}+ ${o}`),t[o])return t[o];let a=Se(n);for(let c of await e.search({package:n})){let l=c.url;if(!l||!(isStructureDefinition(c)||U(c)||J(c)))continue;let d=l;a.canonicalResolution[d]&&r?.dryWarn("#duplicateCanonical",`Duplicate canonical URL: ${d} at ${o}.`),a.canonicalResolution[d]=[{deep:i,pkg:n,pkgId:o,resource:c}];}let s=await en(e,n);for(let c of s){let{canonicalResolution:l}=await Re(e,c,i+1,t,r);for(let[d,u]of Object.entries(l)){let g=d;a.canonicalResolution[g]=[...a.canonicalResolution[g]||[],...u];}}for(let c of Object.values(a.canonicalResolution))c.sort((l,d)=>l.deep-d.deep);return t[o]=a,a},nn=(e,n)=>{for(let{pkg:i,canonicalResolution:t}of Object.values(e)){let r=R(i);if(!e[r])throw new Error(`Package ${r} not found`);let o=0;n?.info(`FHIR Schema conversion for '${R(i)}' begins...`);for(let[a,s]of Object.entries(t)){let c=s[0];if(!c)throw new Error("Resource not found");let l=c.resource,d=c.pkg;if(isStructureDefinition(l)){let u=he.translate(l),g=ce(u,d);o++,e[r].fhirSchemas[g.url]=g;}if(U(l)){let u=pe(l,d);e[r].valueSets[u.url]=u;}}n?.info(`FHIR Schema conversion for '${R(i)}' completed: ${o} successful`);}},tn=(e,n,i)=>{let t=Object.values(e).flatMap(r=>r.canonicalResolution[n]);if(!t)throw new Error(`No canonical resolution found for ${n} in any package`);return t[0]?.resource},rn=async(e,{logger:n,focusedPackages:i})=>{let t=i??await e.packages(),r={};for(let p of t)await Re(e,p,0,r,n);nn(r,n);let o=(p,m)=>{let f=r[R(p)];if(f){let y=f.canonicalResolution[m]?.[0];if(y)return r[y.pkgId]?.fhirSchemas[m]}for(let y of Object.values(r)){let h=y.fhirSchemas[m];if(h&&h.package_meta.name===p.name)return h}for(let y of Object.values(r)){let h=y.fhirSchemas[m];if(h)return h}},a=(p,m)=>{let f=r[R(p)];if(f){let y=f.canonicalResolution[m]?.[0];if(y)return r[y.pkgId]?.valueSets[m]}for(let y of Object.values(r)){let h=y.valueSets[m];if(h&&h.package_meta.name===p.name)return h}for(let y of Object.values(r)){let h=y.valueSets[m];if(h)return h}},s=p=>(p.includes("|")&&(p=p.split("|")[0]),p.match(/^[a-zA-Z0-9]+$/)?`http://hl7.org/fhir/StructureDefinition/${p}`:p),c=(p,m)=>{let f=o(p,m);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${m}'`);let y=[f];for(;f?.base;){let h=f.package_meta,S=s(f.base);if(f=o(h,S),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${m}'. Problem: '${S}' from '${R(h)}'`);y.push(f);}return y},l=(p,m)=>c(p,m).filter(f=>f.derivation==="specialization"),d=(p,m)=>{let f=c(p.package_meta,p.url),y=V(f,m);return Z(y)},u=p=>{let m=new Set;for(let[f,y]of Object.entries(p)){m.add(f);for(let h of y?.choices||[])p[h]||m.add(h);}return Array.from(m)},g;return {testAppendFs(p){let m=R(p.package_meta);r[m]||(r[m]=Se(p.package_meta)),r[m].fhirSchemas[p.url]=p,g=void 0;},resolveFs:o,resolveFsGenealogy:c,resolveFsSpecializations:l,ensureSpecializationCanonicalUrl:s,resolveSd:(p,m)=>{let f=r[R(p)]?.canonicalResolution[m]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(r).flatMap(p=>Object.values(p.canonicalResolution).flatMap(m=>m.map(f=>{let y=f.resource;return y.package_name?y:{...y,package_name:p.pkg.name,package_version:p.pkg.version}}))).filter(p=>isStructureDefinition(p)).sort((p,m)=>p.url.localeCompare(m.url)),allFs:()=>Object.values(r).flatMap(p=>Object.values(p.fhirSchemas)),allVs:()=>Object.values(r).flatMap(p=>Object.values(p.valueSets)),resolveVs:a,resolveAny:p=>tn(r,p),resolveElementSnapshot:d,getAllElementKeys:u,resolver:r,resolutionTree:()=>{if(g)return g;let p={};for(let[m,f]of Object.entries(r)){let y=f.pkg.name;p[y]={};for(let[h,S]of Object.entries(f.canonicalResolution)){let x=h;p[y][x]=[];for(let C of S)p[y][x].push({deep:C.deep,pkg:C.pkg});}}return g=p,p}}},xe=async(e,n)=>{let i=e.map(ae);n?.logger?.info(`Loading FHIR packages: ${i.join(", ")}`);let t=CanonicalManager({packages:i,workingDir:".codegen-cache/canonical-manager-cache",registry:n.registry||void 0});return await t.init(),await rn(t,{...n,focusedPackages:e})},V=(e,n)=>{let[i,...t]=n;return i===void 0?[]:e.map(r=>{if(!r.elements)return;let o=r.elements?.[i];for(let a of t)o=o?.elements?.[a];return o}).filter(r=>r!==void 0)};function Z(e){let n=e.reverse(),i=Object.assign({},...n);return i.elements=void 0,i}var Ce=(e,n,i)=>{let t=e.resolveFsSpecializations(n.package_meta,n.url),r=V(t,i),o=Z(r).type,a;if(o){let s=e.ensureSpecializationCanonicalUrl(o),l=e.resolveFsGenealogy(n.package_meta,s).flatMap(d=>Object.keys(d.elements??{}));l.length>0&&(a=new Set(l));}for(let s of r)if(!(!s.elements||Object.keys(s.elements).length===0)&&!(a&&!Object.keys(s.elements).some(c=>!a.has(c))))return true;return false},Q=(e,n,i,t,r)=>t.type==="BackboneElement"?true:!r?.elements||r.choiceOf!==void 0?false:Ce(e,n,i),on=e=>e.elements?new Set(X(e,[],e.elements).filter(([n,i])=>i.elements&&Object.keys(i.elements).length>0).map(([n])=>n.join("."))):new Set;function O(e,n,i){let t={},r=n.derivation==="constraint"?e.resolveFsSpecializations(n.package_meta,n.url):e.resolveFsGenealogy(n.package_meta,n.url);for(let d of [...r].reverse()){let u=on(d);for(let g of u)t[g]=`${d.url}#${g}`;}let o=i.join("."),a=t[o]??`${n.url}#${o}`,s=a.split("#")[0],l=e.resolveFs(n.package_meta,s)?.package_meta??n.package_meta;return {kind:"nested",package:l.name,version:l.version,name:o,url:a}}function X(e,n,i){let t=[];for(let[r,o]of Object.entries(i)){let a=[...n,r];o.elements&&o.choiceOf===void 0&&t.push([a,o]),o.elements&&t.push(...X(e,a,o.elements));}return t}function an(e,n,i,t,r){let o={},a=e.resolveFsGenealogy(n.package_meta,n.url),s=V(a,i),c=new Set;for(let l of s)if(l.elements)for(let d of Object.keys(l.elements))c.add(d);for(let l of c){let d=[...i,l],u=e.resolveElementSnapshot(n,d);Q(e,n,d,u,t[l])?o[l]=M(e,n,d,u):o[l]=B(e,n,d,u,r);}return o}function ke(e,n,i){if(!n.elements)return;let t=X(n,[],n.elements).filter(([o,a])=>!a.elements||Object.keys(a.elements).length===0?false:a.type!=="BackboneElement"?Ce(e,n,o):true),r=[];for(let[o,a]of t){let s=O(e,n,o),c;a.type==="BackboneElement"||!a.type?c="BackboneElement":c=a.type;let l=e.ensureSpecializationCanonicalUrl(c),d=e.resolveFs(n.package_meta,l);if(!d)throw new Error(`Could not resolve base type ${c}`);let u={kind:"complex-type",package:d.package_meta.name,version:d.package_meta.version,name:c,url:l},g=an(e,n,o,a.elements??{},i),p={identifier:s,base:u,fields:g};r.push(p);}return r.sort((o,a)=>o.identifier.url.localeCompare(a.identifier.url)),r.length===0?void 0:r}function Ie(e){let n=[];for(let i of e){i.base&&n.push(i.base);for(let t of Object.values(i.fields||{}))"type"in t&&t.type&&n.push(t.type),"binding"in t&&t.binding&&n.push(t.binding);}return n}var sn=new Set(["Availability","CodeableReference","ExtendedContactDetail","MonetaryComponent","RatioRange","VirtualServiceDetail"]),cn=(e,n)=>{let i=e.resolver[R(n)];if(!i)return false;for(let t of Object.values(i.canonicalResolution))for(let r of t)if(r.pkg.name==="hl7.fhir.r4.core")return true;return false},ln=(e,n,i)=>!sn.has(i)||!cn(e,n)?"":`
|
|
3
3
|
hint: '${i}' is an R5+ type and is not available when generating against R4.
|
|
4
|
-
Either skip this canonical via skip-hack.ts, or upgrade the target to R5.`;function be(e,
|
|
5
|
-
package: ${
|
|
6
|
-
schema: ${
|
|
7
|
-
field: ${
|
|
8
|
-
type: ${
|
|
9
|
-
`),await writeFile(c,
|
|
4
|
+
Either skip this canonical via skip-hack.ts, or upgrade the target to R5.`;function be(e,n,i){let t=i[i.length-1];if(!t)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(n.package_meta,n.url).flatMap(a=>{if(r.length===0)return a.required||[];if(!a.elements)return [];let s=a;for(let c of r)s=s?.elements?.[c];return s?.required||[]});return new Set(o).has(t)}function Te(e,n,i){let t=i[i.length-1];if(!t)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(n.package_meta,n.url).flatMap(a=>{if(r.length===0)return a.excluded||[];if(!a.elements)return [];let s=a;for(let c of r)s=s?.elements?.[c];return s?.excluded||[]});return new Set(o).has(t)}var pn=(e,n,i)=>{if(i.refers)return i.refers.map(t=>{let r=e.ensureSpecializationCanonicalUrl(t),o=e.resolveFs(n.package_meta,r);if(!o)throw new Error(`Failed to resolve fs for ${r}`);return I(o)})},dn=e=>{let n=new Set,i=new Set;if(e.required)for(let r of e.required)n.add(r);if(e.excluded)for(let r of e.excluded)i.add(r);if(e.elements)for(let[r,o]of Object.entries(e.elements))o.min!==void 0&&o.min>0&&n.add(r);let t=e.elements?Object.keys(e.elements):void 0;return {required:n.size>0?Array.from(n):void 0,excluded:i.size>0?Array.from(i):void 0,elements:t&&t.length>0?t:void 0}},mn=e=>!e||typeof e=="object"&&Object.keys(e).length===0,j=(e,n,i)=>{let t=e;for(let o=0;o<n.length-1;o++){let a=n[o];(!t[a]||typeof t[a]!="object")&&(t[a]={}),t=t[a];}let r=n[n.length-1];t[r]=i;},un=(e,n)=>{let i=e;for(let t of n)if(i&&typeof i=="object"&&!Array.isArray(i))i=i[t];else return;return i},Fe=(e,n,i,t,r)=>{if(i>=n.length||!e.elements)return;let o=n[i],a=e.elements[o];if(a){if(i===n.length-1&&a.fixed?.value!==void 0){j(t,n,a.fixed.value);return}if(a.slicing?.slices){r.add(n.slice(0,i+1).join("."));let s=n.slice(i+1);for(let c of Object.values(a.slicing.slices)){if(!c.min||c.min<1||!c.match||typeof c.match!="object")continue;let l=c.match;if(Object.keys(l).length!==0)if(s.length>0){let d=un(l,s);d!==void 0&&j(t,n,d);}else j(t,n.slice(0,i+1),l);}return}Fe(a,n,i+1,t,r);}},fn=(e,n,i)=>{if(e==="$this")return;let t=e.split("."),r=n;for(let a of t)if(r=r?.elements?.[a],!r)return;let o=r.type;!o||o.includes("/")||j(i,t,{resourceType:o});},gn=(e,n)=>{if(!n||!e||e.length===0)return;let i={},t=new Set;for(let r of e)if(r.type==="type")fn(r.path,n,i);else {if(!n.elements)continue;let o=r.path.split(".");Fe(n,o,0,i,t);}if(Object.keys(i).length!==0){for(let r of t){let o=r.split("."),a=i;for(let c=0;c<o.length-1;c++){let l=a[o[c]];if(!l||typeof l!="object"||Array.isArray(l))break;a=l;}let s=o[o.length-1];a[s]&&typeof a[s]=="object"&&!Array.isArray(a[s])&&(a[s]=[a[s]]);}return i}},ve=(e,n)=>{let i=n.slicing;if(!i)return;let t={};for(let[r,o]of Object.entries(i.slices??{})){if(!o)continue;let{required:a,excluded:s,elements:c}=o.schema?dn(o.schema):{};t[r]={min:o.min,max:o.max,match:mn(o.match)?gn(i.discriminator??[],o.schema):o.match,required:a,excluded:s,elements:c,nameCandidates:ge(e,r)};}return {discriminator:i.discriminator??[],rules:i.rules,ordered:i.ordered,slices:Object.keys(t).length>0?t:void 0}};function P(e,n,i,t,r){if(t.elementReference){let o=t.elementReference.slice(1).filter((a,s)=>s%2===1);return O(e,n,o)}else if(t.type){let o=e.ensureSpecializationCanonicalUrl(t.type),a=e.resolveFs(n.package_meta,o);if(!a){let s=R(n.package_meta),c=i.join("."),l=ln(e,n.package_meta,t.type);throw new Error(`Could not resolve field type:
|
|
5
|
+
package: ${s}
|
|
6
|
+
schema: ${n.url}
|
|
7
|
+
field: ${c}
|
|
8
|
+
type: ${t.type}${l}`)}return I(a)}else {if(t.choices)return;if(n.derivation==="constraint")return;r?.dryWarn("#fieldTypeNotFound",`Can't recognize element type: <${n.url}>.${i.join(".")} (pkg: '${R(n.package_meta)}'): missing type info`);return}}var B=(e,n,i,t,r,o)=>{let a,s;t.binding&&(a=H(n,i,t),W.has(t.type??"")&&(s=K(e,n,t,r)));let c=P(e,n,i,t,r);c||r?.dryWarn("#fieldTypeNotFound",`Field type not found for '${n.url}#${i.join(".")}' (${n.derivation})`);let l;t.pattern?l={kind:"pattern",type:t.pattern.type,value:t.pattern.value}:t.fixed&&(l={kind:"fixed",type:t.fixed.type,value:t.fixed.value});let d=o??t;if(!l&&d.elements?.coding?.slicing?.slices){let u=d.elements.coding.slicing.slices,g=Object.values(u);g.length>0&&g.every(m=>m.min!==void 0&&m.min>=1&&m.match&&typeof m.match=="object"&&Object.keys(m.match).length>0)&&(l={kind:"fixed",type:"CodeableConcept",value:{coding:g.flatMap(f=>f.match?[f.match]:[])}});}return {type:c,required:be(e,n,i),excluded:Te(e,n,i),reference:pn(e,n,t),array:t.array||false,min:t.min,max:t.max,slicing:ve(i[i.length-1]??"",t),choices:t.choices,choiceOf:t.choiceOf,binding:a,enum:s,valueConstraint:l,mustSupport:t.mustSupport}};function M(e,n,i,t){return {type:O(e,n,i),array:t.array||false,required:be(e,n,i),excluded:Te(e,n,i),slicing:ve(i[i.length-1]??"",t)}}var yn=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=[];for(let[a,s]of Object.entries(r.elements)){if(s.choiceOf!=="value"&&!a.startsWith("value"))continue;let c=P(e,r,[a],s,t);c&&o.push(c);}return E(o)},hn=(e,n,i)=>{let t=[];if(!n.elements)return t;for(let[r,o]of Object.entries(n.elements)){if(!r.startsWith("extension:"))continue;let a=r.split(":")[1];if(!a)continue;let s;for(let[c,l]of Object.entries(o.elements??{}))if(!(l.choiceOf!=="value"&&!c.startsWith("value"))&&(s=P(e,n,[r,c],l,i),s))break;t.push({name:a,url:o.url??a,valueFieldType:s,min:o.min,max:o.max!==void 0?String(o.max):void 0});}return t},Sn=(e,n,i)=>{let t=[],o=n.elements?.extension?.slicing?.slices;if(!o||typeof o!="object")return t;for(let[a,s]of Object.entries(o)){let c=s,l=c.schema;if(!l)continue;let d;for(let[u,g]of Object.entries(l.elements??{})){let p=g;if(!(p.choiceOf!=="value"&&!u.startsWith("value"))&&(d=P(e,n,[u],p,i),d))break}t.push({name:a,url:c.match?.url??a,valueFieldType:d,min:l._required?1:l.min??0,max:l.max!==void 0?String(l.max):l.array?"*":"1"});}return t},Rn=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=hn(e,r,t),a=Sn(e,r,t),s=[...o,...a];return s.length>0?s:void 0},Ee=(e,n,i)=>{let t=[],r=(c,l,d)=>{let u=d.url,g=u?yn(e,n,u,i):void 0,p=u?Rn(e,n,u,i):void 0;if(!u){let S=n.elements?.extension?.slicing?.slices?.[l]?.schema;if(S){u=S.elements?.url?.fixed?.value??l;for(let[x,C]of Object.entries(S.elements??{})){let N=C;if(N.choiceOf==="value"||x.startsWith("value")){let te=P(e,n,[x],N,i);if(te){g=[te];break}}}}}let m=p&&p.length>0,f=u?e.resolveFs(n.package_meta,u):void 0,y=f?I(f):void 0,h=[...c,"extension"].join(".");t.push({name:l,path:h,url:u,profile:y,min:d.min,max:d.max!==void 0?String(d.max):void 0,mustSupport:d.mustSupport,valueFieldTypes:g,subExtensions:p,isComplex:m,nameCandidates:fe({name:l,path:h})});},o=(c,l)=>{if(l.extensions)for(let[d,u]of Object.entries(l.extensions))r(c,d,u);if(l.elements)for(let[d,u]of Object.entries(l.elements))o([...c,d],u);};o([],n);let a=new Set,s=t.filter(c=>{let l=`${c.url}:${c.path}`;return a.has(l)?false:(a.add(l),true)});return s.length===0?void 0:s};function xn(e,n,i,t,r){if(!t)return;let o={};for(let a of e.getAllElementKeys(t)){let s=[...i,a],c=e.resolveElementSnapshot(n,s),l=c.type?e.ensureSpecializationCanonicalUrl(c.type):void 0;if(l&&v(n.package_meta,l).shouldSkip){r?.warn("#skipCanonical",`Skipping field ${s} for ${l} due to skip hack ${v(n.package_meta,l).reason}`);continue}Q(e,n,s,c,t[a])?o[a]=M(e,n,s,c):o[a]=B(e,n,s,c,r,t[a]);}return o}function Cn(e){let n=[];for(let i of Object.values(e))"type"in i&&i.type&&n.push(i.type),"binding"in i&&i.binding&&n.push(i.binding);return n}async function De(e,n,i){if(!n.url)throw new Error("ValueSet URL is required");let t=L(e,n.package_meta,n.url),r=q(e,n.package_meta,n.url);return {identifier:t,description:n.description,concept:r,compose:r?void 0:n.compose}}var Le=(e,n,i)=>{let t=[];return e&&t.push(e),n&&t.push(...Cn(n)),i&&t.push(...Ie(i)),t},Ne=(e,n,i,t)=>{let o=Le(n,i,t).filter(a=>!(a.url===e.url||G(a)));return E(o)},kn=(e,n,i,t)=>{let o=Le(n,i,t).filter(a=>a.url!==e.url);return E(o)};function He(e,n,i){let t;if(n.base){let l=e.resolveFs(n.package_meta,e.ensureSpecializationCanonicalUrl(n.base));if(!l)throw new Error(`Base resource not found '${n.base}' for <${n.url}> from ${R(n.package_meta)}`);let d=I(l);Pe(!G(d),`Unexpected nested base for ${n.url}`),t=d;}let r=xn(e,n,[],n.elements,i),o=ke(e,n,i),a=me(e,n,i);if(n.derivation==="constraint"){let l=I(n);if(!t)throw new Error(`Profile ${n.url} must have a base type`);let d=Ee(e,n,i),u=d?.flatMap(le),g=kn(l,t,r,o),p={identifier:l,base:t,fields:r,nested:o,description:n.description,dependencies:E(g,u),extensions:d};return ye(p),[p,...a]}if(n.kind==="primitive-type"){let l=I(n);return Pe(t,`Primitive type ${n.url} must have a base type`),[{identifier:l,description:n.description,base:t,dependencies:Ne(l,t,r,o)},...a]}let s=I(n);return [{identifier:s,base:t,fields:r,nested:o,description:n.description,dependencies:Ne(s,t,r,o),typeFamily:void 0},...a]}var In=(e,n,i)=>{let t={};for(let a of e){let s=`${a.schema.identifier.url}|${a.schema.identifier.package}`,c=se(a.schema);t[s]??={},t[s][c]??={typeSchema:a.schema,sources:[]},t[s][c].sources.push(a);}let r=[],o={};for(let a of Object.values(t)){let s=Object.values(a).sort((l,d)=>d.sources.length-l.sources.length),c=s[0];if(c)if(s.length>1){let l=c.typeSchema.identifier.url,d=c.typeSchema.identifier.package;i?.dryWarn("#duplicateSchema",`'${l}' from '${d}' has ${s.length} versions`),r.push(c.typeSchema);o[d]??={},o[d][l]=s.flatMap(g=>g.sources.map(p=>({typeSchema:g.typeSchema,sourcePackage:p.sourcePackage,sourceCanonical:p.sourceCanonical})));}else r.push(c.typeSchema);}return {schemas:r,collisions:o}},we=async(e,n,i)=>{let t=[];for(let r of e.allFs()){let o=R(r.package_meta),a=v(r.package_meta,r.url);if(a.shouldSkip){i?.dryWarn("#skipCanonical",`Skip ${r.url} from ${o}. Reason: ${a.reason}`);continue}for(let s of He(e,r,i))t.push({schema:s,sourcePackage:o,sourceCanonical:r.url});}for(let r of e.allVs())t.push({schema:await De(e,r),sourcePackage:R(r.package_meta),sourceCanonical:r.url});return In(t,n,i)};var Ue={command:"generate <packages..>",describe:"Generate TypeSchema files from FHIR packages",builder:{packages:{type:"string",array:true,demandOption:true,describe:"FHIR packages to process (e.g., hl7.fhir.r4.core@4.0.1)"},output:{alias:"o",type:"string",describe:"Output file or directory",default:"./schemas.ndjson"},format:{alias:"f",type:"string",choices:["ndjson","json"],default:"ndjson",describe:"Output format for TypeSchema files"},treeshake:{alias:"t",type:"string",array:true,describe:"Only generate TypeSchemas for specific ResourceTypes (treeshaking)"},singleFile:{alias:"s",type:"boolean",default:false,describe:"Generate single TypeSchema file instead of multiple files (NDJSON format)"},verbose:{alias:"v",type:"boolean",default:false,describe:"Enable verbose output"},registry:{alias:"r",type:"string",describe:"Custom FHIR package registry URL (default: https://fs.get-ig.org/pkgs/)"}},handler:async e=>{let n=k({prefix:"TypeSchema"});try{n.info("Generating TypeSchema from FHIR packages"),n.info(`Packages: ${e.packages.join(", ")}`),n.info(`Output: ${e.output}`);let i=e.singleFile?"ndjson":e.format;n.debug(`Format: ${i}${e.singleFile&&e.format==="json"?" (forced from json due to singleFile)":""}`),e.treeshake&&e.treeshake.length>0&&n.info(`Treeshaking enabled for ResourceTypes: ${e.treeshake.join(", ")}`),e.singleFile&&n.info("Single file output enabled (NDJSON format)"),e.registry&&n.info(`Using custom registry: ${e.registry}`);let t=Date.now(),r=e.packages.map(d=>{if(d.includes("@")){let u=d.lastIndexOf("@");return {name:d.slice(0,u),version:d.slice(u+1)||"latest"}}return {name:d,version:"latest"}});n.info(`Processing packages: ${r.map(d=>`${d.name}@${d.version}`).join(", ")}`);let o=await xe(r,{logger:n,registry:e.registry,focusedPackages:r}),{schemas:a}=await we(o,void 0,n);if(a.length===0)throw new Error("No schemas were generated from the specified packages");let s=e.output;if(!s)throw new Error("Output format not specified");await mkdir(dirname(s),{recursive:!0});let c;i==="json"?c=JSON.stringify(a,null,2):c=a.map(d=>JSON.stringify(d)).join(`
|
|
9
|
+
`),await writeFile(s,c,"utf-8");let l=Date.now()-t;if(re(`Generated ${a.length} TypeSchema definitions`,l,{schemas:a.length}),n.info(`Output: ${s}`),e.verbose){n.debug("Generated schemas:");let d=a.map(u=>`${u.identifier?.name||"Unknown"} (${u.identifier?.kind||"unknown"})`);F(d);}}catch(i){n.error(`Failed to generate TypeSchema: ${i instanceof Error?i.message:String(i)}`),process.exit(1);}}};var ee=k({prefix:"typeschema"}),$e={command:"typeschema [subcommand]",describe:"TypeSchema operations - generate, validate and merge schemas",builder:e=>e.command(Ue).help().example("$0 typeschema generate hl7.fhir.r4.core@4.0.1","Generate TypeSchema from FHIR R4 core package"),handler:e=>{if(!e.subcommand&&e._.length===1){ee.info("Available typeschema subcommands:"),F(["generate Generate TypeSchema files from FHIR packages"]),console.log(`
|
|
10
10
|
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),console.log(`
|
|
11
|
-
Examples:`),
|
|
12
|
-
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};var _=k({prefix:"cli"});async function
|
|
11
|
+
Examples:`),F(["atomic-codegen typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson","atomic-codegen typeschema validate schemas.ndjson","atomic-codegen typeschema merge schema1.ndjson schema2.ndjson -o merged.ndjson"]);return}e.subcommand&&!["generate","validate","merge"].includes(e.subcommand)&&(ee.error(`Unknown typeschema subcommand: ${e.subcommand}`),ee.info("Available typeschema subcommands:"),F(["generate Generate TypeSchema files from FHIR packages","validate Validate TypeSchema files for correctness and consistency","merge Merge multiple TypeSchema files into a single file"]),console.log(`
|
|
12
|
+
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};var _=k({prefix:"cli"});async function Pn(e){let n=e.logLevel??(e.debug||e.verbose?"DEBUG":"INFO");_=k({prefix:"cli",level:n});}function Nn(){return vn(hideBin(process.argv)).scriptName("atomic-codegen").usage("$0 <command> [options]").middleware(Pn).command($e).option("verbose",{alias:"v",type:"boolean",description:"Enable verbose output",default:false,global:true}).option("debug",{alias:"d",type:"boolean",description:"Enable debug output with detailed logging",default:false,global:true}).option("log-level",{alias:"l",type:"string",choices:["DEBUG","INFO","WARN","ERROR","SILENT"],description:"Set the log level (default: INFO)",global:true}).demandCommand(0).middleware(e=>{e._.length===0&&(ie("Welcome to Atomic Codegen!"),console.log("Available commands:"),console.log(" typeschema Generate, validate and merge TypeSchema files"),console.log(`
|
|
13
13
|
Use 'atomic-codegen <command> --help' for more information about a command.`),console.log(`
|
|
14
14
|
Quick examples:`),console.log(" atomic-codegen typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson"),console.log(`
|
|
15
|
-
Use 'atomic-codegen --help' to see all options.`),process.exit(0));}).help().version("0.1.0").example("$0 typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson","Generate TypeSchemas from FHIR package").fail((e,
|
|
15
|
+
Use 'atomic-codegen --help' to see all options.`),process.exit(0));}).help().version("0.1.0").example("$0 typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson","Generate TypeSchemas from FHIR package").fail((e,n,i)=>{_.error(n?n.message:e),_.error("Use --help for usage information"),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function ne(){await Nn().parseAsync();}import.meta.main&&ne().catch(e=>{_.error(String(e)),process.exit(1);});ne().catch(e=>{console.error("CLI Error:",e instanceof Error?e.message:e),process.exit(1);});
|
package/dist/index.d.ts
CHANGED
|
@@ -913,7 +913,7 @@ type LoggerOptions<T extends string> = {
|
|
|
913
913
|
level?: LogLevel;
|
|
914
914
|
};
|
|
915
915
|
|
|
916
|
-
type CodegenTag = "#binding" | "#largeValueSet" | "#fieldTypeNotFound" | "#skipCanonical" | "#duplicateSchema" | "#duplicateCanonical" | "#resolveBase" | "#resolveCollisionMiss";
|
|
916
|
+
type CodegenTag = "#binding" | "#largeValueSet" | "#placeholderValueSet" | "#fieldTypeNotFound" | "#skipCanonical" | "#duplicateSchema" | "#duplicateCanonical" | "#resolveBase" | "#resolveCollisionMiss";
|
|
917
917
|
type CodegenLog = Log<CodegenTag>;
|
|
918
918
|
type CodegenLogManager = LogManager<CodegenTag>;
|
|
919
919
|
declare const mkCodegenLogger: (opts?: LoggerOptions<CodegenTag>) => LogManager<CodegenTag>;
|