@quenk/preconditions
Version:
Make data satisfy constraints before using.
133 lines • 4.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.reduce = exports.tuple = exports.map = exports.filter = exports.range = exports.minItems = exports.maxItems = exports.nonEmpty = exports.toArray = exports.isArray = void 0;
const lazy = require("@quenk/noni/lib/data/lazy");
const type_1 = require("@quenk/noni/lib/data/type");
const either_1 = require("@quenk/noni/lib/data/either");
const array_1 = require("./result/failure/array");
const result_1 = require("./result");
/**
* isArray tests if the value is an array
*/
const isArray = (a) => Array.isArray(a) ? (0, result_1.succeed)(a) : (0, result_1.fail)('isArray', a);
exports.isArray = isArray;
/**
* toArray converts a value into an array.
*
* If the value is an empty string or nullish, an empty array is produced.
*/
const toArray = (value) => {
if (Array.isArray(value))
return (0, result_1.succeed)(value);
if (((0, type_1.isString)(value) && value === '') || (0, type_1.isNull)(value))
return (0, result_1.succeed)([]);
else
return (0, result_1.succeed)([value]);
};
exports.toArray = toArray;
/**
* notEmpty tests if an array has at least one member.
*/
const nonEmpty = (value) => value.length === 0
? (0, result_1.fail)('nonEmpty', value, { value })
: (0, result_1.succeed)(value);
exports.nonEmpty = nonEmpty;
/**
* maxItems sets a maximum number of elements the array can contain.
*/
const maxItems = (target) => (value) => value.length > target
? (0, result_1.fail)('maxItems', value, { target, value })
: (0, result_1.succeed)(value);
exports.maxItems = maxItems;
/**
* minItems sets a minimum number of elements the array can contain.
*/
const minItems = (target) => (value) => value.length < target
? (0, result_1.fail)('minItems', value, { target, value })
: (0, result_1.succeed)(value);
exports.minItems = minItems;
/**
* range tests whether an array's length falls within a specific min and max range.
*/
const range = (min, max) => (value) => value.length < min
? (0, result_1.fail)('range.min', value, { min, max, value })
: value.length > max
? (0, result_1.fail)('range.max', value)
: (0, result_1.succeed)(value);
exports.range = range;
/**
* filter applies a precondition to each member of an array producing
* an array where only the successful members are kept.
*/
const filter = (p) => (value) => (0, result_1.succeed)(value
.map(p)
.filter(e => e instanceof either_1.Right)
.map(e => e.takeRight()));
exports.filter = filter;
/**
* map applies a precondition to each member of an array.
*
* If the precondition fails for any of the members,
* the entire array is considered a failure.
*/
const map = (p) => (value) => {
let failed = 0;
let failures = {};
let values = [];
for (let i = 0; i < value.length; i++) {
let result = p(value[i]);
if (result.isLeft()) {
failed++;
failures[i] = result.takeLeft();
}
else {
values[i] = result.takeRight();
}
}
return failed === 0
? (0, result_1.succeed)(values)
: (0, either_1.left)(array_1.ArrayFailure.create(failures, value, { value }));
};
exports.map = map;
/**
* tuple tests whether the value supplied qualifies as a tuple.
*
* Each precondition in the list represents a precondition for its
* corresponding tuple element.
*/
const tuple = (list) => (value) => {
if (value.length !== list.length)
return (0, result_1.fail)('tuple', value);
let results = value.map((v, idx) => list[idx](v));
let fails = results.filter(v => v.isLeft()).map(e => e.takeLeft());
if (fails.length > 0) {
let failMap = fails.reduce((p, c, k) => {
p[k] = c;
return p;
}, {});
return (0, either_1.left)(array_1.ArrayFailure.create(failMap, value, { value }));
}
return (0, result_1.succeed)(results.map(e => e.takeRight()));
};
exports.tuple = tuple;
/**
* reduce a list of values into an accumalated value initially specified by the
* parameter "accum".
*
* Be careful not to mutate the accumulated value directly to avoid subtle bugs.
* Instead copy the value to be accumualted in each call to the reducer.
*/
const reduce = (getAccum, func) => (value) => {
let accum = lazy.evaluate(getAccum);
for (let i = 0; i < value.length; i++) {
let eresult = func(accum)(value[i]);
if (eresult.isLeft()) {
let err = eresult.takeLeft();
return (0, either_1.left)(array_1.ArrayFailure.create({ [i]: err }, value, {}));
}
accum = eresult.takeRight();
}
return (0, result_1.succeed)(accum);
};
exports.reduce = reduce;
//# sourceMappingURL=array.js.map