@gesslar/actioneer 2.0.2 → 2.2.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.
@@ -1,4 +1,4 @@
1
- import {Promised, Data, Sass, Valid} from "@gesslar/toolkit"
1
+ import {Promised, Data, Sass, Valid, Notify} from "@gesslar/toolkit"
2
2
 
3
3
  import {ACTIVITY} from "./Activity.js"
4
4
  import Piper from "./Piper.js"
@@ -7,10 +7,15 @@ import Piper from "./Piper.js"
7
7
  * @typedef {(message: string, level?: number, ...args: Array<unknown>) => void} DebugFn
8
8
  */
9
9
 
10
+ /**
11
+ * @typedef {import("./ActionBuilder.js").default} ActionBuilder
12
+ */
13
+
10
14
  /**
11
15
  * @typedef {object} ActionRunnerOptions
12
16
  * @property {DebugFn} [debug] Logger function.
13
17
  */
18
+
14
19
  /**
15
20
  * Orchestrates execution of {@link ActionBuilder}-produced pipelines.
16
21
  *
@@ -31,6 +36,13 @@ export default class ActionRunner extends Piper {
31
36
  */
32
37
  #debug = () => {}
33
38
 
39
+ /**
40
+ * Event emitter for cross-runner communication (BREAK/CONTINUE signals).
41
+ *
42
+ * @type {typeof Notify}
43
+ */
44
+ #notify = Notify
45
+
34
46
  /**
35
47
  * Instantiate a runner over an optional action wrapper.
36
48
  *
@@ -58,108 +70,146 @@ export default class ActionRunner extends Piper {
58
70
  /**
59
71
  * Executes the configured action pipeline.
60
72
  * Builds the ActionWrapper on first run and caches it for subsequent calls.
61
- * Supports WHILE, UNTIL, and SPLIT activity kinds.
73
+ * Supports WHILE, UNTIL, IF, SPLIT, BREAK, and CONTINUE activity kinds.
62
74
  *
63
75
  * @param {unknown} context - Seed value passed to the first activity.
76
+ * @param {import("./ActionWrapper.js").default|null} [parentWrapper] - Parent wrapper for BREAK/CONTINUE signaling.
64
77
  * @returns {Promise<unknown>} Final value produced by the pipeline.
65
78
  * @throws {Sass} When no activities are registered, conflicting activity kinds are used, or execution fails.
66
79
  */
67
- async run(context) {
80
+ async run(context, parentWrapper=null) {
68
81
  if(!this.#actionWrapper)
69
82
  this.#actionWrapper = await this.#actionBuilder.build()
70
83
 
71
84
  const actionWrapper = this.#actionWrapper
72
- const activities = actionWrapper.activities
73
-
74
- for(const activity of activities) {
75
- try {
76
- // await timeout(500)
77
-
78
- const kind = activity.kind
79
-
80
- // If we have no kind, then it's just a once.
81
- // Get it over and done with!
82
- if(!kind) {
83
- context = await this.#execute(activity, context)
84
- } else {
85
- // Validate that only one activity kind bit is set
86
- // (kind & (kind - 1)) !== 0 means multiple bits are set
87
- const multipleBitsSet = (kind & (kind - 1)) !== 0
88
- if(multipleBitsSet)
89
- throw Sass.new(
90
- "For Kathy Griffin's sake! You can't combine activity kinds. " +
91
- "Pick one: WHILE, UNTIL, or SPLIT!"
92
- )
93
-
94
- const {WHILE,UNTIL,SPLIT} = ACTIVITY
95
- const kindWhile = kind & WHILE
96
- const kindUntil = kind & UNTIL
97
- const kindSplit = kind & SPLIT
98
-
99
- if(kindWhile || kindUntil) {
100
- const predicate = activity.pred
101
-
102
- for(;;) {
103
-
104
- if(kindWhile)
105
- if(!await this.#hasPredicate(activity,predicate,context))
85
+ const activities = Array.from(actionWrapper.activities)
86
+
87
+ try {
88
+ for(
89
+ let cursor = 0, max = activities.length;
90
+ cursor < max && cursor !== -1;
91
+ cursor++
92
+ ) {
93
+ const activity = activities[cursor]
94
+
95
+ try {
96
+ const kind = activity.kind
97
+
98
+ // If we have no kind, then it's just a once.
99
+ // Get it over and done with!
100
+ if(!kind) {
101
+ context = await this.#execute(activity, context)
102
+ } else {
103
+ const {UNTIL, WHILE, IF, SPLIT, BREAK, CONTINUE} = ACTIVITY
104
+ const kindUntil = kind === UNTIL
105
+ const kindWhile = kind === WHILE
106
+ const kindIf = kind === IF
107
+ const kindSplit = kind === SPLIT
108
+ const kindBreak = kind === BREAK
109
+ const kindContinue = kind === CONTINUE
110
+
111
+ if(kindBreak || kindContinue) {
112
+ if(!parentWrapper)
113
+ throw Sass.new(`Invalid use of control flow outside of context.`)
114
+
115
+ if(await this.#evalPredicate(activity, context)) {
116
+ if(kindBreak) {
117
+ this.#notify.emit("loop.break", parentWrapper)
106
118
  break
107
-
108
- context = await this.#execute(activity,context)
109
-
110
- if(kindUntil)
111
- if(await this.#hasPredicate(activity,predicate,context))
119
+ }
120
+
121
+ if(kindContinue)
122
+ cursor = max
123
+ }
124
+ } else if(kindIf) {
125
+ if(await this.#evalPredicate(activity, context))
126
+ context = await this.#execute(activity, context)
127
+ } else if(kindWhile || kindUntil) {
128
+ // Simple if, no loop, only gainz.
129
+ for(;;) {
130
+ if(kindWhile)
131
+ if(!await this.#evalPredicate(activity, context))
132
+ break
133
+
134
+ let weWereOnABreak = false
135
+ const breakReceiver = this.#notify.on("loop.break", wrapper => {
136
+ if(wrapper.id === actionWrapper.id) {
137
+ weWereOnABreak = true
138
+ }
139
+ })
140
+ context = await this.#execute(activity, context)
141
+ breakReceiver()
142
+ if(weWereOnABreak)
112
143
  break
113
- }
114
- } else if(kindSplit) {
115
- // SPLIT activity: parallel execution with splitter/rejoiner
116
- // pattern
117
- const {splitter, rejoiner} = activity
118
-
119
- if(!splitter || !rejoiner)
120
- throw Sass.new(
121
- `SPLIT activity "${String(activity.name)}" requires both ` +
122
- `splitter and rejoiner functions.`
144
+
145
+ if(kindUntil)
146
+ if(await this.#evalPredicate(activity, context))
147
+ break
148
+ }
149
+ } else if(kindSplit) {
150
+ // SPLIT activity: parallel execution with splitter/rejoiner
151
+ // pattern
152
+ const {splitter, rejoiner} = activity
153
+
154
+ if(!splitter || !rejoiner)
155
+ throw Sass.new(
156
+ `SPLIT activity "${String(activity.name)}" requires both ` +
157
+ `splitter and rejoiner functions.`
158
+ )
159
+
160
+ const original = context
161
+ const splitContexts = await splitter.call(
162
+ activity.action,
163
+ context
123
164
  )
124
165
 
125
- const original = context
126
- const splitContexts = await splitter.call(activity.action, context)
166
+ let settled
127
167
 
128
- let settled
168
+ if(activity.opKind === "ActionBuilder") {
169
+ if(activity.action)
170
+ activity.op.withAction(activity.action)
129
171
 
130
- if(activity.opKind === "ActionBuilder") {
131
- if(activity.action)
132
- activity.op.withAction(activity.action)
172
+ if(activity.hooks)
173
+ activity.op.withHooks(activity.hooks)
133
174
 
134
- if(activity.hooks)
135
- activity.op.withHooks(activity.hooks)
175
+ const runner = new this.constructor(activity.op, {
176
+ debug: this.#debug, name: activity.name
177
+ })
136
178
 
137
- const runner = new this.constructor(activity.op, {
138
- debug: this.#debug, name: activity.name
139
- })
179
+ settled = await runner.pipe(splitContexts)
180
+ } else {
181
+ // For plain functions, process each split context
182
+ settled = await Promised.settle(
183
+ splitContexts.map(ctx => this.#execute(activity, ctx))
184
+ )
185
+ }
140
186
 
141
- // pipe() returns settled results with concurrency control
142
- settled = await runner.pipe(splitContexts)
143
- } else {
144
- // For plain functions, process each split context
145
- settled = await Promised.settle(
146
- splitContexts.map(ctx => this.#execute(activity, ctx))
187
+ const rejoined = await rejoiner.call(
188
+ activity.action,
189
+ original,
190
+ settled
147
191
  )
148
- }
149
-
150
- const rejoined = await rejoiner.call(
151
- activity.action,
152
- original,
153
- settled
154
- )
155
192
 
156
- context = rejoined
157
- } else {
158
- context = await this.#execute(activity, context)
193
+ context = rejoined
194
+ } else {
195
+ context = await this.#execute(activity, context)
196
+ }
159
197
  }
198
+ } catch(error) {
199
+ throw Sass.new("ActionRunner running activity", error)
200
+ }
201
+ }
202
+ } finally {
203
+ // Execute done callback if registered - always runs, even on error
204
+ // Only run for top-level pipelines, not nested builders (inside loops)
205
+ if(actionWrapper.done && !parentWrapper) {
206
+ try {
207
+ context = await actionWrapper.done.call(
208
+ actionWrapper.action, context
209
+ )
210
+ } catch(error) {
211
+ throw Sass.new("ActionRunner running done callback", error)
160
212
  }
161
- } catch(error) {
162
- throw Sass.new("ActionRunner running activity", error)
163
213
  }
164
214
  }
165
215
 
@@ -201,11 +251,11 @@ export default class ActionRunner extends Piper {
201
251
  if(parallel) {
202
252
  return await runner.pipe(context)
203
253
  } else {
204
- return await runner.run(context)
254
+ return await runner.run(context, activity.wrapper)
205
255
  }
206
256
  } else if(opKind === "Function") {
207
257
  try {
208
- const result = await activity.run(context)
258
+ const result = await activity.run(context, activity.wrapper)
209
259
 
210
260
  if(Data.isType(result, "ActionBuilder")) {
211
261
  if(activity.action)
@@ -221,7 +271,7 @@ export default class ActionRunner extends Piper {
221
271
  if(parallel) {
222
272
  return await runner.pipe(context)
223
273
  } else {
224
- return await runner.run(context)
274
+ return await runner.run(context, activity.wrapper)
225
275
  }
226
276
  } else {
227
277
  return result
@@ -237,18 +287,17 @@ export default class ActionRunner extends Piper {
237
287
  }
238
288
 
239
289
  /**
240
- * Evaluate the predicate for WHILE/UNTIL activity kinds.
290
+ * Evaluate the predicate for WHILE/UNTIL/IF/BREAK/CONTINUE activity kinds.
241
291
  *
242
292
  * @param {import("./Activity.js").default} activity Activity currently executing.
243
- * @param {(context: unknown) => boolean|Promise<boolean>} predicate Predicate to evaluate.
244
293
  * @param {unknown} context Current pipeline context.
245
- * @returns {Promise<boolean>} True when the predicate allows another iteration.
294
+ * @returns {Promise<boolean>} True when the predicate condition is met.
246
295
  * @private
247
296
  */
248
- async #hasPredicate(activity,predicate,context) {
249
- Valid.type(predicate, "Function")
297
+ async #evalPredicate(activity, context) {
298
+ Valid.type(activity?.pred, "Function")
250
299
 
251
- return !!(await predicate.call(activity.action, context))
300
+ return !!(await activity.pred.call(activity.action, context))
252
301
  }
253
302
 
254
303
  toString() {
@@ -11,7 +11,7 @@ import Activity from "./Activity.js"
11
11
  */
12
12
 
13
13
  /**
14
- * @typedef {Generator<Activity, void, unknown>} ActivityIterator
14
+ * @typedef {import("@gesslar/toolkit").Generator<Activity, void, unknown>} ActivityIterator
15
15
  */
16
16
 
17
17
  /**
@@ -24,6 +24,7 @@ export default class ActionWrapper {
24
24
  * @type {Map<string|symbol, WrappedActivityConfig>}
25
25
  */
26
26
  #activities = new Map()
27
+
27
28
  /**
28
29
  * Logger invoked for wrapper lifecycle events.
29
30
  *
@@ -31,17 +32,37 @@ export default class ActionWrapper {
31
32
  */
32
33
  #debug = () => {}
33
34
 
35
+ /** @type {import("./ActionHooks.js").default|null} */
34
36
  #hooks = null
37
+ /** @type {((context: unknown) => unknown|Promise<unknown>)|null} */
38
+ #done = null
39
+ /** @type {unknown} */
40
+ #action = null
41
+ /** @type {symbol} */
42
+ #id = Symbol(performance.now())
35
43
 
36
44
  /**
37
45
  * Create a wrapper from the builder payload.
38
46
  *
39
47
  * @param {{activities: Map<string|symbol, WrappedActivityConfig>, debug: (message: string, level?: number, ...args: Array<unknown>) => void}} init Builder payload containing activities + logger.
40
48
  */
41
- constructor({activities,hooks,debug}) {
49
+ constructor({activities,hooks,debug,done: doneCallback,action}) {
42
50
  this.#debug = debug
43
51
  this.#hooks = hooks
44
- this.#activities = activities
52
+ this.#done = doneCallback
53
+ this.#action = action
54
+
55
+ for(const [key, value] of activities) {
56
+ this.#activities.set(
57
+ key,
58
+ new Activity({
59
+ ...value,
60
+ hooks: this.#hooks,
61
+ wrapper: this
62
+ })
63
+ )
64
+ }
65
+
45
66
  this.#debug(
46
67
  "Instantiating ActionWrapper with %o activities.",
47
68
  2,
@@ -49,17 +70,40 @@ export default class ActionWrapper {
49
70
  )
50
71
  }
51
72
 
52
- *#_activities() {
53
- for(const [,activity] of this.#activities)
54
- yield new Activity({...activity, hooks: this.#hooks})
73
+ /**
74
+ * Unique identifier for this wrapper instance.
75
+ * Used by BREAK/CONTINUE to match events to the correct loop.
76
+ *
77
+ * @returns {symbol} Unique symbol identifier
78
+ */
79
+ get id() {
80
+ return this.#id
55
81
  }
56
82
 
57
83
  /**
58
84
  * Iterator over the registered activities.
59
85
  *
60
- * @returns {ActivityIterator} Lazy iterator yielding Activity instances.
86
+ * @returns {Iterator<Activity>} Iterator yielding Activity instances.
61
87
  */
62
88
  get activities() {
63
- return this.#_activities()
89
+ return this.#activities.values()
90
+ }
91
+
92
+ /**
93
+ * Get the done callback if registered.
94
+ *
95
+ * @returns {((context: unknown) => unknown|Promise<unknown>)|null} Done callback or null.
96
+ */
97
+ get done() {
98
+ return this.#done
99
+ }
100
+
101
+ /**
102
+ * Get the action instance.
103
+ *
104
+ * @returns {unknown|null} Action instance or null.
105
+ */
106
+ get action() {
107
+ return this.#action
64
108
  }
65
109
  }
@@ -8,14 +8,20 @@ import {Data} from "@gesslar/toolkit"
8
8
  *
9
9
  * @readonly
10
10
  * @enum {number}
11
- * @property {number} WHILE - Execute activity while predicate returns true (2)
12
- * @property {number} UNTIL - Execute activity until predicate returns true (4)
13
- * @property {number} SPLIT - Execute activity with split/rejoin pattern for parallel execution (8)
11
+ * @property {number} WHILE - Execute activity while predicate returns true 1
12
+ * @property {number} UNTIL - Execute activity until predicate returns true 2
13
+ * @property {number} SPLIT - Execute activity with split/rejoin pattern for parallel execution 3
14
+ * @property {number} IF - Execute activity if predicate returns true 4
15
+ * @property {number} BREAK - Break out of a WHILE/UNTIL if predicate returns true 5
16
+ * @property {number} CONTINUE - Returns to the top of a WHILE/UNTIL if predicate returns true 6
14
17
  */
15
18
  export const ACTIVITY = Object.freeze({
16
- WHILE: 1<<1,
17
- UNTIL: 1<<2,
18
- SPLIT: 1<<3,
19
+ WHILE: 1,
20
+ UNTIL: 2,
21
+ SPLIT: 3,
22
+ IF: 4,
23
+ BREAK: 5,
24
+ CONTINUE: 6,
19
25
  })
20
26
 
21
27
  export default class Activity {
@@ -37,6 +43,10 @@ export default class Activity {
37
43
  #rejoiner = null
38
44
  /** @type {((context: unknown) => unknown)|null} */
39
45
  #splitter = null
46
+ /** @type {import("./ActionWrapper.js").default|null} */
47
+ #wrapper = null
48
+ /** @type {symbol} */
49
+ #id = Symbol(performance.now())
40
50
 
41
51
  /**
42
52
  * Construct an Activity definition wrapper.
@@ -50,8 +60,9 @@ export default class Activity {
50
60
  * @param {ActionHooks} [init.hooks] - Optional hooks instance
51
61
  * @param {(context: unknown) => unknown} [init.splitter] - Optional splitter function for SPLIT activities
52
62
  * @param {(originalContext: unknown, splitResults: unknown) => unknown} [init.rejoiner] - Optional rejoiner function for SPLIT activities
63
+ * @param {import("./ActionWrapper.js").default} [init.wrapper] - Optional wrapper containing this activity
53
64
  */
54
- constructor({action,name,op,kind,pred,hooks,splitter,rejoiner}) {
65
+ constructor({action,name,op,kind,pred,hooks,splitter,rejoiner,wrapper}) {
55
66
  this.#action = action
56
67
  this.#hooks = hooks
57
68
  this.#kind = kind
@@ -60,6 +71,16 @@ export default class Activity {
60
71
  this.#pred = pred
61
72
  this.#rejoiner = rejoiner
62
73
  this.#splitter = splitter
74
+ this.#wrapper = wrapper ?? null
75
+ }
76
+
77
+ /**
78
+ * Unique identifier for this activity instance.
79
+ *
80
+ * @returns {symbol} Unique symbol identifier
81
+ */
82
+ get id() {
83
+ return this.#id
63
84
  }
64
85
 
65
86
  /**
@@ -81,7 +102,7 @@ export default class Activity {
81
102
  }
82
103
 
83
104
  /**
84
- * The predicate function for WHILE/UNTIL flows.
105
+ * The predicate function for WHILE/UNTIL/IF flows.
85
106
  *
86
107
  * @returns {(context: unknown) => boolean|Promise<boolean>|undefined} - Predicate used to continue/stop loops
87
108
  */
@@ -143,6 +164,16 @@ export default class Activity {
143
164
  return this.#action
144
165
  }
145
166
 
167
+ /**
168
+ * Get the ActionWrapper containing this activity.
169
+ * Used by BREAK/CONTINUE to signal the parent loop.
170
+ *
171
+ * @returns {import("./ActionWrapper.js").default|null} The wrapper or null
172
+ */
173
+ get wrapper() {
174
+ return this.#wrapper ?? null
175
+ }
176
+
146
177
  /**
147
178
  * Execute the activity with before/after hooks.
148
179
  *
@@ -109,7 +109,7 @@ export default class Piper {
109
109
  }
110
110
 
111
111
  const setupResult = await Promised.settle(
112
- [...this.#lifeCycle.get("setup")].map(e => e())
112
+ [...this.#lifeCycle.get("setup")].map(e => Promise.resolve(e()))
113
113
  )
114
114
 
115
115
  this.#processResult("Setting up the pipeline.", setupResult)
@@ -127,7 +127,7 @@ export default class Piper {
127
127
  } finally {
128
128
  // Run cleanup hooks
129
129
  const teardownResult = await Promised.settle(
130
- [...this.#lifeCycle.get("teardown")].map(e => e())
130
+ [...this.#lifeCycle.get("teardown")].map(e => Promise.resolve(e()))
131
131
  )
132
132
 
133
133
  this.#processResult("Tearing down the pipeline.", teardownResult)
@@ -41,6 +41,14 @@ export default class ActionHooks extends BrowserActionHooks {
41
41
  return this.#hooksFile
42
42
  }
43
43
 
44
+ /**
45
+ * @typedef {object} ActionHooksConfig
46
+ * @property {string} [hooksFile] Path to the hooks file
47
+ * @property {string} [hooksKind] Name of the hooks class to instantiate
48
+ * @property {object} [hooks] Pre-instantiated hooks object
49
+ * @property {number} [timeout] Timeout for hook execution
50
+ */
51
+
44
52
  /**
45
53
  * Static factory method to create and initialize a hook manager.
46
54
  * Loads hooks from the specified file and returns an initialized instance.
@@ -58,9 +58,10 @@ export default class ActionBuilder {
58
58
  * Register an activity that the runner can execute.
59
59
  *
60
60
  * Overloads:
61
- * - do(name, op)
62
- * - do(name, kind, pred, opOrWrapper)
63
- * - do(name, kind, splitter, rejoiner, opOrWrapper)
61
+ * - do(name, op) - Simple once-off activity
62
+ * - do(name, kind, pred) - BREAK/CONTINUE control flow (no op, just predicate)
63
+ * - do(name, kind, pred, opOrWrapper) - WHILE/UNTIL/IF with predicate and operation
64
+ * - do(name, kind, splitter, rejoiner, opOrWrapper) - SPLIT with parallel execution
64
65
  *
65
66
  * @overload
66
67
  * @param {string|symbol} name Activity name
@@ -71,22 +72,30 @@ export default class ActionBuilder {
71
72
  /**
72
73
  * @overload
73
74
  * @param {string|symbol} name Activity name
74
- * @param {number} kind Kind bitfield from {@link ActivityFlags}.
75
+ * @param {number} kind ACTIVITY.BREAK or ACTIVITY.CONTINUE flag.
76
+ * @param {(context: unknown) => boolean|Promise<boolean>} pred Predicate to evaluate for control flow.
77
+ * @returns {ActionBuilder}
78
+ */
79
+ do(name: string | symbol, kind: number, pred: (context: unknown) => boolean | Promise<boolean>): ActionBuilder;
80
+ /**
81
+ * @overload
82
+ * @param {string|symbol} name Activity name
83
+ * @param {number} kind Activity kind (WHILE, UNTIL, or IF) from {@link ActivityFlags}.
75
84
  * @param {(context: unknown) => boolean|Promise<boolean>} pred Predicate executed before/after the op.
76
- * @param {ActionFunction|import("./ActionWrapper.js").default} op Operation or nested wrapper to execute.
85
+ * @param {ActionFunction|ActionBuilder} op Operation or nested builder to execute.
77
86
  * @returns {ActionBuilder}
78
87
  */
79
- do(name: string | symbol, kind: number, pred: (context: unknown) => boolean | Promise<boolean>, op: ActionFunction | import("./ActionWrapper.js").default): ActionBuilder;
88
+ do(name: string | symbol, kind: number, pred: (context: unknown) => boolean | Promise<boolean>, op: ActionFunction | ActionBuilder): ActionBuilder;
80
89
  /**
81
90
  * @overload
82
91
  * @param {string|symbol} name Activity name
83
92
  * @param {number} kind ACTIVITY.SPLIT flag.
84
93
  * @param {(context: unknown) => unknown} splitter Splitter function for SPLIT mode.
85
94
  * @param {(originalContext: unknown, splitResults: unknown) => unknown} rejoiner Rejoiner function for SPLIT mode.
86
- * @param {ActionFunction|import("./ActionWrapper.js").default} op Operation or nested wrapper to execute.
95
+ * @param {ActionFunction|ActionBuilder} op Operation or nested builder to execute.
87
96
  * @returns {ActionBuilder}
88
97
  */
89
- do(name: string | symbol, kind: number, splitter: (context: unknown) => unknown, rejoiner: (originalContext: unknown, splitResults: unknown) => unknown, op: ActionFunction | import("./ActionWrapper.js").default): ActionBuilder;
98
+ do(name: string | symbol, kind: number, splitter: (context: unknown) => unknown, rejoiner: (originalContext: unknown, splitResults: unknown) => unknown, op: ActionFunction | ActionBuilder): ActionBuilder;
90
99
  /**
91
100
  * Configure hooks to be loaded from a file when the action is built.
92
101
  *
@@ -112,6 +121,13 @@ export default class ActionBuilder {
112
121
  * @returns {ActionBuilder} The builder instance for chaining.
113
122
  */
114
123
  withAction(action: ActionBuilderAction): ActionBuilder;
124
+ /**
125
+ * Register a callback to be executed after all activities complete.
126
+ *
127
+ * @param {ActionFunction} callback Function to execute at the end of the pipeline.
128
+ * @returns {ActionBuilder} The builder instance for chaining.
129
+ */
130
+ done(callback: ActionFunction): ActionBuilder;
115
131
  /**
116
132
  * Finalises the builder and returns a payload that can be consumed by the
117
133
  * runner.
@@ -1 +1 @@
1
- {"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionBuilder.js"],"names":[],"mappings":"AAMA,kEAAkE;AAClE,uEAAuE;AAEvE;;GAEG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAaE;;;;;OAKG;IACH,qBAHW,mBAAmB,mBACnB,mBAAmB,EAe7B;IAED,yBAEC;;;;;;;;;;;;;;IAUE,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;;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,YACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,YAC7B,CAAC,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,KAAK,OAAO,MAC5D,cAAc,GAAC,OAAO,oBAAoB,EAAE,OAAO,GACjD,aAAa,CACzB;IA0DD;;;;;;;OAOG;IACH,yBALW,MAAM,aACN,MAAM,GACJ,aAAa,CAYzB;IAED;;;;;;OAMG;IACH,iBAJW,OAAO,kBAAkB,EAAE,OAAO,GAChC,aAAa,CAgBzB;IAED;;;;;;OAMG;IACH,mBAHW,mBAAmB,GACjB,aAAa,CAczB;IAeD;;;;;OAKG;IACH,SAFa,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAmBzD;;CAqBF;2BA3Sa,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"}
1
+ {"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionBuilder.js"],"names":[],"mappings":"AAMA,kEAAkE;AAClE,uEAAuE;AAEvE;;GAEG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAkBE;;;;;OAKG;IACH,qBAHW,mBAAmB,mBACnB,mBAAmB,EAe7B;IAED,yBAEC;;;;;;;;;;;;;;;IAWE,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,GAC5C,aAAa,CACzB;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,QACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,MAC9C,cAAc,GAAC,aAAa,GAC1B,aAAa,CACzB;;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,YACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,YAC7B,CAAC,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,KAAK,OAAO,MAC5D,cAAc,GAAC,aAAa,GAC1B,aAAa,CACzB;IAkED;;;;;;;OAOG;IACH,yBALW,MAAM,aACN,MAAM,GACJ,aAAa,CAYzB;IAED;;;;;;OAMG;IACH,iBAJW,OAAO,kBAAkB,EAAE,OAAO,GAChC,aAAa,CAgBzB;IAED;;;;;;OAMG;IACH,mBAHW,mBAAmB,GACjB,aAAa,CAczB;IAED;;;;;OAKG;IACH,eAHW,cAAc,GACZ,aAAa,CAOzB;IAeD;;;;;OAKG;IACH,SAFa,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAqBzD;;CAqBF;2BAhVa,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"}
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * @typedef {(message: string, level?: number, ...args: Array<unknown>) => void} DebugFn
3
3
  */
4
+ /**
5
+ * @typedef {import("./ActionBuilder.js").default} ActionBuilder
6
+ */
4
7
  /**
5
8
  * @typedef {object} ActionRunnerOptions
6
9
  * @property {DebugFn} [debug] Logger function.
@@ -23,16 +26,18 @@ export default class ActionRunner extends Piper {
23
26
  /**
24
27
  * Executes the configured action pipeline.
25
28
  * Builds the ActionWrapper on first run and caches it for subsequent calls.
26
- * Supports WHILE, UNTIL, and SPLIT activity kinds.
29
+ * Supports WHILE, UNTIL, IF, SPLIT, BREAK, and CONTINUE activity kinds.
27
30
  *
28
31
  * @param {unknown} context - Seed value passed to the first activity.
32
+ * @param {import("./ActionWrapper.js").default|null} [parentWrapper] - Parent wrapper for BREAK/CONTINUE signaling.
29
33
  * @returns {Promise<unknown>} Final value produced by the pipeline.
30
34
  * @throws {Sass} When no activities are registered, conflicting activity kinds are used, or execution fails.
31
35
  */
32
- run(context: unknown): Promise<unknown>;
36
+ run(context: unknown, parentWrapper?: import("./ActionWrapper.js").default | null): Promise<unknown>;
33
37
  #private;
34
38
  }
35
39
  export type DebugFn = (message: string, level?: number, ...args: Array<unknown>) => void;
40
+ export type ActionBuilder = import("./ActionBuilder.js").default;
36
41
  export type ActionRunnerOptions = {
37
42
  /**
38
43
  * Logger function.
@@ -1 +1 @@
1
- {"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionRunner.js"],"names":[],"mappings":"AAKA;;GAEG;AAEH;;;GAGG;AACH;;;;;;GAMG;AACH;IAaE;;;;;OAKG;IACH,2BAHW,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,cACzC,mBAAmB,EAkB7B;IAED;;;;;;;;OAQG;IACH,aAJW,OAAO,GACL,OAAO,CAAC,OAAO,CAAC,CAuG5B;;CA0FF;sBA1PY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;kBAH7D,YAAY"}
1
+ {"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionRunner.js"],"names":[],"mappings":"AAKA;;GAEG;AAEH;;GAEG;AAEH;;;GAGG;AAEH;;;;;;GAMG;AACH;IAoBE;;;;;OAKG;IACH,2BAHW,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,cACzC,mBAAmB,EAkB7B;IAED;;;;;;;;;OASG;IACH,aALW,OAAO,kBACP,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,GACvC,OAAO,CAAC,OAAO,CAAC,CA4I5B;;CAyFF;sBA3SY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;4BAIlE,OAAO,oBAAoB,EAAE,OAAO;;;;;;;kBAP/B,YAAY"}