async-validator.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356
  1. function _extends() {
  2. _extends = Object.assign || function(target) {
  3. for (var i = 1; i < arguments.length; i++) {
  4. var source = arguments[i];
  5. for (var key in source) {
  6. if (Object.prototype.hasOwnProperty.call(source, key)) {
  7. target[key] = source[key];
  8. }
  9. }
  10. }
  11. return target;
  12. };
  13. return _extends.apply(this, arguments);
  14. }
  15. /* eslint no-console:0 */
  16. var formatRegExp = /%[sdj%]/g;
  17. var warning = function warning() {}; // don't print warning message when in production env or node runtime
  18. if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production' && typeof window !==
  19. 'undefined' && typeof document !== 'undefined') {
  20. warning = function warning(type, errors) {
  21. if (typeof console !== 'undefined' && console.warn) {
  22. if (errors.every(function(e) {
  23. return typeof e === 'string';
  24. })) {
  25. console.warn(type, errors);
  26. }
  27. }
  28. };
  29. }
  30. function convertFieldsError(errors) {
  31. if (!errors || !errors.length) return null;
  32. var fields = {};
  33. errors.forEach(function(error) {
  34. var field = error.field;
  35. fields[field] = fields[field] || [];
  36. fields[field].push(error);
  37. });
  38. return fields;
  39. }
  40. function format() {
  41. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  42. args[_key] = arguments[_key];
  43. }
  44. var i = 1;
  45. var f = args[0];
  46. var len = args.length;
  47. if (typeof f === 'function') {
  48. return f.apply(null, args.slice(1));
  49. }
  50. if (typeof f === 'string') {
  51. var str = String(f).replace(formatRegExp, function(x) {
  52. if (x === '%%') {
  53. return '%';
  54. }
  55. if (i >= len) {
  56. return x;
  57. }
  58. switch (x) {
  59. case '%s':
  60. return String(args[i++]);
  61. case '%d':
  62. return Number(args[i++]);
  63. case '%j':
  64. try {
  65. return JSON.stringify(args[i++]);
  66. } catch (_) {
  67. return '[Circular]';
  68. }
  69. break;
  70. default:
  71. return x;
  72. }
  73. });
  74. for (var arg = args[i]; i < len; arg = args[++i]) {
  75. str += " " + arg;
  76. }
  77. return str;
  78. }
  79. return f;
  80. }
  81. function isNativeStringType(type) {
  82. return type === 'string' || type === 'url' || type === 'hex' || type === 'email' || type === 'pattern';
  83. }
  84. function isEmptyValue(value, type) {
  85. if (value === undefined || value === null) {
  86. return true;
  87. }
  88. if (type === 'array' && Array.isArray(value) && !value.length) {
  89. return true;
  90. }
  91. if (isNativeStringType(type) && typeof value === 'string' && !value) {
  92. return true;
  93. }
  94. return false;
  95. }
  96. function asyncParallelArray(arr, func, callback) {
  97. var results = [];
  98. var total = 0;
  99. var arrLength = arr.length;
  100. function count(errors) {
  101. results.push.apply(results, errors);
  102. total++;
  103. if (total === arrLength) {
  104. callback(results);
  105. }
  106. }
  107. arr.forEach(function(a) {
  108. func(a, count);
  109. });
  110. }
  111. function asyncSerialArray(arr, func, callback) {
  112. var index = 0;
  113. var arrLength = arr.length;
  114. function next(errors) {
  115. if (errors && errors.length) {
  116. callback(errors);
  117. return;
  118. }
  119. var original = index;
  120. index = index + 1;
  121. if (original < arrLength) {
  122. func(arr[original], next);
  123. } else {
  124. callback([]);
  125. }
  126. }
  127. next([]);
  128. }
  129. function flattenObjArr(objArr) {
  130. var ret = [];
  131. Object.keys(objArr).forEach(function(k) {
  132. ret.push.apply(ret, objArr[k]);
  133. });
  134. return ret;
  135. }
  136. function asyncMap(objArr, option, func, callback) {
  137. if (option.first) {
  138. var _pending = new Promise(function(resolve, reject) {
  139. var next = function next(errors) {
  140. callback(errors);
  141. return errors.length ? reject({
  142. errors: errors,
  143. fields: convertFieldsError(errors)
  144. }) : resolve();
  145. };
  146. var flattenArr = flattenObjArr(objArr);
  147. asyncSerialArray(flattenArr, func, next);
  148. });
  149. _pending["catch"](function(e) {
  150. return e;
  151. });
  152. return _pending;
  153. }
  154. var firstFields = option.firstFields || [];
  155. if (firstFields === true) {
  156. firstFields = Object.keys(objArr);
  157. }
  158. var objArrKeys = Object.keys(objArr);
  159. var objArrLength = objArrKeys.length;
  160. var total = 0;
  161. var results = [];
  162. var pending = new Promise(function(resolve, reject) {
  163. var next = function next(errors) {
  164. results.push.apply(results, errors);
  165. total++;
  166. if (total === objArrLength) {
  167. callback(results);
  168. return results.length ? reject({
  169. errors: results,
  170. fields: convertFieldsError(results)
  171. }) : resolve();
  172. }
  173. };
  174. if (!objArrKeys.length) {
  175. callback(results);
  176. resolve();
  177. }
  178. objArrKeys.forEach(function(key) {
  179. var arr = objArr[key];
  180. if (firstFields.indexOf(key) !== -1) {
  181. asyncSerialArray(arr, func, next);
  182. } else {
  183. asyncParallelArray(arr, func, next);
  184. }
  185. });
  186. });
  187. pending["catch"](function(e) {
  188. return e;
  189. });
  190. return pending;
  191. }
  192. function complementError(rule) {
  193. return function(oe) {
  194. if (oe && oe.message) {
  195. oe.field = oe.field || rule.fullField;
  196. return oe;
  197. }
  198. return {
  199. message: typeof oe === 'function' ? oe() : oe,
  200. field: oe.field || rule.fullField
  201. };
  202. };
  203. }
  204. function deepMerge(target, source) {
  205. if (source) {
  206. for (var s in source) {
  207. if (source.hasOwnProperty(s)) {
  208. var value = source[s];
  209. if (typeof value === 'object' && typeof target[s] === 'object') {
  210. target[s] = _extends({}, target[s], {}, value);
  211. } else {
  212. target[s] = value;
  213. }
  214. }
  215. }
  216. }
  217. return target;
  218. }
  219. /**
  220. * Rule for validating required fields.
  221. *
  222. * @param rule The validation rule.
  223. * @param value The value of the field on the source object.
  224. * @param source The source object being validated.
  225. * @param errors An array of errors that this rule may add
  226. * validation errors to.
  227. * @param options The validation options.
  228. * @param options.messages The validation messages.
  229. */
  230. function required(rule, value, source, errors, options, type) {
  231. if (rule.required && (!source.hasOwnProperty(rule.field) || isEmptyValue(value, type || rule.type))) {
  232. errors.push(format(options.messages.required, rule.fullField));
  233. }
  234. }
  235. /**
  236. * Rule for validating whitespace.
  237. *
  238. * @param rule The validation rule.
  239. * @param value The value of the field on the source object.
  240. * @param source The source object being validated.
  241. * @param errors An array of errors that this rule may add
  242. * validation errors to.
  243. * @param options The validation options.
  244. * @param options.messages The validation messages.
  245. */
  246. function whitespace(rule, value, source, errors, options) {
  247. if (/^\s+$/.test(value) || value === '') {
  248. errors.push(format(options.messages.whitespace, rule.fullField));
  249. }
  250. }
  251. /* eslint max-len:0 */
  252. var pattern = {
  253. // http://emailregex.com/
  254. email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
  255. url: new RegExp(
  256. "^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$",
  257. 'i'),
  258. hex: /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i
  259. };
  260. var types = {
  261. integer: function integer(value) {
  262. return types.number(value) && parseInt(value, 10) === value;
  263. },
  264. "float": function float(value) {
  265. return types.number(value) && !types.integer(value);
  266. },
  267. array: function array(value) {
  268. return Array.isArray(value);
  269. },
  270. regexp: function regexp(value) {
  271. if (value instanceof RegExp) {
  272. return true;
  273. }
  274. try {
  275. return !!new RegExp(value);
  276. } catch (e) {
  277. return false;
  278. }
  279. },
  280. date: function date(value) {
  281. return typeof value.getTime === 'function' && typeof value.getMonth === 'function' && typeof value.getYear ===
  282. 'function';
  283. },
  284. number: function number(value) {
  285. if (isNaN(value)) {
  286. return false;
  287. }
  288. // 修改源码,将字符串数值先转为数值
  289. return typeof +value === 'number';
  290. },
  291. object: function object(value) {
  292. return typeof value === 'object' && !types.array(value);
  293. },
  294. method: function method(value) {
  295. return typeof value === 'function';
  296. },
  297. email: function email(value) {
  298. return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255;
  299. },
  300. url: function url(value) {
  301. return typeof value === 'string' && !!value.match(pattern.url);
  302. },
  303. hex: function hex(value) {
  304. return typeof value === 'string' && !!value.match(pattern.hex);
  305. }
  306. };
  307. /**
  308. * Rule for validating the type of a value.
  309. *
  310. * @param rule The validation rule.
  311. * @param value The value of the field on the source object.
  312. * @param source The source object being validated.
  313. * @param errors An array of errors that this rule may add
  314. * validation errors to.
  315. * @param options The validation options.
  316. * @param options.messages The validation messages.
  317. */
  318. function type(rule, value, source, errors, options) {
  319. if (rule.required && value === undefined) {
  320. required(rule, value, source, errors, options);
  321. return;
  322. }
  323. var custom = ['integer', 'float', 'array', 'regexp', 'object', 'method', 'email', 'number', 'date', 'url', 'hex'];
  324. var ruleType = rule.type;
  325. if (custom.indexOf(ruleType) > -1) {
  326. if (!types[ruleType](value)) {
  327. errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type));
  328. } // straight typeof check
  329. } else if (ruleType && typeof value !== rule.type) {
  330. errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type));
  331. }
  332. }
  333. /**
  334. * Rule for validating minimum and maximum allowed values.
  335. *
  336. * @param rule The validation rule.
  337. * @param value The value of the field on the source object.
  338. * @param source The source object being validated.
  339. * @param errors An array of errors that this rule may add
  340. * validation errors to.
  341. * @param options The validation options.
  342. * @param options.messages The validation messages.
  343. */
  344. function range(rule, value, source, errors, options) {
  345. var len = typeof rule.len === 'number';
  346. var min = typeof rule.min === 'number';
  347. var max = typeof rule.max === 'number'; // 正则匹配码点范围从U+010000一直到U+10FFFF的文字(补充平面Supplementary Plane)
  348. var spRegexp = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
  349. var val = value;
  350. var key = null;
  351. var num = typeof value === 'number';
  352. var str = typeof value === 'string';
  353. var arr = Array.isArray(value);
  354. if (num) {
  355. key = 'number';
  356. } else if (str) {
  357. key = 'string';
  358. } else if (arr) {
  359. key = 'array';
  360. } // if the value is not of a supported type for range validation
  361. // the validation rule rule should use the
  362. // type property to also test for a particular type
  363. if (!key) {
  364. return false;
  365. }
  366. if (arr) {
  367. val = value.length;
  368. }
  369. if (str) {
  370. // 处理码点大于U+010000的文字length属性不准确的bug,如"𠮷𠮷𠮷".length !== 3
  371. val = value.replace(spRegexp, '_').length;
  372. }
  373. if (len) {
  374. if (val !== rule.len) {
  375. errors.push(format(options.messages[key].len, rule.fullField, rule.len));
  376. }
  377. } else if (min && !max && val < rule.min) {
  378. errors.push(format(options.messages[key].min, rule.fullField, rule.min));
  379. } else if (max && !min && val > rule.max) {
  380. errors.push(format(options.messages[key].max, rule.fullField, rule.max));
  381. } else if (min && max && (val < rule.min || val > rule.max)) {
  382. errors.push(format(options.messages[key].range, rule.fullField, rule.min, rule.max));
  383. }
  384. }
  385. var ENUM = 'enum';
  386. /**
  387. * Rule for validating a value exists in an enumerable list.
  388. *
  389. * @param rule The validation rule.
  390. * @param value The value of the field on the source object.
  391. * @param source The source object being validated.
  392. * @param errors An array of errors that this rule may add
  393. * validation errors to.
  394. * @param options The validation options.
  395. * @param options.messages The validation messages.
  396. */
  397. function enumerable(rule, value, source, errors, options) {
  398. rule[ENUM] = Array.isArray(rule[ENUM]) ? rule[ENUM] : [];
  399. if (rule[ENUM].indexOf(value) === -1) {
  400. errors.push(format(options.messages[ENUM], rule.fullField, rule[ENUM].join(', ')));
  401. }
  402. }
  403. /**
  404. * Rule for validating a regular expression pattern.
  405. *
  406. * @param rule The validation rule.
  407. * @param value The value of the field on the source object.
  408. * @param source The source object being validated.
  409. * @param errors An array of errors that this rule may add
  410. * validation errors to.
  411. * @param options The validation options.
  412. * @param options.messages The validation messages.
  413. */
  414. function pattern$1(rule, value, source, errors, options) {
  415. if (rule.pattern) {
  416. if (rule.pattern instanceof RegExp) {
  417. // if a RegExp instance is passed, reset `lastIndex` in case its `global`
  418. // flag is accidentally set to `true`, which in a validation scenario
  419. // is not necessary and the result might be misleading
  420. rule.pattern.lastIndex = 0;
  421. if (!rule.pattern.test(value)) {
  422. errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern));
  423. }
  424. } else if (typeof rule.pattern === 'string') {
  425. var _pattern = new RegExp(rule.pattern);
  426. if (!_pattern.test(value)) {
  427. errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern));
  428. }
  429. }
  430. }
  431. }
  432. var rules = {
  433. required: required,
  434. whitespace: whitespace,
  435. type: type,
  436. range: range,
  437. "enum": enumerable,
  438. pattern: pattern$1
  439. };
  440. /**
  441. * Performs validation for string types.
  442. *
  443. * @param rule The validation rule.
  444. * @param value The value of the field on the source object.
  445. * @param callback The callback function.
  446. * @param source The source object being validated.
  447. * @param options The validation options.
  448. * @param options.messages The validation messages.
  449. */
  450. function string(rule, value, callback, source, options) {
  451. var errors = [];
  452. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  453. if (validate) {
  454. if (isEmptyValue(value, 'string') && !rule.required) {
  455. return callback();
  456. }
  457. rules.required(rule, value, source, errors, options, 'string');
  458. if (!isEmptyValue(value, 'string')) {
  459. rules.type(rule, value, source, errors, options);
  460. rules.range(rule, value, source, errors, options);
  461. rules.pattern(rule, value, source, errors, options);
  462. if (rule.whitespace === true) {
  463. rules.whitespace(rule, value, source, errors, options);
  464. }
  465. }
  466. }
  467. callback(errors);
  468. }
  469. /**
  470. * Validates a function.
  471. *
  472. * @param rule The validation rule.
  473. * @param value The value of the field on the source object.
  474. * @param callback The callback function.
  475. * @param source The source object being validated.
  476. * @param options The validation options.
  477. * @param options.messages The validation messages.
  478. */
  479. function method(rule, value, callback, source, options) {
  480. var errors = [];
  481. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  482. if (validate) {
  483. if (isEmptyValue(value) && !rule.required) {
  484. return callback();
  485. }
  486. rules.required(rule, value, source, errors, options);
  487. if (value !== undefined) {
  488. rules.type(rule, value, source, errors, options);
  489. }
  490. }
  491. callback(errors);
  492. }
  493. /**
  494. * Validates a number.
  495. *
  496. * @param rule The validation rule.
  497. * @param value The value of the field on the source object.
  498. * @param callback The callback function.
  499. * @param source The source object being validated.
  500. * @param options The validation options.
  501. * @param options.messages The validation messages.
  502. */
  503. function number(rule, value, callback, source, options) {
  504. var errors = [];
  505. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  506. if (validate) {
  507. if (value === '') {
  508. value = undefined;
  509. }
  510. if (isEmptyValue(value) && !rule.required) {
  511. return callback();
  512. }
  513. rules.required(rule, value, source, errors, options);
  514. if (value !== undefined) {
  515. rules.type(rule, value, source, errors, options);
  516. rules.range(rule, value, source, errors, options);
  517. }
  518. }
  519. callback(errors);
  520. }
  521. /**
  522. * Validates a boolean.
  523. *
  524. * @param rule The validation rule.
  525. * @param value The value of the field on the source object.
  526. * @param callback The callback function.
  527. * @param source The source object being validated.
  528. * @param options The validation options.
  529. * @param options.messages The validation messages.
  530. */
  531. function _boolean(rule, value, callback, source, options) {
  532. var errors = [];
  533. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  534. if (validate) {
  535. if (isEmptyValue(value) && !rule.required) {
  536. return callback();
  537. }
  538. rules.required(rule, value, source, errors, options);
  539. if (value !== undefined) {
  540. rules.type(rule, value, source, errors, options);
  541. }
  542. }
  543. callback(errors);
  544. }
  545. /**
  546. * Validates the regular expression type.
  547. *
  548. * @param rule The validation rule.
  549. * @param value The value of the field on the source object.
  550. * @param callback The callback function.
  551. * @param source The source object being validated.
  552. * @param options The validation options.
  553. * @param options.messages The validation messages.
  554. */
  555. function regexp(rule, value, callback, source, options) {
  556. var errors = [];
  557. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  558. if (validate) {
  559. if (isEmptyValue(value) && !rule.required) {
  560. return callback();
  561. }
  562. rules.required(rule, value, source, errors, options);
  563. if (!isEmptyValue(value)) {
  564. rules.type(rule, value, source, errors, options);
  565. }
  566. }
  567. callback(errors);
  568. }
  569. /**
  570. * Validates a number is an integer.
  571. *
  572. * @param rule The validation rule.
  573. * @param value The value of the field on the source object.
  574. * @param callback The callback function.
  575. * @param source The source object being validated.
  576. * @param options The validation options.
  577. * @param options.messages The validation messages.
  578. */
  579. function integer(rule, value, callback, source, options) {
  580. var errors = [];
  581. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  582. if (validate) {
  583. if (isEmptyValue(value) && !rule.required) {
  584. return callback();
  585. }
  586. rules.required(rule, value, source, errors, options);
  587. if (value !== undefined) {
  588. rules.type(rule, value, source, errors, options);
  589. rules.range(rule, value, source, errors, options);
  590. }
  591. }
  592. callback(errors);
  593. }
  594. /**
  595. * Validates a number is a floating point number.
  596. *
  597. * @param rule The validation rule.
  598. * @param value The value of the field on the source object.
  599. * @param callback The callback function.
  600. * @param source The source object being validated.
  601. * @param options The validation options.
  602. * @param options.messages The validation messages.
  603. */
  604. function floatFn(rule, value, callback, source, options) {
  605. var errors = [];
  606. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  607. if (validate) {
  608. if (isEmptyValue(value) && !rule.required) {
  609. return callback();
  610. }
  611. rules.required(rule, value, source, errors, options);
  612. if (value !== undefined) {
  613. rules.type(rule, value, source, errors, options);
  614. rules.range(rule, value, source, errors, options);
  615. }
  616. }
  617. callback(errors);
  618. }
  619. /**
  620. * Validates an array.
  621. *
  622. * @param rule The validation rule.
  623. * @param value The value of the field on the source object.
  624. * @param callback The callback function.
  625. * @param source The source object being validated.
  626. * @param options The validation options.
  627. * @param options.messages The validation messages.
  628. */
  629. function array(rule, value, callback, source, options) {
  630. var errors = [];
  631. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  632. if (validate) {
  633. if (isEmptyValue(value, 'array') && !rule.required) {
  634. return callback();
  635. }
  636. rules.required(rule, value, source, errors, options, 'array');
  637. if (!isEmptyValue(value, 'array')) {
  638. rules.type(rule, value, source, errors, options);
  639. rules.range(rule, value, source, errors, options);
  640. }
  641. }
  642. callback(errors);
  643. }
  644. /**
  645. * Validates an object.
  646. *
  647. * @param rule The validation rule.
  648. * @param value The value of the field on the source object.
  649. * @param callback The callback function.
  650. * @param source The source object being validated.
  651. * @param options The validation options.
  652. * @param options.messages The validation messages.
  653. */
  654. function object(rule, value, callback, source, options) {
  655. var errors = [];
  656. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  657. if (validate) {
  658. if (isEmptyValue(value) && !rule.required) {
  659. return callback();
  660. }
  661. rules.required(rule, value, source, errors, options);
  662. if (value !== undefined) {
  663. rules.type(rule, value, source, errors, options);
  664. }
  665. }
  666. callback(errors);
  667. }
  668. var ENUM$1 = 'enum';
  669. /**
  670. * Validates an enumerable list.
  671. *
  672. * @param rule The validation rule.
  673. * @param value The value of the field on the source object.
  674. * @param callback The callback function.
  675. * @param source The source object being validated.
  676. * @param options The validation options.
  677. * @param options.messages The validation messages.
  678. */
  679. function enumerable$1(rule, value, callback, source, options) {
  680. var errors = [];
  681. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  682. if (validate) {
  683. if (isEmptyValue(value) && !rule.required) {
  684. return callback();
  685. }
  686. rules.required(rule, value, source, errors, options);
  687. if (value !== undefined) {
  688. rules[ENUM$1](rule, value, source, errors, options);
  689. }
  690. }
  691. callback(errors);
  692. }
  693. /**
  694. * Validates a regular expression pattern.
  695. *
  696. * Performs validation when a rule only contains
  697. * a pattern property but is not declared as a string type.
  698. *
  699. * @param rule The validation rule.
  700. * @param value The value of the field on the source object.
  701. * @param callback The callback function.
  702. * @param source The source object being validated.
  703. * @param options The validation options.
  704. * @param options.messages The validation messages.
  705. */
  706. function pattern$2(rule, value, callback, source, options) {
  707. var errors = [];
  708. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  709. if (validate) {
  710. if (isEmptyValue(value, 'string') && !rule.required) {
  711. return callback();
  712. }
  713. rules.required(rule, value, source, errors, options);
  714. if (!isEmptyValue(value, 'string')) {
  715. rules.pattern(rule, value, source, errors, options);
  716. }
  717. }
  718. callback(errors);
  719. }
  720. function date(rule, value, callback, source, options) {
  721. var errors = [];
  722. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  723. if (validate) {
  724. if (isEmptyValue(value) && !rule.required) {
  725. return callback();
  726. }
  727. rules.required(rule, value, source, errors, options);
  728. if (!isEmptyValue(value)) {
  729. var dateObject;
  730. if (typeof value === 'number') {
  731. dateObject = new Date(value);
  732. } else {
  733. dateObject = value;
  734. }
  735. rules.type(rule, dateObject, source, errors, options);
  736. if (dateObject) {
  737. rules.range(rule, dateObject.getTime(), source, errors, options);
  738. }
  739. }
  740. }
  741. callback(errors);
  742. }
  743. function required$1(rule, value, callback, source, options) {
  744. var errors = [];
  745. var type = Array.isArray(value) ? 'array' : typeof value;
  746. rules.required(rule, value, source, errors, options, type);
  747. callback(errors);
  748. }
  749. function type$1(rule, value, callback, source, options) {
  750. var ruleType = rule.type;
  751. var errors = [];
  752. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  753. if (validate) {
  754. if (isEmptyValue(value, ruleType) && !rule.required) {
  755. return callback();
  756. }
  757. rules.required(rule, value, source, errors, options, ruleType);
  758. if (!isEmptyValue(value, ruleType)) {
  759. rules.type(rule, value, source, errors, options);
  760. }
  761. }
  762. callback(errors);
  763. }
  764. /**
  765. * Performs validation for any type.
  766. *
  767. * @param rule The validation rule.
  768. * @param value The value of the field on the source object.
  769. * @param callback The callback function.
  770. * @param source The source object being validated.
  771. * @param options The validation options.
  772. * @param options.messages The validation messages.
  773. */
  774. function any(rule, value, callback, source, options) {
  775. var errors = [];
  776. var validate = rule.required || !rule.required && source.hasOwnProperty(rule.field);
  777. if (validate) {
  778. if (isEmptyValue(value) && !rule.required) {
  779. return callback();
  780. }
  781. rules.required(rule, value, source, errors, options);
  782. }
  783. callback(errors);
  784. }
  785. var validators = {
  786. string: string,
  787. method: method,
  788. number: number,
  789. "boolean": _boolean,
  790. regexp: regexp,
  791. integer: integer,
  792. "float": floatFn,
  793. array: array,
  794. object: object,
  795. "enum": enumerable$1,
  796. pattern: pattern$2,
  797. date: date,
  798. url: type$1,
  799. hex: type$1,
  800. email: type$1,
  801. required: required$1,
  802. any: any
  803. };
  804. function newMessages() {
  805. return {
  806. "default": 'Validation error on field %s',
  807. required: '%s is required',
  808. "enum": '%s must be one of %s',
  809. whitespace: '%s cannot be empty',
  810. date: {
  811. format: '%s date %s is invalid for format %s',
  812. parse: '%s date could not be parsed, %s is invalid ',
  813. invalid: '%s date %s is invalid'
  814. },
  815. types: {
  816. string: '%s is not a %s',
  817. method: '%s is not a %s (function)',
  818. array: '%s is not an %s',
  819. object: '%s is not an %s',
  820. number: '%s is not a %s',
  821. date: '%s is not a %s',
  822. "boolean": '%s is not a %s',
  823. integer: '%s is not an %s',
  824. "float": '%s is not a %s',
  825. regexp: '%s is not a valid %s',
  826. email: '%s is not a valid %s',
  827. url: '%s is not a valid %s',
  828. hex: '%s is not a valid %s'
  829. },
  830. string: {
  831. len: '%s must be exactly %s characters',
  832. min: '%s must be at least %s characters',
  833. max: '%s cannot be longer than %s characters',
  834. range: '%s must be between %s and %s characters'
  835. },
  836. number: {
  837. len: '%s must equal %s',
  838. min: '%s cannot be less than %s',
  839. max: '%s cannot be greater than %s',
  840. range: '%s must be between %s and %s'
  841. },
  842. array: {
  843. len: '%s must be exactly %s in length',
  844. min: '%s cannot be less than %s in length',
  845. max: '%s cannot be greater than %s in length',
  846. range: '%s must be between %s and %s in length'
  847. },
  848. pattern: {
  849. mismatch: '%s value %s does not match pattern %s'
  850. },
  851. clone: function clone() {
  852. var cloned = JSON.parse(JSON.stringify(this));
  853. cloned.clone = this.clone;
  854. return cloned;
  855. }
  856. };
  857. }
  858. var messages = newMessages();
  859. /**
  860. * Encapsulates a validation schema.
  861. *
  862. * @param descriptor An object declaring validation rules
  863. * for this schema.
  864. */
  865. function Schema(descriptor) {
  866. this.rules = null;
  867. this._messages = messages;
  868. this.define(descriptor);
  869. }
  870. Schema.prototype = {
  871. messages: function messages(_messages) {
  872. if (_messages) {
  873. this._messages = deepMerge(newMessages(), _messages);
  874. }
  875. return this._messages;
  876. },
  877. define: function define(rules) {
  878. if (!rules) {
  879. throw new Error('Cannot configure a schema with no rules');
  880. }
  881. if (typeof rules !== 'object' || Array.isArray(rules)) {
  882. throw new Error('Rules must be an object');
  883. }
  884. this.rules = {};
  885. var z;
  886. var item;
  887. for (z in rules) {
  888. if (rules.hasOwnProperty(z)) {
  889. item = rules[z];
  890. this.rules[z] = Array.isArray(item) ? item : [item];
  891. }
  892. }
  893. },
  894. validate: function validate(source_, o, oc) {
  895. var _this = this;
  896. if (o === void 0) {
  897. o = {};
  898. }
  899. if (oc === void 0) {
  900. oc = function oc() {};
  901. }
  902. var source = source_;
  903. var options = o;
  904. var callback = oc;
  905. if (typeof options === 'function') {
  906. callback = options;
  907. options = {};
  908. }
  909. if (!this.rules || Object.keys(this.rules).length === 0) {
  910. if (callback) {
  911. callback();
  912. }
  913. return Promise.resolve();
  914. }
  915. function complete(results) {
  916. var i;
  917. var errors = [];
  918. var fields = {};
  919. function add(e) {
  920. if (Array.isArray(e)) {
  921. var _errors;
  922. errors = (_errors = errors).concat.apply(_errors, e);
  923. } else {
  924. errors.push(e);
  925. }
  926. }
  927. for (i = 0; i < results.length; i++) {
  928. add(results[i]);
  929. }
  930. if (!errors.length) {
  931. errors = null;
  932. fields = null;
  933. } else {
  934. fields = convertFieldsError(errors);
  935. }
  936. callback(errors, fields);
  937. }
  938. if (options.messages) {
  939. var messages$1 = this.messages();
  940. if (messages$1 === messages) {
  941. messages$1 = newMessages();
  942. }
  943. deepMerge(messages$1, options.messages);
  944. options.messages = messages$1;
  945. } else {
  946. options.messages = this.messages();
  947. }
  948. var arr;
  949. var value;
  950. var series = {};
  951. var keys = options.keys || Object.keys(this.rules);
  952. keys.forEach(function(z) {
  953. arr = _this.rules[z];
  954. value = source[z];
  955. arr.forEach(function(r) {
  956. var rule = r;
  957. if (typeof rule.transform === 'function') {
  958. if (source === source_) {
  959. source = _extends({}, source);
  960. }
  961. value = source[z] = rule.transform(value);
  962. }
  963. if (typeof rule === 'function') {
  964. rule = {
  965. validator: rule
  966. };
  967. } else {
  968. rule = _extends({}, rule);
  969. }
  970. rule.validator = _this.getValidationMethod(rule);
  971. rule.field = z;
  972. rule.fullField = rule.fullField || z;
  973. rule.type = _this.getType(rule);
  974. if (!rule.validator) {
  975. return;
  976. }
  977. series[z] = series[z] || [];
  978. series[z].push({
  979. rule: rule,
  980. value: value,
  981. source: source,
  982. field: z
  983. });
  984. });
  985. });
  986. var errorFields = {};
  987. return asyncMap(series, options, function(data, doIt) {
  988. var rule = data.rule;
  989. var deep = (rule.type === 'object' || rule.type === 'array') && (typeof rule.fields === 'object' || typeof rule.defaultField ===
  990. 'object');
  991. deep = deep && (rule.required || !rule.required && data.value);
  992. rule.field = data.field;
  993. function addFullfield(key, schema) {
  994. return _extends({}, schema, {
  995. fullField: rule.fullField + "." + key
  996. });
  997. }
  998. function cb(e) {
  999. if (e === void 0) {
  1000. e = [];
  1001. }
  1002. var errors = e;
  1003. if (!Array.isArray(errors)) {
  1004. errors = [errors];
  1005. }
  1006. if (!options.suppressWarning && errors.length) {
  1007. Schema.warning('async-validator:', errors);
  1008. }
  1009. if (errors.length && rule.message) {
  1010. errors = [].concat(rule.message);
  1011. }
  1012. errors = errors.map(complementError(rule));
  1013. if (options.first && errors.length) {
  1014. errorFields[rule.field] = 1;
  1015. return doIt(errors);
  1016. }
  1017. if (!deep) {
  1018. doIt(errors);
  1019. } else {
  1020. // if rule is required but the target object
  1021. // does not exist fail at the rule level and don't
  1022. // go deeper
  1023. if (rule.required && !data.value) {
  1024. if (rule.message) {
  1025. errors = [].concat(rule.message).map(complementError(rule));
  1026. } else if (options.error) {
  1027. errors = [options.error(rule, format(options.messages.required, rule.field))];
  1028. } else {
  1029. errors = [];
  1030. }
  1031. return doIt(errors);
  1032. }
  1033. var fieldsSchema = {};
  1034. if (rule.defaultField) {
  1035. for (var k in data.value) {
  1036. if (data.value.hasOwnProperty(k)) {
  1037. fieldsSchema[k] = rule.defaultField;
  1038. }
  1039. }
  1040. }
  1041. fieldsSchema = _extends({}, fieldsSchema, {}, data.rule.fields);
  1042. for (var f in fieldsSchema) {
  1043. if (fieldsSchema.hasOwnProperty(f)) {
  1044. var fieldSchema = Array.isArray(fieldsSchema[f]) ? fieldsSchema[f] : [fieldsSchema[f]];
  1045. fieldsSchema[f] = fieldSchema.map(addFullfield.bind(null, f));
  1046. }
  1047. }
  1048. var schema = new Schema(fieldsSchema);
  1049. schema.messages(options.messages);
  1050. if (data.rule.options) {
  1051. data.rule.options.messages = options.messages;
  1052. data.rule.options.error = options.error;
  1053. }
  1054. schema.validate(data.value, data.rule.options || options, function(errs) {
  1055. var finalErrors = [];
  1056. if (errors && errors.length) {
  1057. finalErrors.push.apply(finalErrors, errors);
  1058. }
  1059. if (errs && errs.length) {
  1060. finalErrors.push.apply(finalErrors, errs);
  1061. }
  1062. doIt(finalErrors.length ? finalErrors : null);
  1063. });
  1064. }
  1065. }
  1066. var res;
  1067. if (rule.asyncValidator) {
  1068. res = rule.asyncValidator(rule, data.value, cb, data.source, options);
  1069. } else if (rule.validator) {
  1070. res = rule.validator(rule, data.value, cb, data.source, options);
  1071. if (res === true) {
  1072. cb();
  1073. } else if (res === false) {
  1074. cb(rule.message || rule.field + " fails");
  1075. } else if (res instanceof Array) {
  1076. cb(res);
  1077. } else if (res instanceof Error) {
  1078. cb(res.message);
  1079. }
  1080. }
  1081. if (res && res.then) {
  1082. res.then(function() {
  1083. return cb();
  1084. }, function(e) {
  1085. return cb(e);
  1086. });
  1087. }
  1088. }, function(results) {
  1089. complete(results);
  1090. });
  1091. },
  1092. getType: function getType(rule) {
  1093. if (rule.type === undefined && rule.pattern instanceof RegExp) {
  1094. rule.type = 'pattern';
  1095. }
  1096. if (typeof rule.validator !== 'function' && rule.type && !validators.hasOwnProperty(rule.type)) {
  1097. throw new Error(format('Unknown rule type %s', rule.type));
  1098. }
  1099. return rule.type || 'string';
  1100. },
  1101. getValidationMethod: function getValidationMethod(rule) {
  1102. if (typeof rule.validator === 'function') {
  1103. return rule.validator;
  1104. }
  1105. var keys = Object.keys(rule);
  1106. var messageIndex = keys.indexOf('message');
  1107. if (messageIndex !== -1) {
  1108. keys.splice(messageIndex, 1);
  1109. }
  1110. if (keys.length === 1 && keys[0] === 'required') {
  1111. return validators.required;
  1112. }
  1113. return validators[this.getType(rule)] || false;
  1114. }
  1115. };
  1116. Schema.register = function register(type, validator) {
  1117. if (typeof validator !== 'function') {
  1118. throw new Error('Cannot register a validator by type, validator is not a function');
  1119. }
  1120. validators[type] = validator;
  1121. };
  1122. Schema.warning = warning;
  1123. Schema.messages = messages;
  1124. export default Schema;
  1125. //# sourceMappingURL=index.js.map