index.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import _extends from 'babel-runtime/helpers/extends';
  2. import _typeof from 'babel-runtime/helpers/typeof';
  3. import { format, complementError, asyncMap, warning, deepMerge } from './util';
  4. import validators from './validator/';
  5. import { messages as defaultMessages, newMessages } from './messages';
  6. /**
  7. * Encapsulates a validation schema.
  8. *
  9. * @param descriptor An object declaring validation rules
  10. * for this schema.
  11. */
  12. function Schema(descriptor) {
  13. this.rules = null;
  14. this._messages = defaultMessages;
  15. this.define(descriptor);
  16. }
  17. Schema.prototype = {
  18. messages: function messages(_messages) {
  19. if (_messages) {
  20. this._messages = deepMerge(newMessages(), _messages);
  21. }
  22. return this._messages;
  23. },
  24. define: function define(rules) {
  25. if (!rules) {
  26. throw new Error('Cannot configure a schema with no rules');
  27. }
  28. if ((typeof rules === 'undefined' ? 'undefined' : _typeof(rules)) !== 'object' || Array.isArray(rules)) {
  29. throw new Error('Rules must be an object');
  30. }
  31. this.rules = {};
  32. var z = void 0;
  33. var item = void 0;
  34. for (z in rules) {
  35. if (rules.hasOwnProperty(z)) {
  36. item = rules[z];
  37. this.rules[z] = Array.isArray(item) ? item : [item];
  38. }
  39. }
  40. },
  41. validate: function validate(source_) {
  42. var _this = this;
  43. var o = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  44. var oc = arguments[2];
  45. var source = source_;
  46. var options = o;
  47. var callback = oc;
  48. if (typeof options === 'function') {
  49. callback = options;
  50. options = {};
  51. }
  52. if (!this.rules || Object.keys(this.rules).length === 0) {
  53. if (callback) {
  54. callback();
  55. }
  56. return;
  57. }
  58. function complete(results) {
  59. var i = void 0;
  60. var field = void 0;
  61. var errors = [];
  62. var fields = {};
  63. function add(e) {
  64. if (Array.isArray(e)) {
  65. errors = errors.concat.apply(errors, e);
  66. } else {
  67. errors.push(e);
  68. }
  69. }
  70. for (i = 0; i < results.length; i++) {
  71. add(results[i]);
  72. }
  73. if (!errors.length) {
  74. errors = null;
  75. fields = null;
  76. } else {
  77. for (i = 0; i < errors.length; i++) {
  78. field = errors[i].field;
  79. fields[field] = fields[field] || [];
  80. fields[field].push(errors[i]);
  81. }
  82. }
  83. callback(errors, fields);
  84. }
  85. if (options.messages) {
  86. var messages = this.messages();
  87. if (messages === defaultMessages) {
  88. messages = newMessages();
  89. }
  90. deepMerge(messages, options.messages);
  91. options.messages = messages;
  92. } else {
  93. options.messages = this.messages();
  94. }
  95. var arr = void 0;
  96. var value = void 0;
  97. var series = {};
  98. var keys = options.keys || Object.keys(this.rules);
  99. keys.forEach(function (z) {
  100. arr = _this.rules[z];
  101. value = source[z];
  102. arr.forEach(function (r) {
  103. var rule = r;
  104. if (typeof rule.transform === 'function') {
  105. if (source === source_) {
  106. source = _extends({}, source);
  107. }
  108. value = source[z] = rule.transform(value);
  109. }
  110. if (typeof rule === 'function') {
  111. rule = {
  112. validator: rule
  113. };
  114. } else {
  115. rule = _extends({}, rule);
  116. }
  117. rule.validator = _this.getValidationMethod(rule);
  118. rule.field = z;
  119. rule.fullField = rule.fullField || z;
  120. rule.type = _this.getType(rule);
  121. if (!rule.validator) {
  122. return;
  123. }
  124. series[z] = series[z] || [];
  125. series[z].push({
  126. rule: rule,
  127. value: value,
  128. source: source,
  129. field: z
  130. });
  131. });
  132. });
  133. var errorFields = {};
  134. asyncMap(series, options, function (data, doIt) {
  135. var rule = data.rule;
  136. var deep = (rule.type === 'object' || rule.type === 'array') && (_typeof(rule.fields) === 'object' || _typeof(rule.defaultField) === 'object');
  137. deep = deep && (rule.required || !rule.required && data.value);
  138. rule.field = data.field;
  139. function addFullfield(key, schema) {
  140. return _extends({}, schema, {
  141. fullField: rule.fullField + '.' + key
  142. });
  143. }
  144. function cb() {
  145. var e = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  146. var errors = e;
  147. if (!Array.isArray(errors)) {
  148. errors = [errors];
  149. }
  150. if (errors.length) {
  151. warning('async-validator:', errors);
  152. }
  153. if (errors.length && rule.message) {
  154. errors = [].concat(rule.message);
  155. }
  156. errors = errors.map(complementError(rule));
  157. if (options.first && errors.length) {
  158. errorFields[rule.field] = 1;
  159. return doIt(errors);
  160. }
  161. if (!deep) {
  162. doIt(errors);
  163. } else {
  164. // if rule is required but the target object
  165. // does not exist fail at the rule level and don't
  166. // go deeper
  167. if (rule.required && !data.value) {
  168. if (rule.message) {
  169. errors = [].concat(rule.message).map(complementError(rule));
  170. } else if (options.error) {
  171. errors = [options.error(rule, format(options.messages.required, rule.field))];
  172. } else {
  173. errors = [];
  174. }
  175. return doIt(errors);
  176. }
  177. var fieldsSchema = {};
  178. if (rule.defaultField) {
  179. for (var k in data.value) {
  180. if (data.value.hasOwnProperty(k)) {
  181. fieldsSchema[k] = rule.defaultField;
  182. }
  183. }
  184. }
  185. fieldsSchema = _extends({}, fieldsSchema, data.rule.fields);
  186. for (var f in fieldsSchema) {
  187. if (fieldsSchema.hasOwnProperty(f)) {
  188. var fieldSchema = Array.isArray(fieldsSchema[f]) ? fieldsSchema[f] : [fieldsSchema[f]];
  189. fieldsSchema[f] = fieldSchema.map(addFullfield.bind(null, f));
  190. }
  191. }
  192. var schema = new Schema(fieldsSchema);
  193. schema.messages(options.messages);
  194. if (data.rule.options) {
  195. data.rule.options.messages = options.messages;
  196. data.rule.options.error = options.error;
  197. }
  198. schema.validate(data.value, data.rule.options || options, function (errs) {
  199. doIt(errs && errs.length ? errors.concat(errs) : errs);
  200. });
  201. }
  202. }
  203. var res = rule.validator(rule, data.value, cb, data.source, options);
  204. if (res && res.then) {
  205. res.then(function () {
  206. return cb();
  207. }, function (e) {
  208. return cb(e);
  209. });
  210. }
  211. }, function (results) {
  212. complete(results);
  213. });
  214. },
  215. getType: function getType(rule) {
  216. if (rule.type === undefined && rule.pattern instanceof RegExp) {
  217. rule.type = 'pattern';
  218. }
  219. if (typeof rule.validator !== 'function' && rule.type && !validators.hasOwnProperty(rule.type)) {
  220. throw new Error(format('Unknown rule type %s', rule.type));
  221. }
  222. return rule.type || 'string';
  223. },
  224. getValidationMethod: function getValidationMethod(rule) {
  225. if (typeof rule.validator === 'function') {
  226. return rule.validator;
  227. }
  228. var keys = Object.keys(rule);
  229. var messageIndex = keys.indexOf('message');
  230. if (messageIndex !== -1) {
  231. keys.splice(messageIndex, 1);
  232. }
  233. if (keys.length === 1 && keys[0] === 'required') {
  234. return validators.required;
  235. }
  236. return validators[this.getType(rule)] || false;
  237. }
  238. };
  239. Schema.register = function register(type, validator) {
  240. if (typeof validator !== 'function') {
  241. throw new Error('Cannot register a validator by type, validator is not a function');
  242. }
  243. validators[type] = validator;
  244. };
  245. Schema.messages = defaultMessages;
  246. export default Schema;