Repository: FHIR/sushi (ts)

Issue:
Cannot get Canonical for Instances when url is assigned via a RuleSet
Reported by Brian Kaney on Zulip: https://chat.fhir.org/#narrow/stream/215610-shorthand/topic/Canonical.20with.20rule-set

Suppose a rule-set that sets the URL and version
```
RuleSet: LibraryMetadata(id)
* url = "http://fhir/ig/Library/{id}"
* version = "0.1.0"
```

When I insert it in a resource, called MyLibrary and try to make a canonical reference, it fails:
```
* library = Canonical(MyLibrary)
```

with:
> error Cannot use canonical URL of MyLibrary because it does not exist. Be sure that MyLibrary exists and it has a URL.

It seems that unless url is explicitly set (e.g. not via a rule-set), the canonical doesn't work...

Pull request:
Apply insert rules on Instances when fishing for metadata
Fixes #958 and completes task [CIMPL-857](https://standardhealthrecord.atlassian.net/browse/CIMPL-857).

An Instance's url may be set by a rule from a RuleSet. Apply insert rules on the found instance so that these rules can be found in order to correctly determine the url.

It is not necessary to do this with other FSH types because Instances are exported after all other FSH types. So, the correct url can be found on the exported resource in the Package.

Patch:
diff --git a/src/import/FSHTank.ts b/src/import/FSHTank.ts
index 7aa6b34..ed2b354 100644
--- a/src/import/FSHTank.ts
+++ b/src/import/FSHTank.ts
@@ -15,7 +15,7 @@ import {
 } from '../fshtypes';
 import { AssignmentRule } from '../fshtypes/rules';
 import { Type, Metadata, Fishable } from '../utils/Fishable';
-import { getUrlFromFshDefinition } from '../fhirtypes/common';
+import { getUrlFromFshDefinition, applyInsertRules } from '../fhirtypes/common';
 import flatMap from 'lodash/flatMap';
 
 export class FSHTank implements Fishable {
@@ -394,6 +394,8 @@ export class FSHTank implements Fishable {
           meta.resourceType = 'CodeSystem';
         }
       } else if (result instanceof Instance) {
+        // the url may be added in a RuleSet, so apply insert rules
+        applyInsertRules(result, this);
         result.rules?.forEach(r => {
           if (r.path === 'url' && r instanceof AssignmentRule && typeof r.value === 'string') {
             meta.url = r.value;


Test patch:
diff --git a/test/export/InstanceExporter.test.ts b/test/export/InstanceExporter.test.ts
index 629350c..689b79d 100644
--- a/test/export/InstanceExporter.test.ts
+++ b/test/export/InstanceExporter.test.ts
@@ -2169,6 +2169,52 @@ describe('InstanceExporter', () => {
       });
     });
 
+    it('should apply an Assignment rule with Canonical of an instance that has its url assigned by a RuleSet', () => {
+      // RuleSet: LibraryMetadata
+      // * url = "http://fhir/ig/Library/273"
+      // * version = "0.1.0"
+      const ruleSet = new RuleSet('LibraryMetadata');
+      const urlRule = new AssignmentRule('url');
+      urlRule.value = 'http://fhir/ig/Library/273';
+      const versionRule = new AssignmentRule('version');
+      versionRule.value = '0.1.0';
+      ruleSet.rules.push(urlRule, versionRule);
+      doc.ruleSets.set(ruleSet.name, ruleSet);
+      // Instance: MyActivity
+      // InstanceOf: ActivityDefinition
+      // * status = #active
+      // * library = Canonical(MyLibrary)
+      const activityInstance = new Instance('MyActivity');
+      activityInstance.instanceOf = 'ActivityDefinition';
+      const activityStatus = new AssignmentRule('status');
+      activityStatus.value = new FshCode('active');
+      const activityLibrary = new AssignmentRule('library');
+      activityLibrary.value = new FshCanonical('MyLibrary');
+      activityInstance.rules.push(activityStatus, activityLibrary);
+      doc.instances.set(activityInstance.name, activityInstance);
+      // Instance: MyLibrary
+      // InstanceOf: Library
+      // * insert LibraryMetadata
+      // * status = #active
+      // * type = #logic-library
+      const libraryInstance = new Instance('MyLibrary');
+      libraryInstance.instanceOf = 'Library';
+      const libraryInsert = new InsertRule('');
+      libraryInsert.ruleSet = 'LibraryMetadata';
+      const libraryStatus = new AssignmentRule('status');
+      libraryStatus.value = new FshCode('active');
+      const libraryType = new AssignmentRule('type');
+      libraryType.value = new FshCode('logic-library');
+      libraryInstance.rules.push(libraryInsert, libraryStatus, libraryType);
+      doc.instances.set(libraryInstance.name, libraryInstance);
+
+      const instances = exporter.export().instances;
+      const exportedActivity = instances.find(
+        instanceDefinition => instanceDefinition.id === 'MyActivity'
+      );
+      expect(exportedActivity.library).toEqual(['http://fhir/ig/Library/273']);
+    });
+
     it('should not apply an Assignment rule with an invalid Canonical entity and log an error', () => {
       const observationInstance = new Instance('MyObservation');
       observationInstance.instanceOf = 'Observation';