UNPKG

fhir

Version:

Library that assists in handling FHIR resources. Supports serialization between JSON and XML, validation and FhirPath evaluation.

225 lines 11.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SnapshotGenerator = void 0; class SnapshotGenerator { constructor(parser, bundle) { this.choiceRegexString = '(Instant|Time|Date|DateTime|Decimal|Boolean|Integer|String|Uri|Base64Binary|Code|Id|Oid|UnsignedInt|PositiveInt|Markdown|Url|Canonical|Uuid|Identifier|HumanName|Address|ContactPoint|Timing|Quantity|SimpleQuantity|Attachment|Range|Period|Ratio|CodeableConcept|Coding|SampledData|Age|Distance|Duration|Count|Money|MoneyQuantity|Annotation|Signature|ContactDetail|Contributor|DataRequirement|ParameterDefinition|RelatedArtifact|TriggerDefinition|UsageContext|Expression|Reference|Narrative|Extension|Meta|ElementDefinition|Dosage|Xhtml)'; this.processedUrls = []; this.parser = parser; this.bundle = bundle; } static createBundle(...structureDefinitions) { const entries = structureDefinitions.map((sd) => { return { resource: sd }; }); const bundle = { resourceType: 'Bundle', total: structureDefinitions.length, entry: entries }; return bundle; } getStructureDefinition(url, type) { const isBaseProfile = this.parser.isBaseProfile(url); const fhirBase = isBaseProfile ? this.parser.structureDefinitions.find(sd => sd.url.toLowerCase() === ('http://hl7.org/fhir/StructureDefinition/' + type).toLowerCase()) : null; if (isBaseProfile && !fhirBase) { throw new Error(`Base profile for ${url} not found. Perhaps the structures have not been loaded?`); } if (fhirBase) { return fhirBase; } const parentEntry = this.bundle.entry.find(entry => entry.resource.url === url); if (!parentEntry) { throw new Error(`Cannot find base definition "${url}" in bundle or core FHIR specification.`); } this.process(parentEntry.resource); return parentEntry.resource; } merge(diff, snapshot) { const dest = JSON.parse(JSON.stringify(snapshot)); const explicitOverwrites = ['id', 'representation', 'sliceName', 'sliceIsConstraining', 'label', 'code', 'short', 'definition', 'comment', 'requirements', 'alias', 'min', 'max', 'contentReference', 'meaningWhenMissing', 'orderMeaning', 'maxLength', 'condition', 'mustSupport', 'isModifier', 'isModifierReason', 'isSummary', 'example']; for (const eo of explicitOverwrites) { if (diff.hasOwnProperty(eo)) dest[eo] = diff[eo]; } if (diff.slicing && dest.slicing) { if (diff.slicing.hasOwnProperty('discriminator')) dest.slicing.discriminator = diff.slicing.discriminator; if (diff.slicing.hasOwnProperty('description')) dest.slicing.description = diff.slicing.description; if (diff.slicing.hasOwnProperty('ordered')) dest.slicing.ordered = diff.slicing.ordered; if (diff.slicing.hasOwnProperty('rules')) dest.slicing.rules = diff.slicing.rules; } else if (diff.slicing) { dest.slicing = diff.slicing; } if (diff.base && dest.base) { if (diff.base.hasOwnProperty('path')) dest.base.path = diff.base.path; if (diff.base.hasOwnProperty('min')) dest.base.min = diff.base.min; if (diff.base.hasOwnProperty('max')) dest.base.max = diff.base.max; } else if (diff.base) { dest.base = diff.base; } if (diff.type && dest.type) { for (const dt of dest.type) { const diffType = diff.type.find(t => t.code === dt.code); if (diffType) { if (diffType.hasOwnProperty('profile')) dt.profile = diffType.profile; if (diffType.hasOwnProperty('targetProfile')) dt.targetProfile = diffType.targetProfile; if (diffType.hasOwnProperty('aggregation')) dt.aggregation = diffType.aggregation; if (diffType.hasOwnProperty('versioning')) dt.versioning = diffType.versioning; } } for (const diffType of diff.type) { if (!dest.type.find(t => t.code === diffType.code)) { dest.type.push(JSON.parse(JSON.stringify(diffType))); } } } else if (diff.type) { dest.type = diff.type; } if (diff.constraint && dest.constraint) { for (const dc of dest.constraint) { const diffConstraint = diff.constraint.find(c => c.key === dc.key); if (diffConstraint) { if (diffConstraint.hasOwnProperty('requirements')) dc.requirements = diffConstraint.requirements; if (diffConstraint.hasOwnProperty('severity')) dc.severity = diffConstraint.severity; if (diffConstraint.hasOwnProperty('human')) dc.human = diffConstraint.human; if (diffConstraint.hasOwnProperty('expression')) dc.expression = diffConstraint.expression; if (diffConstraint.hasOwnProperty('xpath')) dc.xpath = diffConstraint.xpath; if (diffConstraint.hasOwnProperty('source')) dc.source = diffConstraint.source; } } for (const diffConstraint of diff.constraint) { if (!dest.constraint.find(c => c.key === diffConstraint.key)) { dest.constraint.push(JSON.parse(JSON.stringify(diffConstraint))); } } } else if (diff.constraint) { dest.constraint = diff.constraint; } const diffKeys = Object.keys(diff); const destKeys = Object.keys(dest); const diffDefaultValueKey = diffKeys.find(k => k.startsWith('defaultValue')); const diffMinValueKey = diffKeys.find(k => k.startsWith('minValue')); const diffMaxValueKey = diffKeys.find(k => k.startsWith('maxValue')); const diffFixedKey = diffKeys.find(k => k.startsWith('fixed')); const diffPatternKey = diffKeys.find(k => k.startsWith('pattern')); const destDefaultValueKey = destKeys.find(k => k.startsWith('defaultValue')); const destMinValueKey = destKeys.find(k => k.startsWith('minValue')); const destMaxValueKey = destKeys.find(k => k.startsWith('maxValue')); const destFixedKey = destKeys.find(k => k.startsWith('fixed')); const destPatternKey = destKeys.find(k => k.startsWith('pattern')); if (diffDefaultValueKey) { if (destDefaultValueKey) delete dest[destDefaultValueKey]; dest[diffDefaultValueKey] = diff[diffDefaultValueKey]; } if (diffMinValueKey) { if (destMinValueKey) delete dest[destMinValueKey]; dest[diffMinValueKey] = diff[diffMinValueKey]; } if (diffMaxValueKey) { if (destMaxValueKey) delete dest[destMaxValueKey]; dest[diffMaxValueKey] = diff[diffMaxValueKey]; } if (diffFixedKey) { if (destFixedKey) delete dest[destFixedKey]; dest[diffFixedKey] = diff[diffFixedKey]; } if (diffPatternKey) { if (destPatternKey) delete dest[destPatternKey]; dest[diffPatternKey] = diff[diffPatternKey]; } return dest; } process(structureDefinition) { if (this.parser.isBaseProfile(structureDefinition.url) || this.processedUrls.indexOf(structureDefinition.url) >= 0) { return; } if (!structureDefinition.differential || !structureDefinition.differential.element || structureDefinition.differential.element.length === 0) { throw new Error(`Structure ${structureDefinition.url} does not have a differential.`); } const base = this.getStructureDefinition(structureDefinition.baseDefinition, structureDefinition.type); const newElements = JSON.parse(JSON.stringify(base.snapshot.element)); const matched = newElements.filter(newElement => { if (newElement.path === structureDefinition.type) { return false; } const choiceName = newElement.path.match(/^(.*\.)?(.+)\[x\]/); const matching = structureDefinition.differential.element.filter((element) => { const regexString = newElement.path .replace(/\[x\]/g, this.choiceRegexString) .replace(/\./g, '\\.'); const regex = new RegExp(regexString, 'gm'); const isMatch = regex.test(element.path); return isMatch; }); return matching.length > 0; }); matched.forEach((snapshotElement) => { const snapshotIndex = newElements.indexOf(snapshotElement); const differentialElements = structureDefinition.differential.element.filter(element => { const regexString = snapshotElement.path .replace(/\[x\]/g, this.choiceRegexString) .replace(/\./g, '\\.') + '(\\..*)?'; const regex = new RegExp(regexString, 'gm'); return regex.test(element.path); }); const removeElements = newElements.filter((next) => next === snapshotElement || next.path.indexOf(snapshotElement.path + '.') === 0); removeElements.forEach(removeElement => { const index = newElements.indexOf(removeElement); newElements.splice(index, 1); }); for (let i = differentialElements.length - 1; i >= 0; i--) { const found = (base.snapshot && base.snapshot.element ? base.snapshot.element : []) .find(e => e.path === differentialElements[i].path); const diff = found ? this.merge(differentialElements[i], found) : differentialElements[i]; newElements.splice(snapshotIndex, 0, diff); } }); structureDefinition.snapshot = { element: newElements }; this.processedUrls.push(structureDefinition.url); } generate() { this.processedUrls = []; if (this.bundle && this.bundle.entry) { this.bundle.entry.forEach((entry) => { if (!entry.resource || entry.resource.resourceType !== 'StructureDefinition') { return; } this.process(entry.resource); }); } } } exports.SnapshotGenerator = SnapshotGenerator; //# sourceMappingURL=snapshotGenerator.js.map