index.js 35 KB

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