diff --git a/index.js b/index.js index 3e066bc..50562c6 100644 --- a/index.js +++ b/index.js @@ -22,6 +22,7 @@ const wrapPath = require("@validatem/wrap-path"); // FIXME: Make sure to explain the purpose of this in the documentation (multi-step merging, like in zapdb) let DeleteValue = Symbol("DeleteValue"); +let Template = Symbol("Template"); function wrapValidationPath(basePathSegments, lastProperty, rules) { let combinedPath = basePathSegments.concat(virtualProperty(lastProperty)); @@ -102,12 +103,17 @@ function mergeValue(rule, a, b, path, options) { return a; } } else if (typeof rule === "function") { - if (effectiveA === undefined) { - return b; - } else if (b === undefined) { - return a; + if (Template in rule) { + // This is another merge-by-template merger, the user is attempting to compose them together, so we will just apply the template directly + return mergeValue(rule[Template], a, b, path, options); } else { - return rule(effectiveA, b, path, options); // FIXME: Do we want to pass the original A to the function instead? + if (effectiveA === undefined) { + return b; + } else if (b === undefined) { + return a; + } else { + return rule(effectiveA, b, path, options); // FIXME: Do we want to pass the original A to the function instead? + } } } else if (typeof rule === "object") { if (Array.isArray(rule)) { @@ -130,7 +136,7 @@ module.exports = { }] }); - return function merge(_items, _options) { + let merger = function merge(_items, _options) { let [ items, mergeOptions ] = validateArguments(arguments, { items: [ isArray, removeNullishItems ], options: { @@ -145,6 +151,10 @@ module.exports = { return mergeValue(template, merged, item, [], effectiveOptions); }, items[0]); }; + + merger[Template] = template; + + return merger; }, anyProperty: function (template) { /* Used for cases where an object is used like a key->value map */