formio/node_modules/ajv/lib/dotjs/validate.js   F
last analyzed

Complexity

Total Complexity 130
Complexity/F 32.5

Size

Lines of Code 458
Function Count 4

Duplication

Duplicated Lines 35
Ratio 7.64 %

Importance

Changes 0
Metric Value
cc 0
wmc 130
nc 0
mnd 11
bc 129
fnc 4
dl 35
loc 458
rs 1.5789
bpm 32.25
cpm 32.5
noi 5
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
F validate.js ➔ generate_validate 35 457 123

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like formio/node_modules/ajv/lib/dotjs/validate.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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