validateUtil.js 11 KB

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