validate.js (20297B)
1 'use strict'; 2 module.exports = function generate_validate(it, $keyword, $ruleType) { 3 var out = ''; 4 var $async = it.schema.$async === true, 5 $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref'), 6 $id = it.self._getId(it.schema); 7 if (it.opts.strictKeywords) { 8 var $unknownKwd = it.util.schemaUnknownRules(it.schema, it.RULES.keywords); 9 if ($unknownKwd) { 10 var $keywordsMsg = 'unknown keyword: ' + $unknownKwd; 11 if (it.opts.strictKeywords === 'log') it.logger.warn($keywordsMsg); 12 else throw new Error($keywordsMsg); 13 } 14 } 15 if (it.isTop) { 16 out += ' var validate = '; 17 if ($async) { 18 it.async = true; 19 out += 'async '; 20 } 21 out += 'function(data, dataPath, parentData, parentDataProperty, rootData) { \'use strict\'; '; 22 if ($id && (it.opts.sourceCode || it.opts.processCode)) { 23 out += ' ' + ('/\*# sourceURL=' + $id + ' */') + ' '; 24 } 25 } 26 if (typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref)) { 27 var $keyword = 'false schema'; 28 var $lvl = it.level; 29 var $dataLvl = it.dataLevel; 30 var $schema = it.schema[$keyword]; 31 var $schemaPath = it.schemaPath + it.util.getProperty($keyword); 32 var $errSchemaPath = it.errSchemaPath + '/' + $keyword; 33 var $breakOnError = !it.opts.allErrors; 34 var $errorKeyword; 35 var $data = 'data' + ($dataLvl || ''); 36 var $valid = 'valid' + $lvl; 37 if (it.schema === false) { 38 if (it.isTop) { 39 $breakOnError = true; 40 } else { 41 out += ' var ' + ($valid) + ' = false; '; 42 } 43 var $$outStack = $$outStack || []; 44 $$outStack.push(out); 45 out = ''; /* istanbul ignore else */ 46 if (it.createErrors !== false) { 47 out += ' { keyword: \'' + ($errorKeyword || 'false schema') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} '; 48 if (it.opts.messages !== false) { 49 out += ' , message: \'boolean schema is false\' '; 50 } 51 if (it.opts.verbose) { 52 out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; 53 } 54 out += ' } '; 55 } else { 56 out += ' {} '; 57 } 58 var __err = out; 59 out = $$outStack.pop(); 60 if (!it.compositeRule && $breakOnError) { 61 /* istanbul ignore if */ 62 if (it.async) { 63 out += ' throw new ValidationError([' + (__err) + ']); '; 64 } else { 65 out += ' validate.errors = [' + (__err) + ']; return false; '; 66 } 67 } else { 68 out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; 69 } 70 } else { 71 if (it.isTop) { 72 if ($async) { 73 out += ' return data; '; 74 } else { 75 out += ' validate.errors = null; return true; '; 76 } 77 } else { 78 out += ' var ' + ($valid) + ' = true; '; 79 } 80 } 81 if (it.isTop) { 82 out += ' }; return validate; '; 83 } 84 return out; 85 } 86 if (it.isTop) { 87 var $top = it.isTop, 88 $lvl = it.level = 0, 89 $dataLvl = it.dataLevel = 0, 90 $data = 'data'; 91 it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema)); 92 it.baseId = it.baseId || it.rootId; 93 delete it.isTop; 94 it.dataPathArr = [undefined]; 95 if (it.schema.default !== undefined && it.opts.useDefaults && it.opts.strictDefaults) { 96 var $defaultMsg = 'default is ignored in the schema root'; 97 if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); 98 else throw new Error($defaultMsg); 99 } 100 out += ' var vErrors = null; '; 101 out += ' var errors = 0; '; 102 out += ' if (rootData === undefined) rootData = data; '; 103 } else { 104 var $lvl = it.level, 105 $dataLvl = it.dataLevel, 106 $data = 'data' + ($dataLvl || ''); 107 if ($id) it.baseId = it.resolve.url(it.baseId, $id); 108 if ($async && !it.async) throw new Error('async schema in sync schema'); 109 out += ' var errs_' + ($lvl) + ' = errors;'; 110 } 111 var $valid = 'valid' + $lvl, 112 $breakOnError = !it.opts.allErrors, 113 $closingBraces1 = '', 114 $closingBraces2 = ''; 115 var $errorKeyword; 116 var $typeSchema = it.schema.type, 117 $typeIsArray = Array.isArray($typeSchema); 118 if ($typeSchema && it.opts.nullable && it.schema.nullable === true) { 119 if ($typeIsArray) { 120 if ($typeSchema.indexOf('null') == -1) $typeSchema = $typeSchema.concat('null'); 121 } else if ($typeSchema != 'null') { 122 $typeSchema = [$typeSchema, 'null']; 123 $typeIsArray = true; 124 } 125 } 126 if ($typeIsArray && $typeSchema.length == 1) { 127 $typeSchema = $typeSchema[0]; 128 $typeIsArray = false; 129 } 130 if (it.schema.$ref && $refKeywords) { 131 if (it.opts.extendRefs == 'fail') { 132 throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); 133 } else if (it.opts.extendRefs !== true) { 134 $refKeywords = false; 135 it.logger.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"'); 136 } 137 } 138 if (it.schema.$comment && it.opts.$comment) { 139 out += ' ' + (it.RULES.all.$comment.code(it, '$comment')); 140 } 141 if ($typeSchema) { 142 if (it.opts.coerceTypes) { 143 var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); 144 } 145 var $rulesGroup = it.RULES.types[$typeSchema]; 146 if ($coerceToTypes || $typeIsArray || $rulesGroup === true || ($rulesGroup && !$shouldUseGroup($rulesGroup))) { 147 var $schemaPath = it.schemaPath + '.type', 148 $errSchemaPath = it.errSchemaPath + '/type'; 149 var $schemaPath = it.schemaPath + '.type', 150 $errSchemaPath = it.errSchemaPath + '/type', 151 $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType'; 152 out += ' if (' + (it.util[$method]($typeSchema, $data, true)) + ') { '; 153 if ($coerceToTypes) { 154 var $dataType = 'dataType' + $lvl, 155 $coerced = 'coerced' + $lvl; 156 out += ' var ' + ($dataType) + ' = typeof ' + ($data) + '; '; 157 if (it.opts.coerceTypes == 'array') { 158 out += ' if (' + ($dataType) + ' == \'object\' && Array.isArray(' + ($data) + ')) ' + ($dataType) + ' = \'array\'; '; 159 } 160 out += ' var ' + ($coerced) + ' = undefined; '; 161 var $bracesCoercion = ''; 162 var arr1 = $coerceToTypes; 163 if (arr1) { 164 var $type, $i = -1, 165 l1 = arr1.length - 1; 166 while ($i < l1) { 167 $type = arr1[$i += 1]; 168 if ($i) { 169 out += ' if (' + ($coerced) + ' === undefined) { '; 170 $bracesCoercion += '}'; 171 } 172 if (it.opts.coerceTypes == 'array' && $type != 'array') { 173 out += ' if (' + ($dataType) + ' == \'array\' && ' + ($data) + '.length == 1) { ' + ($coerced) + ' = ' + ($data) + ' = ' + ($data) + '[0]; ' + ($dataType) + ' = typeof ' + ($data) + '; } '; 174 } 175 if ($type == 'string') { 176 out += ' if (' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\') ' + ($coerced) + ' = \'\' + ' + ($data) + '; else if (' + ($data) + ' === null) ' + ($coerced) + ' = \'\'; '; 177 } else if ($type == 'number' || $type == 'integer') { 178 out += ' if (' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' === null || (' + ($dataType) + ' == \'string\' && ' + ($data) + ' && ' + ($data) + ' == +' + ($data) + ' '; 179 if ($type == 'integer') { 180 out += ' && !(' + ($data) + ' % 1)'; 181 } 182 out += ')) ' + ($coerced) + ' = +' + ($data) + '; '; 183 } else if ($type == 'boolean') { 184 out += ' if (' + ($data) + ' === \'false\' || ' + ($data) + ' === 0 || ' + ($data) + ' === null) ' + ($coerced) + ' = false; else if (' + ($data) + ' === \'true\' || ' + ($data) + ' === 1) ' + ($coerced) + ' = true; '; 185 } else if ($type == 'null') { 186 out += ' if (' + ($data) + ' === \'\' || ' + ($data) + ' === 0 || ' + ($data) + ' === false) ' + ($coerced) + ' = null; '; 187 } else if (it.opts.coerceTypes == 'array' && $type == 'array') { 188 out += ' if (' + ($dataType) + ' == \'string\' || ' + ($dataType) + ' == \'number\' || ' + ($dataType) + ' == \'boolean\' || ' + ($data) + ' == null) ' + ($coerced) + ' = [' + ($data) + ']; '; 189 } 190 } 191 } 192 out += ' ' + ($bracesCoercion) + ' if (' + ($coerced) + ' === undefined) { '; 193 var $$outStack = $$outStack || []; 194 $$outStack.push(out); 195 out = ''; /* istanbul ignore else */ 196 if (it.createErrors !== false) { 197 out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; 198 if ($typeIsArray) { 199 out += '' + ($typeSchema.join(",")); 200 } else { 201 out += '' + ($typeSchema); 202 } 203 out += '\' } '; 204 if (it.opts.messages !== false) { 205 out += ' , message: \'should be '; 206 if ($typeIsArray) { 207 out += '' + ($typeSchema.join(",")); 208 } else { 209 out += '' + ($typeSchema); 210 } 211 out += '\' '; 212 } 213 if (it.opts.verbose) { 214 out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; 215 } 216 out += ' } '; 217 } else { 218 out += ' {} '; 219 } 220 var __err = out; 221 out = $$outStack.pop(); 222 if (!it.compositeRule && $breakOnError) { 223 /* istanbul ignore if */ 224 if (it.async) { 225 out += ' throw new ValidationError([' + (__err) + ']); '; 226 } else { 227 out += ' validate.errors = [' + (__err) + ']; return false; '; 228 } 229 } else { 230 out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; 231 } 232 out += ' } else { '; 233 var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData', 234 $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty'; 235 out += ' ' + ($data) + ' = ' + ($coerced) + '; '; 236 if (!$dataLvl) { 237 out += 'if (' + ($parentData) + ' !== undefined)'; 238 } 239 out += ' ' + ($parentData) + '[' + ($parentDataProperty) + '] = ' + ($coerced) + '; } '; 240 } else { 241 var $$outStack = $$outStack || []; 242 $$outStack.push(out); 243 out = ''; /* istanbul ignore else */ 244 if (it.createErrors !== false) { 245 out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; 246 if ($typeIsArray) { 247 out += '' + ($typeSchema.join(",")); 248 } else { 249 out += '' + ($typeSchema); 250 } 251 out += '\' } '; 252 if (it.opts.messages !== false) { 253 out += ' , message: \'should be '; 254 if ($typeIsArray) { 255 out += '' + ($typeSchema.join(",")); 256 } else { 257 out += '' + ($typeSchema); 258 } 259 out += '\' '; 260 } 261 if (it.opts.verbose) { 262 out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; 263 } 264 out += ' } '; 265 } else { 266 out += ' {} '; 267 } 268 var __err = out; 269 out = $$outStack.pop(); 270 if (!it.compositeRule && $breakOnError) { 271 /* istanbul ignore if */ 272 if (it.async) { 273 out += ' throw new ValidationError([' + (__err) + ']); '; 274 } else { 275 out += ' validate.errors = [' + (__err) + ']; return false; '; 276 } 277 } else { 278 out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; 279 } 280 } 281 out += ' } '; 282 } 283 } 284 if (it.schema.$ref && !$refKeywords) { 285 out += ' ' + (it.RULES.all.$ref.code(it, '$ref')) + ' '; 286 if ($breakOnError) { 287 out += ' } if (errors === '; 288 if ($top) { 289 out += '0'; 290 } else { 291 out += 'errs_' + ($lvl); 292 } 293 out += ') { '; 294 $closingBraces2 += '}'; 295 } 296 } else { 297 var arr2 = it.RULES; 298 if (arr2) { 299 var $rulesGroup, i2 = -1, 300 l2 = arr2.length - 1; 301 while (i2 < l2) { 302 $rulesGroup = arr2[i2 += 1]; 303 if ($shouldUseGroup($rulesGroup)) { 304 if ($rulesGroup.type) { 305 out += ' if (' + (it.util.checkDataType($rulesGroup.type, $data)) + ') { '; 306 } 307 if (it.opts.useDefaults) { 308 if ($rulesGroup.type == 'object' && it.schema.properties) { 309 var $schema = it.schema.properties, 310 $schemaKeys = Object.keys($schema); 311 var arr3 = $schemaKeys; 312 if (arr3) { 313 var $propertyKey, i3 = -1, 314 l3 = arr3.length - 1; 315 while (i3 < l3) { 316 $propertyKey = arr3[i3 += 1]; 317 var $sch = $schema[$propertyKey]; 318 if ($sch.default !== undefined) { 319 var $passData = $data + it.util.getProperty($propertyKey); 320 if (it.compositeRule) { 321 if (it.opts.strictDefaults) { 322 var $defaultMsg = 'default is ignored for: ' + $passData; 323 if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); 324 else throw new Error($defaultMsg); 325 } 326 } else { 327 out += ' if (' + ($passData) + ' === undefined '; 328 if (it.opts.useDefaults == 'empty') { 329 out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' '; 330 } 331 out += ' ) ' + ($passData) + ' = '; 332 if (it.opts.useDefaults == 'shared') { 333 out += ' ' + (it.useDefault($sch.default)) + ' '; 334 } else { 335 out += ' ' + (JSON.stringify($sch.default)) + ' '; 336 } 337 out += '; '; 338 } 339 } 340 } 341 } 342 } else if ($rulesGroup.type == 'array' && Array.isArray(it.schema.items)) { 343 var arr4 = it.schema.items; 344 if (arr4) { 345 var $sch, $i = -1, 346 l4 = arr4.length - 1; 347 while ($i < l4) { 348 $sch = arr4[$i += 1]; 349 if ($sch.default !== undefined) { 350 var $passData = $data + '[' + $i + ']'; 351 if (it.compositeRule) { 352 if (it.opts.strictDefaults) { 353 var $defaultMsg = 'default is ignored for: ' + $passData; 354 if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg); 355 else throw new Error($defaultMsg); 356 } 357 } else { 358 out += ' if (' + ($passData) + ' === undefined '; 359 if (it.opts.useDefaults == 'empty') { 360 out += ' || ' + ($passData) + ' === null || ' + ($passData) + ' === \'\' '; 361 } 362 out += ' ) ' + ($passData) + ' = '; 363 if (it.opts.useDefaults == 'shared') { 364 out += ' ' + (it.useDefault($sch.default)) + ' '; 365 } else { 366 out += ' ' + (JSON.stringify($sch.default)) + ' '; 367 } 368 out += '; '; 369 } 370 } 371 } 372 } 373 } 374 } 375 var arr5 = $rulesGroup.rules; 376 if (arr5) { 377 var $rule, i5 = -1, 378 l5 = arr5.length - 1; 379 while (i5 < l5) { 380 $rule = arr5[i5 += 1]; 381 if ($shouldUseRule($rule)) { 382 var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); 383 if ($code) { 384 out += ' ' + ($code) + ' '; 385 if ($breakOnError) { 386 $closingBraces1 += '}'; 387 } 388 } 389 } 390 } 391 } 392 if ($breakOnError) { 393 out += ' ' + ($closingBraces1) + ' '; 394 $closingBraces1 = ''; 395 } 396 if ($rulesGroup.type) { 397 out += ' } '; 398 if ($typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes) { 399 out += ' else { '; 400 var $schemaPath = it.schemaPath + '.type', 401 $errSchemaPath = it.errSchemaPath + '/type'; 402 var $$outStack = $$outStack || []; 403 $$outStack.push(out); 404 out = ''; /* istanbul ignore else */ 405 if (it.createErrors !== false) { 406 out += ' { keyword: \'' + ($errorKeyword || 'type') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \''; 407 if ($typeIsArray) { 408 out += '' + ($typeSchema.join(",")); 409 } else { 410 out += '' + ($typeSchema); 411 } 412 out += '\' } '; 413 if (it.opts.messages !== false) { 414 out += ' , message: \'should be '; 415 if ($typeIsArray) { 416 out += '' + ($typeSchema.join(",")); 417 } else { 418 out += '' + ($typeSchema); 419 } 420 out += '\' '; 421 } 422 if (it.opts.verbose) { 423 out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' '; 424 } 425 out += ' } '; 426 } else { 427 out += ' {} '; 428 } 429 var __err = out; 430 out = $$outStack.pop(); 431 if (!it.compositeRule && $breakOnError) { 432 /* istanbul ignore if */ 433 if (it.async) { 434 out += ' throw new ValidationError([' + (__err) + ']); '; 435 } else { 436 out += ' validate.errors = [' + (__err) + ']; return false; '; 437 } 438 } else { 439 out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; '; 440 } 441 out += ' } '; 442 } 443 } 444 if ($breakOnError) { 445 out += ' if (errors === '; 446 if ($top) { 447 out += '0'; 448 } else { 449 out += 'errs_' + ($lvl); 450 } 451 out += ') { '; 452 $closingBraces2 += '}'; 453 } 454 } 455 } 456 } 457 } 458 if ($breakOnError) { 459 out += ' ' + ($closingBraces2) + ' '; 460 } 461 if ($top) { 462 if ($async) { 463 out += ' if (errors === 0) return data; '; 464 out += ' else throw new ValidationError(vErrors); '; 465 } else { 466 out += ' validate.errors = vErrors; '; 467 out += ' return errors === 0; '; 468 } 469 out += ' }; return validate;'; 470 } else { 471 out += ' var ' + ($valid) + ' = errors === errs_' + ($lvl) + ';'; 472 } 473 out = it.util.cleanUpCode(out); 474 if ($top) { 475 out = it.util.finalCleanUpCode(out, $async); 476 } 477 478 function $shouldUseGroup($rulesGroup) { 479 var rules = $rulesGroup.rules; 480 for (var i = 0; i < rules.length; i++) 481 if ($shouldUseRule(rules[i])) return true; 482 } 483 484 function $shouldUseRule($rule) { 485 return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImplementsSomeKeyword($rule)); 486 } 487 488 function $ruleImplementsSomeKeyword($rule) { 489 var impl = $rule.implements; 490 for (var i = 0; i < impl.length; i++) 491 if (it.schema[impl[i]] !== undefined) return true; 492 } 493 return out; 494 }