@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.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(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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(
|
|
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(
|
|
111
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
168
|
-
|
|
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(
|
|
171
|
-
|
|
172
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
219
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
259
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
290
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
405
|
-
|
|
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(
|
|
529
|
+
checkStatusSetOps({
|
|
530
|
+
ops: action.ops,
|
|
531
|
+
activityNames,
|
|
532
|
+
path: [...path, "actions", a, "ops"],
|
|
533
|
+
issues
|
|
534
|
+
});
|
|
408
535
|
}
|
|
409
|
-
function checkStatusSetOps(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
589
|
+
checkDuplicates({
|
|
590
|
+
names: sites,
|
|
591
|
+
what: "effect name (registry key \u2014 unique per definition)",
|
|
592
|
+
issues
|
|
593
|
+
});
|
|
446
594
|
}
|
|
447
|
-
function collectEffects(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
859
|
+
return parseOrThrow({
|
|
860
|
+
schema: AuthoringTransitionSchema,
|
|
861
|
+
input: transition,
|
|
862
|
+
label: transitionLabel(transition)
|
|
863
|
+
});
|
|
673
864
|
}
|
|
674
865
|
function defineField(entry) {
|
|
675
|
-
return parseOrThrow(
|
|
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(
|
|
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(
|
|
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)));
|