@typed/fp
Version:
Data Structures and Resources for fp-ts
609 lines • 19.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ap = exports.Chain = exports.chain = exports.fromIO = exports.tupled = exports.flap = exports.bindTo = exports.Functor = exports.Pointed = exports.strict = exports.condemmMissingKeys = exports.condemnUnexpectedKeys = exports.absolve = exports.absolveWhen = exports.condemn = exports.condemnWhen = exports.map = exports.of = exports.URI = exports.lazy = exports.intersect = exports.tuple = exports.unexpectedIndexes = exports.missingIndexes = exports.fromTuple = exports.record = exports.fromRecord = exports.struct = exports.unexpectedKeys = exports.missingKeys = exports.fromStruct = exports.array = exports.fromArray = exports.unknownRecord = exports.unknownArray = exports.optional = exports.nullable = exports.literal = exports.sum = exports.date = exports.isDate = exports.union = exports.refine = exports.WithRefine = exports.dateFromISOString = exports.boolean = exports.number = exports.string = exports.compose = exports.fromRefinement = void 0;
exports.assertStrict = exports.assert = exports.jsonParse = exports.jsonParseFromString = exports.WithUnion = exports.Schemable = exports.Monad = exports.Do = exports.getApplicativeMonoid = exports.Applicative = exports.getApplySemigroup = exports.apT = exports.apSecond = exports.apS = exports.apFirst = exports.Apply = exports.bind = exports.chainFirst = void 0;
const tslib_1 = require("tslib");
/**
* Decoder is a data structure for representing runtime representations of your types.
* @since 0.9.4
*/
const date_fns_1 = require("date-fns");
const App = (0, tslib_1.__importStar)(require("fp-ts/Applicative"));
const Ap = (0, tslib_1.__importStar)(require("fp-ts/Apply"));
const Ch = (0, tslib_1.__importStar)(require("fp-ts/Chain"));
const Ei = (0, tslib_1.__importStar)(require("fp-ts/Either"));
const F = (0, tslib_1.__importStar)(require("fp-ts/Functor"));
const N = (0, tslib_1.__importStar)(require("fp-ts/number"));
const Predicate_1 = require("fp-ts/Predicate");
const RA = (0, tslib_1.__importStar)(require("fp-ts/ReadonlyArray"));
const ReadonlyNonEmptyArray_1 = require("fp-ts/ReadonlyNonEmptyArray");
const S = (0, tslib_1.__importStar)(require("fp-ts/string"));
const DE = (0, tslib_1.__importStar)(require("./DecodeError"));
const DecodeError_1 = require("./DecodeError");
const function_1 = require("./function");
const internal_1 = require("./internal");
const St = (0, tslib_1.__importStar)(require("./struct"));
const struct_1 = require("./struct");
const T = (0, tslib_1.__importStar)(require("./These"));
/**
* @category Constructor
* @since 0.9.4
*/
function fromRefinement(refinement, expected) {
return {
decode: (i) => (refinement(i) ? T.right(i) : T.left([DE.leaf(i, expected)])),
};
}
exports.fromRefinement = fromRefinement;
/**
* @category Combinator
* @since 0.9.4
*/
const compose = (second) => (first) => {
const { chain } = T.getChain(DE.getSemigroup());
return {
decode: (i) => (0, function_1.pipe)(i, first.decode, chain(second.decode)),
};
};
exports.compose = compose;
/**
* @category Constructor
* @since 0.9.4
*/
exports.string = fromRefinement((x) => typeof x === 'string', 'string');
/**
* @category Constructor
* @since 0.9.4
*/
exports.number = fromRefinement((x) => typeof x === 'number', 'number');
/**
* @category Constructor
* @since 0.9.4
*/
exports.boolean = fromRefinement((x) => typeof x === 'boolean', 'boolean');
/**
* @category Decoder
* @since 0.9.5
*/
exports.dateFromISOString = {
decode: (i) => {
const date = (0, date_fns_1.parseISO)(i);
const time = date.getTime();
if (Number.isNaN(time)) {
return T.left([(0, DecodeError_1.leaf)(i, `dateFromISOString`)]);
}
return T.right(date);
},
};
/**
* @category Instance
* @since 0.9.5
*/
exports.WithRefine = {
refine: (refinment, id) => (from) => (0, function_1.pipe)(from, (0, exports.compose)(fromRefinement(refinment, id))),
};
/**
* @category Combinator
* @since 0.9.5
*/
exports.refine = exports.WithRefine.refine;
/**
* @category Constructor
* @since 0.9.4
*/
const union = (second) => (first) => {
const { concat } = DE.getSemigroup();
return {
decode: (i) => (0, function_1.pipe)(i, first.decode, T.mapLeft((errors) => [DE.member(0, errors)]), T.matchW((e1) => (0, function_1.pipe)(i, second.decode, T.mapLeft((errors) => [DE.member(1, errors)]), T.matchW((e2) => (0, function_1.pipe)(e1, concat(e2), T.left), T.right, (e2, a) => T.both((0, function_1.pipe)(e1, concat(e2)), a))), T.right, (e1, o1) => (0, function_1.pipe)(i, second.decode, T.mapLeft((errors) => [DE.member(1, errors)]), T.matchW((e2) => T.both((0, function_1.pipe)(e1, concat(e2)), o1), T.right, (e2) => T.both((0, function_1.pipe)(e1, concat(e2)), o1))))),
};
};
exports.union = union;
/**
* @category Refinement
* @since 0.9.6
*/
const isDate = (x) => x instanceof Date;
exports.isDate = isDate;
/**
* @category Constructor
* @since 0.9.6
*/
exports.date = (0, function_1.pipe)(exports.string, (0, exports.refine)(exports.isDate, 'Date'), (0, exports.union)(fromRefinement(exports.isDate, 'Date')));
/**
* @category Constructor
* @since 0.9.6
*/
const sum = (tag) => (members) => {
return {
decode: (i) => (0, function_1.pipe)(i, struct(St.make(tag, (0, exports.literal)(...Object.keys(members)))).decode, T.matchW(T.left, (a) => members[a[tag]].decode(a), ([first, ...rest], a) => (0, function_1.pipe)(members[a[tag]].decode(a), T.mapLeft((e) => [first, ...rest, ...e])))),
};
};
exports.sum = sum;
/**
* @category Constructor
* @since 0.9.6
*/
const literal = (...literals) => fromRefinement((x) => literals.includes(x), literals.join(' | '));
exports.literal = literal;
/**
* @category Combinator
* @since 0.9.4
*/
exports.nullable = (0, exports.union)(fromRefinement((x) => x === null, 'null'));
/**
* @category Combinator
* @since 0.9.4
*/
exports.optional = (0, exports.union)(fromRefinement((x) => x === undefined, 'undefined'));
/**
* @category Constructor
* @since 0.9.4
*/
exports.unknownArray = fromRefinement(Array.isArray, 'Array<unknown>');
/**
* @category Constructor
* @since 0.9.4
*/
exports.unknownRecord = fromRefinement((x) => !!x && !Array.isArray(x) && typeof x === 'object', 'Record<string, unknown>');
/**
* @category Constructor
* @since 0.9.4
*/
const fromArray = (member) => {
const { concat } = T.getSemigroup(DE.getSemigroup(), RA.getSemigroup());
return {
decode: (inputs) => {
const array = inputs.map((input, index) => (0, function_1.pipe)(input, member.decode, T.mapLeft((e) => [DE.index(index, e)]), T.map((o) => [o])));
return array.reduce((acc, x) => (0, function_1.pipe)(x, concat(acc)), T.right([]));
},
};
};
exports.fromArray = fromArray;
/**
* @category Constructor
* @since 0.9.4
*/
const array = (member) => (0, function_1.pipe)(exports.unknownArray, (0, exports.compose)((0, exports.fromArray)(member)));
exports.array = array;
/**
* @category Constructor
* @since 0.9.4
*/
const fromStruct = (properties) => {
const { concat } = T.getSemigroup(DE.getSemigroup(), St.getAssignSemigroup());
return {
decode: (i) => {
const expectedKeys = Object.keys(properties);
const remainingKeys = expectedKeys.filter((k) => k in i);
const struct = remainingKeys.map((k) => (0, function_1.pipe)(properties[k].decode(i[k]), T.mapLeft((e) => [DE.key(k, e)]), T.map((o) => (0, struct_1.make)(k, o))));
const result = struct.reduce((acc, x) => (0, function_1.pipe)(x, concat(acc)), T.right({}));
return result;
},
};
};
exports.fromStruct = fromStruct;
/**
* @category Constructor
* @since 0.9.4
*/
function missingKeys(properties) {
const diff = RA.difference(S.Eq);
return {
decode: (i) => {
const expectedKeys = Object.keys(properties);
const actualKeys = Object.keys(i);
const missingKeys = (0, function_1.pipe)(expectedKeys, diff(actualKeys));
const result = RA.isNonEmpty(missingKeys)
? T.both([DE.missingKeys([missingKeys[0], ...missingKeys.slice(1)])], i)
: T.right(i);
return result;
},
};
}
exports.missingKeys = missingKeys;
/**
* @category Constructor
* @since 0.9.4
*/
function unexpectedKeys(properties) {
const diff = RA.difference(S.Eq);
return {
decode: (i) => {
const expectedKeys = Object.keys(properties);
const actualKeys = Object.keys(i);
const unexpectedKeys = (0, function_1.pipe)(actualKeys, diff(expectedKeys));
const result = RA.isNonEmpty(unexpectedKeys)
? T.both([DE.unexpectedKeys([unexpectedKeys[0], ...unexpectedKeys.slice(1)])], i)
: T.right(i);
return result;
},
};
}
exports.unexpectedKeys = unexpectedKeys;
/**
* @category Constructor
* @since 0.9.4
*/
function struct(properties) {
return (0, function_1.pipe)(exports.unknownRecord, (0, exports.compose)(missingKeys(properties)), (0, exports.compose)(unexpectedKeys(properties)), (0, exports.compose)((0, exports.fromStruct)(properties)));
}
exports.struct = struct;
/**
* @category Constructor
* @since 0.9.4
*/
function fromRecord(decoder) {
const { concat } = T.getSemigroup(DE.getSemigroup(), St.getAssignSemigroup());
return {
decode: (i) => {
const results = Object.entries(i).map(([key, value]) => (0, function_1.pipe)(value, decoder.decode, T.mapLeft((errors) => [DE.key(key, errors)]), T.map((b) => ({ [key]: b }))));
return results.reduce((acc, x) => (0, function_1.pipe)(x, concat(acc)), T.of(Object.create(null)));
},
};
}
exports.fromRecord = fromRecord;
/**
* @category Constructor
* @since 0.9.6
*/
const record = (codomain) => (0, function_1.pipe)(exports.unknownRecord, (0, exports.compose)(fromRecord(codomain)));
exports.record = record;
/**
* @category Constructor
* @since 0.9.4
*/
function fromTuple(...components) {
const { concat } = T.getSemigroup(DE.getSemigroup(), RA.getSemigroup());
return {
decode: (input) => {
const tuple = components.map((d, i) => (0, function_1.pipe)(d.decode(input[i]), T.mapLeft((errors) => [DE.index(i, errors)]), T.map((o) => [o])));
const result = tuple.reduce((acc, x) => (0, function_1.pipe)(x, concat(acc)), T.right([]));
return result;
},
};
}
exports.fromTuple = fromTuple;
/**
* @category Constructor
* @since 0.9.4
*/
function missingIndexes(...components) {
const diff = RA.difference(N.Eq);
return {
decode: (i) => {
const expectedKeys = Object.keys(components).map(parseFloat);
const actualKeys = Object.keys(i).map(parseFloat);
const missingKeys = (0, function_1.pipe)(expectedKeys, diff(actualKeys));
const result = RA.isNonEmpty(missingKeys)
? T.both([DE.missingIndexes([missingKeys[0], ...missingKeys.slice(1)])], i)
: T.right(i);
return result;
},
};
}
exports.missingIndexes = missingIndexes;
/**
* @category Constructor
* @since 0.9.4
*/
function unexpectedIndexes(...components) {
const diff = RA.difference(S.Eq);
return {
decode: (i) => {
const expectedKeys = Object.keys(components);
const actualKeys = Object.keys(i);
const unexpectedKeys = (0, function_1.pipe)(actualKeys, diff(expectedKeys));
const result = RA.isNonEmpty(unexpectedKeys)
? T.both([DE.unexpectedKeys([unexpectedKeys[0], ...unexpectedKeys.slice(1)])], i)
: T.right(i);
return result;
},
};
}
exports.unexpectedIndexes = unexpectedIndexes;
/**
* @category Constructor
* @since 0.9.4
*/
function tuple(...components) {
return (0, function_1.pipe)(exports.unknownArray, (0, exports.compose)(missingIndexes(...components)), (0, exports.compose)(unexpectedIndexes(...components)), (0, exports.compose)(fromTuple(...components)));
}
exports.tuple = tuple;
/**
* @category Combinator
* @since 0.9.6
*/
const intersect = (second) => (first) => {
const { concat } = T.getSemigroup(DE.getSemigroup(), St.getAssignSemigroup());
return {
decode: (i) => concat(second.decode(i))(first.decode(i)),
};
};
exports.intersect = intersect;
/**
* @category Constructor
* @since 0.9.6
*/
const lazy = (id, f) => {
const get = (0, internal_1.memoize)((_) => f());
return {
decode: (i) => (0, function_1.pipe)(get().decode(i), T.mapLeft((errors) => [DE.lazy(id, errors)])),
};
};
exports.lazy = lazy;
/**
* @category URI
* @since 0.9.4
*/
exports.URI = '@typed/fp/Decoder';
/**
* @category Constructor
* @since 0.9.4
*/
const of = (value) => ({
decode: () => T.right(value),
});
exports.of = of;
/**
* @category Combinator
* @since 0.9.4
*/
const map = (f) => (decoder) => ({
decode: (i) => (0, function_1.pipe)(i, decoder.decode, T.map(f)),
});
exports.map = map;
/**
* @category Combinator
* @since 0.9.4
*/
function condemnWhen(predicate) {
return (decoder) => ({
decode: (i) => (0, function_1.pipe)(i, decoder.decode, T.matchW(T.left, T.right, (errors, a) => {
const { left: absolved, right: condemned } = (0, function_1.pipe)(errors, RA.map(Ei.fromPredicate(predicate)), RA.separate);
return RA.isNonEmpty(condemned)
? T.left(condemned)
: RA.isNonEmpty(absolved)
? T.both(absolved, a)
: T.right(a);
})),
});
}
exports.condemnWhen = condemnWhen;
/**
* @category Combinator
* @since 0.9.4
*/
exports.condemn = condemnWhen(() => true);
/**
* @category Combinator
* @since 0.9.4
*/
function absolveWhen(predicate) {
return (decoder) => ({
decode: (i) => (0, function_1.pipe)(i, decoder.decode, T.matchW(T.left, T.right, (errors, a) => {
const { left: condemned, right: absolved } = (0, function_1.pipe)(errors, RA.map(Ei.fromPredicate((0, Predicate_1.not)(predicate))), RA.separate);
return RA.isNonEmpty(absolved)
? T.right(a)
: RA.isNonEmpty(condemned)
? T.both(condemned, a)
: T.right(a);
})),
});
}
exports.absolveWhen = absolveWhen;
/**
* @category Combinator
* @since 0.9.4
*/
exports.absolve = absolveWhen(() => true);
/**
* @category Combinator
* @since 0.9.4
*/
exports.condemnUnexpectedKeys = condemnWhen((d) => d._tag === 'UnexpectedKeys');
/**
* @category Combinator
* @since 0.9.4
*/
exports.condemmMissingKeys = condemnWhen((d) => d._tag === 'MissingKeys');
/**
* @category Combinator
* @since 0.9.4
*/
exports.strict = condemnWhen((d) => d._tag === 'UnexpectedKeys' || d._tag === 'MissingKeys');
/**
* @category Instance
* @since 0.9.4
*/
exports.Pointed = {
of: exports.of,
};
/**
* @category Instance
* @since 0.9.4
*/
exports.Functor = {
map: exports.map,
};
/**
* @category Combinator
* @since 0.9.4
*/
exports.bindTo = F.bindTo(exports.Functor);
/**
* @category Combinator
* @since 0.9.4
*/
exports.flap = F.flap(exports.Functor);
/**
* @category Combinator
* @since 0.9.4
*/
exports.tupled = F.tupled(exports.Functor);
/**
* @category Constructor
* @since 0.9.4
*/
const fromIO = (io) => ({
decode: () => T.right(io()),
});
exports.fromIO = fromIO;
/**
* @category Combinator
* @since 0.9.4
*/
const chain = (f) => (decoder) => ({
decode: (i) => (0, function_1.pipe)(i, decoder.decode, T.matchW(T.left, (a) => f(a).decode(i), (errors, a) => (0, function_1.pipe)(i, f(a).decode, T.mapLeft((0, ReadonlyNonEmptyArray_1.concatW)(errors))))),
});
exports.chain = chain;
/**
* @category Constructor
* @since 0.9.4
*/
exports.Chain = {
map: exports.map,
chain: exports.chain,
};
/**
* @category Combinator
* @since 0.9.4
*/
exports.ap = Ch.ap(exports.Chain);
/**
* @category Combinator
* @since 0.9.4
*/
exports.chainFirst = Ch.chainFirst(exports.Chain);
/**
* @category Combinator
* @since 0.9.4
*/
exports.bind = Ch.bind(exports.Chain);
/**
* @category Instance
* @since 0.9.4
*/
exports.Apply = {
map: exports.map,
ap: exports.ap,
};
/**
* @category Combinator
* @since 0.9.4
*/
exports.apFirst = Ap.apFirst(exports.Apply);
/**
* @category Combinator
* @since 0.9.4
*/
exports.apS = Ap.apS(exports.Apply);
/**
* @category Combinator
* @since 0.9.4
*/
exports.apSecond = Ap.apSecond(exports.Apply);
/**
* @category Combinator
* @since 0.9.4
*/
exports.apT = Ap.apT(exports.Apply);
/**
* @category Typeclass Constructor
* @since 0.9.4
*/
exports.getApplySemigroup = Ap.getApplySemigroup(exports.Apply);
/**
* @category Instance
* @since 0.9.4
*/
exports.Applicative = {
of: exports.of,
...exports.Apply,
};
/**
* @category Combinator
* @since 0.9.4
*/
exports.getApplicativeMonoid = App.getApplicativeMonoid(exports.Applicative);
/**
* @category Constructor
* @since 0.9.4
*/
exports.Do = (0, exports.fromIO)(() => Object.create(null));
/**
* @category Instance
* @since 0.9.4
*/
exports.Monad = {
...exports.Pointed,
...exports.Chain,
};
/**
* @category Instance
* @since 0.9.5
*/
exports.Schemable = {
URI: exports.URI,
literal: exports.literal,
string: exports.string,
number: exports.number,
boolean: exports.boolean,
date: exports.date,
nullable: exports.nullable,
optional: exports.optional,
struct: struct,
record: exports.record,
array: exports.array,
tuple: tuple,
intersect: exports.intersect,
sum: exports.sum,
lazy: exports.lazy,
branded: ((d) => d),
unknownArray: exports.unknownArray,
unknownRecord: exports.unknownRecord,
};
/**
* @category Instance
* @since 0.9.5
*/
exports.WithUnion = {
union: exports.union,
};
/**
* @category Decoder
* @since 0.9.5
*/
exports.jsonParseFromString = {
decode: (i) => {
try {
return T.right(JSON.parse(i));
}
catch (e) {
return T.left([DE.leaf(i, `Json`)]);
}
},
};
/**
* @category Decoder
* @since 0.9.5
*/
exports.jsonParse = (0, function_1.pipe)(exports.string, (0, exports.compose)(exports.jsonParseFromString));
/**
* Throw if not a valid decoder. Absolves optional errors
* @category Interpreter
* @since 0.9.5
*/
const assert = (decoder) => (i) => (0, function_1.pipe)(i, decoder.decode, T.absolve, Ei.matchW((errors) => {
throw new Error(DE.drawErrors(errors));
}, (o) => o));
exports.assert = assert;
/**
* Throw if not a valid decoder. Condemns optional errors
* @category Interpreter
* @since 0.9.5
*/
const assertStrict = (decoder) => (i) => (0, function_1.pipe)(i, decoder.decode, T.condemn, Ei.matchW((errors) => {
throw new Error(DE.drawErrors(errors));
}, (o) => o));
exports.assertStrict = assertStrict;
//# sourceMappingURL=Decoder.js.map