Skip to content

Update to FHIRModels 0.9 - #4

Open
vishnuravi wants to merge 5 commits into
mainfrom
update-fhirmodels-0.9
Open

Update to FHIRModels 0.9#4
vishnuravi wants to merge 5 commits into
mainfrom
update-fhirmodels-0.9

Conversation

@vishnuravi

@vishnuravi vishnuravi commented Sep 13, 2026

Copy link
Copy Markdown
Member

♻️ Current situation & Problem

FHIRModels 0.9.0 is a breaking release: every model type is now a Sendable struct, Element, BackboneElement, and DomainResource are protocols, and FHIRAbstractResource no longer exists. #3 pinned this package to 0.8.0..<0.9.0 as a stopgap, which now also blocks downstream packages such as HealthKitOnFHIR from moving to 0.9.

This PR ports the package to FHIRModels 0.9.3 with the smallest API change that works with value semantics. Helper names are unchanged.

⚙️ Release Notes

  • The FHIRModels dependency is now .upToNextMinor(from: "0.9.3"), and the FMCore product is declared explicitly.
  • Breaking: every helper that modifies a resource is now mutating. This affects the Observation append helpers, setEffective(startDate:endDate:timeZone:), setIssued(on:), encodeAbsoluteTimeRangeIntoExtension(), and the appendExtension(s) / removeFirstExtension / removeAllExtensions helpers. Call them on a var.
  • Breaking: FHIRExtensionBuilder closures and all apply overloads receive the Observation as inout. FHIRExtensionBuilderProtocol now refines Sendable, so erased builders can be stored in Sendable types and passed across isolation boundaries.
  • Breaking: FHIRResourceMutationExtensions is removed. The keypath helpers (appendElement(s), removeFirstElement, removeAllElements) are now available on every FHIRType, using WritableKeyPath.
  • FHIRTypeWithExtensions no longer requires AnyObject. Since a protocol cannot be conformed to another protocol, the conformances are now declared per concrete type in the generated FHIRTypeWithExtensions+Conformances.swift: all 650 R4 elements, backbone elements, domain resources, and FHIRPrimitive, so extensions on primitive elements are covered too. Scripts/generate_extension_conformances.py regenerates the file from the resolved FHIRModels checkout, and a new static-analysis job fails if the committed file is out of date.
  • Appending an empty collection to a nil property now leaves it nil instead of creating an empty array, matching FHIR's rule that arrays are never empty.
  • The nonisolated(unsafe) annotations on the extension URL constants are removed; FHIRPrimitive is Sendable now.

📚 Documentation

  • The README overview is rewritten to describe what each of the three products provides, with a short usage example that is compiled as part of this PR's verification.
  • Doc comments are updated in place, the DocC landing page explains the value-semantics model, and the generated conformance file and the script that produces it are documented in their headers.
  • The dead Swift Package Manager documentation link in the README is replaced, and a .linkspector.yml ignores the Zenodo and Swift Package Index badge targets, which answer automated requests with 403 or time out and were failing the required link check on main as well.

✅ Testing

  • New FHIRExtensionBuilderTests cover typed and type-erased builder application, value-semantics isolation, setEffective / setIssued, the absolute time range extension (including the replace-on-reencode and unsupported-effective paths), extension helpers on nested extensions, backbone elements, non-observation resources, and primitives, and the keypath helpers including their nil-when-empty behavior.
  • Existing tests are updated to mutate through var; the @MainActor workaround for Bug report: FHIRModels is not concurrency safe, leading to crashes at runtime apple/FHIRModels#36 is no longer needed.
  • Verified locally with Xcode 26.6: swift test on macOS, and xcodebuild test on the iOS, watchOS, and tvOS simulators and as Mac Catalyst. SwiftLint reports no violations and the DocC build has no warnings in package sources.
  • Verified downstream: HealthKitOnFHIR builds against this branch with only mechanical letvar / inout changes, and its full test suite passes on macOS and on the iOS and watchOS simulators.

Code of Conduct & Contributing Guidelines

By creating and submitting this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

FHIRModels 0.9 turned all model types into structs and made Element,
BackboneElement, and DomainResource protocols. Port the helpers to value
semantics: mutating resource helpers, inout extension builders, keypath
helpers on FHIRType, and generated FHIRTypeWithExtensions conformances
for all R4 types that carry extensions.
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 0251ff42-5002-4d2c-b431-85a3a9eeb6c6


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 13, 2026

Copy link
Copy Markdown

API breaking changes

  • FHIRModelsExtensions
    💔 API breakage: protocol FHIRExtensionBuilderProtocol has generic signature change from to
    💔 API breakage: protocol FHIRExtensionBuilderProtocol has added inherited protocol Sendable
    💔 API breakage: protocol FHIRExtensionBuilderProtocol has added inherited protocol SendableMetatype
    💔 API breakage: func FHIRExtensionBuilderProtocol.apply(input:to:) has parameter 1 changing from Default to InOut
    💔 API breakage: func FHIRExtensionBuilderProtocol.apply(to:) has parameter 0 changing from Default to InOut
    💔 API breakage: func FHIRExtensionBuilderProtocol.apply(typeErasedInput:to:) has parameter 1 changing from Default to InOut
    💔 API breakage: func FHIRExtensionBuilder.apply(input:to:) has parameter 1 changing from Default to InOut
    💔 API breakage: protocol FHIRTypeWithExtensions has generic signature change from to
    💔 API breakage: func FHIRTypeWithExtensions.appendExtension(:replaceAllExistingWithSameUrl:) has generic signature change from <Self where Self : FHIRModelsExtensions.FHIRResourceMutationExtensions, Self : FHIRModelsExtensions.FHIRTypeWithExtensions> to
    💔 API breakage: func FHIRTypeWithExtensions.appendExtension(
    :replaceAllExistingWithSameUrl:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func FHIRTypeWithExtensions.appendExtensions(:replaceAllExistingWithSameUrl:) has generic signature change from <Self where Self : FHIRModelsExtensions.FHIRResourceMutationExtensions, Self : FHIRModelsExtensions.FHIRTypeWithExtensions> to
    💔 API breakage: func FHIRTypeWithExtensions.appendExtensions(
    :replaceAllExistingWithSameUrl:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func FHIRTypeWithExtensions.removeFirstExtension(withUrl:) has generic signature change from <Self where Self : FHIRModelsExtensions.FHIRResourceMutationExtensions, Self : FHIRModelsExtensions.FHIRTypeWithExtensions> to
    💔 API breakage: func FHIRTypeWithExtensions.removeFirstExtension(withUrl:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func FHIRTypeWithExtensions.removeAllExtensions(withUrl:) has generic signature change from <Self where Self : FHIRModelsExtensions.FHIRResourceMutationExtensions, Self : FHIRModelsExtensions.FHIRTypeWithExtensions> to
    💔 API breakage: func FHIRTypeWithExtensions.removeAllExtensions(withUrl:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: extension Observation is no longer open for subclassing
    💔 API breakage: extension Observation has been changed to a struct
    💔 API breakage: extension Observation has removed conformance to FHIRResourceMutationExtensions
    💔 API breakage: func Observation.encodeAbsoluteTimeRangeIntoExtension() has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.apply(:input:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.apply(
    :) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.setEffective(startDate:endDate:timeZone:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.setIssued(on:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendIdentifier(:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendIdentifiers(
    :) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendCategory(:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendCategories(
    :) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendCoding(:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendCodings(
    :) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendComponent(:) has self access kind changing from NonMutating to Mutating
    💔 API breakage: func Observation.appendComponents(
    :) has self access kind changing from NonMutating to Mutating
    💔 API breakage: extension QuestionnaireItem is no longer open for subclassing
    💔 API breakage: extension QuestionnaireItem has been changed to a struct
    💔 API breakage: extension QuestionnaireItem has removed conformance to FHIRResourceMutationExtensions
    💔 API breakage: extension Questionnaire is no longer open for subclassing
    💔 API breakage: extension Questionnaire has been changed to a struct
    💔 API breakage: extension Questionnaire has removed conformance to FHIRResourceMutationExtensions
    💔 API breakage: protocol FHIRResourceMutationExtensions has been removed
  • FHIRPathParser: no breaking changes
  • FHIRQuestionnaires
    💔 API breakage: extension Questionnaire is no longer open for subclassing
    💔 API breakage: extension Questionnaire has been changed to a struct

@codecov

codecov Bot commented Sep 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 39.25%. Comparing base (530f535) to head (2974ec1).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main       #4      +/-   ##
==========================================
+ Coverage   38.22%   39.25%   +1.03%     
==========================================
  Files          23       23              
  Lines         471      474       +3     
==========================================
+ Hits          180      186       +6     
+ Misses        291      288       -3     
Files with missing lines Coverage Δ
...ilder/FHIRExtensionBuilder+AbsoluteTimeRange.swift 50.00% <100.00%> (ø)
.../FHIR Extension Builder/FHIRExtensionBuilder.swift 100.00% <100.00%> (+25.00%) ⬆️
...urces/FHIRModelsExtensions/Observation+Dates.swift 100.00% <100.00%> (+50.00%) ⬆️
...es/FHIRModelsExtensions/Resource+Collections.swift 100.00% <100.00%> (ø)
...urces/FHIRModelsExtensions/Resource+Mutation.swift 100.00% <100.00%> (ø)
...s/FHIRQuestionnaires/Questionnaire+Resources.swift 44.45% <ø> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 530f535...2974ec1. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Make FHIRExtensionBuilderProtocol refine Sendable, declare the FMCore
product dependency explicitly, include FHIRPrimitive in the generated
FHIRTypeWithExtensions conformances so extensions on primitive elements
are covered, and add a static-analysis job that regenerates the
conformance file and fails if the committed copy is stale.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant