From b773b473882e3013bea53784c5bf552eae1e462f Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Thu, 30 Apr 2026 17:14:07 +0200 Subject: [PATCH 1/3] TypeSchema: improve field type resolution error - Multi-line error with package, schema, field, type rows - R5_ONLY_TYPES set + dependsOnR4Core helper to gate the hint - Hint suggests skip-hack.ts entry or upgrading to R5 --- src/typeschema/core/field-builder.ts | 42 ++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/typeschema/core/field-builder.ts b/src/typeschema/core/field-builder.ts index d7c06b6c..ab7de8bd 100644 --- a/src/typeschema/core/field-builder.ts +++ b/src/typeschema/core/field-builder.ts @@ -15,6 +15,7 @@ import type { FieldSlice, FieldSlicing, Name, + PackageMeta, RegularField, RichFHIRSchema, TypeIdentifier, @@ -25,6 +26,35 @@ import { mkBindingIdentifier, mkIdentifier } from "./identifier"; import { mkSliceNameCandidates } from "./name-candidates"; import { mkNestedIdentifier } from "./nested-types"; +const R5_ONLY_TYPES = new Set([ + "Availability", + "CodeableReference", + "ExtendedContactDetail", + "MonetaryComponent", + "RatioRange", + "VirtualServiceDetail", +]); + +const dependsOnR4Core = (register: Register, pkg: PackageMeta): boolean => { + const pkgIndex = register.resolver[packageMetaToFhir(pkg)]; + if (!pkgIndex) return false; + for (const options of Object.values(pkgIndex.canonicalResolution)) { + for (const opt of options) { + if (opt.pkg.name === "hl7.fhir.r4.core") return true; + } + } + return false; +}; + +const fieldTypeResolutionHint = (register: Register, pkg: PackageMeta, type: string): string => { + if (!R5_ONLY_TYPES.has(type)) return ""; + if (!dependsOnR4Core(register, pkg)) return ""; + return ( + `\n hint: '${type}' is an R5+ type and is not available when generating against R4.` + + `\n Either skip this canonical via skip-hack.ts, or upgrade the target to R5.` + ); +}; + function isRequired(register: Register, fhirSchema: RichFHIRSchema, path: string[]): boolean { const fieldName = path[path.length - 1]; if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`); @@ -283,10 +313,18 @@ export function buildFieldType( } else if (element.type) { const url = register.ensureSpecializationCanonicalUrl(element.type); const fieldFs = register.resolveFs(fhirSchema.package_meta, url); - if (!fieldFs) + if (!fieldFs) { + const pkgId = packageMetaToFhir(fhirSchema.package_meta); + const fieldPath = path.join("."); + const hint = fieldTypeResolutionHint(register, fhirSchema.package_meta, element.type); throw new Error( - `Could not resolve field type: <${fhirSchema.url}>.${path.join(".")}: <${element.type}> (pkg: '${packageMetaToFhir(fhirSchema.package_meta)}'))`, + `Could not resolve field type: + package: ${pkgId} + schema: ${fhirSchema.url} + field: ${fieldPath} + type: ${element.type}${hint}`, ); + } return mkIdentifier(fieldFs); } else if (element.choices) { return undefined; From 767b65ed657ba018a70256ef6683dcd1a6b6780d Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Thu, 30 Apr 2026 17:14:13 +0200 Subject: [PATCH 2/3] TypeSchema: skip biologicallyderivedproduct R5-typed extensions Add biologicallyderivedproduct-manipulation and -processing from hl7.fhir.uv.extensions.r4 to the skip list. Both reference CodeableReference, which is R5-only and unavailable when generating against R4. --- src/typeschema/skip-hack.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/typeschema/skip-hack.ts b/src/typeschema/skip-hack.ts index 5e28b67f..b619fbc2 100644 --- a/src/typeschema/skip-hack.ts +++ b/src/typeschema/skip-hack.ts @@ -5,6 +5,8 @@ const availabilityInR4 = "Use Availability which is not provided by FHIR R4."; export const skipList: Record> = { "hl7.fhir.uv.extensions.r4": { + "http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-manipulation": codeableReferenceInR4, + "http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-processing": codeableReferenceInR4, "http://hl7.org/fhir/StructureDefinition/extended-contact-availability": availabilityInR4, "http://hl7.org/fhir/StructureDefinition/immunization-procedure": codeableReferenceInR4, "http://hl7.org/fhir/StructureDefinition/specimen-additive": codeableReferenceInR4, From 7d70bb93e6ff454a883faadbdbf1cbffa1ee074e Mon Sep 17 00:00:00 2001 From: Aleksandr Penskoi Date: Thu, 30 Apr 2026 17:14:17 +0200 Subject: [PATCH 3/3] TypeSchema: extend kbv-r4 example with de.basisprofil + kbv.basis Replace the explicit hl7.fhir.r4.core dep (now pulled transitively) with de.basisprofil.r4@1.6.0-ballot2 and kbv.basis@1.8.0 to exercise the cross-package version graph from PR #151. --- examples/on-the-fly/kbv-r4/generate.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/on-the-fly/kbv-r4/generate.ts b/examples/on-the-fly/kbv-r4/generate.ts index d10b1980..286df767 100644 --- a/examples/on-the-fly/kbv-r4/generate.ts +++ b/examples/on-the-fly/kbv-r4/generate.ts @@ -32,8 +32,9 @@ if (require.main === module) { registry: "https://packages.simplifier.net", ignorePackageIndex: true, }) - .fromPackage("hl7.fhir.r4.core", "4.0.1") .fromPackage("kbv.ita.for", "1.3.1") + .fromPackage("de.basisprofil.r4", "1.6.0-ballot2") + .fromPackage("kbv.basis", "1.8.0") .throwException() .typescript({ withDebugComment: false,