"use strict"; const isArguments = require("is-arguments"); const flatten = require("flatten"); const asExpression = require("as-expression"); const ValidationError = require("@validatem/error"); const annotateErrors = require("@validatem/annotate-errors"); const applyValidators = require("../apply-validators"); const createValidationMethod = require("./validation-method"); // TODO: Simplify below by treating it like an array or object? Or would that introduce too much complexity through specialcasing? // TODO: Find a way to produce validatem-style errors for the below invocation errors, without introducing recursion module.exports = createValidationMethod((args, argumentDefinitions) => { if (!isArguments(args)) { throw new Error(`First argument is not an 'arguments' object; maybe you forgot to put it before the validation rules?`); } else if (argumentDefinitions == null) { throw new Error(`Validation rules (second argument) are missing; maybe you forgot to specify them?`); } else { let usesArrayAPI = (Array.isArray(argumentDefinitions)); let definitionCount = (usesArrayAPI) ? argumentDefinitions.length : Object.keys(argumentDefinitions).length; if (args.length > definitionCount) { return { errors: [ new ValidationError(`Got ${args.length} arguments, but only expected ${definitionCount}`) ], // Cast the below to an array, for consistency with *success* output, in case we ever want to expose the new values to the user in an error case too. newValue: Array.from(args) }; } else { let normalizedDefinitions = asExpression(() => { if (usesArrayAPI) { return argumentDefinitions.map((definition) => { let [ name, ...rules ] = definition; if (typeof name !== "string") { throw new Error("First item in the argument rules list must be the argument name"); } else { return { name: name, rules: rules }; } }); } else { return Object.entries(argumentDefinitions).map(([ key, value ]) => { return { name: key, rules: value }; }); } }); let results = normalizedDefinitions.map(({ name, rules }, i) => { let argument = args[i]; let validatorResult = applyValidators(argument, rules); return { errors: annotateErrors({ pathSegments: [ name ], errors: validatorResult.errors }), newValue: (validatorResult.newValue !== undefined) ? validatorResult.newValue : argument }; }); let combinedErrors = results.map((result) => result.errors); let flattenedErrors = flatten(combinedErrors); // TODO: Switch to `Array#flat` once Node 10.x goes EOL (April 2021) let newValues = results.map((result) => result.newValue); return { errors: flattenedErrors, newValue: newValues }; } } });