UNPKG

@claudebernard/fhir-mapper

Version:

A simple FHIR / BCB resource mapper to help stay interoperable while still using the Claude Bernard intelligence

919 lines (911 loc) 38.6 kB
const unitsOfTime = { 's': { value: 0, label: 'seconde' }, 'min': { value: 10, label: 'minute' }, 'h': { value: 20, label: 'heure' }, 'd': { value: 40, label: 'jour' }, 'wk': { value: 50, label: 'semaine' }, 'mo': { value: 70, label: 'mois' }, 'a': { value: 100, label: 'an' } }; function buildDoseAndRate(dosage) { const coding = { system: dosage.codeUnitePrise ? 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/intake-units' : undefined, code: dosage.codeUnitePrise ?? undefined, unit: dosage.codeUnitePrise ? dosage.libUnitePrise : undefined }; const doseAndRate = dosage.quantite2 ? { doseRange: { low: { value: dosage.quantite1, ...coding }, high: { value: dosage.quantite2, ...coding } } } : { doseQuantity: { value: dosage.quantite1, ...coding } }; return [doseAndRate]; } // The formula used here is count = dose * frequency * (duration / period) function calculateCount(dose, frequency, period, periodUnit, duration, durationUnit) { // Provide default values for null or undefined parameters const actualDose = dose ?? 0; const actualFrequency = frequency ?? 0; const actualPeriod = period ?? 1; const actualDuration = duration ?? 0; const actualPeriodUnit = periodUnit ?? ''; const actualDurationUnit = durationUnit ?? ''; // Convert duration to the same unit as period const convertedDuration = actualDurationUnit === actualPeriodUnit ? actualDuration : convertTime(actualDuration, actualDurationUnit, actualPeriodUnit); // Check if dose, frequency, convertedDuration, or period is null or 0 and compute count accordingly if (!actualDose) { return actualFrequency * (convertedDuration / actualPeriod); } else if (!actualFrequency) { return actualDose * (convertedDuration / actualPeriod); } else if (!convertedDuration) { return actualDose * actualFrequency * actualPeriod; } else if (!actualPeriod) { return actualDose * actualFrequency * convertedDuration; } else { return actualDose * actualFrequency * (convertedDuration / actualPeriod); } } function convertTime(value, fromUnit, toUnit) { const conversionFactors = { 's': 1, 'min': 60, 'h': 3600, 'd': 86400, 'wk': 604800, 'mo': 2628000, 'a': 31536000 }; if (!conversionFactors[fromUnit]) { throw new Error(`Invalid fromUnit: ${fromUnit}`); } if (!conversionFactors[toUnit]) { throw new Error(`Invalid toUnit: ${toUnit}`); } // Convert the input value to seconds const valueInSeconds = value * conversionFactors[fromUnit]; // Convert from seconds to the desired unit const convertedValue = valueInSeconds / conversionFactors[toUnit]; return convertedValue; } async function handleCodifications(dosage, indicationMapper, routeMapper, intakeMapper) { let conditionCode; let conditionLabel; let intakeCode; let intakeLabel; let routeCode; let routeLabel; let errors = []; if (dosage.asNeededFor && dosage.asNeededFor[0].coding && dosage.asNeededFor[0].coding.length > 0) { if (dosage.asNeededFor[0]?.coding?.[0]?.system === 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/indications') { conditionCode = dosage.asNeededFor?.[0]?.coding?.[0]?.code; conditionLabel = dosage.asNeededFor?.[0]?.coding?.[0]?.display; } else if (indicationMapper) { const result = await indicationMapper(dosage?.asNeededFor?.[0]?.coding?.[0]); let indication = undefined; if (Array.isArray(result)) { if (result.length > 0) indication = result[0]; } else if (result) { indication = result; } if (indication) { conditionCode = indication.code; conditionLabel = indication.label; } else { conditionCode = undefined; conditionLabel = undefined; errors.push({ field: 'codeIndication', message: 'No mapping found for indication code' }); } } else { errors.push({ field: 'codeIndication', message: 'The system used in the asNeededFor coding field is not supported and no custom mapper was provided' }); } } if (dosage.route && dosage.route.coding && dosage.route.coding.length > 0) { if (dosage.route?.coding?.[0]?.system === 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/routes') { routeCode = parseInt(dosage?.route?.coding?.[0]?.code ?? ''); routeLabel = dosage.route?.coding?.[0]?.display; } else if (dosage.route && routeMapper) { const result = await routeMapper(dosage.route?.coding?.[0]); let route = undefined; if (Array.isArray(result)) { if (result.length > 0) route = result[0]; } else if (result) { route = result; } if (route) { routeCode = parseInt(route.code); routeLabel = route.label; } else { routeCode = undefined; routeLabel = undefined; errors.push({ field: 'codeVoie', message: 'No mapping found for route code' }); } } else { errors.push({ field: 'codeVoie', message: 'The system used in the route coding field is not supported and no custom mapper was provided' }); } } if (dosage.doseAndRate && dosage.doseAndRate.length > 0) { if (dosage.doseAndRate?.[0]?.doseQuantity?.system === 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/intake-units') { intakeCode = parseInt(dosage.doseAndRate?.[0]?.doseQuantity.code ?? ''); intakeLabel = dosage.doseAndRate?.[0]?.doseQuantity.unit; } else if (dosage.doseAndRate && intakeMapper) { const result = await intakeMapper(dosage.doseAndRate?.[0]?.doseQuantity); let intake = undefined; if (Array.isArray(result)) { if (result.length > 0) intake = result[0]; } else if (result) { intake = result; } if (intake) { intakeCode = parseInt(intake.code); intakeLabel = intake.label; } else { intakeCode = undefined; intakeLabel = undefined; errors.push({ field: 'codeUnitePrise', message: 'No mapping found for intake code' }); } } else { errors.push({ field: 'codeUnitePrise', message: 'The system used in the doseQuantity coding field is not supported and no custom mapper was provided' }); } } return { conditionCode, conditionLabel, intakeCode, intakeLabel, routeCode, routeLabel, codificationErrors: errors }; } // adding this function to support new naming convention without breaking changes async function fhirToBcb$1(dosageInstructions, indicationMapper, routeMapper, intakeMapper) { return await mapToBcb(dosageInstructions, indicationMapper, routeMapper, intakeMapper); } async function mapToBcb(dosageInstructions, indicationMapper, routeMapper, intakeMapper) { if (!dosageInstructions || dosageInstructions.length === 0) { return [ { result: undefined, errors: [{ field: 'root', message: 'Invalid Dosage array' }] } ]; } const safeIndicationMapper = wrapMaybeAsync$1(indicationMapper); const safeRouteMapper = wrapMaybeAsync$1(routeMapper); const safeIntakeMapper = wrapMaybeAsync$1(intakeMapper); const results = []; for (const dosage of dosageInstructions) { let errors = []; const periodUnit = dosage.timing?.repeat?.periodUnit; const quantite1 = dosage?.doseAndRate?.[0]?.doseQuantity?.value ?? dosage?.doseAndRate?.[0]?.doseRange?.low?.value; const quantite2 = dosage?.doseAndRate?.[0]?.doseRange?.high?.value ?? null; let maximum = null; let codeDuree3 = null; let maxDosePerDay = null; if (dosage.maxDosePerPeriod) { maxDosePerDay = dosage.maxDosePerPeriod.find(period => period?.denominator?.unit === 'd' && period?.denominator?.value === 1); if (maxDosePerDay) { maximum = maxDosePerDay?.numerator?.value; codeDuree3 = maxDosePerDay?.denominator?.unit; } } let libSpecifPrise1 = dosage.asNeeded ? 'selon besoin' : null; const doseSpacing = dosage.maxDosePerPeriod?.find(period => period?.denominator?.unit === 'h'); if (doseSpacing) { const spacingText = `en espaçant les prises de ${doseSpacing?.denominator?.value}h minimum`; libSpecifPrise1 = libSpecifPrise1 ? `${libSpecifPrise1}, ${spacingText}` : spacingText; } // handleCodifications must be updated to support async mappers const { conditionCode, conditionLabel, intakeCode, intakeLabel, routeCode, routeLabel, codificationErrors } = await handleCodifications(dosage, safeIndicationMapper, safeRouteMapper, safeIntakeMapper); const codeDuree2 = dosage?.timing?.repeat?.boundsDuration?.code; const bcbDosage = { noPosologie: dosage.sequence ?? undefined, libellePosologie: dosage.text ?? undefined, codeIndication: conditionCode, libIndication: conditionLabel, codeDuree1: periodUnit ? unitsOfTime[periodUnit]?.value : undefined, libDuree1: periodUnit ? unitsOfTime[periodUnit]?.label : undefined, quantite1: quantite1 ?? undefined, quantite2: quantite2 ?? undefined, tousLes: dosage.timing?.repeat?.period ?? undefined, combien1: dosage.timing?.repeat?.frequency ?? undefined, combien2: dosage.timing?.repeat?.frequencyMax ?? undefined, pendant1: dosage.timing?.repeat?.boundsDuration?.value ?? undefined, codeUnitePrise: intakeCode, libUnitePrise: intakeLabel, codeVoie: routeCode, libVoie: routeLabel, codeDuree2: codeDuree2 ? unitsOfTime[codeDuree2]?.value : undefined, libDuree2: codeDuree2 ? unitsOfTime[codeDuree2]?.label : undefined, maximum: maximum ?? undefined, codeDuree3: codeDuree3 ? unitsOfTime[codeDuree3]?.value : undefined, libDuree3: codeDuree3 ? unitsOfTime[codeDuree3]?.label : undefined, libSpecifPrise1: libSpecifPrise1 ?? undefined }; results.push({ result: bcbDosage, errors: codificationErrors.concat(errors) }); } return results; } // adding this function to support new naming convention without breaking changes function bcbToFhir$1(bcbDosages) { return mapToFhir(bcbDosages); } function mapToFhir(bcbDosages) { if (!bcbDosages || bcbDosages.length === 0) { throw new Error('Invalid BCBPosologieStructuree2 array'); } return bcbDosages.map((dosage) => { const keys = Object.keys(unitsOfTime); const periodUnit = keys.find(key => unitsOfTime[key].value === dosage.codeDuree1) ?? undefined; const durationUnit = keys.find(key => unitsOfTime[key].value === dosage.codeDuree2) ?? undefined; const maximumUnit = keys.find(key => unitsOfTime[key].value === dosage.codeDuree3) ?? undefined; const route = dosage.codeVoie ? { coding: [{ system: 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/routes', code: dosage.codeVoie.toString(), display: dosage.libVoie }] } : undefined; const intake = dosage.codeUnitePrise ? { coding: [{ system: 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/intake-units', code: dosage.codeUnitePrise.toString(), display: dosage.libUnitePrise }] } : undefined; const indication = dosage.codeIndication ? [{ coding: [{ system: 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/indications', code: dosage.codeIndication, display: dosage.libIndication }] }] : undefined; const maxDosePerPeriod = dosage.maximum ? [{ numerator: { value: dosage.maximum, system: 'https://platform.claudebernard.fr/fhir/ImplementationGuides/ValueSet/intake-units', code: intake?.coding?.[0]?.code, unit: intake?.coding?.[0]?.display }, denominator: { value: 1, unit: maximumUnit } }] : undefined; const doseAndRate = buildDoseAndRate(dosage); const boundsDuration = dosage.pendant1 ? { value: dosage.pendant1, unit: durationUnit } : undefined; const asNeeded = dosage.libSpecifPrise1?.includes('besoin'); return { result: { text: dosage.libellePosologie, sequence: dosage.noPosologie, doseAndRate: doseAndRate, maxDosePerPeriod: dosage.maximum ? maxDosePerPeriod : undefined, route: route, asNeeded: asNeeded, asNeededFor: indication, timing: { repeat: { frequency: dosage.combien1, frequencyMax: dosage.combien2, period: dosage.tousLes, periodUnit: periodUnit, boundsDuration: boundsDuration, count: calculateCount(dosage.quantite1, dosage.combien1, dosage.tousLes, periodUnit, dosage.pendant1, durationUnit), countMax: calculateCount(dosage.quantite2 ?? dosage.quantite1, dosage.combien2 ?? dosage.combien1, dosage.tousLes, periodUnit, dosage.pendant2 ?? dosage.pendant1, durationUnit) } } }, errors: [] }; }); } // Utility to wrap a possibly sync or async function so it always returns a Promise function wrapMaybeAsync$1(fn) { if (!fn) return undefined; return ((...args) => Promise.resolve(fn(...args))); } var dosageMapper = /*#__PURE__*/Object.freeze({ __proto__: null, bcbToFhir: bcbToFhir$1, fhirToBcb: fhirToBcb$1, mapToBcb: mapToBcb, mapToFhir: mapToFhir }); const genderMap = { male: 'M', female: 'F' }; const fhirGenderMap = { M: 'male', F: 'female' }; const hepaticInsufficiencyMap = { 'A': { code: 'K72.90', display: 'Mild hepatic insufficiency' }, 'B': { code: 'K72.91', display: 'Moderate hepatic insufficiency' }, 'C': { code: 'K72.92', display: 'Severe hepatic insufficiency' } }; const hepaticInsufficiencyReverseMap = { 'K72.90': 'A', 'K72.91': 'B', 'K72.92': 'C' }; const calculateAgeInMonths = (birthDate) => { const birth = new Date(birthDate); const today = new Date(); const yearsDifference = today.getFullYear() - birth.getFullYear(); const monthsDifference = today.getMonth() - birth.getMonth(); const daysDifference = today.getDate() - birth.getDate(); let ageInMonths = yearsDifference * 12 + monthsDifference; if (daysDifference < 0) { ageInMonths--; } return ageInMonths; }; const calculateBirthDateFromAgeInMonths = (ageInMonths) => { const today = new Date(); const birthDate = new Date(today.setMonth(today.getMonth() - ageInMonths)); const year = birthDate.getFullYear(); const month = (birthDate.getMonth() + 1).toString().padStart(2, '0'); const day = birthDate.getDate().toString().padStart(2, '0'); return `${year}-${month}-${day}`; }; const convertPatient = (bcbPatient) => { return { firstName: '', lastName: '', age: bcbPatient.age, gender: bcbPatient.sexe, weight: bcbPatient.poids, pregnancy: bcbPatient.grossesse === 1, breastfeeding: bcbPatient.allaitement === 1, ammPathologies: bcbPatient.lstPathologiesAMM.map(code => ({ type: 'AMM', code: code, label: '' })), allergies: bcbPatient.lstIdComposantAllergie.map(code => ({ code: code, label: '' })), hepaticStage: bcbPatient.insuffisanceHepatique, height: bcbPatient.taille, weeksOfPregnancy: 0, creatinineClearance: bcbPatient.clairanceCreatinine, molCreatinine: bcbPatient.creatininemieMol, mglCreatinine: bcbPatient.creatininemieMg, gfr: 0, medicalTeam: { firstNameDoctor: "", lastNameDoctor: "", firstNameSpecialist: "", lastNameSpecialist: "", firstNamePharmacist: "", lastNamePharmacist: "", firstNameNurse: "", lastNameNurse: "" } }; }; const sortEntries = async (target, entries, allergiesMapper, snomedPathologiesMapper, errors = []) => { const patientEntry = entries.find(entry => entry?.resource?.resourceType === "Patient")?.resource; const observationEntries = entries.filter(entry => entry?.resource?.resourceType === "Observation").map(entry => entry?.resource); const conditionEntries = entries.filter(entry => entry?.resource?.resourceType === "Condition").map(entry => entry?.resource); const allergyIntoleranceEntries = entries.filter(entry => entry?.resource?.resourceType === "AllergyIntolerance").map(entry => entry?.resource); const weightObservation = observationEntries.find(entry => entry?.code?.coding?.[0]?.code === '29463-7'); const heightObservation = observationEntries.find(entry => entry?.code?.coding?.[0]?.code === '8302-2'); const pregnancyObservation = observationEntries.find(entry => entry?.code?.coding?.some(coding => coding.code === '82810-3')); const breastfeedingObservation = observationEntries.find(entry => entry?.code?.coding?.some(coding => coding.code === '63895-7')); const hepaticCondition = conditionEntries.find(entry => entry?.code?.coding?.some(coding => coding.code === '2164-2' || coding.code === '14682-9' || coding.code === '2160-0')); let lstIdComposantAllergie = []; let errorField = target === 'bcb' ? 'lstIdComposantAllergie' : 'allergies'; for (const allergyEntry of allergyIntoleranceEntries) { if (allergiesMapper) { const mappingResult = await allergiesMapper(allergyEntry?.code?.coding?.[0]); if (Array.isArray(mappingResult)) { if (mappingResult.length > 0) { lstIdComposantAllergie.push(...mappingResult); } else { errors.push({ field: errorField, message: `No mapping found for allergy code ${allergyEntry?.code?.coding?.[0]?.code}` }); } } else if (mappingResult) { lstIdComposantAllergie.push(mappingResult); } else { errors.push({ field: errorField, message: `No mapping found for allergy code ${allergyEntry?.code?.coding?.[0]?.code}` }); } } else { errors.push({ field: errorField, message: 'Allergy Intolerance values were found but no allergies mapper was provided, the output field is thus left empty.' }); } } const cim10PathologiesEntries = conditionEntries.filter(entry => entry?.code?.coding?.some(coding => coding.system === 'http://hl7.org/fhir/sid/icd-10')).map(pathology => ({ code: pathology?.code?.coding?.[0]?.code || '', label: '' })); const snomedPathologiesEntries = conditionEntries.filter(entry => entry?.code?.coding?.some(coding => coding.system === 'http://snomed.info/sct')); const ammPathologiesEntries = conditionEntries.filter(entry => entry?.code?.coding?.some(coding => coding.system === 'https://platform.claudebernard.fr/fhir/ImplementationGuides/CodeSystem/amm')).map(pathology => ({ code: pathology?.code?.coding?.[0]?.code || '', label: '' })); let lstPathologies = []; lstPathologies.push(...ammPathologiesEntries); let lstCim10Pathologies = []; lstCim10Pathologies.push(...cim10PathologiesEntries); errorField = target === 'bcb' ? 'lstPathologiesAMM' : 'ammPathologies'; for (const pathology of snomedPathologiesEntries) { if (snomedPathologiesMapper) { const mappingResult = await snomedPathologiesMapper(pathology?.code?.coding?.[0]); if (Array.isArray(mappingResult)) { if (mappingResult.length > 0) { lstPathologies.push(...mappingResult); } else { errors.push({ field: errorField, message: `No mapping found for snomed code ${pathology?.code?.coding?.[0]?.code}` }); } } else if (mappingResult) { lstPathologies.push(mappingResult); } else { errors.push({ field: errorField, message: `No mapping found for snomed code ${pathology?.code?.coding?.[0]?.code}` }); } } else { errors.push({ field: errorField, message: "Snomed pathologies were found but no mapper was provided, the output field is thus left empty." }); } } const clairanceCreatinineObservation = observationEntries.find(entry => entry?.code?.coding?.some(coding => coding.code === '2164-2')); const creatininemieMolObservation = observationEntries.find(entry => entry?.code?.coding?.some(coding => coding.code === '14682-9')); const creatininemieMgObservation = observationEntries.find(entry => entry?.code?.coding?.some(coding => coding.code === '2160-0')); return { patientEntry, weightObservation, heightObservation, pregnancyObservation, breastfeedingObservation, hepaticCondition, lstIdComposantAllergie, lstCim10Pathologies, lstPathologies, clairanceCreatinineObservation, creatininemieMolObservation, creatininemieMgObservation }; }; const patientToFhir = (patientData) => { if (!patientData) { return { result: undefined, errors: [{ field: 'root', message: 'Invalid patient object' }] }; } let errors = []; const bundleEntries = []; const patient = { resourceType: 'Patient', id: '1', birthDate: calculateBirthDateFromAgeInMonths(patientData.age), gender: fhirGenderMap[patientData.gender] || 'unknown' }; const weightObservation = { resourceType: 'Observation', id: '2', code: { coding: [{ code: '29463-7', display: 'Body Weight' }] }, status: 'final', valueQuantity: { value: patientData.weight, unit: 'kg' }, subject: { reference: 'Patient/1' } }; const heightObservation = { resourceType: 'Observation', id: '3', code: { coding: [{ code: '8302-2', display: 'Body Height' }] }, status: 'final', valueQuantity: { value: patientData.height, unit: 'cm' }, subject: { reference: 'Patient/1' } }; let pregnancyObservation = undefined; if (patientData.pregnancy) { pregnancyObservation = { resourceType: 'Observation', id: '4', code: { coding: [{ code: '82810-3', display: 'Pregnancy Status' }] }, status: 'final', subject: { reference: 'Patient/1' } }; } if (pregnancyObservation && patientData.weeksOfPregnancy > 0) { pregnancyObservation.valueQuantity = { value: patientData.weeksOfPregnancy, unit: 'weeks', system: 'http://unitsofmeasure.org', code: 'wk' }; } let breastfeedingObservation = undefined; if (patientData.breastfeeding) { breastfeedingObservation = { resourceType: 'Observation', id: '5', code: { coding: [{ code: '63895-7', display: 'Breastfeeding Status' }] }, status: 'final', subject: { reference: 'Patient/1' } }; } let creatinineClearanceObservation; if (patientData.creatinineClearance > 0) { creatinineClearanceObservation = { resourceType: 'Observation', id: '5', code: { coding: [{ system: 'http://loinc.org', code: '2164-2', display: 'Creatinine clearance' }] }, status: 'final', valueQuantity: { value: patientData.creatinineClearance, unit: 'mL/min' }, subject: { reference: 'Patient/1' } }; } let creatinineMolObservation; if (patientData.molCreatinine > 0) { creatinineMolObservation = { resourceType: 'Observation', id: '6', code: { coding: [{ system: 'http://loinc.org', code: '14682-9', display: 'Creatinine [Moles/volume] in Serum or Plasma' }] }, status: 'final', valueQuantity: { value: patientData.molCreatinine, unit: 'mmol/L' }, subject: { reference: 'Patient/1' } }; } let creatinineMgObservation; if (patientData.mglCreatinine > 0) { creatinineMgObservation = { resourceType: 'Observation', id: '7', code: { coding: [{ system: 'http://loinc.org', code: '2160-0', display: 'Creatinine [Mass/volume] in Serum or Plasma' }] }, status: 'final', valueQuantity: { value: patientData.mglCreatinine, unit: 'mg/dL' }, subject: { reference: 'Patient/1' } }; } let conditions = []; if (patientData.ammPathologies) { conditions = patientData.ammPathologies.map((pathology) => { return { resourceType: 'Condition', id: pathology.code, code: { coding: [{ system: 'https://platform.claudebernard.fr/fhir/ImplementationGuides/CodeSystem/amm', code: pathology.code, display: pathology.label // TODO : find a way to add the label }] }, clinicalStatus: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/condition-clinical', code: 'active', display: 'Active' }] }, subject: { reference: 'Patient/1' } }; }); } let hepaticInsufficiencyCondition; if (patientData.hepaticStage && hepaticInsufficiencyMap[patientData.hepaticStage]) { const stage = hepaticInsufficiencyMap[patientData.hepaticStage]; hepaticInsufficiencyCondition = { resourceType: 'Condition', id: 'hepatic-insufficiency', code: { coding: [{ system: 'http://hl7.org/fhir/sid/icd-10', code: stage.code, display: stage.display }] }, clinicalStatus: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/condition-clinical', code: 'active', display: 'Active' }] }, verificationStatus: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/condition-ver-status', code: 'confirmed', display: 'Confirmed' }] }, subject: { reference: 'Patient/1' } }; } let allergies = []; if (patientData.allergies) { allergies = patientData.allergies.map((allergy) => { return { resourceType: 'AllergyIntolerance', id: allergy.code.toString(), patient: { reference: 'Patient/1' }, code: { coding: [{ system: 'https://platform.claudebernard.fr/fhir/ImplementationGuides/CodeSystem/allergies', code: allergy.code.toString(), display: allergy.label.toString() // TODO : find a way to add the label }] }, clinicalStatus: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/condition-clinical', code: 'active', display: 'Active' }] }, }; }); } bundleEntries.push(...[ { resource: patient }, ...(weightObservation ? [{ resource: weightObservation }] : []), ...(heightObservation ? [{ resource: heightObservation }] : []), ...(pregnancyObservation ? [{ resource: pregnancyObservation }] : []), ...(breastfeedingObservation ? [{ resource: breastfeedingObservation }] : []), ...(creatinineClearanceObservation ? [{ resource: creatinineClearanceObservation }] : []), ...(creatinineMolObservation ? [{ resource: creatinineMolObservation }] : []), ...(creatinineMgObservation ? [{ resource: creatinineMgObservation }] : []), ...conditions.map(condition => ({ resource: condition })), ...allergies.map(allergy => ({ resource: allergy })), ...(hepaticInsufficiencyCondition ? [{ resource: hepaticInsufficiencyCondition }] : []), ]); return { result: bundleEntries, errors: errors }; }; /* ================== FHIR <=> BCB ================== */ function bcbToFhir(bcbPatient) { return patientToFhir(convertPatient(bcbPatient)); } async function fhirToBcb(fhirPatient, allergiesMapper, snomedPathologiesMapper) { if (!fhirPatient || fhirPatient.length === 0) { return { result: undefined, errors: [{ field: 'root', message: 'Invalid Patient array' }] }; } let errors = []; const { patientEntry, weightObservation, heightObservation, pregnancyObservation, breastfeedingObservation, hepaticCondition, lstIdComposantAllergie, lstCim10Pathologies, lstPathologies, clairanceCreatinineObservation, creatininemieMolObservation, creatininemieMgObservation } = await sortEntries('bcb', fhirPatient, wrapMaybeAsync(allergiesMapper), wrapMaybeAsync(snomedPathologiesMapper), errors); const bcbPatient = { lstIdComposantAllergie: lstIdComposantAllergie.map(codification => Number(codification.code)), lstPathologiesCIM10: lstCim10Pathologies.map(codification => codification.code), lstPathologiesAMM: lstPathologies.map(codification => codification.code), age: patientEntry && patientEntry.birthDate ? calculateAgeInMonths(patientEntry.birthDate) : 0, poids: weightObservation && weightObservation?.valueQuantity?.value ? weightObservation?.valueQuantity?.value : 0, taille: heightObservation && heightObservation?.valueQuantity?.value ? heightObservation?.valueQuantity?.value : 0, grossesse: pregnancyObservation ? 1 : 0, allaitement: breastfeedingObservation ? 1 : 0, sexe: patientEntry?.gender ? genderMap[patientEntry.gender] || '' : '', clairanceCreatinine: clairanceCreatinineObservation && clairanceCreatinineObservation?.valueQuantity?.value ? clairanceCreatinineObservation?.valueQuantity?.value : 0, creatininemieMol: creatininemieMolObservation && creatininemieMolObservation?.valueQuantity?.value ? creatininemieMolObservation?.valueQuantity?.value : 0, creatininemieMg: creatininemieMgObservation && creatininemieMgObservation?.valueQuantity?.value ? creatininemieMgObservation?.valueQuantity?.value : 0, insuffisanceHepatique: hepaticCondition?.code?.coding?.[0]?.code ? hepaticInsufficiencyReverseMap[hepaticCondition.code.coding[0].code] : '', }; return { result: bcbPatient, errors: errors }; } /* ================== FHIR <=> CB ================== */ function cbToFhir(cbPatient) { return patientToFhir(cbPatient); } async function fhirToCb(fhirPatient, allergiesMapper, snomedPathologiesMapper) { if (!fhirPatient || fhirPatient.length === 0) { return { result: undefined, errors: [{ field: 'root', message: 'Invalid Patient array' }] }; } let errors = []; const { patientEntry, weightObservation, heightObservation, pregnancyObservation, breastfeedingObservation, hepaticCondition, lstIdComposantAllergie, lstCim10Pathologies, lstPathologies, clairanceCreatinineObservation, creatininemieMolObservation, creatininemieMgObservation } = await sortEntries('cb', fhirPatient, wrapMaybeAsync(allergiesMapper), wrapMaybeAsync(snomedPathologiesMapper), errors); const pathologies = [ ...lstPathologies.map(codification => ({ type: 'AMM', code: codification.code, label: codification.label })), ...lstCim10Pathologies.map(codification => ({ type: 'CIM10', code: codification.code, label: codification.label })) ]; return { result: { firstName: '', lastName: '', age: patientEntry && patientEntry.birthDate ? calculateAgeInMonths(patientEntry.birthDate) : 0, gender: patientEntry?.gender ? genderMap[patientEntry.gender] || '' : '', weight: weightObservation && weightObservation?.valueQuantity?.value ? weightObservation?.valueQuantity?.value : 0, pregnancy: pregnancyObservation ? true : false, breastfeeding: breastfeedingObservation ? true : false, ammPathologies: pathologies, allergies: lstIdComposantAllergie.map(codification => ({ code: Number(codification.code), label: codification.label })), hepaticStage: hepaticCondition?.code?.coding?.[0]?.code || '', height: heightObservation && heightObservation?.valueQuantity?.value ? heightObservation?.valueQuantity?.value : 0, weeksOfPregnancy: pregnancyObservation && pregnancyObservation?.valueQuantity?.value ? pregnancyObservation?.valueQuantity?.value : 0, creatinineClearance: clairanceCreatinineObservation && clairanceCreatinineObservation?.valueQuantity?.value ? clairanceCreatinineObservation?.valueQuantity?.value : 0, molCreatinine: creatininemieMolObservation && creatininemieMolObservation?.valueQuantity?.value ? creatininemieMolObservation?.valueQuantity?.value : 0, mglCreatinine: creatininemieMgObservation && creatininemieMgObservation?.valueQuantity?.value ? creatininemieMgObservation?.valueQuantity?.value : 0, gfr: 0, medicalTeam: { firstNameDoctor: "", lastNameDoctor: "", firstNameSpecialist: "", lastNameSpecialist: "", firstNamePharmacist: "", lastNamePharmacist: "", firstNameNurse: "", lastNameNurse: "" } }, errors: errors }; } // Utility to wrap a possibly sync or async function so it always returns a Promise function wrapMaybeAsync(fn) { if (!fn) return undefined; return ((...args) => Promise.resolve(fn(...args))); } var patientMapper = /*#__PURE__*/Object.freeze({ __proto__: null, bcbToFhir: bcbToFhir, cbToFhir: cbToFhir, fhirToBcb: fhirToBcb, fhirToCb: fhirToCb }); export { dosageMapper, patientMapper }; //# sourceMappingURL=index.js.map