@blokjs/runner 0.4.0 → 0.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/Blok.js +32 -3
- package/dist/Blok.js.map +1 -1
- package/dist/Configuration.d.ts +41 -5
- package/dist/Configuration.js +215 -92
- package/dist/Configuration.js.map +1 -1
- package/dist/ForEachNode.d.ts +59 -0
- package/dist/ForEachNode.js +522 -0
- package/dist/ForEachNode.js.map +1 -0
- package/dist/LoopMaxIterationsError.d.ts +11 -0
- package/dist/LoopMaxIterationsError.js +18 -0
- package/dist/LoopMaxIterationsError.js.map +1 -0
- package/dist/LoopNode.d.ts +36 -0
- package/dist/LoopNode.js +182 -0
- package/dist/LoopNode.js.map +1 -0
- package/dist/Runner.d.ts +11 -1
- package/dist/Runner.js +9 -2
- package/dist/Runner.js.map +1 -1
- package/dist/RunnerSteps.js +419 -112
- package/dist/RunnerSteps.js.map +1 -1
- package/dist/RuntimeAdapterNode.d.ts +2 -1
- package/dist/RuntimeAdapterNode.js +2 -2
- package/dist/RuntimeAdapterNode.js.map +1 -1
- package/dist/RuntimeRegistry.d.ts +23 -2
- package/dist/RuntimeRegistry.js +31 -2
- package/dist/RuntimeRegistry.js.map +1 -1
- package/dist/SubworkflowNode.d.ts +106 -0
- package/dist/SubworkflowNode.js +261 -3
- package/dist/SubworkflowNode.js.map +1 -1
- package/dist/SwitchNode.d.ts +37 -0
- package/dist/SwitchNode.js +153 -0
- package/dist/SwitchNode.js.map +1 -0
- package/dist/TriggerBase.d.ts +50 -0
- package/dist/TriggerBase.js +262 -4
- package/dist/TriggerBase.js.map +1 -1
- package/dist/TryCatchNode.d.ts +32 -0
- package/dist/TryCatchNode.js +207 -0
- package/dist/TryCatchNode.js.map +1 -0
- package/dist/adapters/grpc/GrpcCodec.js +2 -2
- package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +6 -4
- package/dist/adapters/grpc/GrpcRuntimeAdapter.js +6 -4
- package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -1
- package/dist/adapters/grpc/types.d.ts +7 -5
- package/dist/adapters/grpc/types.js.map +1 -1
- package/dist/adapters/transport.d.ts +12 -41
- package/dist/adapters/transport.js +21 -70
- package/dist/adapters/transport.js.map +1 -1
- package/dist/cache/NodeResultCache.js +7 -0
- package/dist/cache/NodeResultCache.js.map +1 -1
- package/dist/concurrency/NatsKvConcurrencyBackend.js +18 -5
- package/dist/concurrency/NatsKvConcurrencyBackend.js.map +1 -1
- package/dist/concurrency/RedisConcurrencyBackend.d.ts +64 -0
- package/dist/concurrency/RedisConcurrencyBackend.js +374 -0
- package/dist/concurrency/RedisConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/createConcurrencyBackend.d.ts +1 -0
- package/dist/concurrency/createConcurrencyBackend.js +5 -1
- package/dist/concurrency/createConcurrencyBackend.js.map +1 -1
- package/dist/defineNode.d.ts +8 -0
- package/dist/defineNode.js +25 -5
- package/dist/defineNode.js.map +1 -1
- package/dist/graphql/GraphQLSchemaGenerator.js +1 -1
- package/dist/graphql/GraphQLSchemaGenerator.js.map +1 -1
- package/dist/index.d.ts +10 -6
- package/dist/index.js +13 -9
- package/dist/index.js.map +1 -1
- package/dist/marketplace/RuntimeCatalog.d.ts +6 -0
- package/dist/marketplace/RuntimeCatalog.js.map +1 -1
- package/dist/marketplace/RuntimeDiscovery.d.ts +2 -2
- package/dist/marketplace/RuntimeDiscovery.js +18 -6
- package/dist/marketplace/RuntimeDiscovery.js.map +1 -1
- package/dist/monitoring/ConcurrencyMetrics.d.ts +26 -0
- package/dist/monitoring/ConcurrencyMetrics.js +36 -4
- package/dist/monitoring/ConcurrencyMetrics.js.map +1 -1
- package/dist/monitoring/ForEachWaitMetrics.d.ts +22 -0
- package/dist/monitoring/ForEachWaitMetrics.js +36 -0
- package/dist/monitoring/ForEachWaitMetrics.js.map +1 -0
- package/dist/openapi/OpenAPIGenerator.js +7 -2
- package/dist/openapi/OpenAPIGenerator.js.map +1 -1
- package/dist/runtime/PrimitiveStack.d.ts +64 -0
- package/dist/runtime/PrimitiveStack.js +92 -0
- package/dist/runtime/PrimitiveStack.js.map +1 -0
- package/dist/scheduling/DebounceBackend.d.ts +108 -0
- package/dist/scheduling/DebounceBackend.js +23 -0
- package/dist/scheduling/DebounceBackend.js.map +1 -0
- package/dist/scheduling/DebounceCoordinator.d.ts +65 -12
- package/dist/scheduling/DebounceCoordinator.js +234 -13
- package/dist/scheduling/DebounceCoordinator.js.map +1 -1
- package/dist/scheduling/DeferredRunScheduler.d.ts +28 -0
- package/dist/scheduling/DeferredRunScheduler.js +105 -3
- package/dist/scheduling/DeferredRunScheduler.js.map +1 -1
- package/dist/scheduling/NatsKvDebounceBackend.d.ts +53 -0
- package/dist/scheduling/NatsKvDebounceBackend.js +334 -0
- package/dist/scheduling/NatsKvDebounceBackend.js.map +1 -0
- package/dist/scheduling/RedisDebounceBackend.d.ts +49 -0
- package/dist/scheduling/RedisDebounceBackend.js +356 -0
- package/dist/scheduling/RedisDebounceBackend.js.map +1 -0
- package/dist/scheduling/createDebounceBackend.d.ts +25 -0
- package/dist/scheduling/createDebounceBackend.js +39 -0
- package/dist/scheduling/createDebounceBackend.js.map +1 -0
- package/dist/security/AuditLogger.js +1 -1
- package/dist/security/AuditLogger.js.map +1 -1
- package/dist/security/AuthMiddleware.d.ts +19 -20
- package/dist/security/AuthMiddleware.js +35 -20
- package/dist/security/AuthMiddleware.js.map +1 -1
- package/dist/security/OAuthProvider.js +2 -2
- package/dist/security/OAuthProvider.js.map +1 -1
- package/dist/security/SecretManager.js +14 -13
- package/dist/security/SecretManager.js.map +1 -1
- package/dist/security/index.d.ts +3 -1
- package/dist/security/index.js +3 -1
- package/dist/security/index.js.map +1 -1
- package/dist/testing/TestHarness.d.ts +27 -12
- package/dist/testing/TestHarness.js +19 -3
- package/dist/testing/TestHarness.js.map +1 -1
- package/dist/testing/WorkflowTestRunner.js +0 -7
- package/dist/testing/WorkflowTestRunner.js.map +1 -1
- package/dist/tracing/InMemoryRunStore.d.ts +14 -1
- package/dist/tracing/InMemoryRunStore.js +95 -6
- package/dist/tracing/InMemoryRunStore.js.map +1 -1
- package/dist/tracing/PostgresRunStore.d.ts +28 -2
- package/dist/tracing/PostgresRunStore.js +276 -3
- package/dist/tracing/PostgresRunStore.js.map +1 -1
- package/dist/tracing/RoutingDiagnostics.d.ts +55 -0
- package/dist/tracing/RoutingDiagnostics.js +50 -0
- package/dist/tracing/RoutingDiagnostics.js.map +1 -0
- package/dist/tracing/RunStore.d.ts +82 -1
- package/dist/tracing/RunTracker.d.ts +7 -1
- package/dist/tracing/RunTracker.js +23 -0
- package/dist/tracing/RunTracker.js.map +1 -1
- package/dist/tracing/SqliteRunStore.d.ts +57 -2
- package/dist/tracing/SqliteRunStore.js +408 -48
- package/dist/tracing/SqliteRunStore.js.map +1 -1
- package/dist/tracing/TraceRouter.js +380 -18
- package/dist/tracing/TraceRouter.js.map +1 -1
- package/dist/tracing/createStore.js +14 -3
- package/dist/tracing/createStore.js.map +1 -1
- package/dist/tracing/metadataFilter.d.ts +63 -0
- package/dist/tracing/metadataFilter.js +224 -0
- package/dist/tracing/metadataFilter.js.map +1 -0
- package/dist/tracing/types.d.ts +331 -7
- package/dist/utils/envAllowlist.d.ts +35 -0
- package/dist/utils/envAllowlist.js +113 -0
- package/dist/utils/envAllowlist.js.map +1 -0
- package/dist/version/RuntimeVersionValidator.d.ts +38 -0
- package/dist/version/RuntimeVersionValidator.js +121 -0
- package/dist/version/RuntimeVersionValidator.js.map +1 -0
- package/dist/visualization/WorkflowVisualizer.js +4 -4
- package/dist/visualization/WorkflowVisualizer.js.map +1 -1
- package/dist/workflow/PersistenceHelper.d.ts +18 -10
- package/dist/workflow/PersistenceHelper.js +35 -9
- package/dist/workflow/PersistenceHelper.js.map +1 -1
- package/dist/workflow/WorkflowNormalizer.d.ts +19 -1
- package/dist/workflow/WorkflowNormalizer.js +469 -19
- package/dist/workflow/WorkflowNormalizer.js.map +1 -1
- package/dist/workflow/WorkflowRegistry.d.ts +122 -0
- package/dist/workflow/WorkflowRegistry.js +121 -0
- package/dist/workflow/WorkflowRegistry.js.map +1 -1
- package/dist/workflow/sampleBody.d.ts +54 -0
- package/dist/workflow/sampleBody.js +320 -0
- package/dist/workflow/sampleBody.js.map +1 -0
- package/package.json +3 -8
- package/dist/adapters/HttpRuntimeAdapter.d.ts +0 -79
- package/dist/adapters/HttpRuntimeAdapter.js +0 -233
- package/dist/adapters/HttpRuntimeAdapter.js.map +0 -1
|
@@ -10,7 +10,7 @@ import { parseDuration } from "@blokjs/helper";
|
|
|
10
10
|
* ```
|
|
11
11
|
* {
|
|
12
12
|
* name, version, trigger,
|
|
13
|
-
* steps: [{ name, node, type, active?, stop
|
|
13
|
+
* steps: [{ name, node, type, active?, stop? }],
|
|
14
14
|
* nodes: { [stepName]: { inputs?, conditions? } }
|
|
15
15
|
* }
|
|
16
16
|
* ```
|
|
@@ -30,7 +30,7 @@ import { parseDuration } from "@blokjs/helper";
|
|
|
30
30
|
* ```
|
|
31
31
|
* {
|
|
32
32
|
* name, version, trigger, // method "*" normalized to "ANY"
|
|
33
|
-
* steps: [{ name, node, type, active, stop,
|
|
33
|
+
* steps: [{ name, node, type, active, stop, as, spread, ephemeral, ... }],
|
|
34
34
|
* nodes: { [stepName]: { inputs?, conditions? } }
|
|
35
35
|
* }
|
|
36
36
|
* ```
|
|
@@ -67,9 +67,33 @@ export function normalizeWorkflow(raw, sourcePath) {
|
|
|
67
67
|
// Legacy builder shape — same unwrap.
|
|
68
68
|
wf = wf._config;
|
|
69
69
|
}
|
|
70
|
+
// `set_var` removed in v0.5. Reject at load time with a migration hint
|
|
71
|
+
// — silently dropping the field would produce subtly different runtime
|
|
72
|
+
// behaviour (every step now default-stores; legacy `set_var: false`
|
|
73
|
+
// was the only opt-out and is replaced by `ephemeral: true`).
|
|
74
|
+
if (Array.isArray(wf.steps)) {
|
|
75
|
+
assertNoSetVar(wf.steps, sourcePath);
|
|
76
|
+
}
|
|
70
77
|
const name = typeof wf.name === "string" ? wf.name : "";
|
|
71
78
|
const version = typeof wf.version === "string" ? wf.version : "1.0.0";
|
|
72
79
|
const description = typeof wf.description === "string" ? wf.description : undefined;
|
|
80
|
+
// `middleware` is overloaded:
|
|
81
|
+
// - `true` → marker bit, this workflow IS a middleware
|
|
82
|
+
// - `string[]` → workflow-level middleware chain (these run on
|
|
83
|
+
// every request to this workflow, before any
|
|
84
|
+
// trigger-level middleware)
|
|
85
|
+
// The two are mutually exclusive — refuse the conflict at load time
|
|
86
|
+
// rather than letting one silently win.
|
|
87
|
+
const middleware = wf.middleware === true ? true : undefined;
|
|
88
|
+
let appliedMiddleware;
|
|
89
|
+
if (Array.isArray(wf.middleware)) {
|
|
90
|
+
const list = wf.middleware.filter((s) => typeof s === "string" && s.length > 0);
|
|
91
|
+
appliedMiddleware = list.length > 0 ? list : undefined;
|
|
92
|
+
}
|
|
93
|
+
if (middleware === true && appliedMiddleware !== undefined) {
|
|
94
|
+
const suffix = sourcePath ? ` (file: ${sourcePath})` : "";
|
|
95
|
+
throw new Error(`[blok] WorkflowNormalizer: workflow "${name}" sets both \`middleware: true\` (marker) and \`middleware: [...]\` (chain). These are mutually exclusive — pick one.${suffix}`);
|
|
96
|
+
}
|
|
73
97
|
// --- Trigger normalization (method "*" → "ANY") ---
|
|
74
98
|
const trigger = normalizeTrigger(wf.trigger, sourcePath);
|
|
75
99
|
// --- Steps normalization ---
|
|
@@ -84,9 +108,16 @@ export function normalizeWorkflow(raw, sourcePath) {
|
|
|
84
108
|
const step = rawStep;
|
|
85
109
|
// v2 branch — { id, branch: { when, then, else? } }
|
|
86
110
|
if (isPlainObject(step.branch)) {
|
|
87
|
-
const { internalStep, nodeConfig } = normalizeBranchStep(step, i);
|
|
111
|
+
const { internalStep, nodeConfig, innerNodes } = normalizeBranchStep(step, i);
|
|
88
112
|
internalSteps.push(internalStep);
|
|
89
113
|
internalNodes[internalStep.name] = nodeConfig;
|
|
114
|
+
// Promote every inner step's nodeConfig into the top-level nodes map
|
|
115
|
+
// so BlokService.run can find `ctx.config[innerStep.name].inputs`
|
|
116
|
+
// when the runner descends into the matching arm. Without this,
|
|
117
|
+
// inner steps with `inputs:` defined inline crash with
|
|
118
|
+
// `opts.inputs undefined` because their config was only attached
|
|
119
|
+
// to the inner step instance, not the global lookup map.
|
|
120
|
+
Object.assign(internalNodes, innerNodes);
|
|
90
121
|
continue;
|
|
91
122
|
}
|
|
92
123
|
// v2 sub-workflow — { id, subworkflow: "<name>", inputs?, wait? }
|
|
@@ -108,6 +139,38 @@ export function normalizeWorkflow(raw, sourcePath) {
|
|
|
108
139
|
internalSteps.push(internalStep);
|
|
109
140
|
continue;
|
|
110
141
|
}
|
|
142
|
+
// v0.5 forEach — { id, forEach: { in, as, mode?, concurrency?, do: [...] } }
|
|
143
|
+
if (isPlainObject(step.forEach)) {
|
|
144
|
+
const { internalStep, nodeConfig, innerNodes } = normalizeForEachStep(step, i);
|
|
145
|
+
internalSteps.push(internalStep);
|
|
146
|
+
internalNodes[internalStep.name] = nodeConfig;
|
|
147
|
+
Object.assign(internalNodes, innerNodes);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// v0.5 loop — { id, loop: { while, maxIterations?, do: [...] } }
|
|
151
|
+
if (isPlainObject(step.loop)) {
|
|
152
|
+
const { internalStep, nodeConfig, innerNodes } = normalizeLoopStep(step, i);
|
|
153
|
+
internalSteps.push(internalStep);
|
|
154
|
+
internalNodes[internalStep.name] = nodeConfig;
|
|
155
|
+
Object.assign(internalNodes, innerNodes);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
// v0.5 switch — { id, switch: { on, cases: [{when, do}], default? } }
|
|
159
|
+
if (isPlainObject(step.switch)) {
|
|
160
|
+
const { internalStep, nodeConfig, innerNodes } = normalizeSwitchStep(step, i);
|
|
161
|
+
internalSteps.push(internalStep);
|
|
162
|
+
internalNodes[internalStep.name] = nodeConfig;
|
|
163
|
+
Object.assign(internalNodes, innerNodes);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// v0.5 tryCatch — { id, tryCatch: { try, catch, finally? } }
|
|
167
|
+
if (isPlainObject(step.tryCatch)) {
|
|
168
|
+
const { internalStep, nodeConfig, innerNodes } = normalizeTryCatchStep(step, i);
|
|
169
|
+
internalSteps.push(internalStep);
|
|
170
|
+
internalNodes[internalStep.name] = nodeConfig;
|
|
171
|
+
Object.assign(internalNodes, innerNodes);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
111
174
|
// v2 regular — { id, use, inputs?, as?, spread?, ephemeral?, ... }
|
|
112
175
|
// or v1 regular — { name, node, type } + nodes[name].inputs
|
|
113
176
|
const { internalStep, nodeConfig } = normalizeRegularStep(step, nodesInput, i);
|
|
@@ -133,6 +196,8 @@ export function normalizeWorkflow(raw, sourcePath) {
|
|
|
133
196
|
trigger,
|
|
134
197
|
steps: internalSteps,
|
|
135
198
|
nodes: internalNodes,
|
|
199
|
+
...(middleware ? { middleware } : {}),
|
|
200
|
+
...(appliedMiddleware ? { appliedMiddleware } : {}),
|
|
136
201
|
};
|
|
137
202
|
}
|
|
138
203
|
// =============================================================================
|
|
@@ -157,10 +222,9 @@ function normalizeRegularStep(step, nodesInput, index) {
|
|
|
157
222
|
const v1NodeConfig = isPlainObject(nodesInput[id]) ? nodesInput[id] : null;
|
|
158
223
|
const v1Inputs = v1NodeConfig?.inputs && isPlainObject(v1NodeConfig.inputs) ? v1NodeConfig.inputs : null;
|
|
159
224
|
const inputs = inlineInputs ?? v1Inputs;
|
|
160
|
-
// Persistence knobs — v2
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
const ephemeral = ephemeralExplicit || ephemeralFromLegacy;
|
|
225
|
+
// Persistence knobs — v2 only. Legacy `set_var` is rejected upstream
|
|
226
|
+
// in `normalizeWorkflow` via `assertNoSetVar`.
|
|
227
|
+
const ephemeral = step.ephemeral === true;
|
|
164
228
|
const as = pickString(step.as);
|
|
165
229
|
const spread = step.spread === true;
|
|
166
230
|
// `as` and `spread` are mutually exclusive — caught at schema level too,
|
|
@@ -174,7 +238,6 @@ function normalizeRegularStep(step, nodesInput, index) {
|
|
|
174
238
|
type,
|
|
175
239
|
active: step.active === undefined ? true : Boolean(step.active),
|
|
176
240
|
stop: step.stop === true,
|
|
177
|
-
set_var: typeof step.set_var === "boolean" ? step.set_var : undefined,
|
|
178
241
|
as,
|
|
179
242
|
spread,
|
|
180
243
|
ephemeral,
|
|
@@ -242,37 +305,49 @@ function normalizeBranchStep(step, index) {
|
|
|
242
305
|
// `nodesInput` because v2 branches inline `inputs` on each nested step.
|
|
243
306
|
const thenInternal = [];
|
|
244
307
|
const elseInternal = [];
|
|
308
|
+
const innerNodes = {};
|
|
245
309
|
for (let i = 0; i < thenSteps.length; i++) {
|
|
246
310
|
const s = thenSteps[i];
|
|
247
311
|
if (!isPlainObject(s))
|
|
248
312
|
continue;
|
|
249
313
|
if (isPlainObject(s.branch)) {
|
|
250
|
-
const { internalStep } = normalizeBranchStep(s, i);
|
|
251
|
-
thenInternal.push(
|
|
314
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig, innerNodes: nestedInner, } = normalizeBranchStep(s, i);
|
|
315
|
+
thenInternal.push(nestedStep);
|
|
316
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
317
|
+
Object.assign(innerNodes, nestedInner);
|
|
252
318
|
continue;
|
|
253
319
|
}
|
|
254
|
-
const { internalStep, nodeConfig } = normalizeRegularStep(s, {}, i);
|
|
320
|
+
const { internalStep: regularStep, nodeConfig } = normalizeRegularStep(s, {}, i);
|
|
255
321
|
// Inline inputs on the step itself so nested-flow execution finds them.
|
|
256
322
|
// (RunnerSteps recursively executes flow nodes' inner steps.)
|
|
257
323
|
if (nodeConfig?.inputs) {
|
|
258
|
-
|
|
324
|
+
regularStep.inputs = nodeConfig.inputs;
|
|
259
325
|
}
|
|
260
|
-
|
|
326
|
+
// Also surface the nodeConfig in the bubbled-up innerNodes map so
|
|
327
|
+
// BlokService.run can read inputs via `ctx.config[step.name]` when
|
|
328
|
+
// the inner step actually executes.
|
|
329
|
+
if (nodeConfig)
|
|
330
|
+
innerNodes[regularStep.name] = nodeConfig;
|
|
331
|
+
thenInternal.push(regularStep);
|
|
261
332
|
}
|
|
262
333
|
for (let i = 0; i < elseSteps.length; i++) {
|
|
263
334
|
const s = elseSteps[i];
|
|
264
335
|
if (!isPlainObject(s))
|
|
265
336
|
continue;
|
|
266
337
|
if (isPlainObject(s.branch)) {
|
|
267
|
-
const { internalStep } = normalizeBranchStep(s, i);
|
|
268
|
-
elseInternal.push(
|
|
338
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig, innerNodes: nestedInner, } = normalizeBranchStep(s, i);
|
|
339
|
+
elseInternal.push(nestedStep);
|
|
340
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
341
|
+
Object.assign(innerNodes, nestedInner);
|
|
269
342
|
continue;
|
|
270
343
|
}
|
|
271
|
-
const { internalStep, nodeConfig } = normalizeRegularStep(s, {}, i);
|
|
344
|
+
const { internalStep: regularStep, nodeConfig } = normalizeRegularStep(s, {}, i);
|
|
272
345
|
if (nodeConfig?.inputs) {
|
|
273
|
-
|
|
346
|
+
regularStep.inputs = nodeConfig.inputs;
|
|
274
347
|
}
|
|
275
|
-
|
|
348
|
+
if (nodeConfig)
|
|
349
|
+
innerNodes[regularStep.name] = nodeConfig;
|
|
350
|
+
elseInternal.push(regularStep);
|
|
276
351
|
}
|
|
277
352
|
const conditions = [{ type: "if", condition: when, steps: thenInternal }];
|
|
278
353
|
if (elseInternal.length > 0) {
|
|
@@ -287,7 +362,7 @@ function normalizeBranchStep(step, index) {
|
|
|
287
362
|
flow: true,
|
|
288
363
|
};
|
|
289
364
|
const nodeConfig = { conditions };
|
|
290
|
-
return { internalStep, nodeConfig };
|
|
365
|
+
return { internalStep, nodeConfig, innerNodes };
|
|
291
366
|
}
|
|
292
367
|
const SUBWORKFLOW_NODE_REF = "@blokjs/subworkflow";
|
|
293
368
|
/**
|
|
@@ -358,6 +433,23 @@ function normalizeSubworkflowStep(step, index) {
|
|
|
358
433
|
if (typeof step.maxDuration === "number" || typeof step.maxDuration === "string") {
|
|
359
434
|
internalStep.maxDuration = step.maxDuration;
|
|
360
435
|
}
|
|
436
|
+
// G3 polymorphic-dispatch safety net — narrow the registry lookup to a
|
|
437
|
+
// fixed set when `subworkflow` is an expression (or just to harden a
|
|
438
|
+
// literal). Filter to non-empty strings here so SubworkflowNode can
|
|
439
|
+
// trust the shape and skip a defensive check on the hot path.
|
|
440
|
+
if (Array.isArray(step.allowList)) {
|
|
441
|
+
const cleaned = step.allowList.filter((s) => typeof s === "string" && s.length > 0);
|
|
442
|
+
if (cleaned.length > 0) {
|
|
443
|
+
internalStep.allowList = cleaned;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// G2 (v0.6) — dispatch strategy. Unknown / missing values fall
|
|
447
|
+
// through as "in-process" inside SubworkflowNode.run, but pass the
|
|
448
|
+
// raw string so the resolver can validate + threading bugs surface
|
|
449
|
+
// at config load instead of at run time.
|
|
450
|
+
if (step.dispatch === "in-process" || step.dispatch === "http-self") {
|
|
451
|
+
internalStep.dispatch = step.dispatch;
|
|
452
|
+
}
|
|
361
453
|
// Inputs land on nodeConfig so the blueprint mapper resolves
|
|
362
454
|
// $.<path> / js/... refs before SubworkflowNode reads them via
|
|
363
455
|
// `ctx.config[step.name]`.
|
|
@@ -425,6 +517,305 @@ function normalizeWaitStep(step, index) {
|
|
|
425
517
|
waitUntil,
|
|
426
518
|
};
|
|
427
519
|
}
|
|
520
|
+
// v0.5 forEach reference for the internal step's `node` field.
|
|
521
|
+
const FOR_EACH_NODE_REF = "@blokjs/forEach";
|
|
522
|
+
const LOOP_NODE_REF = "@blokjs/loop";
|
|
523
|
+
const SWITCH_NODE_REF = "@blokjs/switch";
|
|
524
|
+
const TRY_CATCH_NODE_REF = "@blokjs/tryCatch";
|
|
525
|
+
/**
|
|
526
|
+
* Normalize a v0.5 forEach step into the internal shape. Inner steps
|
|
527
|
+
* are recursively normalized via `normalizeRegularStep` so they get
|
|
528
|
+
* their inputs inlined; their nodeConfigs bubble up via `innerNodes`
|
|
529
|
+
* for the top-level `internalNodes` map (same pattern as branch).
|
|
530
|
+
*/
|
|
531
|
+
function normalizeForEachStep(step, index) {
|
|
532
|
+
const id = pickString(step.id);
|
|
533
|
+
if (!id) {
|
|
534
|
+
throw new Error(`[blok] WorkflowNormalizer: forEach step at index ${index} is missing \`id\`.`);
|
|
535
|
+
}
|
|
536
|
+
const fe = step.forEach;
|
|
537
|
+
const inField = fe.in;
|
|
538
|
+
if (inField === undefined) {
|
|
539
|
+
throw new Error(`[blok] WorkflowNormalizer: forEach step "${id}" is missing \`in\`.`);
|
|
540
|
+
}
|
|
541
|
+
const as = pickString(fe.as);
|
|
542
|
+
if (!as) {
|
|
543
|
+
throw new Error(`[blok] WorkflowNormalizer: forEach step "${id}" is missing \`as\` (per-iteration variable name).`);
|
|
544
|
+
}
|
|
545
|
+
const mode = fe.mode === "parallel" ? "parallel" : "sequential";
|
|
546
|
+
const concurrency = typeof fe.concurrency === "number" && fe.concurrency > 0 ? fe.concurrency : 10;
|
|
547
|
+
const doSteps = Array.isArray(fe.do) ? fe.do : [];
|
|
548
|
+
// v0.6 Phase 3 — parallel forEach + wait composition warning. When
|
|
549
|
+
// a wait fires inside a parallel iteration, peer in-flight iterations
|
|
550
|
+
// are cancelled and re-launched on resume. Re-launches re-execute
|
|
551
|
+
// side effects unless inner steps have `idempotencyKey` (or are
|
|
552
|
+
// naturally side-effect-free). This is a per-author-contract gotcha
|
|
553
|
+
// (see `docs/c/devtools/parallel-foreach-wait-spec.mdx#author-contract`).
|
|
554
|
+
// Warn at load time so authors notice; don't BLOCK the workflow —
|
|
555
|
+
// some authors deliberately accept the retry behavior (e.g. pure
|
|
556
|
+
// fetches) or have their own idempotency layer.
|
|
557
|
+
if (mode === "parallel" && doStepsContainWait(doSteps)) {
|
|
558
|
+
const nonIdempotentInnerSteps = doSteps
|
|
559
|
+
.filter((s) => isPlainObject(s))
|
|
560
|
+
.filter((s) => !isWaitStep(s) && s.idempotencyKey === undefined)
|
|
561
|
+
.map((s) => pickString(s.id) ?? "(unnamed)");
|
|
562
|
+
if (nonIdempotentInnerSteps.length > 0) {
|
|
563
|
+
const stepList = nonIdempotentInnerSteps.map((n) => `"${n}"`).join(", ");
|
|
564
|
+
console.warn(`[blok][normalizer] forEach "${id}" runs in parallel mode with a wait inside the iteration body. When the wait fires, peer iterations are cancelled and re-launched from scratch on resume. Inner steps without an \`idempotencyKey\` will re-execute their side effects on each re-launch: ${stepList}. Add \`idempotencyKey\` to side-effecting steps, OR confirm the steps are side-effect-free. See docs/c/devtools/parallel-foreach-wait-spec.mdx for the author contract.`);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const { innerInternal, innerNodes } = normalizeStepBlock(doSteps);
|
|
568
|
+
const internalStep = {
|
|
569
|
+
name: id,
|
|
570
|
+
node: FOR_EACH_NODE_REF,
|
|
571
|
+
type: "forEach",
|
|
572
|
+
active: step.active === undefined ? true : Boolean(step.active),
|
|
573
|
+
stop: step.stop === true,
|
|
574
|
+
};
|
|
575
|
+
// nodeConfig — top-level `steps` triggers Configuration's
|
|
576
|
+
// isFlowWithProperties path which materializes into NodeBase[].
|
|
577
|
+
const nodeConfig = {
|
|
578
|
+
in: inField,
|
|
579
|
+
as,
|
|
580
|
+
mode,
|
|
581
|
+
concurrency,
|
|
582
|
+
steps: innerInternal,
|
|
583
|
+
};
|
|
584
|
+
return { internalStep, nodeConfig, innerNodes };
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* v0.6 Phase 3 — recognise a wait step in the raw (pre-normalization)
|
|
588
|
+
* shape. Two encodings: v0.5 `{ id, wait: {for|until} }` OR legacy
|
|
589
|
+
* `{ id, type: "wait", waitForMs|waitUntil }`. Used by
|
|
590
|
+
* `normalizeForEachStep` to emit the parallel + wait warning.
|
|
591
|
+
*/
|
|
592
|
+
function isWaitStep(step) {
|
|
593
|
+
if (isPlainObject(step.wait))
|
|
594
|
+
return true;
|
|
595
|
+
if (step.type === "wait")
|
|
596
|
+
return true;
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* v0.6 Phase 3 — scan the doSteps array (one level deep) for a wait
|
|
601
|
+
* step. Doesn't recurse into nested primitives (forEach inside forEach,
|
|
602
|
+
* tryCatch inside forEach) — those are out of scope for this warning;
|
|
603
|
+
* Phase 4 nested-primitive work will extend.
|
|
604
|
+
*/
|
|
605
|
+
function doStepsContainWait(doSteps) {
|
|
606
|
+
for (const s of doSteps) {
|
|
607
|
+
if (isPlainObject(s) && isWaitStep(s))
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Normalize a v0.5 loop step into the internal shape. Same inner-step
|
|
614
|
+
* propagation pattern as forEach.
|
|
615
|
+
*/
|
|
616
|
+
function normalizeLoopStep(step, index) {
|
|
617
|
+
const id = pickString(step.id);
|
|
618
|
+
if (!id) {
|
|
619
|
+
throw new Error(`[blok] WorkflowNormalizer: loop step at index ${index} is missing \`id\`.`);
|
|
620
|
+
}
|
|
621
|
+
const lp = step.loop;
|
|
622
|
+
const whileExpr = pickString(lp.while);
|
|
623
|
+
if (!whileExpr) {
|
|
624
|
+
throw new Error(`[blok] WorkflowNormalizer: loop step "${id}" is missing \`while\` (the JS condition string).`);
|
|
625
|
+
}
|
|
626
|
+
const maxIterations = typeof lp.maxIterations === "number" && lp.maxIterations > 0 ? lp.maxIterations : 1000;
|
|
627
|
+
const doSteps = Array.isArray(lp.do) ? lp.do : [];
|
|
628
|
+
const { innerInternal, innerNodes } = normalizeStepBlock(doSteps);
|
|
629
|
+
const internalStep = {
|
|
630
|
+
name: id,
|
|
631
|
+
node: LOOP_NODE_REF,
|
|
632
|
+
type: "loop",
|
|
633
|
+
active: step.active === undefined ? true : Boolean(step.active),
|
|
634
|
+
stop: step.stop === true,
|
|
635
|
+
};
|
|
636
|
+
const nodeConfig = {
|
|
637
|
+
while: whileExpr,
|
|
638
|
+
maxIterations,
|
|
639
|
+
steps: innerInternal,
|
|
640
|
+
};
|
|
641
|
+
return { internalStep, nodeConfig, innerNodes };
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Helper used by `normalizeSwitchStep` — converts an array of authored
|
|
645
|
+
* step shapes (the `do` block of a case or the `default` block) into
|
|
646
|
+
* resolved InternalSteps + a merged innerNodes map. Mirrors the inner
|
|
647
|
+
* loop in `normalizeForEachStep` / `normalizeLoopStep`, recursing into
|
|
648
|
+
* nested branch / forEach / loop / switch as needed.
|
|
649
|
+
*/
|
|
650
|
+
function normalizeStepBlock(rawSteps) {
|
|
651
|
+
const innerInternal = [];
|
|
652
|
+
const innerNodes = {};
|
|
653
|
+
for (let i = 0; i < rawSteps.length; i++) {
|
|
654
|
+
const s = rawSteps[i];
|
|
655
|
+
if (!isPlainObject(s))
|
|
656
|
+
continue;
|
|
657
|
+
if (isPlainObject(s.branch)) {
|
|
658
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig, innerNodes: nestedInner, } = normalizeBranchStep(s, i);
|
|
659
|
+
innerInternal.push(nestedStep);
|
|
660
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
661
|
+
Object.assign(innerNodes, nestedInner);
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
if (isPlainObject(s.wait)) {
|
|
665
|
+
const nestedStep = normalizeWaitStep(s, i);
|
|
666
|
+
innerInternal.push(nestedStep);
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
if (isPlainObject(s.forEach)) {
|
|
670
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig, innerNodes: nestedInner, } = normalizeForEachStep(s, i);
|
|
671
|
+
innerInternal.push(nestedStep);
|
|
672
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
673
|
+
Object.assign(innerNodes, nestedInner);
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
if (isPlainObject(s.loop)) {
|
|
677
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig, innerNodes: nestedInner, } = normalizeLoopStep(s, i);
|
|
678
|
+
innerInternal.push(nestedStep);
|
|
679
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
680
|
+
Object.assign(innerNodes, nestedInner);
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (isPlainObject(s.switch)) {
|
|
684
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig, innerNodes: nestedInner, } = normalizeSwitchStep(s, i);
|
|
685
|
+
innerInternal.push(nestedStep);
|
|
686
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
687
|
+
Object.assign(innerNodes, nestedInner);
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
if (isPlainObject(s.tryCatch)) {
|
|
691
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig, innerNodes: nestedInner, } = normalizeTryCatchStep(s, i);
|
|
692
|
+
innerInternal.push(nestedStep);
|
|
693
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
694
|
+
Object.assign(innerNodes, nestedInner);
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
if (typeof s.subworkflow === "string") {
|
|
698
|
+
const { internalStep: nestedStep, nodeConfig: nestedConfig } = normalizeSubworkflowStep(s, i);
|
|
699
|
+
innerInternal.push(nestedStep);
|
|
700
|
+
if (nestedConfig)
|
|
701
|
+
innerNodes[nestedStep.name] = nestedConfig;
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
const { internalStep: regularStep, nodeConfig } = normalizeRegularStep(s, {}, i);
|
|
705
|
+
if (nodeConfig?.inputs) {
|
|
706
|
+
regularStep.inputs = nodeConfig.inputs;
|
|
707
|
+
}
|
|
708
|
+
if (nodeConfig)
|
|
709
|
+
innerNodes[regularStep.name] = nodeConfig;
|
|
710
|
+
innerInternal.push(regularStep);
|
|
711
|
+
}
|
|
712
|
+
return { innerInternal, innerNodes };
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Normalize a v0.5 switch step into the internal shape. The cases and
|
|
716
|
+
* optional default each carry their own inner-step list — Configuration
|
|
717
|
+
* resolves them via a dedicated branch in `getNodes()` (mirrors the
|
|
718
|
+
* tryCatch path: each sub-block becomes its own resolved Flow).
|
|
719
|
+
*
|
|
720
|
+
* SwitchNode at run time reads the resolved nodeConfig:
|
|
721
|
+
* { on, cases: [{when, steps: NodeBase[]}], default?: NodeBase[] }
|
|
722
|
+
* and runs the matched case (or default) through a child Runner.
|
|
723
|
+
*/
|
|
724
|
+
function normalizeSwitchStep(step, index) {
|
|
725
|
+
const id = pickString(step.id);
|
|
726
|
+
if (!id) {
|
|
727
|
+
throw new Error(`[blok] WorkflowNormalizer: switch step at index ${index} is missing \`id\`.`);
|
|
728
|
+
}
|
|
729
|
+
const sw = step.switch;
|
|
730
|
+
if (sw.on === undefined) {
|
|
731
|
+
throw new Error(`[blok] WorkflowNormalizer: switch step "${id}" is missing \`on\` (the value to match against).`);
|
|
732
|
+
}
|
|
733
|
+
const rawCases = Array.isArray(sw.cases) ? sw.cases : [];
|
|
734
|
+
if (rawCases.length === 0) {
|
|
735
|
+
throw new Error(`[blok] WorkflowNormalizer: switch step "${id}" has no \`cases\` (need at least one).`);
|
|
736
|
+
}
|
|
737
|
+
const cases = [];
|
|
738
|
+
const innerNodes = {};
|
|
739
|
+
for (let ci = 0; ci < rawCases.length; ci++) {
|
|
740
|
+
const c = rawCases[ci];
|
|
741
|
+
if (!isPlainObject(c)) {
|
|
742
|
+
throw new Error(`[blok] WorkflowNormalizer: switch step "${id}" cases[${ci}] is not an object.`);
|
|
743
|
+
}
|
|
744
|
+
const cobj = c;
|
|
745
|
+
if (cobj.when === undefined) {
|
|
746
|
+
throw new Error(`[blok] WorkflowNormalizer: switch step "${id}" cases[${ci}] is missing \`when\`.`);
|
|
747
|
+
}
|
|
748
|
+
const doSteps = Array.isArray(cobj.do) ? cobj.do : [];
|
|
749
|
+
const { innerInternal, innerNodes: caseInner } = normalizeStepBlock(doSteps);
|
|
750
|
+
Object.assign(innerNodes, caseInner);
|
|
751
|
+
cases.push({ when: cobj.when, steps: innerInternal });
|
|
752
|
+
}
|
|
753
|
+
let defaultSteps;
|
|
754
|
+
if (Array.isArray(sw.default)) {
|
|
755
|
+
const { innerInternal, innerNodes: defaultInner } = normalizeStepBlock(sw.default);
|
|
756
|
+
Object.assign(innerNodes, defaultInner);
|
|
757
|
+
defaultSteps = innerInternal;
|
|
758
|
+
}
|
|
759
|
+
const internalStep = {
|
|
760
|
+
name: id,
|
|
761
|
+
node: SWITCH_NODE_REF,
|
|
762
|
+
type: "switch",
|
|
763
|
+
active: step.active === undefined ? true : Boolean(step.active),
|
|
764
|
+
stop: step.stop === true,
|
|
765
|
+
};
|
|
766
|
+
const nodeConfig = {
|
|
767
|
+
on: sw.on,
|
|
768
|
+
cases,
|
|
769
|
+
...(defaultSteps !== undefined ? { default: defaultSteps } : {}),
|
|
770
|
+
};
|
|
771
|
+
return { internalStep, nodeConfig, innerNodes };
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Normalize a v0.5 tryCatch step into the internal shape. Each of `try`,
|
|
775
|
+
* `catch`, and optional `finally` carries its own inner-step list —
|
|
776
|
+
* Configuration resolves them via a dedicated branch in `getNodes()` so
|
|
777
|
+
* each block becomes its own resolved Flow (steps: NodeBase[]).
|
|
778
|
+
*
|
|
779
|
+
* TryCatchNode at run time reads the resolved nodeConfig:
|
|
780
|
+
* { try: NodeBase[], catch: NodeBase[], finally?: NodeBase[] }
|
|
781
|
+
* and runs them according to JS-like try/catch/finally semantics.
|
|
782
|
+
*/
|
|
783
|
+
function normalizeTryCatchStep(step, index) {
|
|
784
|
+
const id = pickString(step.id);
|
|
785
|
+
if (!id) {
|
|
786
|
+
throw new Error(`[blok] WorkflowNormalizer: tryCatch step at index ${index} is missing \`id\`.`);
|
|
787
|
+
}
|
|
788
|
+
const tc = step.tryCatch;
|
|
789
|
+
if (!Array.isArray(tc.try) || tc.try.length === 0) {
|
|
790
|
+
throw new Error(`[blok] WorkflowNormalizer: tryCatch step "${id}" requires a non-empty \`try\` block.`);
|
|
791
|
+
}
|
|
792
|
+
if (!Array.isArray(tc.catch) || tc.catch.length === 0) {
|
|
793
|
+
throw new Error(`[blok] WorkflowNormalizer: tryCatch step "${id}" requires a non-empty \`catch\` block.`);
|
|
794
|
+
}
|
|
795
|
+
const innerNodes = {};
|
|
796
|
+
const tryBlock = normalizeStepBlock(tc.try);
|
|
797
|
+
Object.assign(innerNodes, tryBlock.innerNodes);
|
|
798
|
+
const catchBlock = normalizeStepBlock(tc.catch);
|
|
799
|
+
Object.assign(innerNodes, catchBlock.innerNodes);
|
|
800
|
+
let finallyBlock;
|
|
801
|
+
if (Array.isArray(tc.finally)) {
|
|
802
|
+
finallyBlock = normalizeStepBlock(tc.finally);
|
|
803
|
+
Object.assign(innerNodes, finallyBlock.innerNodes);
|
|
804
|
+
}
|
|
805
|
+
const internalStep = {
|
|
806
|
+
name: id,
|
|
807
|
+
node: TRY_CATCH_NODE_REF,
|
|
808
|
+
type: "tryCatch",
|
|
809
|
+
active: step.active === undefined ? true : Boolean(step.active),
|
|
810
|
+
stop: step.stop === true,
|
|
811
|
+
};
|
|
812
|
+
const nodeConfig = {
|
|
813
|
+
try: tryBlock.innerInternal,
|
|
814
|
+
catch: catchBlock.innerInternal,
|
|
815
|
+
...(finallyBlock !== undefined ? { finally: finallyBlock.innerInternal } : {}),
|
|
816
|
+
};
|
|
817
|
+
return { internalStep, nodeConfig, innerNodes };
|
|
818
|
+
}
|
|
428
819
|
function normalizeTrigger(rawTrigger, sourcePath) {
|
|
429
820
|
if (!isPlainObject(rawTrigger))
|
|
430
821
|
return {};
|
|
@@ -483,4 +874,63 @@ function pickString(value) {
|
|
|
483
874
|
export function _resetWildcardWarningCache() {
|
|
484
875
|
_wildcardWarnedFiles = new Set();
|
|
485
876
|
}
|
|
877
|
+
/**
|
|
878
|
+
* `set_var` is no longer accepted on workflow steps. Walk the raw step
|
|
879
|
+
* tree (top-level steps + every nested sub-pipeline) and throw with a
|
|
880
|
+
* migration hint on the first occurrence. The walk handles branch,
|
|
881
|
+
* forEach, loop, switch, and tryCatch sub-pipelines so a rejected
|
|
882
|
+
* field at any depth is caught at load time rather than after the
|
|
883
|
+
* partial-normalization point.
|
|
884
|
+
*/
|
|
885
|
+
function assertNoSetVar(steps, sourcePath) {
|
|
886
|
+
for (const raw of steps) {
|
|
887
|
+
if (!isPlainObject(raw))
|
|
888
|
+
continue;
|
|
889
|
+
const step = raw;
|
|
890
|
+
if (Object.prototype.hasOwnProperty.call(step, "set_var")) {
|
|
891
|
+
const id = pickString(step.id) ?? pickString(step.name) ?? "<unnamed>";
|
|
892
|
+
const suffix = sourcePath ? ` (file: ${sourcePath})` : "";
|
|
893
|
+
throw new Error(`[blok] WorkflowNormalizer: step "${id}" uses \`set_var\`, which was removed in v0.5. Replace \`set_var: false\` with \`ephemeral: true\` and drop \`set_var: true\` (v2 default-stores every step's output). Run \`blokctl migrate workflows\` to convert v1 workflows automatically.${suffix}`);
|
|
894
|
+
}
|
|
895
|
+
// Recurse into nested sub-pipelines.
|
|
896
|
+
if (isPlainObject(step.branch)) {
|
|
897
|
+
const branch = step.branch;
|
|
898
|
+
if (Array.isArray(branch.then))
|
|
899
|
+
assertNoSetVar(branch.then, sourcePath);
|
|
900
|
+
if (Array.isArray(branch.else))
|
|
901
|
+
assertNoSetVar(branch.else, sourcePath);
|
|
902
|
+
}
|
|
903
|
+
if (isPlainObject(step.forEach)) {
|
|
904
|
+
const fe = step.forEach;
|
|
905
|
+
if (Array.isArray(fe.do))
|
|
906
|
+
assertNoSetVar(fe.do, sourcePath);
|
|
907
|
+
}
|
|
908
|
+
if (isPlainObject(step.loop)) {
|
|
909
|
+
const lp = step.loop;
|
|
910
|
+
if (Array.isArray(lp.do))
|
|
911
|
+
assertNoSetVar(lp.do, sourcePath);
|
|
912
|
+
}
|
|
913
|
+
if (isPlainObject(step.switch)) {
|
|
914
|
+
const sw = step.switch;
|
|
915
|
+
if (Array.isArray(sw.cases)) {
|
|
916
|
+
for (const c of sw.cases) {
|
|
917
|
+
if (isPlainObject(c) && Array.isArray(c.do)) {
|
|
918
|
+
assertNoSetVar(c.do, sourcePath);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (Array.isArray(sw.default))
|
|
923
|
+
assertNoSetVar(sw.default, sourcePath);
|
|
924
|
+
}
|
|
925
|
+
if (isPlainObject(step.tryCatch)) {
|
|
926
|
+
const tc = step.tryCatch;
|
|
927
|
+
if (Array.isArray(tc.try))
|
|
928
|
+
assertNoSetVar(tc.try, sourcePath);
|
|
929
|
+
if (Array.isArray(tc.catch))
|
|
930
|
+
assertNoSetVar(tc.catch, sourcePath);
|
|
931
|
+
if (Array.isArray(tc.finally))
|
|
932
|
+
assertNoSetVar(tc.finally, sourcePath);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
486
936
|
//# sourceMappingURL=WorkflowNormalizer.js.map
|