diff --git a/src/optimizer/plugins/ConstructInlineInstanceOptimizer.ts b/src/optimizer/plugins/ConstructInlineInstanceOptimizer.ts index 89ad9d7b..f610f081 100644 --- a/src/optimizer/plugins/ConstructInlineInstanceOptimizer.ts +++ b/src/optimizer/plugins/ConstructInlineInstanceOptimizer.ts @@ -31,9 +31,16 @@ export default { optimize(pkg: Package, fisher: MasterFisher, options: ProcessingOptions = {}): void { const inlineInstances: ExportableInstance[] = []; - // Only construct inline instances in instances, profiles, and extensions. // If we add support for other types, update SimplifyInstanceNameOptimizer as well. - [...pkg.instances, ...pkg.profiles, ...pkg.extensions].forEach(resource => { + [ + ...pkg.instances, + ...pkg.profiles, + ...pkg.extensions, + ...pkg.logicals, + ...pkg.resources, + ...pkg.codeSystems, + ...pkg.valueSets + ].forEach(resource => { const ruleType = resource instanceof ExportableInstance ? ExportableAssignmentRule diff --git a/src/optimizer/plugins/SimplifyInstanceNameOptimizer.ts b/src/optimizer/plugins/SimplifyInstanceNameOptimizer.ts index d469c08e..74235088 100644 --- a/src/optimizer/plugins/SimplifyInstanceNameOptimizer.ts +++ b/src/optimizer/plugins/SimplifyInstanceNameOptimizer.ts @@ -35,7 +35,15 @@ export default { }); // Fix up inline assignments in types that may have them (see: ConstructInlineInstanceOptimizer) - [...pkg.instances, ...pkg.profiles, ...pkg.extensions].forEach(resource => { + [ + ...pkg.instances, + ...pkg.profiles, + ...pkg.extensions, + ...pkg.logicals, + ...pkg.resources, + ...pkg.codeSystems, + ...pkg.valueSets + ].forEach(resource => { const inlineAssignmentRules = resource.rules.filter( rule => (rule instanceof ExportableAssignmentRule || rule instanceof ExportableCaretValueRule) && diff --git a/test/optimizer/plugins/ConstructInlineInstanceOptimizer.test.ts b/test/optimizer/plugins/ConstructInlineInstanceOptimizer.test.ts index 30290e07..97dc604b 100644 --- a/test/optimizer/plugins/ConstructInlineInstanceOptimizer.test.ts +++ b/test/optimizer/plugins/ConstructInlineInstanceOptimizer.test.ts @@ -5,9 +5,13 @@ import { Package } from '../../../src/processor'; import { ExportableAssignmentRule, ExportableCaretValueRule, + ExportableCodeSystem, ExportableExtension, ExportableInstance, - ExportableProfile + ExportableLogical, + ExportableProfile, + ExportableResource, + ExportableValueSet } from '../../../src/exportable'; import optimizer from '../../../src/optimizer/plugins/ConstructInlineInstanceOptimizer'; import { @@ -451,6 +455,8 @@ describe('optimizer', () => { let containedId2: ExportableCaretValueRule; let profile: ExportableProfile; let extension: ExportableExtension; + let logical: ExportableLogical; + let resource: ExportableResource; beforeEach(() => { containedResourceType1 = new ExportableCaretValueRule(''); @@ -471,6 +477,10 @@ describe('optimizer', () => { profile.parent = 'Patient'; extension = new ExportableExtension('FooExtension'); + + logical = new ExportableLogical('Pretzel'); + + resource = new ExportableResource('Toast'); }); it('should create inline instances from contained resources on a profile', () => { @@ -557,6 +567,90 @@ describe('optimizer', () => { expect(extension.rules).toEqual([inlineInstanceRule1, inlineInstanceRule2]); }); + it('should create inline instances from contained resources on a logical', () => { + logical.rules = [ + containedResourceType1, + containedId1, + containedResourceType2, + containedId2 + ]; + const myPackage = new Package(); + myPackage.add(logical); + optimizer.optimize(myPackage, fisher); + + expect(myPackage.instances).toHaveLength(2); + assertExportableInstance( + myPackage.instances[0], + 'Bar', + 'Observation', + 'Inline', + undefined, + undefined, + [] + ); + assertExportableInstance( + myPackage.instances[1], + 'Baz', + 'ValueSet', + 'Inline', + undefined, + undefined, + [] + ); + + const inlineInstanceRule1 = new ExportableCaretValueRule(''); + inlineInstanceRule1.caretPath = 'contained[0]'; + inlineInstanceRule1.value = 'Bar'; + inlineInstanceRule1.isInstance = true; + const inlineInstanceRule2 = new ExportableCaretValueRule(''); + inlineInstanceRule2.caretPath = 'contained[1]'; + inlineInstanceRule2.value = 'Baz'; + inlineInstanceRule2.isInstance = true; + expect(logical.rules).toEqual([inlineInstanceRule1, inlineInstanceRule2]); + }); + + it('should create inline instances from contained resources on a resource', () => { + resource.rules = [ + containedResourceType1, + containedId1, + containedResourceType2, + containedId2 + ]; + const myPackage = new Package(); + myPackage.add(resource); + optimizer.optimize(myPackage, fisher); + + expect(myPackage.instances).toHaveLength(2); + assertExportableInstance( + myPackage.instances[0], + 'Bar', + 'Observation', + 'Inline', + undefined, + undefined, + [] + ); + assertExportableInstance( + myPackage.instances[1], + 'Baz', + 'ValueSet', + 'Inline', + undefined, + undefined, + [] + ); + + const inlineInstanceRule1 = new ExportableCaretValueRule(''); + inlineInstanceRule1.caretPath = 'contained[0]'; + inlineInstanceRule1.value = 'Bar'; + inlineInstanceRule1.isInstance = true; + const inlineInstanceRule2 = new ExportableCaretValueRule(''); + inlineInstanceRule2.caretPath = 'contained[1]'; + inlineInstanceRule2.value = 'Baz'; + inlineInstanceRule2.isInstance = true; + expect(resource.rules).toEqual([inlineInstanceRule1, inlineInstanceRule2]); + }); + it('should create an inline instance from a contained resource with non-numeric paths', () => { containedResourceType1.caretPath = 'contained.resourceType'; containedId1.caretPath = 'contained.id'; @@ -1118,5 +1212,183 @@ describe('optimizer', () => { expect(profile.rules).toEqual([inlineInstanceRule1]); }); }); + + describe('ValueSets', () => { + // All FSH types that use Caret rules work the same in this optimizer, + // so a limited subset of the tests from StructureDefinitions are used here. + let containedResourceType1: ExportableCaretValueRule; + let containedId1: ExportableCaretValueRule; + let valueSet: ExportableValueSet; + + beforeEach(() => { + containedResourceType1 = new ExportableCaretValueRule(''); + containedResourceType1.caretPath = 'contained[0].resourceType'; + containedResourceType1.value = 'Observation'; + containedId1 = new ExportableCaretValueRule(''); + containedId1.caretPath = 'contained[0].id'; + containedId1.value = 'Bar'; + + valueSet = new ExportableValueSet('MyValueSet'); + }); + + it('should create an inline instance from a contained resource with additional rules', () => { + const containedString = new ExportableCaretValueRule(''); + containedString.caretPath = 'contained[0].valueString'; + containedString.value = 'string value'; + valueSet.rules = [containedResourceType1, containedId1, containedString]; + const myPackage = new Package(); + myPackage.add(valueSet); + optimizer.optimize(myPackage, fisher); + + expect(myPackage.instances).toHaveLength(1); + const expectedRule = new ExportableAssignmentRule('valueString'); + expectedRule.value = 'string value'; + assertExportableInstance( + myPackage.instances[0], + 'Bar', + 'Observation', + 'Inline', + undefined, + undefined, + [expectedRule] + ); + + const inlineInstanceRule1 = new ExportableCaretValueRule(''); + inlineInstanceRule1.caretPath = 'contained[0]'; + inlineInstanceRule1.value = 'Bar'; + inlineInstanceRule1.isInstance = true; + expect(valueSet.rules).toEqual([inlineInstanceRule1]); + }); + + it('should create a profiled inline instance from a contained resource with multiple profiles when the metaProfile option is first', () => { + const containedProfile1 = new ExportableCaretValueRule(''); + containedProfile1.caretPath = 'contained[0].meta.profile[0]'; + containedProfile1.value = 'http://hl7.org/fhir/StructureDefinition/vitalsigns'; + const containedProfile2 = new ExportableCaretValueRule(''); + containedProfile2.caretPath = 'contained[0].meta.profile[1]'; + containedProfile2.value = + 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab'; + valueSet.rules = [ + containedResourceType1, + containedId1, + containedProfile1, + containedProfile2 + ]; + const myPackage = new Package(); + myPackage.add(valueSet); + optimizer.optimize(myPackage, fisher, { metaProfile: 'first' }); + + expect(myPackage.instances).toHaveLength(1); + const profileRule1 = new ExportableAssignmentRule('meta.profile[0]'); + profileRule1.value = + 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab'; + assertExportableInstance( + myPackage.instances[0], + 'Bar', + 'http://hl7.org/fhir/StructureDefinition/vitalsigns', + 'Inline', + undefined, + undefined, + [profileRule1] + ); + // Even though the second entry in meta.profile won't resolve, we don't try to resolve them when there is more than one. + expect(loggerSpy.getAllMessages('warn')).toHaveLength(0); + + const inlineInstanceRule1 = new ExportableCaretValueRule(''); + inlineInstanceRule1.caretPath = 'contained[0]'; + inlineInstanceRule1.value = 'Bar'; + inlineInstanceRule1.isInstance = true; + expect(valueSet.rules).toEqual([inlineInstanceRule1]); + }); + }); + + describe('CodeSystems', () => { + // All FSH types that use Caret rules work the same in this optimizer, + // so a limited subset of the tests from StructureDefinitions are used here. + let containedResourceType1: ExportableCaretValueRule; + let containedId1: ExportableCaretValueRule; + let codeSystem: ExportableCodeSystem; + + beforeEach(() => { + containedResourceType1 = new ExportableCaretValueRule(''); + containedResourceType1.caretPath = 'contained[0].resourceType'; + containedResourceType1.value = 'Observation'; + containedId1 = new ExportableCaretValueRule(''); + containedId1.caretPath = 'contained[0].id'; + containedId1.value = 'Bar'; + + codeSystem = new ExportableCodeSystem('MyCodeSystem'); + }); + + it('should create an inline instance from a contained resource with additional rules', () => { + const containedString = new ExportableCaretValueRule(''); + containedString.caretPath = 'contained[0].valueString'; + containedString.value = 'string value'; + codeSystem.rules = [containedResourceType1, containedId1, containedString]; + const myPackage = new Package(); + myPackage.add(codeSystem); + optimizer.optimize(myPackage, fisher); + + expect(myPackage.instances).toHaveLength(1); + const expectedRule = new ExportableAssignmentRule('valueString'); + expectedRule.value = 'string value'; + assertExportableInstance( + myPackage.instances[0], + 'Bar', + 'Observation', + 'Inline', + undefined, + undefined, + [expectedRule] + ); + + const inlineInstanceRule1 = new ExportableCaretValueRule(''); + inlineInstanceRule1.caretPath = 'contained[0]'; + inlineInstanceRule1.value = 'Bar'; + inlineInstanceRule1.isInstance = true; + expect(codeSystem.rules).toEqual([inlineInstanceRule1]); + }); + + it('should create a profiled inline instance from a contained resource with multiple profiles when the metaProfile option is first', () => { + const containedProfile1 = new ExportableCaretValueRule(''); + containedProfile1.caretPath = 'contained[0].meta.profile[0]'; + containedProfile1.value = 'http://hl7.org/fhir/StructureDefinition/vitalsigns'; + const containedProfile2 = new ExportableCaretValueRule(''); + containedProfile2.caretPath = 'contained[0].meta.profile[1]'; + containedProfile2.value = + 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab'; + codeSystem.rules = [ + containedResourceType1, + containedId1, + containedProfile1, + containedProfile2 + ]; + const myPackage = new Package(); + myPackage.add(codeSystem); + optimizer.optimize(myPackage, fisher, { metaProfile: 'first' }); + + expect(myPackage.instances).toHaveLength(1); + const profileRule1 = new ExportableAssignmentRule('meta.profile[0]'); + profileRule1.value = + 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab'; + assertExportableInstance( + myPackage.instances[0], + 'Bar', + 'http://hl7.org/fhir/StructureDefinition/vitalsigns', + 'Inline', + undefined, + undefined, + [profileRule1] + ); + // Even though the second entry in meta.profile won't resolve, we don't try to resolve them when there is more than one. + expect(loggerSpy.getAllMessages('warn')).toHaveLength(0); + + const inlineInstanceRule1 = new ExportableCaretValueRule(''); + inlineInstanceRule1.caretPath = 'contained[0]'; + inlineInstanceRule1.value = 'Bar'; + inlineInstanceRule1.isInstance = true; + expect(codeSystem.rules).toEqual([inlineInstanceRule1]); + }); + }); }); }); diff --git a/test/optimizer/plugins/SimplifyInstanceNameOptimizer.test.ts b/test/optimizer/plugins/SimplifyInstanceNameOptimizer.test.ts index 369f8b89..97a64b41 100644 --- a/test/optimizer/plugins/SimplifyInstanceNameOptimizer.test.ts +++ b/test/optimizer/plugins/SimplifyInstanceNameOptimizer.test.ts @@ -4,8 +4,13 @@ import { Package } from '../../../src/processor/Package'; import { ExportableAssignmentRule, ExportableCaretValueRule, + ExportableCodeSystem, + ExportableExtension, ExportableInstance, - ExportableProfile + ExportableLogical, + ExportableProfile, + ExportableResource, + ExportableValueSet } from '../../../src/exportable'; import { MasterFisher } from '../../../src/utils'; import { loadTestDefinitions, stockLake } from '../../helpers'; @@ -134,7 +139,7 @@ describe('optimizer', () => { expect(myPackage.instances).toEqual([expectedInstance1, expectedInstance2, expectedBundle]); }); - it('should update inlined contained rules in a profile when the inline instance name changes', () => { + it('should update inlined contained rules in a profile when the contained instance name changes', () => { const instance1 = new ExportableInstance('AmazingThings'); instance1.instanceOf = 'CodeSystem'; instance1.name = 'AmazingThings-of-CodeSystem'; @@ -146,19 +151,19 @@ describe('optimizer', () => { instance3.name = 'OtherAmazingThings-of-ValueSet'; const profile = new ExportableProfile('MyObservationProfile'); profile.parent = 'Observation'; - const profileContainedRule1 = new ExportableCaretValueRule(''); - profileContainedRule1.caretPath = 'contained[0]'; - profileContainedRule1.isInstance = true; - profileContainedRule1.value = 'AmazingThings-of-CodeSystem'; - const profileContainedRule2 = new ExportableCaretValueRule(''); - profileContainedRule2.caretPath = 'contained[1]'; - profileContainedRule2.isInstance = true; - profileContainedRule2.value = 'AmazingThings-of-ValueSet'; - const profileContainedRule3 = new ExportableCaretValueRule(''); - profileContainedRule3.caretPath = 'contained[2]'; - profileContainedRule3.isInstance = true; - profileContainedRule3.value = 'OtherAmazingThings-of-ValueSet'; - profile.rules = [profileContainedRule1, profileContainedRule2, profileContainedRule3]; + const containedRule1 = new ExportableCaretValueRule(''); + containedRule1.caretPath = 'contained[0]'; + containedRule1.isInstance = true; + containedRule1.value = 'AmazingThings-of-CodeSystem'; + const containedRule2 = new ExportableCaretValueRule(''); + containedRule2.caretPath = 'contained[1]'; + containedRule2.isInstance = true; + containedRule2.value = 'AmazingThings-of-ValueSet'; + const containedRule3 = new ExportableCaretValueRule(''); + containedRule3.caretPath = 'contained[2]'; + containedRule3.isInstance = true; + containedRule3.value = 'OtherAmazingThings-of-ValueSet'; + profile.rules = [containedRule1, containedRule2, containedRule3]; const myPackage = new Package(); myPackage.add(instance1); myPackage.add(instance2); @@ -184,19 +189,19 @@ describe('optimizer', () => { // Now check that names have been updated in inline assignments const expectedProfile = new ExportableProfile('MyObservationProfile'); expectedProfile.parent = 'Observation'; - const expectedProfileRule1 = new ExportableCaretValueRule(''); - expectedProfileRule1.caretPath = 'contained[0]'; - expectedProfileRule1.isInstance = true; - expectedProfileRule1.value = 'AmazingThings-of-CodeSystem'; // This name did not get changed - const expectedProfileRule2 = new ExportableCaretValueRule(''); - expectedProfileRule2.caretPath = 'contained[1]'; - expectedProfileRule2.isInstance = true; - expectedProfileRule2.value = 'AmazingThings-of-ValueSet'; // This name did not get changed - const expectedProfileRule3 = new ExportableCaretValueRule(''); - expectedProfileRule3.caretPath = 'contained[2]'; - expectedProfileRule3.isInstance = true; - expectedProfileRule3.value = 'OtherAmazingThings'; // This name was changed - expectedProfile.rules = [expectedProfileRule1, expectedProfileRule2, expectedProfileRule3]; + const expectedRule1 = new ExportableCaretValueRule(''); + expectedRule1.caretPath = 'contained[0]'; + expectedRule1.isInstance = true; + expectedRule1.value = 'AmazingThings-of-CodeSystem'; // This name did not get changed + const expectedRule2 = new ExportableCaretValueRule(''); + expectedRule2.caretPath = 'contained[1]'; + expectedRule2.isInstance = true; + expectedRule2.value = 'AmazingThings-of-ValueSet'; // This name did not get changed + const expectedRule3 = new ExportableCaretValueRule(''); + expectedRule3.caretPath = 'contained[2]'; + expectedRule3.isInstance = true; + expectedRule3.value = 'OtherAmazingThings'; // This name was changed + expectedProfile.rules = [expectedRule1, expectedRule2, expectedRule3]; expect(myPackage.instances).toEqual([ expectedInstance1, expectedInstance2, @@ -205,6 +210,351 @@ describe('optimizer', () => { expect(myPackage.profiles).toEqual([expectedProfile]); }); + it('should update inlined contained rules in an extension when the contained instance name changes', () => { + const instance1 = new ExportableInstance('AmazingThings'); + instance1.instanceOf = 'CodeSystem'; + instance1.name = 'AmazingThings-of-CodeSystem'; + const instance2 = new ExportableInstance('AmazingThings'); + instance2.instanceOf = 'ValueSet'; + instance2.name = 'AmazingThings-of-ValueSet'; + const instance3 = new ExportableInstance('OtherAmazingThings'); + instance3.instanceOf = 'ValueSet'; + instance3.name = 'OtherAmazingThings-of-ValueSet'; + const extension = new ExportableExtension('MyUsefulExtension'); + const containedRule1 = new ExportableCaretValueRule(''); + containedRule1.caretPath = 'contained[0]'; + containedRule1.isInstance = true; + containedRule1.value = 'AmazingThings-of-CodeSystem'; + const containedRule2 = new ExportableCaretValueRule(''); + containedRule2.caretPath = 'contained[1]'; + containedRule2.isInstance = true; + containedRule2.value = 'AmazingThings-of-ValueSet'; + const containedRule3 = new ExportableCaretValueRule(''); + containedRule3.caretPath = 'contained[2]'; + containedRule3.isInstance = true; + containedRule3.value = 'OtherAmazingThings-of-ValueSet'; + extension.rules = [containedRule1, containedRule2, containedRule3]; + const myPackage = new Package(); + myPackage.add(instance1); + myPackage.add(instance2); + myPackage.add(instance3); + myPackage.add(extension); + optimizer.optimize(myPackage); + + // Check that instances were renamed when appropriate + const amazingThingsIdRule = new ExportableAssignmentRule('id'); + amazingThingsIdRule.value = 'AmazingThings'; + const expectedInstance1 = new ExportableInstance('AmazingThings'); + expectedInstance1.instanceOf = 'CodeSystem'; + expectedInstance1.name = 'AmazingThings-of-CodeSystem'; // No name simplification since it will conflict with other instances + expectedInstance1.rules = [amazingThingsIdRule]; + const expectedInstance2 = new ExportableInstance('AmazingThings'); + expectedInstance2.instanceOf = 'ValueSet'; + expectedInstance2.name = 'AmazingThings-of-ValueSet'; // No name simplification since it will conflict with other instances + expectedInstance2.rules = [amazingThingsIdRule]; + const expectedInstance3 = new ExportableInstance('OtherAmazingThings'); + expectedInstance3.instanceOf = 'ValueSet'; + expectedInstance3.name = 'OtherAmazingThings'; // Name simplification since it didn't conflict with any other instances + // NOTE: expectedInstance3 should not have id rule since name matches id + // Now check that names have been updated in inline assignments + const expectedExtension = new ExportableExtension('MyUsefulExtension'); + const expectedRule1 = new ExportableCaretValueRule(''); + expectedRule1.caretPath = 'contained[0]'; + expectedRule1.isInstance = true; + expectedRule1.value = 'AmazingThings-of-CodeSystem'; // This name did not get changed + const expectedRule2 = new ExportableCaretValueRule(''); + expectedRule2.caretPath = 'contained[1]'; + expectedRule2.isInstance = true; + expectedRule2.value = 'AmazingThings-of-ValueSet'; // This name did not get changed + const expectedRule3 = new ExportableCaretValueRule(''); + expectedRule3.caretPath = 'contained[2]'; + expectedRule3.isInstance = true; + expectedRule3.value = 'OtherAmazingThings'; // This name was changed + expectedExtension.rules = [expectedRule1, expectedRule2, expectedRule3]; + expect(myPackage.instances).toEqual([ + expectedInstance1, + expectedInstance2, + expectedInstance3 + ]); + expect(myPackage.extensions).toEqual([expectedExtension]); + }); + + it('should update inlined contained rules in a logical when the contained instance name changes', () => { + const instance1 = new ExportableInstance('AmazingThings'); + instance1.instanceOf = 'CodeSystem'; + instance1.name = 'AmazingThings-of-CodeSystem'; + const instance2 = new ExportableInstance('AmazingThings'); + instance2.instanceOf = 'ValueSet'; + instance2.name = 'AmazingThings-of-ValueSet'; + const instance3 = new ExportableInstance('OtherAmazingThings'); + instance3.instanceOf = 'ValueSet'; + instance3.name = 'OtherAmazingThings-of-ValueSet'; + const logical = new ExportableLogical('PretzelLogical'); + const containedRule1 = new ExportableCaretValueRule(''); + containedRule1.caretPath = 'contained[0]'; + containedRule1.isInstance = true; + containedRule1.value = 'AmazingThings-of-CodeSystem'; + const containedRule2 = new ExportableCaretValueRule(''); + containedRule2.caretPath = 'contained[1]'; + containedRule2.isInstance = true; + containedRule2.value = 'AmazingThings-of-ValueSet'; + const containedRule3 = new ExportableCaretValueRule(''); + containedRule3.caretPath = 'contained[2]'; + containedRule3.isInstance = true; + containedRule3.value = 'OtherAmazingThings-of-ValueSet'; + logical.rules = [containedRule1, containedRule2, containedRule3]; + const myPackage = new Package(); + myPackage.add(instance1); + myPackage.add(instance2); + myPackage.add(instance3); + myPackage.add(logical); + optimizer.optimize(myPackage); + + // Check that instances were renamed when appropriate + const amazingThingsIdRule = new ExportableAssignmentRule('id'); + amazingThingsIdRule.value = 'AmazingThings'; + const expectedInstance1 = new ExportableInstance('AmazingThings'); + expectedInstance1.instanceOf = 'CodeSystem'; + expectedInstance1.name = 'AmazingThings-of-CodeSystem'; // No name simplification since it will conflict with other instances + expectedInstance1.rules = [amazingThingsIdRule]; + const expectedInstance2 = new ExportableInstance('AmazingThings'); + expectedInstance2.instanceOf = 'ValueSet'; + expectedInstance2.name = 'AmazingThings-of-ValueSet'; // No name simplification since it will conflict with other instances + expectedInstance2.rules = [amazingThingsIdRule]; + const expectedInstance3 = new ExportableInstance('OtherAmazingThings'); + expectedInstance3.instanceOf = 'ValueSet'; + expectedInstance3.name = 'OtherAmazingThings'; // Name simplification since it didn't conflict with any other instances + // NOTE: expectedInstance3 should not have id rule since name matches id + // Now check that names have been updated in inline assignments + const expectedLogical = new ExportableLogical('PretzelLogical'); + const expectedRule1 = new ExportableCaretValueRule(''); + expectedRule1.caretPath = 'contained[0]'; + expectedRule1.isInstance = true; + expectedRule1.value = 'AmazingThings-of-CodeSystem'; // This name did not get changed + const expectedRule2 = new ExportableCaretValueRule(''); + expectedRule2.caretPath = 'contained[1]'; + expectedRule2.isInstance = true; + expectedRule2.value = 'AmazingThings-of-ValueSet'; // This name did not get changed + const expectedRule3 = new ExportableCaretValueRule(''); + expectedRule3.caretPath = 'contained[2]'; + expectedRule3.isInstance = true; + expectedRule3.value = 'OtherAmazingThings'; // This name was changed + expectedLogical.rules = [expectedRule1, expectedRule2, expectedRule3]; + expect(myPackage.instances).toEqual([ + expectedInstance1, + expectedInstance2, + expectedInstance3 + ]); + expect(myPackage.logicals).toEqual([expectedLogical]); + }); + + it('should update inlined contained rules in a resource when the contained instance name changes', () => { + const instance1 = new ExportableInstance('AmazingThings'); + instance1.instanceOf = 'CodeSystem'; + instance1.name = 'AmazingThings-of-CodeSystem'; + const instance2 = new ExportableInstance('AmazingThings'); + instance2.instanceOf = 'ValueSet'; + instance2.name = 'AmazingThings-of-ValueSet'; + const instance3 = new ExportableInstance('OtherAmazingThings'); + instance3.instanceOf = 'ValueSet'; + instance3.name = 'OtherAmazingThings-of-ValueSet'; + const resource = new ExportableResource('Toast'); + const containedRule1 = new ExportableCaretValueRule(''); + containedRule1.caretPath = 'contained[0]'; + containedRule1.isInstance = true; + containedRule1.value = 'AmazingThings-of-CodeSystem'; + const containedRule2 = new ExportableCaretValueRule(''); + containedRule2.caretPath = 'contained[1]'; + containedRule2.isInstance = true; + containedRule2.value = 'AmazingThings-of-ValueSet'; + const containedRule3 = new ExportableCaretValueRule(''); + containedRule3.caretPath = 'contained[2]'; + containedRule3.isInstance = true; + containedRule3.value = 'OtherAmazingThings-of-ValueSet'; + resource.rules = [containedRule1, containedRule2, containedRule3]; + const myPackage = new Package(); + myPackage.add(instance1); + myPackage.add(instance2); + myPackage.add(instance3); + myPackage.add(resource); + optimizer.optimize(myPackage); + + // Check that instances were renamed when appropriate + const amazingThingsIdRule = new ExportableAssignmentRule('id'); + amazingThingsIdRule.value = 'AmazingThings'; + const expectedInstance1 = new ExportableInstance('AmazingThings'); + expectedInstance1.instanceOf = 'CodeSystem'; + expectedInstance1.name = 'AmazingThings-of-CodeSystem'; // No name simplification since it will conflict with other instances + expectedInstance1.rules = [amazingThingsIdRule]; + const expectedInstance2 = new ExportableInstance('AmazingThings'); + expectedInstance2.instanceOf = 'ValueSet'; + expectedInstance2.name = 'AmazingThings-of-ValueSet'; // No name simplification since it will conflict with other instances + expectedInstance2.rules = [amazingThingsIdRule]; + const expectedInstance3 = new ExportableInstance('OtherAmazingThings'); + expectedInstance3.instanceOf = 'ValueSet'; + expectedInstance3.name = 'OtherAmazingThings'; // Name simplification since it didn't conflict with any other instances + // NOTE: expectedInstance3 should not have id rule since name matches id + // Now check that names have been updated in inline assignments + const expectedResource = new ExportableResource('Toast'); + const expectedRule1 = new ExportableCaretValueRule(''); + expectedRule1.caretPath = 'contained[0]'; + expectedRule1.isInstance = true; + expectedRule1.value = 'AmazingThings-of-CodeSystem'; // This name did not get changed + const expectedRule2 = new ExportableCaretValueRule(''); + expectedRule2.caretPath = 'contained[1]'; + expectedRule2.isInstance = true; + expectedRule2.value = 'AmazingThings-of-ValueSet'; // This name did not get changed + const expectedRule3 = new ExportableCaretValueRule(''); + expectedRule3.caretPath = 'contained[2]'; + expectedRule3.isInstance = true; + expectedRule3.value = 'OtherAmazingThings'; // This name was changed + expectedResource.rules = [expectedRule1, expectedRule2, expectedRule3]; + expect(myPackage.instances).toEqual([ + expectedInstance1, + expectedInstance2, + expectedInstance3 + ]); + expect(myPackage.resources).toEqual([expectedResource]); + }); + + it('should update inlined contained rules in a code system when the contained instance name changes', () => { + const instance1 = new ExportableInstance('AmazingThings'); + instance1.instanceOf = 'CodeSystem'; + instance1.name = 'AmazingThings-of-CodeSystem'; + const instance2 = new ExportableInstance('AmazingThings'); + instance2.instanceOf = 'ValueSet'; + instance2.name = 'AmazingThings-of-ValueSet'; + const instance3 = new ExportableInstance('OtherAmazingThings'); + instance3.instanceOf = 'ValueSet'; + instance3.name = 'OtherAmazingThings-of-ValueSet'; + const codeSystem = new ExportableCodeSystem('MyCodeSystem'); + const containedRule1 = new ExportableCaretValueRule(''); + containedRule1.caretPath = 'contained[0]'; + containedRule1.isInstance = true; + containedRule1.value = 'AmazingThings-of-CodeSystem'; + const containedRule2 = new ExportableCaretValueRule(''); + containedRule2.caretPath = 'contained[1]'; + containedRule2.isInstance = true; + containedRule2.value = 'AmazingThings-of-ValueSet'; + const containedRule3 = new ExportableCaretValueRule(''); + containedRule3.caretPath = 'contained[2]'; + containedRule3.isInstance = true; + containedRule3.value = 'OtherAmazingThings-of-ValueSet'; + codeSystem.rules = [containedRule1, containedRule2, containedRule3]; + const myPackage = new Package(); + myPackage.add(instance1); + myPackage.add(instance2); + myPackage.add(instance3); + myPackage.add(codeSystem); + optimizer.optimize(myPackage); + + // Check that instances were renamed when appropriate + const amazingThingsIdRule = new ExportableAssignmentRule('id'); + amazingThingsIdRule.value = 'AmazingThings'; + const expectedInstance1 = new ExportableInstance('AmazingThings'); + expectedInstance1.instanceOf = 'CodeSystem'; + expectedInstance1.name = 'AmazingThings-of-CodeSystem'; // No name simplification since it will conflict with other instances + expectedInstance1.rules = [amazingThingsIdRule]; + const expectedInstance2 = new ExportableInstance('AmazingThings'); + expectedInstance2.instanceOf = 'ValueSet'; + expectedInstance2.name = 'AmazingThings-of-ValueSet'; // No name simplification since it will conflict with other instances + expectedInstance2.rules = [amazingThingsIdRule]; + const expectedInstance3 = new ExportableInstance('OtherAmazingThings'); + expectedInstance3.instanceOf = 'ValueSet'; + expectedInstance3.name = 'OtherAmazingThings'; // Name simplification since it didn't conflict with any other instances + // NOTE: expectedInstance3 should not have id rule since name matches id + // Now check that names have been updated in inline assignments + const expectedCodeSystem = new ExportableCodeSystem('MyCodeSystem'); + const expectedRule1 = new ExportableCaretValueRule(''); + expectedRule1.caretPath = 'contained[0]'; + expectedRule1.isInstance = true; + expectedRule1.value = 'AmazingThings-of-CodeSystem'; // This name did not get changed + const expectedRule2 = new ExportableCaretValueRule(''); + expectedRule2.caretPath = 'contained[1]'; + expectedRule2.isInstance = true; + expectedRule2.value = 'AmazingThings-of-ValueSet'; // This name did not get changed + const expectedRule3 = new ExportableCaretValueRule(''); + expectedRule3.caretPath = 'contained[2]'; + expectedRule3.isInstance = true; + expectedRule3.value = 'OtherAmazingThings'; // This name was changed + expectedCodeSystem.rules = [expectedRule1, expectedRule2, expectedRule3]; + expect(myPackage.instances).toEqual([ + expectedInstance1, + expectedInstance2, + expectedInstance3 + ]); + expect(myPackage.codeSystems).toEqual([expectedCodeSystem]); + }); + + it('should update inlined contained rules in a value set when the contained instance name changes', () => { + const instance1 = new ExportableInstance('AmazingThings'); + instance1.instanceOf = 'CodeSystem'; + instance1.name = 'AmazingThings-of-CodeSystem'; + const instance2 = new ExportableInstance('AmazingThings'); + instance2.instanceOf = 'ValueSet'; + instance2.name = 'AmazingThings-of-ValueSet'; + const instance3 = new ExportableInstance('OtherAmazingThings'); + instance3.instanceOf = 'ValueSet'; + instance3.name = 'OtherAmazingThings-of-ValueSet'; + const valueSet = new ExportableValueSet('MyValueSet'); + const containedRule1 = new ExportableCaretValueRule(''); + containedRule1.caretPath = 'contained[0]'; + containedRule1.isInstance = true; + containedRule1.value = 'AmazingThings-of-CodeSystem'; + const containedRule2 = new ExportableCaretValueRule(''); + containedRule2.caretPath = 'contained[1]'; + containedRule2.isInstance = true; + containedRule2.value = 'AmazingThings-of-ValueSet'; + const containedRule3 = new ExportableCaretValueRule(''); + containedRule3.caretPath = 'contained[2]'; + containedRule3.isInstance = true; + containedRule3.value = 'OtherAmazingThings-of-ValueSet'; + valueSet.rules = [containedRule1, containedRule2, containedRule3]; + const myPackage = new Package(); + myPackage.add(instance1); + myPackage.add(instance2); + myPackage.add(instance3); + myPackage.add(valueSet); + optimizer.optimize(myPackage); + + // Check that instances were renamed when appropriate + const amazingThingsIdRule = new ExportableAssignmentRule('id'); + amazingThingsIdRule.value = 'AmazingThings'; + const expectedInstance1 = new ExportableInstance('AmazingThings'); + expectedInstance1.instanceOf = 'CodeSystem'; + expectedInstance1.name = 'AmazingThings-of-CodeSystem'; // No name simplification since it will conflict with other instances + expectedInstance1.rules = [amazingThingsIdRule]; + const expectedInstance2 = new ExportableInstance('AmazingThings'); + expectedInstance2.instanceOf = 'ValueSet'; + expectedInstance2.name = 'AmazingThings-of-ValueSet'; // No name simplification since it will conflict with other instances + expectedInstance2.rules = [amazingThingsIdRule]; + const expectedInstance3 = new ExportableInstance('OtherAmazingThings'); + expectedInstance3.instanceOf = 'ValueSet'; + expectedInstance3.name = 'OtherAmazingThings'; // Name simplification since it didn't conflict with any other instances + // NOTE: expectedInstance3 should not have id rule since name matches id + // Now check that names have been updated in inline assignments + const expectedValueSet = new ExportableValueSet('MyValueSet'); + const expectedRule1 = new ExportableCaretValueRule(''); + expectedRule1.caretPath = 'contained[0]'; + expectedRule1.isInstance = true; + expectedRule1.value = 'AmazingThings-of-CodeSystem'; // This name did not get changed + const expectedRule2 = new ExportableCaretValueRule(''); + expectedRule2.caretPath = 'contained[1]'; + expectedRule2.isInstance = true; + expectedRule2.value = 'AmazingThings-of-ValueSet'; // This name did not get changed + const expectedRule3 = new ExportableCaretValueRule(''); + expectedRule3.caretPath = 'contained[2]'; + expectedRule3.isInstance = true; + expectedRule3.value = 'OtherAmazingThings'; // This name was changed + expectedValueSet.rules = [expectedRule1, expectedRule2, expectedRule3]; + expect(myPackage.instances).toEqual([ + expectedInstance1, + expectedInstance2, + expectedInstance3 + ]); + expect(myPackage.valueSets).toEqual([expectedValueSet]); + }); + it('should still rename instances when there is a different instance with the same id but it is inline only', () => { const instance1 = new ExportableInstance('AmazingThings'); instance1.instanceOf = 'CodeSystem';