async-validator.js 33 KB

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