Repository: FHIR/sushi (ts)

Issue:
Whitespace in Resource references is not handled correctly
When using a Resource reference, the grammar allows for whitespace to be inside the `()`, but the spaces are not handled properly. The two examples below illustrate this:


If you have the following rule in your FSH
```
* subject = Reference(   mCODEPatientExample01 )
```
the output will be
```
"reference": "   mCODEPatientExample01 "
```
No errors are logged in this case, but this is not the intended output.

Additionally, if you have the following rule in your FSH
```
* stage.assessment only Reference(   CancerStageParent )
```
SUSHI logs the following error and skips the rule:
```
error No definition for the type "   CancerStageParent " could be found.
```

Pull request description:
Support whitespace in Reference()
This PR fixes #535. Spaces inside the `()` of `Reference` is properly supported now. The issue and tests show the cases this could occur in, but below are simplified examples:

Fixed Value Rule: Previously did not find and resolve the reference correctly, but will now resolve properly.

```
* subject = Reference(   mCODEPatientExample01  )
```

Only Rule: Previously logged an error that "    CancerStageParent " could not be found, but now sets the rule properly.

```
* stage.assessment only Reference(   CancerStageParent )
```

Patch:
diff --git a/src/import/FSHImporter.ts b/src/import/FSHImporter.ts
index 4368e4d..9355a5f 100644
--- a/src/import/FSHImporter.ts
+++ b/src/import/FSHImporter.ts
@@ -1248,11 +1248,17 @@ export class FSHImporter extends FSHVisitor {
   }
 
   private parseOrReference(reference: string): string[] {
-    return reference.slice(reference.indexOf('(') + 1, reference.length - 1).split(/\s+or\s+/);
+    return reference
+      .slice(reference.indexOf('(') + 1, reference.length - 1)
+      .split(/\s+or\s+/)
+      .map(r => r.trim());
   }
 
   private parsePipeReference(reference: string): string[] {
-    return reference.slice(reference.indexOf('(') + 1, reference.length - 1).split(/\s*\|\s*/);
+    return reference
+      .slice(reference.indexOf('(') + 1, reference.length - 1)
+      .split(/\s*\|\s*/)
+      .map(r => r.trim());
   }
 
   visitCanonical(ctx: pc.CanonicalContext): FshCanonical {


Test patch:
diff --git a/test/import/FSHImporter.Profile.test.ts b/test/import/FSHImporter.Profile.test.ts
index 14ce977..2f39c71 100644
--- a/test/import/FSHImporter.Profile.test.ts
+++ b/test/import/FSHImporter.Profile.test.ts
@@ -1190,6 +1190,24 @@ describe('FSHImporter', () => {
         assertFixedValueRule(profile.rules[0], 'basedOn', expectedReference);
       });
 
+      it('should parse fixed value Reference rule with whitespace', () => {
+        const input = `
+
+        Profile: ObservationProfile
+        Parent: Observation
+        * basedOn = Reference(   fooProfile   )
+        `;
+
+        const result = importSingleText(input);
+        const profile = result.profiles.get('ObservationProfile');
+        expect(profile.rules).toHaveLength(1);
+
+        const expectedReference = new FshReference('fooProfile')
+          .withLocation([5, 21, 5, 47])
+          .withFile('');
+        assertFixedValueRule(profile.rules[0], 'basedOn', expectedReference);
+      });
+
       it('should log an error when a fixed value Reference rule has a choice of references', () => {
         const input = `
 
@@ -1415,6 +1433,24 @@ describe('FSHImporter', () => {
         );
       });
 
+      it('should parse an only rule with a reference to multiple types with whitespace', () => {
+        const input = `
+        Profile: ObservationProfile
+        Parent: Observation
+        * performer only Reference(   Organization    or  CareTeam)
+        `;
+
+        const result = importSingleText(input);
+        const profile = result.profiles.get('ObservationProfile');
+        expect(profile.rules).toHaveLength(1);
+        assertOnlyRule(
+          profile.rules[0],
+          'performer',
+          { type: 'Organization', isReference: true },
+          { type: 'CareTeam', isReference: true }
+        );
+      });
+
       it('should allow and translate aliases for only types', () => {
         const input = `
         Alias: QUANTITY = http://hl7.org/fhir/StructureDefinition/Quantity
@@ -1458,6 +1494,27 @@ describe('FSHImporter', () => {
           /Using "\|" to list references is deprecated\..*Line: 4\D*/s
         );
       });
+
+      it('should log a warning when references are listed with pipes with whitespace', () => {
+        const input = `
+        Profile: ObservationProfile
+        Parent: Observation
+        * performer only Reference(   Organization  |   CareTeam)
+        `;
+
+        const result = importSingleText(input);
+        const profile = result.profiles.get('ObservationProfile');
+        expect(profile.rules).toHaveLength(1);
+        assertOnlyRule(
+          profile.rules[0],
+          'performer',
+          { type: 'Organization', isReference: true },
+          { type: 'CareTeam', isReference: true }
+        );
+        expect(loggerSpy.getLastMessage('warn')).toMatch(
+          /Using "\|" to list references is deprecated\..*Line: 4\D*/s
+        );
+      });
     });
 
     describe('#containsRule', () => {