UNPKG

@typed/fp

Version:

Data Structures and Resources for fp-ts

186 lines 8.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useKVs = exports.useKVStream = exports.useStream = exports.useStreamWith = exports.useReaderStream = exports.useReaderStreamWith = exports.bindEnvK = exports.useEnvK = exports.useWithPrevious = exports.useEffectWith = exports.useDisposable = exports.useDisposableWith = exports.useMemo = exports.useMemoWith = exports.useEq = exports.useEqWith = exports.defaultOptionRef = void 0; const tslib_1 = require("tslib"); /** * @typed/fp/Use is the only non-referentially transparent module in @typed/fp. It is built atop * of [Ref](./Ref.ts.md) to enable many common workflows. If you're coming from a React background, it is * pretty similar to hooks, but the only constraint is that is should be declared once at the top of the scope of your module. * @since 0.11.0 */ const disposable_1 = require("@most/disposable"); const function_1 = require("fp-ts/function"); const O = (0, tslib_1.__importStar)(require("fp-ts/Option")); const Predicate_1 = require("fp-ts/Predicate"); const E = (0, tslib_1.__importStar)(require("./Env")); const EO = (0, tslib_1.__importStar)(require("./EnvOption")); const Eq_1 = require("./Eq"); const KV = (0, tslib_1.__importStar)(require("./KV")); const RS = (0, tslib_1.__importStar)(require("./ReaderStream")); const Ref = (0, tslib_1.__importStar)(require("./Ref")); const RefDisposable = (0, tslib_1.__importStar)(require("./RefDisposable")); const R = (0, tslib_1.__importStar)(require("./Resume")); const Scheduler_1 = require("./Scheduler"); const S = (0, tslib_1.__importStar)(require("./Stream")); /** * Use Refs to check if a value has changed between invocations * @since 0.11.0 * @category Constructor */ const defaultOptionRef = () => Ref.kv(E.of(O.none), Eq_1.alwaysEqualsEq); exports.defaultOptionRef = defaultOptionRef; /** * Use Refs to check if a value has changed between invocations * @since 0.11.0 * @category Combinator */ function useEqWith(ref) { return (Eq = Eq_1.deepEqualsEq, initial = true) => (value) => (0, function_1.pipe)(E.Do, E.bindW('previous', () => ref.get), E.bindW('changed', ({ previous }) => (0, function_1.pipe)(previous, O.matchW(() => initial, (0, Predicate_1.not)(Eq.equals(value))), E.of)), E.chainW(({ previous, changed }) => (0, function_1.pipe)(previous, O.matchW(() => E.of(changed), () => (0, function_1.pipe)(value, O.some, ref.set, E.constant(changed)))))); } exports.useEqWith = useEqWith; /** * Use Refs to check if a value has changed between invocations * @since 0.11.0 * @category Combinator */ const useEq = (Eq = Eq_1.deepEqualsEq, initial = true) => useEqWith((0, exports.defaultOptionRef)())(Eq, initial); exports.useEq = useEq; /** * @since 0.11.0 * @category Use */ const useMemoWith = (options) => (env, Eq = Eq_1.deepEqualsEq) => { const changed = (0, function_1.pipe)(Eq, useEqWith(options.changed)); const updateRef = options.currentValue.update(() => EO.fromEnv(env)); return (0, function_1.flow)(changed, E.chainFirstW((changed) => (changed ? updateRef : E.of(null))), E.chainW(() => options.currentValue.get), EO.getOrElseEW(() => (0, function_1.pipe)(env, E.chainFirstW((0, function_1.flow)(O.some, options.currentValue.set))))); }; exports.useMemoWith = useMemoWith; const defaultUseMemoRefs = () => ({ currentValue: (0, exports.defaultOptionRef)(), changed: (0, exports.defaultOptionRef)(), }); /** * @since 0.11.0 * @category Use */ const useMemo = (env, Eq = Eq_1.deepEqualsEq) => (0, exports.useMemoWith)(defaultUseMemoRefs())(env, Eq); exports.useMemo = useMemo; /** * @since 0.11.0 * @category Use */ const useDisposableWith = (options) => (Eq = Eq_1.deepEqualsEq, switchLatest = false) => { const changed = useEqWith(options.changed)(Eq); return (f, value) => (0, function_1.pipe)(E.Do, E.bindW('changed', () => changed(value)), E.bindW('current', () => options.disposable.get), E.chainW(({ changed, current }) => changed ? (0, function_1.pipe)(E.fromIO(() => (switchLatest ? current.dispose() : null)), E.chainW(() => E.fromIO(f)), E.chainW((next) => (0, function_1.pipe)(next, RefDisposable.add, E.map((d) => (0, disposable_1.disposeBoth)(d, next)), E.chainW((a) => options.disposable.set(a))))) : E.of(current))); }; exports.useDisposableWith = useDisposableWith; const defaultDisposableRefs = () => ({ disposable: Ref.kv(E.fromIO(disposable_1.disposeNone)), changed: (0, exports.defaultOptionRef)(), }); /** * @since 0.11.0 * @category Use */ const useDisposable = (Eq = Eq_1.deepEqualsEq, switchLatest = false) => (0, exports.useDisposableWith)(defaultDisposableRefs())(Eq, switchLatest); exports.useDisposable = useDisposable; /** * @since 0.11.0 * @category Use */ const useEffectWith = (options) => { const useD = (0, exports.useDisposableWith)(options); return (Eq = Eq_1.deepEqualsEq, switchLatest = false) => { const use = useD(Eq, switchLatest); return (env, value) => (0, function_1.pipe)(E.ask(), E.chainW((r) => use(() => (0, function_1.pipe)(r, (0, function_1.pipe)((0, Scheduler_1.delay)(0), E.chainW(() => env)), R.exec), value))); }; }; exports.useEffectWith = useEffectWith; /** * @since 0.11.0 * @category Use */ const useWithPrevious = (ref) => { return (f, value) => (0, function_1.pipe)(ref.get, E.map((previous) => f(previous, value)), E.chainFirstW(() => (0, function_1.pipe)(value, O.some, ref.set))); }; exports.useWithPrevious = useWithPrevious; /** * Helps you to convert a Kliesli arrow of an Env into a function to * a Disposable. Useful for UIs where you need to provide onClick={fn} * style handlers. * @since 0.11.0 * @category Use */ function useEnvK(f, onValue = E.of) { return (0, function_1.pipe)(E.Do, E.apSW('refDisposable', RefDisposable.get), E.apSW('resumeF', E.toResumeK(f)), E.apSW('resumeV', E.toResumeK(onValue)), E.map(({ resumeF, resumeV, refDisposable }) => (...args) => { const d1 = (0, function_1.pipe)(resumeF(...args), R.chain(resumeV), R.exec); const d2 = refDisposable.addDisposable(d1); return (0, disposable_1.disposeBoth)(d1, d2); })); } exports.useEnvK = useEnvK; /** * @since 0.11.0 * @category Use */ const bindEnvK = (name, f, onValue) => (ma) => E.bindW(name, () => useEnvK(f, onValue))(ma); exports.bindEnvK = bindEnvK; /** * @since 0.11.0 * @category Use */ const useReaderStreamWith = (options) => (Eq = Eq_1.deepEqualsEq) => { const use = (0, exports.useDisposableWith)(options)(Eq); return (rs, dep) => (0, function_1.pipe)(E.asksE((r) => use(() => rs(r).run(S.createSink({ event: (_, value) => (0, function_1.pipe)(value, O.some, options.value.set, E.execWith(r)), }), r.scheduler), dep)), E.chainW(() => options.value.get)); }; exports.useReaderStreamWith = useReaderStreamWith; const defaultUserReaderStreamRefs = () => ({ disposable: Ref.kv(E.fromIO(disposable_1.disposeNone)), changed: (0, exports.defaultOptionRef)(), value: (0, exports.defaultOptionRef)(), }); /** * @since 0.11.0 * @category Use */ const useReaderStream = (Eq = Eq_1.deepEqualsEq) => (0, exports.useReaderStreamWith)(defaultUserReaderStreamRefs())(Eq); exports.useReaderStream = useReaderStream; /** * @since 0.11.0 * @category Use */ const useStreamWith = (options) => (Eq = Eq_1.deepEqualsEq) => { const useRS = (0, function_1.pipe)(Eq, (0, exports.useReaderStreamWith)(options)); return (stream, dep) => useRS(() => stream, dep); }; exports.useStreamWith = useStreamWith; /** * @since 0.11.0 * @category Use */ const useStream = (Eq = Eq_1.deepEqualsEq) => { const use = (0, exports.useStreamWith)(defaultUserReaderStreamRefs())(Eq); return (stream, dep) => use(stream, dep); }; exports.useStream = useStream; /** * @since 0.11.0 * @category Use */ const useKVStream = (f, Eq) => { const use = RS.fromEnv(KV.useKeyedEnvs(Eq_1.EqStrict)); const mergeMap = RS.mergeMapWhen(Eq_1.EqStrict); return (stream) => (0, function_1.pipe)(use, RS.switchMapW(({ findRefs, deleteRefs }) => (0, function_1.pipe)(stream, RS.keyed(Eq), mergeMap((s) => (0, function_1.pipe)(s, RS.fromStream, RS.switchMapW(f), RS.onDispose(deleteRefs(s)), RS.useSomeWith(RS.fromEnv(findRefs(s)))))))); }; exports.useKVStream = useKVStream; /** * @since 0.11.0 * @category Use */ const useKVs = (f, Eq) => (0, exports.useKVStream)((0, function_1.flow)(f, KV.sample), Eq); exports.useKVs = useKVs; //# sourceMappingURL=Use.js.map