Repository: FHIR/sushi
Pull request #1302 (2023-07-11 20:30:56)

Fix problems when setting values on child elements in primitive arrays
Completes task [CIMPL-1116](https://standardhealthrecord.atlassian.net/browse/CIMPL-1116).

Child elements of primitives are represented in JSON by using the name of the primitive element prefixed with an underscore. When the primitive element is also an array, create both the regular and underscore-prefixed arrays at the same time. When adding an element to one array, add a corresponding element to the other. Both arrays track slice names for sliced arrays. While this will sometimes result in the creation of arrays that contain no meaningful elements, these arrays are already cleaned up during export.

This PR changes the way soft index resolution works with `manualSliceOrdering` enabled to make it more accurately fulfill the requirement of "no access to elements with slice names without using the slice name." As a result, while the index values returned from `convertSoftIndicesStrict` have changed, the resulting instances are the same. A similar change is made in `createUsefulSlices`, which is used when `manualSliceOrdering` is enabled.

The useful outcomes of this PR are:
- The correct number of array elements are created when assigning values to a primitive array and its children.
- Cardinality requirements that apply to a primitive array and its children are correctly enforced. This has been observed in cases where the primitive array's `value` child is required on a defined slice, but not required in general.

As there are a lot of potential paths through the new code depending on the order in which primitive elements and their children are assigned, I tried to write tests as well as I could to achieve code coverage. Additionally, there were some places in my initial implementation where code coverage was logically impossible, and the unreachable code was removed. In particular, there are places in [`createUsefulSlices`](https://github.com/FHIR/sushi/compare/cimpl-1116-primitive-array?expand=1#diff-c3ea71b50f004cf55770cf8d3e9c5483a08b05e68093720ea2fd106da774ded6R196) and [`setPropertyOnInstance`](https://github.com/FHIR/sushi/compare/cimpl-1116-primitive-array?expand=1#diff-c3ea71b50f004cf55770cf8d3e9c5483a08b05e68093720ea2fd106da774ded6R659) where I think it is logically impossible to reach the code when `sliceName` is not null. Therefore, these code blocks do not attempt to use `sliceName`. I would appreciate a careful review of these sections in particular.

No changes appeared in the partial regression set. I'm going to be running a full regression tonight, and I will post the results in this thread.


mint-thompson: In the full regression set, I've discovered some problems with handling caret rules on a `type.profile.extension` and `type.targetProfile.extension`. I don't think this will require a complete overhaul, but some of the suggestions @cmoesel made may help with those scenarios.
mint-thompson: I've made some updates that resolve problems that occurred when assigning extensions on `type.targetProfile`. [The PACarePlan profile](https://github.com/HL7/physical-activity/blob/master/input/fsh/Planning.fsh#L71) does this, so that's how I caught it. The array fill on creation was something in my original implementation, but I removed it when I couldn't think of a test case to make it important. I'll have to keep extensions on types in mind for the future. These updates also make use of @cmoesel's suggestions for simplifying some of the branching logic.

Patch:
diff --git a/src/export/InstanceExporter.ts b/src/export/InstanceExporter.ts
index 3e00e1b..781c0ba 100644
--- a/src/export/InstanceExporter.ts
+++ b/src/export/InstanceExporter.ts
@@ -480,10 +480,17 @@ export class InstanceExporter implements Fishable {
       // 2 - The child element is n..m, but it has k < n elements
       // there's a special exception for the "value" child of a primitive,
       // since the actual value may be present on the parent primitive element.
+      // if the parent primitive is an object, the value will be in the "assignedValue" attribute.
+      // otherwise, the value is the parent primitive itself.
       if (
         (child.min > 0 &&
           instanceChild == null &&
-          !(child.id.endsWith('.value') && parentPrimitive != null)) ||
+          !(
+            child.id.endsWith('.value') &&
+            (typeof parentPrimitive === 'object'
+              ? parentPrimitive?.assignedValue
+              : parentPrimitive) != null
+          )) ||
         (Array.isArray(instanceChild) && instanceChild.length < child.min)
       ) {
         // Can't point to any specific rule, so give sourceInfo of entire instance
@@ -608,7 +615,7 @@ export class InstanceExporter implements Fishable {
                     ' See: https://hl7.org/fhir/uv/shorthand/reference.html#sliced-array-paths\n' +
                     `  Path:  ${slicingEl.path}\n` +
                     `  Slice: ${matchedNames.join(' or ')}\n` +
-                    `  Value: ${valueString}}`,
+                    `  Value: ${valueString}`,
                   fshDef.sourceInfo
                 );
               } else {
diff --git a/src/fhirtypes/common.ts b/src/fhirtypes/common.ts
index b691405..0309756 100644
--- a/src/fhirtypes/common.ts
+++ b/src/fhirtypes/common.ts
@@ -101,16 +101,22 @@ export function createUsefulSlices(
 
         // If this is a primitive and the path continues to a nested element of the primitive,
         // then we need to look at the special property that starts with _ instead.
-        const key =
-          pathPart.primitive && i < pathParts.length - 1 ? `_${pathPart.base}` : pathPart.base;
-
+        let key: string;
+        if (pathPart.primitive && i < pathParts.length - 1) {
+          key = `_${pathPart.base}`;
+        } else {
+          key = pathPart.base;
+        }
         const ruleIndex = getArrayIndex(pathPart);
         let effectiveIndex = ruleIndex;
         let sliceName: string;
         if (ruleIndex != null) {
           // If the array doesn't exist, create it
-          if (current[key] == null) {
-            current[key] = [];
+          if (pathPart.primitive) {
+            current[pathPart.base] ??= [];
+            current[`_${pathPart.base}`] ??= [];
+          } else {
+            current[key] ??= [];
           }
           sliceName = pathPart.brackets ? getSliceName(pathPart) : null;
           if (sliceName) {
@@ -145,7 +151,7 @@ export function createUsefulSlices(
              * So we should put the rule at the end of the component, which is effectiveIndex = 3
              */
             if (ruleIndex >= sliceIndices.length) {
-              effectiveIndex = ruleIndex - sliceIndices.length + current[key].length;
+              effectiveIndex = ruleIndex - sliceIndices.length + current[pathPart.base].length;
             } else {
               effectiveIndex = sliceIndices[ruleIndex];
             }
@@ -153,7 +159,7 @@ export function createUsefulSlices(
             // This is an array entry that does not have a named slice (so a typical numeric index)
             knownSlices.set(
               currentPath,
-              Math.max(ruleIndex + 1, knownSlices.get(currentPath) ?? 0)
+              Math.max(effectiveIndex + 1, knownSlices.get(currentPath) ?? 0)
             );
           }
           if (pathPart.brackets != null) {
@@ -170,15 +176,35 @@ export function createUsefulSlices(
               j === effectiveIndex &&
               current[key][effectiveIndex] == null
             ) {
-              current[key][effectiveIndex] = {};
+              if (pathPart.primitive) {
+                current[pathPart.base][effectiveIndex] = {};
+                current[`_${pathPart.base}`][effectiveIndex] = {};
+              } else {
+                current[key][effectiveIndex] = {};
+              }
             } else if (j >= current[key].length) {
               if (sliceName) {
                 // _sliceName is used to later differentiate which slice an element represents
-                current[key].push({ _sliceName: sliceName });
+                if (pathPart.primitive) {
+                  current[pathPart.base].push({ _sliceName: sliceName });
+                  current[`_${pathPart.base}`].push({ _sliceName: sliceName });
+                } else {
+                  current[key].push({ _sliceName: sliceName });
+                }
               } else if (j === effectiveIndex) {
-                current[key].push({});
+                if (pathPart.primitive) {
+                  current[pathPart.base].push({});
+                  current[`_${pathPart.base}`].push({});
+                } else {
+                  current[key].push({});
+                }
               } else {
-                current[key].push(null);
+                if (pathPart.primitive) {
+                  current[pathPart.base].push(null);
+                  current[`_${pathPart.base}`].push(null);
+                } else {
+                  current[key].push(null);
+                }
               }
             }
           }
@@ -402,8 +428,23 @@ export function setImpliedPropertiesOnInstance(
       }
       // check the children for instance of this element
       const children = currentElement.def.children(true);
+      // special handling: if our current element has no slice name, we need guarantee the defined minimum
+      // this is the only place where we do this, in order to accomodate cases where some named slices already exist
+      let existingSliceCount = 0;
+      if (finalMin < currentElement.def.min && currentElement.def.sliceName == null) {
+        // our final min was lowered by slices, so add that to our indices.
+        const slicePaths = currentElement.def
+          .getSlices()
+          .map(el => `${tracePath}[${el.sliceName}]`);
+        slicePaths.forEach(slicePath => {
+          if (knownSlices.has(slicePath)) {
+            existingSliceCount += knownSlices.get(slicePath);
+          }
+        });
+      }
       for (let idx = 0; idx < finalMin; idx++) {
-        const newHistory = traceParts.slice(-1)[0] + (idx > 0 ? `[${idx}]` : '');
+        const effectiveIdx = idx + existingSliceCount;
+        const newHistory = traceParts.slice(-1)[0] + (effectiveIdx > 0 ? `[${effectiveIdx}]` : '');
         elementsToCheck.push(
           ...children.map(
             child =>
@@ -502,7 +543,7 @@ export function setImpliedPropertiesOnInstance(
   }
   sortedRulePaths.forEach(path => {
     const { pathParts } = instanceOfStructureDefinition.validateValueAtPath(path, null, fisher);
-    setPropertyOnInstance(instanceDef, pathParts, sdRuleMap.get(path), fisher, manualSliceOrdering);
+    setPropertyOnInstance(instanceDef, pathParts, sdRuleMap.get(path), fisher);
   });
 }
 
@@ -544,8 +585,7 @@ export function setPropertyOnInstance(
   instance: StructureDefinition | ElementDefinition | InstanceDefinition | ValueSet | CodeSystem,
   pathParts: PathPart[],
   assignedValue: any,
-  fisher: Fishable,
-  manualSliceOrdering = false
+  fisher: Fishable
 ): void {
   if (assignedValue != null) {
     // If we can assign the value on the StructureDefinition StructureDefinition, then we can set the
@@ -554,14 +594,33 @@ export function setPropertyOnInstance(
     for (const [i, pathPart] of pathParts.entries()) {
       // When a primitive has child elements, a _ is appended to the name of the primitive
       // According to https://www.hl7.org/fhir/json.html#primitive
-      const key =
-        pathPart.primitive && i < pathParts.length - 1 ? `_${pathPart.base}` : pathPart.base;
+      let key: string;
+      if (pathPart.primitive && i < pathParts.length - 1) {
+        key = `_${pathPart.base}`;
+      } else {
+        key = pathPart.base;
+      }
       // If this part of the path indexes into an array, the index will be the last bracket
       let index = getArrayIndex(pathPart);
       let sliceName: string;
       if (index != null) {
-        // If the array doesn't exist, create it
-        if (current[key] == null) current[key] = [];
+        if (pathPart.primitive) {
+          // we may need to create or update one or both arrays
+          if (current[pathPart.base] == null) {
+            current[pathPart.base] =
+              current[`_${pathPart.base}`]?.map((x: any) =>
+                x?._sliceName != null ? { _sliceName: x._sliceName } : null
+              ) ?? [];
+          }
+          if (current[`_${pathPart.base}`] == null) {
+            current[`_${pathPart.base}`] = current[pathPart.base].map((x: any) =>
+              x?._sliceName != null ? { _sliceName: x._sliceName } : null
+            );
+          }
+        } else if (current[key] == null) {
+          // if the array doesn't exist, create it
+          current[key] = [];
+        }
         sliceName = getSliceName(pathPart);
         if (sliceName) {
           const sliceIndices: number[] = [];
@@ -581,33 +640,41 @@ export function setPropertyOnInstance(
           } else {
             index = sliceIndices[index];
           }
-        } else if (manualSliceOrdering) {
-          const sliceIndices: number[] = [];
-          current[pathPart.base]?.forEach((el: any, i: number) => {
-            if (el?._sliceName == null) {
-              sliceIndices.push(i);
-            }
-          });
-          // Convert the index in terms of the slice to the corresponding index in the overall array
-          if (index >= sliceIndices.length) {
-            index = index - sliceIndices.length + current[key].length;
-          } else {
-            index = sliceIndices[index];
-          }
         }
         // If the index doesn't exist in the array, add it and lesser indices
         // Empty elements should be null, not undefined, according to https://www.hl7.org/fhir/json.html#primitive
         for (let j = 0; j <= index; j++) {
           if (j < current[key].length && j === index && current[key][index] == null) {
-            current[key][index] = {};
+            if (pathPart.primitive) {
+              // a value may already exist on one of the arrays, so only assign an empty object if it is nullish
+              current[pathPart.base][index] ??= {};
+              current[`_${pathPart.base}`][index] ??= {};
+            } else {
+              current[key][index] = {};
+            }
           } else if (j >= current[key].length) {
             if (sliceName) {
               // _sliceName is used to later differentiate which slice an element represents
-              current[key].push({ _sliceName: sliceName });
+              if (pathPart.primitive) {
+                current[pathPart.base].push({ _sliceName: sliceName });
+                current[`_${pathPart.base}`].push({ _sliceName: sliceName });
+              } else {
+                current[key].push({ _sliceName: sliceName });
+              }
             } else if (j === index) {
-              current[key].push({});
+              if (pathPart.primitive) {
+                current[pathPart.base].push({});
+                current[`_${pathPart.base}`].push({});
+              } else {
+                current[key].push({});
+              }
             } else {
-              current[key].push(null);
+              if (pathPart.primitive) {
+                current[pathPart.base].push(null);
+                current[`_${pathPart.base}`].push(null);
+              } else {
+                current[key].push(null);
+              }
             }
           }
         }
diff --git a/src/utils/Processing.ts b/src/utils/Processing.ts
index 5a7b633..eb708e6 100644
--- a/src/utils/Processing.ts
+++ b/src/utils/Processing.ts
@@ -474,8 +474,15 @@ export function checkNullValuesOnArray(resource: any, parentName = '', priorPath
       }
       if (Array.isArray(property)) {
         const nullIndexes: number[] = [];
+        const hasUnderscoreArray = Array.isArray(resource[`_${propertyKey}`]);
         property.forEach((element: any, index: number) => {
-          if (element === null) nullIndexes.push(index);
+          // if property is a primitive array, also check the corresponding index in the underscore property
+          if (
+            element === null &&
+            (!hasUnderscoreArray || resource[`_${propertyKey}`][index] == null)
+          ) {
+            nullIndexes.push(index);
+          }
           if (isPlainObject(element)) {
             // If we encounter an object property, we'll want to check its properties as well
             checkNullValuesOnArray(element, resourceName, `${currentPath}[${index}]`);


Test patch:
diff --git a/test/export/InstanceExporter.test.ts b/test/export/InstanceExporter.test.ts
index 9e031dc..b5b61c4 100644
--- a/test/export/InstanceExporter.test.ts
+++ b/test/export/InstanceExporter.test.ts
@@ -4606,6 +4606,342 @@ describe('InstanceExporter', () => {
         expect(exportedInstance.rest[0].resource[0]).toBeNull();
         expect(exportedInstance.rest[0].resource[1]).toEqual({ type: 'type' });
       });
+
+      it('should assign extensions on elements of a primitive array', () => {
+        // Instance: MyAllergies
+        // InstanceOf: AllergyIntolerance
+        // * patient = Reference(SomePatient)
+        // * category[0] = #environment
+        // * category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        // * category[2] = #food
+        const instance = new Instance('MyAllergies');
+        instance.instanceOf = 'AllergyIntolerance';
+        const patientReference = new AssignmentRule('patient');
+        patientReference.value = new FshReference('SomePatient');
+        const categoryEnvironment = new AssignmentRule('category[0]');
+        categoryEnvironment.value = new FshCode('environment');
+        const categoryExtension = new AssignmentRule(
+          'category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        categoryExtension.value = new FshCode('unknown');
+        const categoryFood = new AssignmentRule('category[2]');
+        categoryFood.value = new FshCode('food');
+        instance.rules.push(patientReference, categoryEnvironment, categoryExtension, categoryFood);
+        const exportedInstance = exportInstance(instance);
+        expect(exportedInstance.category).toHaveLength(3);
+        expect(exportedInstance.category[0]).toBe('environment');
+        expect(exportedInstance.category[1]).toBeNull();
+        expect(exportedInstance.category[2]).toBe('food');
+        expect(exportedInstance._category).toHaveLength(3);
+        expect(exportedInstance._category[0]).toBeNull();
+        expect(exportedInstance._category[1]).toEqual({
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+              valueCode: 'unknown'
+            }
+          ]
+        });
+        expect(exportedInstance._category[2]).toBeNull();
+        expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
+      });
+
+      it('should assign extensions on elements of a primitive array when extensions are assigned before the values', () => {
+        // Instance: MyAllergies
+        // InstanceOf: AllergyIntolerance
+        // * patient = Reference(SomePatient)
+        // * category[0].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        // * category[1] = #environment
+        // * category[2] = #food
+        const instance = new Instance('MyAllergies');
+        instance.instanceOf = 'AllergyIntolerance';
+        const patientReference = new AssignmentRule('patient');
+        patientReference.value = new FshReference('SomePatient');
+        const categoryExtension = new AssignmentRule(
+          'category[0].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        categoryExtension.value = new FshCode('unknown');
+        const categoryEnvironment = new AssignmentRule('category[1]');
+        categoryEnvironment.value = new FshCode('environment');
+        const categoryFood = new AssignmentRule('category[2]');
+        categoryFood.value = new FshCode('food');
+        instance.rules.push(patientReference, categoryExtension, categoryEnvironment, categoryFood);
+        const exportedInstance = exportInstance(instance);
+        expect(exportedInstance.category).toHaveLength(3);
+        expect(exportedInstance.category[0]).toBeNull();
+        expect(exportedInstance.category[1]).toBe('environment');
+        expect(exportedInstance.category[2]).toBe('food');
+        expect(exportedInstance._category).toHaveLength(3);
+        expect(exportedInstance._category[0]).toEqual({
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+              valueCode: 'unknown'
+            }
+          ]
+        });
+        expect(exportedInstance._category[1]).toBeNull();
+        expect(exportedInstance._category[2]).toBeNull();
+        expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
+      });
+
+      it('should assign extensions and values on out-of-order elements on a primitive array', () => {
+        // Instance: MyAllergies
+        // InstanceOf: AllergyIntolerance
+        // * patient = Reference(SomePatient)
+        // * category[2] = #food
+        // * category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        // * category[0] = #environment
+        const instance = new Instance('MyAllergies');
+        instance.instanceOf = 'AllergyIntolerance';
+        const patientReference = new AssignmentRule('patient');
+        patientReference.value = new FshReference('SomePatient');
+        const categoryFood = new AssignmentRule('category[2]');
+        categoryFood.value = new FshCode('food');
+        const categoryExtension = new AssignmentRule(
+          'category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        categoryExtension.value = new FshCode('unknown');
+        const categoryEnvironment = new AssignmentRule('category[0]');
+        categoryEnvironment.value = new FshCode('environment');
+        instance.rules.push(patientReference, categoryFood, categoryExtension, categoryEnvironment);
+
+        const exportedInstance = exportInstance(instance);
+        expect(exportedInstance.category).toHaveLength(3);
+        expect(exportedInstance.category[0]).toBe('environment');
+        expect(exportedInstance.category[1]).toBeNull();
+        expect(exportedInstance.category[2]).toBe('food');
+        expect(exportedInstance._category).toHaveLength(3);
+        expect(exportedInstance._category[0]).toBeNull();
+        expect(exportedInstance._category[1]).toEqual({
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+              valueCode: 'unknown'
+            }
+          ]
+        });
+        expect(exportedInstance._category[2]).toBeNull();
+        expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
+      });
+
+      it('should assign extensions and values on out-of-order elements on a primitive array when extensions are assigned before values', () => {
+        // Instance: MyAllergies
+        // InstanceOf: AllergyIntolerance
+        // * patient = Reference(SomePatient)
+        // * category[2].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        // * category[1] = #food
+        // * category[0] = #environment
+        const instance = new Instance('MyAllergies');
+        instance.instanceOf = 'AllergyIntolerance';
+        const patientReference = new AssignmentRule('patient');
+        patientReference.value = new FshReference('SomePatient');
+        const categoryExtension = new AssignmentRule(
+          'category[2].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        categoryExtension.value = new FshCode('unknown');
+        const categoryFood = new AssignmentRule('category[1]');
+        categoryFood.value = new FshCode('food');
+        const categoryEnvironment = new AssignmentRule('category[0]');
+        categoryEnvironment.value = new FshCode('environment');
+        instance.rules.push(patientReference, categoryExtension, categoryFood, categoryEnvironment);
+
+        const exportedInstance = exportInstance(instance);
+        expect(exportedInstance.category).toHaveLength(3);
+        expect(exportedInstance.category[0]).toBe('environment');
+        expect(exportedInstance.category[1]).toBe('food');
+        expect(exportedInstance.category[2]).toBeNull();
+        expect(exportedInstance._category).toHaveLength(3);
+        expect(exportedInstance._category[0]).toBeNull();
+        expect(exportedInstance._category[1]).toBeNull();
+        expect(exportedInstance._category[2]).toEqual({
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+              valueCode: 'unknown'
+            }
+          ]
+        });
+        expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
+      });
+
+      it('should assign values and extensions on elements of a primitive array at the same index', () => {
+        // Instance: MyAllergies
+        // InstanceOf: AllergyIntolerance
+        // * patient = Reference(SomePatient)
+        // * category[0].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        // * category[0] = #environment
+        // * category[1] = #food
+        const instance = new Instance('MyAllergies');
+        instance.instanceOf = 'AllergyIntolerance';
+        const patientReference = new AssignmentRule('patient');
+        patientReference.value = new FshReference('SomePatient');
+        const categoryExtension = new AssignmentRule(
+          'category[0].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        categoryExtension.value = new FshCode('unknown');
+        const categoryEnvironment = new AssignmentRule('category[0]');
+        categoryEnvironment.value = new FshCode('environment');
+        const categoryFood = new AssignmentRule('category[1]');
+        categoryFood.value = new FshCode('food');
+        instance.rules.push(patientReference, categoryExtension, categoryEnvironment, categoryFood);
+
+        const exportedInstance = exportInstance(instance);
+        expect(exportedInstance.category).toHaveLength(2);
+        expect(exportedInstance.category[0]).toBe('environment');
+        expect(exportedInstance.category[1]).toBe('food');
+        expect(exportedInstance._category).toHaveLength(2);
+        expect(exportedInstance._category[0]).toEqual({
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+              valueCode: 'unknown'
+            }
+          ]
+        });
+        expect(exportedInstance._category[1]).toBeNull();
+        expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
+      });
+
+      it('should assign extensions on elements of a sliced primitive array', () => {
+        // Profile: SlicedAllergyIntolerance
+        // Parent: AllergyIntolerance
+        // * category ^slicing.discriminator.type = #value
+        // * category ^slicing.discriminator.path = "$this"
+        // * category ^slicing.rules = #open
+        // * category contains Primary 0..* and Secondary 0..*
+        const profile = new Profile('SlicedAllergyIntolerance');
+        profile.parent = 'AllergyIntolerance';
+        const slicingType = new CaretValueRule('category');
+        slicingType.caretPath = 'slicing.discriminator.type';
+        slicingType.value = new FshCode('value');
+        const slicingPath = new CaretValueRule('category');
+        slicingPath.caretPath = 'slicing.discriminator.path';
+        slicingPath.value = '$this';
+        const slicingRules = new CaretValueRule('category');
+        slicingRules.caretPath = 'slicing.rules';
+        slicingRules.value = new FshCode('open');
+        const categoryContains = new ContainsRule('category');
+        categoryContains.items = [{ name: 'Primary' }, { name: 'Secondary' }];
+        const primaryCard = new CardRule('category[Primary]');
+        primaryCard.min = 0;
+        primaryCard.max = '*';
+        const secondaryCard = new CardRule('category[Secondary]');
+        secondaryCard.min = 0;
+        secondaryCard.max = '*';
+        profile.rules.push(
+          slicingType,
+          slicingPath,
+          slicingRules,
+          categoryContains,
+          primaryCard,
+          secondaryCard
+        );
+        doc.profiles.set(profile.name, profile);
+        // Instance: MyAllergies
+        // InstanceOf: SlicedAllergyIntolerance
+        // * patient = Reference(SomePatient)
+        // * category[Secondary][+] = #environment
+        // * category[Primary][+] = #food
+        // * category[Primary][+].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        // * category[Primary][+] = #medication
+        // * category[+].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        const instance = new Instance('MyAllergies');
+        instance.instanceOf = 'SlicedAllergyIntolerance';
+        const patientReference = new AssignmentRule('patient');
+        patientReference.value = new FshReference('SomePatient');
+        const secondaryEnvironment = new AssignmentRule('category[Secondary][+]');
+        secondaryEnvironment.value = new FshCode('environment');
+        const primaryFood = new AssignmentRule('category[Primary][+]');
+        primaryFood.value = new FshCode('food');
+        const primaryExtension = new AssignmentRule(
+          'category[Primary][+].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        primaryExtension.value = new FshCode('unknown');
+        const unnamedExtension = new AssignmentRule(
+          'category[+].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        const primaryMedication = new AssignmentRule('category[Primary][+]');
+        primaryMedication.value = new FshCode('medication');
+        unnamedExtension.value = new FshCode('unknown');
+        instance.rules.push(
+          patientReference,
+          secondaryEnvironment,
+          primaryFood,
+          primaryExtension,
+          primaryMedication,
+          unnamedExtension
+        );
+
+        const exported = exportInstance(instance);
+        expect(exported.category).toHaveLength(5);
+        expect(exported.category).toEqual(['environment', 'food', null, 'medication', null]);
+        expect(exported._category).toHaveLength(5);
+        expect(exported._category).toEqual([
+          null,
+          null,
+          {
+            extension: [
+              {
+                url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+                valueCode: 'unknown'
+              }
+            ]
+          },
+          null,
+          {
+            extension: [
+              {
+                url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+                valueCode: 'unknown'
+              }
+            ]
+          }
+        ]);
+        expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
+      });
+
+      it('should log an error when a required primitive value element is missing on the second element of a parent array primitive, with strict slice ordering enabled', () => {
+        // Profile: TestAllergyIntolerance
+        // Parent: AllergyIntolerance
+        // * category 1..*
+        // * category.value 1..1
+        // * patient = Reference(SomePatient)
+        const allergyProfile = new Profile('TestAllergyIntolerance');
+        allergyProfile.parent = 'AllergyIntolerance';
+        const categoryCard = new CardRule('category');
+        categoryCard.min = 1;
+        categoryCard.max = '*';
+        const valueCard = new CardRule('category.value');
+        valueCard.min = 1;
+        valueCard.max = '1';
+        const patientValue = new AssignmentRule('patient');
+        patientValue.value = new FshReference('SomePatient');
+        allergyProfile.rules.push(categoryCard, valueCard, patientValue);
+        doc.profiles.set(allergyProfile.name, allergyProfile);
+        // Instance: MyAllergies
+        // InstanceOf: TestAllergyIntolerance
+        // * category[0] = #environment
+        // * category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+        const allergyInstance = new Instance('MyAllergies')
+          .withFile('AllergyInstance.fsh')
+          .withLocation([14, 3, 21, 28]);
+        allergyInstance.instanceOf = 'TestAllergyIntolerance';
+        const environmentCategory = new AssignmentRule('category[0]');
+        environmentCategory.value = new FshCode('environment');
+        const unknownCategory = new AssignmentRule(
+          'category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+        );
+        unknownCategory.value = new FshCode('unknown');
+        allergyInstance.rules.push(environmentCategory, unknownCategory);
+        doc.instances.set(allergyInstance.name, allergyInstance);
+
+        exportInstance(allergyInstance);
+        expect(loggerSpy.getAllMessages('error')).toHaveLength(1);
+        expect(loggerSpy.getLastMessage('error')).toMatch(
+          /Element AllergyIntolerance.category.value has minimum cardinality 1.*File: AllergyInstance\.fsh.*Line: 14 - 21/s
+        );
+      });
     });
 
     it('should only create optional slices that are defined even if sibling in array has more slices than other siblings', () => {
@@ -4803,6 +5139,40 @@ describe('InstanceExporter', () => {
       expect(exported.address[0]._line[1].extension[0].url).toBe('foo');
     });
 
+    it('should assign extensions and values on out-of-order elements on a primitive array', () => {
+      // Instance: MyAllergies
+      // InstanceOf: AllergyIntolerance
+      // * patient = Reference(SomePatient)
+      // * category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
+      // * category[0] = #environment
+      const instance = new Instance('MyAllergies');
+      instance.instanceOf = 'AllergyIntolerance';
+      const patientReference = new AssignmentRule('patient');
+      patientReference.value = new FshReference('SomePatient');
+      const categoryValue = new AssignmentRule('category[0]');
+      categoryValue.value = new FshCode('environment');
+      const categoryExtension = new AssignmentRule(
+        'category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
+      );
+      categoryExtension.value = new FshCode('unknown');
+      instance.rules.push(patientReference, categoryExtension, categoryValue);
+
+      const exportedInstance = exportInstance(instance);
+      expect(exportedInstance.category).toHaveLength(2);
+      expect(exportedInstance.category[0]).toBe('environment');
+      expect(exportedInstance._category).toHaveLength(2);
+      expect(exportedInstance._category[0]).toBeNull();
+      expect(exportedInstance._category[1]).toEqual({
+        extension: [
+          {
+            url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+            valueCode: 'unknown'
+          }
+        ]
+      });
+      expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
+    });
+
     it('should assign children of primitive value arrays on an instance with out of order rules', () => {
       const assignedValRule1 = new AssignmentRule('address[0].line[1].extension[0].url');
       assignedValRule1.value = 'bar';
@@ -6901,10 +7271,6 @@ describe('InstanceExporter', () => {
       );
     });
 
-    it.skip('should assign sliced elements on a sliced primitive', () => {
-      /* Need example of sliced primitive */
-    });
-
     // Content Reference
     it('should assign a child of a contentReference element', () => {
       const barRule = new AssignmentRule('compose.exclude.version');
@@ -7348,52 +7714,7 @@ describe('InstanceExporter', () => {
       );
     });
 
-    it.skip('should log an error when a required primitive value element is missing on the second element of a parent array primitive, with manual slice ordering enabled', () => {
-      // this should work once the existing problems with extensions on array primitives are resolved
-      tank.config.instanceOptions = { manualSliceOrdering: true };
-      // Profile: TestAllergyIntolerance
-      // Parent: AllergyIntolerance
-      // * category 1..*
-      // * category.value 1..1
-      // * patient = Reference(SomePatient)
-      const allergyProfile = new Profile('TestAllergyIntolerance');
-      allergyProfile.parent = 'AllergyIntolerance';
-      const categoryCard = new CardRule('category');
-      categoryCard.min = 1;
-      categoryCard.max = '*';
-      const valueCard = new CardRule('category.value');
-      valueCard.min = 1;
-      valueCard.max = '1';
-      const patientValue = new AssignmentRule('patient');
-      patientValue.value = new FshReference('SomePatient');
-      allergyProfile.rules.push(categoryCard, valueCard, patientValue);
-      doc.profiles.set(allergyProfile.name, allergyProfile);
-      // Instance: MyAllergies
-      // InstanceOf: TestAllergyIntolerance
-      // * category[0] = #environment
-      // * category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode = #unknown
-      const allergyInstance = new Instance('MyAllergies')
-        .withFile('AllergyInstance.fsh')
-        .withLocation([14, 3, 21, 28]);
-      allergyInstance.instanceOf = 'TestAllergyIntolerance';
-      const environmentCategory = new AssignmentRule('category[0]');
-      environmentCategory.value = new FshCode('environment');
-      const unknownCategory = new AssignmentRule(
-        'category[1].extension[http://hl7.org/fhir/StructureDefinition/data-absent-reason].valueCode'
-      );
-      unknownCategory.value = new FshCode('unknown');
-      allergyInstance.rules.push(environmentCategory, unknownCategory);
-      doc.instances.set(allergyInstance.name, allergyInstance);
-
-      exportInstance(allergyInstance);
-      expect(loggerSpy.getAllMessages('error')).toHaveLength(1);
-      expect(loggerSpy.getLastMessage('error')).toMatch(
-        /Element AllergyIntolerance.category.value has minimum cardinality 1.*File: AllergyInstance\.fsh.*Line: 14 - 21/s
-      );
-    });
-
-    it.skip('should log an error when a required primitive value element is missing on the parent sliced array primitive', () => {
-      // this should work once the existing problems with extensions on array primitives are resolved
+    it('should log an error when a required primitive value element is missing on the parent sliced array primitive', () => {
       // Profile: SlicedAllergyIntolerance
       // Parent: AllergyIntolerance
       // * category 1..*
@@ -7467,10 +7788,35 @@ describe('InstanceExporter', () => {
       allergyInstance.rules.push(flexibleZero, flexibleOne, strictZero, strictOne);
       doc.instances.set(allergyInstance.name, allergyInstance);
 
-      exportInstance(allergyInstance);
+      const exported = exportInstance(allergyInstance);
+      // because manual slice ordering is off, the slice order in category is:
+      // Flexible[0], Strict[0], Strict[1], Flexible[1]
+      expect(exported.category).toHaveLength(4);
+      expect(exported.category).toEqual([null, 'food', null, 'environment']);
+      expect(exported._category).toHaveLength(4);
+      expect(exported._category).toEqual([
+        {
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+              valueCode: 'unknown'
+            }
+          ]
+        },
+        null,
+        {
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/data-absent-reason',
+              valueCode: 'unknown'
+            }
+          ]
+        },
+        null
+      ]);
       expect(loggerSpy.getAllMessages('error')).toHaveLength(1);
       expect(loggerSpy.getLastMessage('error')).toMatch(
-        /Element AllergyIntolerance.category\[Strict\].value has minimum cardinality 1.*File: AllergyInstance\.fsh.*Line: 15 - 22/s
+        /Element AllergyIntolerance.category:Strict\.value has minimum cardinality 1.*File: AllergyInstance\.fsh.*Line: 15 - 22/s
       );
     });
 
diff --git a/test/export/StructureDefinitionExporter.test.ts b/test/export/StructureDefinitionExporter.test.ts
index dca4c42..8fa2cbe 100644
--- a/test/export/StructureDefinitionExporter.test.ts
+++ b/test/export/StructureDefinitionExporter.test.ts
@@ -91,6 +91,19 @@ describe('StructureDefinitionExporter R4', () => {
       ).trim()
     );
     defs.add(pastPlanet);
+    const typeMustSupport = JSON.parse(
+      readFileSync(
+        path.join(
+          __dirname,
+          '..',
+          'testhelpers',
+          'testdefs',
+          'StructureDefinition-elementdefinition-type-must-support.json'
+        ),
+        'utf-8'
+      ).trim()
+    );
+    defs.add(typeMustSupport);
     loadFromPath(path.join(__dirname, '..', 'testhelpers', 'testdefs'), 'r4-definitions', defs);
   });
 
@@ -7595,6 +7608,63 @@ describe('StructureDefinitionExporter R4', () => {
         valueString: 'ChildName'
       });
     });
+
+    it('should apply CaretValueRules on the targetProfile of a type', () => {
+      // Alias: $typeMS = http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support
+      doc.aliases.set(
+        '$typeMS',
+        'http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support'
+      );
+      // Profile: MyDiagnosticReport
+      // Parent: DiagnosticReport
+      // * result only Reference(observation-bodyheight or observation-bodyweight)
+      //   * ^type[0].targetProfile[0].extension[$typeMS].valueBoolean = true
+      //   * ^type[0].targetProfile[1].extension[$typeMS].valueBoolean = true
+      const profile = new Profile('MyDiagnosticReport');
+      profile.parent = 'DiagnosticReport';
+      const resultOnly = new OnlyRule('result');
+      resultOnly.types = [
+        { type: 'observation-bodyheight', isReference: true },
+        { type: 'observation-bodyweight', isReference: true }
+      ];
+      const firstExtension = new CaretValueRule('result');
+      firstExtension.caretPath = 'type[0].targetProfile[0].extension[$typeMS].valueBoolean';
+      firstExtension.value = true;
+      const secondExtension = new CaretValueRule('result');
+      secondExtension.caretPath = 'type[0].targetProfile[1].extension[$typeMS].valueBoolean';
+      secondExtension.value = true;
+      profile.rules.push(resultOnly, firstExtension, secondExtension);
+
+      exporter.exportStructDef(profile);
+      const sd = pkg.profiles[0];
+
+      const ed = sd.elements.find(e => e.id === 'DiagnosticReport.result');
+      expect(ed.type).toHaveLength(1);
+      const expectedType = new ElementDefinitionType('Reference').withTargetProfiles(
+        'http://hl7.org/fhir/StructureDefinition/bodyheight',
+        'http://hl7.org/fhir/StructureDefinition/bodyweight'
+      );
+      expectedType._targetProfile = [
+        {
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support',
+              valueBoolean: true
+            }
+          ]
+        },
+        {
+          extension: [
+            {
+              url: 'http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support',
+              valueBoolean: true
+            }
+          ]
+        }
+      ];
+      expect(ed.type[0]).toEqual(expectedType);
+      expect(loggerSpy.getAllMessages()).toHaveLength(0);
+    });
   });
 
   describe('#ObeysRule', () => {
diff --git a/test/fhirtypes/ElementDefinition.setInstancePropertyByPath.test.ts b/test/fhirtypes/ElementDefinition.setInstancePropertyByPath.test.ts
index ea2fb6c..2e25743 100644
--- a/test/fhirtypes/ElementDefinition.setInstancePropertyByPath.test.ts
+++ b/test/fhirtypes/ElementDefinition.setInstancePropertyByPath.test.ts
@@ -100,7 +100,10 @@ describe('ElementDefinition', () => {
     it('should change a part of an instance property in an array', () => {
       status.setInstancePropertyByPath('type[0].profile[0]', 'foo', fisher);
       expect(status.type.length).toBe(1);
-      expect(status.type[0]).toEqual(new ElementDefinitionType('code').withProfiles('foo'));
+      // setting an element in the profile array creates an empty element at the corresponding index in the _profile array
+      const expectedType = new ElementDefinitionType('code').withProfiles('foo');
+      expectedType._profile = [{}];
+      expect(status.type[0]).toEqual(expectedType);
     });
 
     // Complex values
diff --git a/test/testhelpers/testdefs/StructureDefinition-elementdefinition-type-must-support.json b/test/testhelpers/testdefs/StructureDefinition-elementdefinition-type-must-support.json
new file mode 100644
index 0000000..560da2f
--- /dev/null
+++ b/test/testhelpers/testdefs/StructureDefinition-elementdefinition-type-must-support.json
@@ -0,0 +1,251 @@
+{
+  "resourceType" : "StructureDefinition",
+  "id" : "elementdefinition-type-must-support",
+  "text" : {
+    "status" : "extensions",
+    "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border: 0px #F0F0F0 solid; font-size: 11px; font-family: verdana; vertical-align: top;\"><tr style=\"border: 1px #F0F0F0 solid; font-size: 11px; font-family: verdana; vertical-align: top\"><th style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><a href=\"https://build.fhir.org/ig/FHIR/ig-guidance/readingIgs.html#table-views\" title=\"The logical name of the element\">Name</a></th><th style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><a href=\"https://build.fhir.org/ig/FHIR/ig-guidance/readingIgs.html#table-views\" title=\"Information about the use of the element\">Flags</a></th><th style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><a href=\"https://build.fhir.org/ig/FHIR/ig-guidance/readingIgs.html#table-views\" title=\"Minimum and Maximum # of times the the element can appear in the instance\">Card.</a></th><th style=\"width: 100px\" class=\"hierarchy\"><a href=\"https://build.fhir.org/ig/FHIR/ig-guidance/readingIgs.html#table-views\" title=\"Reference to the type of the element\">Type</a></th><th style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><a href=\"https://build.fhir.org/ig/FHIR/ig-guidance/readingIgs.html#table-views\" title=\"Additional information about the element\">Description &amp; Constraints</a><span style=\"float: right\"><a href=\"https://build.fhir.org/ig/FHIR/ig-guidance/readingIgs.html#table-views\" title=\"Legend for this format\"><img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goXBCwdPqAP0wAAAldJREFUOMuNk0tIlFEYhp9z/vE2jHkhxXA0zJCMitrUQlq4lnSltEqCFhFG2MJFhIvIFpkEWaTQqjaWZRkp0g26URZkTpbaaOJkDqk10szoODP//7XIMUe0elcfnPd9zsfLOYplGrpRwZaqTtw3K7PtGem7Q6FoidbGgqHVy/HRb669R+56zx7eRV1L31JGxYbBtjKK93cxeqfyQHbehkZbUkK20goELEuIzEd+dHS+qz/Y8PTSif0FnGkbiwcAjHaU1+QWOptFiyCLp/LnKptpqIuXHx6rbR26kJcBX3yLgBfnd7CxwJmflpP2wUg0HIAoUUpZBmKzELGWcN8nAr6Gpu7tLU/CkwAaoKTWRSQyt89Q8w6J+oVQkKnBoblH7V0PPvUOvDYXfopE/SJmALsxnVm6LbkotrUtNowMeIrVrBcBpaMmdS0j9df7abpSuy7HWehwJdt1lhVwi/J58U5beXGAF6c3UXLycw1wdFklArBn87xdh0ZsZtArghBdAA3+OEDVubG4UEzP6x1FOWneHh2VDAHBAt80IbdXDcesNoCvs3E5AFyNSU5nbrDPZpcUEQQTFZiEVx+51fxMhhyJEAgvlriadIJZZksRuwBYMOPBbO3hePVVqgEJhFeUuFLhIPkRP6BQLIBrmMenujm/3g4zc398awIe90Zb5A1vREALqneMcYgP/xVQWlG+Ncu5vgwwlaUNx+3799rfe96u9K0JSDXcOzOTJg4B6IgmXfsygc7/Bvg9g9E58/cDVmGIBOP/zT8Bz1zqWqpbXIsd0O9hajXfL6u4BaOS6SeWAAAAAElFTkSuQmCC\" alt=\"doco\" style=\"background-color: inherit\"/></a></span></th></tr><tr style=\"border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white\"><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck1.png)\" class=\"hierarchy\"><img src=\"tbl_spacer.png\" alt=\".\" style=\"background-color: inherit\" class=\"hierarchy\"/><img src=\"icon_element.gif\" alt=\".\" style=\"background-color: white; background-color: inherit\" title=\"Element\" class=\"hierarchy\"/> <a href=\"StructureDefinition-elementdefinition-type-must-support-definitions.html#Extension\" title=\"If true indicates that the specified type, profile or targetProfile must be supported by implementations.\">Extension</a><a name=\"Extension\"> </a></td><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"/><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\">0..1</td><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><a href=\"http://hl7.org/fhir/R5/extensibility.html#Extension\">Extension</a></td><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\">If true, the specified type/profile/target must be supported by implementations</td></tr>\r\n<tr style=\"border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7\"><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck10.png)\" class=\"hierarchy\"><img src=\"tbl_spacer.png\" alt=\".\" style=\"background-color: inherit\" class=\"hierarchy\"/><img src=\"tbl_vjoin.png\" alt=\".\" style=\"background-color: inherit\" class=\"hierarchy\"/><img src=\"icon_extension_simple.png\" alt=\".\" style=\"background-color: #F7F7F7; background-color: inherit\" title=\"Simple Extension\" class=\"hierarchy\"/> <span style=\"text-decoration:line-through\">extension</span><a name=\"Extension.extension\"> </a></td><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"/><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><span style=\"text-decoration:line-through\"/><span style=\"text-decoration:line-through\">0</span><span style=\"text-decoration:line-through\">..</span><span style=\"text-decoration:line-through\">0</span></td><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"/><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"/></tr>\r\n<tr style=\"border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white\"><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck10.png)\" class=\"hierarchy\"><img src=\"tbl_spacer.png\" alt=\".\" style=\"background-color: inherit\" class=\"hierarchy\"/><img src=\"tbl_vjoin.png\" alt=\".\" style=\"background-color: inherit\" class=\"hierarchy\"/><img src=\"icon_element.gif\" alt=\".\" style=\"background-color: white; background-color: inherit\" title=\"Element\" class=\"hierarchy\"/> <a href=\"StructureDefinition-elementdefinition-type-must-support-definitions.html#Extension.url\">url</a><a name=\"Extension.url\"> </a></td><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"/><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><span style=\"opacity: 0.5\">1</span><span style=\"opacity: 0.5\">..</span><span style=\"opacity: 0.5\">1</span></td><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><a style=\"opacity: 0.5\" href=\"http://hl7.org/fhir/R5/datatypes.html#uri\">uri</a></td><td style=\"vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><span style=\"color: darkgreen\">&quot;http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support&quot;</span></td></tr>\r\n<tr style=\"border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7\"><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck00.png)\" class=\"hierarchy\"><img src=\"tbl_spacer.png\" alt=\".\" style=\"background-color: inherit\" class=\"hierarchy\"/><img src=\"tbl_vjoin_end.png\" alt=\".\" style=\"background-color: inherit\" class=\"hierarchy\"/><img src=\"icon_primitive.png\" alt=\".\" style=\"background-color: #F7F7F7; background-color: inherit\" title=\"Primitive Data Type\" class=\"hierarchy\"/> <a href=\"StructureDefinition-elementdefinition-type-must-support-definitions.html#Extension.value[x]\">value[x]</a><a name=\"Extension.value_x_\"> </a></td><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"/><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\">1..<span style=\"opacity: 0.5\">1</span></td><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><a href=\"http://hl7.org/fhir/R5/datatypes.html#boolean\">boolean</a></td><td style=\"vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px\" class=\"hierarchy\"><span style=\"opacity: 0.5\">Value of extension</span></td></tr>\r\n<tr><td colspan=\"5\" class=\"hierarchy\"><br/><a href=\"https://build.fhir.org/ig/FHIR/ig-guidance/readingIgs.html#table-views\" title=\"Legend for this format\"><img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goXBCwdPqAP0wAAAldJREFUOMuNk0tIlFEYhp9z/vE2jHkhxXA0zJCMitrUQlq4lnSltEqCFhFG2MJFhIvIFpkEWaTQqjaWZRkp0g26URZkTpbaaOJkDqk10szoODP//7XIMUe0elcfnPd9zsfLOYplGrpRwZaqTtw3K7PtGem7Q6FoidbGgqHVy/HRb669R+56zx7eRV1L31JGxYbBtjKK93cxeqfyQHbehkZbUkK20goELEuIzEd+dHS+qz/Y8PTSif0FnGkbiwcAjHaU1+QWOptFiyCLp/LnKptpqIuXHx6rbR26kJcBX3yLgBfnd7CxwJmflpP2wUg0HIAoUUpZBmKzELGWcN8nAr6Gpu7tLU/CkwAaoKTWRSQyt89Q8w6J+oVQkKnBoblH7V0PPvUOvDYXfopE/SJmALsxnVm6LbkotrUtNowMeIrVrBcBpaMmdS0j9df7abpSuy7HWehwJdt1lhVwi/J58U5beXGAF6c3UXLycw1wdFklArBn87xdh0ZsZtArghBdAA3+OEDVubG4UEzP6x1FOWneHh2VDAHBAt80IbdXDcesNoCvs3E5AFyNSU5nbrDPZpcUEQQTFZiEVx+51fxMhhyJEAgvlriadIJZZksRuwBYMOPBbO3hePVVqgEJhFeUuFLhIPkRP6BQLIBrmMenujm/3g4zc398awIe90Zb5A1vREALqneMcYgP/xVQWlG+Ncu5vgwwlaUNx+3799rfe96u9K0JSDXcOzOTJg4B6IgmXfsygc7/Bvg9g9E58/cDVmGIBOP/zT8Bz1zqWqpbXIsd0O9hajXfL6u4BaOS6SeWAAAAAElFTkSuQmCC\" alt=\"doco\" style=\"background-color: inherit\"/> Documentation for this format</a></td></tr></table></div>"
+  },
+  "extension" : [{
+    "url" : "http://hl7.org/fhir/StructureDefinition/structuredefinition-wg",
+    "valueCode" : "fhir"
+  },
+  {
+    "url" : "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm",
+    "valueInteger" : 2
+  },
+  {
+    "url" : "http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status",
+    "valueCode" : "trial-use"
+  }],
+  "url" : "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support",
+  "version" : "1.0.0",
+  "name" : "TypeMustSupport",
+  "title" : "Type must support",
+  "status" : "draft",
+  "experimental" : false,
+  "date" : "2015-02-28",
+  "publisher" : "HL7 International / FHIR Infrastructure",
+  "contact" : [{
+    "telecom" : [{
+      "system" : "url",
+      "value" : "http://hl7.org/Special/committees/fhir-i"
+    }]
+  }],
+  "description" : "If true indicates that the specified type, profile or targetProfile must be supported by implementations.",
+  "jurisdiction" : [{
+    "coding" : [{
+      "system" : "http://unstats.un.org/unsd/methods/m49/m49.htm",
+      "code" : "001"
+    }]
+  }],
+  "fhirVersion" : "5.0.0",
+  "mapping" : [{
+    "identity" : "rim",
+    "uri" : "http://hl7.org/v3",
+    "name" : "RIM Mapping"
+  }],
+  "kind" : "complex-type",
+  "abstract" : false,
+  "context" : [{
+    "type" : "element",
+    "expression" : "ElementDefinition.type"
+  },
+  {
+    "type" : "element",
+    "expression" : "ElementDefinition.type.profile"
+  },
+  {
+    "type" : "element",
+    "expression" : "ElementDefinition.type.targetProfile"
+  }],
+  "type" : "Extension",
+  "baseDefinition" : "http://hl7.org/fhir/StructureDefinition/Extension",
+  "derivation" : "constraint",
+  "snapshot" : {
+    "element" : [{
+      "id" : "Extension",
+      "path" : "Extension",
+      "short" : "If true, the specified type/profile/target must be supported by implementations",
+      "definition" : "If true indicates that the specified type, profile or targetProfile must be supported by implementations.",
+      "comment" : "An element may be labelled as must support. This extension clarifies which types/profiles/targetProfiles are must-support. It has no meaning if the element itself is not must-support. If the element is labelled must-support, and none of the options are labelled as must support, then an application must support at least one of the possible options, but is not required to support all of them. Specific details on what it means to 'support' the specified profile will be defined either by the implementation guide, by the profile and/or in usage notes for the element holding the extension.  If this extension is not declared on a mustSupport element, the presumption is that implementations need only support one of the potential types unless other documentation in the specification explicitly dictates otherwise.",
+      "min" : 0,
+      "max" : "1",
+      "base" : {
+        "path" : "Extension",
+        "min" : 0,
+        "max" : "*"
+      },
+      "constraint" : [{
+        "key" : "ele-1",
+        "severity" : "error",
+        "human" : "All FHIR elements must have a @value or children",
+        "expression" : "hasValue() or (children().count() > id.count())",
+        "source" : "http://hl7.org/fhir/StructureDefinition/Element"
+      },
+      {
+        "key" : "ext-1",
+        "severity" : "error",
+        "human" : "Must have either extensions or value[x], not both",
+        "expression" : "extension.exists() != value.exists()",
+        "source" : "http://hl7.org/fhir/StructureDefinition/Extension"
+      }],
+      "isModifier" : false
+    },
+    {
+      "id" : "Extension.id",
+      "path" : "Extension.id",
+      "representation" : ["xmlAttr"],
+      "short" : "Unique id for inter-element referencing",
+      "definition" : "Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.",
+      "min" : 0,
+      "max" : "1",
+      "base" : {
+        "path" : "Element.id",
+        "min" : 0,
+        "max" : "1"
+      },
+      "type" : [{
+        "extension" : [{
+          "url" : "http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type",
+          "valueUrl" : "id"
+        }],
+        "code" : "http://hl7.org/fhirpath/System.String"
+      }],
+      "condition" : ["ele-1"],
+      "isModifier" : false,
+      "isSummary" : false,
+      "mapping" : [{
+        "identity" : "rim",
+        "map" : "n/a"
+      }]
+    },
+    {
+      "id" : "Extension.extension",
+      "path" : "Extension.extension",
+      "slicing" : {
+        "discriminator" : [{
+          "type" : "value",
+          "path" : "url"
+        }],
+        "description" : "Extensions are always sliced by (at least) url",
+        "rules" : "open"
+      },
+      "short" : "Extension",
+      "definition" : "An Extension",
+      "min" : 0,
+      "max" : "0",
+      "base" : {
+        "path" : "Element.extension",
+        "min" : 0,
+        "max" : "*"
+      },
+      "type" : [{
+        "code" : "Extension"
+      }],
+      "constraint" : [{
+        "key" : "ele-1",
+        "severity" : "error",
+        "human" : "All FHIR elements must have a @value or children",
+        "expression" : "hasValue() or (children().count() > id.count())",
+        "source" : "http://hl7.org/fhir/StructureDefinition/Element"
+      },
+      {
+        "key" : "ext-1",
+        "severity" : "error",
+        "human" : "Must have either extensions or value[x], not both",
+        "expression" : "extension.exists() != value.exists()",
+        "source" : "http://hl7.org/fhir/StructureDefinition/Extension"
+      }],
+      "isModifier" : false,
+      "isSummary" : false
+    },
+    {
+      "id" : "Extension.url",
+      "path" : "Extension.url",
+      "representation" : ["xmlAttr"],
+      "short" : "identifies the meaning of the extension",
+      "definition" : "Source of the definition for the extension code - a logical name or a URL.",
+      "comment" : "The definition may point directly to a computable or human-readable definition of the extensibility codes, or it may be a logical URI as declared in some other specification. The definition SHALL be a URI for the Structure Definition defining the extension.",
+      "min" : 1,
+      "max" : "1",
+      "base" : {
+        "path" : "Extension.url",
+        "min" : 1,
+        "max" : "1"
+      },
+      "type" : [{
+        "extension" : [{
+          "url" : "http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type",
+          "valueUrl" : "uri"
+        }],
+        "code" : "http://hl7.org/fhirpath/System.String"
+      }],
+      "fixedUri" : "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support",
+      "isModifier" : false,
+      "isSummary" : false,
+      "mapping" : [{
+        "identity" : "rim",
+        "map" : "N/A"
+      }]
+    },
+    {
+      "id" : "Extension.value[x]",
+      "path" : "Extension.value[x]",
+      "short" : "Value of extension",
+      "definition" : "Value of extension - must be one of a constrained set of the data types (see [Extensibility](http://hl7.org/fhir/5.0.0-snapshot3/extensibility.html) for a list).",
+      "min" : 1,
+      "max" : "1",
+      "base" : {
+        "path" : "Extension.value[x]",
+        "min" : 0,
+        "max" : "1"
+      },
+      "type" : [{
+        "code" : "boolean"
+      }],
+      "condition" : ["ext-1"],
+      "constraint" : [{
+        "key" : "ele-1",
+        "severity" : "error",
+        "human" : "All FHIR elements must have a @value or children",
+        "expression" : "hasValue() or (children().count() > id.count())",
+        "source" : "http://hl7.org/fhir/StructureDefinition/Element"
+      }],
+      "isModifier" : false,
+      "isSummary" : false,
+      "mapping" : [{
+        "identity" : "rim",
+        "map" : "N/A"
+      }]
+    }]
+  },
+  "differential" : {
+    "element" : [{
+      "id" : "Extension",
+      "path" : "Extension",
+      "short" : "If true, the specified type/profile/target must be supported by implementations",
+      "definition" : "If true indicates that the specified type, profile or targetProfile must be supported by implementations.",
+      "comment" : "An element may be labelled as must support. This extension clarifies which types/profiles/targetProfiles are must-support. It has no meaning if the element itself is not must-support. If the element is labelled must-support, and none of the options are labelled as must support, then an application must support at least one of the possible options, but is not required to support all of them. Specific details on what it means to 'support' the specified profile will be defined either by the implementation guide, by the profile and/or in usage notes for the element holding the extension.  If this extension is not declared on a mustSupport element, the presumption is that implementations need only support one of the potential types unless other documentation in the specification explicitly dictates otherwise.",
+      "min" : 0,
+      "max" : "1"
+    },
+    {
+      "id" : "Extension.extension",
+      "path" : "Extension.extension",
+      "max" : "0"
+    },
+    {
+      "id" : "Extension.url",
+      "path" : "Extension.url",
+      "fixedUri" : "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support"
+    },
+    {
+      "id" : "Extension.value[x]",
+      "path" : "Extension.value[x]",
+      "min" : 1,
+      "type" : [{
+        "code" : "boolean"
+      }]
+    }]
+  }
+}
\ No newline at end of file