From b82a7d359dcc69fa593661f5f38275ce7fbd13d8 Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Sun, 28 Jun 2020 21:16:03 +0200 Subject: [PATCH] Support object syntax for validateArguments as well --- src/api/validate-arguments.js | 79 +++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/src/api/validate-arguments.js b/src/api/validate-arguments.js index c3fe513..bc13036 100644 --- a/src/api/validate-arguments.js +++ b/src/api/validate-arguments.js @@ -2,6 +2,7 @@ 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"); @@ -17,42 +18,68 @@ module.exports = createValidationMethod((args, argumentDefinitions) => { 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 if (args.length > argumentDefinitions.length) { - return { - errors: [ new ValidationError(`Got ${args.length} arguments, but only expected ${argumentDefinitions.length}`) ], - // 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 results = argumentDefinitions.map((definition, i) => { - let argument = args[i]; - let [ argumentName, ...argumentRules ] = definition; + let usesArrayAPI = (Array.isArray(argumentDefinitions)); - if (typeof argumentName !== "string") { - throw new Error("First item in the argument rules list must be the argument name"); - } else { - let validatorResult = applyValidators(argument, argumentRules); + 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: [ argumentName ], + 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 - }; + }); + + 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 + }; + } } });