fume-fhir-converter
Version:
FHIR-Utilized Mapping Engine - Community
127 lines (113 loc) • 3.71 kB
text/typescript
/**
* © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
* Project name: FUME-COMMUNITY
*/
import _ from 'lodash';
const filterAddedFields = (obj) => {
return _.pickBy(obj, (_value, key) => !key.includes('__path_'));
};
/**
* This function creates a new object without keys with empty values, recursively.
* An empty value is an empty string, empty object, empty array or null.
* The only exception is that it won't remove empty values from an array,
* if key starts with _ or there's a corresponding _key
* so it will keep the original index, but will replace those with nulls.
* @param {*} obj the object to cleanse
* @returns a new object without the removed keys
*/
const cleanse = (obj: any | any[]) => {
return _cleanse(obj, false);
};
const _cleanse = (obj: any | any[], keepNulls: boolean) => {
if (obj === '' || obj === undefined || obj === null) {
return null;
}
if (Array.isArray(obj)) {
return _cleanseArray(obj, keepNulls);
}
if (typeof obj === 'object') {
return _cleanseObject(obj);
}
return obj;
};
const _cleanseArray = (array: any[], keepNulls: boolean) => {
const newArray: any[] = [];
let hasActualValue = false;
for (const value of array) {
const newValue = _cleanse(value, false);
if (newValue || keepNulls) {
newArray.push(newValue);
}
if (newValue) {
hasActualValue = true;
}
}
return hasActualValue ? newArray : null;
};
const _cleanseObject = (obj: any) => {
const newObject = {};
obj = filterAddedFields(obj);
for (const key of Object.keys(obj)) {
const keepNulls = _isKeyPair(obj, key);
const value = _cleanse(obj[key], keepNulls);
if (!_.isNil(value)) {
newObject[key] = value;
}
}
return Object.keys(newObject).length === 0 ? null : newObject;
};
const _isKeyPair = (obj: any, key: string) => {
if (key.startsWith('_')) {
const baseKey = key.slice(1);
return Object.prototype.hasOwnProperty.call(obj, baseKey);
}
const pairKey = `_${key}`;
return Object.prototype.hasOwnProperty.call(obj, pairKey);
};
const appendSlices = (obj: any | any[]): any => {
if (Array.isArray(obj)) { // array
const newArray: any[] = [];
for (const fhirifiedChild of obj) {
newArray.push(appendSlices(fhirifiedChild));
}
return newArray;
} else if (typeof obj === 'object' && obj !== null) { // object
const newObject = {};
for (const key of Object.keys(obj)) {
const value = appendSlices(obj[key]);
const isValueAnArray = Array.isArray(value);
const baseKey = key.endsWith(']') ? key.split('[')[0] : key;
const isKeyBaseKey = key === baseKey;
if (baseKey in newObject) { // allready exists
let mergedValue = newObject[baseKey];
// convert merged value to array if needed
if (!Array.isArray(mergedValue)) {
mergedValue = [mergedValue];
}
// add the new elements to the merged array
if (isKeyBaseKey && isValueAnArray) {
mergedValue = value.concat(mergedValue);
} else if (isKeyBaseKey) {
mergedValue.unshift(value);
} else {
mergedValue = mergedValue.concat(value);
}
newObject[baseKey] = mergedValue;
} else if (!isKeyBaseKey && !isValueAnArray) { // make sure merged with 1 element is always an array
newObject[baseKey] = [value];
} else {
newObject[baseKey] = value;
}
}
return newObject;
}
return obj;
};
export const finalize = (obj: any) => {
if (!_.get(obj, 'resourceType')) {
return filterAddedFields(obj);
};
const res = cleanse(appendSlices(obj));
if (res === null) return undefined;
return res;
};