Repository: FHIR/sushi (ts)

Issue:
Context unnecessarily uses [url]#[elementid] form for resources in the base specification
An extension defined with:
```
Context: Resource
```
results in:
```json
"context": [
  {
    "expression": "http://hl7.org/fhir/StructureDefinition/Resource#Resource",
    "type": "element"
  }
]
```
[FSH Online](https://fshschool.org/FSHOnline/#/share/3suM7Ro)

The [FHIR spec](https://hl7.org/fhir/R5/defining-extensions.html#context) says:
> Element Ids are unique within the base specification, and within a structure definition. The full path for the element is [url]#[elementid]. If there is no #, the Element id is one defined in the base specification

Since `Resource` is in the base specification, SUSHI should output the expression as `Resource`, not `http://hl7.org/fhir/StructureDefinition/Resource#Resource`.

Pull request description:
Handle context StructureDefinition without derivation
Fixes #1333 and completes task [CIMPL-1160](https://standardhealthrecord.atlassian.net/browse/CIMPL-1160).

Some core FHIR StructureDefinition resources do not have a derivation attribute. These resources should still use the shortened form when used as an Extension context.

Curiously, the Resource definition in R4 and R4B does not have a derivation, but the derivation is present in R5. There are other definitions in each FHIR version that have no derivation. So, this PR takes the approach that any core FHIR StructureDefinition that doesn't specifically have a derivation of `constraint` can use the short form.

Patch:
diff --git a/src/export/StructureDefinitionExporter.ts b/src/export/StructureDefinitionExporter.ts
index 7e0c40c..a3f1823 100644
--- a/src/export/StructureDefinitionExporter.ts
+++ b/src/export/StructureDefinitionExporter.ts
@@ -497,7 +497,7 @@ export class StructureDefinitionExporter implements Fishable {
                   contextExpression = resourceSD.url;
                   contextType = 'extension';
                 } else if (
-                  resourceSD.derivation === 'specialization' &&
+                  resourceSD.derivation !== 'constraint' &&
                   resourceSD.url.startsWith('http://hl7.org/fhir/StructureDefinition/')
                 ) {
                   contextExpression = targetElement.id;


Test patch:
diff --git a/test/export/StructureDefinition.ExtensionExporter.test.ts b/test/export/StructureDefinition.ExtensionExporter.test.ts
index 8e88f1e..633457d 100644
--- a/test/export/StructureDefinition.ExtensionExporter.test.ts
+++ b/test/export/StructureDefinition.ExtensionExporter.test.ts
@@ -367,6 +367,78 @@ describe('ExtensionExporter', () => {
       ]);
     });
 
+    it('should set extension context for a base resource (with no derivation) root element by id/name', () => {
+      const extension = new Extension('MyExtension');
+      extension.contexts = [
+        {
+          value: 'Resource',
+          isQuoted: false
+        }
+      ];
+      doc.extensions.set(extension.name, extension);
+      const exported = exporter.exportStructDef(extension);
+      expect(exported.context).toEqual([
+        {
+          type: 'element',
+          expression: 'Resource'
+        }
+      ]);
+    });
+
+    it('should set extension context for a base resource (with no derivation) root element by url', () => {
+      const extension = new Extension('MyExtension');
+      extension.contexts = [
+        {
+          value: 'http://hl7.org/fhir/StructureDefinition/Element',
+          isQuoted: false
+        }
+      ];
+      doc.extensions.set(extension.name, extension);
+      const exported = exporter.exportStructDef(extension);
+      expect(exported.context).toEqual([
+        {
+          type: 'element',
+          expression: 'Element'
+        }
+      ]);
+    });
+
+    it('should set extension context for a base resource (with no derivation) by id with a FSH path', () => {
+      const extension = new Extension('MyExtension');
+      extension.contexts = [
+        {
+          value: 'Resource.language',
+          isQuoted: false
+        }
+      ];
+      doc.extensions.set(extension.name, extension);
+      const exported = exporter.exportStructDef(extension);
+      expect(exported.context).toEqual([
+        {
+          type: 'element',
+          expression: 'Resource.language'
+        }
+      ]);
+    });
+
+    it('should set extension context for a base resource (with no derivation) by url with a FSH path', () => {
+      const extension = new Extension('MyExtension');
+      extension.contexts = [
+        {
+          value: 'http://hl7.org/fhir/StructureDefinition/Element#id',
+          isQuoted: false
+        }
+      ];
+      doc.extensions.set(extension.name, extension);
+      const exported = exporter.exportStructDef(extension);
+      expect(exported.context).toEqual([
+        {
+          type: 'element',
+          expression: 'Element.id'
+        }
+      ]);
+    });
+
     it('should set extension context with type "extension" when the path is part of a complex extension by name', () => {
       const extension = new Extension('MyExtension');
       extension.contexts = [