@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 +11 -5
- package/dist/index.d.ts +8 -3
- package/dist/index.js +235 -44
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|
-
|
|
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:`),
|
|
6
|
-
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};var _=k({prefix:"cli"});async function
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
4412
|
-
|
|
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
|
-
|
|
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
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
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
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
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
|
-
|
|
6068
|
+
fieldMap,
|
|
5915
6069
|
isFamilyType
|
|
5916
6070
|
);
|
|
5917
6071
|
const optionalSymbol = field.required ? "" : "?";
|
|
5918
6072
|
const arraySymbol = field.array ? "[]" : "";
|
|
5919
|
-
|
|
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
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
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
|
|
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
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
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 (${
|
|
6028
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6548
|
+
files[buf.relPath] = buf.content;
|
|
6358
6549
|
});
|
|
6359
6550
|
this.logger.info(`Generating ${gen.name} finished successfully`);
|
|
6360
6551
|
} catch (error) {
|