Repository: FHIR/sushi (ts)

Issue:
Building bundle with resources has order dependent behavior in build
If you try to write the Bundle first, then the included resources (in the same file), the FHIR build fails, but if invert the order, the build succeeds.

Sushi should order the resources based on their dependencies.

The build probably shouldn't break with a report about trying to generate the same resource twice during validation phase either, but that would probably be related to IG Builder 



Pull request description:
Don't re-export Instances
Fixes #333 

This adds a check before we begin exporting an instance to check if that instance has already been exported. We have a similar check when exporting StructureDefinitions. This check is necessary now that we can potentially export instances when we `fishForFHIR` in this exporter. If an instance is exported during that process, we don't need to export it again.

The test added mirrors Chris's example on the issue and should fail if you run it on master or run it without the additional `if` statement.

Patch:
diff --git a/src/export/InstanceExporter.ts b/src/export/InstanceExporter.ts
index 2dfd826..ff2d9e8 100644
--- a/src/export/InstanceExporter.ts
+++ b/src/export/InstanceExporter.ts
@@ -286,6 +286,10 @@ export class InstanceExporter implements Fishable {
   }
 
   exportInstance(fshDefinition: Instance): InstanceDefinition {
+    if (this.pkg.instances.some(i => i._instanceMeta.name === fshDefinition.id)) {
+      return;
+    }
+
     const json = this.fisher.fishForFHIR(
       fshDefinition.instanceOf,
       Type.Resource,


Test patch:
diff --git a/test/export/InstanceExporter.test.ts b/test/export/InstanceExporter.test.ts
index 91cd2a0..e2d8333 100644
--- a/test/export/InstanceExporter.test.ts
+++ b/test/export/InstanceExporter.test.ts
@@ -1241,6 +1241,31 @@ describe('InstanceExporter', () => {
       ]);
     });
 
+    it('should only export an instance once', () => {
+      const bundleInstance = new Instance('MyBundle');
+      bundleInstance.instanceOf = 'Bundle';
+      const inlineRule = new FixedValueRule('entry[0].resource');
+      inlineRule.fixedValue = 'MyBundledPatient';
+      inlineRule.isResource = true;
+      bundleInstance.rules.push(inlineRule); // * entry[0].resource = MyBundledPatient
+      doc.instances.set(bundleInstance.name, bundleInstance);
+
+      const inlineInstance = new Instance('MyBundledPatient');
+      inlineInstance.instanceOf = 'Patient';
+      const fixedValRule = new FixedValueRule('active');
+      fixedValRule.fixedValue = true;
+      inlineInstance.rules.push(fixedValRule); // * active = true
+      doc.instances.set(inlineInstance.name, inlineInstance);
+
+      const exported = exporter.export().instances;
+      const exportedBundle = exported.filter(i => i._instanceMeta.name === 'MyBundle');
+      const exportedBundledPatient = exported.filter(
+        i => i._instanceMeta.name === 'MyBundledPatient'
+      );
+      expect(exportedBundle).toHaveLength(1);
+      expect(exportedBundledPatient).toHaveLength(1);
+    });
+
     it('should log an error when fixing an inline resource that does not exist to an instance', () => {
       const inlineRule = new FixedValueRule('contained[0]')
         .withFile('FakeInstance.fsh')