Repository: FHIR/sushi (ts)

Issue:
Canonical usage is sensitive to entity definition order
Based on this zulip conversion: https://chat.fhir.org/#narrow/stream/215610-shorthand/topic/Canonical.28.29.20for.20.23definition.20instances

The ability to use a `Canonical` is sensitive to definition order. For example, the following FSH is processed successfully:
```
Instance: BaselineClinical
InstanceOf: Questionnaire
Usage: #definition
Description: "Clinical response questionnaire at baseline (first doctors' visit)"
* status = #draft

Instance: SampleResponse
InstanceOf: QuestionnaireResponse
Usage: #definition
Description: "This is a sample response"
* status = #in-progress
* questionnaire = Canonical(BaselineClinical)
```

But, this FSH will report an error:
```
Instance: SampleResponse
InstanceOf: QuestionnaireResponse
Usage: #definition
Description: "This is a sample response"
* status = #in-progress
* questionnaire = Canonical(BaselineClinical)

Instance: BaselineClinical
InstanceOf: Questionnaire
Usage: #definition
Description: "Clinical response questionnaire at baseline (first doctors' visit)"
* status = #draft
```

The reported error is: `Cannot use canonical URL of BaselineClinical because it does not exist. Be sure that BaselineClinical exists and it has a URL.`
While the workaround is straightforward if both instances are in the same file, the situation becomes complicated if they are in different files. Additionally, if two instances want to use each others' canonical, the error can't be avoided.

Pull request description:
Automatic url for instances added to fishForMetadata in FSHtank
Fixes #1073, updating the `fishForMetadata` function in the `FSHTank` to always return a url when fishing for Instances, as we do for every other resource type. 

Patch:
diff --git a/src/utils/MasterFisher.ts b/src/utils/MasterFisher.ts
index 4a7034f..e8f95a1 100644
--- a/src/utils/MasterFisher.ts
+++ b/src/utils/MasterFisher.ts
@@ -79,6 +79,10 @@ export class MasterFisher implements Fishable {
             (fishable.fish(item, Type.Instance) as Instance)?.instanceOf
           )?.sdType;
         }
+        // Add url to metadata for non-inline Instances
+        if (!result.url && result.instanceUsage !== 'Inline') {
+          result.url = `${this.pkg.config.canonical}/${result.resourceType}/${result.id}`;
+        }
         return result;
       }
     }


Test patch:
diff --git a/test/utils/MasterFisher.test.ts b/test/utils/MasterFisher.test.ts
index 567a33e..16c5d75 100644
--- a/test/utils/MasterFisher.test.ts
+++ b/test/utils/MasterFisher.test.ts
@@ -1,5 +1,5 @@
 import { FSHDocument, FSHTank } from '../../src/import';
-import { Profile } from '../../src/fshtypes';
+import { Profile, Instance } from '../../src/fshtypes';
 import { FHIRDefinitions, loadFromPath } from '../../src/fhirdefs';
 import { Package } from '../../src/export';
 import { StructureDefinition } from '../../src/fhirtypes';
@@ -31,6 +31,13 @@ describe('MasterFisher', () => {
     );
     doc1.profiles.get('Practitioner').id = 'my-dr';
     doc1.profiles.get('Practitioner').parent = 'Practitioner';
+    doc1.instances.set('Instance1', new Instance('Instance1'));
+    doc1.instances.get('Instance1').id = 'inst1';
+    doc1.instances.get('Instance1').instanceOf = 'Profile1';
+    doc1.instances.set('InlineInstance', new Instance('InlineInstance'));
+    doc1.instances.get('InlineInstance').id = 'inline-instance';
+    doc1.instances.get('InlineInstance').instanceOf = 'Profile1';
+    doc1.instances.get('InlineInstance').usage = 'Inline';
     const tank = new FSHTank([doc1], minimalConfig);
 
     const pkg = new Package(tank.config);
@@ -180,6 +187,35 @@ describe('MasterFisher', () => {
     defs.resetPredefinedResources();
   });
 
+  it('should find an Instance that is only in the Tank', () => {
+    const result = fisher.fishForFHIR('Instance1');
+    expect(result).toBeUndefined();
+
+    const resultMD = fisher.fishForMetadata('Instance1');
+    expect(resultMD).toEqual({
+      id: 'inst1',
+      name: 'Instance1',
+      instanceUsage: 'Example',
+      resourceType: 'Procedure',
+      sdType: undefined,
+      url: 'http://hl7.org/fhir/us/minimal/Procedure/inst1'
+    });
+  });
+
+  it('should find an inline Instance that is only in the Tank', () => {
+    const result = fisher.fishForFHIR('InlineInstance');
+    expect(result).toBeUndefined();
+
+    const resultMD = fisher.fishForMetadata('InlineInstance');
+    expect(resultMD).toEqual({
+      id: 'inline-instance',
+      name: 'InlineInstance',
+      instanceUsage: 'Inline',
+      resourceType: 'Procedure',
+      sdType: undefined
+    });
+  });
+
   it('should not return the FHIR def for a resource if there is a profile w/ the same name in the tank', () => {
     const result = fisher.fishForFHIR('Organization');
     expect(result).toBeUndefined();