@vinicunca/perkakas 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/add-prop.d.cts +1 -1
- package/dist/add-prop.d.ts +1 -1
- package/dist/add-prop.js +1 -1
- package/dist/add.js +1 -1
- package/dist/all-pass.js +1 -1
- package/dist/any-pass.js +1 -1
- package/dist/{array-required-prefix-DxzEAAwi.d.cts → array-required-prefix-BFDM7eSS.d.cts} +8 -8
- package/dist/{array-required-prefix-DxzEAAwi.d.cts.map → array-required-prefix-BFDM7eSS.d.cts.map} +1 -1
- package/dist/{array-required-prefix-CefHtaKs.d.ts → array-required-prefix-DwpaLy0D.d.ts} +8 -8
- package/dist/{array-required-prefix-CefHtaKs.d.ts.map → array-required-prefix-DwpaLy0D.d.ts.map} +1 -1
- package/dist/{binary-search-cutoff-index-yQ2qcJHb.js → binary-search-cutoff-index-CN25H71A.js} +1 -1
- package/dist/{binary-search-cutoff-index-yQ2qcJHb.js.map → binary-search-cutoff-index-CN25H71A.js.map} +1 -1
- package/dist/{bounded-partial-DBIIClPU.d.ts → bounded-partial-CPc1XU57.d.ts} +2 -2
- package/dist/{bounded-partial-DBIIClPU.d.ts.map → bounded-partial-CPc1XU57.d.ts.map} +1 -1
- package/dist/{bounded-partial-D6ouPlXl.d.cts → bounded-partial-CtOsGqxa.d.cts} +2 -2
- package/dist/{bounded-partial-D6ouPlXl.d.cts.map → bounded-partial-CtOsGqxa.d.cts.map} +1 -1
- package/dist/capitalize.cjs +1 -0
- package/dist/capitalize.d.cts +53 -0
- package/dist/capitalize.d.cts.map +1 -0
- package/dist/capitalize.d.ts +53 -0
- package/dist/capitalize.d.ts.map +1 -0
- package/dist/capitalize.js +2 -0
- package/dist/capitalize.js.map +1 -0
- package/dist/ceil.js +1 -1
- package/dist/chunk.d.cts +6 -6
- package/dist/chunk.d.ts +6 -6
- package/dist/chunk.js +1 -1
- package/dist/clamp.js +1 -1
- package/dist/{clamped-integer-subtract-sK2BlhSm.d.ts → clamped-integer-subtract-C-AIuFhk.d.ts} +1 -1
- package/dist/{clamped-integer-subtract-sK2BlhSm.d.ts.map → clamped-integer-subtract-C-AIuFhk.d.ts.map} +1 -1
- package/dist/{clamped-integer-subtract-oLs8msYu.d.cts → clamped-integer-subtract-DueGS_u_.d.cts} +1 -1
- package/dist/{clamped-integer-subtract-oLs8msYu.d.cts.map → clamped-integer-subtract-DueGS_u_.d.cts.map} +1 -1
- package/dist/clone.js +1 -1
- package/dist/{coerced-array-DS7cKtbA.d.cts → coerced-array-BKR9Bvsl.d.cts} +1 -1
- package/dist/{coerced-array-DS7cKtbA.d.cts.map → coerced-array-BKR9Bvsl.d.cts.map} +1 -1
- package/dist/{coerced-array-1Xs4p4iF.d.ts → coerced-array-BfTLxqLo.d.ts} +1 -1
- package/dist/{coerced-array-1Xs4p4iF.d.ts.map → coerced-array-BfTLxqLo.d.ts.map} +1 -1
- package/dist/concat.d.cts +1 -1
- package/dist/concat.d.ts +1 -1
- package/dist/concat.js +1 -1
- package/dist/{conditional-tssGt6Vy.d.cts → conditional-Br0uqqc9.d.cts} +1 -1
- package/dist/{conditional-tssGt6Vy.d.cts.map → conditional-Br0uqqc9.d.cts.map} +1 -1
- package/dist/{conditional-F_nq8vtA.d.ts → conditional-CDez6uXp.d.ts} +1 -1
- package/dist/{conditional-F_nq8vtA.d.ts.map → conditional-CDez6uXp.d.ts.map} +1 -1
- package/dist/{conditional-lp8ZHACd.js → conditional-WbmvQs8H.js} +1 -1
- package/dist/{conditional-lp8ZHACd.js.map → conditional-WbmvQs8H.js.map} +1 -1
- package/dist/conditional.d.cts +1 -1
- package/dist/conditional.d.ts +1 -1
- package/dist/conditional.js +1 -1
- package/dist/count-by.d.cts +1 -1
- package/dist/count-by.d.ts +1 -1
- package/dist/count-by.js +1 -1
- package/dist/{curry-d8_p_Jzt.d.ts → curry-CKDQ1osk.d.ts} +4 -2
- package/dist/curry-CKDQ1osk.d.ts.map +1 -0
- package/dist/{curry-BcQ8Up1_.js → curry-NmniqyJ0.js} +2 -2
- package/dist/curry-NmniqyJ0.js.map +1 -0
- package/dist/{curry-from-lazy-CYtJvyas.js → curry-from-lazy-PQ0BbG-7.js} +2 -2
- package/dist/{curry-from-lazy-CYtJvyas.js.map → curry-from-lazy-PQ0BbG-7.js.map} +1 -1
- package/dist/{curry-B20xQM_9.d.cts → curry-mh6BKSIA.d.cts} +4 -2
- package/dist/curry-mh6BKSIA.d.cts.map +1 -0
- package/dist/{curry-order-rules-cezUWcSx.d.cts → curry-order-rules-BoF09Dq2.d.cts} +1 -1
- package/dist/{curry-order-rules-cezUWcSx.d.cts.map → curry-order-rules-BoF09Dq2.d.cts.map} +1 -1
- package/dist/{curry-order-rules-BCcwbNxd.d.ts → curry-order-rules-CoO4bk5I.d.ts} +1 -1
- package/dist/{curry-order-rules-BCcwbNxd.d.ts.map → curry-order-rules-CoO4bk5I.d.ts.map} +1 -1
- package/dist/{curry-order-rules-C6bwcUwC.js → curry-order-rules-DwrF-_P1.js} +1 -1
- package/dist/{curry-order-rules-C6bwcUwC.js.map → curry-order-rules-DwrF-_P1.js.map} +1 -1
- package/dist/curry.d.cts +1 -1
- package/dist/curry.d.ts +1 -1
- package/dist/curry.js +1 -1
- package/dist/debounce.d.cts +5 -3
- package/dist/debounce.d.cts.map +1 -1
- package/dist/debounce.d.ts +5 -3
- package/dist/debounce.d.ts.map +1 -1
- package/dist/debounce.js.map +1 -1
- package/dist/{deduped-CXeQa-0F.d.cts → deduped-DdwAYzXs.d.cts} +3 -3
- package/dist/{deduped-CXeQa-0F.d.cts.map → deduped-DdwAYzXs.d.cts.map} +1 -1
- package/dist/{deduped-CL5-bmYU.d.ts → deduped-RY-1u-ns.d.ts} +3 -3
- package/dist/{deduped-CL5-bmYU.d.ts.map → deduped-RY-1u-ns.d.ts.map} +1 -1
- package/dist/difference-with.js +1 -1
- package/dist/difference.js +1 -1
- package/dist/dist-8XtUY3ad.cjs +114 -0
- package/dist/dist-Bd1vawFi.js +103 -0
- package/dist/dist-Bd1vawFi.js.map +1 -0
- package/dist/divide.js +1 -1
- package/dist/drop-first-by.d.cts +2 -2
- package/dist/drop-first-by.d.ts +2 -2
- package/dist/drop-first-by.js +1 -1
- package/dist/drop-last-while.d.cts +1 -1
- package/dist/drop-last-while.d.ts +1 -1
- package/dist/drop-last-while.js +1 -1
- package/dist/drop-last.d.cts +1 -1
- package/dist/drop-last.d.ts +1 -1
- package/dist/drop-last.js +1 -1
- package/dist/drop-while.d.cts +1 -1
- package/dist/drop-while.d.ts +1 -1
- package/dist/drop-while.js +1 -1
- package/dist/drop.d.cts +5 -5
- package/dist/drop.d.ts +5 -5
- package/dist/drop.js +1 -1
- package/dist/entries.d.cts +1 -1
- package/dist/entries.d.ts +1 -1
- package/dist/entries.js +1 -1
- package/dist/{enumerable-string-key-of-DMAkBhMk.d.ts → enumerable-string-key-of-CZQf3ld_.d.ts} +2 -2
- package/dist/{enumerable-string-key-of-DMAkBhMk.d.ts.map → enumerable-string-key-of-CZQf3ld_.d.ts.map} +1 -1
- package/dist/{enumerable-string-key-of-FUg082M_.d.cts → enumerable-string-key-of-DhcNc5iz.d.cts} +2 -2
- package/dist/{enumerable-string-key-of-FUg082M_.d.cts.map → enumerable-string-key-of-DhcNc5iz.d.cts.map} +1 -1
- package/dist/{enumerable-string-keyed-value-of-B2F2aTB7.d.ts → enumerable-string-keyed-value-of-CRlVAvdp.d.ts} +1 -1
- package/dist/{enumerable-string-keyed-value-of-B2F2aTB7.d.ts.map → enumerable-string-keyed-value-of-CRlVAvdp.d.ts.map} +1 -1
- package/dist/{enumerable-string-keyed-value-of-CEclDoqe.d.cts → enumerable-string-keyed-value-of-icm2q60J.d.cts} +1 -1
- package/dist/{enumerable-string-keyed-value-of-CEclDoqe.d.cts.map → enumerable-string-keyed-value-of-icm2q60J.d.cts.map} +1 -1
- package/dist/evolve.d.cts +1 -1
- package/dist/evolve.d.ts +1 -1
- package/dist/evolve.js +1 -1
- package/dist/filter.d.cts +2 -2
- package/dist/filter.d.ts +2 -2
- package/dist/filter.js +1 -1
- package/dist/filtered-array-C--8loav.d.cts +22 -0
- package/dist/filtered-array-C--8loav.d.cts.map +1 -0
- package/dist/filtered-array-wtIEwdU7.d.ts +22 -0
- package/dist/filtered-array-wtIEwdU7.d.ts.map +1 -0
- package/dist/find-index.js +1 -1
- package/dist/find-last-index.js +1 -1
- package/dist/find-last.js +1 -1
- package/dist/find.js +1 -1
- package/dist/first-by.d.cts +3 -3
- package/dist/first-by.d.ts +3 -3
- package/dist/first-by.js +1 -1
- package/dist/first.d.cts +1 -1
- package/dist/first.d.ts +1 -1
- package/dist/first.js +1 -1
- package/dist/flat-map.js +1 -1
- package/dist/flat.d.cts +1 -1
- package/dist/flat.d.ts +1 -1
- package/dist/flat.js +1 -1
- package/dist/floor.js +1 -1
- package/dist/for-each-obj.d.cts +2 -2
- package/dist/for-each-obj.d.ts +2 -2
- package/dist/for-each-obj.js +1 -1
- package/dist/for-each.d.cts +1 -1
- package/dist/for-each.d.ts +1 -1
- package/dist/for-each.js +1 -1
- package/dist/from-entries.d.cts +2 -2
- package/dist/from-entries.d.ts +2 -2
- package/dist/from-entries.js +1 -1
- package/dist/from-keys.d.cts +2 -2
- package/dist/from-keys.d.ts +2 -2
- package/dist/from-keys.js +1 -1
- package/dist/funnel.d.cts.map +1 -1
- package/dist/funnel.d.ts.map +1 -1
- package/dist/funnel.lodash-debounce-with-cached-value.test.cjs +1 -1
- package/dist/funnel.lodash-debounce-with-cached-value.test.js +1 -1
- package/dist/funnel.lodash-debounce-with-cached-value.test.js.map +1 -1
- package/dist/funnel.lodash-debounce.test.cjs +1 -1
- package/dist/funnel.lodash-debounce.test.js +1 -1
- package/dist/funnel.lodash-throttle-with-cached-value.test.cjs +1 -1
- package/dist/funnel.lodash-throttle-with-cached-value.test.js +1 -1
- package/dist/funnel.lodash-throttle-with-cached-value.test.js.map +1 -1
- package/dist/funnel.lodash-throttle.test.cjs +1 -1
- package/dist/funnel.lodash-throttle.test.js +1 -1
- package/dist/funnel.perkakas-debounce.test.cjs +1 -1
- package/dist/funnel.perkakas-debounce.test.js +1 -1
- package/dist/funnel.perkakas-debounce.test.js.map +1 -1
- package/dist/funnel.reference-batch.test.cjs +1 -1
- package/dist/funnel.reference-batch.test.js +1 -1
- package/dist/funnel.reference-batch.test.js.map +1 -1
- package/dist/funnel.test-d.cjs +1 -1
- package/dist/funnel.test-d.js +1 -1
- package/dist/funnel.test.cjs +1 -1
- package/dist/funnel.test.js +1 -1
- package/dist/funnel.test.js.map +1 -1
- package/dist/group-by-prop.d.cts +10 -10
- package/dist/group-by-prop.d.ts +10 -10
- package/dist/group-by-prop.js +1 -1
- package/dist/group-by-prop.js.map +1 -1
- package/dist/group-by.d.cts +2 -2
- package/dist/group-by.d.ts +2 -2
- package/dist/group-by.js +1 -1
- package/dist/has-at-least-Coy9sM-B.js +2 -0
- package/dist/{has-at-least-DyIhWZJH.js.map → has-at-least-Coy9sM-B.js.map} +1 -1
- package/dist/has-at-least.d.cts +2 -2
- package/dist/has-at-least.d.ts +2 -2
- package/dist/has-at-least.js +1 -1
- package/dist/has-sub-object.js +1 -1
- package/dist/{heap-bARaRULU.js → heap-BhpfhYWj.js} +2 -2
- package/dist/{heap-bARaRULU.js.map → heap-BhpfhYWj.js.map} +1 -1
- package/dist/index-by.d.cts +1 -1
- package/dist/index-by.d.ts +1 -1
- package/dist/index-by.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +12 -14
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +12 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{int-range-inclusive-ClGdUant.d.ts → int-range-inclusive-BlGXX6Cz.d.ts} +1 -1
- package/dist/{int-range-inclusive-ClGdUant.d.ts.map → int-range-inclusive-BlGXX6Cz.d.ts.map} +1 -1
- package/dist/{int-range-inclusive-q-Jb7w6P.d.cts → int-range-inclusive-KocNpK0p.d.cts} +1 -1
- package/dist/{int-range-inclusive-q-Jb7w6P.d.cts.map → int-range-inclusive-KocNpK0p.d.cts.map} +1 -1
- package/dist/intersection-with.js +1 -1
- package/dist/intersection.js +1 -1
- package/dist/invert.d.cts +1 -1
- package/dist/invert.d.ts +1 -1
- package/dist/invert.js +1 -1
- package/dist/is-array.d.cts +1 -1
- package/dist/is-array.d.ts +1 -1
- package/dist/is-big-int.d.cts +1 -1
- package/dist/is-big-int.d.ts +1 -1
- package/dist/is-boolean.d.cts +1 -1
- package/dist/is-boolean.d.ts +1 -1
- package/dist/{is-bounded-record-BGclJjRX.d.ts → is-bounded-record-Bx4n8QB0.d.ts} +1 -1
- package/dist/{is-bounded-record-BGclJjRX.d.ts.map → is-bounded-record-Bx4n8QB0.d.ts.map} +1 -1
- package/dist/{is-bounded-record-D9YK_OC8.d.cts → is-bounded-record-DV6ZQk9H.d.cts} +1 -1
- package/dist/{is-bounded-record-D9YK_OC8.d.cts.map → is-bounded-record-DV6ZQk9H.d.cts.map} +1 -1
- package/dist/is-deep-equal.js +1 -1
- package/dist/is-empty.d.cts +1 -1
- package/dist/is-empty.d.ts +1 -1
- package/dist/{is-emptyish-CIxZzxxz.d.ts → is-emptyish-9tX94IVx.d.cts} +2 -3
- package/dist/is-emptyish-9tX94IVx.d.cts.map +1 -0
- package/dist/{is-emptyish-oX5mpcfW.d.cts → is-emptyish-DVFGJe-T.d.ts} +2 -3
- package/dist/is-emptyish-DVFGJe-T.d.ts.map +1 -0
- package/dist/is-emptyish.d.cts +1 -1
- package/dist/is-emptyish.d.ts +1 -1
- package/dist/is-emptyish.js.map +1 -1
- package/dist/is-emptyish.test-d.cjs +1 -1
- package/dist/is-emptyish.test-d.js +1 -1
- package/dist/is-emptyish.test.cjs +1 -1
- package/dist/is-emptyish.test.js +1 -1
- package/dist/is-function.d.cts +5 -2
- package/dist/is-function.d.cts.map +1 -1
- package/dist/is-function.d.ts +5 -2
- package/dist/is-function.d.ts.map +1 -1
- package/dist/is-function.js.map +1 -1
- package/dist/is-included-in.d.cts +2 -3
- package/dist/is-included-in.d.cts.map +1 -1
- package/dist/is-included-in.d.ts +2 -3
- package/dist/is-included-in.d.ts.map +1 -1
- package/dist/is-included-in.js.map +1 -1
- package/dist/is-nullish.d.cts +1 -1
- package/dist/is-nullish.d.ts +1 -1
- package/dist/is-number.d.cts +1 -1
- package/dist/is-number.d.ts +1 -1
- package/dist/is-object-type.d.cts +1 -1
- package/dist/is-object-type.d.ts +1 -1
- package/dist/is-plain-object.d.cts +1 -1
- package/dist/is-plain-object.d.ts +1 -1
- package/dist/is-shallow-equal.js +1 -1
- package/dist/is-strict-equal.js +1 -1
- package/dist/is-string.d.cts +1 -1
- package/dist/is-string.d.ts +1 -1
- package/dist/is-symbol.d.cts +1 -1
- package/dist/is-symbol.d.ts +1 -1
- package/dist/{iterable-container-OFsaw8WL.d.cts → iterable-container-1TN3AJ3s.d.cts} +1 -1
- package/dist/{iterable-container-OFsaw8WL.d.cts.map → iterable-container-1TN3AJ3s.d.cts.map} +1 -1
- package/dist/{iterable-container-BdjPuIjL.d.ts → iterable-container-Dv5vSKht.d.ts} +1 -1
- package/dist/iterable-container-Dv5vSKht.d.ts.map +1 -0
- package/dist/join.js +1 -1
- package/dist/keys.d.cts +3 -3
- package/dist/keys.d.ts +3 -3
- package/dist/keys.js +1 -1
- package/dist/last.d.cts +1 -1
- package/dist/last.d.ts +1 -1
- package/dist/last.js +1 -1
- package/dist/{lazy-data-last-impl-DW5TXWv8.js → lazy-data-last-impl-R05wr4K6.js} +1 -1
- package/dist/lazy-data-last-impl-R05wr4K6.js.map +1 -0
- package/dist/length.js +1 -1
- package/dist/{magic-string.es-BY9a6RR2.js → magic-string.es-94aXgwpn.js} +1 -1
- package/dist/{magic-string.es-BY9a6RR2.js.map → magic-string.es-94aXgwpn.js.map} +1 -1
- package/dist/map-keys.d.cts +3 -3
- package/dist/map-keys.d.ts +3 -3
- package/dist/map-keys.js +1 -1
- package/dist/map-to-obj.js +1 -1
- package/dist/map-values.d.cts +2 -2
- package/dist/map-values.d.ts +2 -2
- package/dist/map-values.js +1 -1
- package/dist/map-with-feedback.d.cts +2 -2
- package/dist/map-with-feedback.d.ts +2 -2
- package/dist/map-with-feedback.js +1 -1
- package/dist/map.d.cts +2 -2
- package/dist/map.d.ts +2 -2
- package/dist/map.js +1 -1
- package/dist/{mapped-LCblUtt3.d.ts → mapped-BbrC9t3s.d.ts} +2 -2
- package/dist/mapped-BbrC9t3s.d.ts.map +1 -0
- package/dist/{mapped-m3FRlUOA.d.cts → mapped-CkRNfTnY.d.cts} +2 -2
- package/dist/mapped-CkRNfTnY.d.cts.map +1 -0
- package/dist/mean-by.js +1 -1
- package/dist/{merge-all-CW8DGAy8.d.cts → merge-all-CISawx-J.d.cts} +4 -4
- package/dist/{merge-all-CW8DGAy8.d.cts.map → merge-all-CISawx-J.d.cts.map} +1 -1
- package/dist/{merge-all-B9JBhVzy.d.ts → merge-all-DJ6n7R1b.d.ts} +4 -4
- package/dist/{merge-all-B9JBhVzy.d.ts.map → merge-all-DJ6n7R1b.d.ts.map} +1 -1
- package/dist/merge-all.d.cts +1 -1
- package/dist/merge-all.d.ts +1 -1
- package/dist/merge-deep.js +1 -1
- package/dist/merge.js +1 -1
- package/dist/multiply.js +1 -1
- package/dist/{n-tuple-Bu1e7UH_.d.cts → n-tuple-BkMobYQ9.d.cts} +1 -1
- package/dist/{n-tuple-Bu1e7UH_.d.cts.map → n-tuple-BkMobYQ9.d.cts.map} +1 -1
- package/dist/{n-tuple-DoE0z7Kl.d.ts → n-tuple-zo5g_mSL.d.ts} +1 -1
- package/dist/{n-tuple-DoE0z7Kl.d.ts.map → n-tuple-zo5g_mSL.d.ts.map} +1 -1
- package/dist/{narrowed-to-j75i8Rl2.d.ts → narrowed-to-B7tkuY2k.d.ts} +1 -1
- package/dist/{narrowed-to-j75i8Rl2.d.ts.map → narrowed-to-B7tkuY2k.d.ts.map} +1 -1
- package/dist/{narrowed-to-Yf5qTOcD.d.cts → narrowed-to-D_6H-aZW.d.cts} +1 -1
- package/dist/{narrowed-to-Yf5qTOcD.d.cts.map → narrowed-to-D_6H-aZW.d.cts.map} +1 -1
- package/dist/{non-empty-array-DXkY7ynY.d.ts → non-empty-array-DHAKSw6t.d.ts} +1 -1
- package/dist/non-empty-array-DHAKSw6t.d.ts.map +1 -0
- package/dist/{non-empty-array-CFG7wGD-.d.cts → non-empty-array-NDjbHRjk.d.cts} +1 -1
- package/dist/non-empty-array-NDjbHRjk.d.cts.map +1 -0
- package/dist/{nth-by-Bs6FNGL-.js → nth-by-JP3-Htbo.js} +2 -2
- package/dist/{nth-by-Bs6FNGL-.js.map → nth-by-JP3-Htbo.js.map} +1 -1
- package/dist/nth-by.d.cts +3 -3
- package/dist/nth-by.d.ts +3 -3
- package/dist/nth-by.js +1 -1
- package/dist/obj-of.js +1 -1
- package/dist/omit-DI8DRDHj.d.ts +71 -0
- package/dist/omit-DI8DRDHj.d.ts.map +1 -0
- package/dist/omit-DQiCiWAg.d.cts +71 -0
- package/dist/omit-DQiCiWAg.d.cts.map +1 -0
- package/dist/omit-by.d.cts +3 -3
- package/dist/omit-by.d.ts +3 -3
- package/dist/omit-by.js +1 -1
- package/dist/omit.d.cts +2 -29
- package/dist/omit.d.ts +2 -29
- package/dist/omit.js +1 -1
- package/dist/omit.js.map +1 -1
- package/dist/only.d.cts +1 -1
- package/dist/only.d.ts +1 -1
- package/dist/only.js +1 -1
- package/dist/optional-options-with-defaults-BFaBSKkF.d.ts +12 -0
- package/dist/optional-options-with-defaults-BFaBSKkF.d.ts.map +1 -0
- package/dist/optional-options-with-defaults-BZVW8GfC.d.cts +12 -0
- package/dist/optional-options-with-defaults-BZVW8GfC.d.cts.map +1 -0
- package/dist/{partial-array-CoV_xxyQ.d.cts → partial-array-CQF5oggb.d.cts} +1 -1
- package/dist/partial-array-CQF5oggb.d.cts.map +1 -0
- package/dist/{partial-array-CeoXpbZU.d.ts → partial-array-DU-2Vkyx.d.ts} +1 -1
- package/dist/partial-array-DU-2Vkyx.d.ts.map +1 -0
- package/dist/partition-by-union-BztEpKVh.d.cts +20 -0
- package/dist/partition-by-union-BztEpKVh.d.cts.map +1 -0
- package/dist/partition-by-union-DnfiiEMU.d.ts +20 -0
- package/dist/partition-by-union-DnfiiEMU.d.ts.map +1 -0
- package/dist/partition.js +1 -1
- package/dist/path-or.js +1 -1
- package/dist/{perkakas-type-error-DmmsEmEF.d.ts → perkakas-type-error-B9ULNhW0.d.ts} +1 -1
- package/dist/{perkakas-type-error-DmmsEmEF.d.ts.map → perkakas-type-error-B9ULNhW0.d.ts.map} +1 -1
- package/dist/{perkakas-type-error-BERl_sWR.d.cts → perkakas-type-error-ClCCHBW1.d.cts} +1 -1
- package/dist/{perkakas-type-error-BERl_sWR.d.cts.map → perkakas-type-error-ClCCHBW1.d.cts.map} +1 -1
- package/dist/pick-by.d.cts +4 -4
- package/dist/pick-by.d.cts.map +1 -1
- package/dist/pick-by.d.ts +4 -4
- package/dist/pick-by.d.ts.map +1 -1
- package/dist/pick-by.js +1 -1
- package/dist/pick-by.js.map +1 -1
- package/dist/pick.d.cts +4 -15
- package/dist/pick.d.cts.map +1 -1
- package/dist/pick.d.ts +4 -15
- package/dist/pick.d.ts.map +1 -1
- package/dist/pick.js +1 -1
- package/dist/pick.js.map +1 -1
- package/dist/{pipe-BGazHnZ_.js → pipe-CZKusDA-.js} +2 -2
- package/dist/pipe-CZKusDA-.js.map +1 -0
- package/dist/pipe.d.cts +95 -23
- package/dist/pipe.d.cts.map +1 -1
- package/dist/pipe.d.ts +95 -23
- package/dist/pipe.d.ts.map +1 -1
- package/dist/pipe.js +1 -1
- package/dist/piped.js +1 -1
- package/dist/product.d.cts +2 -2
- package/dist/product.d.ts +2 -2
- package/dist/product.js +1 -1
- package/dist/product.js.map +1 -1
- package/dist/{prop-DulcbWGG.d.ts → prop-D-4cFXSd.d.cts} +5 -6
- package/dist/prop-D-4cFXSd.d.cts.map +1 -0
- package/dist/{prop-C3rYih5m.d.cts → prop-DL-oRBeN.d.ts} +5 -6
- package/dist/prop-DL-oRBeN.d.ts.map +1 -0
- package/dist/prop.d.cts +1 -1
- package/dist/prop.d.ts +1 -1
- package/dist/prop.js.map +1 -1
- package/dist/pull-object.d.cts +2 -2
- package/dist/pull-object.d.ts +2 -2
- package/dist/pull-object.js +1 -1
- package/dist/random-integer.d.cts +1 -1
- package/dist/random-integer.d.ts +1 -1
- package/dist/random-string.js +1 -1
- package/dist/range.js +1 -1
- package/dist/rank-by.d.cts +2 -2
- package/dist/rank-by.d.ts +2 -2
- package/dist/rank-by.js +1 -1
- package/dist/reduce.js +1 -1
- package/dist/{reordered-array-B2klHneX.d.ts → reordered-array-BWG6tVSK.d.ts} +2 -2
- package/dist/reordered-array-BWG6tVSK.d.ts.map +1 -0
- package/dist/{reordered-array-BsUBOnYh.d.cts → reordered-array-CmReuxDi.d.cts} +2 -2
- package/dist/reordered-array-CmReuxDi.d.cts.map +1 -0
- package/dist/reverse.js +1 -1
- package/dist/round.js +1 -1
- package/dist/sample.d.cts +5 -5
- package/dist/sample.d.ts +5 -5
- package/dist/sample.js +1 -1
- package/dist/set-path.d.cts +1 -1
- package/dist/set-path.d.ts +1 -1
- package/dist/set-path.js +1 -1
- package/dist/set.d.cts +1 -1
- package/dist/set.d.ts +1 -1
- package/dist/set.js +1 -1
- package/dist/shuffle.d.cts +2 -2
- package/dist/shuffle.d.ts +2 -2
- package/dist/shuffle.js +1 -1
- package/dist/sort-by.d.cts +4 -4
- package/dist/sort-by.d.ts +4 -4
- package/dist/sort-by.js +1 -1
- package/dist/sort.d.cts +2 -2
- package/dist/sort.d.ts +2 -2
- package/dist/sort.js +1 -1
- package/dist/sorted-index-by.js +1 -1
- package/dist/sorted-index-with.js +1 -1
- package/dist/sorted-index.js +1 -1
- package/dist/sorted-last-index-by.js +1 -1
- package/dist/sorted-last-index.js +1 -1
- package/dist/splice.js +1 -1
- package/dist/split-at.js +1 -1
- package/dist/split-when.js +1 -1
- package/dist/split.d.cts +8 -8
- package/dist/split.d.cts.map +1 -1
- package/dist/split.d.ts +8 -8
- package/dist/split.d.ts.map +1 -1
- package/dist/split.js.map +1 -1
- package/dist/strict-function-BBgKFNUw.d.ts +26 -0
- package/dist/strict-function-BBgKFNUw.d.ts.map +1 -0
- package/dist/strict-function-CPTwDgnZ.d.cts +26 -0
- package/dist/strict-function-CPTwDgnZ.d.cts.map +1 -0
- package/dist/subtract.js +1 -1
- package/dist/sum-by.d.cts +1 -1
- package/dist/sum-by.d.ts +1 -1
- package/dist/sum-by.js +1 -1
- package/dist/sum.d.cts +1 -1
- package/dist/sum.d.ts +1 -1
- package/dist/sum.js +1 -1
- package/dist/{swap-in-place-COm7qHj4.js → swap-in-place-C_jXKHuD.js} +1 -1
- package/dist/{swap-in-place-COm7qHj4.js.map → swap-in-place-C_jXKHuD.js.map} +1 -1
- package/dist/swap-indices.d.cts +1 -1
- package/dist/swap-indices.d.ts +1 -1
- package/dist/swap-indices.js +1 -1
- package/dist/swap-props.js +1 -1
- package/dist/take-first-by.d.cts +2 -2
- package/dist/take-first-by.d.ts +2 -2
- package/dist/take-first-by.js +1 -1
- package/dist/take-last-while.d.cts +1 -1
- package/dist/take-last-while.d.ts +1 -1
- package/dist/take-last-while.js +1 -1
- package/dist/take-last.d.cts +1 -1
- package/dist/take-last.d.ts +1 -1
- package/dist/take-last.js +1 -1
- package/dist/take-while.d.cts +1 -1
- package/dist/take-while.d.ts +1 -1
- package/dist/take-while.js +1 -1
- package/dist/take.d.cts +1 -1
- package/dist/take.d.ts +1 -1
- package/dist/take.js +1 -1
- package/dist/tap.js +1 -1
- package/dist/times.js +1 -1
- package/dist/to-camel-case.cjs +1 -1
- package/dist/to-camel-case.d.cts +72 -20
- package/dist/to-camel-case.d.cts.map +1 -1
- package/dist/to-camel-case.d.ts +72 -20
- package/dist/to-camel-case.d.ts.map +1 -1
- package/dist/to-camel-case.js +1 -1
- package/dist/to-camel-case.js.map +1 -1
- package/dist/to-kebab-case.cjs +1 -1
- package/dist/to-kebab-case.d.cts +48 -19
- package/dist/to-kebab-case.d.cts.map +1 -1
- package/dist/to-kebab-case.d.ts +48 -19
- package/dist/to-kebab-case.d.ts.map +1 -1
- package/dist/to-kebab-case.js +1 -1
- package/dist/to-kebab-case.js.map +1 -1
- package/dist/to-lower-case.cjs +1 -0
- package/dist/to-lower-case.d.cts +51 -0
- package/dist/to-lower-case.d.cts.map +1 -0
- package/dist/to-lower-case.d.ts +51 -0
- package/dist/to-lower-case.d.ts.map +1 -0
- package/dist/to-lower-case.js +2 -0
- package/dist/to-lower-case.js.map +1 -0
- package/dist/{to-single-vYpRavjM.js → to-single-BKYbBic-.js} +1 -1
- package/dist/to-single-BKYbBic-.js.map +1 -0
- package/dist/to-snake-case.cjs +1 -1
- package/dist/to-snake-case.d.cts +48 -19
- package/dist/to-snake-case.d.cts.map +1 -1
- package/dist/to-snake-case.d.ts +48 -19
- package/dist/to-snake-case.d.ts.map +1 -1
- package/dist/to-snake-case.js +1 -1
- package/dist/to-snake-case.js.map +1 -1
- package/dist/{to-string-Se4KcQka.d.cts → to-string-DkC3zRUJ.d.cts} +1 -1
- package/dist/to-string-DkC3zRUJ.d.cts.map +1 -0
- package/dist/{to-string-C6_OnZ6e.d.ts → to-string-YIFx2KS6.d.ts} +1 -1
- package/dist/to-string-YIFx2KS6.d.ts.map +1 -0
- package/dist/to-title-case.cjs +1 -0
- package/dist/to-title-case.d.cts +86 -0
- package/dist/to-title-case.d.cts.map +1 -0
- package/dist/to-title-case.d.ts +86 -0
- package/dist/to-title-case.d.ts.map +1 -0
- package/dist/to-title-case.js +2 -0
- package/dist/to-title-case.js.map +1 -0
- package/dist/to-upper-case.cjs +1 -0
- package/dist/to-upper-case.d.cts +51 -0
- package/dist/to-upper-case.d.cts.map +1 -0
- package/dist/to-upper-case.d.ts +51 -0
- package/dist/to-upper-case.d.ts.map +1 -0
- package/dist/to-upper-case.js +2 -0
- package/dist/to-upper-case.js.map +1 -0
- package/dist/{tuple-parts-Bhbm4jiu.d.ts → tuple-parts-BYI4o8Vk.d.ts} +8 -8
- package/dist/{tuple-parts-Bhbm4jiu.d.ts.map → tuple-parts-BYI4o8Vk.d.ts.map} +1 -1
- package/dist/{tuple-parts-BJQEORxn.d.cts → tuple-parts-CzQQupgi.d.cts} +8 -8
- package/dist/{tuple-parts-BJQEORxn.d.cts.map → tuple-parts-CzQQupgi.d.cts.map} +1 -1
- package/dist/uncapitalize.cjs +1 -0
- package/dist/uncapitalize.d.cts +51 -0
- package/dist/uncapitalize.d.cts.map +1 -0
- package/dist/uncapitalize.d.ts +51 -0
- package/dist/uncapitalize.d.ts.map +1 -0
- package/dist/uncapitalize.js +2 -0
- package/dist/uncapitalize.js.map +1 -0
- package/dist/unique-by.d.cts +2 -2
- package/dist/unique-by.d.ts +2 -2
- package/dist/unique-by.js +1 -1
- package/dist/unique-with.d.cts +2 -2
- package/dist/unique-with.d.ts +2 -2
- package/dist/unique-with.js +1 -1
- package/dist/unique.d.cts +2 -2
- package/dist/unique.d.ts +2 -2
- package/dist/unique.js +1 -1
- package/dist/{upsert-prop-__xTQQ07.d.ts → upsert-prop-0hwik6JJ.d.cts} +2 -3
- package/dist/{upsert-prop-__xTQQ07.d.ts.map → upsert-prop-0hwik6JJ.d.cts.map} +1 -1
- package/dist/{upsert-prop-P-aJDDII.d.cts → upsert-prop-_NpaZwm4.d.ts} +2 -3
- package/dist/upsert-prop-_NpaZwm4.d.ts.map +1 -0
- package/dist/{utility-evaluators-BwYLtB8b.js → utility-evaluators-Boc-TMbq.js} +1 -1
- package/dist/{utility-evaluators-BwYLtB8b.js.map → utility-evaluators-Boc-TMbq.js.map} +1 -1
- package/dist/values.d.cts +2 -2
- package/dist/values.d.ts +2 -2
- package/dist/values.js +1 -1
- package/dist/{with-precision-CWWiMmxZ.js → with-precision-CQ90Walk.js} +1 -1
- package/dist/{with-precision-CWWiMmxZ.js.map → with-precision-CQ90Walk.js.map} +1 -1
- package/dist/words-DQCM5umD.js +3 -0
- package/dist/words-DQCM5umD.js.map +1 -0
- package/dist/words-DRQKxzLU.cjs +2 -0
- package/dist/zip-with.d.cts +1 -1
- package/dist/zip-with.d.ts +1 -1
- package/dist/zip-with.js +1 -1
- package/dist/zip.d.cts +1 -1
- package/dist/zip.d.ts +1 -1
- package/dist/zip.js +1 -1
- package/package.json +4 -6
- package/dist/case.transform-CCMWrBmz.js +0 -2
- package/dist/case.transform-CCMWrBmz.js.map +0 -1
- package/dist/case.transform-FNx2XsC3.cjs +0 -1
- package/dist/case.types-BxuWJgN1.d.cts +0 -19
- package/dist/case.types-BxuWJgN1.d.cts.map +0 -1
- package/dist/case.types-CVfGg990.d.ts +0 -19
- package/dist/case.types-CVfGg990.d.ts.map +0 -1
- package/dist/curry-B20xQM_9.d.cts.map +0 -1
- package/dist/curry-BcQ8Up1_.js.map +0 -1
- package/dist/curry-d8_p_Jzt.d.ts.map +0 -1
- package/dist/dist-CUT1dnRU.js +0 -343
- package/dist/dist-CUT1dnRU.js.map +0 -1
- package/dist/dist-CiyBKPT6.cjs +0 -343
- package/dist/filtered-array-D_RqQ8tX.d.cts +0 -13
- package/dist/filtered-array-D_RqQ8tX.d.cts.map +0 -1
- package/dist/filtered-array-Yij-X3T4.d.ts +0 -13
- package/dist/filtered-array-Yij-X3T4.d.ts.map +0 -1
- package/dist/has-at-least-DyIhWZJH.js +0 -2
- package/dist/is-emptyish-CIxZzxxz.d.ts.map +0 -1
- package/dist/is-emptyish-oX5mpcfW.d.cts.map +0 -1
- package/dist/is-union-Bu19sEkP.d.ts +0 -8
- package/dist/is-union-Bu19sEkP.d.ts.map +0 -1
- package/dist/is-union-Dp9mCo1b.d.cts +0 -8
- package/dist/is-union-Dp9mCo1b.d.cts.map +0 -1
- package/dist/iterable-container-BdjPuIjL.d.ts.map +0 -1
- package/dist/lazy-data-last-impl-DW5TXWv8.js.map +0 -1
- package/dist/mapped-LCblUtt3.d.ts.map +0 -1
- package/dist/mapped-m3FRlUOA.d.cts.map +0 -1
- package/dist/no-infer-BIHbaQcD.d.ts +0 -5
- package/dist/no-infer-BIHbaQcD.d.ts.map +0 -1
- package/dist/no-infer-BVbyldno.d.cts +0 -5
- package/dist/no-infer-BVbyldno.d.cts.map +0 -1
- package/dist/non-empty-array-CFG7wGD-.d.cts.map +0 -1
- package/dist/non-empty-array-DXkY7ynY.d.ts.map +0 -1
- package/dist/omit.d.cts.map +0 -1
- package/dist/omit.d.ts.map +0 -1
- package/dist/partial-array-CeoXpbZU.d.ts.map +0 -1
- package/dist/partial-array-CoV_xxyQ.d.cts.map +0 -1
- package/dist/pipe-BGazHnZ_.js.map +0 -1
- package/dist/prop-C3rYih5m.d.cts.map +0 -1
- package/dist/prop-DulcbWGG.d.ts.map +0 -1
- package/dist/reordered-array-B2klHneX.d.ts.map +0 -1
- package/dist/reordered-array-BsUBOnYh.d.cts.map +0 -1
- package/dist/to-capital-case.cjs +0 -1
- package/dist/to-capital-case.d.cts +0 -31
- package/dist/to-capital-case.d.cts.map +0 -1
- package/dist/to-capital-case.d.ts +0 -31
- package/dist/to-capital-case.d.ts.map +0 -1
- package/dist/to-capital-case.js +0 -2
- package/dist/to-capital-case.js.map +0 -1
- package/dist/to-constant-case.cjs +0 -1
- package/dist/to-constant-case.d.cts +0 -31
- package/dist/to-constant-case.d.cts.map +0 -1
- package/dist/to-constant-case.d.ts +0 -31
- package/dist/to-constant-case.d.ts.map +0 -1
- package/dist/to-constant-case.js +0 -2
- package/dist/to-constant-case.js.map +0 -1
- package/dist/to-no-case.cjs +0 -1
- package/dist/to-no-case.d.cts +0 -31
- package/dist/to-no-case.d.cts.map +0 -1
- package/dist/to-no-case.d.ts +0 -31
- package/dist/to-no-case.d.ts.map +0 -1
- package/dist/to-no-case.js +0 -2
- package/dist/to-no-case.js.map +0 -1
- package/dist/to-pascal-case.cjs +0 -1
- package/dist/to-pascal-case.d.cts +0 -32
- package/dist/to-pascal-case.d.cts.map +0 -1
- package/dist/to-pascal-case.d.ts +0 -32
- package/dist/to-pascal-case.d.ts.map +0 -1
- package/dist/to-pascal-case.js +0 -2
- package/dist/to-pascal-case.js.map +0 -1
- package/dist/to-pascal-snake-case.cjs +0 -1
- package/dist/to-pascal-snake-case.d.cts +0 -31
- package/dist/to-pascal-snake-case.d.cts.map +0 -1
- package/dist/to-pascal-snake-case.d.ts +0 -31
- package/dist/to-pascal-snake-case.d.ts.map +0 -1
- package/dist/to-pascal-snake-case.js +0 -2
- package/dist/to-pascal-snake-case.js.map +0 -1
- package/dist/to-sentence-case.cjs +0 -1
- package/dist/to-sentence-case.d.cts +0 -31
- package/dist/to-sentence-case.d.cts.map +0 -1
- package/dist/to-sentence-case.d.ts +0 -31
- package/dist/to-sentence-case.d.ts.map +0 -1
- package/dist/to-sentence-case.js +0 -2
- package/dist/to-sentence-case.js.map +0 -1
- package/dist/to-single-vYpRavjM.js.map +0 -1
- package/dist/to-string-C6_OnZ6e.d.ts.map +0 -1
- package/dist/to-string-Se4KcQka.d.cts.map +0 -1
- package/dist/to-train-case.cjs +0 -1
- package/dist/to-train-case.d.cts +0 -31
- package/dist/to-train-case.d.cts.map +0 -1
- package/dist/to-train-case.d.ts +0 -31
- package/dist/to-train-case.d.ts.map +0 -1
- package/dist/to-train-case.js +0 -2
- package/dist/to-train-case.js.map +0 -1
- package/dist/upsert-prop-P-aJDDII.d.cts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"funnel.lodash-debounce-with-cached-value.test.js","names":["cachedValue: ReturnType<F> | undefined"],"sources":["../src/funnel.lodash-debounce-with-cached-value.test.ts"],"sourcesContent":["/* eslint-disable no-nested-ternary */\n/* eslint-disable antfu/consistent-list-newline */\n/* eslint-disable ts/explicit-function-return-type, ts/no-explicit-any --\n * These aren't useful for a reference implementation for a legacy library!\n */\n\nimport { describe, expect, it, vi } from 'vitest';\nimport { constant } from './constant';\nimport { funnel } from './funnel';\nimport { identity } from './identity';\nimport { sleep } from './sleep';\n\n/**\n * A reference implementation of the Lodash `debounce` function using the\n * The `funnel` function. While migrating from Lodash you can copy this\n * function as-is into your codebase and use it as a drop-in replacement; but\n * we recommend eventually inlining the call to `funnel` so you can adjust the\n * function to your specific needs.\n *\n * This is a more complex implementation which respects Lodash capability to\n * track the return value of the callback function. In most cases you are more\n * likely to prefer the simpler reference implementation `debounce` which can\n * be found in the other test file.\n *\n * The following tests in this file are based on the Lodash tests for debounce.\n * They have been adapted to work with our testing framework, have been fixed\n * or expanded slightly were it felt necessary, and have been modernized for\n * better readability. The names of the test cases have been preserved to ease\n * comparing them to the original tests. Tests that are unrelated to the cache\n * capability have been removed to avoid duplication with the other test file.\n *\n * Note that this means that whenever Lodash offered a concrete spec, we made\n * sure our reference implementation respects it, but there might be untested\n * use-cases that would have differing runtime behaviors.\n *\n * @see Lodash Documentation: https://lodash.com/docs/4.17.15#debounce\n * @see Lodash Implementation: https://github.com/lodash/lodash/blob/4.17.21/lodash.js#L10372\n * @see Lodash Tests: https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L4187\n * @see Lodash Typing: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/common/function.d.ts#L374\n */\nfunction debounceWithCachedValue<F extends (...args: any) => any>(\n func: F,\n wait = 0,\n {\n leading = false,\n trailing = true,\n maxWait,\n }: {\n readonly leading?: boolean;\n readonly trailing?: boolean;\n readonly maxWait?: number;\n } = {}) {\n let cachedValue: ReturnType<F> | undefined;\n\n const { call, flush, cancel } = funnel(\n (args: Parameters<F>) => {\n if (!leading && !trailing) {\n /**\n * In Lodash you can disable both the trailing and leading edges of the\n * debounce window, effectively causing the function to never be\n * invoked. Our's uses the invokedAt enum exactly to prevent such a\n * situation; so to simulate Lodash we need to only pass the callback\n * when at least one of them is enabled.\n */\n return;\n }\n\n /**\n * Funnel provides more control over the args, but lodash simply passes\n * them through, to replicate this behavior we need to spread the args\n * array maintained via the reducer below.\n * Also, every time the function is invoked the cached value is updated.\n */\n cachedValue = func(...args) as ReturnType<F>;\n },\n {\n /**\n * Debounce stores the latest args it was called with for the next\n * invocation of the callback.\n */\n reducer: (_, ...args: Parameters<F>) => args,\n minQuietPeriodMs: wait,\n ...(maxWait !== undefined && { maxBurstDurationMs: maxWait }),\n ...(trailing\n ? leading\n ? { triggerAt: 'both' }\n : { triggerAt: 'end' }\n : { triggerAt: 'start' }),\n },\n );\n\n /**\n * Lodash uses a legacy JS-isms to attach helper functions to the main\n * callback of `debounce`. In our function we return a proper object where the\n * callback is one of the available properties. Here we destructure and then\n * reconstruct the object to fit the Lodash API.\n */\n return Object.assign(\n (...args: Parameters<F>) => {\n call(...args);\n return cachedValue;\n },\n {\n flush: () => {\n flush();\n return cachedValue;\n },\n\n cancel,\n },\n );\n}\n\n/**\n * We need some non-trivial duration to use in all our tests, to abstract the\n * actual chosen value we use this UnitOfTime (UT) constant. As long as it is a\n * positive integer, the actual value doesn't matter (but the larger it is,\n * the longer the tests would take to run); the value used by Lodash is 32.\n * The number is in milliseconds.\n */\nconst UT = 16;\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L4187', () => {\n it('should debounce a function', async () => {\n const mockFn = vi.fn<(x: string) => string>(identity());\n const debounced = debounceWithCachedValue(mockFn, UT);\n\n expect(debounced('a')).toBeUndefined();\n expect(debounced('b')).toBeUndefined();\n expect(debounced('c')).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(4 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n expect(debounced('d')).toBe('c');\n expect(debounced('e')).toBe('c');\n expect(debounced('f')).toBe('c');\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(4 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('subsequent debounced calls return the last `func` result', async () => {\n const debounced = debounceWithCachedValue(identity(), UT);\n debounced('a');\n await sleep(2 * UT);\n\n expect(debounced('b')).not.toBe('b');\n\n await sleep(2 * UT);\n\n expect(debounced('c')).not.toBe('c');\n });\n\n it('subsequent leading debounced calls return the last `func` result', async () => {\n const debounced = debounceWithCachedValue(identity(), UT, {\n leading: true,\n trailing: false,\n });\n\n expect(debounced('a')).toBe('a');\n expect(debounced('b')).toBe('a');\n\n await sleep(2 * UT);\n\n expect(debounced('c')).toBe('c');\n expect(debounced('d')).toBe('c');\n });\n\n it('should invoke the trailing call with the correct arguments and `this` binding', async () => {\n const DATA = {};\n const mockFn = vi.fn<(a: object, b: string) => boolean>(constant(false));\n\n /**\n * In Lodash the test uses both `leading` and `trailing` timing options\n * for this test, but it only works because the `leading` option in Lodash\n * runs within the same execution frame as the call to the debouncer; the\n * Lodash test also passes when the `leading` option is removed. For our\n * implementation the \"leading\" option is delayed to the next execution\n * frame, which, when used together with `maxWait` would cause the debouncer\n * to see a \"quiet window\" and trigger an additional invocation of the\n * mockFn, and the test to fail.\n */\n const debounced = debounceWithCachedValue(mockFn, UT, { maxWait: 2 * UT });\n\n while (debounced(DATA, 'a') ?? true) {\n // eslint-disable-next-line no-await-in-loop -- We sleep to yield execution so that the timeouts in the debouncer have a chance to run.\n await sleep(0);\n }\n await sleep(2 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n expect(mockFn).toHaveBeenLastCalledWith(DATA, 'a');\n });\n});\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038', () => {\n it('should reset `lastCalled` after cancelling', async () => {\n let callCount = 0;\n const debounced = debounceWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: true },\n );\n\n expect(debounced()).toBe(1);\n\n debounced.cancel();\n\n expect(debounced()).toBe(2);\n\n debounced();\n await sleep(2 * UT);\n\n expect(callCount).toBe(3);\n });\n\n it('should support flushing delayed calls', async () => {\n let callCount = 0;\n const debounced = debounceWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: false },\n );\n debounced();\n\n expect(debounced.flush()).toBe(1);\n\n await sleep(2 * UT);\n\n expect(callCount).toBe(1);\n });\n\n it('should noop `cancel` and `flush` when nothing is queued', async () => {\n const mockFn = vi.fn<() => string>(constant('hello'));\n const debounced = debounceWithCachedValue(mockFn, UT);\n debounced.cancel();\n\n expect(debounced.flush()).toBeUndefined();\n\n await sleep(2 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n });\n});\n\ndescribe('features not tested by Lodash', () => {\n it('does nothing when neither leading nor trailing are enabled', async () => {\n const debounced = debounceWithCachedValue(identity(), UT, {\n leading: false,\n trailing: false,\n });\n\n expect(debounced('hello')).toBeUndefined();\n expect(debounced('world')).toBeUndefined();\n\n await sleep(4 * UT);\n\n expect(debounced('goodbye')).toBeUndefined();\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"funnel.lodash-debounce-with-cached-value.test.js","names":["cachedValue: ReturnType<F> | undefined"],"sources":["../src/funnel.lodash-debounce-with-cached-value.test.ts"],"sourcesContent":["/* eslint-disable no-nested-ternary */\n\n/* eslint-disable ts/explicit-function-return-type --\n * These aren't useful for a reference implementation for a legacy library!\n */\n\nimport type { StrictFunction } from './internal/types/strict-function';\nimport { describe, expect, it, vi } from 'vitest';\nimport { constant } from './constant';\nimport { funnel } from './funnel';\nimport { identity } from './identity';\nimport { sleep } from './sleep';\n\n/**\n * A reference implementation of the Lodash `debounce` function using the\n * The `funnel` function. While migrating from Lodash you can copy this\n * function as-is into your codebase and use it as a drop-in replacement; but\n * we recommend eventually inlining the call to `funnel` so you can adjust the\n * function to your specific needs.\n *\n * This is a more complex implementation which respects Lodash capability to\n * track the return value of the callback function. In most cases you are more\n * likely to prefer the simpler reference implementation `debounce` which can\n * be found in the other test file.\n *\n * The following tests in this file are based on the Lodash tests for debounce.\n * They have been adapted to work with our testing framework, have been fixed\n * or expanded slightly were it felt necessary, and have been modernized for\n * better readability. The names of the test cases have been preserved to ease\n * comparing them to the original tests. Tests that are unrelated to the cache\n * capability have been removed to avoid duplication with the other test file.\n *\n * Note that this means that whenever Lodash offered a concrete spec, we made\n * sure our reference implementation respects it, but there might be untested\n * use-cases that would have differing runtime behaviors.\n *\n * @see Lodash Documentation: https://lodash.com/docs/4.17.15#debounce\n * @see Lodash Implementation: https://github.com/lodash/lodash/blob/4.17.21/lodash.js#L10372\n * @see Lodash Tests: https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L4187\n * @see Lodash Typing: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/common/function.d.ts#L374\n */\nfunction debounceWithCachedValue<F extends StrictFunction>(\n func: F,\n wait = 0,\n {\n leading = false,\n trailing = true,\n maxWait,\n }: {\n readonly leading?: boolean;\n readonly trailing?: boolean;\n readonly maxWait?: number;\n } = {},\n) {\n let cachedValue: ReturnType<F> | undefined;\n\n const { call, flush, cancel } = funnel(\n (args: Parameters<F>) => {\n if (!leading && !trailing) {\n /**\n * In Lodash you can disable both the trailing and leading edges of the\n * debounce window, effectively causing the function to never be\n * invoked. Our's uses the invokedAt enum exactly to prevent such a\n * situation; so to simulate Lodash we need to only pass the callback\n * when at least one of them is enabled.\n */\n return;\n }\n\n /**\n * Funnel provides more control over the args, but lodash simply passes\n * them through, to replicate this behavior we need to spread the args\n * array maintained via the reducer below.\n * Also, every time the function is invoked the cached value is updated.\n */\n // @ts-expect-error [ts2345, ts2322] -- TypeScript infers the generic sub-\n // types too eagerly, making itself blind to the fact that the types\n // match here.\n cachedValue = func(...args) as ReturnType<F>;\n },\n {\n /**\n * Debounce stores the latest args it was called with for the next\n * invocation of the callback.\n */\n reducer: (_, ...args: Parameters<F>) => args,\n minQuietPeriodMs: wait,\n ...(maxWait !== undefined && { maxBurstDurationMs: maxWait }),\n ...(trailing\n ? leading\n ? { triggerAt: 'both' }\n : { triggerAt: 'end' }\n : { triggerAt: 'start' }),\n },\n );\n\n /**\n * Lodash uses a legacy JS-isms to attach helper functions to the main\n * callback of `debounce`. In our function we return a proper object where the\n * callback is one of the available properties. Here we destructure and then\n * reconstruct the object to fit the Lodash API.\n */\n return Object.assign(\n (...args: Parameters<F>) => {\n call(...args);\n return cachedValue;\n },\n {\n flush: () => {\n flush();\n return cachedValue;\n },\n\n cancel,\n },\n );\n}\n\n/**\n * We need some non-trivial duration to use in all our tests, to abstract the\n * actual chosen value we use this UnitOfTime (UT) constant. As long as it is a\n * positive integer, the actual value doesn't matter (but the larger it is,\n * the longer the tests would take to run); the value used by Lodash is 32.\n * The number is in milliseconds.\n */\nconst UT = 16;\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L4187', () => {\n it('should debounce a function', async () => {\n const mockFn = vi.fn<(x: string) => string>(identity());\n const debounced = debounceWithCachedValue(mockFn, UT);\n\n expect(debounced('a')).toBeUndefined();\n expect(debounced('b')).toBeUndefined();\n expect(debounced('c')).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(4 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n expect(debounced('d')).toBe('c');\n expect(debounced('e')).toBe('c');\n expect(debounced('f')).toBe('c');\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(4 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('subsequent debounced calls return the last `func` result', async () => {\n const debounced = debounceWithCachedValue(identity(), UT);\n debounced('a');\n await sleep(2 * UT);\n\n expect(debounced('b')).not.toBe('b');\n\n await sleep(2 * UT);\n\n expect(debounced('c')).not.toBe('c');\n });\n\n it('subsequent leading debounced calls return the last `func` result', async () => {\n const debounced = debounceWithCachedValue(identity(), UT, {\n leading: true,\n trailing: false,\n });\n\n expect(debounced('a')).toBe('a');\n expect(debounced('b')).toBe('a');\n\n await sleep(2 * UT);\n\n expect(debounced('c')).toBe('c');\n expect(debounced('d')).toBe('c');\n });\n\n it('should invoke the trailing call with the correct arguments and `this` binding', async () => {\n const DATA = {};\n const mockFn = vi.fn<(a: object, b: string) => boolean>(constant(false));\n\n /**\n * In Lodash the test uses both `leading` and `trailing` timing options\n * for this test, but it only works because the `leading` option in Lodash\n * runs within the same execution frame as the call to the debouncer; the\n * Lodash test also passes when the `leading` option is removed. For our\n * implementation the \"leading\" option is delayed to the next execution\n * frame, which, when used together with `maxWait` would cause the debouncer\n * to see a \"quiet window\" and trigger an additional invocation of the\n * mockFn, and the test to fail.\n */\n const debounced = debounceWithCachedValue(mockFn, UT, { maxWait: 2 * UT });\n\n while (debounced(DATA, 'a') ?? true) {\n // eslint-disable-next-line no-await-in-loop -- We sleep to yield execution so that the timeouts in the debouncer have a chance to run.\n await sleep(0);\n }\n await sleep(2 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n expect(mockFn).toHaveBeenLastCalledWith(DATA, 'a');\n });\n});\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038', () => {\n it('should reset `lastCalled` after cancelling', async () => {\n let callCount = 0;\n const debounced = debounceWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: true },\n );\n\n expect(debounced()).toBe(1);\n\n debounced.cancel();\n\n expect(debounced()).toBe(2);\n\n debounced();\n await sleep(2 * UT);\n\n expect(callCount).toBe(3);\n });\n\n it('should support flushing delayed calls', async () => {\n let callCount = 0;\n const debounced = debounceWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: false },\n );\n debounced();\n\n expect(debounced.flush()).toBe(1);\n\n await sleep(2 * UT);\n\n expect(callCount).toBe(1);\n });\n\n it('should noop `cancel` and `flush` when nothing is queued', async () => {\n const mockFn = vi.fn<() => string>(constant('hello'));\n const debounced = debounceWithCachedValue(mockFn, UT);\n debounced.cancel();\n\n expect(debounced.flush()).toBeUndefined();\n\n await sleep(2 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n });\n});\n\ndescribe('features not tested by Lodash', () => {\n it('does nothing when neither leading nor trailing are enabled', async () => {\n const debounced = debounceWithCachedValue(identity(), UT, {\n leading: false,\n trailing: false,\n });\n\n expect(debounced('hello')).toBeUndefined();\n expect(debounced('world')).toBeUndefined();\n\n await sleep(4 * UT);\n\n expect(debounced('goodbye')).toBeUndefined();\n });\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./dist-
|
|
1
|
+
const e=require(`./dist-8XtUY3ad.cjs`),t=require(`./funnel.cjs`),n=require(`./sleep.cjs`);function r(e,n=0,{leading:r=!1,trailing:i=!0,maxWait:a}={}){let{call:o,isIdle:s,...c}=t.funnel(t=>{!i&&!r||e(...t)},{reducer:(e,...t)=>t,minQuietPeriodMs:n,...a!==void 0&&{maxBurstDurationMs:a},...i?r?{triggerAt:`both`}:{triggerAt:`end`}:{triggerAt:`start`}});return Object.assign(o,c)}const i=16;e.i(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L4187`,()=>{e.a(`should debounce a function`,async()=>{let t=e.r.fn(),i=r(t,16);i(`a`),i(`b`),i(`c`),e.n(t).toHaveBeenCalledTimes(0),await n.sleep(64),e.n(t).toHaveBeenCalledExactlyOnceWith(`c`),i(`d`),i(`e`),i(`f`),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(64),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should not immediately call `func` when `wait` is `0`",async()=>{let t=e.r.fn(),n=r(t,0);n(),n(),e.n(t).toHaveBeenCalledTimes(0),await a(),e.n(t).toHaveBeenCalledTimes(1)}),e.a(`should apply default options`,async()=>{let t=e.r.fn();r(t,16,{})(),e.n(t).toHaveBeenCalledTimes(0),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(1)}),e.a("should support a `leading` option",async()=>{let t=e.r.fn(),i=e.r.fn(),a=r(t,16,{leading:!0,trailing:!1}),o=r(i,16,{leading:!0,trailing:!0});a(),e.n(t).toHaveBeenCalledTimes(1),o(),o(),e.n(i).toHaveBeenCalledTimes(1),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(1),e.n(i).toHaveBeenCalledTimes(2),a(),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should support a `trailing` option",async()=>{let t=e.r.fn(),i=e.r.fn(),a=r(t,16,{trailing:!0}),o=r(i,16,{trailing:!1});a(),e.n(t).toHaveBeenCalledTimes(0),o(),e.n(i).toHaveBeenCalledTimes(0),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(1),e.n(i).toHaveBeenCalledTimes(0)}),e.a("should support a `maxWait` option",async()=>{let t=e.r.fn(),i=r(t,16,{maxWait:32});i(),i(),e.n(t).toHaveBeenCalledTimes(0),await n.sleep(64),e.n(t).toHaveBeenCalledTimes(1),i(),i(),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(64),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should support `maxWait` in a tight loop",async()=>{let t=e.r.fn(),n=e.r.fn(),i=r(t,32,{maxWait:64}),o=r(n,48),s=Date.now()+160;for(;Date.now()<s;)i(),o();e.n(n).toHaveBeenCalledTimes(0),e.n(t).toHaveBeenCalledTimes(0),await a(),e.n(n).toHaveBeenCalledTimes(0),e.n(t).toHaveBeenCalledTimes(1)}),e.a("should queue a trailing call for subsequent debounced calls after `maxWait`",async()=>{let t=e.r.fn(),i=r(t,96,{maxWait:96});i(),await n.sleep(5.5*16),i(),await n.sleep(.5*16),i(),await n.sleep(.5*16),i(),await n.sleep(9.5*16),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should cancel `maxDelayed` when `delayed` is invoked",async()=>{let t=e.r.fn(),i=r(t,16,{maxWait:32});i(),await n.sleep(64),i(),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should invoke the trailing call with the correct arguments and `this` binding",async()=>{let t=e.r.fn(),i={},o=r(t,16,{leading:!0,maxWait:32});for(;t.mock.calls.length<2;)o(i,`a`),await a();await n.sleep(32),e.n(t).toHaveBeenCalledTimes(2),e.n(t).toHaveBeenLastCalledWith(i,`a`)})}),e.i(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038`,()=>{e.a("should use a default `wait` of `0`",async()=>{let t=e.r.fn(),i=r(t);i(),await n.sleep(16),i(),e.n(t).toHaveBeenCalledTimes(1)}),e.a(`supports recursive calls`,async()=>{let t=[],i=[`a`,`b`,`c`],a=r(e=>{t.push(e);let n=i.shift();n!==void 0&&a(n)},16);a(i.shift()),e.n(t).toStrictEqual([]),await n.sleep(128),e.n(t).toStrictEqual([`a`,`b`,`c`])}),e.a(`should support cancelling delayed calls`,async()=>{let t=e.r.fn(),i=r(t,16,{leading:!1});i(),i.cancel(),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(0)}),e.a("should reset `lastCalled` after cancelling",async()=>{let t=e.r.fn(),i=r(t,16,{leading:!0});i(),e.n(t).toHaveBeenCalledTimes(1),i.cancel(),i(),e.n(t).toHaveBeenCalledTimes(2),i(),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(3)}),e.a(`should support flushing delayed calls`,async()=>{let t=e.r.fn(),i=r(t,16,{leading:!1});i(),i.flush(),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(1)}),e.a("should noop `cancel` and `flush` when nothing is queued",async()=>{let t=e.r.fn(),i=r(t,16);i.cancel(),i.flush(),e.n(t).toHaveBeenCalledTimes(0),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(0)})});async function a(){return await n.sleep(0)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,i as t,n,r}from"./dist-
|
|
1
|
+
import{a as e,i as t,n,r}from"./dist-Bd1vawFi.js";import{funnel as i}from"./funnel.js";import{sleep as a}from"./sleep.js";function o(e,t=0,{leading:n=!1,trailing:r=!0,maxWait:a}={}){let{call:o,isIdle:s,...c}=i(t=>{!r&&!n||e(...t)},{reducer:(e,...t)=>t,minQuietPeriodMs:t,...a!==void 0&&{maxBurstDurationMs:a},...r?n?{triggerAt:`both`}:{triggerAt:`end`}:{triggerAt:`start`}});return Object.assign(o,c)}t(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L4187`,()=>{e(`should debounce a function`,async()=>{let e=r.fn(),t=o(e,16);t(`a`),t(`b`),t(`c`),n(e).toHaveBeenCalledTimes(0),await a(64),n(e).toHaveBeenCalledExactlyOnceWith(`c`),t(`d`),t(`e`),t(`f`),n(e).toHaveBeenCalledTimes(1),await a(64),n(e).toHaveBeenCalledTimes(2)}),e("should not immediately call `func` when `wait` is `0`",async()=>{let e=r.fn(),t=o(e,0);t(),t(),n(e).toHaveBeenCalledTimes(0),await s(),n(e).toHaveBeenCalledTimes(1)}),e(`should apply default options`,async()=>{let e=r.fn();o(e,16,{})(),n(e).toHaveBeenCalledTimes(0),await a(32),n(e).toHaveBeenCalledTimes(1)}),e("should support a `leading` option",async()=>{let e=r.fn(),t=r.fn(),i=o(e,16,{leading:!0,trailing:!1}),s=o(t,16,{leading:!0,trailing:!0});i(),n(e).toHaveBeenCalledTimes(1),s(),s(),n(t).toHaveBeenCalledTimes(1),await a(32),n(e).toHaveBeenCalledTimes(1),n(t).toHaveBeenCalledTimes(2),i(),n(e).toHaveBeenCalledTimes(2)}),e("should support a `trailing` option",async()=>{let e=r.fn(),t=r.fn(),i=o(e,16,{trailing:!0}),s=o(t,16,{trailing:!1});i(),n(e).toHaveBeenCalledTimes(0),s(),n(t).toHaveBeenCalledTimes(0),await a(32),n(e).toHaveBeenCalledTimes(1),n(t).toHaveBeenCalledTimes(0)}),e("should support a `maxWait` option",async()=>{let e=r.fn(),t=o(e,16,{maxWait:32});t(),t(),n(e).toHaveBeenCalledTimes(0),await a(64),n(e).toHaveBeenCalledTimes(1),t(),t(),n(e).toHaveBeenCalledTimes(1),await a(64),n(e).toHaveBeenCalledTimes(2)}),e("should support `maxWait` in a tight loop",async()=>{let e=r.fn(),t=r.fn(),i=o(e,32,{maxWait:64}),a=o(t,48),c=Date.now()+160;for(;Date.now()<c;)i(),a();n(t).toHaveBeenCalledTimes(0),n(e).toHaveBeenCalledTimes(0),await s(),n(t).toHaveBeenCalledTimes(0),n(e).toHaveBeenCalledTimes(1)}),e("should queue a trailing call for subsequent debounced calls after `maxWait`",async()=>{let e=r.fn(),t=o(e,96,{maxWait:96});t(),await a(5.5*16),t(),await a(.5*16),t(),await a(.5*16),t(),await a(9.5*16),n(e).toHaveBeenCalledTimes(2)}),e("should cancel `maxDelayed` when `delayed` is invoked",async()=>{let e=r.fn(),t=o(e,16,{maxWait:32});t(),await a(64),t(),n(e).toHaveBeenCalledTimes(1),await a(32),n(e).toHaveBeenCalledTimes(2)}),e("should invoke the trailing call with the correct arguments and `this` binding",async()=>{let e=r.fn(),t={},i=o(e,16,{leading:!0,maxWait:32});for(;e.mock.calls.length<2;)i(t,`a`),await s();await a(32),n(e).toHaveBeenCalledTimes(2),n(e).toHaveBeenLastCalledWith(t,`a`)})}),t(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038`,()=>{e("should use a default `wait` of `0`",async()=>{let e=r.fn(),t=o(e);t(),await a(16),t(),n(e).toHaveBeenCalledTimes(1)}),e(`supports recursive calls`,async()=>{let e=[],t=[`a`,`b`,`c`],r=o(n=>{e.push(n);let i=t.shift();i!==void 0&&r(i)},16);r(t.shift()),n(e).toStrictEqual([]),await a(128),n(e).toStrictEqual([`a`,`b`,`c`])}),e(`should support cancelling delayed calls`,async()=>{let e=r.fn(),t=o(e,16,{leading:!1});t(),t.cancel(),await a(32),n(e).toHaveBeenCalledTimes(0)}),e("should reset `lastCalled` after cancelling",async()=>{let e=r.fn(),t=o(e,16,{leading:!0});t(),n(e).toHaveBeenCalledTimes(1),t.cancel(),t(),n(e).toHaveBeenCalledTimes(2),t(),await a(32),n(e).toHaveBeenCalledTimes(3)}),e(`should support flushing delayed calls`,async()=>{let e=r.fn(),t=o(e,16,{leading:!1});t(),t.flush(),n(e).toHaveBeenCalledTimes(1),await a(32),n(e).toHaveBeenCalledTimes(1)}),e("should noop `cancel` and `flush` when nothing is queued",async()=>{let e=r.fn(),t=o(e,16);t.cancel(),t.flush(),n(e).toHaveBeenCalledTimes(0),await a(32),n(e).toHaveBeenCalledTimes(0)})});async function s(){return await a(0)}
|
|
2
2
|
//# sourceMappingURL=funnel.lodash-debounce.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./dist-
|
|
1
|
+
const e=require(`./dist-8XtUY3ad.cjs`),t=require(`./constant.cjs`),n=require(`./funnel.cjs`),r=require(`./identity.cjs`),i=require(`./sleep.cjs`);function a(e,t=0,{leading:r=!0,trailing:i=!0}={}){let a,{call:o,flush:s,cancel:c}=n.funnel(t=>{!r&&!i||(a=e(...t))},{reducer:(e,...t)=>t,minQuietPeriodMs:t,maxBurstDurationMs:t,...i?r?{triggerAt:`both`}:{triggerAt:`end`}:{triggerAt:`start`}});return Object.assign((...e)=>(o(...e),a),{flush:()=>(s(),a),cancel:c})}const o=16;e.i(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768`,()=>{e.a(`subsequent calls should return the result of the first call`,async()=>{let t=a(r.identity(),16);e.n(t(`a`)).toBe(`a`),e.n(t(`b`)).toBe(`a`),await i.sleep(32);let n=t(`c`),o=t(`d`);e.n(n).not.toBe(`a`),e.n(n).toBeDefined(),e.n(o).not.toBe(`d`),e.n(o).toBeDefined()}),e.a("should support a `leading` option",()=>{let t=a(r.identity(),16,{leading:!0}),n=a(r.identity(),16,{leading:!1});e.n(t(`a`)).toBe(`a`),e.n(n(`a`)).toBeUndefined()}),e.a("should support a `trailing` option",async()=>{let t=e.r.fn(r.identity()),n=e.r.fn(r.identity()),o=a(t,32,{trailing:!0}),s=a(n,32,{trailing:!1});e.n(o(`a`)).toBe(`a`),e.n(o(`b`)).toBe(`a`),e.n(s(`a`)).toBe(`a`),e.n(s(`b`)).toBe(`a`),await i.sleep(128),e.n(t).toHaveBeenCalledTimes(2),e.n(n).toHaveBeenCalledTimes(1)})}),e.i(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038`,()=>{e.a("should reset `lastCalled` after cancelling",async()=>{let t=0,n=a(()=>(t+=1,t),16,{leading:!0});e.n(n()).toBe(1),n.cancel(),e.n(n()).toBe(2),n(),await i.sleep(32),e.n(t).toBe(3)}),e.a(`should support flushing delayed calls`,async()=>{let t=0,n=a(()=>(t+=1,t),16,{leading:!1});n(),e.n(n.flush()).toBe(1),await i.sleep(32),e.n(t).toBe(1)}),e.a("should noop `cancel` and `flush` when nothing is queued",async()=>{let n=e.r.fn(t.constant(`hello`)),r=a(n,16);r.cancel(),e.n(r.flush()).toBeUndefined(),await i.sleep(32),e.n(n).toHaveBeenCalledTimes(0)})}),e.i(`features not tested by Lodash`,()=>{e.a(`does nothing when neither leading nor trailing are enabled`,async()=>{let t=a(r.identity(),16,{leading:!1,trailing:!1});e.n(t(`hello`)).toBeUndefined(),e.n(t(`world`)).toBeUndefined(),await i.sleep(64),e.n(t(`goodbye`)).toBeUndefined()})});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{constant as e}from"./constant.js";import{a as t,i as n,n as r,r as i}from"./dist-Bd1vawFi.js";import{funnel as a}from"./funnel.js";import{identity as o}from"./identity.js";import{sleep as s}from"./sleep.js";function c(e,t=0,{leading:n=!0,trailing:r=!0}={}){let i,{call:o,flush:s,cancel:c}=a(t=>{!n&&!r||(i=e(...t))},{reducer:(e,...t)=>t,minQuietPeriodMs:t,maxBurstDurationMs:t,...r?n?{triggerAt:`both`}:{triggerAt:`end`}:{triggerAt:`start`}});return Object.assign((...e)=>(o(...e),i),{flush:()=>(s(),i),cancel:c})}n(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768`,()=>{t(`subsequent calls should return the result of the first call`,async()=>{let e=c(o(),16);r(e(`a`)).toBe(`a`),r(e(`b`)).toBe(`a`),await s(32);let t=e(`c`),n=e(`d`);r(t).not.toBe(`a`),r(t).toBeDefined(),r(n).not.toBe(`d`),r(n).toBeDefined()}),t("should support a `leading` option",()=>{let e=c(o(),16,{leading:!0}),t=c(o(),16,{leading:!1});r(e(`a`)).toBe(`a`),r(t(`a`)).toBeUndefined()}),t("should support a `trailing` option",async()=>{let e=i.fn(o()),t=i.fn(o()),n=c(e,32,{trailing:!0}),a=c(t,32,{trailing:!1});r(n(`a`)).toBe(`a`),r(n(`b`)).toBe(`a`),r(a(`a`)).toBe(`a`),r(a(`b`)).toBe(`a`),await s(128),r(e).toHaveBeenCalledTimes(2),r(t).toHaveBeenCalledTimes(1)})}),n(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038`,()=>{t("should reset `lastCalled` after cancelling",async()=>{let e=0,t=c(()=>(e+=1,e),16,{leading:!0});r(t()).toBe(1),t.cancel(),r(t()).toBe(2),t(),await s(32),r(e).toBe(3)}),t(`should support flushing delayed calls`,async()=>{let e=0,t=c(()=>(e+=1,e),16,{leading:!1});t(),r(t.flush()).toBe(1),await s(32),r(e).toBe(1)}),t("should noop `cancel` and `flush` when nothing is queued",async()=>{let t=i.fn(e(`hello`)),n=c(t,16);n.cancel(),r(n.flush()).toBeUndefined(),await s(32),r(t).toHaveBeenCalledTimes(0)})}),n(`features not tested by Lodash`,()=>{t(`does nothing when neither leading nor trailing are enabled`,async()=>{let e=c(o(),16,{leading:!1,trailing:!1});r(e(`hello`)).toBeUndefined(),r(e(`world`)).toBeUndefined(),await s(64),r(e(`goodbye`)).toBeUndefined()})});
|
|
2
2
|
//# sourceMappingURL=funnel.lodash-throttle-with-cached-value.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"funnel.lodash-throttle-with-cached-value.test.js","names":["cachedValue: ReturnType<F> | undefined"],"sources":["../src/funnel.lodash-throttle-with-cached-value.test.ts"],"sourcesContent":["/* eslint-disable no-nested-ternary, function-paren-newline, ts/explicit-function-return-type, ts/no-explicit-any --\n * These aren't useful for a reference implementation for a legacy library!\n */\n\nimport { describe, expect, it, vi } from 'vitest';\nimport { constant } from './constant';\nimport { funnel } from './funnel';\nimport { identity } from './identity';\nimport { sleep } from './sleep';\n\n/**\n * A reference implementation of the Lodash `throttle` function using the\n * Our `funnel` function. While migrating from Lodash you can copy this\n * function as-is into your codebase and use it as a drop-in replacement; but\n * we recommend eventually inlining the call to `funnel` so you can adjust the\n * function to your specific needs.\n *\n * This is a more complex implementation which respects Lodash capability to\n * track the return value of the callback function. In most cases you are more\n * likely to prefer the simpler reference implementation `throttle` which can\n * be found in the other test file.\n *\n * The following tests in this file are based on the Lodash tests for throttle.\n * They have been adapted to work with our testing framework, have been fixed\n * or expanded slightly were it felt necessary, and have been modernized for\n * better readability. The names of the test cases have been preserved to ease\n * comparing them to the original tests. Tests that are unrelated to the cache\n * capability have been removed to avoid duplication with the other test file.\n *\n * Note that this means that whenever Lodash offered a concrete spec, we made\n * sure our reference implementation respects it, but there might be untested\n * use-cases that would have differing runtime behaviors.\n *\n * @see Lodash Documentation: https://lodash.com/docs/4.17.15#throttle\n * @see Lodash Implementation: https://github.com/lodash/lodash/blob/4.17.21/lodash.js#L10965\n * @see Lodash Tests: https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768\n * @see Lodash Typing: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/common/function.d.ts#L1347\n */\nfunction throttleWithCachedValue<F extends (...args: any) => any>(\n func: F,\n wait = 0,\n {\n leading = true,\n trailing = true,\n }: { readonly leading?: boolean; readonly trailing?: boolean } = {},\n) {\n let cachedValue: ReturnType<F> | undefined;\n\n const { call, flush, cancel } = funnel(\n (args: Parameters<F>) => {\n if (!leading && !trailing) {\n /**\n * In Lodash you can disable both the trailing and leading edges of the\n * throttle window, effectively causing the function to never be\n * invoked. Our's uses the invokedAt enum exactly to prevent such a\n * situation; so to simulate Lodash we need to only pass the callback\n * when at least one of them is enabled.\n */\n return;\n }\n\n /**\n * Funnel provides more control over the args, but lodash simply passes\n * them through, to replicate this behavior we need to spread the args\n * array maintained via the reducer below.\n * Also, every time the function is invoked the cached value is updated.\n */\n cachedValue = func(...args) as ReturnType<F>;\n },\n {\n // Throttle stores the latest args it was called with for the next invocation of the callback.\n reducer: (_, ...args: Parameters<F>) => args,\n minQuietPeriodMs: wait,\n maxBurstDurationMs: wait,\n ...(trailing\n ? leading\n ? { triggerAt: 'both' }\n : { triggerAt: 'end' }\n : { triggerAt: 'start' }),\n },\n );\n\n /**\n * Lodash uses a legacy JS-isms to attach helper functions to the main\n * callback of `throttle`. In our's we return a proper object where the\n * callback is one of the available properties. Here we destructure and then\n * reconstruct the object to fit the Lodash API.\n */\n return Object.assign(\n (...args: Parameters<F>) => {\n call(...args);\n return cachedValue;\n },\n {\n flush: () => {\n flush();\n return cachedValue;\n },\n\n cancel,\n },\n );\n}\n\n/**\n * We need some non-trivial duration to use in all our tests, to abstract the\n * actual chosen value we use this UnitOfTime (UT) constant. As long as it is a\n * positive integer, the actual value doesn't matter (but the larger it is,\n * the longer the tests would take to run); the value used by Lodash is 32.\n * The number is in milliseconds.\n */\nconst UT = 16;\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768', () => {\n it('subsequent calls should return the result of the first call', async () => {\n const throttled = throttleWithCachedValue(identity(), UT);\n\n expect(throttled('a')).toBe('a');\n expect(throttled('b')).toBe('a');\n\n await sleep(2 * UT);\n const resultC = throttled('c');\n const resultD = throttled('d');\n\n expect(resultC).not.toBe('a');\n expect(resultC).toBeDefined();\n expect(resultD).not.toBe('d');\n expect(resultD).toBeDefined();\n });\n\n it('should support a `leading` option', () => {\n const withLeading = throttleWithCachedValue(identity(), UT, {\n leading: true,\n });\n const withoutLeading = throttleWithCachedValue(identity(), UT, {\n leading: false,\n });\n\n expect(withLeading('a')).toBe('a');\n expect(withoutLeading('a')).toBeUndefined();\n });\n\n it('should support a `trailing` option', async () => {\n const mockWith = vi.fn<<T>(x: T) => T>(identity());\n const mockWithout = vi.fn<<T>(x: T) => T>(identity());\n const withTrailing = throttleWithCachedValue(mockWith, 2 * UT, {\n trailing: true,\n });\n const withoutTrailing = throttleWithCachedValue(mockWithout, 2 * UT, {\n trailing: false,\n });\n\n expect(withTrailing('a')).toBe('a');\n expect(withTrailing('b')).toBe('a');\n expect(withoutTrailing('a')).toBe('a');\n expect(withoutTrailing('b')).toBe('a');\n\n await sleep(8 * UT);\n\n expect(mockWith).toHaveBeenCalledTimes(2);\n expect(mockWithout).toHaveBeenCalledTimes(1);\n });\n});\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038', () => {\n it('should reset `lastCalled` after cancelling', async () => {\n let callCount = 0;\n const throttled = throttleWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: true },\n );\n\n expect(throttled()).toBe(1);\n\n throttled.cancel();\n\n expect(throttled()).toBe(2);\n\n throttled();\n await sleep(2 * UT);\n\n expect(callCount).toBe(3);\n });\n\n it('should support flushing delayed calls', async () => {\n let callCount = 0;\n const throttled = throttleWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: false },\n );\n throttled();\n\n expect(throttled.flush()).toBe(1);\n\n await sleep(2 * UT);\n\n expect(callCount).toBe(1);\n });\n\n it('should noop `cancel` and `flush` when nothing is queued', async () => {\n const mockFn = vi.fn<() => string>(constant('hello'));\n const throttled = throttleWithCachedValue(mockFn, UT);\n throttled.cancel();\n\n expect(throttled.flush()).toBeUndefined();\n\n await sleep(2 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n });\n});\n\ndescribe('features not tested by Lodash', () => {\n it('does nothing when neither leading nor trailing are enabled', async () => {\n const throttled = throttleWithCachedValue(identity(), UT, {\n leading: false,\n trailing: false,\n });\n\n expect(throttled('hello')).toBeUndefined();\n expect(throttled('world')).toBeUndefined();\n\n await sleep(4 * UT);\n\n expect(throttled('goodbye')).toBeUndefined();\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"funnel.lodash-throttle-with-cached-value.test.js","names":["cachedValue: ReturnType<F> | undefined"],"sources":["../src/funnel.lodash-throttle-with-cached-value.test.ts"],"sourcesContent":["/* eslint-disable no-nested-ternary, ts/explicit-function-return-type --\n * These aren't useful for a reference implementation for a legacy library!\n */\n\nimport type { StrictFunction } from './internal/types/strict-function';\nimport { describe, expect, it, vi } from 'vitest';\nimport { constant } from './constant';\nimport { funnel } from './funnel';\nimport { identity } from './identity';\nimport { sleep } from './sleep';\n\n/**\n * A reference implementation of the Lodash `throttle` function using the\n * Our `funnel` function. While migrating from Lodash you can copy this\n * function as-is into your codebase and use it as a drop-in replacement; but\n * we recommend eventually inlining the call to `funnel` so you can adjust the\n * function to your specific needs.\n *\n * This is a more complex implementation which respects Lodash capability to\n * track the return value of the callback function. In most cases you are more\n * likely to prefer the simpler reference implementation `throttle` which can\n * be found in the other test file.\n *\n * The following tests in this file are based on the Lodash tests for throttle.\n * They have been adapted to work with our testing framework, have been fixed\n * or expanded slightly were it felt necessary, and have been modernized for\n * better readability. The names of the test cases have been preserved to ease\n * comparing them to the original tests. Tests that are unrelated to the cache\n * capability have been removed to avoid duplication with the other test file.\n *\n * Note that this means that whenever Lodash offered a concrete spec, we made\n * sure our reference implementation respects it, but there might be untested\n * use-cases that would have differing runtime behaviors.\n *\n * @see Lodash Documentation: https://lodash.com/docs/4.17.15#throttle\n * @see Lodash Implementation: https://github.com/lodash/lodash/blob/4.17.21/lodash.js#L10965\n * @see Lodash Tests: https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768\n * @see Lodash Typing: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/common/function.d.ts#L1347\n */\nfunction throttleWithCachedValue<F extends StrictFunction>(\n func: F,\n wait = 0,\n {\n leading = true,\n trailing = true,\n }: { readonly leading?: boolean; readonly trailing?: boolean } = {},\n) {\n let cachedValue: ReturnType<F> | undefined;\n\n const { call, flush, cancel } = funnel(\n (args: Parameters<F>) => {\n if (!leading && !trailing) {\n /**\n * In Lodash you can disable both the trailing and leading edges of the\n * throttle window, effectively causing the function to never be\n * invoked. Our's uses the invokedAt enum exactly to prevent such a\n * situation; so to simulate Lodash we need to only pass the callback\n * when at least one of them is enabled.\n */\n return;\n }\n\n /**\n * Funnel provides more control over the args, but lodash simply passes\n * them through, to replicate this behavior we need to spread the args\n * array maintained via the reducer below.\n * Also, every time the function is invoked the cached value is updated.\n */\n // @ts-expect-error [ts2345, ts2322] -- TypeScript infers the generic sub-\n // types too eagerly, making itself blind to the fact that the types\n // match here.\n cachedValue = func(...args) as ReturnType<F>;\n },\n {\n // Throttle stores the latest args it was called with for the next invocation of the callback.\n reducer: (_, ...args: Parameters<F>) => args,\n minQuietPeriodMs: wait,\n maxBurstDurationMs: wait,\n ...(trailing\n ? leading\n ? { triggerAt: 'both' }\n : { triggerAt: 'end' }\n : { triggerAt: 'start' }),\n },\n );\n\n /**\n * Lodash uses a legacy JS-isms to attach helper functions to the main\n * callback of `throttle`. In our's we return a proper object where the\n * callback is one of the available properties. Here we destructure and then\n * reconstruct the object to fit the Lodash API.\n */\n return Object.assign(\n (...args: Parameters<F>) => {\n call(...args);\n return cachedValue;\n },\n {\n flush: () => {\n flush();\n return cachedValue;\n },\n\n cancel,\n },\n );\n}\n\n/**\n * We need some non-trivial duration to use in all our tests, to abstract the\n * actual chosen value we use this UnitOfTime (UT) constant. As long as it is a\n * positive integer, the actual value doesn't matter (but the larger it is,\n * the longer the tests would take to run); the value used by Lodash is 32.\n * The number is in milliseconds.\n */\nconst UT = 16;\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768', () => {\n it('subsequent calls should return the result of the first call', async () => {\n const throttled = throttleWithCachedValue(identity(), UT);\n\n expect(throttled('a')).toBe('a');\n expect(throttled('b')).toBe('a');\n\n await sleep(2 * UT);\n const resultC = throttled('c');\n const resultD = throttled('d');\n\n expect(resultC).not.toBe('a');\n expect(resultC).toBeDefined();\n expect(resultD).not.toBe('d');\n expect(resultD).toBeDefined();\n });\n\n it('should support a `leading` option', () => {\n const withLeading = throttleWithCachedValue(identity(), UT, {\n leading: true,\n });\n const withoutLeading = throttleWithCachedValue(identity(), UT, {\n leading: false,\n });\n\n expect(withLeading('a')).toBe('a');\n expect(withoutLeading('a')).toBeUndefined();\n });\n\n it('should support a `trailing` option', async () => {\n const mockWith = vi.fn<<T>(x: T) => T>(identity());\n const mockWithout = vi.fn<<T>(x: T) => T>(identity());\n const withTrailing = throttleWithCachedValue(mockWith, 2 * UT, {\n trailing: true,\n });\n const withoutTrailing = throttleWithCachedValue(mockWithout, 2 * UT, {\n trailing: false,\n });\n\n expect(withTrailing('a')).toBe('a');\n expect(withTrailing('b')).toBe('a');\n expect(withoutTrailing('a')).toBe('a');\n expect(withoutTrailing('b')).toBe('a');\n\n await sleep(8 * UT);\n\n expect(mockWith).toHaveBeenCalledTimes(2);\n expect(mockWithout).toHaveBeenCalledTimes(1);\n });\n});\n\ndescribe('https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038', () => {\n it('should reset `lastCalled` after cancelling', async () => {\n let callCount = 0;\n const throttled = throttleWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: true },\n );\n\n expect(throttled()).toBe(1);\n\n throttled.cancel();\n\n expect(throttled()).toBe(2);\n\n throttled();\n await sleep(2 * UT);\n\n expect(callCount).toBe(3);\n });\n\n it('should support flushing delayed calls', async () => {\n let callCount = 0;\n const throttled = throttleWithCachedValue(\n () => {\n callCount += 1;\n return callCount;\n },\n UT,\n { leading: false },\n );\n throttled();\n\n expect(throttled.flush()).toBe(1);\n\n await sleep(2 * UT);\n\n expect(callCount).toBe(1);\n });\n\n it('should noop `cancel` and `flush` when nothing is queued', async () => {\n const mockFn = vi.fn<() => string>(constant('hello'));\n const throttled = throttleWithCachedValue(mockFn, UT);\n throttled.cancel();\n\n expect(throttled.flush()).toBeUndefined();\n\n await sleep(2 * UT);\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n });\n});\n\ndescribe('features not tested by Lodash', () => {\n it('does nothing when neither leading nor trailing are enabled', async () => {\n const throttled = throttleWithCachedValue(identity(), UT, {\n leading: false,\n trailing: false,\n });\n\n expect(throttled('hello')).toBeUndefined();\n expect(throttled('world')).toBeUndefined();\n\n await sleep(4 * UT);\n\n expect(throttled('goodbye')).toBeUndefined();\n });\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./dist-
|
|
1
|
+
const e=require(`./dist-8XtUY3ad.cjs`),t=require(`./funnel.cjs`),n=require(`./sleep.cjs`);function r(e,n=0,{leading:r=!0,trailing:i=!0}={}){let{call:a,isIdle:o,...s}=t.funnel(t=>{!r&&!i||e(...t)},{reducer:(e,...t)=>t,minQuietPeriodMs:n,maxBurstDurationMs:n,...i?r?{triggerAt:`both`}:{triggerAt:`end`}:{triggerAt:`start`}});return Object.assign(a,s)}const i=16;e.i(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768`,()=>{e.a(`should throttle a function`,async()=>{let t=e.r.fn(),i=r(t,16);i(),i(),i();let a=t.mock.calls.length;e.n(a).toBeGreaterThan(0),await n.sleep(32),e.n(t.mock.calls.length).toBeGreaterThan(a)}),e.a("should clear timeout when `func` is called",async()=>{let t=e.r.fn(),i=r(t,16);i(),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(32),i(),e.n(t).toHaveBeenCalledTimes(2)}),e.a(`should not trigger a trailing call when invoked once`,async()=>{let t=e.r.fn();r(t,16)(),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(1)}),e.a(`should trigger a call when invoked repeatedly`,()=>{let t=e.r.fn(),n=r(t,16),i=Date.now()+160;for(;Date.now()<i;)n();e.n(t).toHaveBeenCalledExactlyOnceWith()}),e.a("should trigger a call when invoked repeatedly and `leading` is `false`",async()=>{let t=e.r.fn(),i=r(t,16,{leading:!1}),a=Date.now()+160;for(;Date.now()<a;)i();await n.sleep(0),e.n(t).toHaveBeenCalledExactlyOnceWith()}),e.a(`should trigger a second throttled call as soon as possible`,async()=>{let t=e.r.fn(),i=r(t,64,{leading:!1});i(),await n.sleep(96),e.n(t).toHaveBeenCalledTimes(1),i(),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(64),e.n(t).toHaveBeenCalledTimes(2)}),e.a(`should apply default options`,async()=>{let t=e.r.fn(),i=r(t,16,{});i(),i(),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(64),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should support a `leading` option",()=>{let t=e.r.fn(),n=e.r.fn(),i=r(t,16,{leading:!0}),a=r(n,16,{leading:!1});i(),a(),e.n(t).toHaveBeenCalledTimes(1),e.n(n).toHaveBeenCalledTimes(0)}),e.a("should support a `trailing` option",async()=>{let t=e.r.fn(),i=e.r.fn(),a=r(t,32,{trailing:!0}),o=r(i,32,{trailing:!1});a(`a`),a(`b`),o(`a`),o(`b`),e.n(t).toHaveBeenCalledExactlyOnceWith(`a`),e.n(i).toHaveBeenCalledExactlyOnceWith(`a`),await n.sleep(128),e.n(t).toHaveBeenCalledTimes(2),e.n(i).toHaveBeenCalledTimes(1)}),e.a("should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`",async()=>{let t=e.r.fn(),i=r(t,64,{trailing:!1});i(),i(),await n.sleep(48),i(),i(),await n.sleep(48),e.n(t).toHaveBeenCalledExactlyOnceWith()})}),e.i(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038`,()=>{e.a("should use a default `wait` of `0`",async()=>{let t=e.r.fn(),i=r(t);i(),await n.sleep(16),i(),e.n(t).toHaveBeenCalledTimes(2)}),e.a(`supports recursive calls`,async()=>{let t=[],i=[`a`,`b`,`c`],a=r(e=>{t.push(e);let n=i.shift();n!==void 0&&a(n)},16);a(i.shift()),e.n(t).toStrictEqual([`a`]),await n.sleep(128),e.n(t).toStrictEqual([`a`,`b`,`c`])}),e.a(`should support cancelling delayed calls`,async()=>{let t=e.r.fn(),i=r(t,16,{leading:!1});i(),i.cancel(),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(0)}),e.a("should reset `lastCalled` after cancelling",async()=>{let t=e.r.fn(),i=r(t,16,{leading:!0});i(),e.n(t).toHaveBeenCalledTimes(1),i.cancel(),i(),e.n(t).toHaveBeenCalledTimes(2),i(),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(3)}),e.a(`should support flushing delayed calls`,async()=>{let t=e.r.fn(),i=r(t,16,{leading:!1});i(),i.flush(),e.n(t).toHaveBeenCalledTimes(1),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(1)}),e.a("should noop `cancel` and `flush` when nothing is queued",async()=>{let t=e.r.fn(),i=r(t,16);i.cancel(),i.flush(),e.n(t).toHaveBeenCalledTimes(0),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(0)})}),e.i(`not tested by Lodash`,()=>{e.a("should do nothing when `leading` and `trailing` are both `disabled`",async()=>{let t=e.r.fn(),i=r(t,16,{leading:!1,trailing:!1});i(),i(),i(),e.n(t).toHaveBeenCalledTimes(0),await n.sleep(32),e.n(t).toHaveBeenCalledTimes(0)})});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,i as t,n,r}from"./dist-
|
|
1
|
+
import{a as e,i as t,n,r}from"./dist-Bd1vawFi.js";import{funnel as i}from"./funnel.js";import{sleep as a}from"./sleep.js";function o(e,t=0,{leading:n=!0,trailing:r=!0}={}){let{call:a,isIdle:o,...s}=i(t=>{!n&&!r||e(...t)},{reducer:(e,...t)=>t,minQuietPeriodMs:t,maxBurstDurationMs:t,...r?n?{triggerAt:`both`}:{triggerAt:`end`}:{triggerAt:`start`}});return Object.assign(a,s)}t(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L22768`,()=>{e(`should throttle a function`,async()=>{let e=r.fn(),t=o(e,16);t(),t(),t();let i=e.mock.calls.length;n(i).toBeGreaterThan(0),await a(32),n(e.mock.calls.length).toBeGreaterThan(i)}),e("should clear timeout when `func` is called",async()=>{let e=r.fn(),t=o(e,16);t(),n(e).toHaveBeenCalledTimes(1),await a(32),t(),n(e).toHaveBeenCalledTimes(2)}),e(`should not trigger a trailing call when invoked once`,async()=>{let e=r.fn();o(e,16)(),n(e).toHaveBeenCalledTimes(1),await a(32),n(e).toHaveBeenCalledTimes(1)}),e(`should trigger a call when invoked repeatedly`,()=>{let e=r.fn(),t=o(e,16),i=Date.now()+160;for(;Date.now()<i;)t();n(e).toHaveBeenCalledExactlyOnceWith()}),e("should trigger a call when invoked repeatedly and `leading` is `false`",async()=>{let e=r.fn(),t=o(e,16,{leading:!1}),i=Date.now()+160;for(;Date.now()<i;)t();await a(0),n(e).toHaveBeenCalledExactlyOnceWith()}),e(`should trigger a second throttled call as soon as possible`,async()=>{let e=r.fn(),t=o(e,64,{leading:!1});t(),await a(96),n(e).toHaveBeenCalledTimes(1),t(),await a(32),n(e).toHaveBeenCalledTimes(1),await a(64),n(e).toHaveBeenCalledTimes(2)}),e(`should apply default options`,async()=>{let e=r.fn(),t=o(e,16,{});t(),t(),n(e).toHaveBeenCalledTimes(1),await a(64),n(e).toHaveBeenCalledTimes(2)}),e("should support a `leading` option",()=>{let e=r.fn(),t=r.fn(),i=o(e,16,{leading:!0}),a=o(t,16,{leading:!1});i(),a(),n(e).toHaveBeenCalledTimes(1),n(t).toHaveBeenCalledTimes(0)}),e("should support a `trailing` option",async()=>{let e=r.fn(),t=r.fn(),i=o(e,32,{trailing:!0}),s=o(t,32,{trailing:!1});i(`a`),i(`b`),s(`a`),s(`b`),n(e).toHaveBeenCalledExactlyOnceWith(`a`),n(t).toHaveBeenCalledExactlyOnceWith(`a`),await a(128),n(e).toHaveBeenCalledTimes(2),n(t).toHaveBeenCalledTimes(1)}),e("should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`",async()=>{let e=r.fn(),t=o(e,64,{trailing:!1});t(),t(),await a(48),t(),t(),await a(48),n(e).toHaveBeenCalledExactlyOnceWith()})}),t(`https://github.com/lodash/lodash/blob/4.17.21/test/test.js#L23038`,()=>{e("should use a default `wait` of `0`",async()=>{let e=r.fn(),t=o(e);t(),await a(16),t(),n(e).toHaveBeenCalledTimes(2)}),e(`supports recursive calls`,async()=>{let e=[],t=[`a`,`b`,`c`],r=o(n=>{e.push(n);let i=t.shift();i!==void 0&&r(i)},16);r(t.shift()),n(e).toStrictEqual([`a`]),await a(128),n(e).toStrictEqual([`a`,`b`,`c`])}),e(`should support cancelling delayed calls`,async()=>{let e=r.fn(),t=o(e,16,{leading:!1});t(),t.cancel(),await a(32),n(e).toHaveBeenCalledTimes(0)}),e("should reset `lastCalled` after cancelling",async()=>{let e=r.fn(),t=o(e,16,{leading:!0});t(),n(e).toHaveBeenCalledTimes(1),t.cancel(),t(),n(e).toHaveBeenCalledTimes(2),t(),await a(32),n(e).toHaveBeenCalledTimes(3)}),e(`should support flushing delayed calls`,async()=>{let e=r.fn(),t=o(e,16,{leading:!1});t(),t.flush(),n(e).toHaveBeenCalledTimes(1),await a(32),n(e).toHaveBeenCalledTimes(1)}),e("should noop `cancel` and `flush` when nothing is queued",async()=>{let e=r.fn(),t=o(e,16);t.cancel(),t.flush(),n(e).toHaveBeenCalledTimes(0),await a(32),n(e).toHaveBeenCalledTimes(0)})}),t(`not tested by Lodash`,()=>{e("should do nothing when `leading` and `trailing` are both `disabled`",async()=>{let e=r.fn(),t=o(e,16,{leading:!1,trailing:!1});t(),t(),t(),n(e).toHaveBeenCalledTimes(0),await a(32),n(e).toHaveBeenCalledTimes(0)})});
|
|
2
2
|
//# sourceMappingURL=funnel.lodash-throttle.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./dist-
|
|
1
|
+
const e=require(`./dist-8XtUY3ad.cjs`),t=require(`./constant.cjs`),n=require(`./funnel.cjs`),r=require(`./identity.cjs`),i=require(`./sleep.cjs`);function a(e,{timing:t,waitMs:r,maxWaitMs:i}){if(i!==void 0&&r!==void 0&&i<r)throw Error(`debounce: maxWaitMs (${i.toString()}) cannot be less than waitMs (${r.toString()})`);let a,o=n.funnel(t=>{a=e(...t)},{reducer:(e,...t)=>t,minQuietPeriodMs:r??i??0,...i!==void 0&&{maxBurstDurationMs:i},...t===`leading`?{triggerAt:`start`}:t===`both`?{triggerAt:`both`}:{triggerAt:`end`}});return{call:(...e)=>(o.call(...e),a),flush:()=>(o.flush(),a),cancel:()=>{o.cancel()},get isPending(){return!o.isIdle},get cachedValue(){return a}}}e.i(`main functionality`,()=>{e.a(`should debounce a function`,async()=>{let t=e.r.fn(r.identity()),n=a(t,{waitMs:32});e.n([n.call(`a`),n.call(`b`),n.call(`c`)]).toStrictEqual([void 0,void 0,void 0]),e.n(t).toHaveBeenCalledTimes(0),await i.sleep(128),e.n(t).toHaveBeenCalledTimes(1),e.n([n.call(`d`),n.call(`e`),n.call(`f`)]).toStrictEqual([`c`,`c`,`c`]),e.n(t).toHaveBeenCalledTimes(1),await i.sleep(256),e.n(t).toHaveBeenCalledTimes(2)}),e.a("subsequent debounced calls return the last `func` result",async()=>{let t=a(r.identity(),{waitMs:32});t.call(`a`),await i.sleep(64),e.n(t.call(`b`)).toBe(`a`),await i.sleep(128),e.n(t.call(`c`)).toBe(`b`)}),e.a("should not immediately call `func` when `wait` is `0`",async()=>{let t=e.r.fn(),n=a(t,{});n.call(),n.call(),e.n(t).toHaveBeenCalledTimes(0),await i.sleep(5),e.n(t).toHaveBeenCalledTimes(1)}),e.a(`should apply default options`,async()=>{let t=e.r.fn();a(t,{waitMs:32}).call(),e.n(t).toHaveBeenCalledTimes(0),await i.sleep(64),e.n(t).toHaveBeenCalledTimes(1)}),e.a("should support a `leading` option",async()=>{let t=e.r.fn(),n=e.r.fn(),r=a(t,{waitMs:32,timing:`leading`});r.call(),e.n(t).toHaveBeenCalledTimes(1);let o=a(n,{waitMs:32,timing:`both`});o.call(),o.call(),e.n(n).toHaveBeenCalledTimes(1),await i.sleep(64),e.n(n).toHaveBeenCalledTimes(2),r.call(),e.n(t).toHaveBeenCalledTimes(2)}),e.a("subsequent leading debounced calls return the last `func` result",async()=>{let t=a(r.identity(),{waitMs:32,timing:`leading`});e.n([t.call(`a`),t.call(`b`)]).toStrictEqual([`a`,`a`]),await i.sleep(64),e.n([t.call(`c`),t.call(`d`)]).toStrictEqual([`c`,`c`])}),e.a("should support a `trailing` option",async()=>{let t=e.r.fn();a(t,{waitMs:32,timing:`trailing`}).call(),e.n(t).toHaveBeenCalledTimes(0),await i.sleep(64),e.n(t).toHaveBeenCalledTimes(1)})}),e.i(`optional param maxWaitMs`,()=>{e.a("should support a `maxWait` option",async()=>{let t=e.r.fn(),n=a(t,{waitMs:32,maxWaitMs:64});n.call(`a`),n.call(`b`),e.n(t).toHaveBeenCalledTimes(0),await i.sleep(128),e.n(t).toHaveBeenCalledTimes(1),n.call(`c`),n.call(`d`),e.n(t).toHaveBeenCalledTimes(1),await i.sleep(256),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should support `maxWait` in a tight loop",async()=>{let t=e.r.fn(),n=e.r.fn(),r=a(t,{waitMs:32,maxWaitMs:128}),o=a(n,{waitMs:96}),s=Date.now();for(;Date.now()-s<320;)r.call(),o.call();await i.sleep(1),e.n(n).toHaveBeenCalledTimes(0),e.n(t).not.toHaveBeenCalledTimes(0)}),e.a("should queue a trailing call for subsequent debounced calls after `maxWait`",async()=>{let t=e.r.fn(),n=a(t,{waitMs:200,maxWaitMs:200});n.call(),setTimeout(()=>{n.call()},190),setTimeout(()=>{n.call()},200),setTimeout(()=>{n.call()},210),await i.sleep(500),e.n(t).toHaveBeenCalledTimes(2)}),e.a("should cancel `maxDelayed` when `delayed` is invoked",async()=>{let t=e.r.fn(),n=a(t,{waitMs:32,maxWaitMs:64});n.call(),await i.sleep(128),n.call(),e.n(t).toHaveBeenCalledTimes(1),await i.sleep(192),e.n(t).toHaveBeenCalledTimes(2)}),e.a(`works like a leaky bucket when only maxWaitMs is set`,async()=>{let t=e.r.fn(),n=a(t,{maxWaitMs:32});n.call(),e.n(t).toHaveBeenCalledTimes(0),await i.sleep(16),n.call(),e.n(t).toHaveBeenCalledTimes(0),await i.sleep(17),e.n(t).toHaveBeenCalledTimes(1)})}),e.i(`additional functionality`,()=>{e.a(`can cancel before the timer starts`,async()=>{let t=a(r.identity(),{waitMs:32});e.n(()=>{t.cancel()}).not.toThrowError(),e.n(t.call(`hello`)).toBeUndefined(),await i.sleep(32),e.n(t.call(`world`)).toBe(`hello`)}),e.a(`can cancel the timer`,async()=>{let n=e.r.fn(t.constant(`Hello, World!`)),r=a(n,{waitMs:32});e.n(r.call()).toBeUndefined(),e.n(n).toHaveBeenCalledTimes(0),await i.sleep(1),e.n(r.call()).toBeUndefined(),e.n(n).toHaveBeenCalledTimes(0),r.cancel(),await i.sleep(32),e.n(r.call()).toBeUndefined(),e.n(n).toHaveBeenCalledTimes(0),await i.sleep(32),e.n(r.call()).toBe(`Hello, World!`),e.n(n).toHaveBeenCalledTimes(1)}),e.a(`can cancel after the timer ends`,async()=>{let t=a(r.identity(),{waitMs:32});e.n(t.call(`hello`)).toBeUndefined(),await i.sleep(32),e.n(t.call(`world`)).toBe(`hello`),e.n(()=>{t.cancel()}).not.toThrowError()}),e.a(`can cancel maxWait timer`,async()=>{let t=a(r.identity(),{waitMs:16,maxWaitMs:32});e.n(t.call(`hello`)).toBeUndefined(),await i.sleep(1),t.cancel(),await i.sleep(32),e.n(t.call(`world`)).toBeUndefined()}),e.a(`can return a cached value`,()=>{let t=a(r.identity(),{timing:`leading`,waitMs:32});e.n(t.cachedValue).toBeUndefined(),e.n(t.call(`hello`)).toBe(`hello`),e.n(t.cachedValue).toBe(`hello`)}),e.a(`can check for inflight timers (trailing)`,async()=>{let t=a(r.identity(),{waitMs:32});e.n(t.isPending).toBe(!1),e.n(t.call(`hello`)).toBeUndefined(),e.n(t.isPending).toBe(!0),await i.sleep(1),e.n(t.isPending).toBe(!0),await i.sleep(32),e.n(t.isPending).toBe(!1)}),e.a(`can check for inflight timers (leading)`,async()=>{let t=a(r.identity(),{timing:`leading`,waitMs:32});e.n(t.isPending).toBe(!1),e.n(t.call(`hello`)).toBe(`hello`),e.n(t.isPending).toBe(!0),await i.sleep(1),e.n(t.isPending).toBe(!0),await i.sleep(32),e.n(t.isPending).toBe(!1)}),e.a(`can flush before a cool-down`,async()=>{let t=a(r.identity(),{waitMs:32});e.n(t.flush()).toBeUndefined(),e.n(t.call(`hello`)).toBeUndefined(),await i.sleep(32),e.n(t.call(`world`)).toBe(`hello`)}),e.a(`can flush during a cool-down`,async()=>{let t=a(r.identity(),{waitMs:32});e.n(t.call(`hello`)).toBeUndefined(),await i.sleep(1),e.n(t.call(`world`)).toBeUndefined(),await i.sleep(1),e.n(t.flush()).toBe(`world`)}),e.a(`can flush after a cool-down`,async()=>{let t=a(r.identity(),{waitMs:32});e.n(t.call(`hello`)).toBeUndefined(),await i.sleep(32),e.n(t.flush()).toBe(`hello`)})}),e.i(`errors`,()=>{e.a(`prevents maxWaitMs to be less then waitMs`,()=>{e.n(()=>a(r.identity(),{waitMs:32,maxWaitMs:16})).toThrowError(`debounce: maxWaitMs (16) cannot be less than waitMs (32)`)})});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{constant as e}from"./constant.js";import{a as t,i as n,n as r,r as i}from"./dist-Bd1vawFi.js";import{funnel as a}from"./funnel.js";import{identity as o}from"./identity.js";import{sleep as s}from"./sleep.js";function c(e,{timing:t,waitMs:n,maxWaitMs:r}){if(r!==void 0&&n!==void 0&&r<n)throw Error(`debounce: maxWaitMs (${r.toString()}) cannot be less than waitMs (${n.toString()})`);let i,o=a(t=>{i=e(...t)},{reducer:(e,...t)=>t,minQuietPeriodMs:n??r??0,...r!==void 0&&{maxBurstDurationMs:r},...t===`leading`?{triggerAt:`start`}:t===`both`?{triggerAt:`both`}:{triggerAt:`end`}});return{call:(...e)=>(o.call(...e),i),flush:()=>(o.flush(),i),cancel:()=>{o.cancel()},get isPending(){return!o.isIdle},get cachedValue(){return i}}}n(`main functionality`,()=>{t(`should debounce a function`,async()=>{let e=i.fn(o()),t=c(e,{waitMs:32});r([t.call(`a`),t.call(`b`),t.call(`c`)]).toStrictEqual([void 0,void 0,void 0]),r(e).toHaveBeenCalledTimes(0),await s(128),r(e).toHaveBeenCalledTimes(1),r([t.call(`d`),t.call(`e`),t.call(`f`)]).toStrictEqual([`c`,`c`,`c`]),r(e).toHaveBeenCalledTimes(1),await s(256),r(e).toHaveBeenCalledTimes(2)}),t("subsequent debounced calls return the last `func` result",async()=>{let e=c(o(),{waitMs:32});e.call(`a`),await s(64),r(e.call(`b`)).toBe(`a`),await s(128),r(e.call(`c`)).toBe(`b`)}),t("should not immediately call `func` when `wait` is `0`",async()=>{let e=i.fn(),t=c(e,{});t.call(),t.call(),r(e).toHaveBeenCalledTimes(0),await s(5),r(e).toHaveBeenCalledTimes(1)}),t(`should apply default options`,async()=>{let e=i.fn();c(e,{waitMs:32}).call(),r(e).toHaveBeenCalledTimes(0),await s(64),r(e).toHaveBeenCalledTimes(1)}),t("should support a `leading` option",async()=>{let e=i.fn(),t=i.fn(),n=c(e,{waitMs:32,timing:`leading`});n.call(),r(e).toHaveBeenCalledTimes(1);let a=c(t,{waitMs:32,timing:`both`});a.call(),a.call(),r(t).toHaveBeenCalledTimes(1),await s(64),r(t).toHaveBeenCalledTimes(2),n.call(),r(e).toHaveBeenCalledTimes(2)}),t("subsequent leading debounced calls return the last `func` result",async()=>{let e=c(o(),{waitMs:32,timing:`leading`});r([e.call(`a`),e.call(`b`)]).toStrictEqual([`a`,`a`]),await s(64),r([e.call(`c`),e.call(`d`)]).toStrictEqual([`c`,`c`])}),t("should support a `trailing` option",async()=>{let e=i.fn();c(e,{waitMs:32,timing:`trailing`}).call(),r(e).toHaveBeenCalledTimes(0),await s(64),r(e).toHaveBeenCalledTimes(1)})}),n(`optional param maxWaitMs`,()=>{t("should support a `maxWait` option",async()=>{let e=i.fn(),t=c(e,{waitMs:32,maxWaitMs:64});t.call(`a`),t.call(`b`),r(e).toHaveBeenCalledTimes(0),await s(128),r(e).toHaveBeenCalledTimes(1),t.call(`c`),t.call(`d`),r(e).toHaveBeenCalledTimes(1),await s(256),r(e).toHaveBeenCalledTimes(2)}),t("should support `maxWait` in a tight loop",async()=>{let e=i.fn(),t=i.fn(),n=c(e,{waitMs:32,maxWaitMs:128}),a=c(t,{waitMs:96}),o=Date.now();for(;Date.now()-o<320;)n.call(),a.call();await s(1),r(t).toHaveBeenCalledTimes(0),r(e).not.toHaveBeenCalledTimes(0)}),t("should queue a trailing call for subsequent debounced calls after `maxWait`",async()=>{let e=i.fn(),t=c(e,{waitMs:200,maxWaitMs:200});t.call(),setTimeout(()=>{t.call()},190),setTimeout(()=>{t.call()},200),setTimeout(()=>{t.call()},210),await s(500),r(e).toHaveBeenCalledTimes(2)}),t("should cancel `maxDelayed` when `delayed` is invoked",async()=>{let e=i.fn(),t=c(e,{waitMs:32,maxWaitMs:64});t.call(),await s(128),t.call(),r(e).toHaveBeenCalledTimes(1),await s(192),r(e).toHaveBeenCalledTimes(2)}),t(`works like a leaky bucket when only maxWaitMs is set`,async()=>{let e=i.fn(),t=c(e,{maxWaitMs:32});t.call(),r(e).toHaveBeenCalledTimes(0),await s(16),t.call(),r(e).toHaveBeenCalledTimes(0),await s(17),r(e).toHaveBeenCalledTimes(1)})}),n(`additional functionality`,()=>{t(`can cancel before the timer starts`,async()=>{let e=c(o(),{waitMs:32});r(()=>{e.cancel()}).not.toThrowError(),r(e.call(`hello`)).toBeUndefined(),await s(32),r(e.call(`world`)).toBe(`hello`)}),t(`can cancel the timer`,async()=>{let t=i.fn(e(`Hello, World!`)),n=c(t,{waitMs:32});r(n.call()).toBeUndefined(),r(t).toHaveBeenCalledTimes(0),await s(1),r(n.call()).toBeUndefined(),r(t).toHaveBeenCalledTimes(0),n.cancel(),await s(32),r(n.call()).toBeUndefined(),r(t).toHaveBeenCalledTimes(0),await s(32),r(n.call()).toBe(`Hello, World!`),r(t).toHaveBeenCalledTimes(1)}),t(`can cancel after the timer ends`,async()=>{let e=c(o(),{waitMs:32});r(e.call(`hello`)).toBeUndefined(),await s(32),r(e.call(`world`)).toBe(`hello`),r(()=>{e.cancel()}).not.toThrowError()}),t(`can cancel maxWait timer`,async()=>{let e=c(o(),{waitMs:16,maxWaitMs:32});r(e.call(`hello`)).toBeUndefined(),await s(1),e.cancel(),await s(32),r(e.call(`world`)).toBeUndefined()}),t(`can return a cached value`,()=>{let e=c(o(),{timing:`leading`,waitMs:32});r(e.cachedValue).toBeUndefined(),r(e.call(`hello`)).toBe(`hello`),r(e.cachedValue).toBe(`hello`)}),t(`can check for inflight timers (trailing)`,async()=>{let e=c(o(),{waitMs:32});r(e.isPending).toBe(!1),r(e.call(`hello`)).toBeUndefined(),r(e.isPending).toBe(!0),await s(1),r(e.isPending).toBe(!0),await s(32),r(e.isPending).toBe(!1)}),t(`can check for inflight timers (leading)`,async()=>{let e=c(o(),{timing:`leading`,waitMs:32});r(e.isPending).toBe(!1),r(e.call(`hello`)).toBe(`hello`),r(e.isPending).toBe(!0),await s(1),r(e.isPending).toBe(!0),await s(32),r(e.isPending).toBe(!1)}),t(`can flush before a cool-down`,async()=>{let e=c(o(),{waitMs:32});r(e.flush()).toBeUndefined(),r(e.call(`hello`)).toBeUndefined(),await s(32),r(e.call(`world`)).toBe(`hello`)}),t(`can flush during a cool-down`,async()=>{let e=c(o(),{waitMs:32});r(e.call(`hello`)).toBeUndefined(),await s(1),r(e.call(`world`)).toBeUndefined(),await s(1),r(e.flush()).toBe(`world`)}),t(`can flush after a cool-down`,async()=>{let e=c(o(),{waitMs:32});r(e.call(`hello`)).toBeUndefined(),await s(32),r(e.flush()).toBe(`hello`)})}),n(`errors`,()=>{t(`prevents maxWaitMs to be less then waitMs`,()=>{r(()=>c(o(),{waitMs:32,maxWaitMs:16})).toThrowError(`debounce: maxWaitMs (16) cannot be less than waitMs (32)`)})});
|
|
2
2
|
//# sourceMappingURL=funnel.perkakas-debounce.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"funnel.perkakas-debounce.test.js","names":["cachedValue: ReturnType<F> | undefined"],"sources":["../src/funnel.perkakas-debounce.test.ts"],"sourcesContent":["/* eslint-disable function-paren-newline, no-nested-ternary, ts/explicit-function-return-type, ts/no-explicit-any --\n * These aren't useful for a reference implementation!\n */\n\nimport { describe, expect, it, vi } from 'vitest';\nimport { constant } from './constant';\nimport { funnel } from './funnel';\nimport { identity } from './identity';\nimport { sleep } from './sleep';\n\ninterface Debouncer<\n F extends (...args: any) => unknown,\n IsNullable extends boolean = true,\n> {\n readonly call: (\n ...args: Parameters<F>\n ) => ReturnType<F> | (true extends IsNullable ? undefined : never);\n readonly cancel: () => void;\n readonly flush: () => ReturnType<F> | undefined;\n readonly isPending: boolean;\n readonly cachedValue: ReturnType<F> | undefined;\n}\n\ninterface DebounceOptions {\n readonly waitMs?: number;\n readonly maxWaitMs?: number;\n}\n\n/**\n * A reference implementation of the now deprecated `debounce` function using\n * the `funnel` function instead. While you update your codebase you can copy\n * this function as-is and use it as a drop-in replacement; but we recommend\n * eventually inlining the call to `funnel` so you can adjust the function to\n * your specific needs.\n *\n * The following tests in this file are the original tests for debounce.\n *\n * @see debounce\n */\nfunction debounce<F extends (...args: any) => any>(\n func: F,\n options: DebounceOptions & { readonly timing?: 'trailing' },\n): Debouncer<F>;\nfunction debounce<F extends (...args: any) => any>(\n func: F,\n options:\n | (DebounceOptions & { readonly timing: 'both' })\n | (Omit<DebounceOptions, 'maxWaitMs'> & { readonly timing: 'leading' }),\n): Debouncer<F, false>;\nfunction debounce<F extends (...args: any) => any>(\n func: F,\n {\n timing,\n waitMs,\n maxWaitMs,\n }: DebounceOptions & {\n readonly timing?: 'both' | 'leading' | 'trailing';\n },\n) {\n if (maxWaitMs !== undefined && waitMs !== undefined && maxWaitMs < waitMs) {\n throw new Error(\n `debounce: maxWaitMs (${maxWaitMs.toString()}) cannot be less than waitMs (${waitMs.toString()})`,\n );\n }\n\n let cachedValue: ReturnType<F> | undefined;\n\n const debouncingFunnel = funnel(\n (args: Parameters<F>) => {\n // Every time the function is invoked the cached value is updated.\n cachedValue = func(...args) as ReturnType<F>;\n },\n {\n // Debounce stores the latest args it was called with for the next invocation of the callback.\n reducer: (_, ...args: Parameters<F>) => args,\n minQuietPeriodMs: waitMs ?? maxWaitMs ?? 0,\n ...(maxWaitMs !== undefined && { maxBurstDurationMs: maxWaitMs }),\n ...(timing === 'leading'\n ? { triggerAt: 'start' }\n : timing === 'both'\n ? { triggerAt: 'both' }\n : { triggerAt: 'end' }),\n },\n );\n\n return {\n call: (...args: Parameters<F>) => {\n debouncingFunnel.call(...args);\n return cachedValue;\n },\n\n flush: () => {\n debouncingFunnel.flush();\n return cachedValue;\n },\n\n cancel: () => {\n debouncingFunnel.cancel();\n },\n\n get isPending() {\n return !debouncingFunnel.isIdle;\n },\n\n get cachedValue() {\n return cachedValue;\n },\n };\n}\n\ndescribe('main functionality', () => {\n it('should debounce a function', async () => {\n const mockFn = vi.fn<(x: string) => string>(identity());\n const debouncer = debounce(mockFn, { waitMs: 32 });\n\n expect([\n debouncer.call('a'),\n debouncer.call('b'),\n debouncer.call('c'),\n ]).toStrictEqual([undefined, undefined, undefined]);\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(128);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n expect([\n debouncer.call('d'),\n debouncer.call('e'),\n debouncer.call('f'),\n ]).toStrictEqual(['c', 'c', 'c']);\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(256);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('subsequent debounced calls return the last `func` result', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n debouncer.call('a');\n await sleep(64);\n\n expect(debouncer.call('b')).toBe('a');\n\n await sleep(128);\n\n expect(debouncer.call('c')).toBe('b');\n });\n\n it('should not immediately call `func` when `wait` is `0`', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, {});\n debouncer.call();\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(5);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n\n it('should apply default options', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { waitMs: 32 });\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(64);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n\n it('should support a `leading` option', async () => {\n const leadingMockFn = vi.fn<() => void>();\n const bothMockFn = vi.fn<() => void>();\n const withLeading = debounce(leadingMockFn, {\n waitMs: 32,\n timing: 'leading',\n });\n withLeading.call();\n\n expect(leadingMockFn).toHaveBeenCalledTimes(1);\n\n const withLeadingAndTrailing = debounce(bothMockFn, {\n waitMs: 32,\n timing: 'both',\n });\n withLeadingAndTrailing.call();\n withLeadingAndTrailing.call();\n\n expect(bothMockFn).toHaveBeenCalledTimes(1);\n\n await sleep(64);\n\n expect(bothMockFn).toHaveBeenCalledTimes(2);\n\n withLeading.call();\n\n expect(leadingMockFn).toHaveBeenCalledTimes(2);\n });\n\n it('subsequent leading debounced calls return the last `func` result', async () => {\n const debouncer = debounce(identity(), { waitMs: 32, timing: 'leading' });\n\n expect([debouncer.call('a'), debouncer.call('b')]).toStrictEqual([\n 'a',\n 'a',\n ]);\n\n await sleep(64);\n\n expect([debouncer.call('c'), debouncer.call('d')]).toStrictEqual([\n 'c',\n 'c',\n ]);\n });\n\n it('should support a `trailing` option', async () => {\n const mockFn = vi.fn<() => void>();\n const withTrailing = debounce(mockFn, { waitMs: 32, timing: 'trailing' });\n withTrailing.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(64);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n});\n\ndescribe('optional param maxWaitMs', () => {\n it('should support a `maxWait` option', async () => {\n const mockFn = vi.fn<(x: string) => void>();\n const debouncer = debounce(mockFn, { waitMs: 32, maxWaitMs: 64 });\n debouncer.call('a');\n debouncer.call('b');\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(128);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n debouncer.call('c');\n debouncer.call('d');\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(256);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('should support `maxWait` in a tight loop', async () => {\n const withMockFn = vi.fn<() => void>();\n const withoutMockFn = vi.fn<() => void>();\n const withMaxWait = debounce(withMockFn, { waitMs: 32, maxWaitMs: 128 });\n const withoutMaxWait = debounce(withoutMockFn, { waitMs: 96 });\n const start = Date.now();\n while (Date.now() - start < 320) {\n withMaxWait.call();\n withoutMaxWait.call();\n }\n await sleep(1);\n\n expect(withoutMockFn).toHaveBeenCalledTimes(0);\n expect(withMockFn).not.toHaveBeenCalledTimes(0);\n });\n\n it('should queue a trailing call for subsequent debounced calls after `maxWait`', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { waitMs: 200, maxWaitMs: 200 });\n debouncer.call();\n setTimeout(() => {\n debouncer.call();\n }, 190);\n setTimeout(() => {\n debouncer.call();\n }, 200);\n setTimeout(() => {\n debouncer.call();\n }, 210);\n await sleep(500);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('should cancel `maxDelayed` when `delayed` is invoked', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { waitMs: 32, maxWaitMs: 64 });\n debouncer.call();\n await sleep(128);\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(192);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('works like a leaky bucket when only maxWaitMs is set', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { maxWaitMs: 32 });\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(16);\n // Without maxWaitMs this call would cause the actual invocation to be\n // postponed for a full window.\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(17);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n});\n\ndescribe('additional functionality', () => {\n it('can cancel before the timer starts', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(() => {\n debouncer.cancel();\n }).not.toThrow();\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.call('world')).toBe('hello');\n });\n\n it('can cancel the timer', async () => {\n const mockFn = vi.fn<() => string>(constant('Hello, World!'));\n const debouncer = debounce(mockFn, { waitMs: 32 });\n\n expect(debouncer.call()).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(1);\n\n expect(debouncer.call()).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n debouncer.cancel();\n await sleep(32);\n\n expect(debouncer.call()).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(32);\n\n expect(debouncer.call()).toBe('Hello, World!');\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n\n it('can cancel after the timer ends', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.call('world')).toBe('hello');\n expect(() => {\n debouncer.cancel();\n }).not.toThrow();\n });\n\n it('can cancel maxWait timer', async () => {\n const debouncer = debounce(identity(), { waitMs: 16, maxWaitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(1);\n debouncer.cancel();\n await sleep(32);\n\n expect(debouncer.call('world')).toBeUndefined();\n });\n\n it('can return a cached value', () => {\n const debouncer = debounce(identity(), { timing: 'leading', waitMs: 32 });\n\n expect(debouncer.cachedValue).toBeUndefined();\n expect(debouncer.call('hello')).toBe('hello');\n expect(debouncer.cachedValue).toBe('hello');\n });\n\n it('can check for inflight timers (trailing)', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.isPending).toBe(false);\n expect(debouncer.call('hello')).toBeUndefined();\n expect(debouncer.isPending).toBe(true);\n\n await sleep(1);\n\n expect(debouncer.isPending).toBe(true);\n\n await sleep(32);\n\n expect(debouncer.isPending).toBe(false);\n });\n\n it('can check for inflight timers (leading)', async () => {\n const debouncer = debounce(identity(), { timing: 'leading', waitMs: 32 });\n\n expect(debouncer.isPending).toBe(false);\n expect(debouncer.call('hello')).toBe('hello');\n expect(debouncer.isPending).toBe(true);\n\n await sleep(1);\n\n expect(debouncer.isPending).toBe(true);\n\n await sleep(32);\n\n expect(debouncer.isPending).toBe(false);\n });\n\n it('can flush before a cool-down', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.flush()).toBeUndefined();\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.call('world')).toBe('hello');\n });\n\n it('can flush during a cool-down', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(1);\n\n expect(debouncer.call('world')).toBeUndefined();\n\n await sleep(1);\n\n expect(debouncer.flush()).toBe('world');\n });\n\n it('can flush after a cool-down', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.flush()).toBe('hello');\n });\n});\n\ndescribe('errors', () => {\n it('prevents maxWaitMs to be less then waitMs', () => {\n expect(() => debounce(identity(), { waitMs: 32, maxWaitMs: 16 })).toThrow(\n 'debounce: maxWaitMs (16) cannot be less than waitMs (32)',\n );\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"funnel.perkakas-debounce.test.js","names":["cachedValue: ReturnType<F> | undefined"],"sources":["../src/funnel.perkakas-debounce.test.ts"],"sourcesContent":["/* eslint-disable no-nested-ternary, ts/explicit-function-return-type --\n * These aren't useful for a reference implementation!\n */\n\nimport type { StrictFunction } from './internal/types/strict-function';\nimport { describe, expect, it, vi } from 'vitest';\nimport { constant } from './constant';\nimport { funnel } from './funnel';\nimport { identity } from './identity';\nimport { sleep } from './sleep';\n\ninterface Debouncer<F extends StrictFunction, IsNullable extends boolean = true> {\n readonly call: (\n ...args: Parameters<F>\n ) => ReturnType<F> | (true extends IsNullable ? undefined : never);\n readonly cancel: () => void;\n readonly flush: () => ReturnType<F> | undefined;\n readonly isPending: boolean;\n readonly cachedValue: ReturnType<F> | undefined;\n}\n\ninterface DebounceOptions {\n readonly waitMs?: number;\n readonly maxWaitMs?: number;\n}\n\n/**\n * A reference implementation of the now deprecated `debounce` function using\n * the `funnel` function instead. While you update your codebase you can copy\n * this function as-is and use it as a drop-in replacement; but we recommend\n * eventually inlining the call to `funnel` so you can adjust the function to\n * your specific needs.\n *\n * The following tests in this file are the original tests for debounce.\n *\n * @see debounce\n */\nfunction debounce<F extends StrictFunction>(\n func: F,\n options: DebounceOptions & { readonly timing?: 'trailing' },\n): Debouncer<F>;\nfunction debounce<F extends StrictFunction>(\n func: F,\n options:\n | (DebounceOptions & { readonly timing: 'both' })\n | (Omit<DebounceOptions, 'maxWaitMs'> & { readonly timing: 'leading' }),\n): Debouncer<F, false>;\nfunction debounce<F extends StrictFunction>(\n func: F,\n {\n timing,\n waitMs,\n maxWaitMs,\n }: DebounceOptions & {\n readonly timing?: 'both' | 'leading' | 'trailing';\n },\n) {\n if (maxWaitMs !== undefined && waitMs !== undefined && maxWaitMs < waitMs) {\n throw new Error(\n `debounce: maxWaitMs (${maxWaitMs.toString()}) cannot be less than waitMs (${waitMs.toString()})`,\n );\n }\n\n let cachedValue: ReturnType<F> | undefined;\n\n const debouncingFunnel = funnel(\n (args: Parameters<F>) => {\n // @ts-expect-error [ts2345, ts2322] -- TypeScript infers the generic sub-\n // types too eagerly, making itself blind to the fact that the types\n // match here.\n cachedValue = func(...args) as ReturnType<F>;\n },\n {\n // Debounce stores the latest args it was called with for the next invocation of the callback.\n reducer: (_, ...args: Parameters<F>) => args,\n minQuietPeriodMs: waitMs ?? maxWaitMs ?? 0,\n ...(maxWaitMs !== undefined && { maxBurstDurationMs: maxWaitMs }),\n ...(timing === 'leading'\n ? { triggerAt: 'start' }\n : timing === 'both'\n ? { triggerAt: 'both' }\n : { triggerAt: 'end' }),\n },\n );\n\n return {\n call: (...args: Parameters<F>) => {\n debouncingFunnel.call(...args);\n return cachedValue;\n },\n\n flush: () => {\n debouncingFunnel.flush();\n return cachedValue;\n },\n\n cancel: () => {\n debouncingFunnel.cancel();\n },\n\n get isPending() {\n return !debouncingFunnel.isIdle;\n },\n\n get cachedValue() {\n return cachedValue;\n },\n };\n}\n\ndescribe('main functionality', () => {\n it('should debounce a function', async () => {\n const mockFn = vi.fn<(x: string) => string>(identity());\n const debouncer = debounce(mockFn, { waitMs: 32 });\n\n expect([\n debouncer.call('a'),\n debouncer.call('b'),\n debouncer.call('c'),\n ]).toStrictEqual([undefined, undefined, undefined]);\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(128);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n expect([\n debouncer.call('d'),\n debouncer.call('e'),\n debouncer.call('f'),\n ]).toStrictEqual(['c', 'c', 'c']);\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(256);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('subsequent debounced calls return the last `func` result', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n debouncer.call('a');\n await sleep(64);\n\n expect(debouncer.call('b')).toBe('a');\n\n await sleep(128);\n\n expect(debouncer.call('c')).toBe('b');\n });\n\n it('should not immediately call `func` when `wait` is `0`', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, {});\n debouncer.call();\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(5);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n\n it('should apply default options', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { waitMs: 32 });\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(64);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n\n it('should support a `leading` option', async () => {\n const leadingMockFn = vi.fn<() => void>();\n const bothMockFn = vi.fn<() => void>();\n const withLeading = debounce(leadingMockFn, {\n waitMs: 32,\n timing: 'leading',\n });\n withLeading.call();\n\n expect(leadingMockFn).toHaveBeenCalledTimes(1);\n\n const withLeadingAndTrailing = debounce(bothMockFn, {\n waitMs: 32,\n timing: 'both',\n });\n withLeadingAndTrailing.call();\n withLeadingAndTrailing.call();\n\n expect(bothMockFn).toHaveBeenCalledTimes(1);\n\n await sleep(64);\n\n expect(bothMockFn).toHaveBeenCalledTimes(2);\n\n withLeading.call();\n\n expect(leadingMockFn).toHaveBeenCalledTimes(2);\n });\n\n it('subsequent leading debounced calls return the last `func` result', async () => {\n const debouncer = debounce(identity(), { waitMs: 32, timing: 'leading' });\n\n expect([debouncer.call('a'), debouncer.call('b')]).toStrictEqual([\n 'a',\n 'a',\n ]);\n\n await sleep(64);\n\n expect([debouncer.call('c'), debouncer.call('d')]).toStrictEqual([\n 'c',\n 'c',\n ]);\n });\n\n it('should support a `trailing` option', async () => {\n const mockFn = vi.fn<() => void>();\n const withTrailing = debounce(mockFn, { waitMs: 32, timing: 'trailing' });\n withTrailing.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(64);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n});\n\ndescribe('optional param maxWaitMs', () => {\n it('should support a `maxWait` option', async () => {\n const mockFn = vi.fn<(x: string) => void>();\n const debouncer = debounce(mockFn, { waitMs: 32, maxWaitMs: 64 });\n debouncer.call('a');\n debouncer.call('b');\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(128);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n debouncer.call('c');\n debouncer.call('d');\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(256);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('should support `maxWait` in a tight loop', async () => {\n const withMockFn = vi.fn<() => void>();\n const withoutMockFn = vi.fn<() => void>();\n const withMaxWait = debounce(withMockFn, { waitMs: 32, maxWaitMs: 128 });\n const withoutMaxWait = debounce(withoutMockFn, { waitMs: 96 });\n const start = Date.now();\n while (Date.now() - start < 320) {\n withMaxWait.call();\n withoutMaxWait.call();\n }\n await sleep(1);\n\n expect(withoutMockFn).toHaveBeenCalledTimes(0);\n expect(withMockFn).not.toHaveBeenCalledTimes(0);\n });\n\n it('should queue a trailing call for subsequent debounced calls after `maxWait`', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { waitMs: 200, maxWaitMs: 200 });\n debouncer.call();\n setTimeout(() => {\n debouncer.call();\n }, 190);\n setTimeout(() => {\n debouncer.call();\n }, 200);\n setTimeout(() => {\n debouncer.call();\n }, 210);\n await sleep(500);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('should cancel `maxDelayed` when `delayed` is invoked', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { waitMs: 32, maxWaitMs: 64 });\n debouncer.call();\n await sleep(128);\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n\n await sleep(192);\n\n expect(mockFn).toHaveBeenCalledTimes(2);\n });\n\n it('works like a leaky bucket when only maxWaitMs is set', async () => {\n const mockFn = vi.fn<() => void>();\n const debouncer = debounce(mockFn, { maxWaitMs: 32 });\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(16);\n // Without maxWaitMs this call would cause the actual invocation to be\n // postponed for a full window.\n debouncer.call();\n\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(17);\n\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n});\n\ndescribe('additional functionality', () => {\n it('can cancel before the timer starts', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(() => {\n debouncer.cancel();\n }).not.toThrowError();\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.call('world')).toBe('hello');\n });\n\n it('can cancel the timer', async () => {\n const mockFn = vi.fn<() => string>(constant('Hello, World!'));\n const debouncer = debounce(mockFn, { waitMs: 32 });\n\n expect(debouncer.call()).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(1);\n\n expect(debouncer.call()).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n debouncer.cancel();\n await sleep(32);\n\n expect(debouncer.call()).toBeUndefined();\n expect(mockFn).toHaveBeenCalledTimes(0);\n\n await sleep(32);\n\n expect(debouncer.call()).toBe('Hello, World!');\n expect(mockFn).toHaveBeenCalledTimes(1);\n });\n\n it('can cancel after the timer ends', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.call('world')).toBe('hello');\n expect(() => {\n debouncer.cancel();\n }).not.toThrowError();\n });\n\n it('can cancel maxWait timer', async () => {\n const debouncer = debounce(identity(), { waitMs: 16, maxWaitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(1);\n debouncer.cancel();\n await sleep(32);\n\n expect(debouncer.call('world')).toBeUndefined();\n });\n\n it('can return a cached value', () => {\n const debouncer = debounce(identity(), { timing: 'leading', waitMs: 32 });\n\n expect(debouncer.cachedValue).toBeUndefined();\n expect(debouncer.call('hello')).toBe('hello');\n expect(debouncer.cachedValue).toBe('hello');\n });\n\n it('can check for inflight timers (trailing)', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.isPending).toBe(false);\n expect(debouncer.call('hello')).toBeUndefined();\n expect(debouncer.isPending).toBe(true);\n\n await sleep(1);\n\n expect(debouncer.isPending).toBe(true);\n\n await sleep(32);\n\n expect(debouncer.isPending).toBe(false);\n });\n\n it('can check for inflight timers (leading)', async () => {\n const debouncer = debounce(identity(), { timing: 'leading', waitMs: 32 });\n\n expect(debouncer.isPending).toBe(false);\n expect(debouncer.call('hello')).toBe('hello');\n expect(debouncer.isPending).toBe(true);\n\n await sleep(1);\n\n expect(debouncer.isPending).toBe(true);\n\n await sleep(32);\n\n expect(debouncer.isPending).toBe(false);\n });\n\n it('can flush before a cool-down', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.flush()).toBeUndefined();\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.call('world')).toBe('hello');\n });\n\n it('can flush during a cool-down', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(1);\n\n expect(debouncer.call('world')).toBeUndefined();\n\n await sleep(1);\n\n expect(debouncer.flush()).toBe('world');\n });\n\n it('can flush after a cool-down', async () => {\n const debouncer = debounce(identity(), { waitMs: 32 });\n\n expect(debouncer.call('hello')).toBeUndefined();\n\n await sleep(32);\n\n expect(debouncer.flush()).toBe('hello');\n });\n});\n\ndescribe('errors', () => {\n it('prevents maxWaitMs to be less then waitMs', () => {\n expect(() => debounce(identity(), { waitMs: 32, maxWaitMs: 16 })).toThrowError(\n 'debounce: maxWaitMs (16) cannot be less than waitMs (32)',\n );\n });\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./dist-
|
|
1
|
+
const e=require(`./dist-8XtUY3ad.cjs`),t=require(`./do-nothing.cjs`),n=require(`./from-keys.cjs`),r=require(`./funnel.cjs`);function i(e,t,n=0){let i=r.funnel(n=>{e(n.map(({params:e})=>e)).then(e=>{for(let[r,{params:i,promiseCallbacks:[a]}]of n.entries())a(t(e,r,...i))}).catch(e=>{for(let{promiseCallbacks:[,t]}of n)t(e)})},{reducer:(e,t)=>[...e??[],t],maxBurstDurationMs:n,triggerAt:`end`});return{...i,call:async(...e)=>new Promise((...t)=>{i.call({promiseCallbacks:t,params:e})})}}e.i(`showcase`,()=>{e.a(`results as object`,async()=>{let t=e.r.fn(async e=>n.fromKeys(e,e=>e.length)),r=i(async e=>await t(e.flat()),(e,t,n)=>e[n]),a=[r.call(`short`),r.call(`medium`),r.call(`loooooooooooooong`)];e.n(t).toHaveBeenCalledTimes(0);let[o,s,c]=await Promise.all(a);e.n(t).toHaveBeenCalledTimes(1),e.n(t).toHaveBeenLastCalledWith([`short`,`medium`,`loooooooooooooong`]),e.n(t).toHaveLastResolvedWith({short:5,medium:6,loooooooooooooong:17}),e.n(o).toBe(5),e.n(s).toBe(6),e.n(c).toBe(17)}),e.a(`results as array`,async()=>{let t=e.r.fn(async e=>e.map(e=>e.length)),n=i(async e=>await t(e.flat()),(e,t)=>e[t]),r=[n.call(`short`),n.call(`medium`),n.call(`loooooooooooooong`)];e.n(t).toHaveBeenCalledTimes(0);let[a,o,s]=await Promise.all(r);e.n(t).toHaveBeenCalledTimes(1),e.n(t).toHaveBeenLastCalledWith([`short`,`medium`,`loooooooooooooong`]),e.n(t).toHaveLastResolvedWith([5,6,17]),e.n(a).toBe(5),e.n(o).toBe(6),e.n(s).toBe(17)}),e.a(`error handling`,async()=>{let n=i(async e=>{if(e.length>1)throw Error(`Batch too big! ${JSON.stringify(e)}`)},t.doNothing());await e.n(n.call(`a`)).resolves.toBeUndefined(),await e.n(Promise.all([n.call(`hello`),n.call(`world`)])).rejects.toThrowError(`Batch too big! [["hello"],["world"]]`)})});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{doNothing as e}from"./do-nothing.js";import{fromKeys as t}from"./from-keys.js";import{a as n,i as r,n as i,r as a}from"./dist-Bd1vawFi.js";import{funnel as o}from"./funnel.js";function s(e,t,n=0){let r=o(n=>{e(n.map(({params:e})=>e)).then(e=>{for(let[r,{params:i,promiseCallbacks:[a]}]of n.entries())a(t(e,r,...i))}).catch(e=>{for(let{promiseCallbacks:[,t]}of n)t(e)})},{reducer:(e,t)=>[...e??[],t],maxBurstDurationMs:n,triggerAt:`end`});return{...r,call:async(...e)=>new Promise((...t)=>{r.call({promiseCallbacks:t,params:e})})}}r(`showcase`,()=>{n(`results as object`,async()=>{let e=a.fn(async e=>t(e,e=>e.length)),n=s(async t=>await e(t.flat()),(e,t,n)=>e[n]),r=[n.call(`short`),n.call(`medium`),n.call(`loooooooooooooong`)];i(e).toHaveBeenCalledTimes(0);let[o,c,l]=await Promise.all(r);i(e).toHaveBeenCalledTimes(1),i(e).toHaveBeenLastCalledWith([`short`,`medium`,`loooooooooooooong`]),i(e).toHaveLastResolvedWith({short:5,medium:6,loooooooooooooong:17}),i(o).toBe(5),i(c).toBe(6),i(l).toBe(17)}),n(`results as array`,async()=>{let e=a.fn(async e=>e.map(e=>e.length)),t=s(async t=>await e(t.flat()),(e,t)=>e[t]),n=[t.call(`short`),t.call(`medium`),t.call(`loooooooooooooong`)];i(e).toHaveBeenCalledTimes(0);let[r,o,c]=await Promise.all(n);i(e).toHaveBeenCalledTimes(1),i(e).toHaveBeenLastCalledWith([`short`,`medium`,`loooooooooooooong`]),i(e).toHaveLastResolvedWith([5,6,17]),i(r).toBe(5),i(o).toBe(6),i(c).toBe(17)}),n(`error handling`,async()=>{let t=s(async e=>{if(e.length>1)throw Error(`Batch too big! ${JSON.stringify(e)}`)},e());await i(t.call(`a`)).resolves.toBeUndefined(),await i(Promise.all([t.call(`hello`),t.call(`world`)])).rejects.toThrowError(`Batch too big! [["hello"],["world"]]`)})});
|
|
2
2
|
//# sourceMappingURL=funnel.reference-batch.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"funnel.reference-batch.test.js","names":["expect"],"sources":["../src/funnel.reference-batch.test.ts"],"sourcesContent":["/* eslint-disable ts/explicit-function-return-type, ts/no-explicit-any --\n * These aren't useful for a reference implementation!\n */\n\nimport { describe, expect, it, vi } from 'vitest';\nimport { doNothing } from './do-nothing';\nimport { fromKeys } from './from-keys';\nimport { funnel } from './funnel';\n\ninterface BatchRequest<Params extends Array<any>, Result> {\n readonly params: Params;\n readonly promiseCallbacks: Readonly<\n Parameters<ConstructorParameters<typeof Promise<Result>>[0]>\n >;\n}\n\n/**\n * A reference implementation for an async batching utility function built on\n * top of the `funnel` general purpose execution utility function. It will\n * accumulate all params passed to an async `call` method within the defined\n * burst duration and then use an async executor to process them in one\n * invocation. It then extracts an individual result for each call which is\n * used to resolve the original call.\n *\n * This allows synchronizing multiple async calls while keeping each call site\n * isolated from the rest (for example, as react components).\n *\n * This reference implementation can be copied into your project as-is, or you\n * can use it as the basis for a more complex implementation with additional\n * features.\n *\n * @param callback - The main function that takes a batch and returns an\n * aggregated response. The typing for the it's parameters will derive the\n * typing for the extractor and the `call` method.\n * @param extractor - A function that takes the aggregated response and extracts\n * from it the result for each individual call. The function is called with both\n * the index in the batch, and the params passed to the `call` method. This\n * allows handling APIs that return batch results as both objects and arrays.\n * @param maxBurstDurationMs - The period of time where the batcher would\n * collect params before triggering the executor. When set to 0 the batcher\n * does not incur any additional delays to the execution and would trigger at\n * the next tick, just like a regular async function would. This is also the\n * default value.\n * @returns A Funnel object with the `call` method augmented to support async\n * response.\n */\nfunction batch<Params extends Array<any>, BatchResponse, Result>(\n callback: (requests: ReadonlyArray<Params>) => Promise<BatchResponse>,\n extractor: (\n response: BatchResponse,\n index: number,\n ...params: Params\n ) => Result,\n maxBurstDurationMs = 0,\n) {\n const batchFunnel = funnel(\n // Passes all accumulated parameters to the callback and then extracts the response for each individual call via the extractor.\n (requests: ReadonlyArray<BatchRequest<Params, Result>>) => {\n callback(requests.map(({ params }) => params))\n // On success we iterate again over all calls and allow the extractor to pull a value out of the aggregated response for each one.\n .then((response) => {\n for (const [\n index,\n {\n params,\n promiseCallbacks: [resolve],\n },\n ] of requests.entries()) {\n const result = extractor(response, index, ...params);\n resolve(result);\n }\n })\n\n // On error we simply pass the error along to all reject callbacks.\n .catch((error) => {\n for (const {\n promiseCallbacks: [, reject],\n } of requests) {\n reject(error);\n }\n });\n },\n {\n // Reducer: Accumulates the parameters for each call, together with the promise executor callbacks needed to resolve or reject the call.\n reducer: (requests, request: BatchRequest<Params, Result>) => [\n ...(requests ?? []),\n request,\n ],\n maxBurstDurationMs,\n triggerAt: 'end',\n },\n );\n\n return {\n ...batchFunnel,\n\n call: async (...params: Params) =>\n new Promise<Result>((...promiseCallbacks) => {\n batchFunnel.call({ promiseCallbacks, params });\n }),\n };\n}\n\ndescribe('showcase', () => {\n it('results as object', async () => {\n const mockApi = vi.fn<\n (words: ReadonlyArray<string>) => Promise<Record<string, number>>\n
|
|
1
|
+
{"version":3,"file":"funnel.reference-batch.test.js","names":["expect"],"sources":["../src/funnel.reference-batch.test.ts"],"sourcesContent":["/* eslint-disable ts/explicit-function-return-type, ts/no-explicit-any --\n * These aren't useful for a reference implementation!\n */\n\nimport { describe, expect, it, vi } from 'vitest';\nimport { doNothing } from './do-nothing';\nimport { fromKeys } from './from-keys';\nimport { funnel } from './funnel';\n\ninterface BatchRequest<Params extends Array<any>, Result> {\n readonly params: Params;\n readonly promiseCallbacks: Readonly<\n Parameters<ConstructorParameters<typeof Promise<Result>>[0]>\n >;\n}\n\n/**\n * A reference implementation for an async batching utility function built on\n * top of the `funnel` general purpose execution utility function. It will\n * accumulate all params passed to an async `call` method within the defined\n * burst duration and then use an async executor to process them in one\n * invocation. It then extracts an individual result for each call which is\n * used to resolve the original call.\n *\n * This allows synchronizing multiple async calls while keeping each call site\n * isolated from the rest (for example, as react components).\n *\n * This reference implementation can be copied into your project as-is, or you\n * can use it as the basis for a more complex implementation with additional\n * features.\n *\n * @param callback - The main function that takes a batch and returns an\n * aggregated response. The typing for the it's parameters will derive the\n * typing for the extractor and the `call` method.\n * @param extractor - A function that takes the aggregated response and extracts\n * from it the result for each individual call. The function is called with both\n * the index in the batch, and the params passed to the `call` method. This\n * allows handling APIs that return batch results as both objects and arrays.\n * @param maxBurstDurationMs - The period of time where the batcher would\n * collect params before triggering the executor. When set to 0 the batcher\n * does not incur any additional delays to the execution and would trigger at\n * the next tick, just like a regular async function would. This is also the\n * default value.\n * @returns A Funnel object with the `call` method augmented to support async\n * response.\n */\nfunction batch<Params extends Array<any>, BatchResponse, Result>(\n callback: (requests: ReadonlyArray<Params>) => Promise<BatchResponse>,\n extractor: (\n response: BatchResponse,\n index: number,\n ...params: Params\n ) => Result,\n maxBurstDurationMs = 0,\n) {\n const batchFunnel = funnel(\n // Passes all accumulated parameters to the callback and then extracts the response for each individual call via the extractor.\n (requests: ReadonlyArray<BatchRequest<Params, Result>>) => {\n callback(requests.map(({ params }) => params))\n // On success we iterate again over all calls and allow the extractor to pull a value out of the aggregated response for each one.\n .then((response) => {\n for (const [\n index,\n {\n params,\n promiseCallbacks: [resolve],\n },\n ] of requests.entries()) {\n const result = extractor(response, index, ...params);\n resolve(result);\n }\n })\n\n // On error we simply pass the error along to all reject callbacks.\n .catch((error) => {\n for (const {\n promiseCallbacks: [, reject],\n } of requests) {\n reject(error);\n }\n });\n },\n {\n // Reducer: Accumulates the parameters for each call, together with the promise executor callbacks needed to resolve or reject the call.\n reducer: (requests, request: BatchRequest<Params, Result>) => [\n ...(requests ?? []),\n request,\n ],\n maxBurstDurationMs,\n triggerAt: 'end',\n },\n );\n\n return {\n ...batchFunnel,\n\n call: async (...params: Params) =>\n new Promise<Result>((...promiseCallbacks) => {\n batchFunnel.call({ promiseCallbacks, params });\n }),\n };\n}\n\ndescribe('showcase', () => {\n it('results as object', async () => {\n const mockApi = vi.fn<\n (words: ReadonlyArray<string>) => Promise<Record<string, number>>\n >(async (words) => fromKeys(words, (word) => word.length));\n\n const countLettersApi = batch(\n // We only need to type the `requests` param of the `executor` callback.\n // All other types are derived from it.\n async (requests: ReadonlyArray<[word: string]>) =>\n await mockApi(requests.flat()),\n (response, _, word) => response[word],\n );\n\n const prepared = [\n countLettersApi.call('short'),\n countLettersApi.call('medium'),\n countLettersApi.call('loooooooooooooong'),\n ];\n\n expect(mockApi).toHaveBeenCalledTimes(0);\n\n const [shortResult, mediumResult, longResult] = await Promise.all(prepared);\n\n expect(mockApi).toHaveBeenCalledTimes(1);\n expect(mockApi).toHaveBeenLastCalledWith([\n 'short',\n 'medium',\n 'loooooooooooooong',\n ]);\n expect(mockApi).toHaveLastResolvedWith({\n short: 5,\n medium: 6,\n loooooooooooooong: 17,\n });\n expect(shortResult).toBe(5);\n expect(mediumResult).toBe(6);\n expect(longResult).toBe(17);\n });\n\n it('results as array', async () => {\n const mockApi = vi.fn<\n (words: ReadonlyArray<string>) => Promise<ReadonlyArray<number>>\n >(async (words) => words.map((word) => word.length));\n\n const countLettersApi = batch(\n // We only need to type the `requests` param of the `executor` callback.\n // All other types are derived from it.\n async (requests: ReadonlyArray<[word: string]>) =>\n await mockApi(requests.flat()),\n (response, index) => response[index],\n );\n\n const prepared = [\n countLettersApi.call('short'),\n countLettersApi.call('medium'),\n countLettersApi.call('loooooooooooooong'),\n ];\n\n expect(mockApi).toHaveBeenCalledTimes(0);\n\n const [shortResult, mediumResult, longResult] = await Promise.all(prepared);\n\n expect(mockApi).toHaveBeenCalledTimes(1);\n expect(mockApi).toHaveBeenLastCalledWith([\n 'short',\n 'medium',\n 'loooooooooooooong',\n ]);\n expect(mockApi).toHaveLastResolvedWith([5, 6, 17]);\n expect(shortResult).toBe(5);\n expect(mediumResult).toBe(6);\n expect(longResult).toBe(17);\n });\n\n it('error handling', async () => {\n const failingApi = batch(\n // We only need to type the `requests` param of the `executor` callback.\n // All other types are derived from it.\n async (requests: ReadonlyArray<[id: string]>) => {\n if (requests.length > 1) {\n throw new Error(`Batch too big! ${JSON.stringify(requests)}`);\n }\n },\n doNothing(),\n );\n\n await expect(failingApi.call('a')).resolves.toBeUndefined();\n\n await expect(\n Promise.all([failingApi.call('hello'), failingApi.call('world')]),\n ).rejects.toThrowError('Batch too big! [[\"hello\"],[\"world\"]]');\n });\n});\n"],"mappings":"uLA8CA,SAAS,EACP,EACA,EAKA,EAAqB,EACrB,CACA,IAAM,EAAc,EAEjB,GAA0D,CACzD,EAAS,EAAS,KAAK,CAAE,YAAa,EAAO,CAAC,CAE3C,KAAM,GAAa,CAClB,IAAK,GAAM,CACT,EACA,CACE,SACA,iBAAkB,CAAC,OAElB,EAAS,SAAS,CAErB,EADe,EAAU,EAAU,EAAO,GAAG,EAAO,CACrC,EAEjB,CAGD,MAAO,GAAU,CAChB,IAAK,GAAM,CACT,iBAAkB,EAAG,MAClB,EACH,EAAO,EAAM,EAEf,EAEN,CAEE,SAAU,EAAU,IAA0C,CAC5D,GAAI,GAAY,EAAE,CAClB,EACD,CACD,qBACA,UAAW,MACZ,CACF,CAED,MAAO,CACL,GAAG,EAEH,KAAM,MAAO,GAAG,IACd,IAAI,SAAiB,GAAG,IAAqB,CAC3C,EAAY,KAAK,CAAE,mBAAkB,SAAQ,CAAC,EAC9C,CACL,CAGH,EAAS,eAAkB,CACzB,EAAG,oBAAqB,SAAY,CAClC,IAAM,EAAU,EAAG,GAEjB,KAAO,IAAU,EAAS,EAAQ,GAAS,EAAK,OAAO,CAAC,CAEpD,EAAkB,EAGtB,KAAO,IACL,MAAM,EAAQ,EAAS,MAAM,CAAC,EAC/B,EAAU,EAAG,IAAS,EAAS,GACjC,CAEK,EAAW,CACf,EAAgB,KAAK,QAAQ,CAC7B,EAAgB,KAAK,SAAS,CAC9B,EAAgB,KAAK,oBAAoB,CAC1C,CAED,EAAO,EAAQ,CAAC,sBAAsB,EAAE,CAExC,GAAM,CAAC,EAAa,EAAc,GAAc,MAAM,QAAQ,IAAI,EAAS,CAE3E,EAAO,EAAQ,CAAC,sBAAsB,EAAE,CACxC,EAAO,EAAQ,CAAC,yBAAyB,CACvC,QACA,SACA,oBACD,CAAC,CACF,EAAO,EAAQ,CAAC,uBAAuB,CACrC,MAAO,EACP,OAAQ,EACR,kBAAmB,GACpB,CAAC,CACF,EAAO,EAAY,CAAC,KAAK,EAAE,CAC3B,EAAO,EAAa,CAAC,KAAK,EAAE,CAC5B,EAAO,EAAW,CAAC,KAAK,GAAG,EAC3B,CAEF,EAAG,mBAAoB,SAAY,CACjC,IAAM,EAAU,EAAG,GAEjB,KAAO,IAAU,EAAM,IAAK,GAAS,EAAK,OAAO,CAAC,CAE9C,EAAkB,EAGtB,KAAO,IACL,MAAM,EAAQ,EAAS,MAAM,CAAC,EAC/B,EAAU,IAAU,EAAS,GAC/B,CAEK,EAAW,CACf,EAAgB,KAAK,QAAQ,CAC7B,EAAgB,KAAK,SAAS,CAC9B,EAAgB,KAAK,oBAAoB,CAC1C,CAED,EAAO,EAAQ,CAAC,sBAAsB,EAAE,CAExC,GAAM,CAAC,EAAa,EAAc,GAAc,MAAM,QAAQ,IAAI,EAAS,CAE3E,EAAO,EAAQ,CAAC,sBAAsB,EAAE,CACxC,EAAO,EAAQ,CAAC,yBAAyB,CACvC,QACA,SACA,oBACD,CAAC,CACF,EAAO,EAAQ,CAAC,uBAAuB,CAAC,EAAG,EAAG,GAAG,CAAC,CAClD,EAAO,EAAY,CAAC,KAAK,EAAE,CAC3B,EAAO,EAAa,CAAC,KAAK,EAAE,CAC5B,EAAO,EAAW,CAAC,KAAK,GAAG,EAC3B,CAEF,EAAG,iBAAkB,SAAY,CAC/B,IAAM,EAAa,EAGjB,KAAO,IAA0C,CAC/C,GAAI,EAAS,OAAS,EACpB,MAAU,MAAM,kBAAkB,KAAK,UAAU,EAAS,GAAG,EAGjE,GAAW,CACZ,CAED,MAAMA,EAAO,EAAW,KAAK,IAAI,CAAC,CAAC,SAAS,eAAe,CAE3D,MAAMA,EACJ,QAAQ,IAAI,CAAC,EAAW,KAAK,QAAQ,CAAE,EAAW,KAAK,QAAQ,CAAC,CAAC,CAClE,CAAC,QAAQ,aAAa,uCAAuC,EAC9D,EACF"}
|
package/dist/funnel.test-d.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./dist-
|
|
1
|
+
const e=require(`./dist-8XtUY3ad.cjs`),t=require(`./do-nothing.cjs`),n=require(`./funnel.cjs`);e.i(`'call' method args`,()=>{e.a(`no args`,()=>{(0,e.t.expectTypeOf)(n.funnel(t.doNothing(),{reducer:e=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()}),e.a(`non-optional args`,()=>{(0,e.t.expectTypeOf)(n.funnel(t.doNothing(),{reducer:(e,t,n,r)=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()}),e.a(`optional args`,()=>{(0,e.t.expectTypeOf)(n.funnel(t.doNothing(),{reducer:(e,t)=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()}),e.a(`rest args`,()=>{(0,e.t.expectTypeOf)(n.funnel(t.doNothing(),{reducer:(e,...t)=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()})}),e.i(`derive the reducer accumulator type from the executor param`,()=>{e.a(`simple types`,()=>{n.funnel(e=>{},{reducer:t=>((0,e.t.expectTypeOf)(t).toEqualTypeOf(),t),triggerAt:`start`})}),e.a(`arrays`,()=>{n.funnel(e=>{},{reducer:t=>((0,e.t.expectTypeOf)(t).toEqualTypeOf(),t),triggerAt:`start`})}),e.a(`objects`,()=>{n.funnel(e=>{},{reducer:t=>((0,e.t.expectTypeOf)(t).toEqualTypeOf(),t),triggerAt:`start`})})}),e.i(`prevent bad options`,()=>{e.a(`minGapMs cannot be the only option with timing: end`,()=>{n.funnel(t.doNothing(),{minGapMs:100}),n.funnel(t.doNothing(),{triggerAt:`end`,minGapMs:100}),n.funnel(t.doNothing(),{triggerAt:`start`,minGapMs:100}),n.funnel(t.doNothing(),{triggerAt:`both`,minGapMs:100})})});
|
package/dist/funnel.test-d.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{doNothing as e}from"./do-nothing.js";import{a as t,i as n,t as r}from"./dist-Bd1vawFi.js";import{funnel as i}from"./funnel.js";n(`'call' method args`,()=>{t(`no args`,()=>{r(i(e(),{reducer:e=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()}),t(`non-optional args`,()=>{r(i(e(),{reducer:(e,t,n,r)=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()}),t(`optional args`,()=>{r(i(e(),{reducer:(e,t)=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()}),t(`rest args`,()=>{r(i(e(),{reducer:(e,...t)=>`test`,triggerAt:`start`}).call).parameters.toEqualTypeOf()})}),n(`derive the reducer accumulator type from the executor param`,()=>{t(`simple types`,()=>{i(e=>{},{reducer:e=>(r(e).toEqualTypeOf(),e),triggerAt:`start`})}),t(`arrays`,()=>{i(e=>{},{reducer:e=>(r(e).toEqualTypeOf(),e),triggerAt:`start`})}),t(`objects`,()=>{i(e=>{},{reducer:e=>(r(e).toEqualTypeOf(),e),triggerAt:`start`})})}),n(`prevent bad options`,()=>{t(`minGapMs cannot be the only option with timing: end`,()=>{i(e(),{minGapMs:100}),i(e(),{triggerAt:`end`,minGapMs:100}),i(e(),{triggerAt:`start`,minGapMs:100}),i(e(),{triggerAt:`both`,minGapMs:100})})});
|
|
2
2
|
//# sourceMappingURL=funnel.test-d.js.map
|