We want to write a Monoid, which able to take function called 'run', therefore we able to run a serial of functions together to get a combined result.
Prototype:
/** * Take a `run` function, return a object which contain `run & concat` * methods. * * concat take other Monoid. we able to concat the reuslt inside concat function. * @param {run: function} */ const Fn = run => ({ run, concat(otherM) { return Fn(x => run(x).concat(otherM.run(x))); } });
Example:
const { List } = require("immutable-ext"); const Success = x => ({ x, isFail: false, concat(otherM) { return otherM.isFail ? otherM : Success(x); } }); const Fail = x => ({ x, isFail: true, concat(otherM) { return otherM.isFail ? Fail(x.concat(otherM.x)) : Fail(x); } }); const Validation = run => ({ run, concat(otherM) { return Validation((key, x) => run(key, x).concat(otherM.run(key, x))); } }); ///////////////// const isPresent = Validation((key, x) => !!x ? Success(x) : Fail([`${key} is required`]) ); const isEmail = Validation((key, x) => /@/.test(x) ? Success(x) : Fail([`${key} is not a valid email`]) ); const validate = (schema, obj) => List(Object.keys(schema)).foldMap( key => schema[key].run(key, obj[key]), Success(obj) ); //////////////////// const validationSchema = { name: isPresent, email: isPresent.concat(isEmail) }; const obj = { name: "Zhentian", email: "wan@wan.one" }; const res = validate(validationSchema, obj); console.log(res);
'Validtion' is the monid we create which enable to run a serial of validation functions such as 'isPresent' & 'isEmail'.
Output result is if 'Success': then return the object itself.
If 'Fail': Then return all the error message.