ts-data-forge 14.4.0 → 14.6.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 (123) hide show
  1. package/README.md +6 -0
  2. package/dist/array/impl/array-utils-element-access.mjs +1 -1
  3. package/dist/array/impl/array-utils-reducing-value.mjs +3 -3
  4. package/dist/array/impl/array-utils-search.d.mts.map +1 -1
  5. package/dist/array/impl/array-utils-search.mjs +1 -1
  6. package/dist/array/impl/array-utils-search.mjs.map +1 -1
  7. package/dist/collections/imap-mapped.mjs +1 -1
  8. package/dist/collections/imap.mjs +1 -1
  9. package/dist/entry-point.mjs +8 -6
  10. package/dist/entry-point.mjs.map +1 -1
  11. package/dist/functional/async-result/async-result.d.mts +16 -0
  12. package/dist/functional/async-result/async-result.d.mts.map +1 -0
  13. package/dist/functional/async-result/async-result.mjs +3 -0
  14. package/dist/functional/async-result/async-result.mjs.map +1 -0
  15. package/dist/functional/async-result/impl/async-result-flat-map.d.mts +39 -0
  16. package/dist/functional/async-result/impl/async-result-flat-map.d.mts.map +1 -0
  17. package/dist/functional/async-result/impl/async-result-flat-map.mjs +25 -0
  18. package/dist/functional/async-result/impl/async-result-flat-map.mjs.map +1 -0
  19. package/dist/functional/async-result/impl/async-result-from-promise.d.mts +47 -0
  20. package/dist/functional/async-result/impl/async-result-from-promise.d.mts.map +1 -0
  21. package/dist/functional/async-result/impl/async-result-from-promise.mjs +11 -0
  22. package/dist/functional/async-result/impl/async-result-from-promise.mjs.map +1 -0
  23. package/dist/functional/async-result/impl/async-result-from-throwable.d.mts +53 -0
  24. package/dist/functional/async-result/impl/async-result-from-throwable.d.mts.map +1 -0
  25. package/dist/functional/async-result/impl/async-result-from-throwable.mjs +17 -0
  26. package/dist/functional/async-result/impl/async-result-from-throwable.mjs.map +1 -0
  27. package/dist/functional/async-result/impl/async-result-map-err.d.mts +35 -0
  28. package/dist/functional/async-result/impl/async-result-map-err.d.mts.map +1 -0
  29. package/dist/functional/async-result/impl/async-result-map-err.mjs +23 -0
  30. package/dist/functional/async-result/impl/async-result-map-err.mjs.map +1 -0
  31. package/dist/functional/async-result/impl/async-result-map.d.mts +45 -0
  32. package/dist/functional/async-result/impl/async-result-map.d.mts.map +1 -0
  33. package/dist/functional/async-result/impl/async-result-map.mjs +23 -0
  34. package/dist/functional/async-result/impl/async-result-map.mjs.map +1 -0
  35. package/dist/functional/async-result/impl/async-result-unwrap-or.d.mts +34 -0
  36. package/dist/functional/async-result/impl/async-result-unwrap-or.d.mts.map +1 -0
  37. package/dist/functional/async-result/impl/async-result-unwrap-or.mjs +10 -0
  38. package/dist/functional/async-result/impl/async-result-unwrap-or.mjs.map +1 -0
  39. package/dist/functional/async-result/impl/index.d.mts +8 -0
  40. package/dist/functional/async-result/impl/index.d.mts.map +1 -0
  41. package/dist/functional/async-result/impl/index.mjs +7 -0
  42. package/dist/functional/async-result/impl/index.mjs.map +1 -0
  43. package/dist/functional/async-result/impl/types.d.mts +45 -0
  44. package/dist/functional/async-result/impl/types.d.mts.map +1 -0
  45. package/dist/functional/async-result/impl/types.mjs +2 -0
  46. package/dist/functional/async-result/impl/types.mjs.map +1 -0
  47. package/dist/functional/async-result/index.d.mts +2 -0
  48. package/dist/functional/async-result/index.d.mts.map +1 -0
  49. package/dist/functional/async-result/index.mjs +3 -0
  50. package/dist/functional/async-result/index.mjs.map +1 -0
  51. package/dist/functional/index.d.mts +1 -0
  52. package/dist/functional/index.d.mts.map +1 -1
  53. package/dist/functional/index.mjs +8 -6
  54. package/dist/functional/index.mjs.map +1 -1
  55. package/dist/functional/optional/impl/index.d.mts +1 -0
  56. package/dist/functional/optional/impl/index.d.mts.map +1 -1
  57. package/dist/functional/optional/impl/index.mjs +1 -0
  58. package/dist/functional/optional/impl/index.mjs.map +1 -1
  59. package/dist/functional/optional/impl/optional-match.d.mts +48 -0
  60. package/dist/functional/optional/impl/optional-match.d.mts.map +1 -0
  61. package/dist/functional/optional/impl/optional-match.mjs +22 -0
  62. package/dist/functional/optional/impl/optional-match.mjs.map +1 -0
  63. package/dist/functional/result/impl/index.d.mts +4 -0
  64. package/dist/functional/result/impl/index.d.mts.map +1 -1
  65. package/dist/functional/result/impl/index.mjs +4 -0
  66. package/dist/functional/result/impl/index.mjs.map +1 -1
  67. package/dist/functional/result/impl/result-from-optional.d.mts +41 -0
  68. package/dist/functional/result/impl/result-from-optional.d.mts.map +1 -0
  69. package/dist/functional/result/impl/result-from-optional.mjs +24 -0
  70. package/dist/functional/result/impl/result-from-optional.mjs.map +1 -0
  71. package/dist/functional/result/impl/result-from-promise.d.mts +5 -0
  72. package/dist/functional/result/impl/result-from-promise.d.mts.map +1 -1
  73. package/dist/functional/result/impl/result-from-promise.mjs.map +1 -1
  74. package/dist/functional/result/impl/result-match.d.mts +47 -0
  75. package/dist/functional/result/impl/result-match.d.mts.map +1 -0
  76. package/dist/functional/result/impl/result-match.mjs +24 -0
  77. package/dist/functional/result/impl/result-match.mjs.map +1 -0
  78. package/dist/functional/result/impl/result-safe-try.d.mts +51 -0
  79. package/dist/functional/result/impl/result-safe-try.d.mts.map +1 -0
  80. package/dist/functional/result/impl/result-safe-try.mjs +24 -0
  81. package/dist/functional/result/impl/result-safe-try.mjs.map +1 -0
  82. package/dist/functional/result/impl/result-safe-unwrap.d.mts +36 -0
  83. package/dist/functional/result/impl/result-safe-unwrap.d.mts.map +1 -0
  84. package/dist/functional/result/impl/result-safe-unwrap.mjs +14 -0
  85. package/dist/functional/result/impl/result-safe-unwrap.mjs.map +1 -0
  86. package/dist/json/json.mjs +2 -2
  87. package/dist/number/refined-number-utils.mjs +1 -1
  88. package/dist/object/object.mjs +1 -1
  89. package/dist/others/debounce-function.d.mts.map +1 -1
  90. package/dist/others/debounce-function.mjs.map +1 -1
  91. package/dist/others/fast-deep-equal.d.mts.map +1 -1
  92. package/dist/others/fast-deep-equal.mjs +1 -1
  93. package/dist/others/fast-deep-equal.mjs.map +1 -1
  94. package/package.json +10 -10
  95. package/src/array/impl/array-utils-modification.test.mts +3 -3
  96. package/src/array/impl/array-utils-search.mts +22 -8
  97. package/src/array/impl/array-utils-shape-invariants.test.mts +3 -3
  98. package/src/array/impl/array-utils-transformation.test.mts +1 -1
  99. package/src/functional/async-result/async-result.mts +17 -0
  100. package/src/functional/async-result/impl/async-result-flat-map.mts +99 -0
  101. package/src/functional/async-result/impl/async-result-from-promise.mts +69 -0
  102. package/src/functional/async-result/impl/async-result-from-throwable.mts +78 -0
  103. package/src/functional/async-result/impl/async-result-map-err.mts +84 -0
  104. package/src/functional/async-result/impl/async-result-map.mts +94 -0
  105. package/src/functional/async-result/impl/async-result-unwrap-or.mts +42 -0
  106. package/src/functional/async-result/impl/index.mts +7 -0
  107. package/src/functional/async-result/impl/types.mts +51 -0
  108. package/src/functional/async-result/index.mts +1 -0
  109. package/src/functional/async-result.test.mts +290 -0
  110. package/src/functional/index.mts +1 -0
  111. package/src/functional/optional/impl/index.mts +1 -0
  112. package/src/functional/optional/impl/optional-match.mts +108 -0
  113. package/src/functional/optional.test.mts +79 -0
  114. package/src/functional/result/impl/index.mts +4 -0
  115. package/src/functional/result/impl/result-from-optional.mts +80 -0
  116. package/src/functional/result/impl/result-from-promise.mts +5 -0
  117. package/src/functional/result/impl/result-match.mts +108 -0
  118. package/src/functional/result/impl/result-safe-try.mts +110 -0
  119. package/src/functional/result/impl/result-safe-unwrap.mts +50 -0
  120. package/src/functional/result.test.mts +331 -0
  121. package/src/guard/is-error.test.mts +7 -7
  122. package/src/others/debounce-function.mts +5 -1
  123. package/src/others/fast-deep-equal.mts +9 -2
@@ -0,0 +1,24 @@
1
+ import { isOk } from './result-is-ok.mjs';
2
+
3
+ function match(...args) {
4
+ switch (args.length) {
5
+ case 2: {
6
+ const [result, cases] = args;
7
+ return matchImpl(result, cases);
8
+ }
9
+ case 1: {
10
+ const [cases] = args;
11
+ return (result) => matchImpl(result, cases);
12
+ }
13
+ }
14
+ }
15
+ const matchImpl = (result, cases) => isOk(result) ? (
16
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
17
+ cases.ok(result.value)
18
+ ) : (
19
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
20
+ cases.err(result.value)
21
+ );
22
+
23
+ export { match };
24
+ //# sourceMappingURL=result-match.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-match.mjs","sources":["../../../../src/functional/result/impl/result-match.mts"],"sourcesContent":["import { type UnknownResult } from '../result.mjs';\nimport { isOk } from './result-is-ok.mjs';\nimport { type UnwrapErr, type UnwrapOk } from './types.mjs';\n\n/**\n * Folds a `Result` into a plain value by applying one of two case handlers:\n * `ok` if the `Result` is `Ok`, `err` otherwise. This is the function form of\n * pattern matching on a `Result`.\n *\n * Unlike {@link Result.fold}, which maps both sides and returns another\n * `Result`, `match` unwraps: both branches produce the final value directly.\n *\n * @example\n *\n * ```ts\n * const doubledOrZero = Result.match(Result.ok(21), {\n * ok: (value) => value * 2,\n * err: () => 0,\n * });\n *\n * assert.deepStrictEqual(doubledOrZero, 42);\n *\n * const matcher = Result.match({\n * ok: (value: number) => value + 1,\n * err: (error: string) => error.length,\n * });\n *\n * assert.deepStrictEqual(matcher(Result.ok(1)), 2);\n *\n * assert.deepStrictEqual(matcher(Result.err('oops')), 4);\n * ```\n *\n * @template R The input `UnknownResult` type.\n * @template S2 The type returned by the `ok` case.\n * @template E2 The type returned by the `err` case.\n * @param result The `Result` to match on.\n * @param cases An object with an `ok` handler receiving the success value and\n * an `err` handler receiving the error value.\n * @returns The value produced by whichever case handler was applied.\n */\nexport function match<R extends UnknownResult, S2, E2>(\n result: R,\n cases: Readonly<{\n ok: (value: UnwrapOk<R>) => S2;\n err: (error: UnwrapErr<R>) => E2;\n }>,\n): E2 | S2;\n\n// Curried version\n//\n// The returned function is generic over the *whole* result, mirroring the\n// direct overload above; see the comment on the curried overload of\n// `Result.map` for why the parameter is a conditional type instead of a plain\n// `Result<S, E>`. Both sides have to be checked here, hence the nested\n// conditional.\nexport function match<S, E, S2, E2>(\n cases: Readonly<{\n ok: (value: S) => S2;\n err: (error: E) => E2;\n }>,\n): <R extends UnknownResult>(\n result: UnwrapOk<R> extends S ? (UnwrapErr<R> extends E ? R : never) : never,\n) => E2 | S2;\n\nexport function match<R extends UnknownResult, S2, E2>(\n ...args:\n | readonly [\n result: R,\n cases: Readonly<{\n ok: (value: UnwrapOk<R>) => S2;\n err: (error: UnwrapErr<R>) => E2;\n }>,\n ]\n | readonly [\n cases: Readonly<{\n ok: (value: UnwrapOk<R>) => S2;\n err: (error: UnwrapErr<R>) => E2;\n }>,\n ]\n): E2 | S2 | ((result: R) => E2 | S2) {\n switch (args.length) {\n case 2: {\n const [result, cases] = args;\n\n return matchImpl(result, cases);\n }\n\n case 1: {\n // Curried version: the only argument is the case handlers\n const [cases] = args;\n\n return (result: R) => matchImpl(result, cases);\n }\n }\n}\n\nconst matchImpl = <R extends UnknownResult, S2, E2>(\n result: R,\n cases: Readonly<{\n ok: (value: UnwrapOk<R>) => S2;\n err: (error: UnwrapErr<R>) => E2;\n }>,\n): E2 | S2 =>\n isOk(result)\n ? // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n cases.ok(result.value as UnwrapOk<R>)\n : // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n cases.err(result.value as UnwrapErr<R>);\n"],"names":[],"mappings":";;AAgEO,SAAS,SACX,IAAA,EAciC;AACpC,EAAA,QAAQ,KAAK,MAAA;AAAQ,IACnB,KAAK,CAAA,EAAG;AACN,MAAA,MAAM,CAAC,MAAA,EAAQ,KAAK,CAAA,GAAI,IAAA;AAExB,MAAA,OAAO,SAAA,CAAU,QAAQ,KAAK,CAAA;AAAA,IAChC;AAAA,IAEA,KAAK,CAAA,EAAG;AAEN,MAAA,MAAM,CAAC,KAAK,CAAA,GAAI,IAAA;AAEhB,MAAA,OAAO,CAAC,MAAA,KAAc,SAAA,CAAU,MAAA,EAAQ,KAAK,CAAA;AAAA,IAC/C;AAAA;AAEJ;AAEA,MAAM,SAAA,GAAY,CAChB,MAAA,EACA,KAAA,KAKA,KAAK,MAAM,CAAA;AAAA;AAAA,EAEP,KAAA,CAAM,EAAA,CAAG,MAAA,CAAO,KAAoB;AAAA;AAAA;AAAA,EAEpC,KAAA,CAAM,GAAA,CAAI,MAAA,CAAO,KAAqB;AAAA,CAAA;;;;"}
@@ -0,0 +1,51 @@
1
+ import { type Err } from '../../../types.mjs';
2
+ import { type Result, type UnknownResult } from '../result.mjs';
3
+ import { type UnwrapErr, type UnwrapOk } from './types.mjs';
4
+ /**
5
+ * Runs a generator body in which `yield* Result.safeUnwrap(...)` unwraps `Ok`
6
+ * values and short-circuits on the first `Err`, emulating Rust's `?` operator
7
+ * (early-return error propagation).
8
+ *
9
+ * The body must return a `Result`. If every unwrapped `Result` is `Ok`, the
10
+ * returned value is the body's `Result`; otherwise it is the first `Err`
11
+ * encountered, and the rest of the body never runs — though the generator is
12
+ * closed rather than dropped, so `finally` blocks and `using` disposals
13
+ * pending in the body still run. An exception thrown by the body is not
14
+ * converted to an `Err`: it propagates out of `safeTry` (as a rejected
15
+ * `Promise` for an async body). Use {@link Result.fromThrowable} for that.
16
+ *
17
+ * Passing an async generator (`async function*`) returns a
18
+ * `Promise<Result<...>>` instead, so `await` can be used inside the body.
19
+ * Note that `yield*` inside an `async function*` awaits what it receives, so
20
+ * unwrapping an `Ok` whose value is itself a `Promise` yields the awaited
21
+ * value there while the static type still says `Promise<...>`; keep promises
22
+ * out of the `Ok` side of a `Result` unwrapped in an async body.
23
+ *
24
+ * @example
25
+ *
26
+ * ```ts
27
+ * const parseTwo = (a: string, b: string): Result<number, Error> =>
28
+ * Result.safeTry(function* () {
29
+ * const x = yield* Result.safeUnwrap(Num.safeParseInt(a));
30
+ *
31
+ * const y = yield* Result.safeUnwrap(Num.safeParseInt(b));
32
+ *
33
+ * return Result.ok(x + y);
34
+ * });
35
+ *
36
+ * assert.deepStrictEqual(parseTwo('1', '2'), Result.ok(3));
37
+ *
38
+ * assert.isTrue(Result.isErr(parseTwo('1', 'not a number')));
39
+ * ```
40
+ *
41
+ * @template Y The union of `Err` types unwrapped via
42
+ * {@link Result.safeUnwrap} (`never` if nothing is unwrapped).
43
+ * @template R2 The `Result` type returned by the body.
44
+ * @param body A generator function whose `yield*` expressions delegate to
45
+ * {@link Result.safeUnwrap} and whose return value is a `Result`.
46
+ * @returns The body's `Result`, or the first `Err` short-circuited out of it
47
+ * (wrapped in a `Promise` for an async generator body).
48
+ */
49
+ export declare function safeTry<Y extends Err<unknown>, R2 extends UnknownResult>(body: () => Generator<Y, R2>): Result<UnwrapOk<R2>, UnwrapErr<R2> | UnwrapErr<Y>>;
50
+ export declare function safeTry<Y extends Err<unknown>, R2 extends UnknownResult>(body: () => AsyncGenerator<Y, R2>): Promise<Result<UnwrapOk<R2>, UnwrapErr<R2> | UnwrapErr<Y>>>;
51
+ //# sourceMappingURL=result-safe-try.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-safe-try.d.mts","sourceRoot":"","sources":["../../../../src/functional/result/impl/result-safe-try.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,aAAa,EACtE,IAAI,EAAE,MAAM,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAC3B,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtD,wBAAgB,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,aAAa,EACtE,IAAI,EAAE,MAAM,cAAc,CAAC,CAAC,EAAE,EAAE,CAAC,GAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { hasKey } from '../../../guard/has-key.mjs';
2
+ import { isRecord } from '../../../guard/is-record.mjs';
3
+
4
+ function safeTry(body) {
5
+ const generator = body();
6
+ const step = generator.next();
7
+ if (isSyncStep(step)) {
8
+ if (step.done !== true && isSyncGenerator(generator, step)) {
9
+ generator.return(step.value);
10
+ }
11
+ return step.value;
12
+ }
13
+ return step.then(async (asyncStep) => {
14
+ if (asyncStep.done !== true) {
15
+ await generator.return(asyncStep.value);
16
+ }
17
+ return asyncStep.value;
18
+ });
19
+ }
20
+ const isSyncStep = (value) => isRecord(value) && hasKey(value, "done");
21
+ const isSyncGenerator = (_generator, step) => isSyncStep(step);
22
+
23
+ export { safeTry };
24
+ //# sourceMappingURL=result-safe-try.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-safe-try.mjs","sources":["../../../../src/functional/result/impl/result-safe-try.mts"],"sourcesContent":["import { hasKey, isRecord } from '../../../guard/index.mjs';\nimport { type Err } from '../../../types.mjs';\nimport { type Result, type UnknownResult } from '../result.mjs';\nimport { type UnwrapErr, type UnwrapOk } from './types.mjs';\n\n/**\n * Runs a generator body in which `yield* Result.safeUnwrap(...)` unwraps `Ok`\n * values and short-circuits on the first `Err`, emulating Rust's `?` operator\n * (early-return error propagation).\n *\n * The body must return a `Result`. If every unwrapped `Result` is `Ok`, the\n * returned value is the body's `Result`; otherwise it is the first `Err`\n * encountered, and the rest of the body never runs — though the generator is\n * closed rather than dropped, so `finally` blocks and `using` disposals\n * pending in the body still run. An exception thrown by the body is not\n * converted to an `Err`: it propagates out of `safeTry` (as a rejected\n * `Promise` for an async body). Use {@link Result.fromThrowable} for that.\n *\n * Passing an async generator (`async function*`) returns a\n * `Promise<Result<...>>` instead, so `await` can be used inside the body.\n * Note that `yield*` inside an `async function*` awaits what it receives, so\n * unwrapping an `Ok` whose value is itself a `Promise` yields the awaited\n * value there while the static type still says `Promise<...>`; keep promises\n * out of the `Ok` side of a `Result` unwrapped in an async body.\n *\n * @example\n *\n * ```ts\n * const parseTwo = (a: string, b: string): Result<number, Error> =>\n * Result.safeTry(function* () {\n * const x = yield* Result.safeUnwrap(Num.safeParseInt(a));\n *\n * const y = yield* Result.safeUnwrap(Num.safeParseInt(b));\n *\n * return Result.ok(x + y);\n * });\n *\n * assert.deepStrictEqual(parseTwo('1', '2'), Result.ok(3));\n *\n * assert.isTrue(Result.isErr(parseTwo('1', 'not a number')));\n * ```\n *\n * @template Y The union of `Err` types unwrapped via\n * {@link Result.safeUnwrap} (`never` if nothing is unwrapped).\n * @template R2 The `Result` type returned by the body.\n * @param body A generator function whose `yield*` expressions delegate to\n * {@link Result.safeUnwrap} and whose return value is a `Result`.\n * @returns The body's `Result`, or the first `Err` short-circuited out of it\n * (wrapped in a `Promise` for an async generator body).\n */\nexport function safeTry<Y extends Err<unknown>, R2 extends UnknownResult>(\n body: () => Generator<Y, R2>,\n): Result<UnwrapOk<R2>, UnwrapErr<R2> | UnwrapErr<Y>>;\n\nexport function safeTry<Y extends Err<unknown>, R2 extends UnknownResult>(\n body: () => AsyncGenerator<Y, R2>,\n): Promise<Result<UnwrapOk<R2>, UnwrapErr<R2> | UnwrapErr<Y>>>;\n\nexport function safeTry(\n body:\n | (() => AsyncGenerator<UnknownResult, UnknownResult>)\n | (() => Generator<UnknownResult, UnknownResult>),\n): Promise<UnknownResult> | UnknownResult {\n const generator = body();\n\n // A yielded `Err` and a returned `Result` are both already the final\n // answer, so the first step's `value` is the result in either case: the\n // generator is closed rather than resumed after yielding.\n const step = generator.next();\n\n if (isSyncStep(step)) {\n // Dropping a suspended generator would skip the `finally` blocks and\n // `using` disposals still pending in the body; closing it runs them\n // before the short-circuited `Err` is handed back. `isSyncGenerator` is\n // what makes `return()` here synchronous rather than a floating promise.\n if (step.done !== true && isSyncGenerator(generator, step)) {\n generator.return(step.value);\n }\n\n return step.value;\n }\n\n return step.then(async (asyncStep) => {\n if (asyncStep.done !== true) {\n await generator.return(asyncStep.value);\n }\n\n return asyncStep.value;\n });\n}\n\n// A sync generator's `next()` returns a plain `{ value, done }` object with\n// own properties, while an async generator's returns a `Promise`, whose\n// `then` lives on the prototype — so an own-key check on `done` separates the\n// two.\nconst isSyncStep = (\n value: unknown,\n): value is IteratorResult<UnknownResult, UnknownResult> =>\n isRecord(value) && hasKey(value, 'done');\n\n// The generator-side counterpart of `isSyncStep`: a step in the sync form can\n// only have come from a sync generator, so the step is what narrows the\n// generator that produced it — hence the predicate reads its second argument\n// and not its first.\nconst isSyncGenerator = (\n _generator:\n | AsyncGenerator<UnknownResult, UnknownResult>\n | Generator<UnknownResult, UnknownResult>,\n step: unknown,\n): _generator is Generator<UnknownResult, UnknownResult> => isSyncStep(step);\n"],"names":[],"mappings":";;;AA0DO,SAAS,QACd,IAAA,EAGwC;AACxC,EAAA,MAAM,YAAY,IAAA,EAAK;AAKvB,EAAA,MAAM,IAAA,GAAO,UAAU,IAAA,EAAK;AAE5B,EAAA,IAAI,UAAA,CAAW,IAAI,CAAA,EAAG;AAKpB,IAAA,IAAI,KAAK,IAAA,KAAS,IAAA,IAAQ,eAAA,CAAgB,SAAA,EAAW,IAAI,CAAA,EAAG;AAC1D,MAAA,SAAA,CAAU,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,IAC7B;AAEA,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AAEA,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,OAAO,SAAA,KAAc;AACpC,IAAA,IAAI,SAAA,CAAU,SAAS,IAAA,EAAM;AAC3B,MAAA,MAAM,SAAA,CAAU,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA;AAAA,IACxC;AAEA,IAAA,OAAO,SAAA,CAAU,KAAA;AAAA,EACnB,CAAC,CAAA;AACH;AAMA,MAAM,UAAA,GAAa,CACjB,KAAA,KAEA,QAAA,CAAS,KAAK,CAAA,IAAK,MAAA,CAAO,OAAO,MAAM,CAAA;AAMzC,MAAM,eAAA,GAAkB,CACtB,UAAA,EAGA,IAAA,KAC0D,WAAW,IAAI,CAAA;;;;"}
@@ -0,0 +1,36 @@
1
+ import { type UnknownResult } from '../result.mjs';
2
+ import { type NarrowToErr, type UnwrapOk } from './types.mjs';
3
+ /**
4
+ * Unwraps a `Result` inside a {@link Result.safeTry} generator body via
5
+ * `yield*`, emulating Rust's `?` operator.
6
+ *
7
+ * If the `Result` is `Ok`, the `yield*` expression evaluates to the contained
8
+ * value and execution continues. If it is `Err`, the error is yielded to
9
+ * {@link Result.safeTry}, which returns it immediately — the rest of the
10
+ * generator body never runs.
11
+ *
12
+ * This generator must only be delegated to (`yield*`) inside a
13
+ * {@link Result.safeTry} body; resuming it after it has yielded an `Err`
14
+ * throws.
15
+ *
16
+ * @example
17
+ *
18
+ * ```ts
19
+ * const result = Result.safeTry(function* () {
20
+ * const x = yield* Result.safeUnwrap(Result.ok(2));
21
+ *
22
+ * const y = yield* Result.safeUnwrap(Result.ok(3));
23
+ *
24
+ * return Result.ok(x + y);
25
+ * });
26
+ *
27
+ * assert.deepStrictEqual(result, Result.ok(5));
28
+ * ```
29
+ *
30
+ * @template R The input `UnknownResult` type.
31
+ * @param result The `Result` to unwrap.
32
+ * @returns A generator that yields the `Err` (if any) and returns the `Ok`
33
+ * value.
34
+ */
35
+ export declare function safeUnwrap<R extends UnknownResult>(result: R): Generator<NarrowToErr<R>, UnwrapOk<R>, unknown>;
36
+ //# sourceMappingURL=result-safe-unwrap.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-safe-unwrap.d.mts","sourceRoot":"","sources":["../../../../src/functional/result/impl/result-safe-unwrap.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAiB,UAAU,CAAC,CAAC,SAAS,aAAa,EACjD,MAAM,EAAE,CAAC,GACR,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAWjD"}
@@ -0,0 +1,14 @@
1
+ import { isErr } from './result-is-err.mjs';
2
+
3
+ function* safeUnwrap(result) {
4
+ if (isErr(result)) {
5
+ yield result;
6
+ throw new Error(
7
+ "`safeUnwrap()` generator was resumed after yielding an `Err`; it must only be used via `yield*` inside `safeTry()`"
8
+ );
9
+ }
10
+ return result.value;
11
+ }
12
+
13
+ export { safeUnwrap };
14
+ //# sourceMappingURL=result-safe-unwrap.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-safe-unwrap.mjs","sources":["../../../../src/functional/result/impl/result-safe-unwrap.mts"],"sourcesContent":["import { type UnknownResult } from '../result.mjs';\nimport { isErr } from './result-is-err.mjs';\nimport { type NarrowToErr, type UnwrapOk } from './types.mjs';\n\n/**\n * Unwraps a `Result` inside a {@link Result.safeTry} generator body via\n * `yield*`, emulating Rust's `?` operator.\n *\n * If the `Result` is `Ok`, the `yield*` expression evaluates to the contained\n * value and execution continues. If it is `Err`, the error is yielded to\n * {@link Result.safeTry}, which returns it immediately — the rest of the\n * generator body never runs.\n *\n * This generator must only be delegated to (`yield*`) inside a\n * {@link Result.safeTry} body; resuming it after it has yielded an `Err`\n * throws.\n *\n * @example\n *\n * ```ts\n * const result = Result.safeTry(function* () {\n * const x = yield* Result.safeUnwrap(Result.ok(2));\n *\n * const y = yield* Result.safeUnwrap(Result.ok(3));\n *\n * return Result.ok(x + y);\n * });\n *\n * assert.deepStrictEqual(result, Result.ok(5));\n * ```\n *\n * @template R The input `UnknownResult` type.\n * @param result The `Result` to unwrap.\n * @returns A generator that yields the `Err` (if any) and returns the `Ok`\n * value.\n */\nexport function* safeUnwrap<R extends UnknownResult>(\n result: R,\n): Generator<NarrowToErr<R>, UnwrapOk<R>, unknown> {\n if (isErr(result)) {\n yield result;\n\n throw new Error(\n '`safeUnwrap()` generator was resumed after yielding an `Err`; it must only be used via `yield*` inside `safeTry()`',\n );\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return result.value as UnwrapOk<R>;\n}\n"],"names":[],"mappings":";;AAoCO,UAAU,WACf,MAAA,EACiD;AACjD,EAAA,IAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACjB,IAAA,MAAM,MAAA;AAEN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAGA,EAAA,OAAO,MAAA,CAAO,KAAA;AAChB;;;;"}
@@ -34,13 +34,13 @@ import '../number/enum/int8.mjs';
34
34
  import '../number/enum/uint8.mjs';
35
35
  import '../number/num.mjs';
36
36
  import '../number/refined-number-utils.mjs';
37
- import { isRecord } from '../guard/is-record.mjs';
38
- import { pipe } from '../functional/pipe.mjs';
39
37
  import { err } from '../functional/result/impl/result-err.mjs';
40
38
  import { ok } from '../functional/result/impl/result-ok.mjs';
39
+ import { isRecord } from '../guard/is-record.mjs';
41
40
  import '@sindresorhus/is';
42
41
  import { castMutable } from '../others/cast-mutable.mjs';
43
42
  import { unknownToString } from '../others/unknown-to-string.mjs';
43
+ import { pipe } from '../functional/pipe.mjs';
44
44
  import '../collections/imap-mapped.mjs';
45
45
  import '../collections/imap.mjs';
46
46
  import '../collections/iset-mapped.mjs';
@@ -1,5 +1,5 @@
1
- import { pipe } from '../functional/pipe.mjs';
2
1
  import '@sindresorhus/is';
2
+ import { pipe } from '../functional/pipe.mjs';
3
3
  import { Num } from './num.mjs';
4
4
 
5
5
  var TsDataForgeInternals;
@@ -34,9 +34,9 @@ import '../number/enum/int8.mjs';
34
34
  import '../number/enum/uint8.mjs';
35
35
  import '../number/num.mjs';
36
36
  import '../number/refined-number-utils.mjs';
37
+ import { isSome } from '../functional/optional/impl/optional-is-some.mjs';
37
38
  import { hasKey } from '../guard/has-key.mjs';
38
39
  import { isRecord } from '../guard/is-record.mjs';
39
- import { isSome } from '../functional/optional/impl/optional-is-some.mjs';
40
40
  import '@sindresorhus/is';
41
41
  import { isNonEmpty } from '../array/impl/array-utils-length-bounded-array-guard.mjs';
42
42
  import '../collections/imap-mapped.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"debounce-function.d.mts","sourceRoot":"","sources":["../../src/others/debounce-function.mts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,GAAI,IAAI,SAAS,SAAS,OAAO,EAAE,QAChD,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,oBACX,MAAM,KACvB,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,CAU1B,CAAC"}
1
+ {"version":3,"file":"debounce-function.d.mts","sourceRoot":"","sources":["../../src/others/debounce-function.mts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,GAAI,IAAI,SAAS,SAAS,OAAO,EAAE,QAChD,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,oBACX,MAAM,KACvB,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI,CAc1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"debounce-function.mjs","sources":["../../src/others/debounce-function.mts"],"sourcesContent":["/**\n * Creates a debounced function that delays invoking `func` until after `waitMilliseconds`\n * have elapsed since the last time the debounced function was invoked.\n *\n * @template F The type of the function to debounce.\n * @param func The function to debounce.\n * @param waitMilliseconds The number of milliseconds to delay.\n * @returns The new debounced function.\n */\nexport const debounce = <Args extends readonly unknown[]>(\n func: (...args: Args) => void,\n waitMilliseconds: number,\n): ((...args: Args) => void) => {\n let mut_timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n return (...args: Args): void => {\n clearTimeout(mut_timeoutId);\n\n mut_timeoutId = setTimeout(() => {\n func(...args);\n }, waitMilliseconds);\n };\n};\n"],"names":[],"mappings":"AASO,MAAM,QAAA,GAAW,CACtB,IAAA,EACA,gBAAA,KAC8B;AAC9B,EAAA,IAAI,aAAA;AAEJ,EAAA,OAAO,IAAI,IAAA,KAAqB;AAC9B,IAAA,YAAA,CAAa,aAAa,CAAA;AAE1B,IAAA,aAAA,GAAgB,WAAW,MAAM;AAC/B,MAAA,IAAA,CAAK,GAAG,IAAI,CAAA;AAAA,IACd,GAAG,gBAAgB,CAAA;AAAA,EACrB,CAAA;AACF;;;;"}
1
+ {"version":3,"file":"debounce-function.mjs","sources":["../../src/others/debounce-function.mts"],"sourcesContent":["/**\n * Creates a debounced function that delays invoking `func` until after `waitMilliseconds`\n * have elapsed since the last time the debounced function was invoked.\n *\n * @template F The type of the function to debounce.\n * @param func The function to debounce.\n * @param waitMilliseconds The number of milliseconds to delay.\n * @returns The new debounced function.\n */\nexport const debounce = <Args extends readonly unknown[]>(\n func: (...args: Args) => void,\n waitMilliseconds: number,\n): ((...args: Args) => void) => {\n // Not `ReturnType<typeof setTimeout>`: with both the DOM and Node\n // declarations in scope that resolves to `unknown`, which `clearTimeout`\n // will not take. Naming what `clearTimeout` accepts says the same thing and\n // stays true in either environment.\n let mut_timeoutId: Parameters<typeof clearTimeout>[0];\n\n return (...args: Args): void => {\n clearTimeout(mut_timeoutId);\n\n mut_timeoutId = setTimeout(() => {\n func(...args);\n }, waitMilliseconds);\n };\n};\n"],"names":[],"mappings":"AASO,MAAM,QAAA,GAAW,CACtB,IAAA,EACA,gBAAA,KAC8B;AAK9B,EAAA,IAAI,aAAA;AAEJ,EAAA,OAAO,IAAI,IAAA,KAAqB;AAC9B,IAAA,YAAA,CAAa,aAAa,CAAA;AAE1B,IAAA,aAAA,GAAgB,WAAW,MAAM;AAC/B,MAAA,IAAA,CAAK,GAAG,IAAI,CAAA;AAAA,IACd,GAAG,gBAAgB,CAAA;AAAA,EACrB,CAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"fast-deep-equal.d.mts","sourceRoot":"","sources":["../../src/others/fast-deep-equal.mts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,KAAM,CAAC,KAAK,CAAC,KAAG,OAyF9C,CAAC"}
1
+ {"version":3,"file":"fast-deep-equal.d.mts","sourceRoot":"","sources":["../../src/others/fast-deep-equal.mts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,KAAM,CAAC,KAAK,CAAC,KAAG,OAgG9C,CAAC"}
@@ -49,7 +49,7 @@ const fastDeepEqual = (a, b) => {
49
49
  !(key === "_owner" && a["$$typeof"]) && fastDeepEqual(a[key], b[key])
50
50
  );
51
51
  }
52
- return Number.isNaN(a) && Number.isNaN(b);
52
+ return typeof a === "number" && typeof b === "number" && Number.isNaN(a) && Number.isNaN(b);
53
53
  };
54
54
 
55
55
  export { fastDeepEqual };
@@ -1 +1 @@
1
- {"version":3,"file":"fast-deep-equal.mjs","sources":["../../src/others/fast-deep-equal.mts"],"sourcesContent":["import { isMap, isRegExp, isSet, isTypedArray } from '@sindresorhus/is';\nimport { hasKey, isRecord } from '../guard/index.mjs';\n\n/**\n * The fastest deep equal with ES6 Map, Set and Typed arrays support.\n * Checks equality of Date and RegExp objects by value.\n *\n * Forked from https://github.com/epoberezkin/fast-deep-equal/blob/v3.1.3/src/index.jst\n */\nexport const fastDeepEqual = <T,>(a: T, b: T): boolean => {\n if (a === b) {\n return true;\n }\n\n if (typeof a !== typeof b) {\n return false;\n }\n\n // Arrays are handled before `isRecord`, which excludes them.\n if (Array.isArray(a)) {\n return (\n Array.isArray(b) &&\n a.constructor === b.constructor &&\n a.length === b.length &&\n a.every((ai, index) => fastDeepEqual(ai, b[index]))\n );\n }\n\n if (isRecord(a)) {\n if (!isRecord(b)) {\n return false;\n }\n\n if (a.constructor !== b.constructor) {\n return false;\n }\n\n if (isMap(a)) {\n return (\n isMap(b) &&\n a.size === b.size &&\n a\n .entries()\n .every(\n ([key, value]) => b.has(key) && fastDeepEqual(value, b.get(key)),\n )\n );\n }\n\n if (isSet(a)) {\n return (\n isSet(b) &&\n a.size === b.size &&\n a.entries().every(([value]) => b.has(value))\n );\n }\n\n if (isTypedArray(a)) {\n return (\n isTypedArray(b) &&\n a.length === b.length &&\n a.every((value, index) => value === b[index])\n );\n }\n\n if (isRegExp(a)) {\n return isRegExp(b) && a.source === b.source && a.flags === b.flags;\n }\n\n if (a.valueOf !== Object.prototype.valueOf) {\n return a.valueOf() === b.valueOf();\n }\n\n if (a.toString !== Object.prototype.toString) {\n return a.toString() === b.toString();\n }\n\n const aKeys: readonly string[] = Object.keys(a);\n\n const bKeys: readonly string[] = Object.keys(b);\n\n return (\n aKeys.length === bKeys.length &&\n aKeys.every(\n (key) =>\n hasKey(b, key) &&\n // React-specific: avoid traversing React elements' _owner.\n // _owner contains circular references\n // and is not needed when comparing the actual elements (and not their owners)\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n !(key === '_owner' && a['$$typeof']) &&\n fastDeepEqual(a[key], b[key]),\n )\n );\n }\n\n // true if both NaN, false otherwise\n return Number.isNaN(a) && Number.isNaN(b);\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fast-deep-equal.mjs","sources":["../../src/others/fast-deep-equal.mts"],"sourcesContent":["import { isMap, isRegExp, isSet, isTypedArray } from '@sindresorhus/is';\nimport { hasKey, isRecord } from '../guard/index.mjs';\n\n/**\n * The fastest deep equal with ES6 Map, Set and Typed arrays support.\n * Checks equality of Date and RegExp objects by value.\n *\n * Forked from https://github.com/epoberezkin/fast-deep-equal/blob/v3.1.3/src/index.jst\n */\nexport const fastDeepEqual = <T,>(a: T, b: T): boolean => {\n if (a === b) {\n return true;\n }\n\n if (typeof a !== typeof b) {\n return false;\n }\n\n // Arrays are handled before `isRecord`, which excludes them.\n if (Array.isArray(a)) {\n return (\n Array.isArray(b) &&\n a.constructor === b.constructor &&\n a.length === b.length &&\n a.every((ai, index) => fastDeepEqual(ai, b[index]))\n );\n }\n\n if (isRecord(a)) {\n if (!isRecord(b)) {\n return false;\n }\n\n if (a.constructor !== b.constructor) {\n return false;\n }\n\n if (isMap(a)) {\n return (\n isMap(b) &&\n a.size === b.size &&\n a\n .entries()\n .every(\n ([key, value]) => b.has(key) && fastDeepEqual(value, b.get(key)),\n )\n );\n }\n\n if (isSet(a)) {\n return (\n isSet(b) &&\n a.size === b.size &&\n a.entries().every(([value]) => b.has(value))\n );\n }\n\n if (isTypedArray(a)) {\n return (\n isTypedArray(b) &&\n a.length === b.length &&\n a.every((value, index) => value === b[index])\n );\n }\n\n if (isRegExp(a)) {\n return isRegExp(b) && a.source === b.source && a.flags === b.flags;\n }\n\n if (a.valueOf !== Object.prototype.valueOf) {\n return a.valueOf() === b.valueOf();\n }\n\n if (a.toString !== Object.prototype.toString) {\n return a.toString() === b.toString();\n }\n\n const aKeys: readonly string[] = Object.keys(a);\n\n const bKeys: readonly string[] = Object.keys(b);\n\n return (\n aKeys.length === bKeys.length &&\n aKeys.every(\n (key) =>\n hasKey(b, key) &&\n // React-specific: avoid traversing React elements' _owner.\n // _owner contains circular references\n // and is not needed when comparing the actual elements (and not their owners)\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n !(key === '_owner' && a['$$typeof']) &&\n fastDeepEqual(a[key], b[key]),\n )\n );\n }\n\n // true if both NaN, false otherwise. `Number.isNaN` takes a number: called\n // with anything else it is always false, so the check belongs behind a\n // `typeof` guard rather than relying on that.\n return (\n typeof a === 'number' &&\n typeof b === 'number' &&\n Number.isNaN(a) &&\n Number.isNaN(b)\n );\n};\n"],"names":[],"mappings":";;;;AASO,MAAM,aAAA,GAAgB,CAAK,CAAA,EAAM,CAAA,KAAkB;AACxD,EAAA,IAAI,MAAM,CAAA,EAAG;AACX,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,CAAA,KAAM,OAAO,CAAA,EAAG;AACzB,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG;AACpB,IAAA,OACE,KAAA,CAAM,QAAQ,CAAC,CAAA,IACf,EAAE,WAAA,KAAgB,CAAA,CAAE,WAAA,IACpB,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,UACf,CAAA,CAAE,KAAA,CAAM,CAAC,EAAA,EAAI,KAAA,KAAU,cAAc,EAAA,EAAI,CAAA,CAAE,KAAK,CAAC,CAAC,CAAA;AAAA,EAEtD;AAEA,EAAA,IAAI,QAAA,CAAS,CAAC,CAAA,EAAG;AACf,IAAA,IAAI,CAAC,QAAA,CAAS,CAAC,CAAA,EAAG;AAChB,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,CAAA,CAAE,WAAA,KAAgB,CAAA,CAAE,WAAA,EAAa;AACnC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,KAAA,CAAM,CAAC,CAAA,EAAG;AACZ,MAAA,OACE,KAAA,CAAM,CAAC,CAAA,IACP,CAAA,CAAE,SAAS,CAAA,CAAE,IAAA,IACb,CAAA,CACG,OAAA,EAAQ,CACR,KAAA;AAAA,QACC,CAAC,CAAC,GAAA,EAAK,KAAK,MAAM,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,IAAK,aAAA,CAAc,KAAA,EAAO,CAAA,CAAE,GAAA,CAAI,GAAG,CAAC;AAAA,OACjE;AAAA,IAEN;AAEA,IAAA,IAAI,KAAA,CAAM,CAAC,CAAA,EAAG;AACZ,MAAA,OACE,MAAM,CAAC,CAAA,IACP,EAAE,IAAA,KAAS,CAAA,CAAE,QACb,CAAA,CAAE,OAAA,EAAQ,CAAE,KAAA,CAAM,CAAC,CAAC,KAAK,MAAM,CAAA,CAAE,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,IAE/C;AAEA,IAAA,IAAI,YAAA,CAAa,CAAC,CAAA,EAAG;AACnB,MAAA,OACE,YAAA,CAAa,CAAC,CAAA,IACd,CAAA,CAAE,WAAW,CAAA,CAAE,MAAA,IACf,CAAA,CAAE,KAAA,CAAM,CAAC,KAAA,EAAO,KAAA,KAAU,KAAA,KAAU,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IAEhD;AAEA,IAAA,IAAI,QAAA,CAAS,CAAC,CAAA,EAAG;AACf,MAAA,OAAO,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,CAAE,WAAW,CAAA,CAAE,MAAA,IAAU,CAAA,CAAE,KAAA,KAAU,CAAA,CAAE,KAAA;AAAA,IAC/D;AAEA,IAAA,IAAI,CAAA,CAAE,OAAA,KAAY,MAAA,CAAO,SAAA,CAAU,OAAA,EAAS;AAC1C,MAAA,OAAO,CAAA,CAAE,OAAA,EAAQ,KAAM,CAAA,CAAE,OAAA,EAAQ;AAAA,IACnC;AAEA,IAAA,IAAI,CAAA,CAAE,QAAA,KAAa,MAAA,CAAO,SAAA,CAAU,QAAA,EAAU;AAC5C,MAAA,OAAO,CAAA,CAAE,QAAA,EAAS,KAAM,CAAA,CAAE,QAAA,EAAS;AAAA,IACrC;AAEA,IAAA,MAAM,KAAA,GAA2B,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAE9C,IAAA,MAAM,KAAA,GAA2B,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAE9C,IAAA,OACE,KAAA,CAAM,MAAA,KAAW,KAAA,CAAM,MAAA,IACvB,KAAA,CAAM,KAAA;AAAA,MACJ,CAAC,GAAA,KACC,MAAA,CAAO,CAAA,EAAG,GAAG,CAAA;AAAA;AAAA;AAAA;AAAA,MAKb,EAAE,GAAA,KAAQ,QAAA,IAAY,CAAA,CAAE,UAAU,CAAA,CAAA,IAClC,aAAA,CAAc,CAAA,CAAE,GAAG,CAAA,EAAG,CAAA,CAAE,GAAG,CAAC;AAAA,KAChC;AAAA,EAEJ;AAKA,EAAA,OACE,OAAO,CAAA,KAAM,QAAA,IACb,OAAO,CAAA,KAAM,QAAA,IACb,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,IACd,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA;AAElB;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-data-forge",
3
- "version": "14.4.0",
3
+ "version": "14.6.0",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript",
@@ -37,29 +37,29 @@
37
37
  ],
38
38
  "dependencies": {
39
39
  "@sindresorhus/is": "^8.1.0",
40
- "ts-type-forge": "~9.2.1"
40
+ "ts-type-forge": "~9.2.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@emotion/react": "11.14.0",
44
44
  "@emotion/styled": "11.14.1",
45
45
  "@mui/material": "9.3.1",
46
46
  "@types/react": "19.2.18",
47
- "@vitest/browser-playwright": "4.1.10",
47
+ "@vitest/browser-playwright": "4.1.11",
48
48
  "dedent": "1.7.2",
49
- "immer": "11.1.16",
49
+ "eslint-config-typed": "5.10.1",
50
+ "eslint-plugin-ts-fortress": "1.0.6",
51
+ "eslint-plugin-ts-type-forge": "0.7.2",
52
+ "immer": "11.1.18",
50
53
  "playwright": "1.62.1",
51
54
  "prettier": "3.9.6",
52
55
  "prettier-plugin-organize-imports": "4.3.0",
53
56
  "prettier-plugin-packagejson": "3.0.2",
54
57
  "react": "19.2.8",
55
- "rollup": "4.62.4",
58
+ "rollup": "4.62.5",
59
+ "ts-repo-utils": "10.3.3",
56
60
  "typedoc": "0.28.20",
57
61
  "typedoc-github-theme": "0.4.0",
58
- "vite": "8.2.1",
59
- "eslint-plugin-ts-fortress": "1.0.4",
60
- "eslint-config-typed": "5.9.3",
61
- "ts-repo-utils": "10.2.0",
62
- "eslint-plugin-ts-type-forge": "0.6.6"
62
+ "vite": "8.2.2"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "typescript": ">=4.8"
@@ -257,7 +257,7 @@ describe('Arr modifications', () => {
257
257
  xs: T,
258
258
  ): Readonly<{ [K in keyof T]: 0 }> => toFilled(xs, 0);
259
259
 
260
- const result = blank([1, 2, 3] as const);
260
+ const result = blank([1, 2, 3]);
261
261
 
262
262
  expectType<typeof result, FixedLengthTuple<3, 0>>('=');
263
263
 
@@ -269,7 +269,7 @@ describe('Arr modifications', () => {
269
269
  xs: T,
270
270
  ): Readonly<{ [K in keyof T]: 0 }> => toFilled(0)(xs);
271
271
 
272
- const result = blank([1, 2] as const);
272
+ const result = blank([1, 2]);
273
273
 
274
274
  expectType<typeof result, FixedLengthTuple<2, 0>>('=');
275
275
 
@@ -319,7 +319,7 @@ describe('Arr modifications', () => {
319
319
  xs: T,
320
320
  ): Readonly<{ [K in keyof T]: number }> => toRangeFilled(xs, 0, [1, 2]);
321
321
 
322
- const result = blankMiddle([1, 2, 3] as const);
322
+ const result = blankMiddle([1, 2, 3]);
323
323
 
324
324
  expectType<typeof result, FixedLengthTuple<3, number>>('=');
325
325
 
@@ -79,10 +79,17 @@ const findImpl = <E,>(
79
79
  predicate as () => boolean,
80
80
  );
81
81
 
82
- expectType<
83
- Parameters<typeof array.findIndex>[0],
84
- (value: E, index: number, arr: readonly E[]) => unknown
85
- >('=');
82
+ // Left as a comment rather than asserted. This pinned the shape of the
83
+ // standard library's `findIndex`, and the shape differs between the stock
84
+ // library and the strict one — `(value, index, obj: this) => boolean` there
85
+ // against `(value, index, arr: readonly E[]) => unknown` here. `src` ships
86
+ // to consumers so that "Go to Definition" reaches it, so an assertion that
87
+ // only holds under one of them shows up as an error in their editor.
88
+ //
89
+ // expectType<
90
+ // Parameters<typeof array.findIndex>[0],
91
+ // (value: E, index: number, arr: readonly E[]) => unknown
92
+ // >('=');
86
93
 
87
94
  expectType<
88
95
  typeof predicate,
@@ -162,10 +169,17 @@ const findLastImpl = <E,>(
162
169
  predicate as () => boolean,
163
170
  );
164
171
 
165
- expectType<
166
- Parameters<typeof array.findIndex>[0],
167
- (value: E, index: number, arr: readonly E[]) => unknown
168
- >('=');
172
+ // Left as a comment rather than asserted. This pinned the shape of the
173
+ // standard library's `findIndex`, and the shape differs between the stock
174
+ // library and the strict one — `(value, index, obj: this) => boolean` there
175
+ // against `(value, index, arr: readonly E[]) => unknown` here. `src` ships
176
+ // to consumers so that "Go to Definition" reaches it, so an assertion that
177
+ // only holds under one of them shows up as an error in their editor.
178
+ //
179
+ // expectType<
180
+ // Parameters<typeof array.findIndex>[0],
181
+ // (value: E, index: number, arr: readonly E[]) => unknown
182
+ // >('=');
169
183
 
170
184
  expectType<
171
185
  typeof predicate,
@@ -267,7 +267,7 @@ describe('Arr shape invariants', () => {
267
267
  );
268
268
 
269
269
  assert.deepStrictEqual<readonly string[]>(
270
- toSortedNonNumberInGenericContext(['c', 'a', 'b'] as const),
270
+ toSortedNonNumberInGenericContext(['c', 'a', 'b']),
271
271
  ['a', 'b', 'c'],
272
272
  );
273
273
 
@@ -313,12 +313,12 @@ describe('Arr shape invariants', () => {
313
313
  );
314
314
 
315
315
  assert.deepStrictEqual<readonly number[]>(
316
- uniqInGenericContext([1, 1, 2] as const),
316
+ uniqInGenericContext([1, 1, 2]),
317
317
  [1, 2],
318
318
  );
319
319
 
320
320
  assert.deepStrictEqual<readonly number[]>(
321
- uniqByInGenericContext([1, 1, 2] as const),
321
+ uniqByInGenericContext([1, 1, 2]),
322
322
  [1, 2],
323
323
  );
324
324
  });
@@ -77,7 +77,7 @@ describe('Arr transformations', () => {
77
77
  boxes: T,
78
78
  ): Readonly<{ [K in keyof T]: unknown }> => map(boxes, (b) => b.v);
79
79
 
80
- const result = mapValues([{ v: 1 }, { v: 'a' }] as const);
80
+ const result = mapValues([{ v: 1 }, { v: 'a' }]);
81
81
 
82
82
  expectType<typeof result, FixedLengthTuple<2, unknown>>('=');
83
83
 
@@ -0,0 +1,17 @@
1
+ import { type Result } from '../result/index.mjs';
2
+
3
+ /**
4
+ * Represents an asynchronous computation that can either succeed (`Ok`) or
5
+ * fail (`Err`) — a `Promise` that resolves to a `Result<S, E>`.
6
+ *
7
+ * Unlike a raw `Promise`, an `AsyncResult` never rejects for expected
8
+ * failures: errors are carried in the `Err` channel with a concrete type `E`,
9
+ * so they can be handled with the same combinators as a synchronous
10
+ * `Result`.
11
+ *
12
+ * @template S The type of the success value.
13
+ * @template E The type of the error value.
14
+ */
15
+ export type AsyncResult<S, E> = Promise<Result<S, E>>;
16
+
17
+ export * as AsyncResult from './impl/index.mjs';
@@ -0,0 +1,99 @@
1
+ import { Result, type UnknownResult } from '../../result/index.mjs';
2
+ import { type AsyncResult } from '../async-result.mjs';
3
+ import {
4
+ type UnknownAsyncResult,
5
+ type UnwrapErr,
6
+ type UnwrapOk,
7
+ } from './types.mjs';
8
+
9
+ /**
10
+ * Applies a function that returns an `AsyncResult` or a `Result` to the
11
+ * success value of an `AsyncResult`. If the input resolves to `Err`, the
12
+ * original `Err` is passed through and the function is not called. This is
13
+ * the monadic bind operation for `AsyncResult`.
14
+ *
15
+ * @example
16
+ *
17
+ * ```ts
18
+ * const parseNumber = (input: string): Result<number, string> => {
19
+ * const num = Number.parseInt(input, 10);
20
+ *
21
+ * return Number.isNaN(num) ? Result.err('not a number') : Result.ok(num);
22
+ * };
23
+ *
24
+ * const input = AsyncResult.fromPromise(
25
+ * Promise.resolve('42'),
26
+ * () => 'failed',
27
+ * );
28
+ *
29
+ * const parsed = await AsyncResult.flatMap(input, parseNumber);
30
+ *
31
+ * assert.deepStrictEqual(parsed, Result.ok(42));
32
+ * ```
33
+ *
34
+ * @template S The type of the success value of the input.
35
+ * @template E The type of the error value of the input.
36
+ * @template R2 The `AsyncResult` or `Result` type returned by the function.
37
+ * @param asyncResult The `AsyncResult` to flat map.
38
+ * @param flatMapFn The function to apply that returns an `AsyncResult` or a
39
+ * `Result`.
40
+ * @returns The result of applying the function, or the original `Err`.
41
+ */
42
+ export function flatMap<S, E, R2 extends UnknownAsyncResult | UnknownResult>(
43
+ asyncResult: AsyncResult<S, E>,
44
+ flatMapFn: (value: S) => R2,
45
+ ): AsyncResult<UnwrapOk<R2>, E | UnwrapErr<R2>>;
46
+
47
+ // Curried version
48
+ //
49
+ // The function's return type is captured as a whole (`R2`) and unwrapped with
50
+ // `UnwrapOk` / `UnwrapErr`, instead of being written as
51
+ // `AsyncResult<S2, E2> | Result<S2, E2>` with separate `S2` / `E2` type
52
+ // parameters. With the union form, inference for `E2` collects a candidate
53
+ // from matching `Ok<S2>` against `Err<E2>` (both have a `value` property), so
54
+ // `E2` ends up as the success type and the call fails to type-check even for
55
+ // a function annotated as returning `Result<S2, E2>`.
56
+ export function flatMap<S, R2 extends UnknownAsyncResult | UnknownResult>(
57
+ flatMapFn: (value: S) => R2,
58
+ ): <E>(
59
+ asyncResult: AsyncResult<S, E>,
60
+ ) => AsyncResult<UnwrapOk<R2>, E | UnwrapErr<R2>>;
61
+
62
+ export function flatMap<S, E, R2 extends UnknownAsyncResult | UnknownResult>(
63
+ ...args:
64
+ | readonly [asyncResult: AsyncResult<S, E>, flatMapFn: (value: S) => R2]
65
+ | readonly [flatMapFn: (value: S) => R2]
66
+ ):
67
+ | AsyncResult<UnwrapOk<R2>, E | UnwrapErr<R2>>
68
+ | ((
69
+ asyncResult: AsyncResult<S, E>,
70
+ ) => AsyncResult<UnwrapOk<R2>, E | UnwrapErr<R2>>) {
71
+ switch (args.length) {
72
+ case 2: {
73
+ // Direct version: first argument is asyncResult
74
+ const [asyncResult, flatMapFn] = args;
75
+
76
+ return flatMapImpl(asyncResult, flatMapFn);
77
+ }
78
+
79
+ case 1: {
80
+ // Curried version
81
+ const [flatMapFn] = args;
82
+
83
+ return (asyncResult: AsyncResult<S, E>) =>
84
+ flatMapImpl(asyncResult, flatMapFn);
85
+ }
86
+ }
87
+ }
88
+
89
+ const flatMapImpl = async <S, E, R2 extends UnknownAsyncResult | UnknownResult>(
90
+ asyncResult: AsyncResult<S, E>,
91
+ flatMapFn: (value: S) => R2,
92
+ ): AsyncResult<UnwrapOk<R2>, E | UnwrapErr<R2>> => {
93
+ const result = await asyncResult;
94
+
95
+ return Result.isErr(result)
96
+ ? result
97
+ : // eslint-disable-next-line total-functions/no-unsafe-type-assertion
98
+ ((await flatMapFn(result.value)) as Result<UnwrapOk<R2>, UnwrapErr<R2>>);
99
+ };
@@ -0,0 +1,69 @@
1
+ import { Result } from '../../result/index.mjs';
2
+ import { type AsyncResult } from '../async-result.mjs';
3
+
4
+ /**
5
+ * Converts a `Promise` into an `AsyncResult`. If the input Promise resolves,
6
+ * the `AsyncResult` resolves to `Ok` with the resolved value. If the input
7
+ * Promise rejects, the rejection reason is passed through `mapError` and the
8
+ * `AsyncResult` resolves to `Err` with the mapped error.
9
+ *
10
+ * Passing `mapError` is what gives the error channel a concrete type `E`.
11
+ * Omitting it carries the rejection reason through untouched, leaving the
12
+ * error channel as `unknown` — the same contract as `Result.fromPromise`.
13
+ *
14
+ * @example
15
+ *
16
+ * ```ts
17
+ * const resolved = await AsyncResult.fromPromise(
18
+ * Promise.resolve('ok'),
19
+ * (error) => `failed: ${String(error)}`,
20
+ * );
21
+ *
22
+ * const rejected = await AsyncResult.fromPromise(
23
+ * Promise.reject(new Error('boom')),
24
+ * (error) => (isError(error) ? error.message : 'unknown'),
25
+ * );
26
+ *
27
+ * assert.deepStrictEqual(resolved, Result.ok('ok'));
28
+ *
29
+ * assert.deepStrictEqual(rejected, Result.err('boom'));
30
+ *
31
+ * // Without `mapError`, the rejection reason is carried as-is.
32
+ * const untyped = await AsyncResult.fromPromise(
33
+ * Promise.reject(new Error('boom')),
34
+ * );
35
+ *
36
+ * assert.isTrue(Result.isErr(untyped));
37
+ * ```
38
+ *
39
+ * @template S The type of the success value.
40
+ * @template E The type of the error value.
41
+ * @param promise The Promise to convert.
42
+ * @param mapError The function applied to the rejection reason to produce the
43
+ * error value. Omit it to carry the rejection reason as `unknown`.
44
+ * @returns An `AsyncResult<S, E>` that never rejects for the input Promise's
45
+ * failure.
46
+ */
47
+ export function fromPromise<S>(promise: Promise<S>): AsyncResult<S, unknown>;
48
+
49
+ export function fromPromise<S, E>(
50
+ promise: Promise<S>,
51
+ mapError: (error: unknown) => E,
52
+ ): AsyncResult<S, E>;
53
+
54
+ export function fromPromise<S, E>(
55
+ promise: Promise<S>,
56
+ mapError?: (error: unknown) => E,
57
+ ): AsyncResult<S, E> | AsyncResult<S, unknown> {
58
+ return mapError === undefined
59
+ ? fromPromiseImpl(promise, (error: unknown) => error)
60
+ : fromPromiseImpl(promise, mapError);
61
+ }
62
+
63
+ const fromPromiseImpl = <S, E>(
64
+ promise: Promise<S>,
65
+ mapError: (error: unknown) => E,
66
+ ): AsyncResult<S, E> =>
67
+ promise
68
+ .then((value) => Result.ok(value))
69
+ .catch((error: unknown) => Result.err(mapError(error)));