validateUtil.js 11 KB

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