@oscarpalmer/atoms 0.207.0 → 0.208.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/index.d.mts CHANGED
@@ -4589,18 +4589,64 @@ export declare function setValue<Data extends PlainObject>(data: Data, path: str
4589
4589
  //#endregion
4590
4590
  //#region src/internal/models/plan.model.d.ts
4591
4591
  /**
4592
- * A plan of execution that can yield intermediate results and eventually return a value or an error.
4592
+ * An asynchronous plan of execution that can yield intermediate results and eventually return a result
4593
4593
  */
4594
- type Plan<out Value, out Error = unknown> = {
4594
+ type AsyncPlan<Value, Error = unknown> = {
4595
4595
  /**
4596
4596
  * Run the plan to completion
4597
4597
  *
4598
- * @returns Final result, or an error
4598
+ * @returns Result
4599
4599
  */
4600
- run: () => Error | Value;
4600
+ run: () => Promise<Result<Value, Error>>;
4601
+ };
4602
+ /**
4603
+ * A plan of execution that can yield intermediate results and eventually return a result
4604
+ */
4605
+ type Plan<Value, Error = unknown> = {
4606
+ /**
4607
+ * Run the plan to completion
4608
+ *
4609
+ * @returns Result
4610
+ */
4611
+ run: () => Result<Value, Error>;
4601
4612
  };
4602
4613
  //#endregion
4603
4614
  //#region src/plan/index.d.ts
4615
+ /**
4616
+ * Create a plan for an asynchronous generator function
4617
+ *
4618
+ * @param generator Generator to plan for
4619
+ * @returns Generator plan
4620
+ */
4621
+ export declare function asyncPlan<Value = unknown, Error = unknown>(generator: () => AsyncGenerator<unknown, Value, unknown>): AsyncPlan<Value, Error>;
4622
+ /**
4623
+ * Run an asynchronous generator to completion
4624
+ *
4625
+ * @param generator Generator to run
4626
+ * @returns Result
4627
+ */
4628
+ export declare function asyncRun<Value = unknown, Error = unknown>(generator: () => AsyncGenerator<unknown, Value, unknown>): Promise<Result<Value, Error>>;
4629
+ /**
4630
+ * Run an asynchronous plan to completion
4631
+ *
4632
+ * @param plan Plan to run
4633
+ * @returns Result
4634
+ */
4635
+ export declare function asyncRun<Value = unknown, Error = unknown>(plan: AsyncPlan<Value, Error>): Promise<Result<Value, Error>>;
4636
+ /**
4637
+ * Is the value an asynchronous plan?
4638
+ *
4639
+ * @param value Value to check
4640
+ * @returns `true` if the value is an asynchronous plan, otherwise `false`
4641
+ */
4642
+ export declare function isAsyncPlan<Value = unknown, Error = unknown>(value: unknown): value is AsyncPlan<Value, Error>;
4643
+ /**
4644
+ * Is the value an asynchronous generator function?
4645
+ *
4646
+ * @param value Value to check
4647
+ * @returns `true` if the value is an asynchronous generator function, otherwise `false`
4648
+ */
4649
+ export declare function isAsyncGenerator(value: unknown): value is () => AsyncGenerator;
4604
4650
  /**
4605
4651
  * Is the value a generator function?
4606
4652
  *
@@ -4626,16 +4672,22 @@ export declare function plan<Value = unknown, Error = unknown>(generator: () =>
4626
4672
  * Run a generator to completion
4627
4673
  *
4628
4674
  * @param generator Generator to run
4629
- * @returns Final result, or an error
4675
+ * @returns Result
4630
4676
  */
4631
- export declare function run<Value = unknown, Error = unknown>(generator: () => Generator<unknown, Value, unknown>): Error | Value;
4677
+ export declare function run<Value = unknown, Error = unknown>(generator: () => Generator<unknown, Value, unknown>): Result<Value, Error>;
4632
4678
  /**
4633
4679
  * Run a plan to completion
4634
4680
  *
4635
4681
  * @param plan Plan to run
4636
- * @returns Final result, or an error
4682
+ * @returns Result
4637
4683
  */
4638
- export declare function run<Value = unknown, Error = unknown>(plan: Plan<Value, Error>): Error | Value;
4684
+ export declare function run<Value = unknown, Error = unknown>(plan: Plan<Value, Error>): Result<Value, Error>;
4685
+ export declare namespace plan {
4686
+ export var async: typeof asyncPlan;
4687
+ }
4688
+ export declare namespace run {
4689
+ export var async: typeof asyncRun;
4690
+ }
4639
4691
  //#endregion
4640
4692
  //#region src/internal/aborter.d.ts
4641
4693
  type Aborter = {
package/dist/index.mjs CHANGED
@@ -2749,14 +2749,56 @@ const SET_EXPRESSION_INDEX = /^\d+$/;
2749
2749
  const PLAN_MESSAGE_PLAN_INPUT = "plan requires a generator function";
2750
2750
  const PLAN_MESSAGE_RUN_INPUT = "run requires a plan or a generator function";
2751
2751
  const PLAN_SYMBOL = Symbol("plan");
2752
+ const PLAN_TYPE_PLAN_ASYNC = "asyncPlan";
2753
+ const PLAN_TYPE_PLAN_SYNC = "plan";
2752
2754
  //#endregion
2753
2755
  //#region src/plan/index.ts
2756
+ function AsyncPlan(generator) {
2757
+ this[PLAN_SYMBOL] = {
2758
+ generator,
2759
+ type: PLAN_TYPE_PLAN_ASYNC
2760
+ };
2761
+ }
2762
+ AsyncPlan.prototype.run = runAsyncPlan;
2754
2763
  function Plan(generator) {
2755
- this[PLAN_SYMBOL] = { generator };
2764
+ this[PLAN_SYMBOL] = {
2765
+ generator,
2766
+ type: PLAN_TYPE_PLAN_SYNC
2767
+ };
2756
2768
  }
2757
2769
  Plan.prototype.run = runPlan;
2770
+ function asyncExecute(callback) {
2771
+ return asyncAttempt(async () => {
2772
+ const generator = callback();
2773
+ let lastValue;
2774
+ while (true) {
2775
+ const next = await generator.next();
2776
+ const { done } = next;
2777
+ let value = next.value;
2778
+ if (value instanceof Error) throw value;
2779
+ lastValue = value;
2780
+ if (done === true) break;
2781
+ }
2782
+ return lastValue;
2783
+ });
2784
+ }
2785
+ /**
2786
+ * Create a plan for an asynchronous generator function
2787
+ *
2788
+ * @param generator Generator to plan for
2789
+ * @returns Generator plan
2790
+ */
2791
+ function asyncPlan(generator) {
2792
+ if (!isAsyncGenerator(generator)) throw new Error(PLAN_MESSAGE_PLAN_INPUT);
2793
+ return new AsyncPlan(generator);
2794
+ }
2795
+ async function asyncRun(input) {
2796
+ if (isAsyncPlan(input)) return input.run();
2797
+ if (!isAsyncGenerator(input)) throw new Error(PLAN_MESSAGE_RUN_INPUT);
2798
+ return asyncExecute(input);
2799
+ }
2758
2800
  function execute(callback) {
2759
- const result = attempt(() => {
2801
+ return attempt(() => {
2760
2802
  const generator = callback();
2761
2803
  let lastValue;
2762
2804
  while (true) {
@@ -2769,7 +2811,24 @@ function execute(callback) {
2769
2811
  }
2770
2812
  return lastValue;
2771
2813
  });
2772
- return result.ok ? result.value : result.error;
2814
+ }
2815
+ /**
2816
+ * Is the value an asynchronous plan?
2817
+ *
2818
+ * @param value Value to check
2819
+ * @returns `true` if the value is an asynchronous plan, otherwise `false`
2820
+ */
2821
+ function isAsyncPlan(value) {
2822
+ return isPlanInstance(PLAN_TYPE_PLAN_ASYNC, value);
2823
+ }
2824
+ /**
2825
+ * Is the value an asynchronous generator function?
2826
+ *
2827
+ * @param value Value to check
2828
+ * @returns `true` if the value is an asynchronous generator function, otherwise `false`
2829
+ */
2830
+ function isAsyncGenerator(value) {
2831
+ return typeof value === "function" && value.constructor.name === "AsyncGeneratorFunction" && typeof value.prototype.next === "function" && typeof value.prototype.return === "function" && typeof value.prototype.throw === "function";
2773
2832
  }
2774
2833
  /**
2775
2834
  * Is the value a generator function?
@@ -2787,7 +2846,10 @@ function isGenerator(value) {
2787
2846
  * @returns `true` if the value is a plan, otherwise `false`
2788
2847
  */
2789
2848
  function isPlan(value) {
2790
- return typeof value === "object" && value !== null && PLAN_SYMBOL in value;
2849
+ return isPlanInstance(PLAN_TYPE_PLAN_SYNC, value);
2850
+ }
2851
+ function isPlanInstance(type, value) {
2852
+ return typeof value === "object" && value !== null && PLAN_SYMBOL in value && value[PLAN_SYMBOL].type === type;
2791
2853
  }
2792
2854
  /**
2793
2855
  * Create a plan for a generator function
@@ -2804,9 +2866,14 @@ function run(input) {
2804
2866
  if (!isGenerator(input)) throw new Error(PLAN_MESSAGE_RUN_INPUT);
2805
2867
  return execute(input);
2806
2868
  }
2869
+ function runAsyncPlan() {
2870
+ return asyncExecute(this[PLAN_SYMBOL].generator);
2871
+ }
2807
2872
  function runPlan() {
2808
2873
  return execute(this[PLAN_SYMBOL].generator);
2809
2874
  }
2875
+ plan.async = asyncPlan;
2876
+ run.async = asyncRun;
2810
2877
  //#endregion
2811
2878
  //#region src/internal/aborter.ts
2812
2879
  function createAborter(value, onAbort) {
@@ -6908,4 +6975,4 @@ var SizedSet = class extends Set {
6908
6975
  }
6909
6976
  };
6910
6977
  //#endregion
6911
- export { CancelablePromise, Logger, PromiseTimeoutError, QueueError, RetryError, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SizedMap, SizedSet, push as append, push, assert, assertCondition, assertDefined, assertInstanceOf, assertIs, assertProperty, assign, asyncAttempt, asyncDebounce, asyncFlow, asyncMatchResult, asyncOnce, asyncPipe, asyncThrottle, attempt, attemptAsyncFlow, attemptAsyncPipe, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, copy, count, debounce, deburr, dedent, delay, deregisterCloner, deregisterComparator, deregisterEqualizer, diff, difference, drop, endsWith, endsWithArray, equal, error, exclude, exists, filter, filterAndMap, filterAndMap as select, find, findLast, first, firstOrDefault, flatFreeze, flatten, floor, flow, freeze, fromQuery, toPromise as fromResult, toPromise, fuzzy, fuzzyMatch, getArray, getArrayComparison, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getHwbColor, getHwbaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloatingNumber as getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getSortedIndex, getString, getTimedPromise, getUuid, getValue, groupArraysBy, groupBy, handleResult, hasValue, hasValueResult, herald, hexToHsl, hexToHsla, hexToHwb, hexToHwba, hexToRgb, hexToRgba, hslToHex, hslToHwb, hslToHwba, hslToRgb, hslToRgba, hwbToHex, hwbToHsl, hwbToHsla, hwbToRgb, hwbToRgba, ignoreKey, inMap, inSet, includes, includesArray, indexOf, indexOfArray, initializeAssigner, initializeCloner, initializeEqualizer, initializeMerger, initializeNormalizer, initializeSorter, initializeTemplater, initializeTransformer, insert, interpolate, intersection, isArrayOrPlainObject, isAsyncOnce, isBeacon, isBeaconSubscription, isColor, isConstructor, isEmpty, isError, isFrozen, isFulfilled, isFuzzy, isGenerator, isHerald, isHeraldEvents, isHeraldSubscription, isHexColor, isHslColor, isHslaColor, isHwbColor, isHwbaColor, isInstanceOf, isKey, isKeyedQueue, isLogger, isNonArrayOrPlainObject, isNonConstructor, isNonEmpty, isNonInstanceOf, isNonKey, isNonNullable, isNonNullableOrEmpty, isNonNullableOrWhitespace, isNonNumber, isNonNumerical, isNonObject, isNonPlainObject, isNonPrimitive, isNonTemplateStringsArray, isNonTypedArray, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isObservable, isOk, isOnce, isPlainObject, isPlan, isPrimitive, isQueue, isQueueInstance, isRejected, isResult, isRgbColor, isRgbaColor, isSorted, isSubscription, isSubscriptions, isTemplateStringsArray, isTimeLogger, isTypedArray, join, kebabCase, keyedQueue, last, lastIndexOf, lastOrDefault, lowerCase, mapAndFilter, mapAndFilter as reverseSelect, matchResult, max, median, memoize, merge, min, move, moveIndices, moveToIndex, noop, normalize, ok, omit, once, parse, partition, pascalCase, pick, pipe, plan, promises, queue, range, registerCloner, registerComparator, registerEqualizer, resultPromises, retry, reverse, rgbToHex, rgbToHsl, rgbToHsla, rgbToHwb, rgbToHwba, round, run, setValue, settlePromise, shake, shuffle, single, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, subscriptions, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toMapArrays, toQuery, toRecord, toRecordArrays, toResult, toSet, toggle, transform, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
6978
+ export { CancelablePromise, Logger, PromiseTimeoutError, QueueError, RetryError, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SizedMap, SizedSet, push as append, push, assert, assertCondition, assertDefined, assertInstanceOf, assertIs, assertProperty, assign, asyncAttempt, asyncDebounce, asyncFlow, asyncMatchResult, asyncOnce, asyncPipe, asyncPlan, asyncRun, asyncThrottle, attempt, attemptAsyncFlow, attemptAsyncPipe, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, copy, count, debounce, deburr, dedent, delay, deregisterCloner, deregisterComparator, deregisterEqualizer, diff, difference, drop, endsWith, endsWithArray, equal, error, exclude, exists, filter, filterAndMap, filterAndMap as select, find, findLast, first, firstOrDefault, flatFreeze, flatten, floor, flow, freeze, fromQuery, toPromise as fromResult, toPromise, fuzzy, fuzzyMatch, getArray, getArrayComparison, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getHwbColor, getHwbaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloatingNumber as getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getSortedIndex, getString, getTimedPromise, getUuid, getValue, groupArraysBy, groupBy, handleResult, hasValue, hasValueResult, herald, hexToHsl, hexToHsla, hexToHwb, hexToHwba, hexToRgb, hexToRgba, hslToHex, hslToHwb, hslToHwba, hslToRgb, hslToRgba, hwbToHex, hwbToHsl, hwbToHsla, hwbToRgb, hwbToRgba, ignoreKey, inMap, inSet, includes, includesArray, indexOf, indexOfArray, initializeAssigner, initializeCloner, initializeEqualizer, initializeMerger, initializeNormalizer, initializeSorter, initializeTemplater, initializeTransformer, insert, interpolate, intersection, isArrayOrPlainObject, isAsyncGenerator, isAsyncOnce, isAsyncPlan, isBeacon, isBeaconSubscription, isColor, isConstructor, isEmpty, isError, isFrozen, isFulfilled, isFuzzy, isGenerator, isHerald, isHeraldEvents, isHeraldSubscription, isHexColor, isHslColor, isHslaColor, isHwbColor, isHwbaColor, isInstanceOf, isKey, isKeyedQueue, isLogger, isNonArrayOrPlainObject, isNonConstructor, isNonEmpty, isNonInstanceOf, isNonKey, isNonNullable, isNonNullableOrEmpty, isNonNullableOrWhitespace, isNonNumber, isNonNumerical, isNonObject, isNonPlainObject, isNonPrimitive, isNonTemplateStringsArray, isNonTypedArray, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isObservable, isOk, isOnce, isPlainObject, isPlan, isPrimitive, isQueue, isQueueInstance, isRejected, isResult, isRgbColor, isRgbaColor, isSorted, isSubscription, isSubscriptions, isTemplateStringsArray, isTimeLogger, isTypedArray, join, kebabCase, keyedQueue, last, lastIndexOf, lastOrDefault, lowerCase, mapAndFilter, mapAndFilter as reverseSelect, matchResult, max, median, memoize, merge, min, move, moveIndices, moveToIndex, noop, normalize, ok, omit, once, parse, partition, pascalCase, pick, pipe, plan, promises, queue, range, registerCloner, registerComparator, registerEqualizer, resultPromises, retry, reverse, rgbToHex, rgbToHsl, rgbToHsla, rgbToHwb, rgbToHwba, round, run, setValue, settlePromise, shake, shuffle, single, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, subscriptions, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toMapArrays, toQuery, toRecord, toRecordArrays, toResult, toSet, toggle, transform, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
@@ -1,23 +1,48 @@
1
+ import { Result } from "./result.model.mjs";
1
2
  //#region src/internal/models/plan.model.d.ts
3
+ /**
4
+ * An asynchronous plan of execution that can yield intermediate results and eventually return a result
5
+ */
6
+ export type AsyncPlan<Value, Error = unknown> = {
7
+ /**
8
+ * Run the plan to completion
9
+ *
10
+ * @returns Result
11
+ */
12
+ run: () => Promise<Result<Value, Error>>;
13
+ };
14
+ type AsyncPlanState = {
15
+ generator: () => AsyncGenerator;
16
+ } & BaseState<typeof PLAN_TYPE_PLAN_ASYNC>;
17
+ type BaseState<Type extends PlanType> = {
18
+ type: Type;
19
+ };
20
+ export type InternalAsyncPlan = {
21
+ [PLAN_SYMBOL]: AsyncPlanState;
22
+ } & AsyncPlan<never, never>;
2
23
  export type InternalPlan = {
3
24
  [PLAN_SYMBOL]: PlanState;
4
25
  } & Plan<never, never>;
5
26
  /**
6
- * A plan of execution that can yield intermediate results and eventually return a value or an error.
27
+ * A plan of execution that can yield intermediate results and eventually return a result
7
28
  */
8
- export type Plan<out Value, out Error = unknown> = {
29
+ export type Plan<Value, Error = unknown> = {
9
30
  /**
10
31
  * Run the plan to completion
11
32
  *
12
- * @returns Final result, or an error
33
+ * @returns Result
13
34
  */
14
- run: () => Error | Value;
35
+ run: () => Result<Value, Error>;
15
36
  };
16
37
  type PlanState = {
17
38
  generator: () => Generator;
18
- };
19
- export declare const GENERATOR_NAME = "GeneratorFunction";
39
+ } & BaseState<typeof PLAN_TYPE_PLAN_SYNC>;
40
+ export type PlanType = "asyncPlan" | "plan";
41
+ export declare const GENERATOR_NAME_ASYNC = "AsyncGeneratorFunction";
42
+ export declare const GENERATOR_NAME_SYNC = "GeneratorFunction";
20
43
  export declare const PLAN_MESSAGE_PLAN_INPUT = "plan requires a generator function";
21
44
  export declare const PLAN_MESSAGE_RUN_INPUT = "run requires a plan or a generator function";
22
45
  export declare const PLAN_SYMBOL: symbol;
46
+ export declare const PLAN_TYPE_PLAN_ASYNC: PlanType;
47
+ export declare const PLAN_TYPE_PLAN_SYNC: PlanType;
23
48
  //#endregion
@@ -1,7 +1,10 @@
1
1
  //#region src/internal/models/plan.model.ts
2
- const GENERATOR_NAME = "GeneratorFunction";
2
+ const GENERATOR_NAME_ASYNC = "AsyncGeneratorFunction";
3
+ const GENERATOR_NAME_SYNC = "GeneratorFunction";
3
4
  const PLAN_MESSAGE_PLAN_INPUT = "plan requires a generator function";
4
5
  const PLAN_MESSAGE_RUN_INPUT = "run requires a plan or a generator function";
5
6
  const PLAN_SYMBOL = Symbol("plan");
7
+ const PLAN_TYPE_PLAN_ASYNC = "asyncPlan";
8
+ const PLAN_TYPE_PLAN_SYNC = "plan";
6
9
  //#endregion
7
- export { GENERATOR_NAME, PLAN_MESSAGE_PLAN_INPUT, PLAN_MESSAGE_RUN_INPUT, PLAN_SYMBOL };
10
+ export { GENERATOR_NAME_ASYNC, GENERATOR_NAME_SYNC, PLAN_MESSAGE_PLAN_INPUT, PLAN_MESSAGE_RUN_INPUT, PLAN_SYMBOL, PLAN_TYPE_PLAN_ASYNC, PLAN_TYPE_PLAN_SYNC };
@@ -1,5 +1,41 @@
1
- import { Plan } from "../internal/models/plan.model.mjs";
1
+ import { Result } from "../internal/models/result.model.mjs";
2
+ import { AsyncPlan, Plan } from "../internal/models/plan.model.mjs";
2
3
  //#region src/plan/index.d.ts
4
+ /**
5
+ * Create a plan for an asynchronous generator function
6
+ *
7
+ * @param generator Generator to plan for
8
+ * @returns Generator plan
9
+ */
10
+ export declare function asyncPlan<Value = unknown, Error = unknown>(generator: () => AsyncGenerator<unknown, Value, unknown>): AsyncPlan<Value, Error>;
11
+ /**
12
+ * Run an asynchronous generator to completion
13
+ *
14
+ * @param generator Generator to run
15
+ * @returns Result
16
+ */
17
+ export declare function asyncRun<Value = unknown, Error = unknown>(generator: () => AsyncGenerator<unknown, Value, unknown>): Promise<Result<Value, Error>>;
18
+ /**
19
+ * Run an asynchronous plan to completion
20
+ *
21
+ * @param plan Plan to run
22
+ * @returns Result
23
+ */
24
+ export declare function asyncRun<Value = unknown, Error = unknown>(plan: AsyncPlan<Value, Error>): Promise<Result<Value, Error>>;
25
+ /**
26
+ * Is the value an asynchronous plan?
27
+ *
28
+ * @param value Value to check
29
+ * @returns `true` if the value is an asynchronous plan, otherwise `false`
30
+ */
31
+ export declare function isAsyncPlan<Value = unknown, Error = unknown>(value: unknown): value is AsyncPlan<Value, Error>;
32
+ /**
33
+ * Is the value an asynchronous generator function?
34
+ *
35
+ * @param value Value to check
36
+ * @returns `true` if the value is an asynchronous generator function, otherwise `false`
37
+ */
38
+ export declare function isAsyncGenerator(value: unknown): value is () => AsyncGenerator;
3
39
  /**
4
40
  * Is the value a generator function?
5
41
  *
@@ -25,14 +61,20 @@ export declare function plan<Value = unknown, Error = unknown>(generator: () =>
25
61
  * Run a generator to completion
26
62
  *
27
63
  * @param generator Generator to run
28
- * @returns Final result, or an error
64
+ * @returns Result
29
65
  */
30
- export declare function run<Value = unknown, Error = unknown>(generator: () => Generator<unknown, Value, unknown>): Error | Value;
66
+ export declare function run<Value = unknown, Error = unknown>(generator: () => Generator<unknown, Value, unknown>): Result<Value, Error>;
31
67
  /**
32
68
  * Run a plan to completion
33
69
  *
34
70
  * @param plan Plan to run
35
- * @returns Final result, or an error
71
+ * @returns Result
36
72
  */
37
- export declare function run<Value = unknown, Error = unknown>(plan: Plan<Value, Error>): Error | Value;
73
+ export declare function run<Value = unknown, Error = unknown>(plan: Plan<Value, Error>): Result<Value, Error>;
74
+ export declare namespace plan {
75
+ export var async: typeof asyncPlan;
76
+ }
77
+ export declare namespace run {
78
+ export var async: typeof asyncRun;
79
+ }
38
80
  //#endregion
@@ -1,12 +1,52 @@
1
- import { attempt } from "../internal/result/attempt.mjs";
2
- import { PLAN_MESSAGE_PLAN_INPUT, PLAN_MESSAGE_RUN_INPUT, PLAN_SYMBOL } from "../internal/models/plan.model.mjs";
1
+ import { asyncAttempt, attempt } from "../internal/result/attempt.mjs";
2
+ import { PLAN_MESSAGE_PLAN_INPUT, PLAN_MESSAGE_RUN_INPUT, PLAN_SYMBOL, PLAN_TYPE_PLAN_ASYNC, PLAN_TYPE_PLAN_SYNC } from "../internal/models/plan.model.mjs";
3
3
  //#region src/plan/index.ts
4
+ function AsyncPlan(generator) {
5
+ this[PLAN_SYMBOL] = {
6
+ generator,
7
+ type: PLAN_TYPE_PLAN_ASYNC
8
+ };
9
+ }
10
+ AsyncPlan.prototype.run = runAsyncPlan;
4
11
  function Plan(generator) {
5
- this[PLAN_SYMBOL] = { generator };
12
+ this[PLAN_SYMBOL] = {
13
+ generator,
14
+ type: PLAN_TYPE_PLAN_SYNC
15
+ };
6
16
  }
7
17
  Plan.prototype.run = runPlan;
18
+ function asyncExecute(callback) {
19
+ return asyncAttempt(async () => {
20
+ const generator = callback();
21
+ let lastValue;
22
+ while (true) {
23
+ const next = await generator.next();
24
+ const { done } = next;
25
+ let value = next.value;
26
+ if (value instanceof Error) throw value;
27
+ lastValue = value;
28
+ if (done === true) break;
29
+ }
30
+ return lastValue;
31
+ });
32
+ }
33
+ /**
34
+ * Create a plan for an asynchronous generator function
35
+ *
36
+ * @param generator Generator to plan for
37
+ * @returns Generator plan
38
+ */
39
+ function asyncPlan(generator) {
40
+ if (!isAsyncGenerator(generator)) throw new Error(PLAN_MESSAGE_PLAN_INPUT);
41
+ return new AsyncPlan(generator);
42
+ }
43
+ async function asyncRun(input) {
44
+ if (isAsyncPlan(input)) return input.run();
45
+ if (!isAsyncGenerator(input)) throw new Error(PLAN_MESSAGE_RUN_INPUT);
46
+ return asyncExecute(input);
47
+ }
8
48
  function execute(callback) {
9
- const result = attempt(() => {
49
+ return attempt(() => {
10
50
  const generator = callback();
11
51
  let lastValue;
12
52
  while (true) {
@@ -19,7 +59,24 @@ function execute(callback) {
19
59
  }
20
60
  return lastValue;
21
61
  });
22
- return result.ok ? result.value : result.error;
62
+ }
63
+ /**
64
+ * Is the value an asynchronous plan?
65
+ *
66
+ * @param value Value to check
67
+ * @returns `true` if the value is an asynchronous plan, otherwise `false`
68
+ */
69
+ function isAsyncPlan(value) {
70
+ return isPlanInstance(PLAN_TYPE_PLAN_ASYNC, value);
71
+ }
72
+ /**
73
+ * Is the value an asynchronous generator function?
74
+ *
75
+ * @param value Value to check
76
+ * @returns `true` if the value is an asynchronous generator function, otherwise `false`
77
+ */
78
+ function isAsyncGenerator(value) {
79
+ return typeof value === "function" && value.constructor.name === "AsyncGeneratorFunction" && typeof value.prototype.next === "function" && typeof value.prototype.return === "function" && typeof value.prototype.throw === "function";
23
80
  }
24
81
  /**
25
82
  * Is the value a generator function?
@@ -37,7 +94,10 @@ function isGenerator(value) {
37
94
  * @returns `true` if the value is a plan, otherwise `false`
38
95
  */
39
96
  function isPlan(value) {
40
- return typeof value === "object" && value !== null && PLAN_SYMBOL in value;
97
+ return isPlanInstance(PLAN_TYPE_PLAN_SYNC, value);
98
+ }
99
+ function isPlanInstance(type, value) {
100
+ return typeof value === "object" && value !== null && PLAN_SYMBOL in value && value[PLAN_SYMBOL].type === type;
41
101
  }
42
102
  /**
43
103
  * Create a plan for a generator function
@@ -54,8 +114,13 @@ function run(input) {
54
114
  if (!isGenerator(input)) throw new Error(PLAN_MESSAGE_RUN_INPUT);
55
115
  return execute(input);
56
116
  }
117
+ function runAsyncPlan() {
118
+ return asyncExecute(this[PLAN_SYMBOL].generator);
119
+ }
57
120
  function runPlan() {
58
121
  return execute(this[PLAN_SYMBOL].generator);
59
122
  }
123
+ plan.async = asyncPlan;
124
+ run.async = asyncRun;
60
125
  //#endregion
61
- export { isGenerator, isPlan, plan, run };
126
+ export { asyncPlan, asyncRun, isAsyncGenerator, isAsyncPlan, isGenerator, isPlan, plan, run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/atoms",
3
- "version": "0.207.0",
3
+ "version": "0.208.0",
4
4
  "description": "Atomic utilities for making your JavaScript better.",
5
5
  "keywords": [
6
6
  "array",