@atomic-ehr/codegen 0.0.13 → 0.0.14-canary.20260504104537.e5452bb

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 CHANGED
@@ -1,9 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import b from'picocolors';import In 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(b.cyan(b.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));},re=(e,n,i)=>{let t=e;if(n&&(t+=` ${b.gray(`(${n}ms)`)}`),console.log(`${b.green("")} ${t}`),i)for(let[r,o]of Object.entries(i))console.log(b.gray(` ${r}: ${o}`));},F=(e,n="\u2022")=>{for(let i of e)console.log(b.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",c=p=>oe[p]>=oe[a],l={DEBUG:p=>p,INFO:p=>p,WARN:b.yellow,ERROR:b.red,SILENT:p=>p},s=(p,m,f,y)=>{let h=n?`${n}: `:"",S=y?` ${b.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: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&&c(p)){if(y){let N=`${p}::${S??""}::${x}`;if(o.has(N))return;o.add(N);}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=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(b.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(b.dim(`i ${m}${h} suppressed (${S})`));}},buffer(){return r},bufferClear(){r.length=0;}};return g}var D="Use CodeableReference which is not provided by FHIR R4.",Be="Use Availability which is not provided by FHIR R4.",A={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":Be,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":D,"http://hl7.org/fhir/StructureDefinition/specimen-additive":D,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":D,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":D,"http://hl7.org/fhir/StructureDefinition/workflow-reason":D},"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 T(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 z=e=>e?.kind==="nested";var v=(...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 G(e){let n=e.split("|")[0];return n||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 n=je(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 Me=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 H(e,n,i){let t=G(i),r=Me(t),o={package_meta:{name:"missing_valuesets",version:Oe(t)||"0.0.0"},id:i},a=e.resolveVs(n,t)||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:t}}function L(e,n,i){let t=i.binding?.bindingName,r=n.join("."),[o,a,c]=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:c}}function q(e,n,i,t){let r=G(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=>(Ne(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=(c,l)=>{for(let s of c)t.push({system:l,code:s.code,display:s.display}),s.concept&&a(s.concept,l);};a(o.concept,r.system);}}catch{}}return t.length>0?t:void 0}var de=100,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 c=q(e,n.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){t?.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 ze(e,n,i,t,r){if(!t.binding?.valueSet)return;let o=L(n,i,t),a=H(e,n.package_meta,t.binding.valueSet),c=K(e,n,t,r);return {identifier:o,valueset:a,strength:t.binding.strength,enum:c,dependencies:[a]}}function me(e,n,i){let t=new Set;if(!n.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(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((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 Ge=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[n,...i]=Ge(e);return [n?.toLowerCase(),...i.map(qe)].join("")};var J=e=>!e||e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1);var We=e=>{let n=e.replace(/\[x\]/g,"").replace(/[- :.]/g,"_");return n?J(n):""},w=e=>{let n=e.replace(/\[x\]/g,"").replace(/:/g,"_");return n?J(ue(n)):""},Ke=(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=We(n)||"Slice",r=`${w(e)||"Field"}${i}`;return [i,r,`${r}Slice`]},Ye=(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},{}),Ze=(e,n)=>{let i=e[0]?.candidates.length??0,t=(r,o)=>{if(r.length===0||o>=i)return {};let a=Ye(r,o,n),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,...t(s,o+1)}};return t(e,0)},fe=e=>({candidates:Ke(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,c])=>!("slicing"in c)||!c.slicing?.slices?[]:Object.entries(c.slicing.slices).map(([l,s])=>({key:`slice:${a}:${l}`,candidates:s.nameCandidates.candidates}))),t=new Set(Object.keys(e.fields??{}).map(w)),r=[...n,...i];if(r.length===0)return;let o=Ze(r,t);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 Y=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var U=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var Xe=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 l of await e.search({package:n})){let s=l.url;if(!s||!(isStructureDefinition(l)||U(l)||Y(l)))continue;let d=s;a.canonicalResolution[d]&&r?.dryWarn("#duplicateCanonical",`Duplicate canonical URL: ${d} at ${o}.`),a.canonicalResolution[d]=[{deep:i,pkg:n,pkgId:o,resource:l}];}let c=await Xe(e,n);for(let l of c){let{canonicalResolution:s}=await Re(e,l,i+1,t,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 t[o]=a,a},en=(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,c]of Object.entries(t)){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;}}n?.info(`FHIR Schema conversion for '${R(i)}' completed: ${o} successful`);}},nn=(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},tn=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);en(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}},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=B(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=>nn(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 tn(t,{...n,focusedPackages:e})},B=(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=B(t,i),o=Z(r).type,a;if(o){let c=e.ensureSpecializationCanonicalUrl(o),s=e.resolveFsGenealogy(n.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,n,i,t,r)=>t.type==="BackboneElement"?true:!r?.elements||r.choiceOf!==void 0?false:Ce(e,n,i),rn=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 V(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=rn(d);for(let g of u)t[g]=`${d.url}#${g}`;}let o=i.join("."),a=t[o]??`${n.url}#${o}`,c=a.split("#")[0],s=e.resolveFs(n.package_meta,c)?.package_meta??n.package_meta;return {kind:"nested",package:s.name,version:s.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 on(e,n,i,t,r){let o={},a=e.resolveFsGenealogy(n.package_meta,n.url),c=B(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(n,d);Q(e,n,d,u,t[s])?o[s]=j(e,n,d,u):o[s]=O(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 c=V(e,n,o),l;a.type==="BackboneElement"||!a.type?l="BackboneElement":l=a.type;let s=e.ensureSpecializationCanonicalUrl(l),d=e.resolveFs(n.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=on(e,n,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 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}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 c=a;for(let l of r)c=c?.elements?.[l];return c?.required||[]});return new Set(o).has(t)}function Fe(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 c=a;for(let l of r)c=c?.elements?.[l];return c?.excluded||[]});return new Set(o).has(t)}var an=(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)})},sn=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}},cn=e=>!e||typeof e=="object"&&Object.keys(e).length===0,M=(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;},ln=(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},Te=(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){M(t,n,a.fixed.value);return}if(a.slicing?.slices){r.add(n.slice(0,i+1).join("."));let c=n.slice(i+1);for(let l of Object.values(a.slicing.slices)){if(!l.min||l.min<1||!l.match||typeof l.match!="object")continue;let s=l.match;if(Object.keys(s).length!==0)if(c.length>0){let d=ln(s,c);d!==void 0&&M(t,n,d);}else M(t,n.slice(0,i+1),s);}return}Te(a,n,i+1,t,r);}},pn=(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("/")||M(i,t,{resourceType:o});},dn=(e,n)=>{if(!n||!e||e.length===0)return;let i={},t=new Set;for(let r of e)if(r.type==="type")pn(r.path,n,i);else {if(!n.elements)continue;let o=r.path.split(".");Te(n,o,0,i,t);}if(Object.keys(i).length!==0){for(let r of t){let o=r.split("."),a=i;for(let l=0;l<o.length-1;l++){let s=a[o[l]];if(!s||typeof s!="object"||Array.isArray(s))break;a=s;}let c=o[o.length-1];a[c]&&typeof a[c]=="object"&&!Array.isArray(a[c])&&(a[c]=[a[c]]);}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:c,elements:l}=o.schema?sn(o.schema):{};t[r]={min:o.min,max:o.max,match:cn(o.match)?dn(i.discriminator??[],o.schema):o.match,required:a,excluded:c,elements:l,nameCandidates:ge(e,r)};}return {discriminator:i.discriminator??[],rules:i.rules,ordered:i.ordered,slices:Object.keys(t).length>0?t:void 0}};function E(e,n,i,t,r){if(t.elementReference){let o=t.elementReference.slice(1).filter((a,c)=>c%2===1);return V(e,n,o)}else if(t.type){let o=e.ensureSpecializationCanonicalUrl(t.type),a=e.resolveFs(n.package_meta,o);if(!a)throw new Error(`Could not resolve field type: <${n.url}>.${i.join(".")}: <${t.type}> (pkg: '${R(n.package_meta)}'))`);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 O=(e,n,i,t,r,o)=>{let a,c;t.binding&&(a=L(n,i,t),W.has(t.type??"")&&(c=K(e,n,t,r)));let l=E(e,n,i,t,r);l||r?.dryWarn("#fieldTypeNotFound",`Field type not found for '${n.url}#${i.join(".")}' (${n.derivation})`);let s;t.pattern?s={kind:"pattern",type:t.pattern.type,value:t.pattern.value}:t.fixed&&(s={kind:"fixed",type:t.fixed.type,value:t.fixed.value});let d=o??t;if(!s&&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)&&(s={kind:"fixed",type:"CodeableConcept",value:{coding:g.flatMap(f=>f.match?[f.match]:[])}});}return {type:l,required:be(e,n,i),excluded:Fe(e,n,i),reference:an(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:c,valueConstraint:s,mustSupport:t.mustSupport}};function j(e,n,i,t){return {type:V(e,n,i),array:t.array||false,required:be(e,n,i),excluded:Fe(e,n,i),slicing:ve(i[i.length-1]??"",t)}}var mn=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=[];for(let[a,c]of Object.entries(r.elements)){if(c.choiceOf!=="value"&&!a.startsWith("value"))continue;let l=E(e,r,[a],c,t);l&&o.push(l);}return v(o)},un=(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 c;for(let[l,s]of Object.entries(o.elements??{}))if(!(s.choiceOf!=="value"&&!l.startsWith("value"))&&(c=E(e,n,[r,l],s,i),c))break;t.push({name:a,url:o.url??a,valueFieldType:c,min:o.min,max:o.max!==void 0?String(o.max):void 0});}return t},fn=(e,n,i)=>{let t=[],o=n.elements?.extension?.slicing?.slices;if(!o||typeof o!="object")return t;for(let[a,c]of Object.entries(o)){let l=c,s=l.schema;if(!s)continue;let d;for(let[u,g]of Object.entries(s.elements??{})){let p=g;if(!(p.choiceOf!=="value"&&!u.startsWith("value"))&&(d=E(e,n,[u],p,i),d))break}t.push({name:a,url:l.match?.url??a,valueFieldType:d,min:s._required?1:s.min??0,max:s.max!==void 0?String(s.max):s.array?"*":"1"});}return t},gn=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=un(e,r,t),a=fn(e,r,t),c=[...o,...a];return c.length>0?c:void 0},Ee=(e,n,i)=>{let t=[],r=(l,s,d)=>{let u=d.url,g=u?mn(e,n,u,i):void 0,p=u?gn(e,n,u,i):void 0;if(!u){let S=n.elements?.extension?.slicing?.slices?.[s]?.schema;if(S){u=S.elements?.url?.fixed?.value??s;for(let[x,C]of Object.entries(S.elements??{})){let N=C;if(N.choiceOf==="value"||x.startsWith("value")){let te=E(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=[...l,"extension"].join(".");t.push({name:s,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:s,path:h})});},o=(l,s)=>{if(s.extensions)for(let[d,u]of Object.entries(s.extensions))r(l,d,u);if(s.elements)for(let[d,u]of Object.entries(s.elements))o([...l,d],u);};o([],n);let a=new Set,c=t.filter(l=>{let s=`${l.url}:${l.path}`;return a.has(s)?false:(a.add(s),true)});return c.length===0?void 0:c};function yn(e,n,i,t,r){if(!t)return;let o={};for(let a of e.getAllElementKeys(t)){let c=[...i,a],l=e.resolveElementSnapshot(n,c),s=l.type?e.ensureSpecializationCanonicalUrl(l.type):void 0;if(s&&T(n.package_meta,s).shouldSkip){r?.warn("#skipCanonical",`Skipping field ${c} for ${s} due to skip hack ${T(n.package_meta,s).reason}`);continue}Q(e,n,c,l,t[a])?o[a]=j(e,n,c,l):o[a]=O(e,n,c,l,r,t[a]);}return o}function hn(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=H(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 He=(e,n,i)=>{let t=[];return e&&t.push(e),n&&t.push(...hn(n)),i&&t.push(...Ie(i)),t},Pe=(e,n,i,t)=>{let o=He(n,i,t).filter(a=>!(a.url===e.url||z(a)));return v(o)},Sn=(e,n,i,t)=>{let o=He(n,i,t).filter(a=>a.url!==e.url);return v(o)};function Le(e,n,i){let t;if(n.base){let s=e.resolveFs(n.package_meta,e.ensureSpecializationCanonicalUrl(n.base));if(!s)throw new Error(`Base resource not found '${n.base}' for <${n.url}> from ${R(n.package_meta)}`);let d=I(s);Ne(!z(d),`Unexpected nested base for ${n.url}`),t=d;}let r=yn(e,n,[],n.elements,i),o=ke(e,n,i),a=me(e,n,i);if(n.derivation==="constraint"){let s=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=Sn(s,t,r,o),p={identifier:s,base:t,fields:r,nested:o,description:n.description,dependencies:v(g,u),extensions:d};return ye(p),[p,...a]}if(n.kind==="primitive-type"){let s=I(n);return Ne(t,`Primitive type ${n.url} must have a base type`),[{identifier:s,description:n.description,base:t,dependencies:Pe(s,t,r,o)},...a]}let c=I(n);return [{identifier:c,base:t,fields:r,nested:o,description:n.description,dependencies:Pe(c,t,r,o),typeFamily:void 0},...a]}var Rn=(e,n,i)=>{let t={};for(let a of e){let c=`${a.schema.identifier.url}|${a.schema.identifier.package}`,l=se(a.schema);t[c]??={},t[c][l]??={typeSchema:a.schema,sources:[]},t[c][l].sources.push(a);}let r=[],o={};for(let a of Object.values(t)){let c=Object.values(a).sort((s,d)=>d.sources.length-s.sources.length),l=c[0];if(l)if(c.length>1){let s=l.typeSchema.identifier.url,d=l.typeSchema.identifier.package;i?.dryWarn("#duplicateSchema",`'${s}' from '${d}' has ${c.length} versions`),r.push(l.typeSchema);o[d]??={},o[d][s]=c.flatMap(g=>g.sources.map(p=>({typeSchema:g.typeSchema,sourcePackage:p.sourcePackage,sourceCanonical:p.sourceCanonical})));}else r.push(l.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=T(r.package_meta,r.url);if(a.shouldSkip){i?.dryWarn("#skipCanonical",`Skip ${r.url} from ${o}. Reason: ${a.reason}`);continue}for(let c of Le(e,r,i))t.push({schema:c,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 Rn(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 c=e.output;if(!c)throw new Error("Output format not specified");await mkdir(dirname(c),{recursive:!0});let l;i==="json"?l=JSON.stringify(a,null,2):l=a.map(d=>JSON.stringify(d)).join(`
3
- `),await writeFile(c,l,"utf-8");let s=Date.now()-t;if(re(`Generated ${a.length} TypeSchema definitions`,s,{schemas:a.length}),n.info(`Output: ${c}`),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(`
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)?"":`
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,t,i){let n=i[i.length-1];if(!n)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(a=>{if(r.length===0)return a.required||[];if(!a.elements)return [];let c=a;for(let l of r)c=c?.elements?.[l];return c?.required||[]});return new Set(o).has(n)}function Fe(e,t,i){let n=i[i.length-1];if(!n)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(a=>{if(r.length===0)return a.excluded||[];if(!a.elements)return [];let c=a;for(let l of r)c=c?.elements?.[l];return c?.excluded||[]});return new Set(o).has(n)}var ct=(e,t,i)=>{if(i.refers)return i.refers.map(n=>{let r=e.ensureSpecializationCanonicalUrl(n),o=e.resolveFs(t.package_meta,r);if(!o)throw new Error(`Failed to resolve fs for ${r}`);return I(o)})},lt=e=>{let t=new Set,i=new Set;if(e.required)for(let r of e.required)t.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&&t.add(r);let n=e.elements?Object.keys(e.elements):void 0;return {required:t.size>0?Array.from(t):void 0,excluded:i.size>0?Array.from(i):void 0,elements:n&&n.length>0?n:void 0}},pt=e=>!e||typeof e=="object"&&Object.keys(e).length===0,M=(e,t,i)=>{let n=e;for(let o=0;o<t.length-1;o++){let a=t[o];(!n[a]||typeof n[a]!="object")&&(n[a]={}),n=n[a];}let r=t[t.length-1];n[r]=i;},dt=(e,t)=>{let i=e;for(let n of t)if(i&&typeof i=="object"&&!Array.isArray(i))i=i[n];else return;return i},Te=(e,t,i,n,r)=>{if(i>=t.length||!e.elements)return;let o=t[i],a=e.elements[o];if(a){if(i===t.length-1&&a.fixed?.value!==void 0){M(n,t,a.fixed.value);return}if(a.slicing?.slices){r.add(t.slice(0,i+1).join("."));let c=t.slice(i+1);for(let l of Object.values(a.slicing.slices)){if(!l.min||l.min<1||!l.match||typeof l.match!="object")continue;let s=l.match;if(Object.keys(s).length!==0)if(c.length>0){let d=dt(s,c);d!==void 0&&M(n,t,d);}else M(n,t.slice(0,i+1),s);}return}Te(a,t,i+1,n,r);}},mt=(e,t,i)=>{if(e==="$this")return;let n=e.split("."),r=t;for(let a of n)if(r=r?.elements?.[a],!r)return;let o=r.type;!o||o.includes("/")||M(i,n,{resourceType:o});},ut=(e,t)=>{if(!t||!e||e.length===0)return;let i={},n=new Set;for(let r of e)if(r.type==="type")mt(r.path,t,i);else {if(!t.elements)continue;let o=r.path.split(".");Te(t,o,0,i,n);}if(Object.keys(i).length!==0){for(let r of n){let o=r.split("."),a=i;for(let l=0;l<o.length-1;l++){let s=a[o[l]];if(!s||typeof s!="object"||Array.isArray(s))break;a=s;}let c=o[o.length-1];a[c]&&typeof a[c]=="object"&&!Array.isArray(a[c])&&(a[c]=[a[c]]);}return i}},ve=(e,t)=>{let i=t.slicing;if(!i)return;let n={};for(let[r,o]of Object.entries(i.slices??{})){if(!o)continue;let{required:a,excluded:c,elements:l}=o.schema?lt(o.schema):{};n[r]={min:o.min,max:o.max,match:pt(o.match)?ut(i.discriminator??[],o.schema):o.match,required:a,excluded:c,elements:l,nameCandidates:ge(e,r)};}return {discriminator:i.discriminator??[],rules:i.rules,ordered:i.ordered,slices:Object.keys(n).length>0?n:void 0}};function N(e,t,i,n,r){if(n.elementReference){let o=n.elementReference.slice(1).filter((a,c)=>c%2===1);return B(e,t,o)}else if(n.type){let o=e.ensureSpecializationCanonicalUrl(n.type),a=e.resolveFs(t.package_meta,o);if(!a){let c=R(t.package_meta),l=i.join("."),s=st(e,t.package_meta,n.type);throw new Error(`Could not resolve field type:
5
+ package: ${c}
6
+ schema: ${t.url}
7
+ field: ${l}
8
+ type: ${n.type}${s}`)}return I(a)}else {if(n.choices)return;if(t.derivation==="constraint")return;r?.dryWarn("#fieldTypeNotFound",`Can't recognize element type: <${t.url}>.${i.join(".")} (pkg: '${R(t.package_meta)}'): missing type info`);return}}var O=(e,t,i,n,r,o)=>{let a,c;n.binding&&(a=L(t,i,n),W.has(n.type??"")&&(c=K(e,t,n,r)));let l=N(e,t,i,n,r);l||r?.dryWarn("#fieldTypeNotFound",`Field type not found for '${t.url}#${i.join(".")}' (${t.derivation})`);let s;n.pattern?s={kind:"pattern",type:n.pattern.type,value:n.pattern.value}:n.fixed&&(s={kind:"fixed",type:n.fixed.type,value:n.fixed.value});let d=o??n;if(!s&&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)&&(s={kind:"fixed",type:"CodeableConcept",value:{coding:g.flatMap(f=>f.match?[f.match]:[])}});}return {type:l,required:be(e,t,i),excluded:Fe(e,t,i),reference:ct(e,t,n),array:n.array||false,min:n.min,max:n.max,slicing:ve(i[i.length-1]??"",n),choices:n.choices,choiceOf:n.choiceOf,binding:a,enum:c,valueConstraint:s,mustSupport:n.mustSupport}};function j(e,t,i,n){return {type:B(e,t,i),array:n.array||false,required:be(e,t,i),excluded:Fe(e,t,i),slicing:ve(i[i.length-1]??"",n)}}var ft=(e,t,i,n)=>{let r=e.resolveFs(t.package_meta,i);if(!r?.elements)return;let o=[];for(let[a,c]of Object.entries(r.elements)){if(c.choiceOf!=="value"&&!a.startsWith("value"))continue;let l=N(e,r,[a],c,n);l&&o.push(l);}return E(o)},gt=(e,t,i)=>{let n=[];if(!t.elements)return n;for(let[r,o]of Object.entries(t.elements)){if(!r.startsWith("extension:"))continue;let a=r.split(":")[1];if(!a)continue;let c;for(let[l,s]of Object.entries(o.elements??{}))if(!(s.choiceOf!=="value"&&!l.startsWith("value"))&&(c=N(e,t,[r,l],s,i),c))break;n.push({name:a,url:o.url??a,valueFieldType:c,min:o.min,max:o.max!==void 0?String(o.max):void 0});}return n},yt=(e,t,i)=>{let n=[],o=t.elements?.extension?.slicing?.slices;if(!o||typeof o!="object")return n;for(let[a,c]of Object.entries(o)){let l=c,s=l.schema;if(!s)continue;let d;for(let[u,g]of Object.entries(s.elements??{})){let p=g;if(!(p.choiceOf!=="value"&&!u.startsWith("value"))&&(d=N(e,t,[u],p,i),d))break}n.push({name:a,url:l.match?.url??a,valueFieldType:d,min:s._required?1:s.min??0,max:s.max!==void 0?String(s.max):s.array?"*":"1"});}return n},ht=(e,t,i,n)=>{let r=e.resolveFs(t.package_meta,i);if(!r?.elements)return;let o=gt(e,r,n),a=yt(e,r,n),c=[...o,...a];return c.length>0?c:void 0},Ee=(e,t,i)=>{let n=[],r=(l,s,d)=>{let u=d.url,g=u?ft(e,t,u,i):void 0,p=u?ht(e,t,u,i):void 0;if(!u){let S=t.elements?.extension?.slicing?.slices?.[s]?.schema;if(S){u=S.elements?.url?.fixed?.value??s;for(let[x,C]of Object.entries(S.elements??{})){let P=C;if(P.choiceOf==="value"||x.startsWith("value")){let ne=N(e,t,[x],P,i);if(ne){g=[ne];break}}}}}let m=p&&p.length>0,f=u?e.resolveFs(t.package_meta,u):void 0,y=f?I(f):void 0,h=[...l,"extension"].join(".");n.push({name:s,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:s,path:h})});},o=(l,s)=>{if(s.extensions)for(let[d,u]of Object.entries(s.extensions))r(l,d,u);if(s.elements)for(let[d,u]of Object.entries(s.elements))o([...l,d],u);};o([],t);let a=new Set,c=n.filter(l=>{let s=`${l.url}:${l.path}`;return a.has(s)?false:(a.add(s),true)});return c.length===0?void 0:c};function St(e,t,i,n,r){if(!n)return;let o={};for(let a of e.getAllElementKeys(n)){let c=[...i,a],l=e.resolveElementSnapshot(t,c),s=l.type?e.ensureSpecializationCanonicalUrl(l.type):void 0;if(s&&v(t.package_meta,s).shouldSkip){r?.warn("#skipCanonical",`Skipping field ${c} for ${s} due to skip hack ${v(t.package_meta,s).reason}`);continue}Q(e,t,c,l,n[a])?o[a]=j(e,t,c,l):o[a]=O(e,t,c,l,r,n[a]);}return o}function Rt(e){let t=[];for(let i of Object.values(e))"type"in i&&i.type&&t.push(i.type),"binding"in i&&i.binding&&t.push(i.binding);return t}async function De(e,t,i){if(!t.url)throw new Error("ValueSet URL is required");let n=H(e,t.package_meta,t.url),r=q(e,t.package_meta,t.url);return {identifier:n,description:t.description,concept:r,compose:r?void 0:t.compose}}var He=(e,t,i)=>{let n=[];return e&&n.push(e),t&&n.push(...Rt(t)),i&&n.push(...Ie(i)),n},Pe=(e,t,i,n)=>{let o=He(t,i,n).filter(a=>!(a.url===e.url||G(a)));return E(o)},xt=(e,t,i,n)=>{let o=He(t,i,n).filter(a=>a.url!==e.url);return E(o)};function Le(e,t,i){let n;if(t.base){let s=e.resolveFs(t.package_meta,e.ensureSpecializationCanonicalUrl(t.base));if(!s)throw new Error(`Base resource not found '${t.base}' for <${t.url}> from ${R(t.package_meta)}`);let d=I(s);Ne(!G(d),`Unexpected nested base for ${t.url}`),n=d;}let r=St(e,t,[],t.elements,i),o=ke(e,t,i),a=me(e,t,i);if(t.derivation==="constraint"){let s=I(t);if(!n)throw new Error(`Profile ${t.url} must have a base type`);let d=Ee(e,t,i),u=d?.flatMap(le),g=xt(s,n,r,o),p={identifier:s,base:n,fields:r,nested:o,description:t.description,dependencies:E(g,u),extensions:d};return ye(p),[p,...a]}if(t.kind==="primitive-type"){let s=I(t);return Ne(n,`Primitive type ${t.url} must have a base type`),[{identifier:s,description:t.description,base:n,dependencies:Pe(s,n,r,o)},...a]}let c=I(t);return [{identifier:c,base:n,fields:r,nested:o,description:t.description,dependencies:Pe(c,n,r,o),typeFamily:void 0},...a]}var Ct=(e,t,i)=>{let n={};for(let a of e){let c=`${a.schema.identifier.url}|${a.schema.identifier.package}`,l=se(a.schema);n[c]??={},n[c][l]??={typeSchema:a.schema,sources:[]},n[c][l].sources.push(a);}let r=[],o={};for(let a of Object.values(n)){let c=Object.values(a).sort((s,d)=>d.sources.length-s.sources.length),l=c[0];if(l)if(c.length>1){let s=l.typeSchema.identifier.url,d=l.typeSchema.identifier.package;i?.dryWarn("#duplicateSchema",`'${s}' from '${d}' has ${c.length} versions`),r.push(l.typeSchema);o[d]??={},o[d][s]=c.flatMap(g=>g.sources.map(p=>({typeSchema:g.typeSchema,sourcePackage:p.sourcePackage,sourceCanonical:p.sourceCanonical})));}else r.push(l.typeSchema);}return {schemas:r,collisions:o}},we=async(e,t,i)=>{let n=[];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 c of Le(e,r,i))n.push({schema:c,sourcePackage:o,sourceCanonical:r.url});}for(let r of e.allVs())n.push({schema:await De(e,r),sourcePackage:R(r.package_meta),sourceCanonical:r.url});return Ct(n,t,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 t=k({prefix:"TypeSchema"});try{t.info("Generating TypeSchema from FHIR packages"),t.info(`Packages: ${e.packages.join(", ")}`),t.info(`Output: ${e.output}`);let i=e.singleFile?"ndjson":e.format;t.debug(`Format: ${i}${e.singleFile&&e.format==="json"?" (forced from json due to singleFile)":""}`),e.treeshake&&e.treeshake.length>0&&t.info(`Treeshaking enabled for ResourceTypes: ${e.treeshake.join(", ")}`),e.singleFile&&t.info("Single file output enabled (NDJSON format)"),e.registry&&t.info(`Using custom registry: ${e.registry}`);let n=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"}});t.info(`Processing packages: ${r.map(d=>`${d.name}@${d.version}`).join(", ")}`);let o=await xe(r,{logger:t,registry:e.registry,focusedPackages:r}),{schemas:a}=await we(o,void 0,t);if(a.length===0)throw new Error("No schemas were generated from the specified packages");let c=e.output;if(!c)throw new Error("Output format not specified");await mkdir(dirname(c),{recursive:!0});let l;i==="json"?l=JSON.stringify(a,null,2):l=a.map(d=>JSON.stringify(d)).join(`
9
+ `),await writeFile(c,l,"utf-8");let s=Date.now()-n;if(re(`Generated ${a.length} TypeSchema definitions`,s,{schemas:a.length}),t.info(`Output: ${c}`),e.verbose){t.debug("Generated schemas:");let d=a.map(u=>`${u.identifier?.name||"Unknown"} (${u.identifier?.kind||"unknown"})`);T(d);}}catch(i){t.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:"),T(["generate Generate TypeSchema files from FHIR packages"]),console.log(`
4
10
  Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),console.log(`
5
- 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(`
6
- Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};var _=k({prefix:"cli"});async function Fn(e){let n=e.logLevel??(e.debug||e.verbose?"DEBUG":"INFO");_=k({prefix:"cli",level:n});}function Tn(){return In(hideBin(process.argv)).scriptName("atomic-codegen").usage("$0 <command> [options]").middleware(Fn).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(`
11
+ Examples:`),T(["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:"),T(["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 vt(e){let t=e.logLevel??(e.debug||e.verbose?"DEBUG":"INFO");_=k({prefix:"cli",level:t});}function Et(){return Ft(hideBin(process.argv)).scriptName("atomic-codegen").usage("$0 <command> [options]").middleware(vt).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(`
7
13
  Use 'atomic-codegen <command> --help' for more information about a command.`),console.log(`
8
14
  Quick examples:`),console.log(" atomic-codegen typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson"),console.log(`
9
- 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 Tn().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);});
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,t,i)=>{_.error(t?t.message:e),_.error("Use --help for usage information"),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function te(){await Et().parseAsync();}import.meta.main&&te().catch(e=>{_.error(String(e)),process.exit(1);});te().catch(e=>{console.error("CLI Error:",e instanceof Error?e.message:e),process.exit(1);});
package/dist/index.d.ts CHANGED
@@ -67,7 +67,7 @@ interface Identifier extends Element {
67
67
  interface Reference<T extends string = string> extends Element {
68
68
  display?: string;
69
69
  identifier?: Identifier;
70
- reference?: `${T}/${string}`;
70
+ reference?: `${T}/${string}` | `http://${string}` | `https://${string}` | `urn:uuid:${string}` | `urn:oid:${string}` | `#${string}`;
71
71
  type?: string;
72
72
  }
73
73
 
@@ -1091,12 +1091,17 @@ interface APIBuilderOptions {
1091
1091
  type GenerationReport = {
1092
1092
  success: boolean;
1093
1093
  outputDir: string;
1094
- filesGenerated: Record<string, string>;
1094
+ /** Generated files nested by generator name, then by path: `filesGenerated[generator][path] = content`. */
1095
+ filesGenerated: Record<string, Record<string, string>>;
1095
1096
  errors: string[];
1096
1097
  warnings: string[];
1097
1098
  duration: number;
1098
1099
  };
1099
- declare const prettyReport: (report: GenerationReport) => string;
1100
+ interface PrettyReportOptions {
1101
+ /** When a generator produces more than this many files, aggregate them by directory instead of listing each file. */
1102
+ fileLimit?: number;
1103
+ }
1104
+ declare const prettyReport: (report: GenerationReport, options?: PrettyReportOptions) => string;
1100
1105
  interface LocalStructureDefinitionConfig {
1101
1106
  package: PackageMeta;
1102
1107
  path: string;
package/dist/index.js CHANGED
@@ -868,6 +868,101 @@ var populateTypeFamily = (schemas) => {
868
868
  if (Object.keys(family).length > 0) schema.typeFamily = family;
869
869
  }
870
870
  };
871
+ var collectGenericContributions = (schema, resolveType) => {
872
+ const contributions = [];
873
+ for (const [fieldName, field] of Object.entries(schema.fields ?? {})) {
874
+ if (isChoiceDeclarationField(field) || !field.type) continue;
875
+ const target = resolveType(field.type);
876
+ if (!target) continue;
877
+ if (isNestedTypeSchema(target)) {
878
+ const params = target.generic?.params;
879
+ if (params?.length) contributions.push({ kind: "passthrough", fieldName, params });
880
+ } else if (isSpecializationTypeSchema(target)) {
881
+ const params = target.generic?.params;
882
+ if (params?.length) {
883
+ contributions.push({ kind: "passthrough", fieldName, params });
884
+ } else if ((target.typeFamily?.resources?.length ?? 0) > 0) {
885
+ contributions.push({ kind: "introduce", fieldName, constraint: field.type });
886
+ }
887
+ }
888
+ }
889
+ return contributions;
890
+ };
891
+ var samePath = (a, b) => a.length === b.length && a.every((s, i) => s === b[i]);
892
+ var leafOf = (path) => path[path.length - 1] ?? "";
893
+ var renderGenericParams = (contributions) => {
894
+ const raw = [];
895
+ for (const c of contributions) {
896
+ if (c.kind === "introduce") {
897
+ const path = [c.fieldName];
898
+ if (!raw.find((r) => leafOf(r.path) === leafOf(path))) {
899
+ raw.push({ path, constraint: c.constraint });
900
+ }
901
+ } else {
902
+ for (const np of c.params) {
903
+ const path = [c.fieldName, ...np.path];
904
+ if (!raw.find((r) => leafOf(r.path) === leafOf(path))) {
905
+ raw.push({ path, constraint: np.constraint });
906
+ }
907
+ }
908
+ }
909
+ }
910
+ if (raw.length === 0) return [];
911
+ return raw.map((r, i) => ({
912
+ typeVar: raw.length === 1 ? "T" : `T${i + 1}`,
913
+ constraint: r.constraint,
914
+ path: r.path
915
+ }));
916
+ };
917
+ var populateGeneric = (schemas, resolveType) => {
918
+ const carriers = [];
919
+ for (const schema of schemas) {
920
+ if (isSpecializationTypeSchema(schema)) {
921
+ carriers.push(schema);
922
+ for (const nested of schema.nested ?? []) carriers.push(nested);
923
+ } else if (isProfileTypeSchema(schema)) {
924
+ for (const nested of schema.nested ?? []) carriers.push(nested);
925
+ }
926
+ }
927
+ for (const c of carriers) c.generic = void 0;
928
+ const sameParams = (a, b) => {
929
+ if (a.length !== b.length) return false;
930
+ for (let i = 0; i < a.length; i++) {
931
+ const x = a[i];
932
+ const y = b[i];
933
+ if (x.typeVar !== y.typeVar || !samePath(x.path, y.path) || x.constraint.url !== y.constraint.url)
934
+ return false;
935
+ }
936
+ return true;
937
+ };
938
+ let changed = true;
939
+ let iter = 0;
940
+ while (changed && iter++ <= carriers.length) {
941
+ changed = false;
942
+ for (const c of carriers) {
943
+ const newParams = renderGenericParams(collectGenericContributions(c, resolveType));
944
+ const oldParams = c.generic?.params ?? [];
945
+ if (sameParams(oldParams, newParams)) continue;
946
+ c.generic = newParams.length > 0 ? { params: newParams } : void 0;
947
+ changed = true;
948
+ }
949
+ }
950
+ for (const schema of schemas) {
951
+ if (!isSpecializationTypeSchema(schema)) continue;
952
+ const constraints = [];
953
+ const collect = (params) => {
954
+ for (const p of params) {
955
+ if (!isNestedIdentifier(p.constraint)) constraints.push(p.constraint);
956
+ }
957
+ };
958
+ if (schema.generic) collect(schema.generic.params);
959
+ for (const nested of schema.nested ?? []) {
960
+ if (nested.generic) collect(nested.generic.params);
961
+ }
962
+ if (constraints.length === 0) continue;
963
+ schema.dependencies = concatIdentifiers(schema.dependencies, constraints) ?? schema.dependencies;
964
+ }
965
+ };
871
966
  var mkTypeSchemaIndex = (schemas, {
872
967
  register,
873
968
  logger,
@@ -908,6 +1003,7 @@ var mkTypeSchemaIndex = (schemas, {
908
1003
  if (isNestedIdentifier(id)) return nestedIndex[id.url]?.[id.package];
909
1004
  return index[id.url]?.[id.package];
910
1005
  };
1006
+ populateGeneric(schemas, resolveType);
911
1007
  const resolveByUrl = (pkgName, url) => {
912
1008
  if (register) {
913
1009
  const resolutionTree = register.resolutionTree();
@@ -1754,6 +1850,8 @@ var codeableReferenceInR4 = "Use CodeableReference which is not provided by FHIR
1754
1850
  var availabilityInR4 = "Use Availability which is not provided by FHIR R4.";
1755
1851
  var skipList = {
1756
1852
  "hl7.fhir.uv.extensions.r4": {
1853
+ "http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-manipulation": codeableReferenceInR4,
1854
+ "http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-processing": codeableReferenceInR4,
1757
1855
  "http://hl7.org/fhir/StructureDefinition/extended-contact-availability": availabilityInR4,
1758
1856
  "http://hl7.org/fhir/StructureDefinition/immunization-procedure": codeableReferenceInR4,
1759
1857
  "http://hl7.org/fhir/StructureDefinition/specimen-additive": codeableReferenceInR4,
@@ -2481,6 +2579,31 @@ function extractNestedDependencies(nestedTypes) {
2481
2579
  }
2482
2580
 
2483
2581
  // src/typeschema/core/field-builder.ts
2582
+ var R5_ONLY_TYPES = /* @__PURE__ */ new Set([
2583
+ "Availability",
2584
+ "CodeableReference",
2585
+ "ExtendedContactDetail",
2586
+ "MonetaryComponent",
2587
+ "RatioRange",
2588
+ "VirtualServiceDetail"
2589
+ ]);
2590
+ var dependsOnR4Core = (register, pkg) => {
2591
+ const pkgIndex = register.resolver[packageMetaToFhir(pkg)];
2592
+ if (!pkgIndex) return false;
2593
+ for (const options of Object.values(pkgIndex.canonicalResolution)) {
2594
+ for (const opt of options) {
2595
+ if (opt.pkg.name === "hl7.fhir.r4.core") return true;
2596
+ }
2597
+ }
2598
+ return false;
2599
+ };
2600
+ var fieldTypeResolutionHint = (register, pkg, type) => {
2601
+ if (!R5_ONLY_TYPES.has(type)) return "";
2602
+ if (!dependsOnR4Core(register, pkg)) return "";
2603
+ return `
2604
+ hint: '${type}' is an R5+ type and is not available when generating against R4.
2605
+ Either skip this canonical via skip-hack.ts, or upgrade the target to R5.`;
2606
+ };
2484
2607
  function isRequired(register, fhirSchema, path) {
2485
2608
  const fieldName = path[path.length - 1];
2486
2609
  if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
@@ -2670,10 +2793,18 @@ function buildFieldType(register, fhirSchema, path, element, logger) {
2670
2793
  } else if (element.type) {
2671
2794
  const url = register.ensureSpecializationCanonicalUrl(element.type);
2672
2795
  const fieldFs = register.resolveFs(fhirSchema.package_meta, url);
2673
- if (!fieldFs)
2796
+ if (!fieldFs) {
2797
+ const pkgId = packageMetaToFhir(fhirSchema.package_meta);
2798
+ const fieldPath = path.join(".");
2799
+ const hint = fieldTypeResolutionHint(register, fhirSchema.package_meta, element.type);
2674
2800
  throw new Error(
2675
- `Could not resolve field type: <${fhirSchema.url}>.${path.join(".")}: <${element.type}> (pkg: '${packageMetaToFhir(fhirSchema.package_meta)}'))`
2801
+ `Could not resolve field type:
2802
+ package: ${pkgId}
2803
+ schema: ${fhirSchema.url}
2804
+ field: ${fieldPath}
2805
+ type: ${element.type}${hint}`
2676
2806
  );
2807
+ }
2677
2808
  return mkIdentifier(fieldFs);
2678
2809
  } else if (element.choices) {
2679
2810
  return void 0;
@@ -4311,7 +4442,7 @@ var tsCamelCase = (name) => {
4311
4442
  return camelCase(normalized);
4312
4443
  };
4313
4444
  var tsPackageDir = (name) => {
4314
- return kebabCase(name);
4445
+ return kebabCase(name.replace(/[@/]/g, "_"));
4315
4446
  };
4316
4447
  var tsModuleName = (id) => {
4317
4448
  return uppercaseFirstLetter(tsResourceName(id));
@@ -4408,8 +4539,12 @@ var tsEnumType = (enumDef) => {
4408
4539
  };
4409
4540
  var rewriteFieldTypeDefs = {
4410
4541
  Coding: { code: () => "T" },
4411
- // biome-ignore lint: that is exactly string what we want
4412
- Reference: { reference: () => "`${T}/${string}`" },
4542
+ Reference: {
4543
+ reference: () => (
4544
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: emitted as a TS template literal type, the placeholders are intentional
4545
+ "`${T}/${string}` | `http://${string}` | `https://${string}` | `urn:uuid:${string}` | `urn:oid:${string}` | `#${string}`"
4546
+ )
4547
+ },
4413
4548
  CodeableConcept: { coding: () => "Coding<T>" }
4414
4549
  };
4415
4550
  var resolveFieldTsType = (schemaName, tsName, field, resolveRef, genericFieldMap, isFamilyType) => {
@@ -5391,6 +5526,20 @@ var generateFactoryMethods = (w, tsIndex, flatProfile, factoryInfo) => {
5391
5526
  w.lineSM("return profile");
5392
5527
  });
5393
5528
  w.line();
5529
+ const canEmitIs = hasMeta && isResourceIdentifier(flatProfile.base) || flatProfile.base.name === "Extension";
5530
+ if (canEmitIs) {
5531
+ w.curlyBlock(["static", "is", "(resource: unknown)", `: resource is ${tsBaseResourceName}`], () => {
5532
+ w.line(`if (typeof resource !== "object" || resource === null) return false;`);
5533
+ if (hasMeta && isResourceIdentifier(flatProfile.base)) {
5534
+ w.line(`const r = resource as { resourceType?: string; meta?: { profile?: string[] } };`);
5535
+ w.line(`if (r.resourceType !== ${JSON.stringify(flatProfile.base.name)}) return false;`);
5536
+ w.lineSM(`return (r.meta?.profile ?? []).includes(${profileClassName}.canonicalUrl)`);
5537
+ } else {
5538
+ w.lineSM(`return (resource as { url?: string }).url === ${profileClassName}.canonicalUrl`);
5539
+ }
5540
+ });
5541
+ w.line();
5542
+ }
5394
5543
  w.curlyBlock(["static", "apply", `(resource: ${tsBaseResourceName})`, `: ${profileClassName}`], () => {
5395
5544
  if (hasMeta) {
5396
5545
  w.lineSM(`ensureProfile(resource, ${profileClassName}.canonicalUrl)`);
@@ -5732,6 +5881,8 @@ var resolveTsAssets = (fn) => {
5732
5881
  }
5733
5882
  return Path5.resolve(__dirname, "../../../..", "assets", "api", "writer-generator", "typescript", fn);
5734
5883
  };
5884
+ var leafOf2 = (path) => path[path.length - 1] ?? "";
5885
+ var TS_HARDCODED_GENERIC_NAMES = /* @__PURE__ */ new Set(["Reference", "Coding", "CodeableConcept"]);
5735
5886
  var TypeScript = class extends Writer {
5736
5887
  constructor(options) {
5737
5888
  super({ lineWidth: 120, ...options, resolveAssets: options.resolveAssets ?? resolveTsAssets });
@@ -5855,33 +6006,36 @@ var TypeScript = class extends Writer {
5855
6006
  generateType(tsIndex, schema, isFamilyType) {
5856
6007
  let name;
5857
6008
  const genericTypes = ["Reference", "Coding", "CodeableConcept"];
5858
- if (genericTypes.includes(schema.identifier.name)) {
6009
+ const isHardcodedGeneric = genericTypes.includes(schema.identifier.name);
6010
+ if (isHardcodedGeneric) {
5859
6011
  name = `${schema.identifier.name}<T extends string = string>`;
5860
6012
  } else {
5861
6013
  name = tsResourceName(schema.identifier);
5862
6014
  }
5863
- const typeFamilyFields = [];
5864
- for (const [fieldName, field] of Object.entries(schema.fields ?? {})) {
5865
- if (isChoiceDeclarationField(field) || !field.type) continue;
5866
- const fieldTypeSchema = tsIndex.resolveType(field.type);
5867
- if (isSpecializationTypeSchema(fieldTypeSchema) && (fieldTypeSchema.typeFamily?.resources?.length ?? 0) > 0) {
5868
- typeFamilyFields.push({ fieldName: tsFieldName(fieldName), familyTypeName: field.type.name });
6015
+ const params = isHardcodedGeneric ? [] : schema.generic?.params ?? [];
6016
+ const fieldMap = {};
6017
+ const nestedArgsByField = {};
6018
+ if (!isHardcodedGeneric) {
6019
+ for (const [fieldName, field] of Object.entries(schema.fields ?? {})) {
6020
+ if (isChoiceDeclarationField(field) || !field.type) continue;
6021
+ const target = tsIndex.resolveType(field.type);
6022
+ if (!target || TS_HARDCODED_GENERIC_NAMES.has(target.identifier.name)) continue;
6023
+ const tsName = tsFieldName(fieldName);
6024
+ const targetParams = isNestedTypeSchema(target) || isSpecializationTypeSchema(target) ? target.generic?.params : void 0;
6025
+ if (targetParams?.length) {
6026
+ const args = targetParams.map(
6027
+ (tp) => params.find((q) => leafOf2(q.path) === leafOf2(tp.path))?.typeVar ?? tp.typeVar
6028
+ );
6029
+ nestedArgsByField[tsName] = `<${args.join(", ")}>`;
6030
+ } else if (isSpecializationTypeSchema(target) && (target.typeFamily?.resources?.length ?? 0) > 0) {
6031
+ const p = params.find((q) => leafOf2(q.path) === fieldName);
6032
+ if (p) fieldMap[tsName] = p.typeVar;
6033
+ }
5869
6034
  }
5870
6035
  }
5871
- const genericFieldMap = {};
5872
- if (!genericTypes.includes(schema.identifier.name) && typeFamilyFields.length > 0) {
5873
- const [first, ...rest] = typeFamilyFields;
5874
- if (first && rest.length === 0) {
5875
- genericFieldMap[first.fieldName] = "T";
5876
- name += `<T extends ${first.familyTypeName} = ${first.familyTypeName}>`;
5877
- } else {
5878
- const params = typeFamilyFields.map((tf) => {
5879
- const paramName = `T${uppercaseFirstLetter(tf.fieldName)}`;
5880
- genericFieldMap[tf.fieldName] = paramName;
5881
- return `${paramName} extends ${tf.familyTypeName} = ${tf.familyTypeName}`;
5882
- });
5883
- name += `<${params.join(", ")}>`;
5884
- }
6036
+ if (!isHardcodedGeneric && params.length > 0) {
6037
+ const declParams = params.map((p) => `${p.typeVar} extends ${p.constraint.name} = ${p.constraint.name}`);
6038
+ name += `<${declParams.join(", ")}>`;
5885
6039
  }
5886
6040
  let extendsClause;
5887
6041
  if (schema.base) extendsClause = `extends ${tsNameFromCanonical(schema.base.url)}`;
@@ -5911,12 +6065,13 @@ var TypeScript = class extends Writer {
5911
6065
  tsName,
5912
6066
  field,
5913
6067
  void 0,
5914
- genericFieldMap,
6068
+ fieldMap,
5915
6069
  isFamilyType
5916
6070
  );
5917
6071
  const optionalSymbol = field.required ? "" : "?";
5918
6072
  const arraySymbol = field.array ? "[]" : "";
5919
- this.lineSM(`${tsName}${optionalSymbol}: ${tsType}${arraySymbol}`);
6073
+ const nestedArgs = nestedArgsByField[tsName] ?? "";
6074
+ this.lineSM(`${tsName}${optionalSymbol}: ${tsType}${nestedArgs}${arraySymbol}`);
5920
6075
  if (this.withPrimitiveTypeExtension(schema)) {
5921
6076
  if (isPrimitiveIdentifier(field.type)) {
5922
6077
  this.addFieldExtension(fieldName, field.array ?? false);
@@ -5944,11 +6099,10 @@ var TypeScript = class extends Writer {
5944
6099
  });
5945
6100
  }
5946
6101
  generateNestedTypes(tsIndex, schema, isFamilyType) {
5947
- if (schema.nested) {
5948
- for (const subtype of schema.nested) {
5949
- this.generateType(tsIndex, subtype, isFamilyType);
5950
- this.line();
5951
- }
6102
+ if (!schema.nested) return;
6103
+ for (const subtype of schema.nested) {
6104
+ this.generateType(tsIndex, subtype, isFamilyType);
6105
+ this.line();
5952
6106
  }
5953
6107
  }
5954
6108
  generateResourceModule(tsIndex, schema) {
@@ -6013,19 +6167,54 @@ function countLinesByMatches(text) {
6013
6167
  const m = text.match(/\n/g);
6014
6168
  return m ? m.length + 1 : 1;
6015
6169
  }
6016
- var prettyReport = (report) => {
6170
+ var formatLoc = (loc) => {
6171
+ if (loc >= 1e4) return `${Math.round(loc / 1e3)} kloc`;
6172
+ if (loc >= 1e3) return `${(loc / 1e3).toFixed(1)} kloc`;
6173
+ return `${loc} loc`;
6174
+ };
6175
+ var prettyReport = (report, options = {}) => {
6017
6176
  const { success, filesGenerated, errors, warnings, duration } = report;
6177
+ const fileLimit = options.fileLimit ?? 20;
6018
6178
  const errorsStr = errors.length > 0 ? `Errors: ${errors.join(", ")}` : void 0;
6019
6179
  const warningsStr = warnings.length > 0 ? `Warnings: ${warnings.join(", ")}` : void 0;
6020
- let allLoc = 0;
6021
- const files = Object.entries(filesGenerated).map(([path, content]) => {
6022
- const loc = countLinesByMatches(content);
6023
- allLoc += loc;
6024
- return ` - ${path} (${loc} loc)`;
6025
- }).join("\n");
6180
+ let totalFiles = 0;
6181
+ let totalLoc = 0;
6182
+ const aggregateByDir = (files) => {
6183
+ const byDir = {};
6184
+ for (const [p, loc] of Object.entries(files)) {
6185
+ const dir = Path5.dirname(p);
6186
+ byDir[dir] ??= { count: 0, loc: 0 };
6187
+ byDir[dir].count += 1;
6188
+ byDir[dir].loc += loc;
6189
+ }
6190
+ return Object.entries(byDir).map(([dir, v]) => ({ dir, count: v.count, loc: v.loc })).sort((a, b) => a.dir.localeCompare(b.dir));
6191
+ };
6192
+ const groupStrs = Object.entries(filesGenerated).map(([name, files]) => {
6193
+ const locByPath = {};
6194
+ let groupLoc = 0;
6195
+ for (const [path, content] of Object.entries(files)) {
6196
+ const loc = countLinesByMatches(content);
6197
+ locByPath[path] = loc;
6198
+ groupLoc += loc;
6199
+ }
6200
+ const count = Object.keys(files).length;
6201
+ totalFiles += count;
6202
+ totalLoc += groupLoc;
6203
+ const header = ` ${name} (${count} files, ${formatLoc(groupLoc)}):`;
6204
+ if (count === 0) return header;
6205
+ if (count > fileLimit) {
6206
+ const dirs = aggregateByDir(locByPath);
6207
+ const dirLines = dirs.map((d) => ` - ${d.dir}/ (${d.count} files, ${formatLoc(d.loc)})`).join("\n");
6208
+ return `${header}
6209
+ ${dirLines}`;
6210
+ }
6211
+ const fileLines = Object.entries(locByPath).map(([p, loc]) => ` - ${p} (${loc} loc)`).join("\n");
6212
+ return `${header}
6213
+ ${fileLines}`;
6214
+ });
6026
6215
  return [
6027
- `Generated files (${Math.round(allLoc / 1e3)} kloc):`,
6028
- files,
6216
+ `Generated files (${totalFiles} files, ${formatLoc(totalLoc)}):`,
6217
+ ...groupStrs,
6029
6218
  errorsStr,
6030
6219
  warningsStr,
6031
6220
  `Duration: ${Math.round(duration)}ms`,
@@ -6322,7 +6511,8 @@ var APIBuilder = class {
6322
6511
  await this.executeGenerators(result, tsIndex);
6323
6512
  this.logger.info("Generation completed successfully");
6324
6513
  result.success = result.errors.length === 0;
6325
- this.logger.debug(`Generation completed: ${result.filesGenerated.length} files`);
6514
+ const totalFiles = Object.values(result.filesGenerated).reduce((n, f) => n + Object.keys(f).length, 0);
6515
+ this.logger.debug(`Generation completed: ${totalFiles} files`);
6326
6516
  } catch (error) {
6327
6517
  this.logger.error(`Code generation failed: ${error instanceof Error ? error.message : String(error)}`);
6328
6518
  result.errors.push(error instanceof Error ? error.message : String(error));
@@ -6353,8 +6543,9 @@ var APIBuilder = class {
6353
6543
  try {
6354
6544
  await gen.writer.generateAsync(tsIndex);
6355
6545
  const fileBuffer = gen.writer.writtenFiles();
6546
+ const files = result.filesGenerated[gen.name] ??= {};
6356
6547
  fileBuffer.forEach((buf) => {
6357
- result.filesGenerated[buf.relPath] = buf.content;
6548
+ files[buf.relPath] = buf.content;
6358
6549
  });
6359
6550
  this.logger.info(`Generating ${gen.name} finished successfully`);
6360
6551
  } catch (error) {