@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/_chunks-cjs/schema.cjs +97 -55
- package/dist/_chunks-cjs/schema.cjs.map +1 -1
- package/dist/_chunks-es/schema.js +97 -55
- package/dist/_chunks-es/schema.js.map +1 -1
- package/dist/define.cjs +321 -118
- package/dist/define.cjs.map +1 -1
- package/dist/define.d.cts +1305 -12045
- package/dist/define.d.ts +1305 -12045
- package/dist/define.js +321 -118
- package/dist/define.js.map +1 -1
- package/dist/index.cjs +1345 -642
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1166 -15587
- package/dist/index.d.ts +1166 -15587
- package/dist/index.js +1346 -643
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/define.cjs
CHANGED
|
@@ -36,22 +36,22 @@ function desugarWorkflow(authoring) {
|
|
|
36
36
|
claimFields: /* @__PURE__ */ new Map(),
|
|
37
37
|
claimedFields: /* @__PURE__ */ new Set(),
|
|
38
38
|
roleAliases
|
|
39
|
-
}, workflowFields = desugarFieldEntries(authoring.fields, ["fields"], ctx), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
|
|
40
|
-
const path = ["stages", i], stageFields = desugarFieldEntries(stage.fields, [...path, "fields"], ctx), stageEnv = {
|
|
39
|
+
}, workflowFields = desugarFieldEntries({ entries: authoring.fields, path: ["fields"], ctx }), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
|
|
40
|
+
const path = ["stages", i], stageFields = desugarFieldEntries({ entries: stage.fields, path: [...path, "fields"], ctx }), stageEnv = {
|
|
41
41
|
layers: [
|
|
42
42
|
{ scope: "stage", entries: layerOf(stageFields) },
|
|
43
43
|
{ scope: "workflow", entries: workflowLayer }
|
|
44
44
|
]
|
|
45
45
|
}, activities = (stage.activities ?? []).map(
|
|
46
|
-
(activity, j) => desugarActivity(activity, [...path, "activities", j], stageEnv, ctx)
|
|
46
|
+
(activity, j) => desugarActivity({ activity, path: [...path, "activities", j], stageEnv, ctx })
|
|
47
47
|
), transitions = (stage.transitions ?? []).map(
|
|
48
|
-
(transition, k) => desugarTransition(transition, [...path, "transitions", k], stageEnv, ctx)
|
|
49
|
-
), editable = desugarStageEditable(
|
|
50
|
-
stage.editable,
|
|
51
|
-
editableSlotNames(workflowFields, stageFields, activities),
|
|
52
|
-
[...path, "editable"],
|
|
48
|
+
(transition, k) => desugarTransition({ transition, path: [...path, "transitions", k], stageEnv, ctx })
|
|
49
|
+
), editable = desugarStageEditable({
|
|
50
|
+
overrides: stage.editable,
|
|
51
|
+
inScope: editableSlotNames({ workflowFields, stageFields, activities }),
|
|
52
|
+
path: [...path, "editable"],
|
|
53
53
|
ctx
|
|
54
|
-
);
|
|
54
|
+
});
|
|
55
55
|
return {
|
|
56
56
|
...stripUndefined({
|
|
57
57
|
name: stage.name,
|
|
@@ -96,13 +96,22 @@ const TODOLIST_OF = [
|
|
|
96
96
|
{ type: "actor", name: "actor", title: "Actor" },
|
|
97
97
|
{ type: "datetime", name: "at", title: "At" }
|
|
98
98
|
];
|
|
99
|
-
function desugarFieldEntries(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
function desugarFieldEntries({
|
|
100
|
+
entries,
|
|
101
|
+
path,
|
|
102
|
+
ctx
|
|
103
|
+
}) {
|
|
104
|
+
return !entries || entries.length === 0 ? entries === void 0 ? void 0 : [] : entries.map((entry, i) => desugarFieldEntry({ entry, path: [...path, i], ctx }));
|
|
105
|
+
}
|
|
106
|
+
function desugarFieldEntry({
|
|
107
|
+
entry,
|
|
108
|
+
path,
|
|
109
|
+
ctx
|
|
110
|
+
}) {
|
|
111
|
+
if (entry.type === "claim") return desugarClaimField({ entry, path, ctx });
|
|
112
|
+
if (entry.type === "todoList" || entry.type === "notes")
|
|
113
|
+
return desugarListField({ entry, path, ctx });
|
|
114
|
+
const editable = normalizeEditable({ editable: entry.editable, path: [...path, "editable"], ctx });
|
|
106
115
|
return {
|
|
107
116
|
...stripUndefined({
|
|
108
117
|
type: entry.type,
|
|
@@ -117,15 +126,23 @@ function desugarFieldEntry(entry, path, ctx) {
|
|
|
117
126
|
})
|
|
118
127
|
};
|
|
119
128
|
}
|
|
120
|
-
function desugarClaimField(
|
|
129
|
+
function desugarClaimField({
|
|
130
|
+
entry,
|
|
131
|
+
path,
|
|
132
|
+
ctx
|
|
133
|
+
}) {
|
|
121
134
|
const desugared = {
|
|
122
135
|
...stripUndefined({ name: entry.name, title: entry.title, description: entry.description }),
|
|
123
136
|
type: "actor"
|
|
124
137
|
};
|
|
125
138
|
return ctx.claimFields.set(desugared, { name: entry.name, path }), desugared;
|
|
126
139
|
}
|
|
127
|
-
function desugarListField(
|
|
128
|
-
|
|
140
|
+
function desugarListField({
|
|
141
|
+
entry,
|
|
142
|
+
path,
|
|
143
|
+
ctx
|
|
144
|
+
}) {
|
|
145
|
+
const editable = normalizeEditable({ editable: entry.editable, path: [...path, "editable"], ctx });
|
|
129
146
|
return {
|
|
130
147
|
...stripUndefined({
|
|
131
148
|
name: entry.name,
|
|
@@ -139,7 +156,11 @@ function desugarListField(entry, path, ctx) {
|
|
|
139
156
|
of: entry.type === "todoList" ? TODOLIST_OF : NOTES_OF
|
|
140
157
|
};
|
|
141
158
|
}
|
|
142
|
-
function normalizeEditable(
|
|
159
|
+
function normalizeEditable({
|
|
160
|
+
editable,
|
|
161
|
+
path,
|
|
162
|
+
ctx
|
|
163
|
+
}) {
|
|
143
164
|
if (editable === void 0 || editable === !0) return editable;
|
|
144
165
|
if (Array.isArray(editable)) {
|
|
145
166
|
const condition = rolesCondition(editable, ctx.roleAliases);
|
|
@@ -154,7 +175,11 @@ function normalizeEditable(editable, path, ctx) {
|
|
|
154
175
|
}
|
|
155
176
|
return editable;
|
|
156
177
|
}
|
|
157
|
-
function editableSlotNames(
|
|
178
|
+
function editableSlotNames({
|
|
179
|
+
workflowFields,
|
|
180
|
+
stageFields,
|
|
181
|
+
activities
|
|
182
|
+
}) {
|
|
158
183
|
const names = /* @__PURE__ */ new Set(), collect = (entries) => {
|
|
159
184
|
for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
|
|
160
185
|
};
|
|
@@ -162,7 +187,12 @@ function editableSlotNames(workflowFields, stageFields, activities) {
|
|
|
162
187
|
for (const activity of activities) collect(activity.fields);
|
|
163
188
|
return names;
|
|
164
189
|
}
|
|
165
|
-
function desugarStageEditable(
|
|
190
|
+
function desugarStageEditable({
|
|
191
|
+
overrides,
|
|
192
|
+
inScope,
|
|
193
|
+
path,
|
|
194
|
+
ctx
|
|
195
|
+
}) {
|
|
166
196
|
if (overrides === void 0) return;
|
|
167
197
|
const out = {};
|
|
168
198
|
for (const [name, value] of Object.entries(overrides)) {
|
|
@@ -173,7 +203,7 @@ function desugarStageEditable(overrides, inScope, path, ctx) {
|
|
|
173
203
|
});
|
|
174
204
|
continue;
|
|
175
205
|
}
|
|
176
|
-
const normalized = normalizeEditable(value, [...path, name], ctx);
|
|
206
|
+
const normalized = normalizeEditable({ editable: value, path: [...path, name], ctx });
|
|
177
207
|
normalized !== void 0 && (out[name] = normalized);
|
|
178
208
|
}
|
|
179
209
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
@@ -181,12 +211,27 @@ function desugarStageEditable(overrides, inScope, path, ctx) {
|
|
|
181
211
|
function layerOf(entries) {
|
|
182
212
|
return new Map((entries ?? []).map((entry) => [entry.name, entry]));
|
|
183
213
|
}
|
|
184
|
-
function desugarActivity(
|
|
185
|
-
|
|
214
|
+
function desugarActivity({
|
|
215
|
+
activity,
|
|
216
|
+
path,
|
|
217
|
+
stageEnv,
|
|
218
|
+
ctx
|
|
219
|
+
}) {
|
|
220
|
+
const activityFields = desugarFieldEntries({
|
|
221
|
+
entries: activity.fields,
|
|
222
|
+
path: [...path, "fields"],
|
|
223
|
+
ctx
|
|
224
|
+
}), env = {
|
|
186
225
|
layers: [{ scope: "activity", entries: layerOf(activityFields) }, ...stageEnv.layers]
|
|
187
|
-
}, ops = desugarOps(
|
|
188
|
-
|
|
189
|
-
|
|
226
|
+
}, ops = desugarOps({
|
|
227
|
+
ops: activity.ops,
|
|
228
|
+
path: [...path, "ops"],
|
|
229
|
+
env,
|
|
230
|
+
firingActivity: activity.name,
|
|
231
|
+
ctx
|
|
232
|
+
}), actions = (activity.actions ?? []).map(
|
|
233
|
+
(action, a) => desugarAction({ action, path: [...path, "actions", a], env, activityName: activity.name, ctx })
|
|
234
|
+
), target = desugarTarget({ target: activity.target, env, path: [...path, "target"], ctx });
|
|
190
235
|
return {
|
|
191
236
|
...stripUndefined({
|
|
192
237
|
name: activity.name,
|
|
@@ -208,18 +253,29 @@ function desugarActivity(activity, path, stageEnv, ctx) {
|
|
|
208
253
|
};
|
|
209
254
|
}
|
|
210
255
|
const TARGET_DOC_KINDS = ["doc.ref", "doc.refs", "release.ref"];
|
|
211
|
-
function desugarTarget(
|
|
256
|
+
function desugarTarget({
|
|
257
|
+
target,
|
|
258
|
+
env,
|
|
259
|
+
path,
|
|
260
|
+
ctx
|
|
261
|
+
}) {
|
|
212
262
|
if (target === void 0 || target.type === "url") return target;
|
|
213
|
-
const ref = typeof target.field == "string" ? { field: target.field } : target.field, field = resolveRef(ref, env, [...path, "field"], ctx) ?? fallbackRef(ref), entry = entryAt(env, field);
|
|
263
|
+
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);
|
|
214
264
|
return entry && !TARGET_DOC_KINDS.includes(entry.type) && ctx.issues.push({
|
|
215
265
|
path: [...path, "field"],
|
|
216
266
|
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(", ")})`
|
|
217
267
|
}), { type: "field", field };
|
|
218
268
|
}
|
|
219
|
-
function desugarAction(
|
|
269
|
+
function desugarAction({
|
|
270
|
+
action,
|
|
271
|
+
path,
|
|
272
|
+
env,
|
|
273
|
+
activityName,
|
|
274
|
+
ctx
|
|
275
|
+
}) {
|
|
220
276
|
if ("type" in action)
|
|
221
|
-
return desugarClaimAction(action, path, env, ctx);
|
|
222
|
-
const filter = schema.andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps(action.ops, [...path, "ops"], env, activityName, ctx) ?? [];
|
|
277
|
+
return desugarClaimAction({ action, path, env, ctx });
|
|
278
|
+
const filter = schema.andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps({ ops: action.ops, path: [...path, "ops"], env, firingActivity: activityName, ctx }) ?? [];
|
|
223
279
|
return action.status !== void 0 && ops.push({ type: "status.set", activity: activityName, status: action.status }), {
|
|
224
280
|
...stripUndefined({
|
|
225
281
|
name: action.name,
|
|
@@ -232,14 +288,26 @@ function desugarAction(action, path, env, activityName, ctx) {
|
|
|
232
288
|
...ops.length > 0 ? { ops } : {}
|
|
233
289
|
};
|
|
234
290
|
}
|
|
235
|
-
function desugarClaimAction(
|
|
236
|
-
|
|
291
|
+
function desugarClaimAction({
|
|
292
|
+
action,
|
|
293
|
+
path,
|
|
294
|
+
env,
|
|
295
|
+
ctx
|
|
296
|
+
}) {
|
|
297
|
+
const ref = typeof action.field == "string" ? { field: action.field } : action.field, resolved = resolveRef({ ref, env, path: [...path, "field"], ctx });
|
|
237
298
|
if (resolved) {
|
|
238
299
|
const entry = entryAt(env, resolved);
|
|
239
300
|
entry && entry.type !== "actor" && ctx.issues.push({
|
|
240
301
|
path: [...path, "field"],
|
|
241
302
|
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)`
|
|
242
|
-
}), checkShadowedClaimTarget(
|
|
303
|
+
}), checkShadowedClaimTarget({
|
|
304
|
+
actionName: action.name,
|
|
305
|
+
field: ref.field,
|
|
306
|
+
resolved,
|
|
307
|
+
env,
|
|
308
|
+
path: [...path, "field"],
|
|
309
|
+
ctx
|
|
310
|
+
}), entry && ctx.claimedFields.add(entry);
|
|
243
311
|
}
|
|
244
312
|
const noSteal = `!defined($fields.${ref.field})`, filter = schema.andConditions([
|
|
245
313
|
noSteal,
|
|
@@ -258,7 +326,14 @@ function desugarClaimAction(action, path, env, ctx) {
|
|
|
258
326
|
...ops.length > 0 ? { ops } : {}
|
|
259
327
|
};
|
|
260
328
|
}
|
|
261
|
-
function checkShadowedClaimTarget(
|
|
329
|
+
function checkShadowedClaimTarget({
|
|
330
|
+
actionName,
|
|
331
|
+
field,
|
|
332
|
+
resolved,
|
|
333
|
+
env,
|
|
334
|
+
path,
|
|
335
|
+
ctx
|
|
336
|
+
}) {
|
|
262
337
|
const nearest = env.layers.find((l) => l.entries.has(field));
|
|
263
338
|
nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
|
|
264
339
|
path,
|
|
@@ -272,8 +347,19 @@ function checkUnclaimedClaimFields(ctx) {
|
|
|
272
347
|
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`
|
|
273
348
|
});
|
|
274
349
|
}
|
|
275
|
-
function desugarTransition(
|
|
276
|
-
|
|
350
|
+
function desugarTransition({
|
|
351
|
+
transition,
|
|
352
|
+
path,
|
|
353
|
+
stageEnv,
|
|
354
|
+
ctx
|
|
355
|
+
}) {
|
|
356
|
+
const ops = desugarOps({
|
|
357
|
+
ops: transition.ops,
|
|
358
|
+
path: [...path, "ops"],
|
|
359
|
+
env: stageEnv,
|
|
360
|
+
firingActivity: void 0,
|
|
361
|
+
ctx
|
|
362
|
+
});
|
|
277
363
|
return {
|
|
278
364
|
...stripUndefined({
|
|
279
365
|
name: transition.name,
|
|
@@ -286,11 +372,23 @@ function desugarTransition(transition, path, stageEnv, ctx) {
|
|
|
286
372
|
...ops ? { ops } : {}
|
|
287
373
|
};
|
|
288
374
|
}
|
|
289
|
-
function desugarOps(
|
|
375
|
+
function desugarOps({
|
|
376
|
+
ops,
|
|
377
|
+
path,
|
|
378
|
+
env,
|
|
379
|
+
firingActivity,
|
|
380
|
+
ctx
|
|
381
|
+
}) {
|
|
290
382
|
if (ops)
|
|
291
|
-
return ops.map((op, i) => desugarOp(op, [...path, i], env, firingActivity, ctx));
|
|
292
|
-
}
|
|
293
|
-
function desugarOp(
|
|
383
|
+
return ops.map((op, i) => desugarOp({ op, path: [...path, i], env, firingActivity, ctx }));
|
|
384
|
+
}
|
|
385
|
+
function desugarOp({
|
|
386
|
+
op,
|
|
387
|
+
path,
|
|
388
|
+
env,
|
|
389
|
+
firingActivity,
|
|
390
|
+
ctx
|
|
391
|
+
}) {
|
|
294
392
|
if (op.type === "status.set") {
|
|
295
393
|
const activity = op.activity ?? firingActivity;
|
|
296
394
|
return activity === void 0 && ctx.issues.push({
|
|
@@ -298,13 +396,18 @@ function desugarOp(op, path, env, firingActivity, ctx) {
|
|
|
298
396
|
message: "status.set outside an action must name its target activity"
|
|
299
397
|
}), { type: "status.set", activity: activity ?? "", status: op.status };
|
|
300
398
|
}
|
|
301
|
-
if (op.type === "audit") return desugarAuditOp(op, path, env, ctx);
|
|
302
|
-
const target = resolveRef(op.target, env, [...path, "target"], ctx) ?? fallbackRef(op.target);
|
|
399
|
+
if (op.type === "audit") return desugarAuditOp({ op, path, env, ctx });
|
|
400
|
+
const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
|
|
303
401
|
return { ...op, target };
|
|
304
402
|
}
|
|
305
403
|
const AUDIT_STAMPS = { actor: { type: "actor" }, at: { type: "now" } };
|
|
306
|
-
function desugarAuditOp(
|
|
307
|
-
|
|
404
|
+
function desugarAuditOp({
|
|
405
|
+
op,
|
|
406
|
+
path,
|
|
407
|
+
env,
|
|
408
|
+
ctx
|
|
409
|
+
}) {
|
|
410
|
+
const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
|
|
308
411
|
if (op.value.type !== "object")
|
|
309
412
|
return ctx.issues.push({
|
|
310
413
|
path: [...path, "value"],
|
|
@@ -326,7 +429,12 @@ function desugarAuditOp(op, path, env, ctx) {
|
|
|
326
429
|
}
|
|
327
430
|
return { type: "field.append", target, value: { type: "object", fields } };
|
|
328
431
|
}
|
|
329
|
-
function resolveRef(
|
|
432
|
+
function resolveRef({
|
|
433
|
+
ref,
|
|
434
|
+
env,
|
|
435
|
+
path,
|
|
436
|
+
ctx
|
|
437
|
+
}) {
|
|
330
438
|
const layers = ref.scope === void 0 ? env.layers : env.layers.filter((l) => l.scope === ref.scope);
|
|
331
439
|
for (const layer of layers)
|
|
332
440
|
if (layer.entries.has(ref.field)) return { scope: layer.scope, field: ref.field };
|
|
@@ -372,71 +480,103 @@ const RESERVED_CONDITION_VARS = [
|
|
|
372
480
|
function knownList(ids) {
|
|
373
481
|
return [...ids].map((s) => `"${s}"`).join(", ");
|
|
374
482
|
}
|
|
375
|
-
function checkDuplicates(
|
|
483
|
+
function checkDuplicates({
|
|
484
|
+
names,
|
|
485
|
+
what,
|
|
486
|
+
issues
|
|
487
|
+
}) {
|
|
376
488
|
const seen = /* @__PURE__ */ new Set();
|
|
377
489
|
for (const { name, path } of names)
|
|
378
490
|
seen.has(name) && issues.push({ path, message: `duplicate ${what} "${name}" (already declared earlier)` }), seen.add(name);
|
|
379
491
|
return seen;
|
|
380
492
|
}
|
|
381
493
|
function checkStages(def, issues) {
|
|
382
|
-
const stageNames = checkDuplicates(
|
|
383
|
-
def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
|
|
384
|
-
"stage name",
|
|
494
|
+
const stageNames = checkDuplicates({
|
|
495
|
+
names: def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
|
|
496
|
+
what: "stage name",
|
|
385
497
|
issues
|
|
386
|
-
);
|
|
498
|
+
});
|
|
387
499
|
for (const [i, stage] of def.stages.entries()) {
|
|
388
|
-
const activityNames = checkDuplicates(
|
|
389
|
-
(stage.activities ?? []).map((activity, j) => ({
|
|
500
|
+
const activityNames = checkDuplicates({
|
|
501
|
+
names: (stage.activities ?? []).map((activity, j) => ({
|
|
390
502
|
name: activity.name,
|
|
391
503
|
path: ["stages", i, "activities", j, "name"]
|
|
392
504
|
})),
|
|
393
|
-
`activity name in stage "${stage.name}"`,
|
|
505
|
+
what: `activity name in stage "${stage.name}"`,
|
|
394
506
|
issues
|
|
395
|
-
);
|
|
396
|
-
checkDuplicates(
|
|
397
|
-
(stage.transitions ?? []).map((t, k) => ({
|
|
507
|
+
});
|
|
508
|
+
checkDuplicates({
|
|
509
|
+
names: (stage.transitions ?? []).map((t, k) => ({
|
|
398
510
|
name: t.name,
|
|
399
511
|
path: ["stages", i, "transitions", k, "name"]
|
|
400
512
|
})),
|
|
401
|
-
`transition name in stage "${stage.name}"`,
|
|
513
|
+
what: `transition name in stage "${stage.name}"`,
|
|
402
514
|
issues
|
|
403
|
-
), checkActivities(def, i, activityNames, issues);
|
|
515
|
+
}), checkActivities({ def, i, activityNames, issues });
|
|
404
516
|
}
|
|
405
517
|
return stageNames;
|
|
406
518
|
}
|
|
407
|
-
function checkActivities(
|
|
519
|
+
function checkActivities({
|
|
520
|
+
def,
|
|
521
|
+
i,
|
|
522
|
+
activityNames,
|
|
523
|
+
issues
|
|
524
|
+
}) {
|
|
408
525
|
const stage = def.stages[i];
|
|
409
526
|
for (const [j, activity] of (stage.activities ?? []).entries()) {
|
|
410
527
|
const path = ["stages", i, "activities", j];
|
|
411
|
-
checkDuplicates(
|
|
412
|
-
(activity.actions ?? []).map((action, a) => ({
|
|
528
|
+
checkDuplicates({
|
|
529
|
+
names: (activity.actions ?? []).map((action, a) => ({
|
|
413
530
|
name: action.name,
|
|
414
531
|
path: [...path, "actions", a, "name"]
|
|
415
532
|
})),
|
|
416
|
-
`action name in activity "${activity.name}"`,
|
|
533
|
+
what: `action name in activity "${activity.name}"`,
|
|
417
534
|
issues
|
|
418
|
-
), checkStatusSetTargets(activity, activityNames, path, issues);
|
|
535
|
+
}), checkStatusSetTargets({ activity, activityNames, path, issues });
|
|
419
536
|
}
|
|
420
537
|
}
|
|
421
|
-
function checkStatusSetTargets(
|
|
422
|
-
|
|
538
|
+
function checkStatusSetTargets({
|
|
539
|
+
activity,
|
|
540
|
+
activityNames,
|
|
541
|
+
path,
|
|
542
|
+
issues
|
|
543
|
+
}) {
|
|
544
|
+
checkStatusSetOps({ ops: activity.ops, activityNames, path: [...path, "ops"], issues });
|
|
423
545
|
for (const [a, action] of (activity.actions ?? []).entries())
|
|
424
|
-
checkStatusSetOps(
|
|
546
|
+
checkStatusSetOps({
|
|
547
|
+
ops: action.ops,
|
|
548
|
+
activityNames,
|
|
549
|
+
path: [...path, "actions", a, "ops"],
|
|
550
|
+
issues
|
|
551
|
+
});
|
|
425
552
|
}
|
|
426
|
-
function checkStatusSetOps(
|
|
553
|
+
function checkStatusSetOps({
|
|
554
|
+
ops,
|
|
555
|
+
activityNames,
|
|
556
|
+
path,
|
|
557
|
+
issues
|
|
558
|
+
}) {
|
|
427
559
|
for (const [o, op] of (ops ?? []).entries())
|
|
428
560
|
op.type !== "status.set" || activityNames.has(op.activity) || issues.push({
|
|
429
561
|
path: [...path, o, "activity"],
|
|
430
562
|
message: `status.set targets activity "${op.activity}" which is not declared in this stage. Known activities: ${knownList(activityNames)}`
|
|
431
563
|
});
|
|
432
564
|
}
|
|
433
|
-
function checkInitialStage(
|
|
565
|
+
function checkInitialStage({
|
|
566
|
+
def,
|
|
567
|
+
stageNames,
|
|
568
|
+
issues
|
|
569
|
+
}) {
|
|
434
570
|
stageNames.has(def.initialStage) || issues.push({
|
|
435
571
|
path: ["initialStage"],
|
|
436
572
|
message: `initialStage "${def.initialStage}" is not a declared stage. Known stages: ${knownList(stageNames)}`
|
|
437
573
|
});
|
|
438
574
|
}
|
|
439
|
-
function checkTransitionTargets(
|
|
575
|
+
function checkTransitionTargets({
|
|
576
|
+
def,
|
|
577
|
+
stageNames,
|
|
578
|
+
issues
|
|
579
|
+
}) {
|
|
440
580
|
for (const [i, stage] of def.stages.entries())
|
|
441
581
|
for (const [k, t] of (stage.transitions ?? []).entries())
|
|
442
582
|
stageNames.has(t.to) || issues.push({
|
|
@@ -448,20 +588,32 @@ function checkEffectNames(def, issues) {
|
|
|
448
588
|
const sites = [];
|
|
449
589
|
for (const [i, stage] of def.stages.entries()) {
|
|
450
590
|
for (const [j, activity] of (stage.activities ?? []).entries()) {
|
|
451
|
-
collectEffects(
|
|
591
|
+
collectEffects({
|
|
592
|
+
effects: activity.effects,
|
|
593
|
+
path: ["stages", i, "activities", j, "effects"],
|
|
594
|
+
sites
|
|
595
|
+
});
|
|
452
596
|
for (const [a, action] of (activity.actions ?? []).entries())
|
|
453
|
-
collectEffects(
|
|
454
|
-
action.effects,
|
|
455
|
-
["stages", i, "activities", j, "actions", a, "effects"],
|
|
597
|
+
collectEffects({
|
|
598
|
+
effects: action.effects,
|
|
599
|
+
path: ["stages", i, "activities", j, "actions", a, "effects"],
|
|
456
600
|
sites
|
|
457
|
-
);
|
|
601
|
+
});
|
|
458
602
|
}
|
|
459
603
|
for (const [k, t] of (stage.transitions ?? []).entries())
|
|
460
|
-
collectEffects(t.effects, ["stages", i, "transitions", k, "effects"], sites);
|
|
604
|
+
collectEffects({ effects: t.effects, path: ["stages", i, "transitions", k, "effects"], sites });
|
|
461
605
|
}
|
|
462
|
-
checkDuplicates(
|
|
606
|
+
checkDuplicates({
|
|
607
|
+
names: sites,
|
|
608
|
+
what: "effect name (registry key \u2014 unique per definition)",
|
|
609
|
+
issues
|
|
610
|
+
});
|
|
463
611
|
}
|
|
464
|
-
function collectEffects(
|
|
612
|
+
function collectEffects({
|
|
613
|
+
effects,
|
|
614
|
+
path,
|
|
615
|
+
sites
|
|
616
|
+
}) {
|
|
465
617
|
for (const [e, effect] of (effects ?? []).entries())
|
|
466
618
|
sites.push({ name: effect.name, path: [...path, e, "name"] });
|
|
467
619
|
}
|
|
@@ -472,11 +624,11 @@ function checkGuardNames(def, issues) {
|
|
|
472
624
|
path: ["stages", i, "guards", g, "name"]
|
|
473
625
|
}))
|
|
474
626
|
);
|
|
475
|
-
checkDuplicates(
|
|
476
|
-
sites,
|
|
477
|
-
"guard name (the guard lake _id derives from it \u2014 unique per definition)",
|
|
627
|
+
checkDuplicates({
|
|
628
|
+
names: sites,
|
|
629
|
+
what: "guard name (the guard lake _id derives from it \u2014 unique per definition)",
|
|
478
630
|
issues
|
|
479
|
-
);
|
|
631
|
+
});
|
|
480
632
|
}
|
|
481
633
|
function fieldScopes(def) {
|
|
482
634
|
const scopes = [
|
|
@@ -519,11 +671,11 @@ function checkRequiredField(def, issues) {
|
|
|
519
671
|
}
|
|
520
672
|
function checkFieldEntryNames(def, issues) {
|
|
521
673
|
for (const { entries, path, label } of fieldScopes(def))
|
|
522
|
-
checkDuplicates(
|
|
523
|
-
(entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
|
|
524
|
-
`field entry name in ${label}`,
|
|
674
|
+
checkDuplicates({
|
|
675
|
+
names: (entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
|
|
676
|
+
what: `field entry name in ${label}`,
|
|
525
677
|
issues
|
|
526
|
-
);
|
|
678
|
+
});
|
|
527
679
|
}
|
|
528
680
|
function checkPredicates(def, issues) {
|
|
529
681
|
const reserved = new Set(RESERVED_CONDITION_VARS), names = Object.keys(def.predicates ?? {});
|
|
@@ -533,9 +685,14 @@ function checkPredicates(def, issues) {
|
|
|
533
685
|
message: `predicate "${name}" shadows the built-in $${name} \u2014 pick another name`
|
|
534
686
|
});
|
|
535
687
|
for (const [name, groq2] of Object.entries(def.predicates ?? {}))
|
|
536
|
-
checkPredicateBody(name, groq2, names, issues);
|
|
537
|
-
}
|
|
538
|
-
function checkPredicateBody(
|
|
688
|
+
checkPredicateBody({ name, groq: groq2, names, issues });
|
|
689
|
+
}
|
|
690
|
+
function checkPredicateBody({
|
|
691
|
+
name,
|
|
692
|
+
groq: groq2,
|
|
693
|
+
names,
|
|
694
|
+
issues
|
|
695
|
+
}) {
|
|
539
696
|
for (const caller of PREDICATE_CALLER_VARS)
|
|
540
697
|
referencesVar(groq2, caller) && issues.push({
|
|
541
698
|
path: ["predicates", name],
|
|
@@ -565,33 +722,46 @@ function nonActionFilterConditionSites(def) {
|
|
|
565
722
|
groq: t.filter,
|
|
566
723
|
path: ["stages", i, "transitions", k, "filter"],
|
|
567
724
|
label: `transition "${t.name}" filter`
|
|
568
|
-
}), collectBindingSites(
|
|
569
|
-
t.effects,
|
|
570
|
-
["stages", i, "transitions", k, "effects"],
|
|
571
|
-
`transition "${t.name}"`,
|
|
725
|
+
}), collectBindingSites({
|
|
726
|
+
effects: t.effects,
|
|
727
|
+
path: ["stages", i, "transitions", k, "effects"],
|
|
728
|
+
label: `transition "${t.name}"`,
|
|
572
729
|
sites
|
|
573
|
-
);
|
|
730
|
+
});
|
|
574
731
|
for (const [j, activity] of (stage.activities ?? []).entries())
|
|
575
|
-
collectActivityConditionSites(activity, ["stages", i, "activities", j], sites);
|
|
732
|
+
collectActivityConditionSites({ activity, path: ["stages", i, "activities", j], sites });
|
|
576
733
|
}
|
|
577
734
|
return sites;
|
|
578
735
|
}
|
|
579
|
-
function collectActivityConditionSites(
|
|
736
|
+
function collectActivityConditionSites({
|
|
737
|
+
activity,
|
|
738
|
+
path,
|
|
739
|
+
sites
|
|
740
|
+
}) {
|
|
580
741
|
for (const field of ["filter", "completeWhen", "failWhen"]) {
|
|
581
742
|
const groq2 = activity[field];
|
|
582
743
|
groq2 !== void 0 && sites.push({ groq: groq2, path: [...path, field], label: `activity "${activity.name}".${field}` });
|
|
583
744
|
}
|
|
584
|
-
collectBindingSites(
|
|
745
|
+
collectBindingSites({
|
|
746
|
+
effects: activity.effects,
|
|
747
|
+
path: [...path, "effects"],
|
|
748
|
+
label: `activity "${activity.name}"`,
|
|
749
|
+
sites
|
|
750
|
+
});
|
|
585
751
|
for (const [a, action] of (activity.actions ?? []).entries())
|
|
586
|
-
collectBindingSites(
|
|
587
|
-
action.effects,
|
|
588
|
-
[...path, "actions", a, "effects"],
|
|
589
|
-
`action "${action.name}"`,
|
|
752
|
+
collectBindingSites({
|
|
753
|
+
effects: action.effects,
|
|
754
|
+
path: [...path, "actions", a, "effects"],
|
|
755
|
+
label: `action "${action.name}"`,
|
|
590
756
|
sites
|
|
591
|
-
);
|
|
592
|
-
collectSubworkflowSites(activity, path, sites);
|
|
757
|
+
});
|
|
758
|
+
collectSubworkflowSites({ activity, path, sites });
|
|
593
759
|
}
|
|
594
|
-
function collectSubworkflowSites(
|
|
760
|
+
function collectSubworkflowSites({
|
|
761
|
+
activity,
|
|
762
|
+
path,
|
|
763
|
+
sites
|
|
764
|
+
}) {
|
|
595
765
|
const sub = activity.subworkflows;
|
|
596
766
|
if (sub === void 0) return;
|
|
597
767
|
const subPath = [...path, "subworkflows"];
|
|
@@ -611,7 +781,12 @@ function collectSubworkflowSites(activity, path, sites) {
|
|
|
611
781
|
label: `activity "${activity.name}".subworkflows.${group} "${key}"`
|
|
612
782
|
});
|
|
613
783
|
}
|
|
614
|
-
function collectBindingSites(
|
|
784
|
+
function collectBindingSites({
|
|
785
|
+
effects,
|
|
786
|
+
path,
|
|
787
|
+
label,
|
|
788
|
+
sites
|
|
789
|
+
}) {
|
|
615
790
|
for (const [e, effect] of (effects ?? []).entries())
|
|
616
791
|
for (const [key, groq2] of Object.entries(effect.bindings ?? {}))
|
|
617
792
|
sites.push({
|
|
@@ -669,36 +844,60 @@ function checkActivityKinds(def, issues) {
|
|
|
669
844
|
}
|
|
670
845
|
function checkWorkflowInvariants(def) {
|
|
671
846
|
const issues = [], stageNames = checkStages(def, issues);
|
|
672
|
-
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;
|
|
847
|
+
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;
|
|
673
848
|
}
|
|
674
849
|
function defineWorkflow(definition) {
|
|
675
|
-
const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow(schema.AuthoringWorkflowSchema, definition, label), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
|
|
850
|
+
const label = labelFor("defineWorkflow", definition), parsed = parseOrThrow({ schema: schema.AuthoringWorkflowSchema, input: definition, label }), { definition: stored, issues: desugarIssues } = desugarWorkflow(parsed), issues = [...desugarIssues, ...checkWorkflowInvariants(stored)];
|
|
676
851
|
if (issues.length > 0) throw new Error(schema.formatValidationError(label, issues));
|
|
677
852
|
return stored;
|
|
678
853
|
}
|
|
679
854
|
function defineStage(stage) {
|
|
680
|
-
return parseOrThrow(
|
|
855
|
+
return parseOrThrow({
|
|
856
|
+
schema: schema.AuthoringStageSchema,
|
|
857
|
+
input: stage,
|
|
858
|
+
label: labelFor("defineStage", stage)
|
|
859
|
+
});
|
|
681
860
|
}
|
|
682
861
|
function defineActivity(activity) {
|
|
683
|
-
return parseOrThrow(
|
|
862
|
+
return parseOrThrow({
|
|
863
|
+
schema: schema.AuthoringActivitySchema,
|
|
864
|
+
input: activity,
|
|
865
|
+
label: labelFor("defineActivity", activity)
|
|
866
|
+
});
|
|
684
867
|
}
|
|
685
868
|
function defineAction(action) {
|
|
686
|
-
return parseOrThrow(
|
|
869
|
+
return parseOrThrow({
|
|
870
|
+
schema: schema.AuthoringActionSchema,
|
|
871
|
+
input: action,
|
|
872
|
+
label: labelFor("defineAction", action)
|
|
873
|
+
});
|
|
687
874
|
}
|
|
688
875
|
function defineTransition(transition) {
|
|
689
|
-
return parseOrThrow(
|
|
876
|
+
return parseOrThrow({
|
|
877
|
+
schema: schema.AuthoringTransitionSchema,
|
|
878
|
+
input: transition,
|
|
879
|
+
label: transitionLabel(transition)
|
|
880
|
+
});
|
|
690
881
|
}
|
|
691
882
|
function defineField(entry) {
|
|
692
|
-
return parseOrThrow(
|
|
883
|
+
return parseOrThrow({
|
|
884
|
+
schema: schema.AuthoringFieldEntrySchema,
|
|
885
|
+
input: entry,
|
|
886
|
+
label: labelFor("defineField", entry)
|
|
887
|
+
});
|
|
693
888
|
}
|
|
694
889
|
function defineOp(op) {
|
|
695
|
-
return parseOrThrow(schema.AuthoringOpSchema, op, "defineOp");
|
|
890
|
+
return parseOrThrow({ schema: schema.AuthoringOpSchema, input: op, label: "defineOp" });
|
|
696
891
|
}
|
|
697
892
|
function defineGuard(guard) {
|
|
698
|
-
return parseOrThrow(schema.GuardSchema, guard, labelFor("defineGuard", guard));
|
|
893
|
+
return parseOrThrow({ schema: schema.GuardSchema, input: guard, label: labelFor("defineGuard", guard) });
|
|
699
894
|
}
|
|
700
895
|
function defineEffect(effect) {
|
|
701
|
-
return parseOrThrow(
|
|
896
|
+
return parseOrThrow({
|
|
897
|
+
schema: schema.EffectSchema,
|
|
898
|
+
input: effect,
|
|
899
|
+
label: labelFor("defineEffect", effect)
|
|
900
|
+
});
|
|
702
901
|
}
|
|
703
902
|
function transitionLabel(transition) {
|
|
704
903
|
const { name, to } = transition;
|
|
@@ -708,7 +907,11 @@ function defineEffectDescriptor(descriptor) {
|
|
|
708
907
|
if (!descriptor.name) throw new Error("EffectDescriptor missing name");
|
|
709
908
|
return descriptor;
|
|
710
909
|
}
|
|
711
|
-
function parseOrThrow(
|
|
910
|
+
function parseOrThrow({
|
|
911
|
+
schema: schema$1,
|
|
912
|
+
input,
|
|
913
|
+
label
|
|
914
|
+
}) {
|
|
712
915
|
const result = v__namespace.safeParse(schema$1, input);
|
|
713
916
|
if (!result.success)
|
|
714
917
|
throw new Error(schema.formatValidationError(label, schema.issuesFromValibot(result.issues)));
|