@atomic-ehr/codegen 0.0.7-canary.20260224101452.ccac84d → 0.0.7
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 +7 -7
- package/dist/index.js +28 -5
- package/dist/index.js.map +1 -1
- package/package.json +4 -7
package/dist/cli/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import S from'picocolors';import Ze from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import {createHash}from'crypto';import Te from'assert';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as ge from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var D=class e{options;dryWarnSet=new Set;constructor(t={}){this.options={timestamp:false,level:1,...t};}shouldLog(t){let o=this.options.level??1;return t>=o}static consoleLevelsMap={1:console.log,2:console.warn,3:console.error,0:console.log,4:()=>{}};formatMessage(t,o,i){let n=this.options.timestamp?`${S.gray(new Date().toLocaleTimeString())} `:"",r=this.options.prefix?`${S.cyan(`[${this.options.prefix}]`)} `:"";return `${n}${i(t)} ${r}${o}`}isSuppressed(t){return this.options.suppressLoggingLevel==="all"||this.options.suppressLoggingLevel?.includes(t)||false}tryWriteToConsole(t,o){if(this.isSuppressed(t)||!this.shouldLog(t))return;(e.consoleLevelsMap[t]||console.log)(o);}success(t){this.tryWriteToConsole(1,this.formatMessage("",t,S.green));}error(t,o){if(this.isSuppressed(3)||!this.shouldLog(3))return;console.error(this.formatMessage("X",t,S.red));let i=this.options.level===0;o&&i&&(console.error(S.red(` ${o.message}`)),o.stack&&console.error(S.gray(o.stack)));}warn(t){this.tryWriteToConsole(2,this.formatMessage("!",t,S.yellow));}dryWarn(t){this.dryWarnSet.has(t)||(this.warn(t),this.dryWarnSet.add(t));}info(t){this.tryWriteToConsole(1,this.formatMessage("i",t,S.blue));}debug(t){this.shouldLog(0)&&this.tryWriteToConsole(0,this.formatMessage("\u{1F41B}",t,S.magenta));}step(t){this.tryWriteToConsole(1,this.formatMessage("\u{1F680}",t,S.cyan));}progress(t){this.tryWriteToConsole(1,this.formatMessage("\u23F3",t,S.blue));}plain(t,o=i=>i){let i=this.options.timestamp?`${S.gray(new Date().toLocaleTimeString())} `:"",n=this.options.prefix?`${S.cyan(`[${this.options.prefix}]`)} `:"";this.tryWriteToConsole(1,`${i}${n}${o(t)}`);}dim(t){this.plain(t,S.gray);}child(t){return new e({...this.options,prefix:this.options.prefix?`${this.options.prefix}:${t}`:t})}configure(t){this.options={...this.options,...t};}getLevel(){return this.options.level??1}setLevel(t){this.options.level=t;}},v=new D;function Ce(e){v.success(e);}function C(e,t){v.error(e,t);}function H(e){v.info(e);}function ke(e){v.dim(e);}function K(e){v.configure(e);}function J(e={}){return new D(e)}function Q(e){console.log(),console.log(S.cyan(S.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));}function X(e,t,o){let i=e;t&&(i+=` ${S.gray(`(${t}ms)`)}`),Ce(i),o&&Object.entries(o).forEach(([n,r])=>{ke(` ${n}: ${r}`);});}function k(e,t="\u2022"){e.forEach(o=>{console.log(S.gray(` ${t} ${o}`));});}var F="Use CodeableReference which is not provided by FHIR R4.",be="Use Availability which is not provided by FHIR R4.",O={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":be,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":F,"http://hl7.org/fhir/StructureDefinition/specimen-additive":F,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":F,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":F,"http://hl7.org/fhir/StructureDefinition/workflow-reason":F},"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 b(e,t){let o=`${e.name}#${e.version}`,i=O[o]?.[t];if(i)return {shouldSkip:true,reason:i};let n=O[e.name]?.[t];return n?{shouldSkip:true,reason:n}:{shouldSkip:false}}var x=e=>`${e.name}#${e.version}`,Y=e=>`${e.name}@${e.version}`;var Z=e=>{let t=JSON.stringify(e);return createHash("sha256").update(t).digest("hex").slice(0,16)},ee=(e,t)=>({...e,package_meta:e.package_meta||t,name:e.name,url:e.url,base:e.base});var te=e=>e?.kind==="nested",ne=e=>e?.kind==="profile";var ie=(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 M(e){let t=e.split("|")[0];return t||e}function ve(e){return e.split("|")[1]}function Fe(e){return e.derivation==="constraint"?"profile":e.kind==="primitive-type"?"primitive-type":e.kind==="complex-type"?"complex-type":e.kind==="resource"?"resource":e.kind==="logical"?"logical":"resource"}function I(e){return {kind:Fe(e),package:e.package_meta.name,version:e.package_meta.version,name:e.name,url:e.url}}var Ee=e=>{let t=e.split("/"),o=t[t.length-1];return o&&o.length>0?o.split(/[-_]/).map(i=>i.charAt(0).toUpperCase()+i.slice(1).toLowerCase()).join(""):e};function L(e,t,o){let i=M(o),n=Ee(i),r={package_meta:{name:"missing_valuesets",version:ve(i)||"0.0.0"},id:o},s=e.resolveVs(t,i)||r,c=s?.id&&!/^[a-zA-Z0-9_-]{20,}$/.test(s.id)?s.id:n;return {kind:"value-set",package:s.package_meta.name,version:s.package_meta.version,name:c,url:i}}function P(e,t,o){let i=o.binding?.bindingName,n=t.join("."),[r,s,c]=i?[{name:"shared",version:"1.0.0"},i,`urn:fhir:binding:${i}`]:[e.package_meta,`${e.name}.${n}_binding`,`${e.url}#${n}_binding`];return {kind:"binding",package:r.name,version:r.version,name:s,url:c}}function B(e,t,o,i){let n=M(o)||o,r=e.resolveVs(t,n);if(r)return De(e,r)}function De(e,t,o){if(t.expansion?.contains)return t.expansion.contains.filter(n=>n.code!==void 0).map(n=>(Te(n.code),{code:n.code,display:n.display,system:n.system}));let i=[];if(t.compose?.include){for(let n of t.compose.include)if(n.concept)for(let r of n.concept)i.push({system:n.system,code:r.code,display:r.display});else if(n.system&&!n.filter)try{let r=e.resolveAny(n.system);if(r?.concept){let s=(c,a)=>{for(let l of c)i.push({system:a,code:l.code,display:l.display}),l.concept&&s(l.concept,a);};s(r.concept,n.system);}}catch{}}return i.length>0?i:void 0}var oe=100,j=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function _(e,t,o,i){if(!o.binding)return;let n=o.binding.strength,r=o.binding.valueSet;if(!r)return;if(!j.has(o.type??"")){i?.dryWarn(`eld-11: Binding on non-bindable type '${o.type}' (valueSet: ${r})`);return}if(!(n==="required"||n==="extensible"||n==="preferred"))return;let c=B(e,t.package_meta,r);if(!c||c.length===0)return;let a=c.map(l=>l.code).filter(l=>l&&typeof l=="string"&&l.trim().length>0);if(a.length>oe){i?.dryWarn(`Value set ${r} has ${a.length} which is more than ${oe} codes, which may cause issues with code generation.`);return}if(a.length!==0)return {isOpen:n!=="required",values:a}}function Le(e,t,o,i,n){if(!i.binding?.valueSet)return;let r=P(t,o,i),s=L(e,t.package_meta,i.binding.valueSet),c=_(e,t,i,n);return {identifier:r,valueset:s,strength:i.binding.strength,enum:c,dependencies:[s]}}function re(e,t,o){let i=new Set;if(!t.elements)return [];let n=[];function r(a,l){for(let[u,m]of Object.entries(a)){let h=[...l,u],p=h.join("."),d=e.resolveElementSnapshot(t,h);if(!i.has(p)){if(i.add(p),d.binding){let f=Le(e,t,h,d,o);f&&n.push(f);}m.elements&&r(m.elements,h);}}}r(t.elements,[]),n.sort((a,l)=>a.identifier.name.localeCompare(l.identifier.name));let s=[],c=new Set;for(let a of n)c.has(a.identifier.url)||(c.add(a.identifier.url),s.push(a));return s}function N(e,t,o,i){let n={};if(t.derivation==="constraint"){let m=e.resolveFsSpecializations(t.package_meta,t.url).map(h=>A(e,h,i)).filter(h=>h!==void 0).flat();for(let h of m.reverse())n[h.identifier.name]=h.identifier.url;}let r=o.join("."),s=n[r]??`${t.url}#${r}`,c=s.split("#")[0],l=e.resolveFs(t.package_meta,c)?.package_meta??t.package_meta;return {kind:"nested",package:l.name,version:l.version,name:r,url:s}}function se(e,t,o){let i=[];for(let[n,r]of Object.entries(o)){let s=[...t,n];E(r)&&i.push([s,r]),r.elements&&i.push(...se(e,s,r.elements));}return i}function Pe(e,t,o,i,n){let r={};for(let[s,c]of Object.entries(i)){let a=[...o,s],l=e.resolveElementSnapshot(t,a);E(l)?r[s]=U(e,t,a,l,n):r[s]=w(e,t,a,l,n);}return r}function A(e,t,o){if(!t.elements)return;let i=se(t,[],t.elements).filter(([r,s])=>s.elements&&Object.keys(s.elements).length>0),n=[];for(let[r,s]of i){let c=N(e,t,r,o),a;s.type==="BackboneElement"||!s.type?a="BackboneElement":a=s.type;let l=e.ensureSpecializationCanonicalUrl(a),u=e.resolveFs(t.package_meta,l);if(!u)throw new Error(`Could not resolve base type ${a}`);let m={kind:"complex-type",package:u.package_meta.name,version:u.package_meta.version,name:a,url:l},h=Pe(e,t,r,s.elements??{},o),p={identifier:c,base:m,fields:h};n.push(p);}return n.sort((r,s)=>r.identifier.url.localeCompare(s.identifier.url)),n.length===0?void 0:n}function ae(e){let t=[];for(let o of e){o.base&&t.push(o.base);for(let i of Object.values(o.fields||{}))"type"in i&&i.type&&t.push(i.type),"binding"in i&&i.binding&&t.push(i.binding);}return t}function ce(e,t,o){let i=o[o.length-1];if(!i)throw new Error(`Internal error: fieldName is missing for path ${o.join("/")}`);let n=o.slice(0,-1),r=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(s=>{if(n.length===0)return s.required||[];if(!s.elements)return [];let c=s;for(let a of n)c=c?.elements?.[a];return c?.required||[]});return new Set(r).has(i)}function le(e,t,o){let i=o[o.length-1];if(!i)throw new Error(`Internal error: fieldName is missing for path ${o.join("/")}`);let n=o.slice(0,-1),r=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(s=>{if(n.length===0)return s.excluded||[];if(!s.elements)return [];let c=s;for(let a of n)c=c?.elements?.[a];return c?.excluded||[]});return new Set(r).has(i)}var Ne=(e,t,o)=>{if(o.refers)return o.refers.map(i=>{let n=e.ensureSpecializationCanonicalUrl(i),r=e.resolveFs(t.package_meta,n);if(!r)throw new Error(`Failed to resolve fs for ${n}`);return I(r)})},we=e=>{let t=new Set,o=new Set;if(e.required)for(let i of e.required)t.add(i);if(e.excluded)for(let i of e.excluded)o.add(i);if(e.elements)for(let[i,n]of Object.entries(e.elements))n.min!==void 0&&n.min>0&&t.add(i);return {required:t.size>0?Array.from(t):void 0,excluded:o.size>0?Array.from(o):void 0}},pe=e=>{let t=e.slicing;if(!t)return;let o={};for(let[i,n]of Object.entries(t.slices??{})){if(!n)continue;let{required:r,excluded:s}=n.schema?we(n.schema):{};o[i]={min:n.min,max:n.max,match:n.match,required:r,excluded:s};}return {discriminator:t.discriminator,rules:t.rules,ordered:t.ordered,slices:Object.keys(o).length>0?o:void 0}};function $(e,t,o,i,n){if(i.elementReference){let r=i.elementReference.slice(1).filter((s,c)=>c%2===1);return N(e,t,r,n)}else if(i.type){let r=e.ensureSpecializationCanonicalUrl(i.type),s=e.resolveFs(t.package_meta,r);if(!s)throw new Error(`Could not resolve field type: <${t.url}>.${o.join(".")}: <${i.type}> (pkg: '${x(t.package_meta)}'))`);return I(s)}else {if(i.choices)return;if(t.derivation==="constraint")return;n?.dryWarn(`Can't recognize element type: <${t.url}>.${o.join(".")} (pkg: '${x(t.package_meta)}'): missing type info`);return}}var w=(e,t,o,i,n)=>{let r,s;i.binding&&(r=P(t,o,i),j.has(i.type??"")&&(s=_(e,t,i,n)));let c=$(e,t,o,i,n);return c||n?.dryWarn(`Field type not found for '${t.url}#${o.join(".")}' (${t.derivation})`),{type:c,required:ce(e,t,o),excluded:le(e,t,o),reference:Ne(e,t,i),array:i.array||false,min:i.min,max:i.max,slicing:pe(i),choices:i.choices,choiceOf:i.choiceOf,binding:r,enum:s}};function E(e){let t=e.type==="BackboneElement",o=e.type==="Element"&&e.elements!==void 0&&Object.keys(e.elements).length>0,i=e.type===void 0&&e.choiceOf===void 0&&e.elements!==void 0&&Object.keys(e.elements).length>0;return t||o||i}function U(e,t,o,i,n){return {type:N(e,t,o,n),array:i.array||false,required:ce(e,t,o),excluded:le(e,t,o),slicing:pe(i)}}function Ue(e,t,o,i,n){if(!i)return;let r={};for(let s of e.getAllElementKeys(i)){let c=[...o,s],a=e.resolveElementSnapshot(t,c),l=a.type?e.ensureSpecializationCanonicalUrl(a.type):void 0;if(l&&b(t.package_meta,l).shouldSkip){n?.warn(`Skipping field ${c} for ${l} due to skip hack ${b(t.package_meta,l).reason}`);continue}E(a)?r[s]=U(e,t,c,a,n):r[s]=w(e,t,c,a,n);}return r}function $e(e){let t=[];for(let o of Object.values(e))"type"in o&&o.type&&t.push(o.type),"binding"in o&&o.binding&&t.push(o.binding);return t}async function de(e,t,o){if(!t.url)throw new Error("ValueSet URL is required");let i=L(e,t.package_meta,t.url),n=B(e,t.package_meta,t.url);return {identifier:i,description:t.description,concept:n,compose:n?void 0:t.compose}}function Ve(e,t,o,i){let n=[];t&&n.push(t),o&&n.push(...$e(o)),i&&n.push(...ae(i));let r={};for(let a of n)a.url!==e.url&&(r[a.url]=a);let s=new Set(i?.map(a=>a.identifier.url)),c=Object.values(r).filter(a=>ne(e)||!te(a)?true:!s.has(a.url)).sort((a,l)=>a.url.localeCompare(l.url));return c.length>0?c:void 0}function He(e,t,o){let i=I(t),n;if(t.base&&t.type!=="Element"){let p=e.resolveFs(t.package_meta,e.ensureSpecializationCanonicalUrl(t.base));if(!p)throw new Error(`Base resource not found '${t.base}' for <${t.url}> from ${x(t.package_meta)}`);n=I(p);}let r=Ue(e,t,[],t.elements,o),s=A(e,t,o),c=t.derivation==="constraint"?_e(e,t,o):void 0,a=Ve(i,n,r,s),l=c?.flatMap(p=>p.valueTypes??[])??[],u=(()=>{if(!a&&l.length===0)return a;let p={};for(let d of a??[])p[d.url]=d;for(let d of l)p[d.url]=d;return Object.values(p)})(),m={identifier:i,base:n,fields:r,nested:s,description:t.description,dependencies:u,...c&&c.length>0?{extensions:c}:{}},h=re(e,t,o);return [m,...h]}function Oe(e,t,o,i){let n=e.resolveFs(t.package_meta,o);if(!n?.elements)return;let r=[];for(let[c,a]of Object.entries(n.elements)){if(a.choiceOf!=="value"&&!c.startsWith("value"))continue;let l=$(e,n,[c],a,i);l&&r.push(l);}if(r.length===0)return;let s=new Map(r.map(c=>[c.url,c]));return Array.from(s.values())}var Me=(e,t,o)=>{let i=[];if(!t.elements)return i;for(let[n,r]of Object.entries(t.elements)){if(!n.startsWith("extension:"))continue;let s=n.split(":")[1];if(!s)continue;let c;for(let[a,l]of Object.entries(r.elements??{}))if(!(l.choiceOf!=="value"&&!a.startsWith("value"))&&(c=$(e,t,[n,a],l,o),c))break;i.push({name:s,url:r.url??s,valueType:c,min:r.min,max:r.max!==void 0?String(r.max):void 0});}return i},Be=e=>{let t=[],i=e.elements?.extension?.slicing?.slices;if(!i||typeof i!="object")return t;for(let[n,r]of Object.entries(i)){let s=r,c=s.schema;if(!c)continue;let a;for(let[l,u]of Object.entries(c.elements??{})){let m=u;if(!(m.choiceOf!=="value"&&!l.startsWith("value"))&&m.type){a={kind:"complex-type",package:e.package_meta.name,version:e.package_meta.version,name:m.type,url:`http://hl7.org/fhir/StructureDefinition/${m.type}`};break}}t.push({name:n,url:s.match?.url??n,valueType:a,min:c._required?1:c.min??0,max:c.max!==void 0?String(c.max):c.array?"*":"1"});}return t},je=(e,t,o,i)=>{let n=e.resolveFs(t.package_meta,o);if(!n?.elements)return;let r=Me(e,n,i),s=Be(n),c=[...r,...s];return c.length>0?c:void 0};function _e(e,t,o){let i=[],n=(s,c,a)=>{let l=a.url,u=l?Oe(e,t,l,o):void 0,m=l?je(e,t,l,o):void 0,h=m!==void 0&&m.length>0;i.push({name:c,path:[...s,"extension"].join("."),url:l,min:a.min,max:a.max!==void 0?String(a.max):void 0,mustSupport:a.mustSupport,valueTypes:u,subExtensions:m,isComplex:h});},r=(s,c)=>{if(c.extensions)for(let[a,l]of Object.entries(c.extensions))n(s,a,l);if(c.elements)for(let[a,l]of Object.entries(c.elements))r([...s,a],l);};if(t.extensions)for(let[s,c]of Object.entries(t.extensions))n([],s,c);if(t.elements)for(let[s,c]of Object.entries(t.elements))r([s],c);return i}async function ue(e,t,o){return He(e,t,o)}var Ae=(e,t)=>{let o={};for(let r of e){let s=`${r.schema.identifier.url}|${r.schema.identifier.package}`,c=Z(r.schema);o[s]??={},o[s][c]??={typeSchema:r.schema,sources:[]},o[s][c].sources.push(r);}let i=[],n={};for(let r of Object.values(o)){let s=Object.values(r).sort((a,l)=>l.sources.length-a.sources.length),c=s[0];if(c&&(i.push(c.typeSchema),s.length>1)){let a=c.typeSchema.identifier.package,l=c.typeSchema.identifier.url;t?.dryWarn(`'${l}' from '${a}'' has ${s.length} versions`),n[a]??={},n[a][l]=s.flatMap(u=>u.sources.map(m=>({typeSchema:u.typeSchema,sourcePackage:m.sourcePackage,sourceCanonical:m.sourceCanonical})));}}return {schemas:i,collisions:n}},me=async(e,t)=>{let o=[];for(let i of e.allFs()){let n=x(i.package_meta),r=b(i.package_meta,i.url);if(r.shouldSkip){t?.dryWarn(`Skip ${i.url} from ${n}. Reason: ${r.reason}`);continue}for(let s of await ue(e,i,t))o.push({schema:s,sourcePackage:n,sourceCanonical:i.url});}for(let i of e.allVs())o.push({schema:await de(e,i),sourcePackage:x(i.package_meta),sourceCanonical:i.url});return Ae(o,t)};var G=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var V=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var We=async(e,t)=>{let o=await e.packageJson(t.name);if(!o)return [];let i=o.dependencies;return i!==void 0?Object.entries(i).map(([n,r])=>({name:n,version:r})):[]},he=e=>({pkg:e,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),ye=async(e,t,o,i,n)=>{let r=x(t);if(n?.info(`${" ".repeat(o*2)}+ ${r}`),i[r])return i[r];let s=he(t);for(let a of await e.search({package:t})){let l=a.url;if(!l||!(isStructureDefinition(a)||V(a)||G(a)))continue;let u=l;s.canonicalResolution[u]&&n?.dryWarn(`Duplicate canonical URL: ${u} at ${r}.`),s.canonicalResolution[u]=[{deep:o,pkg:t,pkgId:r,resource:a}];}let c=await We(e,t);for(let a of c){let{canonicalResolution:l}=await ye(e,a,o+1,i,n);for(let[u,m]of Object.entries(l)){let h=u;s.canonicalResolution[h]=[...s.canonicalResolution[h]||[],...m];}}for(let a of Object.values(s.canonicalResolution))a.sort((l,u)=>l.deep-u.deep);return i[r]=s,s},fe=(e,t)=>{for(let{pkg:o,canonicalResolution:i}of Object.values(e)){let n=x(o);if(!e[n])throw new Error(`Package ${n} not found`);for(let[s,c]of Object.entries(i)){let a=c[0];if(!a)throw new Error("Resource not found");let l=a.resource,u=a.pkg;if(isStructureDefinition(l)){let m=ge.translate(l),h=ee(m,u);e[n].fhirSchemas[h.url]=h;}if(V(l)){let m=ie(l,u);e[n].valueSets[m.url]=m;}}}},qe=(e,t,o)=>{let i=Object.values(e).flatMap(n=>n.canonicalResolution[t]);if(!i)throw new Error(`No canonical resolution found for ${t} in any package`);return i[0]?.resource},ze=async(e,{logger:t,focusedPackages:o})=>{let i=o??await e.packages(),n={};for(let p of i)await ye(e,p,0,n,t);fe(n);let r=(p,d)=>{let f=n[x(p)];if(f){let g=f.canonicalResolution[d]?.[0];if(g)return n[g.pkgId]?.fhirSchemas[d]}for(let g of Object.values(n)){let y=g.fhirSchemas[d];if(y&&y.package_meta.name===p.name)return y}for(let g of Object.values(n)){let y=g.fhirSchemas[d];if(y)return y}},s=(p,d)=>{let f=n[x(p)];if(f){let g=f.canonicalResolution[d]?.[0];if(g)return n[g.pkgId]?.valueSets[d]}for(let g of Object.values(n)){let y=g.valueSets[d];if(y&&y.package_meta.name===p.name)return y}for(let g of Object.values(n)){let y=g.valueSets[d];if(y)return y}},c=p=>(p.includes("|")&&(p=p.split("|")[0]),p.match(/^[a-zA-Z0-9]+$/)?`http://hl7.org/fhir/StructureDefinition/${p}`:p),a=(p,d)=>{let f=r(p,d);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${d}'`);let g=[f];for(;f?.base;){let y=f.package_meta,R=c(f.base);if(f=r(y,R),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${d}'. Problem: '${R}' from '${x(y)}'`);g.push(f);}return g},l=(p,d)=>a(p,d).filter(f=>f.derivation==="specialization"),u=(p,d)=>{let f=a(p.package_meta,p.url),g=Ke(f,d);return Je(g)},m=p=>{let d=new Set;for(let[f,g]of Object.entries(p)){d.add(f);for(let y of g?.choices||[])p[y]||d.add(y);}return Array.from(d)},h;return {testAppendFs(p){let d=x(p.package_meta);n[d]||(n[d]=he(p.package_meta)),n[d].fhirSchemas[p.url]=p,h=void 0;},resolveFs:r,resolveFsGenealogy:a,resolveFsSpecializations:l,ensureSpecializationCanonicalUrl:c,resolveSd:(p,d)=>{let f=n[x(p)]?.canonicalResolution[d]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(n).flatMap(p=>Object.values(p.canonicalResolution).flatMap(d=>d.map(f=>{let g=f.resource;return g.package_name?g:{...g,package_name:p.pkg.name,package_version:p.pkg.version}}))).filter(p=>isStructureDefinition(p)).sort((p,d)=>p.url.localeCompare(d.url)),patchSd:p=>{Object.values(n).flatMap(d=>Object.values(d.canonicalResolution).forEach(f=>{f.forEach(g=>{if(isStructureDefinition(g.resource)){let y=g.resource,R=p(d.pkg,y);if(y.url!==R.url)throw new Error(`Patch update StructureDefinition URL: ${y.url} !== ${R.url}`);g.resource=R;}});})),fe(n),h=void 0;},allFs:()=>Object.values(n).flatMap(p=>Object.values(p.fhirSchemas)),allVs:()=>Object.values(n).flatMap(p=>Object.values(p.valueSets)),resolveVs:s,resolveAny:p=>qe(n,p),resolveElementSnapshot:u,getAllElementKeys:m,resolver:n,resolutionTree:()=>{if(h)return h;let p={};for(let[d,f]of Object.entries(n)){let g=f.pkg.name;p[g]={};for(let[y,R]of Object.entries(f.canonicalResolution)){let q=y;p[g][q]=[];for(let z of R)p[g][q].push({deep:z.deep,pkg:z.pkg});}}return h=p,p}}},Se=async(e,t)=>{let o=e.map(Y);t?.logger?.step(`Loading FHIR packages: ${o.join(", ")}`);let i=CanonicalManager({packages:o,workingDir:"tmp/fhir",registry:t.registry||void 0});return await i.init(),await ze(i,{...t,focusedPackages:e})},Ke=(e,t)=>{let[o,...i]=t;return o===void 0?[]:e.map(n=>{if(!n.elements)return;let r=n.elements?.[o];for(let s of i)r=r?.elements?.[s];return r}).filter(n=>n!==void 0)};function Je(e){let t=e.reverse(),o=Object.assign({},...t);return o.elements=void 0,o}var xe={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=J({prefix:"TypeSchema"});try{t.step("Generating TypeSchema from FHIR packages"),t.info(`Packages: ${e.packages.join(", ")}`),t.info(`Output: ${e.output}`);let o=e.singleFile?"ndjson":e.format;t.debug(`Format: ${o}${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 i=Date.now(),n=e.packages.map(u=>{if(u.includes("@")){let m=u.lastIndexOf("@");return {name:u.slice(0,m),version:u.slice(m+1)||"latest"}}return {name:u,version:"latest"}});t.progress(`Processing packages: ${n.map(u=>`${u.name}@${u.version}`).join(", ")}`);let r=await Se(n,{logger:t,registry:e.registry,focusedPackages:n}),{schemas:s}=await me(r,t);if(s.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 a;o==="json"?a=JSON.stringify(s,null,2):a=s.map(u=>JSON.stringify(u)).join(`
|
|
3
|
-
`),await writeFile(c,a,"utf-8");let l=Date.now()-i;if(X(`Generated ${s.length} TypeSchema definitions`,l,{schemas:s.length}),t.dim(`Output: ${c}`),e.verbose){t.debug("Generated schemas:");let u=s.map(m=>`${m.identifier?.name||"Unknown"} (${m.identifier?.kind||"unknown"})`);
|
|
2
|
+
import x from'picocolors';import et from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import {createHash}from'crypto';import Te from'assert';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as ge from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var D=class e{options;dryWarnSet=new Set;constructor(t={}){this.options={timestamp:false,level:1,...t};}shouldLog(t){let o=this.options.level??1;return t>=o}static consoleLevelsMap={1:console.log,2:console.warn,3:console.error,0:console.log,4:()=>{}};formatMessage(t,o,i){let n=this.options.timestamp?`${x.gray(new Date().toLocaleTimeString())} `:"",r=this.options.prefix?`${x.cyan(`[${this.options.prefix}]`)} `:"";return `${n}${i(t)} ${r}${o}`}isSuppressed(t){return this.options.suppressLoggingLevel==="all"||this.options.suppressLoggingLevel?.includes(t)||false}tryWriteToConsole(t,o){if(this.isSuppressed(t)||!this.shouldLog(t))return;(e.consoleLevelsMap[t]||console.log)(o);}success(t){this.tryWriteToConsole(1,this.formatMessage("",t,x.green));}error(t,o){if(this.isSuppressed(3)||!this.shouldLog(3))return;console.error(this.formatMessage("X",t,x.red));let i=this.options.level===0;o&&i&&(console.error(x.red(` ${o.message}`)),o.stack&&console.error(x.gray(o.stack)));}warn(t){this.tryWriteToConsole(2,this.formatMessage("!",t,x.yellow));}dryWarn(t){this.dryWarnSet.has(t)||(this.warn(t),this.dryWarnSet.add(t));}info(t){this.tryWriteToConsole(1,this.formatMessage("i",t,x.blue));}debug(t){this.shouldLog(0)&&this.tryWriteToConsole(0,this.formatMessage("\u{1F41B}",t,x.magenta));}step(t){this.tryWriteToConsole(1,this.formatMessage("\u{1F680}",t,x.cyan));}progress(t){this.tryWriteToConsole(1,this.formatMessage("\u23F3",t,x.blue));}plain(t,o=i=>i){let i=this.options.timestamp?`${x.gray(new Date().toLocaleTimeString())} `:"",n=this.options.prefix?`${x.cyan(`[${this.options.prefix}]`)} `:"";this.tryWriteToConsole(1,`${i}${n}${o(t)}`);}dim(t){this.plain(t,x.gray);}child(t){return new e({...this.options,prefix:this.options.prefix?`${this.options.prefix}:${t}`:t})}configure(t){this.options={...this.options,...t};}getLevel(){return this.options.level??1}setLevel(t){this.options.level=t;}},v=new D;function Ce(e){v.success(e);}function k(e,t){v.error(e,t);}function V(e){v.info(e);}function ke(e){v.dim(e);}function K(e){v.configure(e);}function J(e={}){return new D(e)}function Q(e){console.log(),console.log(x.cyan(x.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));}function X(e,t,o){let i=e;t&&(i+=` ${x.gray(`(${t}ms)`)}`),Ce(i),o&&Object.entries(o).forEach(([n,r])=>{ke(` ${n}: ${r}`);});}function b(e,t="\u2022"){e.forEach(o=>{console.log(x.gray(` ${t} ${o}`));});}var F="Use CodeableReference which is not provided by FHIR R4.",be="Use Availability which is not provided by FHIR R4.",O={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":be,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":F,"http://hl7.org/fhir/StructureDefinition/specimen-additive":F,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":F,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":F,"http://hl7.org/fhir/StructureDefinition/workflow-reason":F},"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 I(e,t){let o=`${e.name}#${e.version}`,i=O[o]?.[t];if(i)return {shouldSkip:true,reason:i};let n=O[e.name]?.[t];return n?{shouldSkip:true,reason:n}:{shouldSkip:false}}var S=e=>`${e.name}#${e.version}`,Y=e=>`${e.name}@${e.version}`;var Z=e=>{let t=JSON.stringify(e);return createHash("sha256").update(t).digest("hex").slice(0,16)},ee=(e,t)=>({...e,package_meta:e.package_meta||t,name:e.name,url:e.url,base:e.base});var te=e=>e?.kind==="nested",ne=e=>e?.kind==="profile";var ie=(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 M(e){let t=e.split("|")[0];return t||e}function ve(e){return e.split("|")[1]}function Fe(e){return e.derivation==="constraint"?"profile":e.kind==="primitive-type"?"primitive-type":e.kind==="complex-type"?"complex-type":e.kind==="resource"?"resource":e.kind==="logical"?"logical":"resource"}function C(e){return {kind:Fe(e),package:e.package_meta.name,version:e.package_meta.version,name:e.name,url:e.url}}var Ee=e=>{let t=e.split("/"),o=t[t.length-1];return o&&o.length>0?o.split(/[-_]/).map(i=>i.charAt(0).toUpperCase()+i.slice(1).toLowerCase()).join(""):e};function L(e,t,o){let i=M(o),n=Ee(i),r={package_meta:{name:"missing_valuesets",version:ve(i)||"0.0.0"},id:o},s=e.resolveVs(t,i)||r,c=s?.id&&!/^[a-zA-Z0-9_-]{20,}$/.test(s.id)?s.id:n;return {kind:"value-set",package:s.package_meta.name,version:s.package_meta.version,name:c,url:i}}function P(e,t,o){let i=o.binding?.bindingName,n=t.join("."),[r,s,c]=i?[{name:"shared",version:"1.0.0"},i,`urn:fhir:binding:${i}`]:[e.package_meta,`${e.name}.${n}_binding`,`${e.url}#${n}_binding`];return {kind:"binding",package:r.name,version:r.version,name:s,url:c}}function B(e,t,o,i){let n=M(o)||o,r=e.resolveVs(t,n);if(r)return De(e,r)}function De(e,t,o){if(t.expansion?.contains)return t.expansion.contains.filter(n=>n.code!==void 0).map(n=>(Te(n.code),{code:n.code,display:n.display,system:n.system}));let i=[];if(t.compose?.include){for(let n of t.compose.include)if(n.concept)for(let r of n.concept)i.push({system:n.system,code:r.code,display:r.display});else if(n.system&&!n.filter)try{let r=e.resolveAny(n.system);if(r?.concept){let s=(c,a)=>{for(let l of c)i.push({system:a,code:l.code,display:l.display}),l.concept&&s(l.concept,a);};s(r.concept,n.system);}}catch{}}return i.length>0?i:void 0}var oe=100,j=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function _(e,t,o,i){if(!o.binding)return;let n=o.binding.strength,r=o.binding.valueSet;if(!r)return;if(!j.has(o.type??"")){i?.dryWarn(`eld-11: Binding on non-bindable type '${o.type}' (valueSet: ${r})`);return}if(!(n==="required"||n==="extensible"||n==="preferred"))return;let c=B(e,t.package_meta,r);if(!c||c.length===0)return;let a=c.map(l=>l.code).filter(l=>l&&typeof l=="string"&&l.trim().length>0);if(a.length>oe){i?.dryWarn(`Value set ${r} has ${a.length} which is more than ${oe} codes, which may cause issues with code generation.`);return}if(a.length!==0)return {isOpen:n!=="required",values:a}}function Le(e,t,o,i,n){if(!i.binding?.valueSet)return;let r=P(t,o,i),s=L(e,t.package_meta,i.binding.valueSet),c=_(e,t,i,n);return {identifier:r,valueset:s,strength:i.binding.strength,enum:c,dependencies:[s]}}function re(e,t,o){let i=new Set;if(!t.elements)return [];let n=[];function r(a,l){for(let[u,m]of Object.entries(a)){let h=[...l,u],p=h.join("."),d=e.resolveElementSnapshot(t,h);if(!i.has(p)){if(i.add(p),d.binding){let f=Le(e,t,h,d,o);f&&n.push(f);}m.elements&&r(m.elements,h);}}}r(t.elements,[]),n.sort((a,l)=>a.identifier.name.localeCompare(l.identifier.name));let s=[],c=new Set;for(let a of n)c.has(a.identifier.url)||(c.add(a.identifier.url),s.push(a));return s}function w(e,t,o,i){let n={};if(t.derivation==="constraint"){let m=e.resolveFsSpecializations(t.package_meta,t.url).map(h=>A(e,h,i)).filter(h=>h!==void 0).flat();for(let h of m.reverse())n[h.identifier.name]=h.identifier.url;}let r=o.join("."),s=n[r]??`${t.url}#${r}`,c=s.split("#")[0],l=e.resolveFs(t.package_meta,c)?.package_meta??t.package_meta;return {kind:"nested",package:l.name,version:l.version,name:r,url:s}}function se(e,t,o){let i=[];for(let[n,r]of Object.entries(o)){let s=[...t,n];E(r)&&i.push([s,r]),r.elements&&i.push(...se(e,s,r.elements));}return i}function Pe(e,t,o,i,n){let r={};for(let[s,c]of Object.entries(i)){let a=[...o,s],l=e.resolveElementSnapshot(t,a);E(l)?r[s]=U(e,t,a,l,n):r[s]=N(e,t,a,l,n);}return r}function A(e,t,o){if(!t.elements)return;let i=se(t,[],t.elements).filter(([r,s])=>s.elements&&Object.keys(s.elements).length>0),n=[];for(let[r,s]of i){let c=w(e,t,r,o),a;s.type==="BackboneElement"||!s.type?a="BackboneElement":a=s.type;let l=e.ensureSpecializationCanonicalUrl(a),u=e.resolveFs(t.package_meta,l);if(!u)throw new Error(`Could not resolve base type ${a}`);let m={kind:"complex-type",package:u.package_meta.name,version:u.package_meta.version,name:a,url:l},h=Pe(e,t,r,s.elements??{},o),p={identifier:c,base:m,fields:h};n.push(p);}return n.sort((r,s)=>r.identifier.url.localeCompare(s.identifier.url)),n.length===0?void 0:n}function ae(e){let t=[];for(let o of e){o.base&&t.push(o.base);for(let i of Object.values(o.fields||{}))"type"in i&&i.type&&t.push(i.type),"binding"in i&&i.binding&&t.push(i.binding);}return t}function ce(e,t,o){let i=o[o.length-1];if(!i)throw new Error(`Internal error: fieldName is missing for path ${o.join("/")}`);let n=o.slice(0,-1),r=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(s=>{if(n.length===0)return s.required||[];if(!s.elements)return [];let c=s;for(let a of n)c=c?.elements?.[a];return c?.required||[]});return new Set(r).has(i)}function le(e,t,o){let i=o[o.length-1];if(!i)throw new Error(`Internal error: fieldName is missing for path ${o.join("/")}`);let n=o.slice(0,-1),r=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(s=>{if(n.length===0)return s.excluded||[];if(!s.elements)return [];let c=s;for(let a of n)c=c?.elements?.[a];return c?.excluded||[]});return new Set(r).has(i)}var we=(e,t,o)=>{if(o.refers)return o.refers.map(i=>{let n=e.ensureSpecializationCanonicalUrl(i),r=e.resolveFs(t.package_meta,n);if(!r)throw new Error(`Failed to resolve fs for ${n}`);return C(r)})},Ne=e=>{let t=new Set,o=new Set;if(e.required)for(let i of e.required)t.add(i);if(e.excluded)for(let i of e.excluded)o.add(i);if(e.elements)for(let[i,n]of Object.entries(e.elements))n.min!==void 0&&n.min>0&&t.add(i);return {required:t.size>0?Array.from(t):void 0,excluded:o.size>0?Array.from(o):void 0}},pe=e=>{let t=e.slicing;if(!t)return;let o={};for(let[i,n]of Object.entries(t.slices??{})){if(!n)continue;let{required:r,excluded:s}=n.schema?Ne(n.schema):{};o[i]={min:n.min,max:n.max,match:n.match,required:r,excluded:s};}return {discriminator:t.discriminator,rules:t.rules,ordered:t.ordered,slices:Object.keys(o).length>0?o:void 0}};function $(e,t,o,i,n){if(i.elementReference){let r=i.elementReference.slice(1).filter((s,c)=>c%2===1);return w(e,t,r,n)}else if(i.type){let r=e.ensureSpecializationCanonicalUrl(i.type),s=e.resolveFs(t.package_meta,r);if(!s)throw new Error(`Could not resolve field type: <${t.url}>.${o.join(".")}: <${i.type}> (pkg: '${S(t.package_meta)}'))`);return C(s)}else {if(i.choices)return;if(t.derivation==="constraint")return;n?.dryWarn(`Can't recognize element type: <${t.url}>.${o.join(".")} (pkg: '${S(t.package_meta)}'): missing type info`);return}}var N=(e,t,o,i,n)=>{let r,s;i.binding&&(r=P(t,o,i),j.has(i.type??"")&&(s=_(e,t,i,n)));let c=$(e,t,o,i,n);return c||n?.dryWarn(`Field type not found for '${t.url}#${o.join(".")}' (${t.derivation})`),{type:c,required:ce(e,t,o),excluded:le(e,t,o),reference:we(e,t,i),array:i.array||false,min:i.min,max:i.max,slicing:pe(i),choices:i.choices,choiceOf:i.choiceOf,binding:r,enum:s}};function E(e){let t=e.type==="BackboneElement",o=e.type==="Element"&&e.elements!==void 0&&Object.keys(e.elements).length>0,i=e.type===void 0&&e.choiceOf===void 0&&e.elements!==void 0&&Object.keys(e.elements).length>0;return t||o||i}function U(e,t,o,i,n){return {type:w(e,t,o,n),array:i.array||false,required:ce(e,t,o),excluded:le(e,t,o),slicing:pe(i)}}function Ue(e,t,o,i,n){if(!i)return;let r={};for(let s of e.getAllElementKeys(i)){let c=[...o,s],a=e.resolveElementSnapshot(t,c),l=a.type?e.ensureSpecializationCanonicalUrl(a.type):void 0;if(l&&I(t.package_meta,l).shouldSkip){n?.warn(`Skipping field ${c} for ${l} due to skip hack ${I(t.package_meta,l).reason}`);continue}E(a)?r[s]=U(e,t,c,a,n):r[s]=N(e,t,c,a,n);}return r}function $e(e){let t=[];for(let o of Object.values(e))"type"in o&&o.type&&t.push(o.type),"binding"in o&&o.binding&&t.push(o.binding);return t}function He(e,t){return !!(e.base==="Extension"||e.base==="http://hl7.org/fhir/StructureDefinition/Extension"||e.url?.includes("/extension/")||e.url?.includes("-extension")||e.name?.toLowerCase().includes("extension")||e.type==="Extension")}async function de(e,t,o){if(!t.url)throw new Error("ValueSet URL is required");let i=L(e,t.package_meta,t.url),n=B(e,t.package_meta,t.url);return {identifier:i,description:t.description,concept:n,compose:n?void 0:t.compose}}function Ve(e,t,o,i){let n=[];t&&n.push(t),o&&n.push(...$e(o)),i&&n.push(...ae(i));let r={};for(let a of n)a.url!==e.url&&(r[a.url]=a);let s=new Set(i?.map(a=>a.identifier.url)),c=Object.values(r).filter(a=>ne(e)||!te(a)?true:!s.has(a.url)).sort((a,l)=>a.url.localeCompare(l.url));return c.length>0?c:void 0}function Oe(e,t,o){let i=C(t),n;if(t.base&&t.type!=="Element"){let p=e.resolveFs(t.package_meta,e.ensureSpecializationCanonicalUrl(t.base));if(!p)throw new Error(`Base resource not found '${t.base}' for <${t.url}> from ${S(t.package_meta)}`);n=C(p);}let r=Ue(e,t,[],t.elements,o),s=A(e,t,o),c=t.derivation==="constraint"?Ae(e,t,o):void 0,a=Ve(i,n,r,s),l=c?.flatMap(p=>p.valueTypes??[])??[],u=(()=>{if(!a&&l.length===0)return a;let p={};for(let d of a??[])p[d.url]=d;for(let d of l)p[d.url]=d;return Object.values(p)})(),m={identifier:i,base:n,fields:r,nested:s,description:t.description,dependencies:u,...c&&c.length>0?{extensions:c}:{}},h=re(e,t,o);return [m,...h]}function Me(e,t,o,i){let n=e.resolveFs(t.package_meta,o);if(!n?.elements)return;let r=[];for(let[c,a]of Object.entries(n.elements)){if(a.choiceOf!=="value"&&!c.startsWith("value"))continue;let l=$(e,n,[c],a,i);l&&r.push(l);}if(r.length===0)return;let s=new Map(r.map(c=>[c.url,c]));return Array.from(s.values())}var Be=(e,t,o)=>{let i=[];if(!t.elements)return i;for(let[n,r]of Object.entries(t.elements)){if(!n.startsWith("extension:"))continue;let s=n.split(":")[1];if(!s)continue;let c;for(let[a,l]of Object.entries(r.elements??{}))if(!(l.choiceOf!=="value"&&!a.startsWith("value"))&&(c=$(e,t,[n,a],l,o),c))break;i.push({name:s,url:r.url??s,valueType:c,min:r.min,max:r.max!==void 0?String(r.max):void 0});}return i},je=e=>{let t=[],i=e.elements?.extension?.slicing?.slices;if(!i||typeof i!="object")return t;for(let[n,r]of Object.entries(i)){let s=r,c=s.schema;if(!c)continue;let a;for(let[l,u]of Object.entries(c.elements??{})){let m=u;if(!(m.choiceOf!=="value"&&!l.startsWith("value"))&&m.type){a={kind:"complex-type",package:e.package_meta.name,version:e.package_meta.version,name:m.type,url:`http://hl7.org/fhir/StructureDefinition/${m.type}`};break}}t.push({name:n,url:s.match?.url??n,valueType:a,min:c._required?1:c.min??0,max:c.max!==void 0?String(c.max):c.array?"*":"1"});}return t},_e=(e,t,o,i)=>{let n=e.resolveFs(t.package_meta,o);if(!n?.elements)return;let r=Be(e,n,i),s=je(n),c=[...r,...s];return c.length>0?c:void 0};function Ae(e,t,o){let i=[],n=(s,c,a)=>{let l=a.url,u=l?Me(e,t,l,o):void 0,m=l?_e(e,t,l,o):void 0,h=m!==void 0&&m.length>0;i.push({name:c,path:[...s,"extension"].join("."),url:l,min:a.min,max:a.max!==void 0?String(a.max):void 0,mustSupport:a.mustSupport,valueTypes:u,subExtensions:m,isComplex:h});},r=(s,c)=>{if(c.extensions)for(let[a,l]of Object.entries(c.extensions))n(s,a,l);if(c.elements)for(let[a,l]of Object.entries(c.elements))r([...s,a],l);};if(t.extensions)for(let[s,c]of Object.entries(t.extensions))n([],s,c);if(t.elements)for(let[s,c]of Object.entries(t.elements))r([s],c);return i}async function ue(e,t,o){let i=Oe(e,t,o);if(He(t,C(t))){let n=i[0];if(!n)throw new Error("Expected schema to be defined");n.metadata={isExtension:true};}return i}var Ge=(e,t)=>{let o={};for(let r of e){let s=`${r.schema.identifier.url}|${r.schema.identifier.package}`,c=Z(r.schema);o[s]??={},o[s][c]??={typeSchema:r.schema,sources:[]},o[s][c].sources.push(r);}let i=[],n={};for(let r of Object.values(o)){let s=Object.values(r).sort((a,l)=>l.sources.length-a.sources.length),c=s[0];if(c&&(i.push(c.typeSchema),s.length>1)){let a=c.typeSchema.identifier.package,l=c.typeSchema.identifier.url;t?.dryWarn(`'${l}' from '${a}'' has ${s.length} versions`),n[a]??={},n[a][l]=s.flatMap(u=>u.sources.map(m=>({typeSchema:u.typeSchema,sourcePackage:m.sourcePackage,sourceCanonical:m.sourceCanonical})));}}return {schemas:i,collisions:n}},me=async(e,t)=>{let o=[];for(let i of e.allFs()){let n=S(i.package_meta),r=I(i.package_meta,i.url);if(r.shouldSkip){t?.dryWarn(`Skip ${i.url} from ${n}. Reason: ${r.reason}`);continue}for(let s of await ue(e,i,t))o.push({schema:s,sourcePackage:n,sourceCanonical:i.url});}for(let i of e.allVs())o.push({schema:await de(e,i),sourcePackage:S(i.package_meta),sourceCanonical:i.url});return Ge(o,t)};var G=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var H=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var qe=async(e,t)=>{let o=await e.packageJson(t.name);if(!o)return [];let i=o.dependencies;return i!==void 0?Object.entries(i).map(([n,r])=>({name:n,version:r})):[]},he=e=>({pkg:e,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),ye=async(e,t,o,i,n)=>{let r=S(t);if(n?.info(`${" ".repeat(o*2)}+ ${r}`),i[r])return i[r];let s=he(t);for(let a of await e.search({package:t})){let l=a.url;if(!l||!(isStructureDefinition(a)||H(a)||G(a)))continue;let u=l;s.canonicalResolution[u]&&n?.dryWarn(`Duplicate canonical URL: ${u} at ${r}.`),s.canonicalResolution[u]=[{deep:o,pkg:t,pkgId:r,resource:a}];}let c=await qe(e,t);for(let a of c){let{canonicalResolution:l}=await ye(e,a,o+1,i,n);for(let[u,m]of Object.entries(l)){let h=u;s.canonicalResolution[h]=[...s.canonicalResolution[h]||[],...m];}}for(let a of Object.values(s.canonicalResolution))a.sort((l,u)=>l.deep-u.deep);return i[r]=s,s},fe=(e,t)=>{for(let{pkg:o,canonicalResolution:i}of Object.values(e)){let n=S(o);if(!e[n])throw new Error(`Package ${n} not found`);for(let[s,c]of Object.entries(i)){let a=c[0];if(!a)throw new Error("Resource not found");let l=a.resource,u=a.pkg;if(isStructureDefinition(l)){let m=ge.translate(l),h=ee(m,u);e[n].fhirSchemas[h.url]=h;}if(H(l)){let m=ie(l,u);e[n].valueSets[m.url]=m;}}}},ze=(e,t,o)=>{let i=Object.values(e).flatMap(n=>n.canonicalResolution[t]);if(!i)throw new Error(`No canonical resolution found for ${t} in any package`);return i[0]?.resource},Ke=async(e,{logger:t,focusedPackages:o})=>{let i=o??await e.packages(),n={};for(let p of i)await ye(e,p,0,n,t);fe(n);let r=(p,d)=>{let f=n[S(p)];if(f){let g=f.canonicalResolution[d]?.[0];if(g)return n[g.pkgId]?.fhirSchemas[d]}for(let g of Object.values(n)){let y=g.fhirSchemas[d];if(y&&y.package_meta.name===p.name)return y}for(let g of Object.values(n)){let y=g.fhirSchemas[d];if(y)return y}},s=(p,d)=>{let f=n[S(p)];if(f){let g=f.canonicalResolution[d]?.[0];if(g)return n[g.pkgId]?.valueSets[d]}for(let g of Object.values(n)){let y=g.valueSets[d];if(y&&y.package_meta.name===p.name)return y}for(let g of Object.values(n)){let y=g.valueSets[d];if(y)return y}},c=p=>(p.includes("|")&&(p=p.split("|")[0]),p.match(/^[a-zA-Z0-9]+$/)?`http://hl7.org/fhir/StructureDefinition/${p}`:p),a=(p,d)=>{let f=r(p,d);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${d}'`);let g=[f];for(;f?.base;){let y=f.package_meta,R=c(f.base);if(f=r(y,R),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${d}'. Problem: '${R}' from '${S(y)}'`);g.push(f);}return g},l=(p,d)=>a(p,d).filter(f=>f.derivation==="specialization"),u=(p,d)=>{let f=a(p.package_meta,p.url),g=Je(f,d);return Qe(g)},m=p=>{let d=new Set;for(let[f,g]of Object.entries(p)){d.add(f);for(let y of g?.choices||[])p[y]||d.add(y);}return Array.from(d)},h;return {testAppendFs(p){let d=S(p.package_meta);n[d]||(n[d]=he(p.package_meta)),n[d].fhirSchemas[p.url]=p,h=void 0;},resolveFs:r,resolveFsGenealogy:a,resolveFsSpecializations:l,ensureSpecializationCanonicalUrl:c,resolveSd:(p,d)=>{let f=n[S(p)]?.canonicalResolution[d]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(n).flatMap(p=>Object.values(p.canonicalResolution).flatMap(d=>d.map(f=>{let g=f.resource;return g.package_name?g:{...g,package_name:p.pkg.name,package_version:p.pkg.version}}))).filter(p=>isStructureDefinition(p)).sort((p,d)=>p.url.localeCompare(d.url)),patchSd:p=>{Object.values(n).flatMap(d=>Object.values(d.canonicalResolution).forEach(f=>{f.forEach(g=>{if(isStructureDefinition(g.resource)){let y=g.resource,R=p(d.pkg,y);if(y.url!==R.url)throw new Error(`Patch update StructureDefinition URL: ${y.url} !== ${R.url}`);g.resource=R;}});})),fe(n),h=void 0;},allFs:()=>Object.values(n).flatMap(p=>Object.values(p.fhirSchemas)),allVs:()=>Object.values(n).flatMap(p=>Object.values(p.valueSets)),resolveVs:s,resolveAny:p=>ze(n,p),resolveElementSnapshot:u,getAllElementKeys:m,resolver:n,resolutionTree:()=>{if(h)return h;let p={};for(let[d,f]of Object.entries(n)){let g=f.pkg.name;p[g]={};for(let[y,R]of Object.entries(f.canonicalResolution)){let q=y;p[g][q]=[];for(let z of R)p[g][q].push({deep:z.deep,pkg:z.pkg});}}return h=p,p}}},xe=async(e,t)=>{let o=e.map(Y);t?.logger?.step(`Loading FHIR packages: ${o.join(", ")}`);let i=CanonicalManager({packages:o,workingDir:"tmp/fhir",registry:t.registry||void 0});return await i.init(),await Ke(i,{...t,focusedPackages:e})},Je=(e,t)=>{let[o,...i]=t;return o===void 0?[]:e.map(n=>{if(!n.elements)return;let r=n.elements?.[o];for(let s of i)r=r?.elements?.[s];return r}).filter(n=>n!==void 0)};function Qe(e){let t=e.reverse(),o=Object.assign({},...t);return o.elements=void 0,o}var Se={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=J({prefix:"TypeSchema"});try{t.step("Generating TypeSchema from FHIR packages"),t.info(`Packages: ${e.packages.join(", ")}`),t.info(`Output: ${e.output}`);let o=e.singleFile?"ndjson":e.format;t.debug(`Format: ${o}${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 i=Date.now(),n=e.packages.map(u=>{if(u.includes("@")){let m=u.lastIndexOf("@");return {name:u.slice(0,m),version:u.slice(m+1)||"latest"}}return {name:u,version:"latest"}});t.progress(`Processing packages: ${n.map(u=>`${u.name}@${u.version}`).join(", ")}`);let r=await xe(n,{logger:t,registry:e.registry,focusedPackages:n}),{schemas:s}=await me(r,t);if(s.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 a;o==="json"?a=JSON.stringify(s,null,2):a=s.map(u=>JSON.stringify(u)).join(`
|
|
3
|
+
`),await writeFile(c,a,"utf-8");let l=Date.now()-i;if(X(`Generated ${s.length} TypeSchema definitions`,l,{schemas:s.length}),t.dim(`Output: ${c}`),e.verbose){t.debug("Generated schemas:");let u=s.map(m=>`${m.identifier?.name||"Unknown"} (${m.identifier?.kind||"unknown"})`);b(u);}}catch(o){t.error("Failed to generate TypeSchema",o instanceof Error?o:new Error(String(o))),process.exit(1);}}};var Re={command:"typeschema [subcommand]",describe:"TypeSchema operations - generate, validate and merge schemas",builder:e=>e.command(Se).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){V("Available typeschema subcommands:"),b(["generate Generate TypeSchema files from FHIR packages"]),console.log(`
|
|
4
4
|
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),console.log(`
|
|
5
|
-
Examples:`),
|
|
6
|
-
`),
|
|
7
|
-
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};function
|
|
5
|
+
Examples:`),b(["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)&&(k(`Unknown typeschema subcommand: ${e.subcommand}
|
|
6
|
+
`),V("Available typeschema subcommands:"),b(["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(`
|
|
7
|
+
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};function nt(e){return e?{debug:0,info:1,warn:2,error:3,silent:4}[e.toLowerCase()]:void 0}async function it(e){let t=nt(e.logLevel);t===void 0&&(e.debug||e.verbose?t=0:t=1),K({timestamp:e.debug,level:t});}function ot(){return et(hideBin(process.argv)).scriptName("atomic-codegen").usage("$0 <command> [options]").middleware(it).command(Re).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&&(Q("Welcome to Atomic Codegen!"),console.log("Available commands:"),console.log(" typeschema Generate, validate and merge TypeSchema files"),console.log(`
|
|
8
8
|
Use 'atomic-codegen <command> --help' for more information about a command.`),console.log(`
|
|
9
9
|
Quick examples:`),console.log(" atomic-codegen typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson"),console.log(`
|
|
10
|
-
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,o)=>{t?
|
|
11
|
-
Use --help for usage information`),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function W(){await
|
|
10
|
+
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,o)=>{t?k(t.message,t):k(e),k(`
|
|
11
|
+
Use --help for usage information`),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function W(){await ot().parseAsync();}import.meta.main&&W().catch(e=>{e("Unexpected error:",e),process.exit(1);});W().catch(e=>{console.error("CLI Error:",e instanceof Error?e.message:e),process.exit(1);});
|
package/dist/index.js
CHANGED
|
@@ -2206,6 +2206,21 @@ function extractFieldDependencies(fields) {
|
|
|
2206
2206
|
}
|
|
2207
2207
|
return deps;
|
|
2208
2208
|
}
|
|
2209
|
+
function isExtensionSchema(fhirSchema, _identifier) {
|
|
2210
|
+
if (fhirSchema.base === "Extension" || fhirSchema.base === "http://hl7.org/fhir/StructureDefinition/Extension") {
|
|
2211
|
+
return true;
|
|
2212
|
+
}
|
|
2213
|
+
if (fhirSchema.url?.includes("/extension/") || fhirSchema.url?.includes("-extension")) {
|
|
2214
|
+
return true;
|
|
2215
|
+
}
|
|
2216
|
+
if (fhirSchema.name?.toLowerCase().includes("extension")) {
|
|
2217
|
+
return true;
|
|
2218
|
+
}
|
|
2219
|
+
if (fhirSchema.type === "Extension") {
|
|
2220
|
+
return true;
|
|
2221
|
+
}
|
|
2222
|
+
return false;
|
|
2223
|
+
}
|
|
2209
2224
|
async function transformValueSet(register, valueSet, logger) {
|
|
2210
2225
|
if (!valueSet.url) throw new Error("ValueSet URL is required");
|
|
2211
2226
|
const identifier = mkValueSetIdentifierByUrl(register, valueSet.package_meta, valueSet.url);
|
|
@@ -2397,7 +2412,16 @@ function extractProfileExtensions(register, fhirSchema, logger) {
|
|
|
2397
2412
|
return extensions;
|
|
2398
2413
|
}
|
|
2399
2414
|
async function transformFhirSchema(register, fhirSchema, logger) {
|
|
2400
|
-
|
|
2415
|
+
const schemas = transformFhirSchemaResource(register, fhirSchema, logger);
|
|
2416
|
+
if (isExtensionSchema(fhirSchema, mkIdentifier(fhirSchema))) {
|
|
2417
|
+
const schema = schemas[0];
|
|
2418
|
+
if (!schema) throw new Error(`Expected schema to be defined`);
|
|
2419
|
+
schema.metadata = {
|
|
2420
|
+
isExtension: true
|
|
2421
|
+
// Mark as extension for file organization
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
return schemas;
|
|
2401
2425
|
}
|
|
2402
2426
|
|
|
2403
2427
|
// src/typeschema/index.ts
|
|
@@ -4169,10 +4193,9 @@ var TypeScript = class extends Writer {
|
|
|
4169
4193
|
this.line();
|
|
4170
4194
|
}
|
|
4171
4195
|
}
|
|
4172
|
-
addFieldExtension(fieldName
|
|
4196
|
+
addFieldExtension(fieldName) {
|
|
4173
4197
|
const extFieldName = tsFieldName(`_${fieldName}`);
|
|
4174
|
-
|
|
4175
|
-
this.lineSM(`${extFieldName}?: ${typeExpr}`);
|
|
4198
|
+
this.lineSM(`${extFieldName}?: Element`);
|
|
4176
4199
|
}
|
|
4177
4200
|
generateType(tsIndex, schema) {
|
|
4178
4201
|
let name;
|
|
@@ -4214,7 +4237,7 @@ var TypeScript = class extends Writer {
|
|
|
4214
4237
|
this.lineSM(`${tsName}${optionalSymbol}: ${tsType}${arraySymbol}`);
|
|
4215
4238
|
if (this.withPrimitiveTypeExtension(schema)) {
|
|
4216
4239
|
if (isPrimitiveIdentifier(field.type)) {
|
|
4217
|
-
this.addFieldExtension(fieldName
|
|
4240
|
+
this.addFieldExtension(fieldName);
|
|
4218
4241
|
}
|
|
4219
4242
|
}
|
|
4220
4243
|
}
|