"use strict"; const defaultValue = require("default-value"); const ValidationError = require("@validatem/error"); const combinator = require("@validatem/combinator"); const annotateErrors = require("@validatem/annotate-errors"); const virtualProperty = require("@validatem/virtual-property"); const validationResult = require("@validatem/validation-result"); module.exports = function (rules) { if (rules.key == null && rules.value == null) { throw new Error(`Must specify either a 'key' or 'value' property in the ruleset`); } else { let keyRules = defaultValue(rules.key, []); let valueRules = defaultValue(rules.value, []); let validator = combinator((object, applyValidators) => { let newObject = {}; let allErrors = []; if (typeof object !== "object" || Array.isArray(object)) { throw new ValidationError("Must be an object"); } else { // NOTE: Reflect.ownEntries is used here to ensure we capture the Symbol-typed keys as well for (let key of Reflect.ownKeys(object)) { let value = object[key]; let keyAsString = key.toString(); // Again, to deal with Symbol-typed keys. let { errors: keyErrors, newValue: newKey } = applyValidators(key, keyRules); let { errors: valueErrors, newValue } = applyValidators(value, valueRules); let annotatedKeyErrors = annotateErrors({ pathSegments: [ keyAsString, virtualProperty("key") ], errors: keyErrors }); let annotatedValueErrors = annotateErrors({ pathSegments: [ keyAsString, virtualProperty("value") ], errors: valueErrors }); newObject[newKey] = newValue; allErrors.push(...annotatedKeyErrors, ...annotatedValueErrors); } return validationResult({ errors: allErrors, newValue: newObject }); } }); validator.callIfNull = false; return validator; } };