Repository: FHIR/sushi
Pull request #671 (2020-11-17 20:50:13)

Fix content reference bug
This fixes the bug that first arose here: https://chat.fhir.org/#narrow/stream/215610-shorthand/topic/Possible.20bug.20with.20dependencies.20and.20nesting.

The issue here actually was not about dependencies, but about the way we find `contentReference` elements, `PlanDefinition.action.action` in this case. We had assumed that a `contentReference` would only be a relative reference, like `#PlanDefinition.action.action`, as this is how it is in the core FHIR spec. However, in the package being generated by the IG, a full reference is used, `http://hl7.org/fhir/StructureDefinition/PlanDefinition#PlanDefinition.action`. The logic we had failed in that case, and this PR fixes that.

The easiest way to test is to use the definition given below, and make a FSH tank with that definition as BYO-JSON, and then an instance defined in FSH which inherits from the `ReproPlanDefinition` profile. On `master`, you should see SUSHI spit out bugs like the ones shown in the linked zulip conversation. On this branch, you should instead see SUSHI run without error.


[StructureDefinition-ReproPlanDefinition.zip](https://github.com/FHIR/sushi/files/5556130/StructureDefinition-ReproPlanDefinition.zip)





Patch:
diff --git a/src/fhirtypes/ElementDefinition.ts b/src/fhirtypes/ElementDefinition.ts
index f7d3ab1..470c406 100644
--- a/src/fhirtypes/ElementDefinition.ts
+++ b/src/fhirtypes/ElementDefinition.ts
@@ -1700,7 +1700,9 @@ export class ElementDefinition {
         if (json) {
           const def = StructureDefinition.fromJSON(json);
           // Content references start with #, slice that off to id of referenced element
-          const referencedElement = def.findElement(this.contentReference.slice(1));
+          const referencedElement = def.findElement(
+            this.contentReference.slice(this.contentReference.indexOf('#') + 1)
+          );
           newElements = referencedElement?.children().map(e => {
             const eClone = e.clone();
             eClone.id = eClone.id.replace(referencedElement.id, this.id);


Test patch:
diff --git a/test/fhirtypes/StructureDefinition.test.ts b/test/fhirtypes/StructureDefinition.test.ts
index c3b85c1..983bcc1 100644
--- a/test/fhirtypes/StructureDefinition.test.ts
+++ b/test/fhirtypes/StructureDefinition.test.ts
@@ -793,6 +793,27 @@ describe('StructureDefinition', () => {
       expect(valueSet.elements.length).toBe(originalLength + 26);
     });
 
+    it('should find a child of a content reference element by path when the reference uses a full URI', () => {
+      const originalLength = valueSet.elements.length;
+      // Modify system on the current ValueSet to test that we are copying from original SD
+      // not the profiled SD
+      const include = valueSet.elements.find(e => e.id === 'ValueSet.compose.include');
+      const includeSystem = valueSet.elements.find(e => e.id === 'ValueSet.compose.include.system');
+      includeSystem.short = 'This should not get copied over!';
+      const exclude = valueSet.elements.find(e => e.id === 'ValueSet.compose.exclude');
+
+      // Set the content reference to be a complete path
+      exclude.contentReference =
+        'http://hl7.org/fhir/StructureDefinition/ValueSet#ValueSet.compose.include';
+      const excludeSystem = valueSet.findElementByPath('compose.exclude.system', fisher);
+      expect(excludeSystem).toBeDefined();
+      expect(excludeSystem.id).toBe('ValueSet.compose.exclude.system');
+      expect(excludeSystem.short).toBe('The system the codes come from');
+      expect(exclude.contentReference).toBeUndefined();
+      expect(exclude.type).toEqual(include.type);
+      expect(valueSet.elements.length).toBe(originalLength + 26);
+    });
+
     it('should find a child of a slice content reference by path', () => {
       const originalLength = valueSet.elements.length;
       const include = valueSet.elements.find(e => e.id === 'ValueSet.compose.include');