validateUtil.js 12 KB

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