@nunofyobiz/effect-extras 1.0.0 → 2.1.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.
Files changed (128) hide show
  1. package/README.md +50 -6
  2. package/dist/ArrayX.d.ts +415 -0
  3. package/dist/ArrayX.d.ts.map +1 -0
  4. package/dist/ArrayX.js +547 -0
  5. package/dist/ArrayX.js.map +1 -0
  6. package/dist/BigIntX.d.ts +24 -0
  7. package/dist/BigIntX.d.ts.map +1 -0
  8. package/dist/BigIntX.js +30 -0
  9. package/dist/BigIntX.js.map +1 -0
  10. package/dist/BooleanX.d.ts +25 -0
  11. package/dist/BooleanX.d.ts.map +1 -0
  12. package/dist/BooleanX.js +25 -0
  13. package/dist/BooleanX.js.map +1 -0
  14. package/dist/DurationX.d.ts +73 -0
  15. package/dist/DurationX.d.ts.map +1 -0
  16. package/dist/DurationX.js +91 -0
  17. package/dist/DurationX.js.map +1 -0
  18. package/dist/EffectX.d.ts +120 -0
  19. package/dist/EffectX.d.ts.map +1 -0
  20. package/dist/EffectX.js +140 -0
  21. package/dist/EffectX.js.map +1 -0
  22. package/dist/FormDataX.d.ts +49 -0
  23. package/dist/FormDataX.d.ts.map +1 -0
  24. package/dist/FormDataX.js +42 -0
  25. package/dist/FormDataX.js.map +1 -0
  26. package/dist/MapX.d.ts +32 -0
  27. package/dist/MapX.d.ts.map +1 -0
  28. package/dist/MapX.js +49 -0
  29. package/dist/MapX.js.map +1 -0
  30. package/dist/NonNullableX.d.ts +174 -0
  31. package/dist/NonNullableX.d.ts.map +1 -0
  32. package/dist/NonNullableX.js +212 -0
  33. package/dist/NonNullableX.js.map +1 -0
  34. package/dist/NumberX.d.ts +178 -0
  35. package/dist/NumberX.d.ts.map +1 -0
  36. package/dist/NumberX.js +214 -0
  37. package/dist/NumberX.js.map +1 -0
  38. package/dist/OptionX.d.ts +181 -0
  39. package/dist/OptionX.d.ts.map +1 -0
  40. package/dist/OptionX.js +195 -0
  41. package/dist/OptionX.js.map +1 -0
  42. package/dist/OrderX.d.ts +32 -0
  43. package/dist/OrderX.d.ts.map +1 -0
  44. package/dist/OrderX.js +32 -0
  45. package/dist/OrderX.js.map +1 -0
  46. package/dist/PredicateX.d.ts +76 -0
  47. package/dist/PredicateX.d.ts.map +1 -0
  48. package/dist/PredicateX.js +73 -0
  49. package/dist/PredicateX.js.map +1 -0
  50. package/dist/PromiseX.d.ts +32 -0
  51. package/dist/PromiseX.d.ts.map +1 -0
  52. package/dist/PromiseX.js +32 -0
  53. package/dist/PromiseX.js.map +1 -0
  54. package/dist/RecordX.d.ts +323 -0
  55. package/dist/RecordX.d.ts.map +1 -0
  56. package/dist/RecordX.js +326 -0
  57. package/dist/RecordX.js.map +1 -0
  58. package/dist/ResultX.d.ts +50 -0
  59. package/dist/ResultX.d.ts.map +1 -0
  60. package/dist/ResultX.js +50 -0
  61. package/dist/ResultX.js.map +1 -0
  62. package/dist/SchemaX.d.ts +249 -0
  63. package/dist/SchemaX.d.ts.map +1 -0
  64. package/dist/SchemaX.js +243 -0
  65. package/dist/SchemaX.js.map +1 -0
  66. package/dist/SetX.d.ts +121 -0
  67. package/dist/SetX.d.ts.map +1 -0
  68. package/dist/SetX.js +137 -0
  69. package/dist/SetX.js.map +1 -0
  70. package/dist/StringX.d.ts +70 -0
  71. package/dist/StringX.d.ts.map +1 -0
  72. package/dist/StringX.js +81 -0
  73. package/dist/StringX.js.map +1 -0
  74. package/dist/StructX.d.ts +219 -0
  75. package/dist/StructX.d.ts.map +1 -0
  76. package/dist/StructX.js +173 -0
  77. package/dist/StructX.js.map +1 -0
  78. package/dist/WarnResult.d.ts +1146 -0
  79. package/dist/WarnResult.d.ts.map +1 -0
  80. package/dist/WarnResult.js +1060 -0
  81. package/dist/WarnResult.js.map +1 -0
  82. package/dist/index.d.ts +22 -3703
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +21 -1005
  85. package/dist/index.js.map +1 -1
  86. package/package.json +18 -5
  87. package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +29 -27
  88. package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
  89. package/src/{RecordX/RecordX.ts → RecordX.ts} +1 -1
  90. package/src/WarnResult.ts +1265 -0
  91. package/src/index.ts +21 -20
  92. package/src/ArrayX/index.ts +0 -1
  93. package/src/BigIntX/index.ts +0 -1
  94. package/src/BooleanX/index.ts +0 -1
  95. package/src/DurationX/index.ts +0 -1
  96. package/src/EffectX/index.ts +0 -1
  97. package/src/FormDataX/index.ts +0 -1
  98. package/src/MapX/index.ts +0 -1
  99. package/src/NonNullableX/index.ts +0 -2
  100. package/src/NumberX/index.ts +0 -1
  101. package/src/OptionX/index.ts +0 -1
  102. package/src/OrderX/index.ts +0 -1
  103. package/src/PredicateX/index.ts +0 -1
  104. package/src/PromiseX/index.ts +0 -1
  105. package/src/RecordX/index.ts +0 -1
  106. package/src/ResultX/index.ts +0 -1
  107. package/src/SchemaX/index.ts +0 -1
  108. package/src/SetX/index.ts +0 -1
  109. package/src/StringX/index.ts +0 -1
  110. package/src/StructX/index.ts +0 -1
  111. package/src/These/These.ts +0 -1173
  112. package/src/These/index.ts +0 -1
  113. /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
  114. /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
  115. /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
  116. /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
  117. /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
  118. /package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +0 -0
  119. /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
  120. /package/src/{OptionX/OptionX.ts → OptionX.ts} +0 -0
  121. /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
  122. /package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +0 -0
  123. /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
  124. /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
  125. /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
  126. /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
  127. /package/src/{StringX/StringX.ts → StringX.ts} +0 -0
  128. /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Predicate` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Predicate } from "effect";
7
+ /**
8
+ * Runs a refinement against `value` and branches on the result, passing the
9
+ * narrowed value to the `whenTrue` handler.
10
+ *
11
+ * It pairs a `Predicate.Refinement<A, B>` with two continuations so the success
12
+ * branch receives `value` already narrowed to `B`, replacing an `if`/`else` that
13
+ * would otherwise re-check or cast. Supports both data-first and data-last
14
+ * (pipeable) call styles.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
19
+ * import { Predicate, pipe } from "effect"
20
+ *
21
+ * // Data-first
22
+ * assert.deepStrictEqual(
23
+ * PredicateX.matchRefine("hello", Predicate.isString, {
24
+ * whenTrue: (value) => `String: ${value}`,
25
+ * whenFalse: () => "Not a string"
26
+ * }),
27
+ * "String: hello"
28
+ * )
29
+ *
30
+ * // Data-last (pipeable)
31
+ * assert.deepStrictEqual(
32
+ * pipe(
33
+ * 42,
34
+ * PredicateX.matchRefine(Predicate.isString, {
35
+ * whenTrue: (value) => `String: ${value}`,
36
+ * whenFalse: () => "Not a string"
37
+ * })
38
+ * ),
39
+ * "Not a string"
40
+ * )
41
+ * ```
42
+ *
43
+ * @category pattern matching
44
+ * @since 0.0.0
45
+ */
46
+ export declare const matchRefine: (<A, B extends A, C>(predicate: Predicate.Refinement<A, B>, handlers: {
47
+ whenFalse: () => C;
48
+ whenTrue: (value: B) => C;
49
+ }) => (value: A) => C) & (<A, B extends A, C>(value: A, predicate: Predicate.Refinement<A, B>, handlers: {
50
+ whenFalse: () => C;
51
+ whenTrue: (value: B) => C;
52
+ }) => C);
53
+ /**
54
+ * Refines an `unknown` value to a non-empty `string`, returning `true` only when
55
+ * the value is present, is a `string`, and has at least one character.
56
+ *
57
+ * This is the compound guard the repo's conventions call for: it folds
58
+ * `Predicate.isNotNullish`, `Predicate.isString`, and `String.isNonEmpty` into a
59
+ * single reusable refinement so call sites get `value is string` narrowing
60
+ * without restating the three checks.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
65
+ *
66
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString("hello"), true)
67
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(""), false)
68
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(null), false)
69
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(123), false)
70
+ * ```
71
+ *
72
+ * @category refinements
73
+ * @since 0.0.0
74
+ */
75
+ export declare function isNonEmptyString(value: unknown): value is string;
76
+ //# sourceMappingURL=PredicateX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PredicateX.d.ts","sourceRoot":"","sources":["../src/PredicateX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAU,MAAM,QAAQ,CAAC;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,WAAW,IACrB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,aACL,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,YAC3B;IACR,SAAS,EAAE,MAAM,CAAC,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;CAC3B,KACE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,MACnB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,SACT,CAAC,aACG,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,YAC3B;IAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;CAAE,KACxD,CAAC,CAQP,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAMhE"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Predicate` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Predicate, String } from "effect";
7
+ import { dual } from "effect/Function";
8
+ /**
9
+ * Runs a refinement against `value` and branches on the result, passing the
10
+ * narrowed value to the `whenTrue` handler.
11
+ *
12
+ * It pairs a `Predicate.Refinement<A, B>` with two continuations so the success
13
+ * branch receives `value` already narrowed to `B`, replacing an `if`/`else` that
14
+ * would otherwise re-check or cast. Supports both data-first and data-last
15
+ * (pipeable) call styles.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
20
+ * import { Predicate, pipe } from "effect"
21
+ *
22
+ * // Data-first
23
+ * assert.deepStrictEqual(
24
+ * PredicateX.matchRefine("hello", Predicate.isString, {
25
+ * whenTrue: (value) => `String: ${value}`,
26
+ * whenFalse: () => "Not a string"
27
+ * }),
28
+ * "String: hello"
29
+ * )
30
+ *
31
+ * // Data-last (pipeable)
32
+ * assert.deepStrictEqual(
33
+ * pipe(
34
+ * 42,
35
+ * PredicateX.matchRefine(Predicate.isString, {
36
+ * whenTrue: (value) => `String: ${value}`,
37
+ * whenFalse: () => "Not a string"
38
+ * })
39
+ * ),
40
+ * "Not a string"
41
+ * )
42
+ * ```
43
+ *
44
+ * @category pattern matching
45
+ * @since 0.0.0
46
+ */
47
+ export const matchRefine = /*#__PURE__*/dual(3, (value, predicate, handlers) => predicate(value) ? handlers.whenTrue(value) : handlers.whenFalse());
48
+ /**
49
+ * Refines an `unknown` value to a non-empty `string`, returning `true` only when
50
+ * the value is present, is a `string`, and has at least one character.
51
+ *
52
+ * This is the compound guard the repo's conventions call for: it folds
53
+ * `Predicate.isNotNullish`, `Predicate.isString`, and `String.isNonEmpty` into a
54
+ * single reusable refinement so call sites get `value is string` narrowing
55
+ * without restating the three checks.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
60
+ *
61
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString("hello"), true)
62
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(""), false)
63
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(null), false)
64
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(123), false)
65
+ * ```
66
+ *
67
+ * @category refinements
68
+ * @since 0.0.0
69
+ */
70
+ export function isNonEmptyString(value) {
71
+ return Predicate.isNotNullish(value) && Predicate.isString(value) && String.isNonEmpty(value);
72
+ }
73
+ //# sourceMappingURL=PredicateX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PredicateX.js","names":["Predicate","String","dual","matchRefine","value","predicate","handlers","whenTrue","whenFalse","isNonEmptyString","isNotNullish","isString","isNonEmpty"],"sources":["../src/PredicateX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,SAAS,EAAEC,MAAM,QAAQ,QAAQ;AAC1C,SAASC,IAAI,QAAQ,iBAAiB;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,OAAO,MAAMC,WAAW,gBAAGD,IAAI,CAc7B,CAAC,EACD,CACEE,KAAQ,EACRC,SAAqC,EACrCC,QAA2D,KACpDD,SAAS,CAACD,KAAK,CAAC,GAAGE,QAAQ,CAACC,QAAQ,CAACH,KAAK,CAAC,GAAGE,QAAQ,CAACE,SAAS,EAAG,CAC7E;AAED;;;;;;;;;;;;;;;;;;;;;;AAsBA,OAAM,SAAUC,gBAAgBA,CAACL,KAAc;EAC7C,OACEJ,SAAS,CAACU,YAAY,CAACN,KAAK,CAAC,IAC7BJ,SAAS,CAACW,QAAQ,CAACP,KAAK,CAAC,IACzBH,MAAM,CAACW,UAAU,CAACR,KAAK,CAAC;AAE5B","ignoreList":[]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Helpers for working with native `Promise`s.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ /**
7
+ * Discards the resolved value of a `Promise`, returning a `Promise<void>` that
8
+ * resolves once the original settles.
9
+ *
10
+ * Useful when you await a promise only for its side effect and want the result
11
+ * type to reflect that nothing meaningful is produced — for example when an API
12
+ * expects a `Promise<void>` or when narrowing a value-bearing promise to keep
13
+ * call sites from accidentally depending on the resolved value. A rejection of
14
+ * the original promise still propagates.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { PromiseX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * const run = async (): Promise<void> => {
21
+ * const result = await PromiseX.asVoid(Promise.resolve(42))
22
+ * assert.deepStrictEqual(result, undefined)
23
+ * }
24
+ *
25
+ * void run()
26
+ * ```
27
+ *
28
+ * @category conversions
29
+ * @since 0.0.0
30
+ */
31
+ export declare const asVoid: <T>(promise: Promise<T>) => Promise<void>;
32
+ //# sourceMappingURL=PromiseX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromiseX.d.ts","sourceRoot":"","sources":["../src/PromiseX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,IAAI,CAC7B,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Helpers for working with native `Promise`s.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ /**
7
+ * Discards the resolved value of a `Promise`, returning a `Promise<void>` that
8
+ * resolves once the original settles.
9
+ *
10
+ * Useful when you await a promise only for its side effect and want the result
11
+ * type to reflect that nothing meaningful is produced — for example when an API
12
+ * expects a `Promise<void>` or when narrowing a value-bearing promise to keep
13
+ * call sites from accidentally depending on the resolved value. A rejection of
14
+ * the original promise still propagates.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { PromiseX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * const run = async (): Promise<void> => {
21
+ * const result = await PromiseX.asVoid(Promise.resolve(42))
22
+ * assert.deepStrictEqual(result, undefined)
23
+ * }
24
+ *
25
+ * void run()
26
+ * ```
27
+ *
28
+ * @category conversions
29
+ * @since 0.0.0
30
+ */
31
+ export const asVoid = promise => promise.then(() => undefined);
32
+ //# sourceMappingURL=PromiseX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromiseX.js","names":["asVoid","promise","then","undefined"],"sources":["../src/PromiseX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,OAAO,MAAMA,MAAM,GAAOC,OAAmB,IAC3CA,OAAO,CAACC,IAAI,CAAC,MAAMC,SAAS,CAAC","ignoreList":[]}
@@ -0,0 +1,323 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Record` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Option, Order, Predicate } from "effect";
7
+ /**
8
+ * Returns `true` when `record` has at least one entry, narrowing it to a
9
+ * known-non-empty `Record`.
10
+ *
11
+ * The negation of `Record.isEmptyRecord`, packaged as a type guard so it reads
12
+ * naturally at call sites that want to branch on "this record has something in
13
+ * it" without a manual `!Record.isEmptyRecord(...)`.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { RecordX } from "@nunofyobiz/effect-extras"
18
+ *
19
+ * assert.deepStrictEqual(RecordX.isNonEmptyRecord({ a: 1 }), true)
20
+ * assert.deepStrictEqual(RecordX.isNonEmptyRecord({}), false)
21
+ * ```
22
+ *
23
+ * @category guards
24
+ * @since 0.0.0
25
+ */
26
+ export declare const isNonEmptyRecord: <K extends PropertyKey, V>(record: Record<K, V>) => record is Record<K, V>;
27
+ /**
28
+ * Modifies the value at `key` in `self` with `f`, leaving the record unchanged
29
+ * if the key doesn't exist.
30
+ *
31
+ * v4's `Record.modify` returns `Option<Record>` — `None` when the key is
32
+ * absent. This helper picks the "do nothing if absent" semantics that v3's
33
+ * `Record.modify` had implicitly, and that most call sites assume. The modifier
34
+ * is never invoked when the key is missing.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import { pipe } from "effect"
39
+ * import { RecordX } from "@nunofyobiz/effect-extras"
40
+ *
41
+ * // data-first
42
+ * assert.deepStrictEqual(
43
+ * RecordX.modifyIfExists({ a: 1, b: 2 }, "b", (n) => n * 10),
44
+ * { a: 1, b: 20 },
45
+ * )
46
+ *
47
+ * // a missing key leaves the record untouched
48
+ * const counts: Record<string, number> = { a: 1, b: 2 }
49
+ * assert.deepStrictEqual(
50
+ * RecordX.modifyIfExists(counts, "missing", (n) => n + 1),
51
+ * { a: 1, b: 2 },
52
+ * )
53
+ *
54
+ * // data-last (pipeable)
55
+ * assert.deepStrictEqual(
56
+ * pipe({ a: 1, b: 2 }, RecordX.modifyIfExists("a", (n) => n * 10)),
57
+ * { a: 10, b: 2 },
58
+ * )
59
+ * ```
60
+ *
61
+ * @category mapping
62
+ * @since 0.0.0
63
+ */
64
+ export declare const modifyIfExists: {
65
+ <K extends string, A>(key: NoInfer<K>, f: (a: A) => A): (self: Record<K, A>) => Record<K, A>;
66
+ <K extends string, A>(self: Record<K, A>, key: NoInfer<K>, f: (a: A) => A): Record<K, A>;
67
+ };
68
+ /**
69
+ * Returns the smallest value of `record` (per `order`) that matches
70
+ * `predicate`, narrowed to the refined type `B`, or `Option.none()` if none
71
+ * match.
72
+ *
73
+ * The `Record` counterpart of `ArrayX.takeFirstWhere`: it considers only the
74
+ * record's values, keeps those satisfying `predicate`, and returns the minimum
75
+ * of them by `order`. Keys are ignored entirely.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * import { Option, Order, pipe } from "effect"
80
+ * import { RecordX } from "@nunofyobiz/effect-extras"
81
+ *
82
+ * const isEven = (n: number): n is number => n % 2 === 0
83
+ *
84
+ * // data-first
85
+ * assert.deepStrictEqual(
86
+ * RecordX.takeFirstWhere({ a: 3, b: 4, c: 2 }, isEven, Order.Number),
87
+ * Option.some(2),
88
+ * )
89
+ *
90
+ * // data-last (pipeable); no even values yields None
91
+ * assert.deepStrictEqual(
92
+ * pipe({ a: 1, b: 3 }, RecordX.takeFirstWhere(isEven, Order.Number)),
93
+ * Option.none(),
94
+ * )
95
+ * ```
96
+ *
97
+ * @category getters
98
+ * @since 0.0.0
99
+ */
100
+ export declare const takeFirstWhere: (<K extends PropertyKey, A, B extends A>(predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => (record: Record<K, A>) => Option.Option<B>) & (<K extends PropertyKey, A, B extends A>(record: Record<K, A>, predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => Option.Option<B>);
101
+ /**
102
+ * Returns the largest value of `record` (per `order`) that matches `predicate`,
103
+ * narrowed to the refined type `B`, or `Option.none()` if none match.
104
+ *
105
+ * The mirror of {@link takeFirstWhere}: it considers only the record's values,
106
+ * keeps those satisfying `predicate`, and returns the maximum of them by
107
+ * `order`. Keys are ignored entirely.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * import { Option, Order, pipe } from "effect"
112
+ * import { RecordX } from "@nunofyobiz/effect-extras"
113
+ *
114
+ * const isEven = (n: number): n is number => n % 2 === 0
115
+ *
116
+ * // data-first
117
+ * assert.deepStrictEqual(
118
+ * RecordX.takeLastWhere({ a: 3, b: 4, c: 2 }, isEven, Order.Number),
119
+ * Option.some(4),
120
+ * )
121
+ *
122
+ * // data-last (pipeable); no even values yields None
123
+ * assert.deepStrictEqual(
124
+ * pipe({ a: 1, b: 3 }, RecordX.takeLastWhere(isEven, Order.Number)),
125
+ * Option.none(),
126
+ * )
127
+ * ```
128
+ *
129
+ * @category getters
130
+ * @since 0.0.0
131
+ */
132
+ export declare const takeLastWhere: (<K extends PropertyKey, A, B extends A>(predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => (record: Record<K, A>) => Option.Option<B>) & (<K extends PropertyKey, A, B extends A>(record: Record<K, A>, predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => Option.Option<B>);
133
+ /**
134
+ * Returns the largest value of `record` according to `order`, wrapped in an
135
+ * `Option` so empty records are handled safely.
136
+ *
137
+ * Sorts the record's values by `order` and takes the last one, yielding
138
+ * `Option.none()` when the record is empty and `Option.some(max)` otherwise.
139
+ * Keys are ignored — only values participate in the ordering.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * import { Option, Order, pipe } from "effect"
144
+ * import { RecordX } from "@nunofyobiz/effect-extras"
145
+ *
146
+ * // data-first
147
+ * assert.deepStrictEqual(
148
+ * RecordX.takeLast({ a: 3, b: 5, c: 1 }, Order.Number),
149
+ * Option.some(5),
150
+ * )
151
+ *
152
+ * // data-last (pipeable); empty record yields None
153
+ * assert.deepStrictEqual(
154
+ * pipe({}, RecordX.takeLast(Order.Number)),
155
+ * Option.none(),
156
+ * )
157
+ * ```
158
+ *
159
+ * @category getters
160
+ * @since 0.0.0
161
+ */
162
+ export declare const takeLast: (<K extends PropertyKey, A>(order: Order.Order<A>) => (record: Record<K, A>) => Option.Option<A>) & (<K extends PropertyKey, A>(record: Record<K, A>, order: Order.Order<A>) => Option.Option<A>);
163
+ /**
164
+ * Re-types the keys of a `Record` to a different key type `K2` without touching
165
+ * the runtime value.
166
+ *
167
+ * A purely type-level reinterpretation: the record is returned as-is, but the
168
+ * compiler now treats its keys as `K2` instead of the inferred `K1`. Use it at a
169
+ * boundary where you know the keys conform to a narrower branded or literal key
170
+ * type that TypeScript can't infer from the value alone. It performs no
171
+ * validation — the caller is responsible for the keys actually matching `K2`.
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * import { RecordX } from "@nunofyobiz/effect-extras"
176
+ *
177
+ * type UserId = string & { readonly _brand: "UserId" }
178
+ *
179
+ * const byId: Record<string, number> = { u1: 10, u2: 20 }
180
+ * const branded = RecordX.keysAs<UserId>()(byId)
181
+ *
182
+ * // Same runtime value, keys now seen as `UserId`
183
+ * assert.deepStrictEqual(branded, { u1: 10, u2: 20 })
184
+ * ```
185
+ *
186
+ * @category conversions
187
+ * @since 0.0.0
188
+ */
189
+ export declare const keysAs: <K2 extends PropertyKey>() => <K1 extends PropertyKey, V>(record: Record<K1, V>) => Record<K2, V>;
190
+ /**
191
+ * Returns the value at `key` in `record`, throwing an `Error` if the key is
192
+ * absent.
193
+ *
194
+ * The unsafe, get-or-explode counterpart to `Record.get` (which returns an
195
+ * `Option`). The thrown error names the missing key and lists the record's
196
+ * existing keys to aid debugging. Reach for {@link getOrThrowWith} when you need
197
+ * a custom error; prefer `Record.get` whenever absence is a real possibility.
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * import { pipe } from "effect"
202
+ * import { RecordX } from "@nunofyobiz/effect-extras"
203
+ *
204
+ * const record: Record<string, number> = { a: 1, b: 2 }
205
+ *
206
+ * // data-first
207
+ * assert.deepStrictEqual(RecordX.getOrThrow(record, "a"), 1)
208
+ *
209
+ * // data-last (pipeable)
210
+ * assert.deepStrictEqual(pipe(record, RecordX.getOrThrow("b")), 2)
211
+ *
212
+ * // missing key throws
213
+ * assert.throws(() => RecordX.getOrThrow(record, "missing"))
214
+ * ```
215
+ *
216
+ * @category unsafe
217
+ * @since 0.0.0
218
+ */
219
+ export declare const getOrThrow: (<K extends string | symbol>(key: K) => <V>(record: Record<K, V>) => V) & (<K extends string | symbol, V>(record: Record<K, V>, key: K) => V);
220
+ /**
221
+ * Returns the value at `key` in `record`, throwing the result of `onNone(key)`
222
+ * if the key is absent.
223
+ *
224
+ * Like {@link getOrThrow}, but lets the caller supply the thrown value (an
225
+ * `Error`, a string, or any custom failure) computed from the missing key. Use
226
+ * it when the default "key not found" message isn't descriptive enough for the
227
+ * call site.
228
+ *
229
+ * @example
230
+ * ```ts
231
+ * import { pipe } from "effect"
232
+ * import { RecordX } from "@nunofyobiz/effect-extras"
233
+ *
234
+ * const record: Record<string, number> = { a: 1 }
235
+ * const onNone = (key: string) => new Error(`no ${key}`)
236
+ *
237
+ * // data-first
238
+ * assert.deepStrictEqual(RecordX.getOrThrowWith(record, "a", onNone), 1)
239
+ *
240
+ * // data-last (pipeable)
241
+ * assert.deepStrictEqual(pipe(record, RecordX.getOrThrowWith("a", onNone)), 1)
242
+ *
243
+ * // missing key throws the custom error
244
+ * assert.throws(() => RecordX.getOrThrowWith(record, "missing", onNone))
245
+ * ```
246
+ *
247
+ * @category unsafe
248
+ * @since 0.0.0
249
+ */
250
+ export declare const getOrThrowWith: (<K extends string | symbol>(key: K, onNone: (key: K) => unknown) => <V>(record: Record<K, V>) => V) & (<K extends string | symbol, V>(record: Record<K, V>, key: K, onNone: (key: K) => unknown) => V);
251
+ /**
252
+ * Inserts or updates the value at `key`, deriving the new value from the current
253
+ * one via `upsert`.
254
+ *
255
+ * The `upsert` function receives an `Option` of the existing value —
256
+ * `Option.some(value)` when the key is present, `Option.none()` when it's
257
+ * absent — and returns the value to store. This unifies "insert if missing" and
258
+ * "update if present" into a single pass, with `Option.match` as the natural way
259
+ * to handle both cases.
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * import { Option, pipe } from "effect"
264
+ * import { RecordX } from "@nunofyobiz/effect-extras"
265
+ *
266
+ * const bump = Option.match({
267
+ * onNone: () => 1,
268
+ * onSome: (n: number) => n + 1,
269
+ * })
270
+ *
271
+ * // data-first: updates an existing entry
272
+ * assert.deepStrictEqual(RecordX.upsert({ a: 1 }, "a", bump), { a: 2 })
273
+ *
274
+ * // data-last (pipeable): inserts a missing entry
275
+ * const counts: Record<string, number> = { a: 1 }
276
+ * assert.deepStrictEqual(pipe(counts, RecordX.upsert("b", bump)), {
277
+ * a: 1,
278
+ * b: 1,
279
+ * })
280
+ * ```
281
+ *
282
+ * @category mapping
283
+ * @since 0.0.0
284
+ */
285
+ export declare const upsert: (<K extends string | symbol, V>(key: K, upsert: (existingValue: Option.Option<V>) => V) => (record: Record<K, V>) => Record<K, V>) & (<K extends string | symbol, V>(record: Record<K, V>, key: K, upsert: (existingValue: Option.Option<V>) => V) => Record<K, V>);
286
+ /**
287
+ * Indexes an iterable of values into a `Record`, keying each value by the result
288
+ * of `identify`.
289
+ *
290
+ * Builds a lookup table from a collection: every value is stored under the key
291
+ * `identify(value)`. When two values produce the same key the later one wins, so
292
+ * the result holds the last value seen per key. Useful for turning a list of
293
+ * records into a by-id map.
294
+ *
295
+ * @example
296
+ * ```ts
297
+ * import { pipe } from "effect"
298
+ * import { RecordX } from "@nunofyobiz/effect-extras"
299
+ *
300
+ * const items = [
301
+ * { id: "a", n: 1 },
302
+ * { id: "b", n: 2 },
303
+ * { id: "a", n: 3 }, // wins over the earlier "a"
304
+ * ]
305
+ *
306
+ * // data-first
307
+ * assert.deepStrictEqual(
308
+ * RecordX.collectBy(items, (item) => item.id),
309
+ * { a: { id: "a", n: 3 }, b: { id: "b", n: 2 } },
310
+ * )
311
+ *
312
+ * // data-last (pipeable)
313
+ * assert.deepStrictEqual(
314
+ * pipe(items, RecordX.collectBy((item) => item.id)),
315
+ * { a: { id: "a", n: 3 }, b: { id: "b", n: 2 } },
316
+ * )
317
+ * ```
318
+ *
319
+ * @category constructors
320
+ * @since 0.0.0
321
+ */
322
+ export declare const collectBy: (<K extends string | symbol, V>(identify: (v: V) => K) => (values: Iterable<V>) => Record<K, V>) & (<K extends string | symbol, V>(values: Iterable<V>, identify: (v: V) => K) => Record<K, V>);
323
+ //# sourceMappingURL=RecordX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecordX.d.ts","sourceRoot":"","sources":["../src/RecordX.ts"],"names":[],"mappings":"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"}