"use strict" ;
const asExpression = require ( "as-expression" ) ;
const defaultValue = require ( "default-value" ) ;
const flatten = require ( "flatten" ) ;
const ValidationError = require ( "@validatem/error" ) ;
const validationResult = require ( "@validatem/validation-result" ) ;
const annotateErrors = require ( "@validatem/annotate-errors" ) ;
const combinator = require ( "@validatem/combinator" ) ;
function containsRules ( rules ) {
// TODO: We cannot use normalize-rules here (for now) since that would create a cyclical dependency; figure out a way to work around this, maybe by removing the hasShape feature in `normalize-rules`, or moving the flattening itself out into a separate `flatten-rules` package?
if ( rules == null ) {
return false ;
} else {
// TODO: Switch to `Array#flat` once Node 10.x goes EOL (April 2021)
let flattenedRules = flatten ( rules ) ;
if ( ! flattenedRules . some ( ( rule ) => rule != null ) ) {
return false ;
} else {
return true ;
}
}
}
module . exports = function hasShape ( rules ) {
return combinator ( ( object , applyValidators , context ) => {
let allowExtraProperties = defaultValue ( context . allowExtraProperties , false ) ;
let unexpectedPropertyErrors = asExpression ( ( ) => {
if ( ! allowExtraProperties ) {
return Object . keys ( object ) . map ( ( propertyName ) => {
if ( ! containsRules ( rules [ propertyName ] ) ) {
return new ValidationError ( ` Encountered an unexpected property ' ${ propertyName } ' ` ) ;
} else {
return null ;
}
} ) . filter ( ( error ) => {
return ( error != null ) ;
} ) ;
} else {
return [ ] ;
}
} ) ;
if ( unexpectedPropertyErrors . length > 0 ) {
return validationResult ( {
errors : unexpectedPropertyErrors ,
newValue : object
} ) ;
} else {
let errors = [ ] ;
let newObject = { } ;
for ( let [ key , rule ] of Object . entries ( rules ) ) {
let value = object [ key ] ;
let { errors : keyErrors , newValue } = applyValidators ( value , rule ) ;
let annotatedErrors = annotateErrors ( {
pathSegments : [ key ] ,
errors : keyErrors
} ) ;
errors . push ( ... annotatedErrors ) ;
newObject [ key ] = newValue ;
}
return validationResult ( {
errors : errors ,
newValue : newObject
} ) ;
}
} ) ;
} ;