validateUtil.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
  2. import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
  3. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  4. import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
  5. import _regeneratorRuntime from "@babel/runtime/regenerator";
  6. import RawAsyncValidator from 'async-validator';
  7. import { cloneVNode } from 'vue';
  8. import { warning } from '../../vc-util/warning';
  9. import { setValues } from './valueUtil';
  10. import { defaultValidateMessages } from './messages';
  11. import { isValidElement } from '../../_util/props-util';
  12. // Remove incorrect original ts define
  13. var AsyncValidator = RawAsyncValidator;
  14. /**
  15. * Replace with template.
  16. * `I'm ${name}` + { name: 'bamboo' } = I'm bamboo
  17. */
  18. function replaceMessage(template, kv) {
  19. return template.replace(/\$\{\w+\}/g, function (str) {
  20. var key = str.slice(2, -1);
  21. return kv[key];
  22. });
  23. }
  24. function validateRule(_x, _x2, _x3, _x4, _x5) {
  25. return _validateRule.apply(this, arguments);
  26. }
  27. /**
  28. * We use `async-validator` to validate the value.
  29. * But only check one value in a time to avoid namePath validate issue.
  30. */
  31. function _validateRule() {
  32. _validateRule = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(name, value, rule, options, messageVariables) {
  33. var cloneRule, subRuleField, validator, messages, result, subResults, kv, fillVariableResult;
  34. return _regeneratorRuntime.wrap(function _callee2$(_context2) {
  35. while (1) switch (_context2.prev = _context2.next) {
  36. case 0:
  37. cloneRule = _objectSpread({}, rule); // Bug of `async-validator`
  38. delete cloneRule.ruleIndex;
  39. delete cloneRule.trigger;
  40. // We should special handle array validate
  41. subRuleField = null;
  42. if (cloneRule && cloneRule.type === 'array' && cloneRule.defaultField) {
  43. subRuleField = cloneRule.defaultField;
  44. delete cloneRule.defaultField;
  45. }
  46. validator = new AsyncValidator(_defineProperty({}, name, [cloneRule]));
  47. messages = setValues({}, defaultValidateMessages, options.validateMessages);
  48. validator.messages(messages);
  49. result = [];
  50. _context2.prev = 9;
  51. _context2.next = 12;
  52. return Promise.resolve(validator.validate(_defineProperty({}, name, value), _objectSpread({}, options)));
  53. case 12:
  54. _context2.next = 17;
  55. break;
  56. case 14:
  57. _context2.prev = 14;
  58. _context2.t0 = _context2["catch"](9);
  59. if (_context2.t0.errors) {
  60. result = _context2.t0.errors.map(function (_ref4, index) {
  61. var message = _ref4.message;
  62. return (
  63. // Wrap VueNode with `key`
  64. isValidElement(message) ? cloneVNode(message, {
  65. key: "error_".concat(index)
  66. }) : message
  67. );
  68. });
  69. } else {
  70. console.error(_context2.t0);
  71. result = [messages.default()];
  72. }
  73. case 17:
  74. if (!(!result.length && subRuleField)) {
  75. _context2.next = 22;
  76. break;
  77. }
  78. _context2.next = 20;
  79. return Promise.all(value.map(function (subValue, i) {
  80. return validateRule("".concat(name, ".").concat(i), subValue, subRuleField, options, messageVariables);
  81. }));
  82. case 20:
  83. subResults = _context2.sent;
  84. return _context2.abrupt("return", subResults.reduce(function (prev, errors) {
  85. return [].concat(_toConsumableArray(prev), _toConsumableArray(errors));
  86. }, []));
  87. case 22:
  88. // Replace message with variables
  89. kv = _objectSpread(_objectSpread({}, rule), {}, {
  90. name: name,
  91. enum: (rule.enum || []).join(', ')
  92. }, messageVariables);
  93. fillVariableResult = result.map(function (error) {
  94. if (typeof error === 'string') {
  95. return replaceMessage(error, kv);
  96. }
  97. return error;
  98. });
  99. return _context2.abrupt("return", fillVariableResult);
  100. case 25:
  101. case "end":
  102. return _context2.stop();
  103. }
  104. }, _callee2, null, [[9, 14]]);
  105. }));
  106. return _validateRule.apply(this, arguments);
  107. }
  108. export function validateRules(namePath, value, rules, options, validateFirst, messageVariables) {
  109. var name = namePath.join('.');
  110. // Fill rule with context
  111. var filledRules = rules.map(function (currentRule, ruleIndex) {
  112. var originValidatorFunc = currentRule.validator;
  113. var cloneRule = _objectSpread(_objectSpread({}, currentRule), {}, {
  114. ruleIndex: ruleIndex
  115. });
  116. // Replace validator if needed
  117. if (originValidatorFunc) {
  118. cloneRule.validator = function (rule, val, callback) {
  119. var hasPromise = false;
  120. // Wrap callback only accept when promise not provided
  121. var wrappedCallback = function wrappedCallback() {
  122. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  123. args[_key] = arguments[_key];
  124. }
  125. // Wait a tick to make sure return type is a promise
  126. Promise.resolve().then(function () {
  127. warning(!hasPromise, 'Your validator function has already return a promise. `callback` will be ignored.');
  128. if (!hasPromise) {
  129. callback.apply(void 0, args);
  130. }
  131. });
  132. };
  133. // Get promise
  134. var promise = originValidatorFunc(rule, val, wrappedCallback);
  135. hasPromise = promise && typeof promise.then === 'function' && typeof promise.catch === 'function';
  136. /**
  137. * 1. Use promise as the first priority.
  138. * 2. If promise not exist, use callback with warning instead
  139. */
  140. warning(hasPromise, '`callback` is deprecated. Please return a promise instead.');
  141. if (hasPromise) {
  142. promise.then(function () {
  143. callback();
  144. }).catch(function (err) {
  145. callback(err || ' ');
  146. });
  147. }
  148. };
  149. }
  150. return cloneRule;
  151. }).sort(function (_ref, _ref2) {
  152. var w1 = _ref.warningOnly,
  153. i1 = _ref.ruleIndex;
  154. var w2 = _ref2.warningOnly,
  155. i2 = _ref2.ruleIndex;
  156. if (!!w1 === !!w2) {
  157. // Let keep origin order
  158. return i1 - i2;
  159. }
  160. if (w1) {
  161. return 1;
  162. }
  163. return -1;
  164. });
  165. // Do validate rules
  166. var summaryPromise;
  167. if (validateFirst === true) {
  168. // >>>>> Validate by serialization
  169. summaryPromise = new Promise( /*#__PURE__*/function () {
  170. var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(resolve, reject) {
  171. var i, rule, errors;
  172. return _regeneratorRuntime.wrap(function _callee$(_context) {
  173. while (1) switch (_context.prev = _context.next) {
  174. case 0:
  175. i = 0;
  176. case 1:
  177. if (!(i < filledRules.length)) {
  178. _context.next = 12;
  179. break;
  180. }
  181. rule = filledRules[i];
  182. _context.next = 5;
  183. return validateRule(name, value, rule, options, messageVariables);
  184. case 5:
  185. errors = _context.sent;
  186. if (!errors.length) {
  187. _context.next = 9;
  188. break;
  189. }
  190. reject([{
  191. errors: errors,
  192. rule: rule
  193. }]);
  194. return _context.abrupt("return");
  195. case 9:
  196. i += 1;
  197. _context.next = 1;
  198. break;
  199. case 12:
  200. /* eslint-enable */
  201. resolve([]);
  202. case 13:
  203. case "end":
  204. return _context.stop();
  205. }
  206. }, _callee);
  207. }));
  208. return function (_x6, _x7) {
  209. return _ref3.apply(this, arguments);
  210. };
  211. }());
  212. } else {
  213. // >>>>> Validate by parallel
  214. var rulePromises = filledRules.map(function (rule) {
  215. return validateRule(name, value, rule, options, messageVariables).then(function (errors) {
  216. return {
  217. errors: errors,
  218. rule: rule
  219. };
  220. });
  221. });
  222. summaryPromise = (validateFirst ? finishOnFirstFailed(rulePromises) : finishOnAllFailed(rulePromises)).then(function (errors) {
  223. // Always change to rejection for Field to catch
  224. return Promise.reject(errors);
  225. });
  226. }
  227. // Internal catch error to avoid console error log.
  228. summaryPromise.catch(function (e) {
  229. return e;
  230. });
  231. return summaryPromise;
  232. }
  233. function finishOnAllFailed(_x8) {
  234. return _finishOnAllFailed.apply(this, arguments);
  235. }
  236. function _finishOnAllFailed() {
  237. _finishOnAllFailed = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(rulePromises) {
  238. return _regeneratorRuntime.wrap(function _callee3$(_context3) {
  239. while (1) switch (_context3.prev = _context3.next) {
  240. case 0:
  241. return _context3.abrupt("return", Promise.all(rulePromises).then(function (errorsList) {
  242. var _ref5;
  243. var errors = (_ref5 = []).concat.apply(_ref5, _toConsumableArray(errorsList));
  244. return errors;
  245. }));
  246. case 1:
  247. case "end":
  248. return _context3.stop();
  249. }
  250. }, _callee3);
  251. }));
  252. return _finishOnAllFailed.apply(this, arguments);
  253. }
  254. function finishOnFirstFailed(_x9) {
  255. return _finishOnFirstFailed.apply(this, arguments);
  256. }
  257. function _finishOnFirstFailed() {
  258. _finishOnFirstFailed = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(rulePromises) {
  259. var count;
  260. return _regeneratorRuntime.wrap(function _callee4$(_context4) {
  261. while (1) switch (_context4.prev = _context4.next) {
  262. case 0:
  263. count = 0;
  264. return _context4.abrupt("return", new Promise(function (resolve) {
  265. rulePromises.forEach(function (promise) {
  266. promise.then(function (ruleError) {
  267. if (ruleError.errors.length) {
  268. resolve([ruleError]);
  269. }
  270. count += 1;
  271. if (count === rulePromises.length) {
  272. resolve([]);
  273. }
  274. });
  275. });
  276. }));
  277. case 2:
  278. case "end":
  279. return _context4.stop();
  280. }
  281. }, _callee4);
  282. }));
  283. return _finishOnFirstFailed.apply(this, arguments);
  284. }