You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
2.8 KiB
JavaScript

'use strict';
const dotty = require("dotty");
const deepAssign = require("deep-assign");
module.exports = function createPropertyMapper(propertyMap) {
let mappings = Object.keys(propertyMap).map((sourceProperty) => {
let destinationPath = propertyMap[sourceProperty];
if (typeof destinationPath === "function") {
return {
sourceProperty: sourceProperty,
transformer: destinationPath
}
} else {
let destinationObject, destinationProperty;
if (destinationPath.includes(".")) {
let destinationPathParts = destinationPath.split(".");
destinationObject = destinationPathParts[0];
destinationProperty = destinationPathParts.slice(1).join(".");
} else {
destinationObject = destinationPath;
destinationProperty = sourceProperty;
}
return {
sourceProperty: sourceProperty,
destinationObject: destinationObject,
destinationProperty: destinationProperty
}
}
}).reduce((mappings, item) => {
mappings[item.sourceProperty] = item;
return mappings;
}, {});
return function mapProperties(properties) {
return Object.keys(properties).map((propertyName) => {
let propertyValue = properties[propertyName];
if (propertyName.includes(".")) {
/* Property names with a dot are attempts to directly access an
* object within a composite object; they need to be handled
* specially since they essentially bypass the mapping step.
* If there is *more* than a single dot, then this is an attempt
* to access a *nested* composite object, and therefore we should
* keep the entire property name after the first dot intact. */
let propertyNameSegments = propertyName.split(".");
let destinationObject = propertyNameSegments[0];
let realPropertyName = propertyNameSegments.slice(1).join(".");
return {
sourceProperty: propertyName,
destinationObject: destinationObject,
destinationProperty: realPropertyName,
value: propertyValue
}
} else if (mappings[propertyName] != null) {
return Object.assign({
value: propertyValue
}, mappings[propertyName]);
} else {
return {
sourceProperty: propertyName,
destinationObject: "_",
destinationProperty: propertyName,
value: propertyValue
}
}
}).filter((item) => {
return (item != null);
}).reduce((objects, item) => {
function ensureObject(object) {
if (objects[object] == null) {
objects[object] = {};
}
}
if (item.destinationProperty != null) {
ensureObject(item.destinationObject);
dotty.put(objects[item.destinationObject], item.destinationProperty, item.value);
} else {
let results = item.transformer(item.value);
Object.keys(results).forEach((object) => {
ensureObject(object);
deepAssign(objects[object], results[object]);
});
}
return objects;
}, {})
}
};