2017-05-03 15:35:00 +02:00
'use strict' ;
module . exports = function generate _validate ( it , $keyword ) {
var out = '' ;
var $async = it . schema . $async === true ;
if ( it . isTop ) {
var $top = it . isTop ,
$lvl = it . level = 0 ,
$dataLvl = it . dataLevel = 0 ,
$data = 'data' ;
it . rootId = it . resolve . fullPath ( it . root . schema . id ) ;
it . baseId = it . baseId || it . rootId ;
if ( $async ) {
it . async = true ;
var $es7 = it . opts . async == 'es7' ;
it . yieldAwait = $es7 ? 'await' : 'yield' ;
}
delete it . isTop ;
it . dataPathArr = [ undefined ] ;
out += ' var validate = ' ;
if ( $async ) {
if ( $es7 ) {
out += ' (async function ' ;
} else {
if ( it . opts . async == 'co*' ) {
out += 'co.wrap' ;
}
out += '(function* ' ;
}
} else {
out += ' (function ' ;
}
out += ' (data, dataPath, parentData, parentDataProperty, rootData) { \'use strict\'; var vErrors = null; ' ;
out += ' var errors = 0; ' ;
out += ' if (rootData === undefined) rootData = data;' ;
} else {
var $lvl = it . level ,
$dataLvl = it . dataLevel ,
$data = 'data' + ( $dataLvl || '' ) ;
if ( it . schema . id ) it . baseId = it . resolve . url ( it . baseId , it . schema . id ) ;
if ( $async && ! it . async ) throw new Error ( 'async schema in sync schema' ) ;
out += ' var errs_' + ( $lvl ) + ' = errors;' ;
}
var $valid = 'valid' + $lvl ,
$breakOnError = ! it . opts . allErrors ,
$closingBraces1 = '' ,
$closingBraces2 = '' ;
var $typeSchema = it . schema . type ,
$typeIsArray = Array . isArray ( $typeSchema ) ;
if ( $typeSchema && it . opts . coerceTypes ) {
var $coerceToTypes = it . util . coerceToTypes ( it . opts . coerceTypes , $typeSchema ) ;
if ( $coerceToTypes ) {
var $schemaPath = it . schemaPath + '.type' ,
$errSchemaPath = it . errSchemaPath + '/type' ,
$method = $typeIsArray ? 'checkDataTypes' : 'checkDataType' ;
out += ' if (' + ( it . util [ $method ] ( $typeSchema , $data , true ) ) + ') { ' ;
var $dataType = 'dataType' + $lvl ,
$coerced = 'coerced' + $lvl ;
out += ' var ' + ( $dataType ) + ' = typeof ' + ( $data ) + '; ' ;
if ( it . opts . coerceTypes == 'array' ) {
out += ' if (' + ( $dataType ) + ' == \'object\' && Array.isArray(' + ( $data ) + ')) ' + ( $dataType ) + ' = \'array\'; ' ;
}
out += ' var ' + ( $coerced ) + ' = undefined; ' ;
var $bracesCoercion = '' ;
var arr1 = $coerceToTypes ;
if ( arr1 ) {
var $type , $i = - 1 ,
l1 = arr1 . length - 1 ;
while ( $i < l1 ) {
$type = arr1 [ $i += 1 ] ;
if ( $i ) {
out += ' if (' + ( $coerced ) + ' === undefined) { ' ;
$bracesCoercion += '}' ;
}
if ( it . opts . coerceTypes == 'array' && $type != 'array' ) {
out += ' if (' + ( $dataType ) + ' == \'array\' && ' + ( $data ) + '.length == 1) { ' + ( $coerced ) + ' = ' + ( $data ) + ' = ' + ( $data ) + '[0]; ' + ( $dataType ) + ' = typeof ' + ( $data ) + '; } ' ;
}
if ( $type == 'string' ) {
out += ' if (' + ( $dataType ) + ' == \'number\' || ' + ( $dataType ) + ' == \'boolean\') ' + ( $coerced ) + ' = \'\' + ' + ( $data ) + '; else if (' + ( $data ) + ' === null) ' + ( $coerced ) + ' = \'\'; ' ;
} else if ( $type == 'number' || $type == 'integer' ) {
out += ' if (' + ( $dataType ) + ' == \'boolean\' || ' + ( $data ) + ' === null || (' + ( $dataType ) + ' == \'string\' && ' + ( $data ) + ' && ' + ( $data ) + ' == +' + ( $data ) + ' ' ;
if ( $type == 'integer' ) {
out += ' && !(' + ( $data ) + ' % 1)' ;
}
out += ')) ' + ( $coerced ) + ' = +' + ( $data ) + '; ' ;
} else if ( $type == 'boolean' ) {
out += ' if (' + ( $data ) + ' === \'false\' || ' + ( $data ) + ' === 0 || ' + ( $data ) + ' === null) ' + ( $coerced ) + ' = false; else if (' + ( $data ) + ' === \'true\' || ' + ( $data ) + ' === 1) ' + ( $coerced ) + ' = true; ' ;
} else if ( $type == 'null' ) {
out += ' if (' + ( $data ) + ' === \'\' || ' + ( $data ) + ' === 0 || ' + ( $data ) + ' === false) ' + ( $coerced ) + ' = null; ' ;
} else if ( it . opts . coerceTypes == 'array' && $type == 'array' ) {
out += ' if (' + ( $dataType ) + ' == \'string\' || ' + ( $dataType ) + ' == \'number\' || ' + ( $dataType ) + ' == \'boolean\' || ' + ( $data ) + ' == null) ' + ( $coerced ) + ' = [' + ( $data ) + ']; ' ;
}
}
}
out += ' ' + ( $bracesCoercion ) + ' if (' + ( $coerced ) + ' === undefined) { ' ;
var $$outStack = $$outStack || [ ] ;
$$outStack . push ( out ) ;
out = '' ; /* istanbul ignore else */
if ( it . createErrors !== false ) {
out += ' { keyword: \'' + ( 'type' ) + '\' , dataPath: (dataPath || \'\') + ' + ( it . errorPath ) + ' , schemaPath: ' + ( it . util . toQuotedString ( $errSchemaPath ) ) + ' , params: { type: \'' ;
if ( $typeIsArray ) {
out += '' + ( $typeSchema . join ( "," ) ) ;
} else {
out += '' + ( $typeSchema ) ;
}
out += '\' } ' ;
if ( it . opts . messages !== false ) {
out += ' , message: \'should be ' ;
if ( $typeIsArray ) {
out += '' + ( $typeSchema . join ( "," ) ) ;
} else {
out += '' + ( $typeSchema ) ;
}
out += '\' ' ;
}
if ( it . opts . verbose ) {
out += ' , schema: validate.schema' + ( $schemaPath ) + ' , parentSchema: validate.schema' + ( it . schemaPath ) + ' , data: ' + ( $data ) + ' ' ;
}
out += ' } ' ;
} else {
out += ' {} ' ;
}
var _ _err = out ;
out = $$outStack . pop ( ) ;
if ( ! it . compositeRule && $breakOnError ) { /* istanbul ignore if */
if ( it . async ) {
out += ' throw new ValidationError([' + ( _ _err ) + ']); ' ;
} else {
out += ' validate.errors = [' + ( _ _err ) + ']; return false; ' ;
}
} else {
out += ' var err = ' + ( _ _err ) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ' ;
}
out += ' } else { ' ;
var $parentData = $dataLvl ? 'data' + ( ( $dataLvl - 1 ) || '' ) : 'parentData' ,
$parentDataProperty = $dataLvl ? it . dataPathArr [ $dataLvl ] : 'parentDataProperty' ;
out += ' ' + ( $data ) + ' = ' + ( $coerced ) + '; ' ;
if ( ! $dataLvl ) {
out += 'if (' + ( $parentData ) + ' !== undefined)' ;
}
out += ' ' + ( $parentData ) + '[' + ( $parentDataProperty ) + '] = ' + ( $coerced ) + '; } } ' ;
}
}
var $refKeywords ;
if ( it . schema . $ref && ( $refKeywords = it . util . schemaHasRulesExcept ( it . schema , it . RULES . all , '$ref' ) ) ) {
if ( it . opts . extendRefs == 'fail' ) {
throw new Error ( '$ref: validation keywords used in schema at path "' + it . errSchemaPath + '"' ) ;
} else if ( it . opts . extendRefs == 'ignore' ) {
$refKeywords = false ;
console . log ( '$ref: keywords ignored in schema at path "' + it . errSchemaPath + '"' ) ;
} else if ( it . opts . extendRefs !== true ) {
console . log ( '$ref: all keywords used in schema at path "' + it . errSchemaPath + '". It will change in the next major version, see issue #260. Use option { extendRefs: true } to keep current behaviour' ) ;
}
}
if ( it . schema . $ref && ! $refKeywords ) {
out += ' ' + ( it . RULES . all . $ref . code ( it , '$ref' ) ) + ' ' ;
if ( $breakOnError ) {
out += ' } if (errors === ' ;
if ( $top ) {
out += '0' ;
} else {
out += 'errs_' + ( $lvl ) ;
}
out += ') { ' ;
$closingBraces2 += '}' ;
}
} else {
var arr2 = it . RULES ;
if ( arr2 ) {
var $rulesGroup , i2 = - 1 ,
l2 = arr2 . length - 1 ;
while ( i2 < l2 ) {
$rulesGroup = arr2 [ i2 += 1 ] ;
if ( $shouldUseGroup ( $rulesGroup ) ) {
if ( $rulesGroup . type ) {
out += ' if (' + ( it . util . checkDataType ( $rulesGroup . type , $data ) ) + ') { ' ;
}
if ( it . opts . useDefaults && ! it . compositeRule ) {
if ( $rulesGroup . type == 'object' && it . schema . properties ) {
var $schema = it . schema . properties ,
$schemaKeys = Object . keys ( $schema ) ;
var arr3 = $schemaKeys ;
if ( arr3 ) {
var $propertyKey , i3 = - 1 ,
l3 = arr3 . length - 1 ;
while ( i3 < l3 ) {
$propertyKey = arr3 [ i3 += 1 ] ;
var $sch = $schema [ $propertyKey ] ;
if ( $sch . default !== undefined ) {
var $passData = $data + it . util . getProperty ( $propertyKey ) ;
out += ' if (' + ( $passData ) + ' === undefined) ' + ( $passData ) + ' = ' ;
if ( it . opts . useDefaults == 'shared' ) {
out += ' ' + ( it . useDefault ( $sch . default ) ) + ' ' ;
} else {
out += ' ' + ( JSON . stringify ( $sch . default ) ) + ' ' ;
}
out += '; ' ;
}
}
}
} else if ( $rulesGroup . type == 'array' && Array . isArray ( it . schema . items ) ) {
var arr4 = it . schema . items ;
if ( arr4 ) {
var $sch , $i = - 1 ,
l4 = arr4 . length - 1 ;
while ( $i < l4 ) {
$sch = arr4 [ $i += 1 ] ;
if ( $sch . default !== undefined ) {
var $passData = $data + '[' + $i + ']' ;
out += ' if (' + ( $passData ) + ' === undefined) ' + ( $passData ) + ' = ' ;
if ( it . opts . useDefaults == 'shared' ) {
out += ' ' + ( it . useDefault ( $sch . default ) ) + ' ' ;
} else {
out += ' ' + ( JSON . stringify ( $sch . default ) ) + ' ' ;
}
out += '; ' ;
}
}
}
}
}
var arr5 = $rulesGroup . rules ;
if ( arr5 ) {
var $rule , i5 = - 1 ,
l5 = arr5 . length - 1 ;
while ( i5 < l5 ) {
$rule = arr5 [ i5 += 1 ] ;
if ( $shouldUseRule ( $rule ) ) {
out += ' ' + ( $rule . code ( it , $rule . keyword ) ) + ' ' ;
if ( $breakOnError ) {
$closingBraces1 += '}' ;
}
}
}
}
if ( $breakOnError ) {
out += ' ' + ( $closingBraces1 ) + ' ' ;
$closingBraces1 = '' ;
}
if ( $rulesGroup . type ) {
out += ' } ' ;
2017-05-24 15:10:37 +02:00
if ( $typeSchema && $typeSchema === $rulesGroup . type && ! $coerceToTypes ) {
2017-05-03 15:35:00 +02:00
var $typeChecked = true ;
out += ' else { ' ;
var $schemaPath = it . schemaPath + '.type' ,
$errSchemaPath = it . errSchemaPath + '/type' ;
var $$outStack = $$outStack || [ ] ;
$$outStack . push ( out ) ;
out = '' ; /* istanbul ignore else */
if ( it . createErrors !== false ) {
out += ' { keyword: \'' + ( 'type' ) + '\' , dataPath: (dataPath || \'\') + ' + ( it . errorPath ) + ' , schemaPath: ' + ( it . util . toQuotedString ( $errSchemaPath ) ) + ' , params: { type: \'' ;
if ( $typeIsArray ) {
out += '' + ( $typeSchema . join ( "," ) ) ;
} else {
out += '' + ( $typeSchema ) ;
}
out += '\' } ' ;
if ( it . opts . messages !== false ) {
out += ' , message: \'should be ' ;
if ( $typeIsArray ) {
out += '' + ( $typeSchema . join ( "," ) ) ;
} else {
out += '' + ( $typeSchema ) ;
}
out += '\' ' ;
}
if ( it . opts . verbose ) {
out += ' , schema: validate.schema' + ( $schemaPath ) + ' , parentSchema: validate.schema' + ( it . schemaPath ) + ' , data: ' + ( $data ) + ' ' ;
}
out += ' } ' ;
} else {
out += ' {} ' ;
}
var _ _err = out ;
out = $$outStack . pop ( ) ;
if ( ! it . compositeRule && $breakOnError ) { /* istanbul ignore if */
if ( it . async ) {
out += ' throw new ValidationError([' + ( _ _err ) + ']); ' ;
} else {
out += ' validate.errors = [' + ( _ _err ) + ']; return false; ' ;
}
} else {
out += ' var err = ' + ( _ _err ) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ' ;
}
out += ' } ' ;
}
}
if ( $breakOnError ) {
out += ' if (errors === ' ;
if ( $top ) {
out += '0' ;
} else {
out += 'errs_' + ( $lvl ) ;
}
out += ') { ' ;
$closingBraces2 += '}' ;
}
}
}
}
}
2017-05-24 15:10:37 +02:00
if ( $typeSchema && ! $typeChecked && ! $coerceToTypes ) {
2017-05-03 15:35:00 +02:00
var $schemaPath = it . schemaPath + '.type' ,
$errSchemaPath = it . errSchemaPath + '/type' ,
$method = $typeIsArray ? 'checkDataTypes' : 'checkDataType' ;
out += ' if (' + ( it . util [ $method ] ( $typeSchema , $data , true ) ) + ') { ' ;
var $$outStack = $$outStack || [ ] ;
$$outStack . push ( out ) ;
out = '' ; /* istanbul ignore else */
if ( it . createErrors !== false ) {
out += ' { keyword: \'' + ( 'type' ) + '\' , dataPath: (dataPath || \'\') + ' + ( it . errorPath ) + ' , schemaPath: ' + ( it . util . toQuotedString ( $errSchemaPath ) ) + ' , params: { type: \'' ;
if ( $typeIsArray ) {
out += '' + ( $typeSchema . join ( "," ) ) ;
} else {
out += '' + ( $typeSchema ) ;
}
out += '\' } ' ;
if ( it . opts . messages !== false ) {
out += ' , message: \'should be ' ;
if ( $typeIsArray ) {
out += '' + ( $typeSchema . join ( "," ) ) ;
} else {
out += '' + ( $typeSchema ) ;
}
out += '\' ' ;
}
if ( it . opts . verbose ) {
out += ' , schema: validate.schema' + ( $schemaPath ) + ' , parentSchema: validate.schema' + ( it . schemaPath ) + ' , data: ' + ( $data ) + ' ' ;
}
out += ' } ' ;
} else {
out += ' {} ' ;
}
var _ _err = out ;
out = $$outStack . pop ( ) ;
if ( ! it . compositeRule && $breakOnError ) { /* istanbul ignore if */
if ( it . async ) {
out += ' throw new ValidationError([' + ( _ _err ) + ']); ' ;
} else {
out += ' validate.errors = [' + ( _ _err ) + ']; return false; ' ;
}
} else {
out += ' var err = ' + ( _ _err ) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ' ;
}
out += ' }' ;
}
if ( $breakOnError ) {
out += ' ' + ( $closingBraces2 ) + ' ' ;
}
if ( $top ) {
if ( $async ) {
out += ' if (errors === 0) return true; ' ;
out += ' else throw new ValidationError(vErrors); ' ;
} else {
out += ' validate.errors = vErrors; ' ;
out += ' return errors === 0; ' ;
}
out += ' }); return validate;' ;
} else {
out += ' var ' + ( $valid ) + ' = errors === errs_' + ( $lvl ) + ';' ;
}
out = it . util . cleanUpCode ( out ) ;
if ( $top && $breakOnError ) {
out = it . util . cleanUpVarErrors ( out , $async ) ;
}
function $shouldUseGroup ( $rulesGroup ) {
for ( var i = 0 ; i < $rulesGroup . rules . length ; i ++ )
if ( $shouldUseRule ( $rulesGroup . rules [ i ] ) ) return true ;
}
function $shouldUseRule ( $rule ) {
return it . schema [ $rule . keyword ] !== undefined || ( $rule . keyword == 'properties' && ( it . schema . additionalProperties === false || typeof it . schema . additionalProperties == 'object' || ( it . schema . patternProperties && Object . keys ( it . schema . patternProperties ) . length ) || ( it . opts . v5 && it . schema . patternGroups && Object . keys ( it . schema . patternGroups ) . length ) ) ) ;
}
return out ;
}