@duplojs/utils 1.5.14 → 1.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.
- package/dist/clean/flag.d.ts +1 -1
- package/dist/clean/primitive/operations/equal.d.ts +3 -3
- package/dist/common/kind.cjs +2 -1
- package/dist/common/kind.d.ts +1 -0
- package/dist/common/kind.mjs +2 -1
- package/dist/flow/breakIf.cjs +14 -0
- package/dist/flow/breakIf.d.ts +50 -0
- package/dist/flow/breakIf.mjs +12 -0
- package/dist/flow/defer.cjs +12 -0
- package/dist/flow/defer.d.ts +47 -0
- package/dist/flow/defer.mjs +10 -0
- package/dist/flow/exec.cjs +125 -0
- package/dist/flow/exec.d.ts +83 -0
- package/dist/flow/exec.mjs +123 -0
- package/dist/flow/exitIf.cjs +14 -0
- package/dist/flow/exitIf.d.ts +67 -0
- package/dist/flow/exitIf.mjs +12 -0
- package/dist/flow/finalizer.cjs +12 -0
- package/dist/flow/finalizer.d.ts +47 -0
- package/dist/flow/finalizer.mjs +10 -0
- package/dist/flow/index.cjs +50 -0
- package/dist/flow/index.d.ts +12 -0
- package/dist/flow/index.mjs +18 -0
- package/dist/flow/initializer.cjs +38 -0
- package/dist/flow/initializer.d.ts +75 -0
- package/dist/flow/initializer.mjs +36 -0
- package/dist/flow/inject.cjs +19 -0
- package/dist/flow/inject.d.ts +46 -0
- package/dist/flow/inject.mjs +17 -0
- package/dist/flow/kind.cjs +9 -0
- package/dist/flow/kind.d.ts +1 -0
- package/dist/flow/kind.mjs +7 -0
- package/dist/flow/run.cjs +139 -0
- package/dist/flow/run.d.ts +80 -0
- package/dist/flow/run.mjs +136 -0
- package/dist/flow/step.cjs +23 -0
- package/dist/flow/step.d.ts +39 -0
- package/dist/flow/step.mjs +21 -0
- package/dist/flow/theFlow/break.cjs +11 -0
- package/dist/flow/theFlow/break.d.ts +7 -0
- package/dist/flow/theFlow/break.mjs +8 -0
- package/dist/flow/theFlow/defer.cjs +11 -0
- package/dist/flow/theFlow/defer.d.ts +5 -0
- package/dist/flow/theFlow/defer.mjs +8 -0
- package/dist/flow/theFlow/dependence.cjs +17 -0
- package/dist/flow/theFlow/dependence.d.ts +50 -0
- package/dist/flow/theFlow/dependence.mjs +14 -0
- package/dist/flow/theFlow/exit.cjs +11 -0
- package/dist/flow/theFlow/exit.d.ts +7 -0
- package/dist/flow/theFlow/exit.mjs +8 -0
- package/dist/flow/theFlow/finalizer.cjs +11 -0
- package/dist/flow/theFlow/finalizer.d.ts +5 -0
- package/dist/flow/theFlow/finalizer.mjs +8 -0
- package/dist/flow/theFlow/index.cjs +14 -0
- package/dist/flow/theFlow/index.d.ts +85 -0
- package/dist/flow/theFlow/index.mjs +11 -0
- package/dist/flow/theFlow/injection.cjs +11 -0
- package/dist/flow/theFlow/injection.d.ts +10 -0
- package/dist/flow/theFlow/injection.mjs +8 -0
- package/dist/flow/theFlow/step.cjs +11 -0
- package/dist/flow/theFlow/step.d.ts +5 -0
- package/dist/flow/theFlow/step.mjs +8 -0
- package/dist/flow/types/index.d.ts +1 -0
- package/dist/index.cjs +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +3 -0
- package/dist/metadata.json +189 -0
- package/dist/object/types/requireAtLeastOne.d.ts +2 -1
- package/package.json +6 -1
package/dist/clean/flag.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export interface FlagHandler<GenericEntity extends Entity = Entity, GenericName
|
|
|
31
31
|
*
|
|
32
32
|
*/
|
|
33
33
|
getValue<GenericInputEntity extends GenericEntity & Flag<GenericName, GenericValue>>(entity: GenericInputEntity): GetKindValue<typeof flagKind, GenericInputEntity>[GenericName];
|
|
34
|
-
has<GenericInputEntity extends GenericEntity>(entity: GenericInputEntity): Extract<GenericInputEntity, Flag<GenericName, any>>;
|
|
34
|
+
has<GenericInputEntity extends GenericEntity>(entity: GenericInputEntity): entity is Extract<GenericInputEntity, Flag<GenericName, any>>;
|
|
35
35
|
}
|
|
36
36
|
export interface Flag<GenericName extends string = string, GenericValue extends unknown = never> extends Kind<typeof flagKind.definition, Record<GenericName, GenericValue>> {
|
|
37
37
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Unwrap } from "../../../common";
|
|
2
2
|
import { type Primitive, type Primitives } from "../base";
|
|
3
3
|
/**
|
|
4
4
|
* Compares two wrapped primitives (or a primitive and a raw value) with a type guard.
|
|
@@ -34,5 +34,5 @@ import { type Primitive, type Primitives } from "../base";
|
|
|
34
34
|
* @namespace C
|
|
35
35
|
*
|
|
36
36
|
*/
|
|
37
|
-
export declare function equal<GenericInput extends Primitives, GenericValue extends (Primitive<
|
|
38
|
-
export declare function equal<GenericInput extends Primitives, GenericValue extends (Primitive<
|
|
37
|
+
export declare function equal<GenericInput extends Primitives, GenericValue extends (Primitive<Unwrap<GenericInput>> | Unwrap<GenericInput>)>(value: GenericValue): (input: GenericInput) => input is GenericInput & Primitive<Unwrap<GenericValue>>;
|
|
38
|
+
export declare function equal<GenericInput extends Primitives, GenericValue extends (Primitive<Unwrap<GenericInput>> | Unwrap<GenericInput>)>(input: GenericInput, value: GenericValue): input is GenericInput & Primitive<Unwrap<GenericValue>>;
|
package/dist/common/kind.cjs
CHANGED
package/dist/common/kind.d.ts
CHANGED
|
@@ -94,6 +94,7 @@ export interface ReservedKindNamespace {
|
|
|
94
94
|
DuplojsUtilsError: true;
|
|
95
95
|
DuplojsUtilsClean: true;
|
|
96
96
|
DuplojsUtilsDate: true;
|
|
97
|
+
DuplojsUtilsFlow: true;
|
|
97
98
|
}
|
|
98
99
|
type ForbiddenKindNamespace<GenericValue extends string> = (ForbiddenKindCharacters<GenericValue> & ForbiddenString<GenericValue, GetPropsWithValue<ReservedKindNamespace, true>>);
|
|
99
100
|
/**
|
package/dist/common/kind.mjs
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _break = require('./theFlow/break.cjs');
|
|
4
|
+
|
|
5
|
+
function* breakIf(value, thePredicate) {
|
|
6
|
+
if (thePredicate(value) === true) {
|
|
7
|
+
yield _break.createBreak(value);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.breakIf = breakIf;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type NeverCoalescing } from "../common";
|
|
2
|
+
import { type Break } from "./theFlow";
|
|
3
|
+
/**
|
|
4
|
+
* Breaks a flow when a predicate matches a value.
|
|
5
|
+
*
|
|
6
|
+
* **Supported call styles:**
|
|
7
|
+
* - Classic boolean predicate: `breakIf(value, thePredicate)` -> yields a break effect or returns the value
|
|
8
|
+
* - Classic predicate overload: `breakIf(value, thePredicate)` -> narrows the matched value type before breaking
|
|
9
|
+
*
|
|
10
|
+
* `breakIf` is designed to be used inside `F.run(...)` or a nested flow executed by `F.exec(...)`.
|
|
11
|
+
* When the predicate returns `true`, the current flow stops with the provided value as a break result.
|
|
12
|
+
* When the predicate returns `false`, the original value is returned and the flow continues normally.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* F.run(
|
|
16
|
+
* function *() {
|
|
17
|
+
* yield *F.breakIf(2, (value) => value === 2);
|
|
18
|
+
*
|
|
19
|
+
* return "test";
|
|
20
|
+
* },
|
|
21
|
+
* ); // 2
|
|
22
|
+
*
|
|
23
|
+
* F.run(
|
|
24
|
+
* function *() {
|
|
25
|
+
* const value = yield *F.breakIf("keep", (value) => value === "stop");
|
|
26
|
+
* return value;
|
|
27
|
+
* },
|
|
28
|
+
* ); // "keep"
|
|
29
|
+
*
|
|
30
|
+
* F.run(
|
|
31
|
+
* function *() {
|
|
32
|
+
* yield *F.step("before break");
|
|
33
|
+
* yield *F.breakIf(2, (value) => value === 2);
|
|
34
|
+
* return "done";
|
|
35
|
+
* },
|
|
36
|
+
* { includeDetails: true },
|
|
37
|
+
* ); // { result: 2, steps: ["before break"] }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* - Use `breakIf` to stop the current flow without exiting outer flows
|
|
42
|
+
*
|
|
43
|
+
* @see [`F.exitIf`](https://utils.duplojs.dev/en/v1/api/flow/exitIf) To exit a flow instead of breaking it
|
|
44
|
+
* @see https://utils.duplojs.dev/en/v1/api/flow/breakIf
|
|
45
|
+
*
|
|
46
|
+
* @namespace F
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
export declare function breakIf<GenericValue extends unknown, GenericPredicate extends GenericValue>(value: GenericValue, thePredicate: (value: GenericValue) => value is GenericPredicate): Generator<Break<NeverCoalescing<Extract<GenericValue, GenericPredicate>, GenericPredicate>>, Exclude<GenericValue, GenericPredicate>>;
|
|
50
|
+
export declare function breakIf<GenericValue extends unknown>(value: GenericValue, thePredicate: (value: GenericValue) => boolean): Generator<Break<GenericValue>, GenericValue>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type Defer } from "./theFlow";
|
|
2
|
+
/**
|
|
3
|
+
* Registers a cleanup callback that runs when the flow finishes.
|
|
4
|
+
*
|
|
5
|
+
* **Supported call styles:**
|
|
6
|
+
* - Classic: `defer(theFunction)` -> yields a defer effect
|
|
7
|
+
*
|
|
8
|
+
* `defer` stores a callback that is executed after the flow has completed.
|
|
9
|
+
* It is useful for releasing resources, closing handles, or running cleanup logic after a `break` or a normal return.
|
|
10
|
+
* Use it inside `F.run(...)` or inside subflows executed by `F.exec(...)`.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* F.run(
|
|
14
|
+
* function *() {
|
|
15
|
+
* yield *F.defer(() => void console.log("close connection"));
|
|
16
|
+
* return "done";
|
|
17
|
+
* },
|
|
18
|
+
* ); // "done"
|
|
19
|
+
*
|
|
20
|
+
* F.run(
|
|
21
|
+
* function *() {
|
|
22
|
+
* yield *F.defer(() => void console.log("clear cache"));
|
|
23
|
+
* yield *F.breakIf(2, (value) => value === 2);
|
|
24
|
+
* return "done";
|
|
25
|
+
* },
|
|
26
|
+
* ); // 2
|
|
27
|
+
*
|
|
28
|
+
* await F.run(
|
|
29
|
+
* async function *() {
|
|
30
|
+
* yield *F.defer(async() => {
|
|
31
|
+
* await Promise.resolve();
|
|
32
|
+
* });
|
|
33
|
+
* return Promise.resolve("done");
|
|
34
|
+
* },
|
|
35
|
+
* ); // Promise<"done">
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* - Deferred callbacks run after the flow result has been computed
|
|
40
|
+
*
|
|
41
|
+
* @see [`F.finalizer`](https://utils.duplojs.dev/en/v1/api/flow/finalizer) To register final logic in the same flow system
|
|
42
|
+
* @see https://utils.duplojs.dev/en/v1/api/flow/defer
|
|
43
|
+
*
|
|
44
|
+
* @namespace F
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
export declare function defer<GenericOutput extends unknown>(theFunction: () => GenericOutput): (Generator<Defer<GenericOutput>, undefined> | (GenericOutput extends Promise<unknown> ? AsyncGenerator<Defer<GenericOutput>, undefined> : never));
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./theFlow/index.cjs');
|
|
4
|
+
var defer = require('./theFlow/defer.cjs');
|
|
5
|
+
var finalizer = require('./theFlow/finalizer.cjs');
|
|
6
|
+
var justExec = require('../common/justExec.cjs');
|
|
7
|
+
var _break = require('./theFlow/break.cjs');
|
|
8
|
+
var exit = require('./theFlow/exit.cjs');
|
|
9
|
+
var step = require('./theFlow/step.cjs');
|
|
10
|
+
var injection = require('./theFlow/injection.cjs');
|
|
11
|
+
var dependence = require('./theFlow/dependence.cjs');
|
|
12
|
+
var forward = require('../common/forward.cjs');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* {@include flow/exec/index.md}
|
|
16
|
+
*/
|
|
17
|
+
function exec(theFlow, ...[params]) {
|
|
18
|
+
let result = undefined;
|
|
19
|
+
let deferFunctions = undefined;
|
|
20
|
+
const generator = justExec.justExec(() => {
|
|
21
|
+
if (Symbol.asyncIterator in theFlow || Symbol.iterator in theFlow) {
|
|
22
|
+
return forward.forward(theFlow);
|
|
23
|
+
}
|
|
24
|
+
else if (typeof theFlow === "function") {
|
|
25
|
+
return theFlow(params?.input);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return index.theFlowKind.getValue(theFlow).run(params?.input);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
if (Symbol.asyncIterator in generator) {
|
|
32
|
+
return (async function* () {
|
|
33
|
+
try {
|
|
34
|
+
do {
|
|
35
|
+
result = await generator.next();
|
|
36
|
+
if (result.done === true) {
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
else if (_break.breakKind.has(result.value)) {
|
|
40
|
+
result = await generator.return(_break.breakKind.getValue(result.value).value);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
else if (exit.exitKind.has(result.value)) {
|
|
44
|
+
yield result.value;
|
|
45
|
+
}
|
|
46
|
+
else if (defer.deferKind.has(result.value)) {
|
|
47
|
+
deferFunctions ??= [];
|
|
48
|
+
deferFunctions.push(defer.deferKind.getValue(result.value));
|
|
49
|
+
}
|
|
50
|
+
else if (finalizer.finalizerKind.has(result.value)) {
|
|
51
|
+
yield result.value;
|
|
52
|
+
}
|
|
53
|
+
else if (step.stepKind.has(result.value)) {
|
|
54
|
+
yield result.value;
|
|
55
|
+
}
|
|
56
|
+
else if (injection.injectionKind.has(result.value)) {
|
|
57
|
+
const injectionProperties = injection.injectionKind.getValue(result.value);
|
|
58
|
+
const dependenceName = dependence.dependenceHandlerKind.getValue(injectionProperties.dependenceHandler);
|
|
59
|
+
if (!params?.dependencies
|
|
60
|
+
|| !(dependenceName in params.dependencies)) {
|
|
61
|
+
yield result.value;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} while (true);
|
|
68
|
+
return result.value;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await generator.return(undefined);
|
|
72
|
+
if (deferFunctions) {
|
|
73
|
+
await Promise.all(deferFunctions.map(justExec.justExec));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
}
|
|
78
|
+
return (function* () {
|
|
79
|
+
try {
|
|
80
|
+
do {
|
|
81
|
+
result = generator.next();
|
|
82
|
+
if (result.done === true) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
else if (_break.breakKind.has(result.value)) {
|
|
86
|
+
result = generator.return(_break.breakKind.getValue(result.value).value);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
else if (exit.exitKind.has(result.value)) {
|
|
90
|
+
yield result.value;
|
|
91
|
+
}
|
|
92
|
+
else if (defer.deferKind.has(result.value)) {
|
|
93
|
+
deferFunctions ??= [];
|
|
94
|
+
deferFunctions.push(defer.deferKind.getValue(result.value));
|
|
95
|
+
}
|
|
96
|
+
else if (finalizer.finalizerKind.has(result.value)) {
|
|
97
|
+
yield result.value;
|
|
98
|
+
}
|
|
99
|
+
else if (step.stepKind.has(result.value)) {
|
|
100
|
+
yield result.value;
|
|
101
|
+
}
|
|
102
|
+
else if (injection.injectionKind.has(result.value)) {
|
|
103
|
+
const injectionProperties = injection.injectionKind.getValue(result.value);
|
|
104
|
+
const dependenceName = dependence.dependenceHandlerKind.getValue(injectionProperties.dependenceHandler);
|
|
105
|
+
if (!params?.dependencies
|
|
106
|
+
|| !(dependenceName in params.dependencies)) {
|
|
107
|
+
yield result.value;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} while (true);
|
|
114
|
+
return result.value;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
generator.return(undefined);
|
|
118
|
+
if (deferFunctions) {
|
|
119
|
+
deferFunctions.map(justExec.justExec);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
exports.exec = exec;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { type SimplifyTopLevel, type IsEqual, type IsExtends, type Or } from "../common";
|
|
2
|
+
import { type TheFlowGenerator, type TheFlow, type TheFlowFunction, type FlowInput, type WrapFlow, type Exit, type Break, type Injection, type Step, type FlowDependencies } from "./theFlow";
|
|
3
|
+
import { type Finalizer } from "./theFlow/finalizer";
|
|
4
|
+
type ComputeExecParams<GenericInput extends unknown, GenericDependencies extends Record<string, unknown>> = SimplifyTopLevel<(Or<[
|
|
5
|
+
IsEqual<GenericInput, unknown>,
|
|
6
|
+
IsEqual<GenericInput, never>,
|
|
7
|
+
IsExtends<GenericInput, undefined>
|
|
8
|
+
]> extends true ? {
|
|
9
|
+
input?: GenericInput;
|
|
10
|
+
} : {
|
|
11
|
+
input: GenericInput;
|
|
12
|
+
}) & {
|
|
13
|
+
dependencies?: GenericDependencies;
|
|
14
|
+
}>;
|
|
15
|
+
export type ExecResult<GenericFlow extends TheFlow> = GenericFlow extends TheFlow<infer InferredFunction> ? InferredFunction extends TheFlowFunction<any, infer InferredGenerator> ? InferredGenerator extends TheFlowGenerator<infer InferredOutput, infer InferredEffect> ? [
|
|
16
|
+
((InferredEffect extends Break<infer InferredValue> ? InferredValue : never) | InferredOutput),
|
|
17
|
+
Extract<InferredEffect, Exit | Injection | Finalizer | Step>
|
|
18
|
+
] extends [
|
|
19
|
+
infer InferredOutput,
|
|
20
|
+
infer InferredEffect
|
|
21
|
+
] ? InferredGenerator extends AsyncGenerator ? AsyncGenerator<InferredEffect, InferredOutput> : Generator<InferredEffect, InferredOutput> : never : never : never : never;
|
|
22
|
+
/**
|
|
23
|
+
* Executes a nested flow inside the current flow.
|
|
24
|
+
*
|
|
25
|
+
* **Supported call styles:**
|
|
26
|
+
* - Classic with a flow function: `exec(theFlow, params?)` -> runs the provided flow function
|
|
27
|
+
* - Classic with a flow instance: `exec(theFlow, params?)` -> runs a flow created with `F.create(...)`
|
|
28
|
+
* - Classic with a generator: `exec(theGenerator, params?)` -> runs an existing generator directly
|
|
29
|
+
*
|
|
30
|
+
* `exec` lets a parent flow call another flow while staying in the same execution model.
|
|
31
|
+
* Break values are converted into the local return value of `exec`, while exit, step, injection, and finalizer effects are forwarded to the outer flow.
|
|
32
|
+
* It can be used in synchronous and asynchronous flows.
|
|
33
|
+
*
|
|
34
|
+
* ```ts
|
|
35
|
+
*
|
|
36
|
+
* const upperCaseFlow = F.create(
|
|
37
|
+
* function *(input: string) {
|
|
38
|
+
* return input.toUpperCase();
|
|
39
|
+
* },
|
|
40
|
+
* );
|
|
41
|
+
*
|
|
42
|
+
* const userFlow = F.create(
|
|
43
|
+
* function *(id: number) {
|
|
44
|
+
* return `user-${id}`;
|
|
45
|
+
* },
|
|
46
|
+
* );
|
|
47
|
+
*
|
|
48
|
+
* const breakableFlow = F.create(
|
|
49
|
+
* function *(value: number) {
|
|
50
|
+
* yield *F.breakIf(value, (current) => current === 2);
|
|
51
|
+
* return "done";
|
|
52
|
+
* },
|
|
53
|
+
* );
|
|
54
|
+
*
|
|
55
|
+
* F.run(
|
|
56
|
+
* function *() {
|
|
57
|
+
* return yield *F.exec(upperCaseFlow, { input: "hello" });
|
|
58
|
+
* },
|
|
59
|
+
* ); // "HELLO"
|
|
60
|
+
*
|
|
61
|
+
* F.run(
|
|
62
|
+
* function *() {
|
|
63
|
+
* return yield *F.exec(userFlow, { input: 42 });
|
|
64
|
+
* },
|
|
65
|
+
* ); // "user-42"
|
|
66
|
+
*
|
|
67
|
+
* F.run(
|
|
68
|
+
* function *() {
|
|
69
|
+
* return yield *F.exec(breakableFlow, { input: 2 });
|
|
70
|
+
* },
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* - `exec` is useful for composing small flows into larger ones
|
|
75
|
+
*
|
|
76
|
+
* @see [`F.run`](https://utils.duplojs.dev/en/v1/api/flow/run) To execute the root flow
|
|
77
|
+
* @see https://utils.duplojs.dev/en/v1/api/flow/exec
|
|
78
|
+
*
|
|
79
|
+
* @namespace F
|
|
80
|
+
*
|
|
81
|
+
*/
|
|
82
|
+
export declare function exec<GenericFlow extends (TheFlowFunction | TheFlow | TheFlowGenerator), GenericWrapFlow extends WrapFlow<GenericFlow>, const GenericParams extends ComputeExecParams<FlowInput<GenericWrapFlow>, FlowDependencies<GenericWrapFlow>>>(theFlow: GenericFlow, ...[params]: ({} extends GenericParams ? [params?: GenericParams] : [params: GenericParams])): ExecResult<WrapFlow<GenericFlow>>;
|
|
83
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { theFlowKind } from './theFlow/index.mjs';
|
|
2
|
+
import { deferKind } from './theFlow/defer.mjs';
|
|
3
|
+
import { finalizerKind } from './theFlow/finalizer.mjs';
|
|
4
|
+
import { justExec } from '../common/justExec.mjs';
|
|
5
|
+
import { breakKind } from './theFlow/break.mjs';
|
|
6
|
+
import { exitKind } from './theFlow/exit.mjs';
|
|
7
|
+
import { stepKind } from './theFlow/step.mjs';
|
|
8
|
+
import { injectionKind } from './theFlow/injection.mjs';
|
|
9
|
+
import { dependenceHandlerKind } from './theFlow/dependence.mjs';
|
|
10
|
+
import { forward } from '../common/forward.mjs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* {@include flow/exec/index.md}
|
|
14
|
+
*/
|
|
15
|
+
function exec(theFlow, ...[params]) {
|
|
16
|
+
let result = undefined;
|
|
17
|
+
let deferFunctions = undefined;
|
|
18
|
+
const generator = justExec(() => {
|
|
19
|
+
if (Symbol.asyncIterator in theFlow || Symbol.iterator in theFlow) {
|
|
20
|
+
return forward(theFlow);
|
|
21
|
+
}
|
|
22
|
+
else if (typeof theFlow === "function") {
|
|
23
|
+
return theFlow(params?.input);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return theFlowKind.getValue(theFlow).run(params?.input);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (Symbol.asyncIterator in generator) {
|
|
30
|
+
return (async function* () {
|
|
31
|
+
try {
|
|
32
|
+
do {
|
|
33
|
+
result = await generator.next();
|
|
34
|
+
if (result.done === true) {
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
else if (breakKind.has(result.value)) {
|
|
38
|
+
result = await generator.return(breakKind.getValue(result.value).value);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
else if (exitKind.has(result.value)) {
|
|
42
|
+
yield result.value;
|
|
43
|
+
}
|
|
44
|
+
else if (deferKind.has(result.value)) {
|
|
45
|
+
deferFunctions ??= [];
|
|
46
|
+
deferFunctions.push(deferKind.getValue(result.value));
|
|
47
|
+
}
|
|
48
|
+
else if (finalizerKind.has(result.value)) {
|
|
49
|
+
yield result.value;
|
|
50
|
+
}
|
|
51
|
+
else if (stepKind.has(result.value)) {
|
|
52
|
+
yield result.value;
|
|
53
|
+
}
|
|
54
|
+
else if (injectionKind.has(result.value)) {
|
|
55
|
+
const injectionProperties = injectionKind.getValue(result.value);
|
|
56
|
+
const dependenceName = dependenceHandlerKind.getValue(injectionProperties.dependenceHandler);
|
|
57
|
+
if (!params?.dependencies
|
|
58
|
+
|| !(dependenceName in params.dependencies)) {
|
|
59
|
+
yield result.value;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} while (true);
|
|
66
|
+
return result.value;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await generator.return(undefined);
|
|
70
|
+
if (deferFunctions) {
|
|
71
|
+
await Promise.all(deferFunctions.map(justExec));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
})();
|
|
75
|
+
}
|
|
76
|
+
return (function* () {
|
|
77
|
+
try {
|
|
78
|
+
do {
|
|
79
|
+
result = generator.next();
|
|
80
|
+
if (result.done === true) {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
else if (breakKind.has(result.value)) {
|
|
84
|
+
result = generator.return(breakKind.getValue(result.value).value);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
else if (exitKind.has(result.value)) {
|
|
88
|
+
yield result.value;
|
|
89
|
+
}
|
|
90
|
+
else if (deferKind.has(result.value)) {
|
|
91
|
+
deferFunctions ??= [];
|
|
92
|
+
deferFunctions.push(deferKind.getValue(result.value));
|
|
93
|
+
}
|
|
94
|
+
else if (finalizerKind.has(result.value)) {
|
|
95
|
+
yield result.value;
|
|
96
|
+
}
|
|
97
|
+
else if (stepKind.has(result.value)) {
|
|
98
|
+
yield result.value;
|
|
99
|
+
}
|
|
100
|
+
else if (injectionKind.has(result.value)) {
|
|
101
|
+
const injectionProperties = injectionKind.getValue(result.value);
|
|
102
|
+
const dependenceName = dependenceHandlerKind.getValue(injectionProperties.dependenceHandler);
|
|
103
|
+
if (!params?.dependencies
|
|
104
|
+
|| !(dependenceName in params.dependencies)) {
|
|
105
|
+
yield result.value;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} while (true);
|
|
112
|
+
return result.value;
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
generator.return(undefined);
|
|
116
|
+
if (deferFunctions) {
|
|
117
|
+
deferFunctions.map(justExec);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
})();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { exec };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type NeverCoalescing } from "../common";
|
|
2
|
+
import { type Exit } from "./theFlow";
|
|
3
|
+
/**
|
|
4
|
+
* Exits a flow when a predicate matches a value.
|
|
5
|
+
*
|
|
6
|
+
* **Supported call styles:**
|
|
7
|
+
* - Classic boolean predicate: `exitIf(value, thePredicate)` -> yields an exit effect or returns the value
|
|
8
|
+
* - Classic predicate overload: `exitIf(value, thePredicate)` -> narrows the matched value type before exiting
|
|
9
|
+
*
|
|
10
|
+
* `exitIf` is designed to be used inside `F.run(...)` or a nested flow executed by `F.exec(...)`.
|
|
11
|
+
* When the predicate returns `true`, the current flow exits with the provided value.
|
|
12
|
+
* When the predicate returns `false`, the original value is returned and the flow continues normally.
|
|
13
|
+
* Because the exit effect is forwarded through nested `exec(...)` calls, it can stop a deeply nested flow from any depth.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const thirdLevelFlow = F.create(
|
|
17
|
+
* function *() {
|
|
18
|
+
* yield *F.exitIf("stop", (value) => value === "stop");
|
|
19
|
+
* return "done";
|
|
20
|
+
* },
|
|
21
|
+
* );
|
|
22
|
+
*
|
|
23
|
+
* const secondLevelFlow = F.create(
|
|
24
|
+
* function *() {
|
|
25
|
+
* return yield *F.exec(thirdLevelFlow);
|
|
26
|
+
* },
|
|
27
|
+
* );
|
|
28
|
+
*
|
|
29
|
+
* const firstLevelFlow = F.create(
|
|
30
|
+
* function *() {
|
|
31
|
+
* return yield *F.exec(secondLevelFlow);
|
|
32
|
+
* },
|
|
33
|
+
* );
|
|
34
|
+
*
|
|
35
|
+
* F.run(
|
|
36
|
+
* function *() {
|
|
37
|
+
* return yield *F.exitIf(2, (value) => value === 2);
|
|
38
|
+
* },
|
|
39
|
+
* ); // 2
|
|
40
|
+
*
|
|
41
|
+
* F.run(
|
|
42
|
+
* function *() {
|
|
43
|
+
* const value = yield *F.exitIf("keep", (value) => value === "stop");
|
|
44
|
+
* return value;
|
|
45
|
+
* },
|
|
46
|
+
* ); // "keep"
|
|
47
|
+
*
|
|
48
|
+
* F.run(
|
|
49
|
+
* function *() {
|
|
50
|
+
* yield *F.step("before deep exit");
|
|
51
|
+
* return yield *F.exec(firstLevelFlow);
|
|
52
|
+
* },
|
|
53
|
+
* { includeDetails: true },
|
|
54
|
+
* ); // { result: "stop", steps: ["before deep exit"] }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* - Use `exitIf` when the whole running flow should stop with a value
|
|
59
|
+
*
|
|
60
|
+
* @see [`F.breakIf`](https://utils.duplojs.dev/en/v1/api/flow/breakIf) To stop only the current local flow branch
|
|
61
|
+
* @see https://utils.duplojs.dev/en/v1/api/flow/exitIf
|
|
62
|
+
*
|
|
63
|
+
* @namespace F
|
|
64
|
+
*
|
|
65
|
+
*/
|
|
66
|
+
export declare function exitIf<GenericValue extends unknown, GenericPredicate extends GenericValue>(value: GenericValue, thePredicate: (value: GenericValue) => value is GenericPredicate): Generator<Exit<NeverCoalescing<Extract<GenericValue, GenericPredicate>, GenericPredicate>>, Exclude<GenericValue, GenericPredicate>>;
|
|
67
|
+
export declare function exitIf<GenericValue extends unknown>(value: GenericValue, thePredicate: (value: GenericValue) => boolean): Generator<Exit<GenericValue>, GenericValue>;
|