Skip to content
This repository
Browse code

Released a new version of Amanda

  • Loading branch information...
commit d57923aa167ca6e4a37ff7fc3a554af8fd0d0781 1 parent 6fff6da
František Hába authored November 24, 2011

Showing 1 changed file with 595 additions and 286 deletions. Show diff stats Hide diff stats

  1. 881  src/amanda.js
881  src/amanda.js
... ...
@@ -1,79 +1,237 @@
1 1
 (function() {
2 2
 
3 3
   /**
  4
+   * IsObject
  5
+   *
  6
+   * @param {object} input
  7
+   */
  8
+  var isObject = function(input) {
  9
+    return Object.prototype.toString.call(input) === '[object Object]';
  10
+  };
  11
+
  12
+  /**
  13
+   * IsArray
  14
+   *
  15
+   * @param {object} input
  16
+   */
  17
+  var isArray = function(input) {
  18
+    return Object.prototype.toString.call(input) === '[object Array]';
  19
+  };
  20
+
  21
+  /**
  22
+   * IsEmpty
  23
+   *  
  24
+   * Returns true if input is empty.
  25
+   *
  26
+   * @param {object} input
  27
+   */
  28
+  var isEmpty = function(input) {
  29
+    
  30
+    // Arrays and strings
  31
+    if (isArray(input)) {
  32
+      return input.length === 0;
  33
+    }
  34
+
  35
+    // Objects
  36
+    if (isObject(input)) {
  37
+      for (var key in input) {
  38
+        if (hasOwnProperty.call(input, key)) {
  39
+          return false;
  40
+        }
  41
+      }
  42
+    }
  43
+
  44
+    return true;
  45
+
  46
+  };
  47
+
  48
+  /**
4 49
    * Each
5 50
    *
  51
+   * Applies an iterator function to each item in an array or an object, in series.
  52
+   *
6 53
    * @param {object} list
7 54
    * @param {function} iterator
8 55
    * @param {function} callback
9 56
    */
10 57
   var each = function(list, iterator, callback) {
11 58
 
12  
-    var queue = [];
13  
-
14 59
     /**
15  
-     * AddToQueue
  60
+     * SyncEach
16 61
      *
17  
-     * @param {string} key
18  
-     * @param {string|object} value
  62
+     * @param {object} list
  63
+     * @param {function} iterator
19 64
      */
20  
-    var addToQueue = function(key, value) {
21  
-      var index = queue.length + 1;
22  
-      queue.push(function() {
23  
-
24  
-        var next = function(error) {
25  
-          var fn = queue[index];
26  
-          if (!error && fn) {
27  
-            return fn();
28  
-          } else if (!error && !fn) {
29  
-            return callback(null);
30  
-          } else {
31  
-            return callback(error);
32  
-          }
33  
-        };
  65
+    var syncEach = function(list, iterator) {
34 66
 
35  
-        return (key && value) ? iterator(key, value, next) : iterator(value, next);
  67
+      // If the list is an array
  68
+      if (isArray(list) && !isEmpty(list)) {
  69
+        for (var i = 0, len = list.length; i < len; i++) {
  70
+          iterator(i, list[i]);
  71
+        }
  72
+      }
  73
+
  74
+      // If the list is an object
  75
+      if (isObject(list) && !isEmpty(list)) {
  76
+        for (var key in list) {
  77
+          if (list.hasOwnProperty(key)) {
  78
+            iterator(key, list[key]);
  79
+          }
  80
+        } 
  81
+      }
36 82
 
37  
-      });
38 83
     };
39 84
 
40  
-    // If the list is an array
41  
-    if (Object.prototype.toString.call(list) === '[object Array]') {
42  
-      for (var i = 0, len = list.length; i < len; i++) {
43  
-        addToQueue(undefined, list[i]);
  85
+    /**
  86
+     * AsyncEach
  87
+     * @param {object} list
  88
+     * @param {function} iterator
  89
+     * @param {function} callback
  90
+     */
  91
+    var asyncEach = function(list, iterator, callback) {
  92
+
  93
+      var queue = [];
  94
+
  95
+      /**
  96
+       * AddToQueue
  97
+       *
  98
+       * @param {string} key
  99
+       * @param {string|object} value
  100
+       */
  101
+      var addToQueue = function(key, value) {
  102
+        var index = queue.length + 1;
  103
+        queue.push(function() {
  104
+
  105
+          var next = function(error) {
  106
+            var fn = queue[index];
  107
+            if (!error && fn) {
  108
+              return fn();
  109
+            } else if (!error && !fn) {
  110
+              return callback();
  111
+            } else {
  112
+              return callback(error);
  113
+            }
  114
+          };
  115
+
  116
+          return iterator(key, value, next);
  117
+
  118
+        });
  119
+      };
  120
+
  121
+      // If the list is an array
  122
+      if (isArray(list) && !isEmpty(list)) {
  123
+        for (var i = 0, len = list.length; i < len; i++) {
  124
+          addToQueue(i, list[i]);
  125
+        }
  126
+
  127
+      // If the list is an object
  128
+      } else if (isObject(list) && !isEmpty(list)) {
  129
+        for (var key in list) {
  130
+          if (list.hasOwnProperty(key)) {
  131
+            addToQueue(key, list[key]);
  132
+          }
  133
+        }
  134
+
  135
+      // If the list is not an array or an object
  136
+      } else {
  137
+        return callback();
44 138
       }
  139
+
  140
+      // And go!
  141
+      return queue[0]();
  142
+
  143
+    };
  144
+
  145
+    if (typeof callback === 'undefined') {
  146
+      return syncEach.apply(this, arguments);
  147
+    } else {
  148
+      return asyncEach.apply(this, arguments);
45 149
     }
46 150
 
47  
-    // If the list is an object
48  
-    if (Object.prototype.toString.call(list) === '[object Object]') {
49  
-      for (var key in list) {
50  
-        if (list.hasOwnProperty(key)) {
51  
-          addToQueue(key, list[key]);
52  
-        }
  151
+  };
  152
+
  153
+  /**
  154
+   * Pluck
  155
+   *
  156
+   * Extracts a list of property values.
  157
+   *
  158
+   * @param {object} list
  159
+   * @param {string} propertyName
  160
+   */
  161
+  var pluck = function(list, propertyName) {
  162
+    var output = [];
  163
+    for (var i = 0, len = list.length; i < len; i++) {
  164
+      var property = list[i][propertyName];
  165
+      if (output.indexOf(property) === -1) {
  166
+        output.push(property);
53 167
       }
54 168
     }
  169
+    return output;
  170
+  };
55 171
 
56  
-    // And go!
57  
-    return queue[0]();
  172
+  /**
  173
+   * Error
  174
+   *
  175
+   * @constructor
  176
+   */
  177
+  var Error = function() {
  178
+    this.length = 0;
  179
+  };
58 180
 
  181
+  Error.prototype.addError = function(error) {
  182
+    this[this.length] = error;
  183
+    this.length++;
59 184
   };
60 185
 
61 186
   /**
62  
-   * Validators
  187
+   * Error.getProperties
  188
+   * Error.getMessages
  189
+   */
  190
+  each({
  191
+    getProperties: 'property',
  192
+    getMessages: 'message'
  193
+  }, function(key, value) {
  194
+    Error.prototype[key] = function() {
  195
+      return pluck(this, value);
  196
+    };    
  197
+  });
  198
+
  199
+  /**
  200
+   * Validator
63 201
    *
64  
-   * List of validators.
  202
+   * @constructor
  203
+   * @param {object} options
65 204
    */
66  
-  var validators = {};
  205
+  var Validator = function(options) {
  206
+
  207
+    var self = this;
  208
+
  209
+    // Errors
  210
+    this.Errors = new Error();
  211
+
  212
+    // Options
  213
+    each([
  214
+      'singleError',
  215
+      'validators'
  216
+    ], function(key, value) {
  217
+      self[value] = options[value];
  218
+    });
  219
+
  220
+  };
67 221
 
68 222
   /**
69  
-   * ValidateParam
  223
+   * Validator.validateProperty
70 224
    *
71  
-   * @param {string} paramName
72  
-   * @param {object} paramValidators
73  
-   * @param {string|object} paramValue
  225
+   * @param {string} property
  226
+   * @param {object} propertyValidators
  227
+   * @param {string|object} propertyValue
  228
+   * @param {boolean} singleError
74 229
    * @param {function} callback
75 230
    */
76  
-  var validateParam = function(paramName, paramValidators, paramValue, callback) {
  231
+  Validator.prototype.validateProperty = function(property, propertyValue, propertyValidators, callback) {
  232
+
  233
+    // Reference na this
  234
+    var self = this;
77 235
 
78 236
     /**
79 237
      * Iterator
@@ -82,329 +240,480 @@
82 240
      * @param {function} callback
83 241
      */
84 242
     var iterator = function(validatorName, validatorFn, callback) {
85  
-      if (paramValidators[validatorName]) {
86  
-        validatorFn(paramName, paramValue, paramValidators[validatorName], paramValidators, function(error) {
  243
+      if (propertyValidators[validatorName]) {
  244
+        validatorFn(propertyValue, propertyValidators[validatorName], function(error) {
  245
+
87 246
           if (error) {
88  
-            return callback({
89  
-              paramName: paramName,
90  
-              paramValue: paramValue,
91  
-              validatorName: validatorName,
92  
-              validatorValue: paramValidators[validatorName]
  247
+            self.Errors.addError({
  248
+              property: property,
  249
+              propertyValue: propertyValue,
  250
+              validator: validatorName,
  251
+              validatorValue: propertyValidators[validatorName]
93 252
             });
94  
-          } else {
95  
-            return callback();
  253
+            return (self.singleError) ? callback(true) : callback();
96 254
           }
  255
+
  256
+          return callback();
  257
+
97 258
         });
98 259
       } else {
99 260
         return callback();
100 261
       }
101 262
     };
102 263
 
103  
-    if (paramValidators.required === false && paramValue === undefined) {
  264
+    if (propertyValidators.required !== true && typeof propertyValue === 'undefined') {
104 265
       return callback();
105 266
     } else {
106  
-      return each(validators, iterator, callback);
  267
+      return each(self.validators, iterator, callback);
107 268
     }
108 269
 
109 270
   };
110 271
 
111 272
   /**
112  
-   * ValidateSchema
  273
+   * Validator.validate
113 274
    *
114 275
    * @param {object} instance
115 276
    * @param {object} schema
  277
+   * @param {boolean} singleError
116 278
    * @param {function} callback
117 279
    */
118  
-  var validateSchema = function(instance, schema, callback) {
  280
+  Validator.prototype.validate = function(instance, schema, callback) {
119 281
 
120  
-    if (schema.required === false && instance === undefined) {
121  
-      return callback(null);
122  
-    } else {
  282
+    var self = this;
123 283
 
124  
-      /**
125  
-       * {
126  
-       *   type: 'object',
127  
-       *   properties: {
128  
-       *     ... 
129  
-       *   }
130  
-       * }
131  
-       */
132  
-      if (['object', 'array'].indexOf(schema.type) !== -1) {
133  
-        return validateParam(undefined, schema, instance, function(error) {
134  
-          if (error) {
135  
-            return callback(error);
136  
-          } else {
  284
+    return this.validateSchema(instance, schema, '', function(error) {
  285
+      return callback((self.Errors.length > 0) ? self.Errors : undefined);
  286
+    });
  287
+
  288
+  };
  289
+
  290
+  /**
  291
+   * Validator.validateSchema
  292
+   *
  293
+   * @param {object} instance
  294
+   * @param {object} schema
  295
+   * @param {boolean} singleError
  296
+   * @param {function} callback
  297
+   */
  298
+  Validator.prototype.validateSchema = function(instance, schema, path, callback) {
  299
+
  300
+    var self = this;
  301
+
  302
+    /**
  303
+     * {
  304
+     *   type: 'object',
  305
+     *   properties: {
  306
+     *     ... 
  307
+     *   }
  308
+     * }
  309
+     * — or —
  310
+     * {
  311
+     *   type: 'array',
  312
+     *   items: {
  313
+     *     ...
  314
+     * }
  315
+     */
  316
+    if (['object', 'array'].indexOf(schema.type) !== -1) {
  317
+      return self.validateProperty(path, instance, schema, function(error) {
  318
+
  319
+        // If an error occurred, the validation process can't continue
  320
+        if (error) {
  321
+          return callback(error);
  322
+        }
  323
+
  324
+        /**
  325
+         * {
  326
+         *   type: 'object',
  327
+         *   properties: {
  328
+         *     ... 
  329
+         *   }
  330
+         * }
  331
+         */
  332
+        if (schema.properties) {
  333
+          return each(schema.properties, function(property, propertyValidators, callback) {
  334
+            
  335
+            var isObject = propertyValidators.type === 'object' && propertyValidators.properties,
  336
+                isArray =  propertyValidators.type === 'array';
  337
+
  338
+            // Get the value of property (instance[property])
  339
+            var propertyValue = self.getProperty(instance, property);
  340
+
  341
+            // Compose the property path
  342
+            var propertyPath = (path.length === 0) ? property : path + '.' + property;
137 343
 
138 344
             /**
139 345
              * {
140 346
              *   type: 'object',
141 347
              *   properties: {
142  
-             *     ... 
  348
+             *     user: {
  349
+             *       type: 'object',
  350
+             *       properties: {
  351
+             *         ...
  352
+             *       }
  353
+             *     }
143 354
              *   }
144 355
              * }
145 356
              */
146  
-            if (schema.properties) {
147  
-              return each(schema.properties, function(paramName, paramValidators, callback) {
148  
-                if ((paramValidators.type === 'object' && paramValidators.properties) || paramValidators.type === 'array')  {
149  
-                  return validateSchema(instance[paramName], schema.properties[paramName], callback);
150  
-                } else {
151  
-                  return validateParam(paramName, paramValidators, instance[paramName], callback);
152  
-                }
153  
-              }, callback);
  357
+            if (isObject || isArray)  {
  358
+              return self.validateSchema(propertyValue, schema.properties[property], propertyPath, callback);
  359
+            } else {
  360
+              return self.validateProperty(propertyPath, propertyValue, propertyValidators, callback);
  361
+            }
154 362
 
155  
-            /**
156  
-             * {
157  
-             *   type: 'array',
158  
-             *   items: {
159  
-             *     type: 'string'
160  
-             *     ... 
161  
-             *   }
162  
-             * }
163  
-             */
164  
-            } else if (schema.items) {
165  
-              if (['object', 'array'].indexOf(schema.items.type) !== -1) {
166  
-                return each(instance, function(item, callback) {
167  
-                  return validateSchema(item, schema.items, callback);
168  
-                }, callback);
169  
-              } else {
170  
-                return each(instance, function(item, callback) {
171  
-                  return validateParam(undefined, schema.items, item, callback);
172  
-                }, callback);
173  
-              }
174  
-            
175  
-            /**
176  
-             * {
177  
-             *   type: 'array'
178  
-             * }
179  
-             */
  363
+          }, callback);
  364
+
  365
+        /**
  366
+         * {
  367
+         *   type: 'array',
  368
+         *   items: {
  369
+         *     type: 'string'
  370
+         *     ... 
  371
+         *   }
  372
+         * }
  373
+         */
  374
+        } else if (schema.items) {
  375
+
  376
+          /**
  377
+           * {
  378
+           *   type: 'array',
  379
+           *   items: {
  380
+           *     type: 'object'
  381
+           *   }
  382
+           * }
  383
+           * — or —
  384
+           * {
  385
+           *   type: 'array',
  386
+           *   items: {
  387
+           *     type: 'array'
  388
+           *   }
  389
+           * }
  390
+           */
  391
+          if (['object', 'array'].indexOf(schema.items.type) !== -1) {
  392
+            if (instance && !isEmpty(instance)) {
  393
+              return each(instance, function(index, propertyValue, callback) {
  394
+                var propertyPath = path + '[' + index + ']';
  395
+                return self.validateSchema(propertyValue, schema.items, propertyPath, callback);
  396
+              }, callback);
180 397
             } else {
181  
-              return callback(null);
  398
+              return callback();
182 399
             }
183 400
 
  401
+          /*
  402
+           * {
  403
+           *   type: 'array',
  404
+           *   items: {
  405
+           *     type: 'string'
  406
+           *   }
  407
+           * }
  408
+           */
  409
+          } else {
  410
+            if (instance && !isEmpty(instance)) {
  411
+              return each(instance, function(index, propertyValue, callback) {
  412
+                var propertyPath = path + '[' + index + ']';
  413
+                return self.validateProperty(propertyPath, propertyValue, schema.items, callback);
  414
+              }, callback);
  415
+            } else {
  416
+              return callback();
  417
+            }
184 418
           }
185  
-        });
186 419
 
187  
-      /**
188  
-       * {
189  
-       *   type: 'string',
190  
-       *   length: ...
191  
-       * }
192  
-       */
193  
-      } else {
194  
-        return validateParam(undefined, schema, instance, callback);
195  
-      }
  420
+        /**
  421
+         * {
  422
+         *   type: 'array'
  423
+         * }
  424
+         * — or —
  425
+         * {
  426
+         *   type: 'object'
  427
+         * }
  428
+         */
  429
+        } else {
  430
+          return callback();
  431
+        }
  432
+
  433
+      });
196 434
 
  435
+    /**
  436
+     * {
  437
+     *   type: 'string',
  438
+     *   length: ...
  439
+     * }
  440
+     */
  441
+    } else {
  442
+      return self.validateProperty(path, instance, schema, callback);
197 443
     }
198 444
 
199 445
   };
200 446
 
201 447
   /**
202  
-   * amanda
  448
+   * GetProperty
203 449
    *
  450
+   * @param {object} source
  451
+   * @param {string} property
204 452
    */
205  
-  var amanda = {
  453
+  Validator.prototype.getProperty = function(source, property) {
  454
+    if (!source) {
  455
+      return undefined;
  456
+    } else {
  457
+      return source[property];
  458
+    }
  459
+  };
206 460
 
207  
-    /**
208  
-     * Validate
209  
-     *
210  
-     * @param {object} structure
211  
-     */
212  
-    validate: function(data, schema, singleError, callback) {
  461
+  /**
  462
+   * Validators
  463
+   */
  464
+  var validators = {
  465
+    
  466
+    required: function(value, options, callback) {
  467
+      if (options && !value) {
  468
+        return callback(true);
  469
+      } else {
  470
+        return callback();
  471
+      }
  472
+    },
213 473
 
214  
-      return validateSchema.apply(this, arguments);
  474
+    type: (function() {
  475
+      
  476
+      var types = {
  477
+        'object': function(input) {
  478
+          return Object.prototype.toString.call(input) === '[object Object]';
  479
+        },
  480
+        'array': function(input) {
  481
+          return Object.prototype.toString.call(input) === '[object Array]';
  482
+        }
  483
+      };
215 484
 
216  
-    },
  485
+      // Generate the rest of type checkers
  486
+      [
  487
+        'string',
  488
+        'number',
  489
+        'function',
  490
+        'boolean'
  491
+      ].forEach(function(type) {
  492
+        types[type] = function() {
  493
+          return typeof arguments[0] === type;
  494
+        };
  495
+      });
217 496
 
218  
-    /**
219  
-     * AddValidator
220  
-     *
221  
-     * @param {string} validatorName
222  
-     * @param {function} validatorFn
223  
-     */
224  
-    addValidator: function(validatorName, validatorFn) {
225  
-      validators[validatorName] = validatorFn;
226  
-    },
  497
+      return function(value, options, callback) {
  498
+
  499
+        /**
  500
+         * {
  501
+         *   type: ['string', 'number']
  502
+         * }
  503
+         */
  504
+        if (Object.prototype.toString.call(options) === '[object Array]') {
  505
+          var noError = options.some(function(type) {
  506
+            return types[type](value);
  507
+          });
  508
+          return (noError) ? callback() : callback(true);
  509
+
  510
+        /**
  511
+         * {
  512
+         *   type: 'string'
  513
+         * }
  514
+         */
  515
+        } else {
  516
+          return (types[options](value)) ? callback() : callback(true);
  517
+        }
  518
+
  519
+      };
  520
+
  521
+    }()),
227 522
 
228 523
     /**
229  
-     * getVersion
  524
+     * Format
230 525
      */
231  
-    getVersion: function() {
232  
-      return [0, 0, 1].join('.');
233  
-    }
  526
+    format: (function() {
234 527
 
235  
-  };
  528
+      /**
  529
+       * Formats
  530
+       */
  531
+      var formats = {
  532
+        'alpha': function(input) {
  533
+          return (typeof input === 'string' && input.match(/^[a-zA-Z]+$/));
  534
+        },
  535
+        'alphanumeric': function(input) {
  536
+          return (typeof input === 'string' && /^[a-zA-Z0-9]+$/.test(input)) || typeof input === 'number';
  537
+        },
  538
+        'ipv4': function(input) {
  539
+          return typeof input === 'string' && input.match(/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/);
  540
+        },
  541
+        'ipv6': function(input) {
  542
+          return typeof input === 'string' && input.match(/(?:(?:[a-f\d]{1,4}:)*(?:[a-f\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:(?:[a-f\d]{1,4}:)*[a-f\d]{1,4})?::(?:(?:[a-f\d]{1,4}:)*(?:[a-f\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))?)/);
  543
+        },
  544
+        'ip': function(input) {
  545
+          return formats.ipv4(input) || formats.ipv6;
  546
+        },
  547
+        'email': function(input) {
  548
+          return typeof input === 'string' && input.match(/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/);
  549
+        },
  550
+        'url': function(input) {
  551
+          return typeof input === 'string' && input.match(/^(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?:\w+:\w+@)?((?:(?:[-\w\d{1-3}]+\.)+(?:com|org|cat|coop|int|pro|tel|xxx|net|gov|mil|biz|info|mobi|name|aero|jobs|edu|co\.uk|ac\.uk|it|fr|tv|museum|asia|local|travel|[a-z]{2})?)|((\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)(\.(\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)){3}))(?::[\d]{1,5})?(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?:#(?:[-\w~!$ |\/.,*:;=]|%[a-f\d]{2})*)?$/);
  552
+        },
  553
+        'date': function(input) {
  554
+          return Object.prototype.toString.call(input) === '[object Date]';
  555
+        },
  556
+        'decimal': function(input) {
  557
+          return /^[0-9]+(\.[0-9]{1,2})?$/.test(input);
  558
+        },
  559
+        'int': function(input) {
  560
+          return /^-?[0-9]+$/.test(input);
  561
+        },
  562
+        'percentage': function(input) {
  563
+          return (typeof input == 'string' && input.match(/^-?[0-9]{0,2}(\.[0-9]{1,2})?$|^-?(100)(\.[0]{1,2})?$/)) || (input >= -100 && input <= 100);
  564
+        },
  565
+        'port': function(input) {
  566
+          return /\:\d+/.test(input);
  567
+        },
  568
+        'regexp': function(input) {
  569
+          return input && input.test && input.exec;
  570
+        },
  571
+        'unsignedInt': function(input) {
  572
+          return /^[0-9]+$/.test(input);
  573
+        }
  574
+      };
236 575
 
237  
-  /**
238  
-   * Required
239  
-   */
240  
-  amanda.addValidator('required', function(paramName, paramValue, validatorValue, validators, callback) {
241  
-    if (validatorValue && !paramValue) {
242  
-      return callback(true);
243  
-    } else {
244  
-      return callback();
245  
-    }
246  
-  });
  576
+      return function(value, options, callback) {
  577
+
  578
+        /**
  579
+         * {
  580
+         *   type: ['string', 'number']
  581
+         * }
  582
+         */
  583
+        if (Object.prototype.toString.call(options) === '[object Array]') {
  584
+          var noError = options.some(function(format) {
  585
+            return formats[format](value);
  586
+          });
  587
+          return (noError) ? callback() : callback(true);
  588
+
  589
+        /**
  590
+         * {
  591
+         *   type: 'string'
  592
+         * }
  593
+         */
  594
+        } else {
  595
+          return (formats[options](value)) ? callback() : callback(true);
  596
+        }
247 597
 
248  
-  /**
249  
-   * Type
250  
-   */
251  
-  amanda.addValidator('type', (function() {
  598
+      };
  599
+
  600
+    }()),
252 601
 
253 602
     /**
254  
-     * Types
  603
+     * Length
255 604
      */
256  
-    var types = {
257  
-      'array': function(input) {
258  
-        return Array.isArray(input);
259  
-      },
260  
-      'alpha': function(input) {
261  
-        return (typeof input === 'string' && input.match(/^[a-zA-Z]+$/));
262  
-      },
263  
-      'alphanumeric': function(input) {
264  
-        return (typeof input === 'string' && /^[a-zA-Z0-9]+$/.test(input)) || typeof input === 'number';
265  
-      },
266  
-      'ipv4': function(input) {
267  
-        return typeof input === 'string' && input.match(/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/);
268  
-      },
269  
-      'ipv6': function(input) {
270  
-        return typeof input === 'string' && input.match(/(?:(?:[a-f\d]{1,4}:)*(?:[a-f\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:(?:[a-f\d]{1,4}:)*[a-f\d]{1,4})?::(?:(?:[a-f\d]{1,4}:)*(?:[a-f\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))?)/);
271  
-      },
272  
-      'ip': function(input) {
273  
-        return types.ipv4(input) || types.ipv6;
274  
-      },
275  
-      'email': function(input) {
276  
-        return typeof input === 'string' && input.match(/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/);
277  
-      },
278  
-      'url': function(input) {
279  
-        return typeof input === 'string' && input.match(/^(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?:\w+:\w+@)?((?:(?:[-\w\d{1-3}]+\.)+(?:com|org|cat|coop|int|pro|tel|xxx|net|gov|mil|biz|info|mobi|name|aero|jobs|edu|co\.uk|ac\.uk|it|fr|tv|museum|asia|local|travel|[a-z]{2})?)|((\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)(\.(\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)){3}))(?::[\d]{1,5})?(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?:#(?:[-\w~!$ |\/.,*:;=]|%[a-f\d]{2})*)?$/);
280  
-      },
281  
-      'date': function(input) {
282  
-        return Object.prototype.toString.call(input) === '[object Date]';
283  
-      },
284  
-      'decimal': function(input) {
285  
-        return /^[0-9]+(\.[0-9]{1,2})?$/.test(input);
286  
-      },
287  
-      'int': function(input) {
288  
-        return /^-?[0-9]+$/.test(input);
289  
-      },
290  
-      'percentage': function(input) {
291  
-        return (typeof input === 'string' && input.match(/^-?[0-9]{0,2}(\.[0-9]{1,2})?$|^-?(100)(\.[0]{1,2})?$/));
292  
-      },
293  
-      'port': function(input) {
294  
-        return /\:\d+/.test(input);
295  
-      },
296  
-      'regexp': function(input) {
297  
-        return input && input.test && input.exec;
298  
-      },
299  
-      'unsignedInt':function(input) {
300  
-        return /^[0-9]+$/.test(input);
301  
-      }
302  
-    };
  605
+    length: function(value, options, callback) {
  606
+    
  607
+      // Check the length only if the type of ‘paramValue’ is string
  608
+      if (typeof value === 'string') {
303 609
 
304  
-    // Generate the rest of type checkers
305  
-    [
306  
-      'string',
307  
-      'number',
308  
-      'function',
309  
-      'object',
310  
-      'boolean'
311  
-    ].forEach(function(type) {
312  
-      types[type] = function() {
313  
-        return (typeof arguments[0] === type) ? true : false;
314  
-      };
315  
-    });
316 610
 
317  
-    return function(paramName, paramValue, validatorValue, validators, callback) {
318  
-      if (!types[validatorValue](paramValue)) {
319  
-        return callback(true);
  611
+        // If the length is specified as an array (for instance ‘[2, 45]’)
  612
+        if (Array.isArray(options) && (value.length < options[0] || value.length > options[1])) {
  613
+          return callback(true);
  614
+
  615
+        // If the length is specified as a string (for instance ‘2’)
  616
+        } else if (typeof options === 'number' && value.length !== options) {
  617
+          return callback(true);
  618
+
  619
+        // If the length is specified in a different way
  620
+        } else {
  621
+          return callback();
  622
+        }
  623
+
320 624
       } else {
321  
-        return callback();
  625
+        return callback(); 
322 626
       }
323  
-    };
324 627
 
325  
-  }()));
  628
+    },
326 629
 
327  
-  /**
328  
-   * Length
329  
-   */
330  
-  amanda.addValidator('length', function(paramName, paramValue, validatorValue, validators, callback) {
331  
-    
332  
-    // Check the length only if the type of ‘paramValue’ is string
333  
-    if (typeof paramValue === 'string') {
  630
+    /**
  631
+     * Enum
  632
+     */
  633
+    enum: function(value, options, callback) {
  634
+      return (options.indexOf(value) === -1) ? callback(true) : callback();
  635
+    },
334 636
 
335  
-      // If the length is specified as an array (for instance ‘[2, 45]’)
336  
-      if (Array.isArray(validatorValue) && (paramValue.length < validatorValue[0] || paramValue.length > validatorValue[1])) {
337  
-        return callback(true);
  637
+    /**
  638
+     * Except
  639
+     */
  640
+    except: function(value, options, callback) {
  641
+      return (options.indexOf(value) !== -1) ? callback(true) : callback();
  642
+    },
338 643
 
339  
-      // If the length is specified as a string (for instance ‘2’)
340  
-      } else if (typeof validatorValue === 'number' && paramValue.length !== validatorValue) {
341  
-        return callback(true);
  644
+    /**
  645
+     * Min
  646
+     */
  647
+    min: function(value, options, callback) {
  648
+      return (typeof value !== 'number' || value < options) ? callback(true) : callback();
  649
+    },
342 650
 
343  
-      // If the length is specified in a different way
344  
-      } else {
345  
-        return callback();
346  
-      }
  651
+    /**
  652
+     * Max
  653
+     */
  654
+    max: function(value, options, callback) {
  655
+      return (typeof value !== 'number' || value > options) ? callback(true) : callback();
  656
+    },
347 657
 
348  
-    } else {
349  
-      return callback(); 
  658
+    /**
  659
+     * Pattern
  660
+     */
  661
+    pattern: function(value, options, callback) {
  662
+      return (typeof value === 'string' && !value.match(options)) ? callback(true) : callback();
350 663
     }
351 664
 
352  
-  });
  665
+  };
353 666
 
354 667
   /**
355  
-   * Values
  668
+   * Amanda
356 669
    */
357  
-  amanda.addValidator('values', function(paramName, paramValue, validatorValue, validators, callback) {
358  
-    if (validatorValue.indexOf(paramValue) === -1) {
359  
-      return callback(true);
360  
-    } else {
361  
-      return callback();
362  
-    }
363  
-  });
  670
+  var amanda = {
364 671
 
365  
-  /**
366  
-   * Except
367  
-   */
368  
-  amanda.addValidator('except', function(paramName, paramValue, validatorValue, validators, callback) {
369  
-    if (validatorValue.indexOf(paramValue) !== -1) {
370  
-      return callback(true);
371  
-    } else {
372  
-      return callback();
373  
-    }
374  
-  });
  672
+    /**
  673
+     * Validate
  674
+     *
  675
+     * @param {object} structure
  676
+     */
  677
+    validate: function(data, schema, options, callback) {
375 678
 
376  
-  /**
377  
-   * Min
378  
-   */
379  
-  amanda.addValidator('min', function(paramName, paramValue, validatorValue, validators, callback) {
380  
-    if (typeof paramValue !== 'number' || paramValue < validatorValue) {
381  
-      return callback(true);
382  
-    } else {
383  
-      return callback();
384  
-    }
385  
-  });
  679
+      if ( typeof options === 'function') {
  680
+        callback = options;
  681
+        options = {
  682
+          singleError: true
  683
+        };
  684
+      }
386 685
 
387  
-  /**
388  
-   * Max
389  
-   */
390  
-  amanda.addValidator('max', function(paramName, paramValue, validatorValue, validators, callback) {
391  
-    if (typeof paramValue !== 'number' || paramValue > validatorValue) {
392  
-      return callback(true);
393  
-    } else {
394  
-      return callback();
395  
-    }
396  
-  });
  686
+      options.validators = validators;
397 687
 
398  
-  /**
399  
-   * Pattern
400  
-   */
401  
-  amanda.addValidator('pattern', function(paramName, paramValue, validatorValue, validators, callback) {
402  
-    if (typeof paramValue === 'string' && !paramValue.match(validatorValue)) {
403  
-      return callback(true);
404  
-    } else {
405  
-      return callback();
  688
+      return (new Validator(options)).validate(data, schema, callback);
  689
+
  690
+    },
  691
+
  692
+    /**
  693
+     * AddValidator
  694
+     *
  695
+     * @param {string} validatorName
  696
+     * @param {function} validatorFn
  697
+     */
  698
+    addValidator: function(validatorName, validatorFn) {
  699
+      validators[validatorName] = validatorFn;
  700
+    },
  701
+
  702
+    /**
  703
+     * GetVersion
  704
+     */
  705
+    getVersion: function() {
  706
+      return [0, 0, 2].join('.');
  707
+    },
  708
+
  709
+    /**
  710
+     * GetValidators
  711
+     */
  712
+    getValidators: function() {
  713
+      return validators;
406 714
     }
407  
-  });
  715
+
  716
+  };
408 717
 
409 718
   // Export
410 719
   if (typeof module !== 'undefined' && module.exports) {

0 notes on commit d57923a

Please sign in to comment.
Something went wrong with that request. Please try again.