Skip to content

Commit 24f43b2

Browse files
authored
Merge pull request #4 from alibaba-fusion/develop
Release
2 parents bb880c5 + 072f75d commit 24f43b2

File tree

5 files changed

+561
-27
lines changed

5 files changed

+561
-27
lines changed

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"build": "ice-scripts build",
1414
"prepublishOnly": "npm run build",
1515
"test": "ice-scripts test",
16+
"test-watch": "ice-scripts test --jest-watchAll",
1617
"precommit": "lint-staged",
1718
"eslint": "eslint '@(src|test)/**/*.@(js|jsx)'"
1819
},
@@ -55,7 +56,8 @@
5556
"prettier": "^1.18.2",
5657
"react": "^16.3.0",
5758
"react-dom": "^16.3.0",
58-
"semantic-release": "^15.13.18"
59+
"semantic-release": "^15.13.18",
60+
"sinon": "^7.3.2"
5961
},
6062
"componentConfig": {
6163
"name": "validate",

src/index.js

+83-25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
/* eslint-disable callback-return */
2-
import { complementError, asyncMap } from './util';
3-
import { getValidationMethod } from './validator';
2+
import {
3+
complementError,
4+
asyncMap,
5+
asyncMapPromise,
6+
serializeRules,
7+
processErrorResults,
8+
} from './util';
49
import defaultMessages from './messages';
510

611
function noop() {}
@@ -32,37 +37,29 @@ class Schema {
3237
);
3338
}
3439

40+
/**
41+
*
42+
* @param {Object} source - map of field names and values to use in validation
43+
* @param {Function} callback - OPTIONAL - callback to run after all
44+
* @returns {null | Promise}
45+
* - { null } - if using callbacks
46+
* - { Promise }
47+
* - { null } - if no rules or no errors
48+
* - { errors: Array, fields: Object } - errors from validation and fields that have errors
49+
*/
3550
validate(source, callback) {
51+
if (!callback) {
52+
return this.validatePromise(source);
53+
}
54+
3655
if (!this._rules || Object.keys(this._rules).length === 0) {
3756
if (callback) {
3857
callback(null);
3958
}
4059
return;
4160
}
4261

43-
// serialize rules
44-
let arr;
45-
let value;
46-
const series = {};
47-
const names = Object.keys(this._rules);
48-
names.forEach(name => {
49-
arr = this._rules[name];
50-
value = source[name];
51-
52-
if (!Array.isArray(arr)) {
53-
arr = [arr];
54-
}
55-
56-
arr.forEach(rule => {
57-
rule.validator = getValidationMethod(rule);
58-
rule.field = name;
59-
if (!rule.validator) {
60-
return;
61-
}
62-
series[name] = series[name] || [];
63-
series[name].push({ rule, value, source, field: name });
64-
});
65-
});
62+
const series = serializeRules(source, this._rules);
6663

6764
if (Object.keys(series).length === 0) {
6865
callback(null);
@@ -136,6 +133,67 @@ class Schema {
136133
}
137134
);
138135
}
136+
137+
/**
138+
*
139+
* @param {Object} source - map of field names and values to use in validation
140+
* @returns {Promise}
141+
* - {null} if no rules or no errors
142+
* - { errors: Array, fields: Object } - errors from validation and fields that have errors
143+
*/
144+
async validatePromise(source) {
145+
if (!this._rules || Object.keys(this._rules).length === 0) {
146+
return Promise.resolve(null);
147+
}
148+
149+
const series = serializeRules(source, this._rules);
150+
151+
if (Object.keys(series).length === 0) {
152+
return Promise.resolve(null);
153+
}
154+
155+
const results = await asyncMapPromise(
156+
series,
157+
this._options,
158+
async data => {
159+
const rule = data.rule;
160+
rule.field = data.field;
161+
162+
let errors;
163+
164+
try {
165+
errors = await rule.validator(
166+
rule,
167+
data.value,
168+
this._options
169+
);
170+
} catch (error) {
171+
errors = error;
172+
}
173+
174+
if (errors) {
175+
if (!Array.isArray(errors)) {
176+
errors = [errors];
177+
}
178+
179+
// 自定义错误
180+
if (errors.length && rule.message) {
181+
errors = [].concat(rule.message);
182+
}
183+
184+
return errors.map(complementError(rule));
185+
} else {
186+
return [];
187+
}
188+
}
189+
);
190+
191+
if (!results) {
192+
return { errors: results };
193+
}
194+
195+
return processErrorResults(results);
196+
}
139197
}
140198

141199
export default Schema;

src/util.js

+101
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { getValidationMethod } from './validator';
2+
13
const formatRegExp = /%[sdj%]/g;
24

35
export function format(...args) {
@@ -103,6 +105,37 @@ export function asyncMap(objArr, option, func, callback) {
103105
});
104106
}
105107

108+
async function resolveErrorPromiseInSeries(arr, func) {
109+
return arr.reduce(async (prevPromise, next) => {
110+
let errors;
111+
try {
112+
errors = await prevPromise;
113+
} catch (e) {
114+
errors = e;
115+
}
116+
117+
if (errors && errors.length) {
118+
return errors;
119+
}
120+
121+
return func(next);
122+
}, Promise.resolve());
123+
}
124+
125+
export async function asyncMapPromise(objArr, option, func) {
126+
if (option.first) {
127+
const flatObjArr = flattenObjArr(objArr);
128+
129+
return resolveErrorPromiseInSeries(flatObjArr, func);
130+
}
131+
132+
const objArrValues = Object.values(objArr);
133+
134+
return Promise.all(
135+
objArrValues.map(val => resolveErrorPromiseInSeries(val, func))
136+
);
137+
}
138+
106139
export function complementError(rule) {
107140
return oe => {
108141
if (oe && oe.message) {
@@ -115,3 +148,71 @@ export function complementError(rule) {
115148
};
116149
};
117150
}
151+
152+
export function serializeRules(source, rules) {
153+
// serialize rules
154+
let arr;
155+
let value;
156+
const series = {};
157+
const names = Object.keys(rules);
158+
names.forEach(name => {
159+
arr = rules[name];
160+
value = source[name];
161+
162+
if (!Array.isArray(arr)) {
163+
arr = [arr];
164+
}
165+
166+
arr.forEach(rule => {
167+
rule.validator = getValidationMethod(rule);
168+
rule.field = name;
169+
if (!rule.validator) {
170+
return;
171+
}
172+
series[name] = series[name] || [];
173+
series[name].push({ rule, value, source, field: name });
174+
});
175+
});
176+
177+
return series;
178+
}
179+
180+
/**
181+
*
182+
* @param {Array} results errors from running validation
183+
* @returns {Object} { errors: Array, fields: Object }
184+
*/
185+
export function processErrorResults(results) {
186+
let errors = [];
187+
let fields = {};
188+
189+
function add(e) {
190+
if (Array.isArray(e)) {
191+
errors = errors.concat(e);
192+
} else {
193+
errors.push(e);
194+
}
195+
}
196+
197+
for (let i = 0; i < results.length; i++) {
198+
add(results[i]);
199+
}
200+
201+
if (!errors.length) {
202+
errors = null;
203+
fields = null;
204+
} else {
205+
for (let i = 0; i < errors.length; i++) {
206+
const field = errors[i].field;
207+
if (field) {
208+
fields[field] = fields[field] || [];
209+
fields[field].push(errors[i]);
210+
}
211+
}
212+
}
213+
214+
return {
215+
errors,
216+
fields,
217+
};
218+
}

0 commit comments

Comments
 (0)