|
| 1 | +# Multi-version IGs |
| 2 | + |
| 3 | +## 1 Introduction |
| 4 | + |
| 5 | +An Implementation Guide is authored against a single primary FHIR version, but the |
| 6 | +IG Publisher can, in a single run, additionally emit **downgraded variant packages** |
| 7 | +for other FHIR versions so that implementers on those versions can consume the IG. |
| 8 | + |
| 9 | +This document describes emitting **R4 (4.0.1)** and **R4B (4.3.0)** consumable packages |
| 10 | +from an IG **authored in R5 (5.0.0)**. Existing R4↔R4B behaviour (see |
| 11 | +[the legacy path](#6-relationship-to-the-legacy-r4r4b-path)) is unchanged. |
| 12 | + |
| 13 | +The variant packages are produced by the semantic `generate-version` conversion path, |
| 14 | +which uses the shared version-conversion machinery (`ProfileVersionAdaptor` and the |
| 15 | +`VersionConvertorFactory_*` factories). No new element-level converters are involved - |
| 16 | +this is about enabling R5 as a source version, per-version wiring, configuration, |
| 17 | +analysis and reporting. |
| 18 | + |
| 19 | +## 2 Selecting the target versions |
| 20 | + |
| 21 | +Add one `generate-version` guidance parameter to the IG for each FHIR version you want |
| 22 | +a variant package for. For an R5 IG that should ship R4 and R4B: |
| 23 | + |
| 24 | +```json |
| 25 | +"parameter" : [ |
| 26 | + { "code" : "generate-version", "value" : "r4" }, |
| 27 | + { "code" : "generate-version", "value" : "r4b" } |
| 28 | +] |
| 29 | +``` |
| 30 | + |
| 31 | +Each target produces an extra package `<packageId>.<token>.tgz` (e.g. `<id>.r4.tgz`, |
| 32 | +`<id>.r4b.tgz`) alongside the R5 `package.tgz`. |
| 33 | + |
| 34 | +### Version tokens |
| 35 | + |
| 36 | +Everywhere a FHIR version is named (the `generate-version` value, the per-version |
| 37 | +dependency extension, and the inclusion parameters) the token is matched by **version |
| 38 | +family**, so all of the following are accepted and collate to the same target: |
| 39 | + |
| 40 | +| Family | Accepted tokens | Recommended | |
| 41 | +|--------|---------------------------------|-------------| |
| 42 | +| R4 | `r4`, `4.0`, `4.0.1` | `r4` | |
| 43 | +| R4B | `r4b`, `4.3`, `4.3.0` | `r4b` | |
| 44 | +| R5 | `r5`, `5.0.0` | `r5` | |
| 45 | + |
| 46 | +Use `r4` / `r4b` as the `generate-version` tokens so the produced file names are |
| 47 | +`<id>.r4.tgz` / `<id>.r4b.tgz`. |
| 48 | + |
| 49 | +## 3 Per-version dependencies |
| 50 | + |
| 51 | +The dependencies a downgraded R4/R4B package needs are usually **not** a mechanical |
| 52 | +rename of the R5 dependencies - they frequently have different package ids and/or |
| 53 | +versions, and some dependencies only make sense for a particular FHIR version. |
| 54 | + |
| 55 | +Per-version dependencies are declared with a single repeating extension on each |
| 56 | +`ImplementationGuide.dependsOn` entry: |
| 57 | + |
| 58 | +`http://hl7.org/fhir/tools/StructureDefinition/ig-dependency-for-version` |
| 59 | + |
| 60 | +with these sub-extensions: |
| 61 | + |
| 62 | +| Part | Card. | Type | Meaning | |
| 63 | +|---------------|-------|--------|------------------------------------------------------------| |
| 64 | +| `fhirVersion` | 1..1 | code | the target version this occurrence describes | |
| 65 | +| `packageId` | 0..1 | id | override the dependency's package id for that version | |
| 66 | +| `version` | 0..1 | string | override the dependency's package version for that version | |
| 67 | +| `use` | 0..1 | code | `override` (default) or `remove` | |
| 68 | + |
| 69 | +Semantics for a given target version `V` (a `generate-version` target, or the base |
| 70 | +version for the R5 package itself): |
| 71 | + |
| 72 | +* **Override** - the entry has an occurrence for `V`: apply its `packageId`/`version` |
| 73 | + overrides (a bare occurrence keeps the authored values). |
| 74 | +* **Remove** - the entry has an occurrence for `V` with `use = remove`: the entry is |
| 75 | + absent from `V`. |
| 76 | +* **Add (version-specific)** - the entry has occurrences for some versions but **not** |
| 77 | + `V`: the entry is absent from `V`. This is how a dependency that applies only to R4 |
| 78 | + is declared - author a normal `dependsOn` row and add one occurrence for `r4`; it is |
| 79 | + then present only in the R4 package and absent from the R5 and R4B packages. |
| 80 | +* **Legacy** - the entry has **no** such extension: it applies to every version, and for |
| 81 | + each variant the historical package-id suffix rename applies (`.r5` → `.r4`, |
| 82 | + with R4B forced to `.r4` for wire-compatibility). |
| 83 | + |
| 84 | +The effective per-version dependencies drive each variant package's `dependsOn` and are |
| 85 | +surfaced in the rendered dependency table. A version-scoped entry is never loaded, |
| 86 | +validated, rendered, or packaged for a version it does not apply to. |
| 87 | + |
| 88 | +## 4 Per-version resource membership |
| 89 | + |
| 90 | +By default every resource is written into every generated package. To scope a resource |
| 91 | +to particular version(s), use the inclusion parameters: |
| 92 | + |
| 93 | +* `r4-inclusion` - value is a resource `Type/id` or canonical URL |
| 94 | +* `r4b-inclusion` |
| 95 | +* `r5-inclusion` |
| 96 | + |
| 97 | +These use **tag-membership** semantics: |
| 98 | + |
| 99 | +* A resource listed in **any** inclusion set appears **only** in the listed version(s). |
| 100 | +* A resource listed in **no** inclusion set appears in **all** versions (the default). |
| 101 | + |
| 102 | +`r5-inclusion` also gates the base R5 package, so a resource can be scoped away from R5 |
| 103 | +entirely (e.g. an R4-only resource authored in R5). Membership governs *package* |
| 104 | +membership only; the R5 site rendering is unchanged. |
| 105 | + |
| 106 | +> The legacy `r4-exclusion` / `r4b-exclusion` parameters are unrelated to this feature - |
| 107 | +> they continue to drive the legacy R4↔R4B path only and are not consulted for an R5 base. |
| 108 | +
|
| 109 | +## 5 Cross-version analysis |
| 110 | + |
| 111 | +For an R5 base with `generate-version`, a `cross-version-analysis` page reports, per |
| 112 | +target version: |
| 113 | + |
| 114 | +* conversion problems (from the `ProfileVersionAdaptor` conversion log for |
| 115 | + StructureDefinition/SearchParameter, and from conversion success/failure for the other |
| 116 | + conformance types and examples), and |
| 117 | +* resources intentionally omitted from that target via the inclusion parameters. |
| 118 | + |
| 119 | +A resource that uses an R5-only type that cannot be represented in R4/R4B yields a |
| 120 | +**warning** on this page (not a build failure); use the inclusion parameters to exclude |
| 121 | +it from the target(s) where it does not belong. |
| 122 | + |
| 123 | +## 6 Relationship to the legacy R4/R4B path |
| 124 | + |
| 125 | +An IG whose base version is **R4 or R4B** continues to use the original cross-version |
| 126 | +mechanism (`R4ToR4BAnalyser`), which re-parses the built package with the R4B parser and |
| 127 | +clones it into `.r4.tgz` / `.r4b.tgz`. That path is unchanged and is only entered for an |
| 128 | +R4/R4B base; an R5 base always uses the `generate-version` path described above. |
0 commit comments