@gesslar/actioneer 0.2.1 → 0.2.3
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 +152 -0
- package/package.json +1 -1
- package/src/lib/ActionBuilder.js +26 -106
- package/src/lib/ActionHooks.js +30 -46
- package/src/lib/ActionRunner.js +1 -1
- package/src/lib/ActionWrapper.js +7 -17
- package/src/lib/Activity.js +1 -1
- package/src/lib/Piper.js +52 -99
- package/src/types/lib/ActionBuilder.d.ts +2 -42
- package/src/types/lib/ActionBuilder.d.ts.map +1 -1
- package/src/types/lib/ActionHooks.d.ts +24 -23
- package/src/types/lib/ActionHooks.d.ts.map +1 -1
- package/src/types/lib/ActionRunner.d.ts +2 -4
- package/src/types/lib/ActionRunner.d.ts.map +1 -1
- package/src/types/lib/ActionWrapper.d.ts +5 -19
- package/src/types/lib/ActionWrapper.d.ts.map +1 -1
- package/src/types/lib/Activity.d.ts +19 -54
- package/src/types/lib/Activity.d.ts.map +1 -1
- package/src/types/lib/Piper.d.ts +7 -24
- package/src/types/lib/Piper.d.ts.map +1 -1
package/src/lib/Piper.js
CHANGED
|
@@ -2,20 +2,18 @@
|
|
|
2
2
|
* Generic Pipeline - Process items through a series of steps with concurrency control
|
|
3
3
|
*
|
|
4
4
|
* This abstraction handles:
|
|
5
|
-
* - Concurrent processing with configurable limits
|
|
6
|
-
* - Pipeline of processing steps
|
|
5
|
+
* - Concurrent processing with configurable limits
|
|
6
|
+
* - Pipeline of processing steps
|
|
7
|
+
* - Result categorization (success/warning/error)
|
|
7
8
|
* - Setup/cleanup lifecycle hooks
|
|
8
9
|
* - Error handling and reporting
|
|
9
|
-
* - Dynamic worker spawning to maintain concurrency
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {Sass, Tantrum, Util} from "@gesslar/toolkit"
|
|
13
13
|
|
|
14
14
|
export default class Piper {
|
|
15
|
-
/** @type {(message: string, level?: number, ...args: Array<unknown>) => void} */
|
|
16
15
|
#debug
|
|
17
16
|
|
|
18
|
-
/** @type {Map<string, Set<unknown>>} */
|
|
19
17
|
#lifeCycle = new Map([
|
|
20
18
|
["setup", new Set()],
|
|
21
19
|
["process", new Set()],
|
|
@@ -32,19 +30,14 @@ export default class Piper {
|
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
/**
|
|
35
|
-
* Add a processing step to the pipeline
|
|
36
|
-
* Each step is executed sequentially per item.
|
|
33
|
+
* Add a processing step to the pipeline
|
|
37
34
|
*
|
|
38
35
|
* @param {(context: unknown) => Promise<unknown>|unknown} fn Function that processes an item
|
|
39
|
-
* @param {{name
|
|
36
|
+
* @param {{name?: string, required?: boolean}} [options] Step options
|
|
40
37
|
* @param {unknown} [newThis] Optional this binding
|
|
41
38
|
* @returns {Piper} The pipeline instance (for chaining)
|
|
42
|
-
* @throws {Sass} If name is not provided in options
|
|
43
39
|
*/
|
|
44
40
|
addStep(fn, options = {}, newThis) {
|
|
45
|
-
if(options.name == null)
|
|
46
|
-
throw Sass.new("Missing name for step.")
|
|
47
|
-
|
|
48
41
|
this.#lifeCycle.get("process").add({
|
|
49
42
|
fn: fn.bind(newThis ?? this),
|
|
50
43
|
name: options.name || `Step ${this.#lifeCycle.get("process").size + 1}`,
|
|
@@ -82,70 +75,33 @@ export default class Piper {
|
|
|
82
75
|
}
|
|
83
76
|
|
|
84
77
|
/**
|
|
85
|
-
* Process items through the pipeline with concurrency control
|
|
86
|
-
* Workers are spawned up to maxConcurrent limit, and as workers complete, new workers
|
|
87
|
-
* are spawned to maintain concurrency until all items are processed.
|
|
88
|
-
*
|
|
89
|
-
* This implementation uses dynamic worker spawning to maintain concurrency:
|
|
90
|
-
* - Initial workers are spawned up to maxConcurrent limit
|
|
91
|
-
* - As each worker completes (success OR failure), a replacement worker is spawned if items remain
|
|
92
|
-
* - Worker spawning occurs in finally block to ensure resilience to individual worker failures
|
|
93
|
-
* - All results are collected with {ok, value} or {ok: false, error} structure
|
|
94
|
-
* - Processing continues even if individual workers fail, collecting all errors
|
|
78
|
+
* Process items through the pipeline with concurrency control
|
|
95
79
|
*
|
|
96
80
|
* @param {Array<unknown>|unknown} items - Items to process
|
|
97
|
-
* @param {number}
|
|
98
|
-
* @returns {Promise<Array<
|
|
99
|
-
* @throws {Sass} If setup or teardown fails
|
|
81
|
+
* @param {number} maxConcurrent - Maximum concurrent items to process
|
|
82
|
+
* @returns {Promise<Array<unknown>>} - Collected results from steps
|
|
100
83
|
*/
|
|
101
84
|
async pipe(items, maxConcurrent = 10) {
|
|
102
85
|
items = Array.isArray(items)
|
|
103
86
|
? items
|
|
104
87
|
: [items]
|
|
105
88
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
let pendingCount = 0
|
|
109
|
-
let resolveAll
|
|
110
|
-
const allDone = new Promise(resolve => {
|
|
111
|
-
resolveAll = resolve
|
|
112
|
-
})
|
|
89
|
+
let itemIndex = 0
|
|
90
|
+
const allResults = []
|
|
113
91
|
|
|
114
|
-
/**
|
|
115
|
-
* Worker function that processes one item and potentially spawns a replacement.
|
|
116
|
-
* Uses shift() to atomically retrieve items from the queue, ensuring no duplicate processing.
|
|
117
|
-
* Spawns replacement workers in the finally block to guarantee resilience to errors.
|
|
118
|
-
*
|
|
119
|
-
* @private
|
|
120
|
-
*/
|
|
121
92
|
const processWorker = async() => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
const result = await this.#processWorker(item)
|
|
135
|
-
pipeResult.push({ok: true, value: result})
|
|
136
|
-
} catch(error) {
|
|
137
|
-
pipeResult.push({ok: false, error: Sass.new("Processing pipeline item.", error)})
|
|
138
|
-
} finally {
|
|
139
|
-
// Spawn a replacement worker if there are more items
|
|
140
|
-
if(items.length > 0) {
|
|
141
|
-
pendingCount++
|
|
142
|
-
processWorker() // Don't await - let it run in parallel
|
|
93
|
+
while(true) {
|
|
94
|
+
const currentIndex = itemIndex++
|
|
95
|
+
if(currentIndex >= items.length)
|
|
96
|
+
break
|
|
97
|
+
|
|
98
|
+
const item = items[currentIndex]
|
|
99
|
+
try {
|
|
100
|
+
const result = await this.#processItem(item)
|
|
101
|
+
allResults.push(result)
|
|
102
|
+
} catch(error) {
|
|
103
|
+
throw Sass.new("Processing pipeline item.", error)
|
|
143
104
|
}
|
|
144
|
-
|
|
145
|
-
if(--pendingCount === 0)
|
|
146
|
-
resolveAll()
|
|
147
|
-
|
|
148
|
-
this.#debug("pendingCount = %o", 2, pendingCount)
|
|
149
105
|
}
|
|
150
106
|
}
|
|
151
107
|
|
|
@@ -156,19 +112,15 @@ export default class Piper {
|
|
|
156
112
|
|
|
157
113
|
try {
|
|
158
114
|
// Start workers up to maxConcurrent limit
|
|
115
|
+
const workers = []
|
|
159
116
|
const workerCount = Math.min(maxConcurrent, items.length)
|
|
160
|
-
pendingCount = workerCount
|
|
161
117
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
} else {
|
|
165
|
-
for(let i = 0; i < workerCount; i++) {
|
|
166
|
-
processWorker() // Don't await - let them all run in parallel
|
|
167
|
-
}
|
|
168
|
-
}
|
|
118
|
+
for(let i = 0; i < workerCount; i++)
|
|
119
|
+
workers.push(processWorker())
|
|
169
120
|
|
|
170
121
|
// Wait for all workers to complete
|
|
171
|
-
await
|
|
122
|
+
const processResult = await Util.settleAll(workers)
|
|
123
|
+
this.#processResult("Processing pipeline.", processResult)
|
|
172
124
|
} finally {
|
|
173
125
|
// Run cleanup hooks
|
|
174
126
|
const teardownResult = await Util.settleAll(
|
|
@@ -177,31 +129,7 @@ export default class Piper {
|
|
|
177
129
|
this.#processResult("Tearing down the pipeline.", teardownResult)
|
|
178
130
|
}
|
|
179
131
|
|
|
180
|
-
return
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Process a single item through all pipeline steps.
|
|
185
|
-
*
|
|
186
|
-
* @param {unknown} item The item to process
|
|
187
|
-
* @returns {Promise<unknown>} Result from the final step
|
|
188
|
-
* @private
|
|
189
|
-
*/
|
|
190
|
-
async #processWorker(item) {
|
|
191
|
-
try {
|
|
192
|
-
// Execute each step in sequence
|
|
193
|
-
let result = item
|
|
194
|
-
|
|
195
|
-
for(const step of this.#lifeCycle.get("process")) {
|
|
196
|
-
this.#debug("Executing step: %o", 4, step.name)
|
|
197
|
-
|
|
198
|
-
result = await step.fn(result) ?? result
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return result
|
|
202
|
-
} catch(error) {
|
|
203
|
-
throw Sass.new("Processing an item.", error)
|
|
204
|
-
}
|
|
132
|
+
return allResults
|
|
205
133
|
}
|
|
206
134
|
|
|
207
135
|
/**
|
|
@@ -218,4 +146,29 @@ export default class Piper {
|
|
|
218
146
|
settled.filter(r => r.status==="rejected").map(r => r.reason)
|
|
219
147
|
)
|
|
220
148
|
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Process a single item through all pipeline steps
|
|
152
|
+
*
|
|
153
|
+
* @param {unknown} item The item to process
|
|
154
|
+
* @returns {Promise<unknown>} Result from the final step
|
|
155
|
+
* @private
|
|
156
|
+
*/
|
|
157
|
+
async #processItem(item) {
|
|
158
|
+
// Execute each step in sequence
|
|
159
|
+
let result = item
|
|
160
|
+
|
|
161
|
+
for(const step of this.#lifeCycle.get("process")) {
|
|
162
|
+
this.#debug("Executing step: %o", 4, step.name)
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
result = await step.fn(result) ?? result
|
|
166
|
+
} catch(error) {
|
|
167
|
+
if(step.required)
|
|
168
|
+
throw Sass.new(`Processing required step "${step.name}".`, error)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return result
|
|
173
|
+
}
|
|
221
174
|
}
|
|
@@ -21,8 +21,6 @@
|
|
|
21
21
|
* @property {ActionFunction|import("./ActionWrapper.js").default} op Operation to execute.
|
|
22
22
|
* @property {number} [kind] Optional kind flags from {@link ActivityFlags}.
|
|
23
23
|
* @property {(context: unknown) => boolean|Promise<boolean>} [pred] Loop predicate.
|
|
24
|
-
* @property {(context: unknown) => unknown} [splitter] Function to split context for parallel execution (SPLIT activities).
|
|
25
|
-
* @property {(originalContext: unknown, splitResults: unknown) => unknown} [rejoiner] Function to rejoin split results (SPLIT activities).
|
|
26
24
|
*/
|
|
27
25
|
/**
|
|
28
26
|
* @typedef {(context: unknown) => unknown|Promise<unknown>} ActionFunction
|
|
@@ -51,16 +49,10 @@ export default class ActionBuilder {
|
|
|
51
49
|
/**
|
|
52
50
|
* Creates a new ActionBuilder instance with the provided action callback.
|
|
53
51
|
*
|
|
54
|
-
* @param {ActionBuilderAction} [action]
|
|
55
|
-
* @param {ActionBuilderConfig} [config]
|
|
52
|
+
* @param {ActionBuilderAction} [action] Base action invoked by the runner when a block satisfies the configured structure.
|
|
53
|
+
* @param {ActionBuilderConfig} [config] Options
|
|
56
54
|
*/
|
|
57
55
|
constructor(action?: ActionBuilderAction, { tag, debug }?: ActionBuilderConfig)
|
|
58
|
-
/**
|
|
59
|
-
* Get the builder's tag symbol.
|
|
60
|
-
*
|
|
61
|
-
* @returns {symbol|null} The tag symbol for this builder instance
|
|
62
|
-
*/
|
|
63
|
-
get tag(): symbol | null
|
|
64
56
|
/**
|
|
65
57
|
* Register an activity that the runner can execute.
|
|
66
58
|
*
|
|
@@ -83,16 +75,6 @@ export default class ActionBuilder {
|
|
|
83
75
|
* @returns {ActionBuilder}
|
|
84
76
|
*/
|
|
85
77
|
do(name: string | symbol, kind: number, pred: (context: unknown) => boolean | Promise<boolean>, op: ActionFunction | import('./ActionWrapper.js').default): ActionBuilder
|
|
86
|
-
/**
|
|
87
|
-
* @overload
|
|
88
|
-
* @param {string|symbol} name Activity name
|
|
89
|
-
* @param {number} kind Kind bitfield (ACTIVITY.SPLIT).
|
|
90
|
-
* @param {(context: unknown) => unknown} splitter Function to split context for parallel execution.
|
|
91
|
-
* @param {(originalContext: unknown, splitResults: unknown) => unknown} rejoiner Function to rejoin split results with original context.
|
|
92
|
-
* @param {ActionFunction|ActionBuilder} op Operation or nested ActionBuilder to execute on split context.
|
|
93
|
-
* @returns {ActionBuilder}
|
|
94
|
-
*/
|
|
95
|
-
do(name: string | symbol, kind: number, splitter: (context: unknown) => unknown, rejoiner: (originalContext: unknown, splitResults: unknown) => unknown, op: ActionFunction | ActionBuilder): ActionBuilder
|
|
96
78
|
/**
|
|
97
79
|
* Configure hooks to be loaded from a file when the action is built.
|
|
98
80
|
*
|
|
@@ -110,14 +92,6 @@ export default class ActionBuilder {
|
|
|
110
92
|
* @throws {Sass} If hooks have already been configured.
|
|
111
93
|
*/
|
|
112
94
|
withHooks(hooks: import('./ActionHooks.js').default): ActionBuilder
|
|
113
|
-
/**
|
|
114
|
-
* Configure hooks using an ActionHooks instance directly (typically used internally).
|
|
115
|
-
*
|
|
116
|
-
* @param {import("./ActionHooks.js").default} actionHooks Pre-configured ActionHooks instance.
|
|
117
|
-
* @returns {ActionBuilder} The builder instance for chaining.
|
|
118
|
-
* @throws {Sass} If hooks have already been configured.
|
|
119
|
-
*/
|
|
120
|
-
withActionHooks(actionHooks: import('./ActionHooks.js').default): ActionBuilder
|
|
121
95
|
/**
|
|
122
96
|
* Finalises the builder and returns a payload that can be consumed by the
|
|
123
97
|
* runner.
|
|
@@ -125,12 +99,6 @@ export default class ActionBuilder {
|
|
|
125
99
|
* @returns {Promise<import("./ActionWrapper.js").default>} Payload consumed by the {@link ActionRunner} constructor.
|
|
126
100
|
*/
|
|
127
101
|
build(): Promise<import('./ActionWrapper.js').default>
|
|
128
|
-
/**
|
|
129
|
-
* Check if this builder has ActionHooks configured.
|
|
130
|
-
*
|
|
131
|
-
* @returns {boolean} True if ActionHooks have been configured.
|
|
132
|
-
*/
|
|
133
|
-
get hasActionHooks(): boolean
|
|
134
102
|
#private
|
|
135
103
|
}
|
|
136
104
|
export type ActionRunner = import('./ActionRunner.js').default
|
|
@@ -181,14 +149,6 @@ export type ActivityDefinition = {
|
|
|
181
149
|
* Loop predicate.
|
|
182
150
|
*/
|
|
183
151
|
pred?: ((context: unknown) => boolean | Promise<boolean>) | undefined;
|
|
184
|
-
/**
|
|
185
|
-
* Function to split context for parallel execution (SPLIT activities).
|
|
186
|
-
*/
|
|
187
|
-
splitter?: ((context: unknown) => unknown) | undefined;
|
|
188
|
-
/**
|
|
189
|
-
* Function to rejoin split results (SPLIT activities).
|
|
190
|
-
*/
|
|
191
|
-
rejoiner?: ((originalContext: unknown, splitResults: unknown) => unknown) | undefined;
|
|
192
152
|
}
|
|
193
153
|
export type ActionFunction = (context: unknown) => unknown | Promise<unknown>
|
|
194
154
|
//# sourceMappingURL=ActionBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../lib/ActionBuilder.js"],"names":[],"mappings":"AAKA,kEAAkE;AAClE,uEAAuE;AAEvE;;GAEG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH
|
|
1
|
+
{"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../lib/ActionBuilder.js"],"names":[],"mappings":"AAKA,kEAAkE;AAClE,uEAAuE;AAEvE;;GAEG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAaE;;;;;OAKG;IACH,qBAHW,mBAAmB,mBACnB,mBAAmB,EAe7B;;;;;;;;;;;;;IASE,SACQ,MAAM,GAAC,MAAM,MACb,cAAc,GACZ,aAAa,CACzB;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,QACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,MAC9C,cAAc,GAAC,OAAO,oBAAoB,EAAE,OAAO,GACjD,aAAa,CACzB;IA4CD;;;;;;;OAOG;IACH,yBALW,MAAM,aACN,MAAM,GACJ,aAAa,CAYzB;IAED;;;;;;OAMG;IACH,iBAJW,OAAO,kBAAkB,EAAE,OAAO,GAChC,aAAa,CAWzB;IAeD;;;;;OAKG;IACH,SAFa,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAmBzD;;CAeF;2BA9Oa,OAAO,mBAAmB,EAAE,OAAO;4BACnC,cAAc,eAAe,EAAE,QAAQ;sBAGxC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;WAKjE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;YAYhC,mBAAmB,GAAC,IAAI;;;;WACxB,OAAO,GAAC,IAAI;;;;UACZ,MAAM,GAAC,MAAM;;;;QACb,cAAc,GAAC,OAAO,oBAAoB,EAAE,OAAO;;;;;;;;sBAEzC,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;;6BAI/C,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC"}
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* @typedef {object} ActionHooksConfig
|
|
6
|
-
* @property {string}
|
|
7
|
-
* @property {FileObject
|
|
8
|
-
* @property {unknown} [
|
|
6
|
+
* @property {string} actionKind Action identifier shared between runner and hooks.
|
|
7
|
+
* @property {FileObject} hooksFile File handle used to import the hooks module.
|
|
8
|
+
* @property {unknown} [hooks] Already-instantiated hooks implementation (skips loading).
|
|
9
9
|
* @property {number} [hookTimeout] Timeout applied to hook execution in milliseconds.
|
|
10
|
+
* @property {DebugFn} debug Logger to emit diagnostics.
|
|
10
11
|
*/
|
|
11
12
|
/**
|
|
12
13
|
* @typedef {Record<string, (context: unknown) => Promise<unknown>|unknown>} HookModule
|
|
@@ -20,38 +21,37 @@ export default class ActionHooks {
|
|
|
20
21
|
/**
|
|
21
22
|
* Static factory method to create and initialize a hook manager.
|
|
22
23
|
* Loads hooks from the specified file and returns an initialized instance.
|
|
23
|
-
*
|
|
24
|
+
* Override loadHooks() in subclasses to customize hook loading logic.
|
|
24
25
|
*
|
|
25
|
-
* @param {ActionHooksConfig} config
|
|
26
|
+
* @param {ActionHooksConfig} config Same configuration object as constructor
|
|
26
27
|
* @param {DebugFn} debug The debug function.
|
|
27
|
-
* @returns {Promise<ActionHooks>} Initialized hook manager
|
|
28
|
+
* @returns {Promise<ActionHooks|null>} Initialized hook manager or null if no hooks found
|
|
28
29
|
*/
|
|
29
|
-
static 'new'(config: ActionHooksConfig, debug: DebugFn): Promise<ActionHooks>
|
|
30
|
+
static 'new'(config: ActionHooksConfig, debug: DebugFn): Promise<ActionHooks | null>
|
|
30
31
|
/**
|
|
31
32
|
* Creates a new ActionHook instance.
|
|
32
33
|
*
|
|
33
34
|
* @param {ActionHooksConfig} config Configuration values describing how to load the hooks.
|
|
34
|
-
* @param {(message: string, level?: number, ...args: Array<unknown>) => void} debug Debug function
|
|
35
35
|
*/
|
|
36
|
-
constructor({ actionKind, hooksFile,
|
|
36
|
+
constructor({ actionKind, hooksFile, hooks, hookTimeout, debug }: ActionHooksConfig)
|
|
37
37
|
/**
|
|
38
38
|
* Gets the action identifier.
|
|
39
39
|
*
|
|
40
|
-
* @returns {string
|
|
40
|
+
* @returns {string} Action identifier or instance
|
|
41
41
|
*/
|
|
42
|
-
get actionKind(): string
|
|
42
|
+
get actionKind(): string
|
|
43
43
|
/**
|
|
44
44
|
* Gets the hooks file object.
|
|
45
45
|
*
|
|
46
|
-
* @returns {FileObject
|
|
46
|
+
* @returns {FileObject} File object containing hooks
|
|
47
47
|
*/
|
|
48
|
-
get hooksFile(): FileObject
|
|
48
|
+
get hooksFile(): FileObject
|
|
49
49
|
/**
|
|
50
50
|
* Gets the loaded hooks object.
|
|
51
51
|
*
|
|
52
|
-
* @returns {
|
|
52
|
+
* @returns {object|null} Hooks object or null if not loaded
|
|
53
53
|
*/
|
|
54
|
-
get hooks():
|
|
54
|
+
get hooks(): object | null
|
|
55
55
|
/**
|
|
56
56
|
* Gets the hook execution timeout in milliseconds.
|
|
57
57
|
*
|
|
@@ -71,15 +71,12 @@ export default class ActionHooks {
|
|
|
71
71
|
*/
|
|
72
72
|
get cleanup(): (args: object) => unknown | null
|
|
73
73
|
/**
|
|
74
|
-
* Invoke a dynamically-named hook such as `before$foo
|
|
75
|
-
* The hook name is constructed by combining the kind with the activity name.
|
|
76
|
-
* Symbols are converted to their description. Non-alphanumeric characters are filtered out.
|
|
74
|
+
* Invoke a dynamically-named hook such as `before$foo`.
|
|
77
75
|
*
|
|
78
76
|
* @param {'before'|'after'|'setup'|'cleanup'|string} kind Hook namespace.
|
|
79
77
|
* @param {string|symbol} activityName Activity identifier.
|
|
80
78
|
* @param {unknown} context Pipeline context supplied to the hook.
|
|
81
79
|
* @returns {Promise<void>}
|
|
82
|
-
* @throws {Sass} If the hook execution fails or exceeds timeout.
|
|
83
80
|
*/
|
|
84
81
|
callHook(kind: 'before' | 'after' | 'setup' | 'cleanup' | string, activityName: string | symbol, context: unknown): Promise<void>
|
|
85
82
|
#private
|
|
@@ -89,19 +86,23 @@ export type ActionHooksConfig = {
|
|
|
89
86
|
/**
|
|
90
87
|
* Action identifier shared between runner and hooks.
|
|
91
88
|
*/
|
|
92
|
-
actionKind
|
|
89
|
+
actionKind: string;
|
|
93
90
|
/**
|
|
94
|
-
* File handle
|
|
91
|
+
* File handle used to import the hooks module.
|
|
95
92
|
*/
|
|
96
|
-
hooksFile
|
|
93
|
+
hooksFile: FileObject;
|
|
97
94
|
/**
|
|
98
95
|
* Already-instantiated hooks implementation (skips loading).
|
|
99
96
|
*/
|
|
100
|
-
|
|
97
|
+
hooks?: unknown;
|
|
101
98
|
/**
|
|
102
99
|
* Timeout applied to hook execution in milliseconds.
|
|
103
100
|
*/
|
|
104
101
|
hookTimeout?: number | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Logger to emit diagnostics.
|
|
104
|
+
*/
|
|
105
|
+
debug: DebugFn;
|
|
105
106
|
}
|
|
106
107
|
export type HookModule = Record<string, (context: unknown) => Promise<unknown> | unknown>
|
|
107
108
|
import { FileObject } from '@gesslar/toolkit'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionHooks.d.ts","sourceRoot":"","sources":["../../lib/ActionHooks.js"],"names":[],"mappings":"AAGA;;GAEG;AAEH
|
|
1
|
+
{"version":3,"file":"ActionHooks.d.ts","sourceRoot":"","sources":["../../lib/ActionHooks.js"],"names":[],"mappings":"AAGA;;GAEG;AAEH;;;;;;;GAOG;AAEH;;GAEG;AAEH;;;;GAIG;AACH;IA+EE;;;;;;;;OAQG;IACH,qBAJW,iBAAiB,SACjB,OAAO,GACL,OAAO,CAAC,WAAW,GAAC,IAAI,CAAC,CA2CrC;IArHD;;;;OAIG;IACH,kEAFW,iBAAiB,EAQ3B;IAED;;;;OAIG;IACH,kBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,iBAFa,UAAU,CAItB;IAED;;;;OAIG;IACH,aAFa,MAAM,GAAC,IAAI,CAIvB;IAED;;;;OAIG;IACH,eAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,aAFa,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAC,IAAI,CAI1C;IAED;;;;OAIG;IACH,eAFa,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAC,IAAI,CAI1C;IAsDD;;;;;;;OAOG;IACH,eALW,QAAQ,GAAC,OAAO,GAAC,OAAO,GAAC,SAAS,GAAC,MAAM,gBACzC,MAAM,GAAC,MAAM,WACb,OAAO,GACL,OAAO,CAAC,IAAI,CAAC,CAwDzB;;CAmBF;sBAzOY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;gBAKjE,MAAM;;;;eACN,UAAU;;;;YACV,OAAO;;;;;;;;WAEP,OAAO;;yBAIR,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,CAAC;2BAhBzB,kBAAkB"}
|
|
@@ -22,12 +22,10 @@ export default class ActionRunner extends Piper {
|
|
|
22
22
|
constructor(actionBuilder: import('./ActionBuilder.js').default | null, { debug }?: ActionRunnerOptions)
|
|
23
23
|
/**
|
|
24
24
|
* Executes the configured action pipeline.
|
|
25
|
-
* Builds the ActionWrapper on first run and caches it for subsequent calls.
|
|
26
|
-
* Supports WHILE, UNTIL, and SPLIT activity kinds.
|
|
27
25
|
*
|
|
28
26
|
* @param {unknown} context - Seed value passed to the first activity.
|
|
29
|
-
* @returns {Promise<unknown>} Final value produced by the pipeline.
|
|
30
|
-
* @throws {Sass} When no activities are registered
|
|
27
|
+
* @returns {Promise<unknown>} Final value produced by the pipeline, or null when a parallel stage reports failures.
|
|
28
|
+
* @throws {Sass} When no activities are registered or required parallel builders are missing.
|
|
31
29
|
*/
|
|
32
30
|
run(context: unknown): Promise<unknown>
|
|
33
31
|
#private
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../lib/ActionRunner.js"],"names":[],"mappings":"AAMA;;GAEG;AAEH;;;GAGG;AACH;;;;;;GAMG;AACH;
|
|
1
|
+
{"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../lib/ActionRunner.js"],"names":[],"mappings":"AAMA;;GAEG;AAEH;;;GAGG;AACH;;;;;;GAMG;AACH;IAUE;;;;;OAKG;IACH,2BAHW,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,cACzC,mBAAmB,EAgB7B;IAED;;;;;;OAMG;IACH,aAJW,OAAO,GACL,OAAO,CAAC,OAAO,CAAC,CA+C5B;;CA2CF;sBA5IY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;kBAH7D,YAAY"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {object} WrappedActivityConfig
|
|
3
3
|
* @property {string|symbol} name Activity identifier used by hooks/logs.
|
|
4
|
-
* @property {(context: unknown) => unknown|Promise<unknown>|
|
|
4
|
+
* @property {(context: unknown) => unknown|Promise<unknown>|ActionWrapper} op Operation or nested wrapper to execute.
|
|
5
5
|
* @property {number} [kind] Optional loop semantic flags.
|
|
6
6
|
* @property {(context: unknown) => boolean|Promise<boolean>} [pred] Predicate tied to WHILE/UNTIL semantics.
|
|
7
|
-
* @property {(context: unknown) => unknown} [splitter] Splitter function for SPLIT activities.
|
|
8
|
-
* @property {(originalContext: unknown, splitResults: unknown) => unknown} [rejoiner] Rejoiner function for SPLIT activities.
|
|
9
7
|
* @property {unknown} [action] Parent action instance supplied when invoking the op.
|
|
10
8
|
* @property {(message: string, level?: number, ...args: Array<unknown>) => void} [debug] Optional logger reference.
|
|
11
9
|
*/
|
|
@@ -19,15 +17,11 @@ export default class ActionWrapper {
|
|
|
19
17
|
/**
|
|
20
18
|
* Create a wrapper from the builder payload.
|
|
21
19
|
*
|
|
22
|
-
* @param {
|
|
23
|
-
* @param {Map<string|symbol, WrappedActivityConfig>} config.activities Activities map
|
|
24
|
-
* @param {(message: string, level?: number, ...args: Array<unknown>) => void} config.debug Debug function
|
|
25
|
-
* @param {object} config.hooks Hooks object
|
|
20
|
+
* @param {{activities: Map<string|symbol, WrappedActivityConfig>, debug: (message: string, level?: number, ...args: Array<unknown>) => void}} init Builder payload containing activities + logger.
|
|
26
21
|
*/
|
|
27
|
-
constructor(
|
|
22
|
+
constructor({ activities, hooks, debug }: {
|
|
28
23
|
activities: Map<string | symbol, WrappedActivityConfig>;
|
|
29
24
|
debug: (message: string, level?: number, ...args: Array<unknown>) => void;
|
|
30
|
-
hooks: object;
|
|
31
25
|
})
|
|
32
26
|
/**
|
|
33
27
|
* Iterator over the registered activities.
|
|
@@ -43,9 +37,9 @@ export type WrappedActivityConfig = {
|
|
|
43
37
|
*/
|
|
44
38
|
name: string | symbol;
|
|
45
39
|
/**
|
|
46
|
-
* Operation or nested
|
|
40
|
+
* Operation or nested wrapper to execute.
|
|
47
41
|
*/
|
|
48
|
-
op: (context: unknown) => unknown | Promise<unknown> |
|
|
42
|
+
op: (context: unknown) => unknown | Promise<unknown> | ActionWrapper;
|
|
49
43
|
/**
|
|
50
44
|
* Optional loop semantic flags.
|
|
51
45
|
*/
|
|
@@ -54,14 +48,6 @@ export type WrappedActivityConfig = {
|
|
|
54
48
|
* Predicate tied to WHILE/UNTIL semantics.
|
|
55
49
|
*/
|
|
56
50
|
pred?: ((context: unknown) => boolean | Promise<boolean>) | undefined;
|
|
57
|
-
/**
|
|
58
|
-
* Splitter function for SPLIT activities.
|
|
59
|
-
*/
|
|
60
|
-
splitter?: ((context: unknown) => unknown) | undefined;
|
|
61
|
-
/**
|
|
62
|
-
* Rejoiner function for SPLIT activities.
|
|
63
|
-
*/
|
|
64
|
-
rejoiner?: ((originalContext: unknown, splitResults: unknown) => unknown) | undefined;
|
|
65
51
|
/**
|
|
66
52
|
* Parent action instance supplied when invoking the op.
|
|
67
53
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionWrapper.d.ts","sourceRoot":"","sources":["../../lib/ActionWrapper.js"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"ActionWrapper.d.ts","sourceRoot":"","sources":["../../lib/ActionWrapper.js"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;GAEG;AACH;IAgBE;;;;OAIG;IACH,0CAFW;QAAC,UAAU,EAAE,GAAG,CAAC,MAAM,GAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;KAAC,EAW5I;IAOD;;;;OAIG;IACH,kBAFa,gBAAgB,CAI5B;;CACF;;;;;UA5Da,MAAM,GAAC,MAAM;;;;QACb,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,aAAa;;;;;;;;sBAElD,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;;;;aAC9C,OAAO;;;;uBACG,MAAM,UAAU,MAAM,WAAW,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;+BAInE,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC;qBAb1B,eAAe"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Activity bit flags recognised by the builder. The flag decides
|
|
3
|
+
* loop semantics for an activity.
|
|
3
4
|
*/
|
|
4
5
|
export type ACTIVITY = number
|
|
5
6
|
/** @typedef {import("./ActionHooks.js").default} ActionHooks */
|
|
@@ -9,38 +10,24 @@ export type ACTIVITY = number
|
|
|
9
10
|
*
|
|
10
11
|
* @readonly
|
|
11
12
|
* @enum {number}
|
|
12
|
-
* @property {number} WHILE - Execute activity while predicate returns true (2)
|
|
13
|
-
* @property {number} UNTIL - Execute activity until predicate returns false (4)
|
|
14
|
-
* @property {number} SPLIT - Execute activity with split/rejoin pattern for parallel execution (8)
|
|
15
13
|
*/
|
|
16
14
|
export const ACTIVITY: Readonly<{
|
|
17
15
|
WHILE: number;
|
|
18
16
|
UNTIL: number;
|
|
19
|
-
SPLIT: number;
|
|
20
17
|
}>
|
|
21
18
|
export default class Activity {
|
|
22
19
|
/**
|
|
23
20
|
* Construct an Activity definition wrapper.
|
|
24
21
|
*
|
|
25
|
-
* @param {
|
|
26
|
-
* @param {unknown} init.action - Parent action instance
|
|
27
|
-
* @param {string|symbol} init.name - Activity identifier
|
|
28
|
-
* @param {(context: unknown) => unknown|Promise<unknown>|import("./ActionBuilder.js").default} init.op - Operation to execute
|
|
29
|
-
* @param {number} [init.kind] - Optional loop semantics flags
|
|
30
|
-
* @param {(context: unknown) => boolean|Promise<boolean>} [init.pred] - Optional predicate for WHILE/UNTIL
|
|
31
|
-
* @param {ActionHooks} [init.hooks] - Optional hooks instance
|
|
32
|
-
* @param {(context: unknown) => unknown} [init.splitter] - Optional splitter function for SPLIT activities
|
|
33
|
-
* @param {(originalContext: unknown, splitResults: unknown) => unknown} [init.rejoiner] - Optional rejoiner function for SPLIT activities
|
|
22
|
+
* @param {{action: unknown, name: string, op: (context: unknown) => unknown|Promise<unknown>|unknown, kind?: number, pred?: (context: unknown) => boolean|Promise<boolean>, hooks?: ActionHooks}} init - Initial properties describing the activity operation, loop semantics, and predicate
|
|
34
23
|
*/
|
|
35
|
-
constructor({ action, name, op, kind, pred, hooks
|
|
24
|
+
constructor({ action, name, op, kind, pred, hooks }: {
|
|
36
25
|
action: unknown;
|
|
37
|
-
name: string
|
|
38
|
-
op: (context: unknown) => unknown | Promise<unknown> |
|
|
39
|
-
kind?: number
|
|
40
|
-
pred?: (
|
|
41
|
-
hooks?:
|
|
42
|
-
splitter?: ((context: unknown) => unknown) | undefined;
|
|
43
|
-
rejoiner?: ((originalContext: unknown, splitResults: unknown) => unknown) | undefined;
|
|
26
|
+
name: string;
|
|
27
|
+
op: (context: unknown) => unknown | Promise<unknown> | unknown;
|
|
28
|
+
kind?: number;
|
|
29
|
+
pred?: (context: unknown) => boolean | Promise<boolean>;
|
|
30
|
+
hooks?: ActionHooks;
|
|
44
31
|
})
|
|
45
32
|
/**
|
|
46
33
|
* The activity name.
|
|
@@ -61,35 +48,17 @@ export default class Activity {
|
|
|
61
48
|
*/
|
|
62
49
|
get pred(): (context: unknown) => boolean | Promise<boolean> | undefined
|
|
63
50
|
/**
|
|
64
|
-
* The
|
|
65
|
-
*
|
|
66
|
-
* @returns {unknown} Current context value
|
|
67
|
-
*/
|
|
68
|
-
get context(): unknown
|
|
69
|
-
/**
|
|
70
|
-
* The operator kind name (Function or ActionBuilder).
|
|
51
|
+
* The operator kind name (Function or ActionWrapper).
|
|
71
52
|
*
|
|
72
53
|
* @returns {string} - Kind name extracted via Data.typeOf
|
|
73
54
|
*/
|
|
74
55
|
get opKind(): string
|
|
75
56
|
/**
|
|
76
|
-
* The operator to execute (function or nested
|
|
57
|
+
* The operator to execute (function or nested wrapper).
|
|
77
58
|
*
|
|
78
|
-
* @returns {
|
|
59
|
+
* @returns {unknown} - Activity operation
|
|
79
60
|
*/
|
|
80
|
-
get op():
|
|
81
|
-
/**
|
|
82
|
-
* The splitter function for SPLIT activities.
|
|
83
|
-
*
|
|
84
|
-
* @returns {((context: unknown) => unknown)|null} Splitter function or null
|
|
85
|
-
*/
|
|
86
|
-
get splitter(): ((context: unknown) => unknown) | null
|
|
87
|
-
/**
|
|
88
|
-
* The rejoiner function for SPLIT activities.
|
|
89
|
-
*
|
|
90
|
-
* @returns {((originalContext: unknown, splitResults: unknown) => unknown)|null} Rejoiner function or null
|
|
91
|
-
*/
|
|
92
|
-
get rejoiner(): ((originalContext: unknown, splitResults: unknown) => unknown) | null
|
|
61
|
+
get op(): unknown
|
|
93
62
|
/**
|
|
94
63
|
* The action instance this activity belongs to.
|
|
95
64
|
*
|
|
@@ -100,22 +69,18 @@ export default class Activity {
|
|
|
100
69
|
* Execute the activity with before/after hooks.
|
|
101
70
|
*
|
|
102
71
|
* @param {unknown} context - Mutable context flowing through the pipeline
|
|
103
|
-
* @returns {Promise<unknown>} - Activity result
|
|
72
|
+
* @returns {Promise<{activityResult: unknown}>} - Activity result wrapper with new context
|
|
104
73
|
*/
|
|
105
|
-
run(context: unknown): Promise<
|
|
74
|
+
run(context: unknown): Promise<{
|
|
75
|
+
activityResult: unknown;
|
|
76
|
+
}>
|
|
106
77
|
/**
|
|
107
78
|
* Attach hooks to this activity instance.
|
|
108
79
|
*
|
|
109
|
-
* @param {
|
|
80
|
+
* @param {unknown} hooks - Hooks instance with optional before$/after$ methods
|
|
110
81
|
* @returns {this} - This activity for chaining
|
|
111
82
|
*/
|
|
112
|
-
setActionHooks(hooks:
|
|
113
|
-
/**
|
|
114
|
-
* Get the hooks instance attached to this activity.
|
|
115
|
-
*
|
|
116
|
-
* @returns {ActionHooks|null} The hooks instance or null
|
|
117
|
-
*/
|
|
118
|
-
get hooks(): ActionHooks | null
|
|
83
|
+
setActionHooks(hooks: unknown): this
|
|
119
84
|
#private
|
|
120
85
|
}
|
|
121
86
|
export type ActionHooks = import('./ActionHooks.js').default
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Activity.d.ts","sourceRoot":"","sources":["../../lib/Activity.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Activity.d.ts","sourceRoot":"","sources":["../../lib/Activity.js"],"names":[],"mappings":";;;;uBASU,MAAM;AAPhB,gEAAgE;AAEhE;;;;;;GAMG;AACH;;;GAGE;AAEF;IAQE;;;;OAIG;IACH,qDAFW;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAC,EAShM;IAED;;;;OAIG;IACH,YAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,YAFa,MAAM,GAAC,IAAI,CAIvB;IAED;;;;OAIG;IACH,YAFa,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,SAAS,CAIpE;IAED;;;;OAIG;IACH,cAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,UAFa,OAAO,CAInB;IAED;;;;OAIG;IACH,cAFa,OAAO,CAInB;IAED;;;;;OAKG;IACH,aAHW,OAAO,GACL,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAC,CAAC,CAa9C;IAED;;;;;OAKG;IACH,sBAHW,OAAO,GACL,IAAI,CAOhB;;CACF;0BAzHa,OAAO,kBAAkB,EAAE,OAAO"}
|