Repository: FHIR/sushi
Pull request #1385 (2023-11-14 19:20:54)

Produce correct FSH for concept CaretValueRules on ValueSets
Completes task [CIMPL-1199](https://standardhealthrecord.atlassian.net/browse/CIMPL-1199).

When a CaretValueRule on a ValueSet has a concept as its path, the system is also included. However, this is not the case when the rule is on a CodeSystem. CaretValueRule should produce FSH that is correct in both cases.

My strategy here was to try to use `pathArray` a little more consistently between CodeSystems and ValueSets. In both cases, the `#` will be included in this array's elements. ValueSets include the system `system#code` and CodeSystems don't `#code`. This means needing to trim off the leading `#` in some situations when exporting CodeSystems.

cmoesel: This seems good, but since it hit a variety of areas in the codebase, I'm running a regression. @mint-thompson - If you already ran one, let me know. Also, it looks like there is a conflict that needs to be resolved.
mint-thompson: The latest update fixes the problems in the regression, as well as correcting some related issues that were popping up involving codes that start with a double-quote `"` character.
cmoesel: I ran a full regression Monday afternoon and got back some changes. I think they might be related to this branch not being up to date w/ master though -- so I'm going to synch the branch and run regression on just the projects that had differences in my last run.

Patch:
diff --git a/src/export/CodeSystemExporter.ts b/src/export/CodeSystemExporter.ts
index 2977006..4b8d8b5 100644
--- a/src/export/CodeSystemExporter.ts
+++ b/src/export/CodeSystemExporter.ts
@@ -209,9 +209,9 @@ export class CodeSystemExporter {
     const conceptIndices: number[] = [];
     let conceptList = codeSystem.concept ?? [];
     for (const codeStep of codePath) {
-      const stepIndex = conceptList.findIndex(concept => concept.code === codeStep);
+      const stepIndex = conceptList.findIndex(concept => `#${concept.code}` === codeStep);
       if (stepIndex === -1) {
-        throw new CannotResolvePathError(codePath.map(code => `#${code}`).join(' '));
+        throw new CannotResolvePathError(codePath.join(' '));
       }
       conceptIndices.push(stepIndex);
       conceptList = conceptList[stepIndex].concept ?? [];
diff --git a/src/export/ValueSetExporter.ts b/src/export/ValueSetExporter.ts
index 80fd358..cbb8906 100644
--- a/src/export/ValueSetExporter.ts
+++ b/src/export/ValueSetExporter.ts
@@ -397,6 +397,7 @@ export class ValueSetExporter {
         rule => rule instanceof ValueSetComponentRule
       ) as ValueSetComponentRule[]
     );
+    conceptCaretRules.forEach(rule => (rule.isCodeCaretRule = true));
     this.setConceptCaretRules(vs, conceptCaretRules);
     if (vs.compose && vs.compose.include.length == 0) {
       throw new ValueSetComposeError(fshDefinition.name);
diff --git a/src/fhirtypes/common.ts b/src/fhirtypes/common.ts
index bbc006d..11728f4 100644
--- a/src/fhirtypes/common.ts
+++ b/src/fhirtypes/common.ts
@@ -1258,7 +1258,8 @@ export function applyInsertRules(
           }
           if (rule.pathArray.length > 0) {
             if (ruleSetRuleClone instanceof ConceptRule) {
-              ruleSetRuleClone.hierarchy.unshift(...rule.pathArray);
+              // strip the leading # when adding to the hierarchy
+              ruleSetRuleClone.hierarchy.unshift(...rule.pathArray.map(code => code.slice(1)));
             } else if (ruleSetRuleClone instanceof CaretValueRule) {
               ruleSetRuleClone.pathArray.unshift(...rule.pathArray);
             }
diff --git a/src/fshtypes/FshCode.ts b/src/fshtypes/FshCode.ts
index 574f57b..0fb2363 100644
--- a/src/fshtypes/FshCode.ts
+++ b/src/fshtypes/FshCode.ts
@@ -9,7 +9,7 @@ export class FshCode extends FshEntity {
 
   toString(): string {
     let codeToShow = this.code;
-    if (/\s/.test(this.code)) {
+    if (/^"|\s/.test(this.code)) {
       codeToShow = `"${fshifyString(this.code)}"`;
     }
     const str = `${this.system ?? ''}#${codeToShow}`;
diff --git a/src/fshtypes/rules/CaretValueRule.ts b/src/fshtypes/rules/CaretValueRule.ts
index 2f9c26b..9c186a6 100644
--- a/src/fshtypes/rules/CaretValueRule.ts
+++ b/src/fshtypes/rules/CaretValueRule.ts
@@ -50,10 +50,13 @@ export class CaretValueRule extends Rule {
         printablePath =
           this.pathArray
             .map(code => {
-              if (/\s/.test(code)) {
-                return `#"${fshifyString(code)}"`;
+              const splitCode = code.split('#');
+              const systemPart = splitCode[0];
+              const codePart = splitCode.slice(1).join('#');
+              if (/^"|\s/.test(codePart)) {
+                return `${systemPart}#"${fshifyString(codePart)}"`;
               } else {
-                return `#${code}`;
+                return `${systemPart}#${codePart}`;
               }
             })
             .join(' ') + ' ';
diff --git a/src/fshtypes/rules/ConceptRule.ts b/src/fshtypes/rules/ConceptRule.ts
index d690b34..961ddcb 100644
--- a/src/fshtypes/rules/ConceptRule.ts
+++ b/src/fshtypes/rules/ConceptRule.ts
@@ -17,8 +17,9 @@ export class ConceptRule extends Rule {
   }
 
   toFSH(): string {
+    // quote codes that contain spaces or start with a double quote
     const quotedCodes = [...this.hierarchy, this.code].map(code =>
-      /\s/.test(code) ? `#"${code}"` : `#${code}`
+      /^"|\s/.test(code) ? `#"${fshifyString(code)}"` : `#${code}`
     );
     let line = `* ${quotedCodes.join(' ')}`;
     if (this.display) {
diff --git a/src/import/FSHImporter.ts b/src/import/FSHImporter.ts
index 29c20b4..fbcf3ee 100644
--- a/src/import/FSHImporter.ts
+++ b/src/import/FSHImporter.ts
@@ -1513,8 +1513,9 @@ export class FSHImporter extends FSHVisitor {
     // the last code in allCodes is the one we are actually defining.
     // the rest are the hierarchy, which may be empty.
     // indentation may also be used to define the hierarchy, which is what the code path with context is for.
+    // the # is included in the array path since it is needed for caret rules.
     const fullCodePath = this.getArrayPathWithContext(
-      localCodePath.map(localCode => localCode.code),
+      localCodePath.map(localCode => `#${localCode.code}`),
       ctx
     );
     const codePart = localCodePath.slice(-1)[0];
@@ -1522,7 +1523,8 @@ export class FSHImporter extends FSHVisitor {
     const concept = new ConceptRule(codePart.code)
       .withLocation(this.extractStartStop(ctx))
       .withFile(this.currentFile);
-    concept.hierarchy = fullCodePath.slice(0, -1);
+    // concepts in the array path have a leading #, which we don't want in the hierarchy
+    concept.hierarchy = fullCodePath.slice(0, -1).map(code => code.slice(1));
     if (availableStrings.length > 0) {
       concept.display = availableStrings[0];
     }
@@ -1772,7 +1774,7 @@ export class FSHImporter extends FSHVisitor {
           if (keepSystem) {
             return `${parsedCode.system ?? ''}#${parsedCode.code}`;
           } else {
-            return parsedCode.code;
+            return `#${parsedCode.code}`;
           }
         })
       : [];
@@ -1830,7 +1832,7 @@ export class FSHImporter extends FSHVisitor {
       if (keepSystem) {
         return `${parsedCode.system ?? ''}#${parsedCode.code}`;
       } else {
-        return parsedCode.code;
+        return `#${parsedCode.code}`;
       }
     });
     const fullCodePath = this.getArrayPathWithContext(localCodePath, ctx);


Test patch:
diff --git a/test/export/CodeSystemExporter.test.ts b/test/export/CodeSystemExporter.test.ts
index ef38e95..2c324fc 100644
--- a/test/export/CodeSystemExporter.test.ts
+++ b/test/export/CodeSystemExporter.test.ts
@@ -504,7 +504,7 @@ describe('CodeSystemExporter', () => {
     const codeSystem = new FshCodeSystem('CaretCodeSystem');
     const someCode = new ConceptRule('someCode', 'Some Code');
     const someCaret = new CaretValueRule('');
-    someCaret.pathArray = ['someCode'];
+    someCaret.pathArray = ['#someCode'];
     someCaret.caretPath = 'designation[0].value';
     someCaret.value = 'Designated value';
     codeSystem.rules.push(someCode, someCaret);
@@ -539,7 +539,7 @@ describe('CodeSystemExporter', () => {
     const otherCode = new ConceptRule('otherCode', 'Other Code');
     otherCode.hierarchy = ['someCode'];
     const someCaret = new CaretValueRule('');
-    someCaret.pathArray = ['someCode', 'otherCode'];
+    someCaret.pathArray = ['#someCode', '#otherCode'];
     someCaret.caretPath = 'designation[0].value';
     someCaret.value = 'Other designated value';
     codeSystem.rules.push(someCode, otherCode, someCaret);
@@ -582,11 +582,11 @@ describe('CodeSystemExporter', () => {
     const codeSystem = new FshCodeSystem('CaretCodeSystem');
     const someCode = new ConceptRule('someCode', 'Some Code');
     const propertyCode = new CaretValueRule('');
-    propertyCode.pathArray = ['someCode'];
+    propertyCode.pathArray = ['#someCode'];
     propertyCode.caretPath = 'property[0].code';
     propertyCode.value = new FshCode('standard');
     const propertyValue = new CaretValueRule('');
-    propertyValue.pathArray = ['someCode'];
+    propertyValue.pathArray = ['#someCode'];
     propertyValue.caretPath = 'property[0].valueCoding';
     propertyValue.value = 'AnInlineCoding';
     propertyValue.isInstance = true;
@@ -635,11 +635,11 @@ describe('CodeSystemExporter', () => {
     const codeSystem = new FshCodeSystem('CaretCodeSystem');
     const someCode = new ConceptRule('someCode', 'Some Code');
     const propertyCode = new CaretValueRule('');
-    propertyCode.pathArray = ['someCode'];
+    propertyCode.pathArray = ['#someCode'];
     propertyCode.caretPath = 'property[0].code';
     propertyCode.value = new FshCode('standard');
     const propertyValue = new CaretValueRule('');
-    propertyValue.pathArray = ['someCode'];
+    propertyValue.pathArray = ['#someCode'];
     propertyValue.caretPath = 'property[0].valueCoding';
     propertyValue.value = 790;
     propertyValue.rawValue = '79e1';
@@ -685,11 +685,11 @@ describe('CodeSystemExporter', () => {
     const codeSystem = new FshCodeSystem('CaretCodeSystem');
     const someCode = new ConceptRule('someCode', 'Some Code');
     const propertyCode = new CaretValueRule('');
-    propertyCode.pathArray = ['someCode'];
+    propertyCode.pathArray = ['#someCode'];
     propertyCode.caretPath = 'property[0].code';
     propertyCode.value = new FshCode('standard');
     const propertyValue = new CaretValueRule('');
-    propertyValue.pathArray = ['someCode'];
+    propertyValue.pathArray = ['#someCode'];
     propertyValue.caretPath = 'property[0].valueCoding';
     propertyValue.value = false;
     propertyValue.rawValue = 'false';
@@ -769,20 +769,20 @@ describe('CodeSystemExporter', () => {
     bottomCode.hierarchy = ['topCode'];
 
     const firstTop = new CaretValueRule('');
-    firstTop.pathArray = ['topCode'];
+    firstTop.pathArray = ['#topCode'];
     firstTop.caretPath = 'designation[+].value';
     firstTop.value = 'First top designation';
     const secondTop = new CaretValueRule('');
-    secondTop.pathArray = ['topCode'];
+    secondTop.pathArray = ['#topCode'];
     secondTop.caretPath = 'designation[+].value';
     secondTop.value = 'Second top designation';
 
     const firstBottom = new CaretValueRule('');
-    firstBottom.pathArray = ['topCode', 'bottomCode'];
+    firstBottom.pathArray = ['#topCode', '#bottomCode'];
     firstBottom.caretPath = 'designation[+].value';
     firstBottom.value = 'First bottom designation';
     const secondBottom = new CaretValueRule('');
-    secondBottom.pathArray = ['topCode', 'bottomCode'];
+    secondBottom.pathArray = ['#topCode', '#bottomCode'];
     secondBottom.caretPath = 'designation[+].value';
     secondBottom.value = 'Second bottom designation';
 
@@ -838,7 +838,7 @@ describe('CodeSystemExporter', () => {
     extensionRule.value = 1;
     const conceptRule = new ConceptRule('bar', 'Bar', 'Bar');
     const conceptExtensionRule = new CaretValueRule('bar');
-    conceptExtensionRule.pathArray = ['bar'];
+    conceptExtensionRule.pathArray = ['#bar'];
     conceptExtensionRule.caretPath = 'extension[structuredefinition-fmm].valueInteger';
     conceptExtensionRule.value = 2;
     codeSystem.rules.push(extensionRule, conceptRule, conceptExtensionRule);
@@ -978,7 +978,7 @@ describe('CodeSystemExporter', () => {
     const someCaret = new CaretValueRule('')
       .withFile('InvalidValue.fsh')
       .withLocation([8, 5, 8, 25]);
-    someCaret.pathArray = ['someCode', 'wrongCode'];
+    someCaret.pathArray = ['#someCode', '#wrongCode'];
     someCaret.caretPath = 'designation[0].value';
     someCaret.value = 'Other designated value';
     codeSystem.rules.push(someCode, otherCode, someCaret);
@@ -1017,13 +1017,13 @@ describe('CodeSystemExporter', () => {
     const codeSystem = new FshCodeSystem('CaretCodeSystem');
     const someCode = new ConceptRule('someCode', 'Some Code');
     const propertyCode = new CaretValueRule('');
-    propertyCode.pathArray = ['someCode'];
+    propertyCode.pathArray = ['#someCode'];
     propertyCode.caretPath = 'property[0].code';
     propertyCode.value = new FshCode('standard');
     const propertyValue = new CaretValueRule('')
       .withFile('CodeSystems.fsh')
       .withLocation([8, 5, 8, 25]);
-    propertyValue.pathArray = ['someCode'];
+    propertyValue.pathArray = ['#someCode'];
     propertyValue.caretPath = 'property[0].valueCoding';
     propertyValue.value = 'AnInlineCoding';
     propertyValue.isInstance = true;
@@ -1061,13 +1061,13 @@ describe('CodeSystemExporter', () => {
     const codeSystem = new FshCodeSystem('CaretCodeSystem');
     const someCode = new ConceptRule('someCode', 'Some Code');
     const propertyCode = new CaretValueRule('');
-    propertyCode.pathArray = ['someCode'];
+    propertyCode.pathArray = ['#someCode'];
     propertyCode.caretPath = 'property[0].code';
     propertyCode.value = new FshCode('standard');
     const propertyValue = new CaretValueRule('')
       .withFile('CodeSystems.fsh')
       .withLocation([8, 6, 8, 29]);
-    propertyValue.pathArray = ['someCode'];
+    propertyValue.pathArray = ['#someCode'];
     propertyValue.caretPath = 'property[0].valueDateTime';
     propertyValue.value = 790;
     propertyValue.rawValue = '79e1';
@@ -1113,13 +1113,13 @@ describe('CodeSystemExporter', () => {
     const codeSystem = new FshCodeSystem('CaretCodeSystem');
     const someCode = new ConceptRule('someCode', 'Some Code');
     const propertyCode = new CaretValueRule('');
-    propertyCode.pathArray = ['someCode'];
+    propertyCode.pathArray = ['#someCode'];
     propertyCode.caretPath = 'property[0].code';
     propertyCode.value = new FshCode('standard');
     const propertyValue = new CaretValueRule('')
       .withFile('CodeSystems.fsh')
       .withLocation([8, 6, 8, 29]);
-    propertyValue.pathArray = ['someCode'];
+    propertyValue.pathArray = ['#someCode'];
     propertyValue.caretPath = 'property[0].valueDateTime';
     propertyValue.value = true;
     propertyValue.rawValue = 'true';
@@ -1252,7 +1252,7 @@ describe('CodeSystemExporter', () => {
       const conceptRule = new ConceptRule('bear');
       const insertRule = new InsertRule('');
       insertRule.ruleSet = 'Bar';
-      insertRule.pathArray = ['bear'];
+      insertRule.pathArray = ['#bear'];
       cs.rules.push(conceptRule, insertRule);
 
       exporter.applyInsertRules();
diff --git a/test/export/ValueSetExporter.test.ts b/test/export/ValueSetExporter.test.ts
index 5032138..5d72b5c 100644
--- a/test/export/ValueSetExporter.test.ts
+++ b/test/export/ValueSetExporter.test.ts
@@ -1963,6 +1963,7 @@ describe('ValueSetExporter', () => {
         ]
       }
     });
+    expect(designation.isCodeCaretRule).toBeTrue();
     expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
   });
 
@@ -2011,6 +2012,7 @@ describe('ValueSetExporter', () => {
         ]
       }
     });
+    expect(designation.isCodeCaretRule).toBeTrue();
     expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
   });
 
@@ -2059,6 +2061,7 @@ describe('ValueSetExporter', () => {
         ]
       }
     });
+    expect(designation.isCodeCaretRule).toBeTrue();
     expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
   });
 
@@ -2118,6 +2121,7 @@ describe('ValueSetExporter', () => {
         ]
       }
     });
+    expect(designation.isCodeCaretRule).toBeTrue();
     expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
   });
 
@@ -2193,6 +2197,8 @@ describe('ValueSetExporter', () => {
         ]
       }
     });
+    expect(designationValue.isCodeCaretRule).toBeTrue();
+    expect(designationExtension.isCodeCaretRule).toBeTrue();
     expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
   });
 
@@ -2240,6 +2246,7 @@ describe('ValueSetExporter', () => {
         ]
       }
     });
+    expect(designation.isCodeCaretRule).toBeTrue();
     expect(loggerSpy.getAllMessages('error')).toHaveLength(1);
     expect(loggerSpy.getLastMessage('error')).toMatch(
       'Could not find concept http://food.org/food#Bread, skipping rule.'
diff --git a/test/fshtypes/FshCode.test.ts b/test/fshtypes/FshCode.test.ts
index f5dbb66..4cb4d13 100644
--- a/test/fshtypes/FshCode.test.ts
+++ b/test/fshtypes/FshCode.test.ts
@@ -47,6 +47,12 @@ describe('FshCode', () => {
       expect(result).toEqual('#"my\\ttabby\\tcode"');
     });
 
+    it('should return a string for a code that starts with a double quote', () => {
+      const code = new FshCode('"my-code');
+      const result = code.toString();
+      expect(result).toEqual('#"\\"my-code"');
+    });
+
     it('should return a string for a code where the code has non-whitespace characters that must be escaped', () => {
       const code = new FshCode('strange\\ "code"');
       const result = code.toString();
diff --git a/test/fshtypes/rules/CaretValueRule.test.ts b/test/fshtypes/rules/CaretValueRule.test.ts
index 3558797..0ad3a5b 100644
--- a/test/fshtypes/rules/CaretValueRule.test.ts
+++ b/test/fshtypes/rules/CaretValueRule.test.ts
@@ -181,7 +181,7 @@ describe('CaretValueRule', () => {
 
     it('should produce FSH for a CaretValueRule with isCodeCaretRule assigning a string', () => {
       const rule = new CaretValueRule('');
-      rule.pathArray = ['bear'];
+      rule.pathArray = ['#bear'];
       rule.isCodeCaretRule = true;
       rule.caretPath = 'display';
       rule.value = 'Bear is "here"';
@@ -189,9 +189,19 @@ describe('CaretValueRule', () => {
       expect(rule.toFSH()).toBe('* #bear ^display = "Bear is \\"here\\""');
     });
 
+    it('should produce FSH for a CaretValueRule with isCodeCaretRule where the path array includes systems', () => {
+      const rule = new CaretValueRule('');
+      rule.pathArray = ['zoo#bear'];
+      rule.isCodeCaretRule = true;
+      rule.caretPath = 'display';
+      rule.value = 'Bear is "here"';
+
+      expect(rule.toFSH()).toBe('* zoo#bear ^display = "Bear is \\"here\\""');
+    });
+
     it('should produce FSH for a nested CaretValueRule with isCodeCaretRule assigning a FshCanonical', () => {
       const rule = new CaretValueRule('');
-      rule.pathArray = ['owl', 'barnowl'];
+      rule.pathArray = ['#owl', '#barnowl'];
       rule.isCodeCaretRule = true;
       rule.caretPath = 'extension.url';
       rule.value = new FshCanonical('OwlExtension');
@@ -210,12 +220,22 @@ describe('CaretValueRule', () => {
 
     it('should produce FSH for a CaretValueRule with isCodeCaretRule where the code contains a space', () => {
       const rule = new CaretValueRule('');
-      rule.pathArray = ['duck', 'big duck'];
+      rule.pathArray = ['#duck', '#big duck'];
       rule.isCodeCaretRule = true;
       rule.caretPath = 'display';
       rule.value = 'is it a big duck or a goose?';
 
       expect(rule.toFSH()).toBe('* #duck #"big duck" ^display = "is it a big duck or a goose?"');
     });
+
+    it('should produce FSH for a CaretValueRUle with isCodeCaretRule where the code starts with a double quote', () => {
+      const rule = new CaretValueRule('');
+      rule.pathArray = ['zoo#"bear"'];
+      rule.isCodeCaretRule = true;
+      rule.caretPath = 'display';
+      rule.value = 'Bear is "here"';
+
+      expect(rule.toFSH()).toBe('* zoo#"\\"bear\\"" ^display = "Bear is \\"here\\""');
+    });
   });
 });
diff --git a/test/fshtypes/rules/ConceptRule.test.ts b/test/fshtypes/rules/ConceptRule.test.ts
index 3737045..e0926be 100644
--- a/test/fshtypes/rules/ConceptRule.test.ts
+++ b/test/fshtypes/rules/ConceptRule.test.ts
@@ -76,7 +76,17 @@ describe('ConceptRule', () => {
       rule.display = 'bar';
       rule.definition = 'baz';
 
-      const expectedResult = '* #"foo\twith\ta\ttab" "bar" "baz"';
+      const expectedResult = '* #"foo\\twith\\ta\\ttab" "bar" "baz"';
+      const result = rule.toFSH();
+      expect(result).toBe(expectedResult);
+    });
+
+    it('should produce FSH for a ConceptRule with a code that starts with quotes', () => {
+      const rule = new ConceptRule('"quotefoo"');
+      rule.display = 'bar';
+      rule.definition = 'baz';
+
+      const expectedResult = '* #"\\"quotefoo\\"" "bar" "baz"';
       const result = rule.toFSH();
       expect(result).toBe(expectedResult);
     });
diff --git a/test/import/FSHImporter.CodeSystem.test.ts b/test/import/FSHImporter.CodeSystem.test.ts
index 01edab7..ef0a191 100644
--- a/test/import/FSHImporter.CodeSystem.test.ts
+++ b/test/import/FSHImporter.CodeSystem.test.ts
@@ -434,7 +434,7 @@ describe('FSHImporter', () => {
           'property[0].valueString',
           'Their threat pose is really cute.',
           false,
-          ['anteater']
+          ['#anteater']
         );
         expect(codeSystem.rules[1].sourceInfo.file).toBe('Zoo.fsh');
         expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
@@ -461,7 +461,7 @@ describe('FSHImporter', () => {
           'property[0].valueString',
           'They are strong climbers.',
           false,
-          ['anteater', 'northern']
+          ['#anteater', '#northern']
         );
         expect(codeSystem.rules[2].sourceInfo.file).toBe('Zoo.fsh');
         expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
@@ -484,7 +484,7 @@ describe('FSHImporter', () => {
           'extension[0].valueInteger',
           0.45,
           false,
-          ['anteater'],
+          ['#anteater'],
           '0.4500'
         );
         expect(codeSystem.rules[1].sourceInfo.file).toBe('Zoo.fsh');
@@ -494,7 +494,7 @@ describe('FSHImporter', () => {
           'extension[1].valueBoolean',
           true,
           false,
-          ['anteater'],
+          ['#anteater'],
           'true'
         );
         expect(codeSystem.rules[2].sourceInfo.file).toBe('Zoo.fsh');
@@ -523,7 +523,7 @@ describe('FSHImporter', () => {
         const result = importSingleText(input, 'Insert.fsh');
         const cs = result.codeSystems.get('MyCS');
         expect(cs.rules).toHaveLength(2);
-        assertInsertRule(cs.rules[1] as InsertRule, '', 'MyRuleSet', [], ['cookie']);
+        assertInsertRule(cs.rules[1] as InsertRule, '', 'MyRuleSet', [], ['#cookie']);
       });
     });
   });
diff --git a/test/import/FSHImporter.RuleSet.test.ts b/test/import/FSHImporter.RuleSet.test.ts
index 503675e..24b24f5 100644
--- a/test/import/FSHImporter.RuleSet.test.ts
+++ b/test/import/FSHImporter.RuleSet.test.ts
@@ -243,7 +243,7 @@ describe('FSHImporter', () => {
         'designation.value',
         'Watch out for big cat!',
         false,
-        ['lion']
+        ['#lion']
       );
       expect(ruleSet.rules[3].sourceInfo.location).toEqual({
         startLine: 6,
diff --git a/test/import/FSHImporter.context.test.ts b/test/import/FSHImporter.context.test.ts
index 06dbe08..8b5f89b 100644
--- a/test/import/FSHImporter.context.test.ts
+++ b/test/import/FSHImporter.context.test.ts
@@ -882,7 +882,7 @@ describe('FSHImporter', () => {
         'property[0].valueString',
         'Their threat pose is really cute.',
         false,
-        ['anteater']
+        ['#anteater']
       );
       expect(codeSystem.rules[1].sourceInfo.file).toBe('Zoo.fsh');
       expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
@@ -909,7 +909,7 @@ describe('FSHImporter', () => {
         'property[0].valueString',
         'They are strong climbers.',
         false,
-        ['anteater', 'northern']
+        ['#anteater', '#northern']
       );
       expect(codeSystem.rules[2].sourceInfo.file).toBe('Zoo.fsh');
       expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
@@ -925,7 +925,7 @@ describe('FSHImporter', () => {
       const codeSystem = result.codeSystems.get('ZOO');
       expect(codeSystem.rules).toHaveLength(2);
       assertConceptRule(codeSystem.rules[0], 'anteater', 'Anteater', undefined, []);
-      assertInsertRule(codeSystem.rules[1], '', 'MyRuleSet', [], ['anteater']);
+      assertInsertRule(codeSystem.rules[1], '', 'MyRuleSet', [], ['#anteater']);
       expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
     });
 
@@ -953,7 +953,7 @@ describe('FSHImporter', () => {
         'property[0].valueString',
         'They are strong climbers.',
         false,
-        ['anteater', 'northern']
+        ['#anteater', '#northern']
       );
       expect(codeSystem.rules[2].sourceInfo.file).toBe('Zoo.fsh');
       assertConceptRule(codeSystem.rules[3], 'anteater', undefined, undefined, []);
@@ -964,7 +964,7 @@ describe('FSHImporter', () => {
         'property[0].valueString',
         'Their threat pose is really cute.',
         false,
-        ['anteater']
+        ['#anteater']
       );
       expect(codeSystem.rules[4].sourceInfo.file).toBe('Zoo.fsh');
       expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
@@ -1000,7 +1000,7 @@ describe('FSHImporter', () => {
         'property[0].valueString',
         'They are strong climbers.',
         false,
-        ['anteater', 'northern']
+        ['#anteater', '#northern']
       );
       expect(codeSystem.rules[4].sourceInfo.file).toBe('Zoo.fsh');
       expect(loggerSpy.getAllMessages('error')).toHaveLength(0);
@@ -1018,11 +1018,11 @@ describe('FSHImporter', () => {
       expect(codeSystem.rules[0].sourceInfo.file).toBe('Zoo.fsh');
       assertCaretValueRule(
         codeSystem.rules[1],
-        'anteater',
+        '#anteater',
         'property[0].valueString',
         'Their threat pose is really cute.',
         false,
-        ['anteater']
+        ['#anteater']
       );
       expect(codeSystem.rules[1].sourceInfo.file).toBe('Zoo.fsh');
       expect(loggerSpy.getAllMessages('error')).toHaveLength(0);