@sanity/workflow-engine 0.12.0 → 0.13.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/define.js CHANGED
@@ -19,22 +19,22 @@ function desugarWorkflow(authoring) {
19
19
  claimFields: /* @__PURE__ */ new Map(),
20
20
  claimedFields: /* @__PURE__ */ new Set(),
21
21
  roleAliases
22
- }, workflowFields = desugarFieldEntries(authoring.fields, ["fields"], ctx), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
23
- const path = ["stages", i], stageFields = desugarFieldEntries(stage.fields, [...path, "fields"], ctx), stageEnv = {
22
+ }, workflowFields = desugarFieldEntries({ entries: authoring.fields, path: ["fields"], ctx }), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
23
+ const path = ["stages", i], stageFields = desugarFieldEntries({ entries: stage.fields, path: [...path, "fields"], ctx }), stageEnv = {
24
24
  layers: [
25
25
  { scope: "stage", entries: layerOf(stageFields) },
26
26
  { scope: "workflow", entries: workflowLayer }
27
27
  ]
28
28
  }, activities = (stage.activities ?? []).map(
29
- (activity, j) => desugarActivity(activity, [...path, "activities", j], stageEnv, ctx)
29
+ (activity, j) => desugarActivity({ activity, path: [...path, "activities", j], stageEnv, ctx })
30
30
  ), transitions = (stage.transitions ?? []).map(
31
- (transition, k) => desugarTransition(transition, [...path, "transitions", k], stageEnv, ctx)
32
- ), editable = desugarStageEditable(
33
- stage.editable,
34
- editableSlotNames(workflowFields, stageFields, activities),
35
- [...path, "editable"],
31
+ (transition, k) => desugarTransition({ transition, path: [...path, "transitions", k], stageEnv, ctx })
32
+ ), editable = desugarStageEditable({
33
+ overrides: stage.editable,
34
+ inScope: editableSlotNames({ workflowFields, stageFields, activities }),
35
+ path: [...path, "editable"],
36
36
  ctx
37
- );
37
+ });
38
38
  return {
39
39
  ...stripUndefined({
40
40
  name: stage.name,
@@ -79,13 +79,22 @@ const TODOLIST_OF = [
79
79
  { type: "actor", name: "actor", title: "Actor" },
80
80
  { type: "datetime", name: "at", title: "At" }
81
81
  ];
82
- function desugarFieldEntries(entries, path, ctx) {
83
- return !entries || entries.length === 0 ? entries === void 0 ? void 0 : [] : entries.map((entry, i) => desugarFieldEntry(entry, [...path, i], ctx));
84
- }
85
- function desugarFieldEntry(entry, path, ctx) {
86
- if (entry.type === "claim") return desugarClaimField(entry, path, ctx);
87
- if (entry.type === "todoList" || entry.type === "notes") return desugarListField(entry, path, ctx);
88
- const editable = normalizeEditable(entry.editable, [...path, "editable"], ctx);
82
+ function desugarFieldEntries({
83
+ entries,
84
+ path,
85
+ ctx
86
+ }) {
87
+ return !entries || entries.length === 0 ? entries === void 0 ? void 0 : [] : entries.map((entry, i) => desugarFieldEntry({ entry, path: [...path, i], ctx }));
88
+ }
89
+ function desugarFieldEntry({
90
+ entry,
91
+ path,
92
+ ctx
93
+ }) {
94
+ if (entry.type === "claim") return desugarClaimField({ entry, path, ctx });
95
+ if (entry.type === "todoList" || entry.type === "notes")
96
+ return desugarListField({ entry, path, ctx });
97
+ const editable = normalizeEditable({ editable: entry.editable, path: [...path, "editable"], ctx });
89
98
  return {
90
99
  ...stripUndefined({
91
100
  type: entry.type,
@@ -100,15 +109,23 @@ function desugarFieldEntry(entry, path, ctx) {
100
109
  })
101
110
  };
102
111
  }
103
- function desugarClaimField(entry, path, ctx) {
112
+ function desugarClaimField({
113
+ entry,
114
+ path,
115
+ ctx
116
+ }) {
104
117
  const desugared = {
105
118
  ...stripUndefined({ name: entry.name, title: entry.title, description: entry.description }),
106
119
  type: "actor"
107
120
  };
108
121
  return ctx.claimFields.set(desugared, { name: entry.name, path }), desugared;
109
122
  }
110
- function desugarListField(entry, path, ctx) {
111
- const editable = normalizeEditable(entry.editable, [...path, "editable"], ctx);
123
+ function desugarListField({
124
+ entry,
125
+ path,
126
+ ctx
127
+ }) {
128
+ const editable = normalizeEditable({ editable: entry.editable, path: [...path, "editable"], ctx });
112
129
  return {
113
130
  ...stripUndefined({
114
131
  name: entry.name,
@@ -122,7 +139,11 @@ function desugarListField(entry, path, ctx) {
122
139
  of: entry.type === "todoList" ? TODOLIST_OF : NOTES_OF
123
140
  };
124
141
  }
125
- function normalizeEditable(editable, path, ctx) {
142
+ function normalizeEditable({
143
+ editable,
144
+ path,
145
+ ctx
146
+ }) {
126
147
  if (editable === void 0 || editable === !0) return editable;
127
148
  if (Array.isArray(editable)) {
128
149
  const condition = rolesCondition(editable, ctx.roleAliases);
@@ -137,7 +158,11 @@ function normalizeEditable(editable, path, ctx) {
137
158
  }
138
159
  return editable;
139
160
  }
140
- function editableSlotNames(workflowFields, stageFields, activities) {
161
+ function editableSlotNames({
162
+ workflowFields,
163
+ stageFields,
164
+ activities
165
+ }) {
141
166
  const names = /* @__PURE__ */ new Set(), collect = (entries) => {
142
167
  for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
143
168
  };
@@ -145,7 +170,12 @@ function editableSlotNames(workflowFields, stageFields, activities) {
145
170
  for (const activity of activities) collect(activity.fields);
146
171
  return names;
147
172
  }
148
- function desugarStageEditable(overrides, inScope, path, ctx) {
173
+ function desugarStageEditable({
174
+ overrides,
175
+ inScope,
176
+ path,
177
+ ctx
178
+ }) {
149
179
  if (overrides === void 0) return;
150
180
  const out = {};
151
181
  for (const [name, value] of Object.entries(overrides)) {
@@ -156,7 +186,7 @@ function desugarStageEditable(overrides, inScope, path, ctx) {
156
186
  });
157
187
  continue;
158
188
  }
159
- const normalized = normalizeEditable(value, [...path, name], ctx);
189
+ const normalized = normalizeEditable({ editable: value, path: [...path, name], ctx });
160
190
  normalized !== void 0 && (out[name] = normalized);
161
191
  }
162
192
  return Object.keys(out).length > 0 ? out : void 0;
@@ -164,12 +194,27 @@ function desugarStageEditable(overrides, inScope, path, ctx) {
164
194
  function layerOf(entries) {
165
195
  return new Map((entries ?? []).map((entry) => [entry.name, entry]));
166
196
  }
167
- function desugarActivity(activity, path, stageEnv, ctx) {
168
- const activityFields = desugarFieldEntries(activity.fields, [...path, "fields"], ctx), env = {
197
+ function desugarActivity({
198
+ activity,
199
+ path,
200
+ stageEnv,
201
+ ctx
202
+ }) {
203
+ const activityFields = desugarFieldEntries({
204
+ entries: activity.fields,
205
+ path: [...path, "fields"],
206
+ ctx
207
+ }), env = {
169
208
  layers: [{ scope: "activity", entries: layerOf(activityFields) }, ...stageEnv.layers]
170
- }, ops = desugarOps(activity.ops, [...path, "ops"], env, activity.name, ctx), actions = (activity.actions ?? []).map(
171
- (action, a) => desugarAction(action, [...path, "actions", a], env, activity.name, ctx)
172
- ), target = desugarTarget(activity.target, env, [...path, "target"], ctx);
209
+ }, ops = desugarOps({
210
+ ops: activity.ops,
211
+ path: [...path, "ops"],
212
+ env,
213
+ firingActivity: activity.name,
214
+ ctx
215
+ }), actions = (activity.actions ?? []).map(
216
+ (action, a) => desugarAction({ action, path: [...path, "actions", a], env, activityName: activity.name, ctx })
217
+ ), target = desugarTarget({ target: activity.target, env, path: [...path, "target"], ctx });
173
218
  return {
174
219
  ...stripUndefined({
175
220
  name: activity.name,
@@ -191,18 +236,29 @@ function desugarActivity(activity, path, stageEnv, ctx) {
191
236
  };
192
237
  }
193
238
  const TARGET_DOC_KINDS = ["doc.ref", "doc.refs", "release.ref"];
194
- function desugarTarget(target, env, path, ctx) {
239
+ function desugarTarget({
240
+ target,
241
+ env,
242
+ path,
243
+ ctx
244
+ }) {
195
245
  if (target === void 0 || target.type === "url") return target;
196
- const ref = typeof target.field == "string" ? { field: target.field } : target.field, field = resolveRef(ref, env, [...path, "field"], ctx) ?? fallbackRef(ref), entry = entryAt(env, field);
246
+ const ref = typeof target.field == "string" ? { field: target.field } : target.field, field = resolveRef({ ref, env, path: [...path, "field"], ctx }) ?? fallbackRef(ref), entry = entryAt(env, field);
197
247
  return entry && !TARGET_DOC_KINDS.includes(entry.type) && ctx.issues.push({
198
248
  path: [...path, "field"],
199
249
  message: `manual activity target references "${field.field}" of kind "${entry.type}" \u2014 a deep-link target needs a document-valued entry (${TARGET_DOC_KINDS.join(", ")})`
200
250
  }), { type: "field", field };
201
251
  }
202
- function desugarAction(action, path, env, activityName, ctx) {
252
+ function desugarAction({
253
+ action,
254
+ path,
255
+ env,
256
+ activityName,
257
+ ctx
258
+ }) {
203
259
  if ("type" in action)
204
- return desugarClaimAction(action, path, env, ctx);
205
- const filter = andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps(action.ops, [...path, "ops"], env, activityName, ctx) ?? [];
260
+ return desugarClaimAction({ action, path, env, ctx });
261
+ const filter = andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps({ ops: action.ops, path: [...path, "ops"], env, firingActivity: activityName, ctx }) ?? [];
206
262
  return action.status !== void 0 && ops.push({ type: "status.set", activity: activityName, status: action.status }), {
207
263
  ...stripUndefined({
208
264
  name: action.name,
@@ -215,14 +271,26 @@ function desugarAction(action, path, env, activityName, ctx) {
215
271
  ...ops.length > 0 ? { ops } : {}
216
272
  };
217
273
  }
218
- function desugarClaimAction(action, path, env, ctx) {
219
- const ref = typeof action.field == "string" ? { field: action.field } : action.field, resolved = resolveRef(ref, env, [...path, "field"], ctx);
274
+ function desugarClaimAction({
275
+ action,
276
+ path,
277
+ env,
278
+ ctx
279
+ }) {
280
+ const ref = typeof action.field == "string" ? { field: action.field } : action.field, resolved = resolveRef({ ref, env, path: [...path, "field"], ctx });
220
281
  if (resolved) {
221
282
  const entry = entryAt(env, resolved);
222
283
  entry && entry.type !== "actor" && ctx.issues.push({
223
284
  path: [...path, "field"],
224
285
  message: `claim action "${action.name}" references "${resolved.field}" of kind "${entry.type}" \u2014 a claim pair needs an actor-valued entry (a "claim" or "actor" field declaration)`
225
- }), checkShadowedClaimTarget(action.name, ref.field, resolved, env, [...path, "field"], ctx), entry && ctx.claimedFields.add(entry);
286
+ }), checkShadowedClaimTarget({
287
+ actionName: action.name,
288
+ field: ref.field,
289
+ resolved,
290
+ env,
291
+ path: [...path, "field"],
292
+ ctx
293
+ }), entry && ctx.claimedFields.add(entry);
226
294
  }
227
295
  const noSteal = `!defined($fields.${ref.field})`, filter = andConditions([
228
296
  noSteal,
@@ -241,7 +309,14 @@ function desugarClaimAction(action, path, env, ctx) {
241
309
  ...ops.length > 0 ? { ops } : {}
242
310
  };
243
311
  }
244
- function checkShadowedClaimTarget(actionName, field, resolved, env, path, ctx) {
312
+ function checkShadowedClaimTarget({
313
+ actionName,
314
+ field,
315
+ resolved,
316
+ env,
317
+ path,
318
+ ctx
319
+ }) {
245
320
  const nearest = env.layers.find((l) => l.entries.has(field));
246
321
  nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
247
322
  path,
@@ -255,8 +330,19 @@ function checkUnclaimedClaimFields(ctx) {
255
330
  message: `claim field "${name}" is never referenced by a claim action \u2014 you announced the pattern and wrote half of it. Declare a defineAction({ type: "claim", field: "${name}" }) or use a raw actor entry`
256
331
  });
257
332
  }
258
- function desugarTransition(transition, path, stageEnv, ctx) {
259
- const ops = desugarOps(transition.ops, [...path, "ops"], stageEnv, void 0, ctx);
333
+ function desugarTransition({
334
+ transition,
335
+ path,
336
+ stageEnv,
337
+ ctx
338
+ }) {
339
+ const ops = desugarOps({
340
+ ops: transition.ops,
341
+ path: [...path, "ops"],
342
+ env: stageEnv,
343
+ firingActivity: void 0,
344
+ ctx
345
+ });
260
346
  return {
261
347
  ...stripUndefined({
262
348
  name: transition.name,
@@ -269,11 +355,23 @@ function desugarTransition(transition, path, stageEnv, ctx) {
269
355
  ...ops ? { ops } : {}
270
356
  };
271
357
  }
272
- function desugarOps(ops, path, env, firingActivity, ctx) {
358
+ function desugarOps({
359
+ ops,
360
+ path,
361
+ env,
362
+ firingActivity,
363
+ ctx
364
+ }) {
273
365
  if (ops)
274
- return ops.map((op, i) => desugarOp(op, [...path, i], env, firingActivity, ctx));
275
- }
276
- function desugarOp(op, path, env, firingActivity, ctx) {
366
+ return ops.map((op, i) => desugarOp({ op, path: [...path, i], env, firingActivity, ctx }));
367
+ }
368
+ function desugarOp({
369
+ op,
370
+ path,
371
+ env,
372
+ firingActivity,
373
+ ctx
374
+ }) {
277
375
  if (op.type === "status.set") {
278
376
  const activity = op.activity ?? firingActivity;
279
377
  return activity === void 0 && ctx.issues.push({
@@ -281,13 +379,18 @@ function desugarOp(op, path, env, firingActivity, ctx) {
281
379
  message: "status.set outside an action must name its target activity"
282
380
  }), { type: "status.set", activity: activity ?? "", status: op.status };
283
381
  }
284
- if (op.type === "audit") return desugarAuditOp(op, path, env, ctx);
285
- const target = resolveRef(op.target, env, [...path, "target"], ctx) ?? fallbackRef(op.target);
382
+ if (op.type === "audit") return desugarAuditOp({ op, path, env, ctx });
383
+ const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
286
384
  return { ...op, target };
287
385
  }
288
386
  const AUDIT_STAMPS = { actor: { type: "actor" }, at: { type: "now" } };
289
- function desugarAuditOp(op, path, env, ctx) {
290
- const target = resolveRef(op.target, env, [...path, "target"], ctx) ?? fallbackRef(op.target);
387
+ function desugarAuditOp({
388
+ op,
389
+ path,
390
+ env,
391
+ ctx
392
+ }) {
393
+ const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
291
394
  if (op.value.type !== "object")
292
395
  return ctx.issues.push({
293
396
  path: [...path, "value"],
@@ -309,7 +412,12 @@ function desugarAuditOp(op, path, env, ctx) {
309
412
  }
310
413
  return { type: "field.append", target, value: { type: "object", fields } };
311
414
  }
312
- function resolveRef(ref, env, path, ctx) {
415
+ function resolveRef({
416
+ ref,
417
+ env,
418
+ path,
419
+ ctx
420
+ }) {
313
421
  const layers = ref.scope === void 0 ? env.layers : env.layers.filter((l) => l.scope === ref.scope);
314
422
  for (const layer of layers)
315
423
  if (layer.entries.has(ref.field)) return { scope: layer.scope, field: ref.field };
@@ -355,71 +463,103 @@ const RESERVED_CONDITION_VARS = [
355
463
  function knownList(ids) {
356
464
  return [...ids].map((s) => `"${s}"`).join(", ");
357
465
  }
358
- function checkDuplicates(names, what, issues) {
466
+ function checkDuplicates({
467
+ names,
468
+ what,
469
+ issues
470
+ }) {
359
471
  const seen = /* @__PURE__ */ new Set();
360
472
  for (const { name, path } of names)
361
473
  seen.has(name) && issues.push({ path, message: `duplicate ${what} "${name}" (already declared earlier)` }), seen.add(name);
362
474
  return seen;
363
475
  }
364
476
  function checkStages(def, issues) {
365
- const stageNames = checkDuplicates(
366
- def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
367
- "stage name",
477
+ const stageNames = checkDuplicates({
478
+ names: def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
479
+ what: "stage name",
368
480
  issues
369
- );
481
+ });
370
482
  for (const [i, stage] of def.stages.entries()) {
371
- const activityNames = checkDuplicates(
372
- (stage.activities ?? []).map((activity, j) => ({
483
+ const activityNames = checkDuplicates({
484
+ names: (stage.activities ?? []).map((activity, j) => ({
373
485
  name: activity.name,
374
486
  path: ["stages", i, "activities", j, "name"]
375
487
  })),
376
- `activity name in stage "${stage.name}"`,
488
+ what: `activity name in stage "${stage.name}"`,
377
489
  issues
378
- );
379
- checkDuplicates(
380
- (stage.transitions ?? []).map((t, k) => ({
490
+ });
491
+ checkDuplicates({
492
+ names: (stage.transitions ?? []).map((t, k) => ({
381
493
  name: t.name,
382
494
  path: ["stages", i, "transitions", k, "name"]
383
495
  })),
384
- `transition name in stage "${stage.name}"`,
496
+ what: `transition name in stage "${stage.name}"`,
385
497
  issues
386
- ), checkActivities(def, i, activityNames, issues);
498
+ }), checkActivities({ def, i, activityNames, issues });
387
499
  }
388
500
  return stageNames;
389
501
  }
390
- function checkActivities(def, i, activityNames, issues) {
502
+ function checkActivities({
503
+ def,
504
+ i,
505
+ activityNames,
506
+ issues
507
+ }) {
391
508
  const stage = def.stages[i];
392
509
  for (const [j, activity] of (stage.activities ?? []).entries()) {
393
510
  const path = ["stages", i, "activities", j];
394
- checkDuplicates(
395
- (activity.actions ?? []).map((action, a) => ({
511
+ checkDuplicates({
512
+ names: (activity.actions ?? []).map((action, a) => ({
396
513
  name: action.name,
397
514
  path: [...path, "actions", a, "name"]
398
515
  })),
399
- `action name in activity "${activity.name}"`,
516
+ what: `action name in activity "${activity.name}"`,
400
517
  issues
401
- ), checkStatusSetTargets(activity, activityNames, path, issues);
518
+ }), checkStatusSetTargets({ activity, activityNames, path, issues });
402
519
  }
403
520
  }
404
- function checkStatusSetTargets(activity, activityNames, path, issues) {
405
- checkStatusSetOps(activity.ops, activityNames, [...path, "ops"], issues);
521
+ function checkStatusSetTargets({
522
+ activity,
523
+ activityNames,
524
+ path,
525
+ issues
526
+ }) {
527
+ checkStatusSetOps({ ops: activity.ops, activityNames, path: [...path, "ops"], issues });
406
528
  for (const [a, action] of (activity.actions ?? []).entries())
407
- checkStatusSetOps(action.ops, activityNames, [...path, "actions", a, "ops"], issues);
529
+ checkStatusSetOps({
530
+ ops: action.ops,
531
+ activityNames,
532
+ path: [...path, "actions", a, "ops"],
533
+ issues
534
+ });
408
535
  }
409
- function checkStatusSetOps(ops, activityNames, path, issues) {
536
+ function checkStatusSetOps({
537
+ ops,
538
+ activityNames,
539
+ path,
540
+ issues
541
+ }) {
410
542
  for (const [o, op] of (ops ?? []).entries())
411
543
  op.type !== "status.set" || activityNames.has(op.activity) || issues.push({
412
544
  path: [...path, o, "activity"],
413
545
  message: `status.set targets activity "${op.activity}" which is not declared in this stage. Known activities: ${knownList(activityNames)}`
414
546
  });
415
547
  }
416
- function checkInitialStage(def, stageNames, issues) {
548
+ function checkInitialStage({
549
+ def,
550
+ stageNames,
551
+ issues
552
+ }) {
417
553
  stageNames.has(def.initialStage) || issues.push({
418
554
  path: ["initialStage"],
419
555
  message: `initialStage "${def.initialStage}" is not a declared stage. Known stages: ${knownList(stageNames)}`
420
556
  });
421
557
  }
422
- function checkTransitionTargets(def, stageNames, issues) {
558
+ function checkTransitionTargets({
559
+ def,
560
+ stageNames,
561
+ issues
562
+ }) {
423
563
  for (const [i, stage] of def.stages.entries())
424
564
  for (const [k, t] of (stage.transitions ?? []).entries())
425
565
  stageNames.has(t.to) || issues.push({
@@ -431,20 +571,32 @@ function checkEffectNames(def, issues) {
431
571
  const sites = [];
432
572
  for (const [i, stage] of def.stages.entries()) {
433
573
  for (const [j, activity] of (stage.activities ?? []).entries()) {
434
- collectEffects(activity.effects, ["stages", i, "activities", j, "effects"], sites);
574
+ collectEffects({
575
+ effects: activity.effects,
576
+ path: ["stages", i, "activities", j, "effects"],
577
+ sites
578
+ });
435
579
  for (const [a, action] of (activity.actions ?? []).entries())
436
- collectEffects(
437
- action.effects,
438
- ["stages", i, "activities", j, "actions", a, "effects"],
580
+ collectEffects({
581
+ effects: action.effects,
582
+ path: ["stages", i, "activities", j, "actions", a, "effects"],
439
583
  sites
440
- );
584
+ });
441
585
  }
442
586
  for (const [k, t] of (stage.transitions ?? []).entries())
443
- collectEffects(t.effects, ["stages", i, "transitions", k, "effects"], sites);
587
+ collectEffects({ effects: t.effects, path: ["stages", i, "transitions", k, "effects"], sites });
444
588
  }
445
- checkDuplicates(sites, "effect name (registry key \u2014 unique per definition)", issues);
589
+ checkDuplicates({
590
+ names: sites,
591
+ what: "effect name (registry key \u2014 unique per definition)",
592
+ issues
593
+ });
446
594
  }
447
- function collectEffects(effects, path, sites) {
595
+ function collectEffects({
596
+ effects,
597
+ path,
598
+ sites
599
+ }) {
448
600
  for (const [e, effect] of (effects ?? []).entries())
449
601
  sites.push({ name: effect.name, path: [...path, e, "name"] });
450
602
  }
@@ -455,11 +607,11 @@ function checkGuardNames(def, issues) {
455
607
  path: ["stages", i, "guards", g, "name"]
456
608
  }))
457
609
  );
458
- checkDuplicates(
459
- sites,
460
- "guard name (the guard lake _id derives from it \u2014 unique per definition)",
610
+ checkDuplicates({
611
+ names: sites,
612
+ what: "guard name (the guard lake _id derives from it \u2014 unique per definition)",
461
613
  issues
462
- );
614
+ });
463
615
  }
464
616
  function fieldScopes(def) {
465
617
  const scopes = [
@@ -502,11 +654,11 @@ function checkRequiredField(def, issues) {
502
654
  }
503
655
  function checkFieldEntryNames(def, issues) {
504
656
  for (const { entries, path, label } of fieldScopes(def))
505
- checkDuplicates(
506
- (entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
507
- `field entry name in ${label}`,
657
+ checkDuplicates({
658
+ names: (entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
659
+ what: `field entry name in ${label}`,
508
660
  issues
509
- );
661
+ });
510
662
  }
511
663
  function checkPredicates(def, issues) {
512
664
  const reserved = new Set(RESERVED_CONDITION_VARS), names = Object.keys(def.predicates ?? {});
@@ -516,9 +668,14 @@ function checkPredicates(def, issues) {
516
668
  message: `predicate "${name}" shadows the built-in $${name} \u2014 pick another name`
517
669
  });
518
670
  for (const [name, groq2] of Object.entries(def.predicates ?? {}))
519
- checkPredicateBody(name, groq2, names, issues);
520
- }
521
- function checkPredicateBody(name, groq2, names, issues) {
671
+ checkPredicateBody({ name, groq: groq2, names, issues });
672
+ }
673
+ function checkPredicateBody({
674
+ name,
675
+ groq: groq2,
676
+ names,
677
+ issues
678
+ }) {
522
679
  for (const caller of PREDICATE_CALLER_VARS)
523
680
  referencesVar(groq2, caller) && issues.push({
524
681
  path: ["predicates", name],
@@ -548,33 +705,46 @@ function nonActionFilterConditionSites(def) {
548
705
  groq: t.filter,
549
706
  path: ["stages", i, "transitions", k, "filter"],
550
707
  label: `transition "${t.name}" filter`
551
- }), collectBindingSites(
552
- t.effects,
553
- ["stages", i, "transitions", k, "effects"],
554
- `transition "${t.name}"`,
708
+ }), collectBindingSites({
709
+ effects: t.effects,
710
+ path: ["stages", i, "transitions", k, "effects"],
711
+ label: `transition "${t.name}"`,
555
712
  sites
556
- );
713
+ });
557
714
  for (const [j, activity] of (stage.activities ?? []).entries())
558
- collectActivityConditionSites(activity, ["stages", i, "activities", j], sites);
715
+ collectActivityConditionSites({ activity, path: ["stages", i, "activities", j], sites });
559
716
  }
560
717
  return sites;
561
718
  }
562
- function collectActivityConditionSites(activity, path, sites) {
719
+ function collectActivityConditionSites({
720
+ activity,
721
+ path,
722
+ sites
723
+ }) {
563
724
  for (const field of ["filter", "completeWhen", "failWhen"]) {
564
725
  const groq2 = activity[field];
565
726
  groq2 !== void 0 && sites.push({ groq: groq2, path: [...path, field], label: `activity "${activity.name}".${field}` });
566
727
  }
567
- collectBindingSites(activity.effects, [...path, "effects"], `activity "${activity.name}"`, sites);
728
+ collectBindingSites({
729
+ effects: activity.effects,
730
+ path: [...path, "effects"],
731
+ label: `activity "${activity.name}"`,
732
+ sites
733
+ });
568
734
  for (const [a, action] of (activity.actions ?? []).entries())
569
- collectBindingSites(
570
- action.effects,
571
- [...path, "actions", a, "effects"],
572
- `action "${action.name}"`,
735
+ collectBindingSites({
736
+ effects: action.effects,
737
+ path: [...path, "actions", a, "effects"],
738
+ label: `action "${action.name}"`,
573
739
  sites
574
- );
575
- collectSubworkflowSites(activity, path, sites);
740
+ });
741
+ collectSubworkflowSites({ activity, path, sites });
576
742
  }
577
- function collectSubworkflowSites(activity, path, sites) {
743
+ function collectSubworkflowSites({
744
+ activity,
745
+ path,
746
+ sites
747
+ }) {
578
748
  const sub = activity.subworkflows;
579
749
  if (sub === void 0) return;
580
750
  const subPath = [...path, "subworkflows"];
@@ -594,7 +764,12 @@ function collectSubworkflowSites(activity, path, sites) {
594
764
  label: `activity "${activity.name}".subworkflows.${group} "${key}"`
595
765
  });
596
766
  }
597
- function collectBindingSites(effects, path, label, sites) {
767
+ function collectBindingSites({
768
+ effects,
769
+ path,
770
+ label,
771
+ sites
772
+ }) {
598
773
  for (const [e, effect] of (effects ?? []).entries())
599
774
  for (const [key, groq2] of Object.entries(effect.bindings ?? {}))
600
775
  sites.push({
@@ -652,36 +827,60 @@ function checkActivityKinds(def, issues) {
652
827
  }
653
828
  function checkWorkflowInvariants(def) {
654
829
  const issues = [], stageNames = checkStages(def, issues);
655
- return checkInitialStage(def, stageNames, issues), checkTransitionTargets(def, stageNames, issues), checkEffectNames(def, issues), checkGuardNames(def, issues), checkFieldEntryNames(def, issues), checkRequiredField(def, issues), checkPredicates(def, issues), checkCanOutsideActionFilters(def, issues), checkAssigneesEntries(def, issues), checkActivityKinds(def, issues), issues;
830
+ return checkInitialStage({ def, stageNames, issues }), checkTransitionTargets({ def, stageNames, issues }), checkEffectNames(def, issues), checkGuardNames(def, issues), checkFieldEntryNames(def, issues), checkRequiredField(def, issues), checkPredicates(def, issues), checkCanOutsideActionFilters(def, issues), checkAssigneesEntries(def, issues), checkActivityKinds(def, issues), issues;
656
831
  }
657
832
  function defineWorkflow(definition) {
658
- const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow(AuthoringWorkflowSchema, definition, label), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
833
+ const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow({ schema: AuthoringWorkflowSchema, input: definition, label }), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
659
834
  if (issues.length > 0) throw new Error(formatValidationError(label, issues));
660
835
  return stored;
661
836
  }
662
837
  function defineStage(stage) {
663
- return parseOrThrow(AuthoringStageSchema, stage, labelFor("defineStage", stage));
838
+ return parseOrThrow({
839
+ schema: AuthoringStageSchema,
840
+ input: stage,
841
+ label: labelFor("defineStage", stage)
842
+ });
664
843
  }
665
844
  function defineActivity(activity) {
666
- return parseOrThrow(AuthoringActivitySchema, activity, labelFor("defineActivity", activity));
845
+ return parseOrThrow({
846
+ schema: AuthoringActivitySchema,
847
+ input: activity,
848
+ label: labelFor("defineActivity", activity)
849
+ });
667
850
  }
668
851
  function defineAction(action) {
669
- return parseOrThrow(AuthoringActionSchema, action, labelFor("defineAction", action));
852
+ return parseOrThrow({
853
+ schema: AuthoringActionSchema,
854
+ input: action,
855
+ label: labelFor("defineAction", action)
856
+ });
670
857
  }
671
858
  function defineTransition(transition) {
672
- return parseOrThrow(AuthoringTransitionSchema, transition, transitionLabel(transition));
859
+ return parseOrThrow({
860
+ schema: AuthoringTransitionSchema,
861
+ input: transition,
862
+ label: transitionLabel(transition)
863
+ });
673
864
  }
674
865
  function defineField(entry) {
675
- return parseOrThrow(AuthoringFieldEntrySchema, entry, labelFor("defineField", entry));
866
+ return parseOrThrow({
867
+ schema: AuthoringFieldEntrySchema,
868
+ input: entry,
869
+ label: labelFor("defineField", entry)
870
+ });
676
871
  }
677
872
  function defineOp(op) {
678
- return parseOrThrow(AuthoringOpSchema, op, "defineOp");
873
+ return parseOrThrow({ schema: AuthoringOpSchema, input: op, label: "defineOp" });
679
874
  }
680
875
  function defineGuard(guard) {
681
- return parseOrThrow(GuardSchema, guard, labelFor("defineGuard", guard));
876
+ return parseOrThrow({ schema: GuardSchema, input: guard, label: labelFor("defineGuard", guard) });
682
877
  }
683
878
  function defineEffect(effect) {
684
- return parseOrThrow(EffectSchema, effect, labelFor("defineEffect", effect));
879
+ return parseOrThrow({
880
+ schema: EffectSchema,
881
+ input: effect,
882
+ label: labelFor("defineEffect", effect)
883
+ });
685
884
  }
686
885
  function transitionLabel(transition) {
687
886
  const { name, to } = transition;
@@ -691,7 +890,11 @@ function defineEffectDescriptor(descriptor) {
691
890
  if (!descriptor.name) throw new Error("EffectDescriptor missing name");
692
891
  return descriptor;
693
892
  }
694
- function parseOrThrow(schema, input, label) {
893
+ function parseOrThrow({
894
+ schema,
895
+ input,
896
+ label
897
+ }) {
695
898
  const result = v.safeParse(schema, input);
696
899
  if (!result.success)
697
900
  throw new Error(formatValidationError(label, issuesFromValibot(result.issues)));