yield-result 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -45,6 +45,16 @@ const processOrder = (id: string) => safe.async(async function* () {
45
45
  });
46
46
  ```
47
47
 
48
+ ### 🎓 How `yield*` Works Under the Hood (Didactic Guide)
49
+
50
+ Many JavaScript developers assume generators are complex, but in `yield-result`, generator delegation (**`yield*`**) is simply a **native protocol for unwrapping values**:
51
+
52
+ 1. **`Ok<T>` Protocol**: Implements `[Symbol.iterator]` to return `value` immediately without yielding anything. Therefore, `const x = yield* ok(10)` assigns `10` directly to `x` in 0 suspension steps.
53
+ 2. **`Err<E>` Protocol**: Implements `[Symbol.iterator]` to `yield` the `Err` instance once back to `safe.sync` / `safe.async`.
54
+ 3. **Short-Circuiting**: The runner (`safe.sync`) receives the `Err` object, immediately calls `gen.return()` (triggering any `try ... finally` cleanup in your function), and early-returns `err(E)`.
55
+
56
+ No exception throwing, no stack unwinding, 100% native ECMAScript iteration semantics.
57
+
48
58
  ---
49
59
 
50
60
  ## 🚀 Installation
@@ -277,14 +287,16 @@ safe.sync(function* () {
277
287
  * **`err(error)`** / **`Result.err(error)`** — Creates an `Err<E>` result.
278
288
  * **`isOk(result)`** / **`isErr(result)`** — TypeScript type guards.
279
289
 
280
- ### Flow Runners (`safe`)
281
- * **`safe.sync(function* () { ... })`** — Executes a synchronous generator function with early-return short-circuiting on `Err`.
282
- * **`safe.async(async function* () { ... })`** — Executes an async generator function with early-return short-circuiting on `Err`.
290
+ ### Flow Runners (`safe` & `Result.gen`)
291
+ * **`safe.sync(function* () { ... })`** / **`Result.gen(function* () { ... })`** — Executes a synchronous generator function with early-return short-circuiting on `Err`.
292
+ * **`safe.async(async function* () { ... })`** / **`Result.gen.async(async function* () { ... })`** — Executes an async generator function with early-return short-circuiting on `Err`.
283
293
 
284
- ### Exception Wrappers
294
+ ### Exception Wrappers & Function Lifting
285
295
  * **`fromThrowable(fn, errorMapper?)`** — Wraps a throwing function into a `Result<T, E>`.
286
296
  * **`fromPromise(promise, errorMapper?)`** — Wraps a Promise into `Promise<Result<T, E>>`.
287
297
  * **`fromAsyncFn(fn, errorMapper?)`** — Wraps an async function into `Promise<Result<T, E>>`.
298
+ * **`lift(fn, errorMapper?)`** — Lifts a sync throwing function `(...args) => T` into a Result function `(...args) => Result<T, E>`.
299
+ * **`liftAsync(fn, errorMapper?)`** — Lifts an async function `(...args) => Promise<T>` into a Promise<Result> function `(...args) => Promise<Result<T, E>>`.
288
300
 
289
301
  ### Combinators & Utilities
290
302
  * **`map(result, fn)`** — Transforms the `Ok` value.
package/dist/types.d.ts CHANGED
@@ -98,7 +98,7 @@ export interface TaggedError<T extends string> {
98
98
  */
99
99
  export declare const taggedError: <T extends string, P extends Record<string, unknown> = {}>(tag: T, props?: P) => Readonly<TaggedError<T> & P>;
100
100
  /**
101
- * Namespace object grouping all Result constructors, guards, and combinators.
101
+ * Namespace object grouping all Result constructors, guards, combinators, and generator runners.
102
102
  */
103
103
  export declare const Result: {
104
104
  readonly ok: <T>(value: T) => Ok<T>;
@@ -123,4 +123,8 @@ export declare const Result: {
123
123
  errors: E[];
124
124
  };
125
125
  readonly taggedError: <T extends string, P extends Record<string, unknown> = {}>(tag: T, props?: P) => Readonly<TaggedError<T> & P>;
126
+ readonly gen: (<G extends Generator<Err<unknown>, unknown, unknown>>(fn: () => G) => Result<G extends Generator<unknown, infer R, unknown> ? R : G extends AsyncGenerator<unknown, infer R_1, unknown> ? R_1 : never, G extends Generator<infer Y, unknown, unknown> ? Y extends Err<infer E> ? E : never : G extends AsyncGenerator<infer Y_1, unknown, unknown> ? Y_1 extends Err<infer E_1> ? E_1 : never : never>) & {
127
+ sync: <G extends Generator<Err<unknown>, unknown, unknown>>(fn: () => G) => Result<G extends Generator<unknown, infer R, unknown> ? R : G extends AsyncGenerator<unknown, infer R_1, unknown> ? R_1 : never, G extends Generator<infer Y, unknown, unknown> ? Y extends Err<infer E> ? E : never : G extends AsyncGenerator<infer Y_1, unknown, unknown> ? Y_1 extends Err<infer E_1> ? E_1 : never : never>;
128
+ async: <G extends AsyncGenerator<Err<unknown>, unknown, unknown>>(fn: () => G) => Promise<Result<G extends Generator<unknown, infer R, unknown> ? R : G extends AsyncGenerator<unknown, infer R_1, unknown> ? R_1 : never, G extends Generator<infer Y, unknown, unknown> ? Y extends Err<infer E> ? E : never : G extends AsyncGenerator<infer Y_1, unknown, unknown> ? Y_1 extends Err<infer E_1> ? E_1 : never : never>>;
129
+ };
126
130
  };
package/dist/types.js CHANGED
@@ -140,8 +140,13 @@ export const taggedError = (tag, props) => Object.freeze({
140
140
  _tag: tag,
141
141
  ...(props ?? {}),
142
142
  });
143
+ import { safe } from "./flow.js";
144
+ const genRunner = Object.assign((fn) => safe.sync(fn), {
145
+ sync: safe.sync,
146
+ async: safe.async,
147
+ });
143
148
  /**
144
- * Namespace object grouping all Result constructors, guards, and combinators.
149
+ * Namespace object grouping all Result constructors, guards, combinators, and generator runners.
145
150
  */
146
151
  export const Result = {
147
152
  ok,
@@ -160,4 +165,5 @@ export const Result = {
160
165
  all,
161
166
  partition,
162
167
  taggedError,
168
+ gen: genRunner,
163
169
  };
@@ -14,3 +14,11 @@ export declare const fromPromise: <T, E = unknown>(promise: Promise<T>, errorMap
14
14
  * Catches both synchronous exceptions thrown during execution and async rejections.
15
15
  */
16
16
  export declare const fromAsyncFn: <T, E = unknown>(fn: () => Promise<T>, errorMapper?: (e: unknown) => E) => Promise<Result<T, E>>;
17
+ /**
18
+ * Lifts a standard synchronous function that may throw into a Result-returning function.
19
+ */
20
+ export declare const lift: <A extends any[], T, E = unknown>(fn: (...args: A) => T, errorMapper?: (e: unknown) => E) => ((...args: A) => Result<T, E>);
21
+ /**
22
+ * Lifts an asynchronous function returning a Promise into a Promise<Result<T, E>> function.
23
+ */
24
+ export declare const liftAsync: <A extends any[], T, E = unknown>(fn: (...args: A) => Promise<T>, errorMapper?: (e: unknown) => E) => ((...args: A) => Promise<Result<T, E>>);
package/dist/wrappers.js CHANGED
@@ -37,3 +37,15 @@ export const fromAsyncFn = async (fn, errorMapper) => {
37
37
  return err(errorMapper ? errorMapper(e) : e);
38
38
  }
39
39
  };
40
+ /**
41
+ * Lifts a standard synchronous function that may throw into a Result-returning function.
42
+ */
43
+ export const lift = (fn, errorMapper) => {
44
+ return (...args) => fromThrowable(() => fn(...args), errorMapper);
45
+ };
46
+ /**
47
+ * Lifts an asynchronous function returning a Promise into a Promise<Result<T, E>> function.
48
+ */
49
+ export const liftAsync = (fn, errorMapper) => {
50
+ return (...args) => fromAsyncFn(() => fn(...args), errorMapper);
51
+ };
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "yield-result",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Rust-style ? operator for TypeScript using generators (yield*). Zero dependencies, type-safe error handling.",
5
5
  "type": "module",
6
+ "sideEffects": false,
6
7
  "main": "./dist/index.js",
7
8
  "module": "./dist/index.js",
8
9
  "types": "./dist/index.d.ts",