You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

async-validator.js 33KB

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