@sanity/workflow-engine 0.11.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 +237 -116
- package/dist/_chunks-cjs/schema.cjs.map +1 -1
- package/dist/_chunks-es/schema.js +238 -117
- package/dist/_chunks-es/schema.js.map +1 -1
- package/dist/define.cjs +461 -210
- package/dist/define.cjs.map +1 -1
- package/dist/define.d.cts +1123 -9270
- package/dist/define.d.ts +1123 -9270
- package/dist/define.js +462 -211
- package/dist/define.js.map +1 -1
- package/dist/index.cjs +2244 -1384
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1706 -12804
- package/dist/index.d.ts +1706 -12804
- package/dist/index.js +2246 -1386
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/define.cjs
CHANGED
|
@@ -29,27 +29,29 @@ function serializeGroqValue(value) {
|
|
|
29
29
|
return serialized;
|
|
30
30
|
}
|
|
31
31
|
function desugarWorkflow(authoring) {
|
|
32
|
-
const
|
|
33
|
-
|
|
32
|
+
const issues = [];
|
|
33
|
+
checkReservedRoleAliasKeys(authoring.roleAliases, issues);
|
|
34
|
+
const roleAliases = schema.normalizeRoleAliases(authoring.roleAliases), ctx = {
|
|
35
|
+
issues,
|
|
34
36
|
claimFields: /* @__PURE__ */ new Map(),
|
|
35
37
|
claimedFields: /* @__PURE__ */ new Set(),
|
|
36
|
-
roleAliases
|
|
37
|
-
}, workflowFields = desugarFieldEntries(authoring.fields, ["fields"], ctx), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
|
|
38
|
-
const path = ["stages", i], stageFields = desugarFieldEntries(stage.fields, [...path, "fields"], ctx), stageEnv = {
|
|
38
|
+
roleAliases
|
|
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 = {
|
|
39
41
|
layers: [
|
|
40
42
|
{ scope: "stage", entries: layerOf(stageFields) },
|
|
41
43
|
{ scope: "workflow", entries: workflowLayer }
|
|
42
44
|
]
|
|
43
|
-
},
|
|
44
|
-
(
|
|
45
|
+
}, activities = (stage.activities ?? []).map(
|
|
46
|
+
(activity, j) => desugarActivity({ activity, path: [...path, "activities", j], stageEnv, ctx })
|
|
45
47
|
), transitions = (stage.transitions ?? []).map(
|
|
46
|
-
(transition, k) => desugarTransition(transition, [...path, "transitions", k], stageEnv, ctx)
|
|
47
|
-
), editable = desugarStageEditable(
|
|
48
|
-
stage.editable,
|
|
49
|
-
editableSlotNames(workflowFields, stageFields,
|
|
50
|
-
[...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"],
|
|
51
53
|
ctx
|
|
52
|
-
);
|
|
54
|
+
});
|
|
53
55
|
return {
|
|
54
56
|
...stripUndefined({
|
|
55
57
|
name: stage.name,
|
|
@@ -58,7 +60,7 @@ function desugarWorkflow(authoring) {
|
|
|
58
60
|
guards: stage.guards
|
|
59
61
|
}),
|
|
60
62
|
...stageFields ? { fields: stageFields } : {},
|
|
61
|
-
...
|
|
63
|
+
...activities.length > 0 ? { activities } : {},
|
|
62
64
|
...transitions.length > 0 ? { transitions } : {},
|
|
63
65
|
...editable ? { editable } : {}
|
|
64
66
|
};
|
|
@@ -66,43 +68,99 @@ function desugarWorkflow(authoring) {
|
|
|
66
68
|
return checkUnclaimedClaimFields(ctx), { definition: {
|
|
67
69
|
...stripUndefined({
|
|
68
70
|
name: authoring.name,
|
|
69
|
-
version: authoring.version,
|
|
70
71
|
title: authoring.title,
|
|
71
72
|
description: authoring.description,
|
|
72
73
|
role: authoring.role,
|
|
73
74
|
initialStage: authoring.initialStage,
|
|
74
75
|
predicates: authoring.predicates,
|
|
75
|
-
roleAliases
|
|
76
|
+
roleAliases
|
|
76
77
|
}),
|
|
77
78
|
...workflowFields ? { fields: workflowFields } : {},
|
|
78
79
|
stages
|
|
79
80
|
}, issues: ctx.issues };
|
|
80
81
|
}
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
source: { type: "write" }
|
|
88
|
-
};
|
|
89
|
-
return ctx.claimFields.set(desugared, { name: entry.name, path: [...path, i] }), desugared;
|
|
90
|
-
}
|
|
91
|
-
const editable = normalizeEditable(entry.editable, [...path, i, "editable"], ctx);
|
|
92
|
-
return {
|
|
93
|
-
...stripUndefined({
|
|
94
|
-
type: entry.type,
|
|
95
|
-
name: entry.name,
|
|
96
|
-
title: entry.title,
|
|
97
|
-
description: entry.description,
|
|
98
|
-
required: entry.required,
|
|
99
|
-
editable
|
|
100
|
-
}),
|
|
101
|
-
source: entry.source
|
|
102
|
-
};
|
|
103
|
-
});
|
|
82
|
+
function checkReservedRoleAliasKeys(aliases, issues) {
|
|
83
|
+
for (const key of Object.keys(aliases ?? {}))
|
|
84
|
+
key.startsWith("$") && issues.push({
|
|
85
|
+
path: ["roleAliases", key],
|
|
86
|
+
message: `role alias key "${key}" uses the reserved "$" prefix \u2014 that namespace is the engine's stored spelling for the universal fulfiller. Use "*" to mean "fulfills any gate", or rename the role.`
|
|
87
|
+
});
|
|
104
88
|
}
|
|
105
|
-
|
|
89
|
+
const TODOLIST_OF = [
|
|
90
|
+
{ type: "string", name: "label", title: "Label" },
|
|
91
|
+
{ type: "string", name: "status", title: "Status" },
|
|
92
|
+
{ type: "assignee", name: "assignee", title: "Assignee" },
|
|
93
|
+
{ type: "date", name: "dueDate", title: "Due date" }
|
|
94
|
+
], NOTES_OF = [
|
|
95
|
+
{ type: "text", name: "body", title: "Body" },
|
|
96
|
+
{ type: "actor", name: "actor", title: "Actor" },
|
|
97
|
+
{ type: "datetime", name: "at", title: "At" }
|
|
98
|
+
];
|
|
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 });
|
|
115
|
+
return {
|
|
116
|
+
...stripUndefined({
|
|
117
|
+
type: entry.type,
|
|
118
|
+
name: entry.name,
|
|
119
|
+
title: entry.title,
|
|
120
|
+
description: entry.description,
|
|
121
|
+
required: entry.required,
|
|
122
|
+
initialValue: entry.initialValue,
|
|
123
|
+
editable,
|
|
124
|
+
fields: entry.fields,
|
|
125
|
+
of: entry.of
|
|
126
|
+
})
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function desugarClaimField({
|
|
130
|
+
entry,
|
|
131
|
+
path,
|
|
132
|
+
ctx
|
|
133
|
+
}) {
|
|
134
|
+
const desugared = {
|
|
135
|
+
...stripUndefined({ name: entry.name, title: entry.title, description: entry.description }),
|
|
136
|
+
type: "actor"
|
|
137
|
+
};
|
|
138
|
+
return ctx.claimFields.set(desugared, { name: entry.name, path }), desugared;
|
|
139
|
+
}
|
|
140
|
+
function desugarListField({
|
|
141
|
+
entry,
|
|
142
|
+
path,
|
|
143
|
+
ctx
|
|
144
|
+
}) {
|
|
145
|
+
const editable = normalizeEditable({ editable: entry.editable, path: [...path, "editable"], ctx });
|
|
146
|
+
return {
|
|
147
|
+
...stripUndefined({
|
|
148
|
+
name: entry.name,
|
|
149
|
+
title: entry.title,
|
|
150
|
+
description: entry.description,
|
|
151
|
+
required: entry.required,
|
|
152
|
+
initialValue: entry.initialValue,
|
|
153
|
+
editable
|
|
154
|
+
}),
|
|
155
|
+
type: "array",
|
|
156
|
+
of: entry.type === "todoList" ? TODOLIST_OF : NOTES_OF
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function normalizeEditable({
|
|
160
|
+
editable,
|
|
161
|
+
path,
|
|
162
|
+
ctx
|
|
163
|
+
}) {
|
|
106
164
|
if (editable === void 0 || editable === !0) return editable;
|
|
107
165
|
if (Array.isArray(editable)) {
|
|
108
166
|
const condition = rolesCondition(editable, ctx.roleAliases);
|
|
@@ -117,26 +175,35 @@ function normalizeEditable(editable, path, ctx) {
|
|
|
117
175
|
}
|
|
118
176
|
return editable;
|
|
119
177
|
}
|
|
120
|
-
function editableSlotNames(
|
|
178
|
+
function editableSlotNames({
|
|
179
|
+
workflowFields,
|
|
180
|
+
stageFields,
|
|
181
|
+
activities
|
|
182
|
+
}) {
|
|
121
183
|
const names = /* @__PURE__ */ new Set(), collect = (entries) => {
|
|
122
184
|
for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
|
|
123
185
|
};
|
|
124
186
|
collect(workflowFields), collect(stageFields);
|
|
125
|
-
for (const
|
|
187
|
+
for (const activity of activities) collect(activity.fields);
|
|
126
188
|
return names;
|
|
127
189
|
}
|
|
128
|
-
function desugarStageEditable(
|
|
190
|
+
function desugarStageEditable({
|
|
191
|
+
overrides,
|
|
192
|
+
inScope,
|
|
193
|
+
path,
|
|
194
|
+
ctx
|
|
195
|
+
}) {
|
|
129
196
|
if (overrides === void 0) return;
|
|
130
197
|
const out = {};
|
|
131
198
|
for (const [name, value] of Object.entries(overrides)) {
|
|
132
199
|
if (!inScope.has(name)) {
|
|
133
200
|
ctx.issues.push({
|
|
134
201
|
path: [...path, name],
|
|
135
|
-
message: `stage editable override "${name}" does not narrow an editable slot in scope \u2014 name a workflow/stage/
|
|
202
|
+
message: `stage editable override "${name}" does not narrow an editable slot in scope \u2014 name a workflow/stage/activity slot of this stage that declares \`editable\``
|
|
136
203
|
});
|
|
137
204
|
continue;
|
|
138
205
|
}
|
|
139
|
-
const normalized = normalizeEditable(value, [...path, name], ctx);
|
|
206
|
+
const normalized = normalizeEditable({ editable: value, path: [...path, name], ctx });
|
|
140
207
|
normalized !== void 0 && (out[name] = normalized);
|
|
141
208
|
}
|
|
142
209
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
@@ -144,46 +211,72 @@ function desugarStageEditable(overrides, inScope, path, ctx) {
|
|
|
144
211
|
function layerOf(entries) {
|
|
145
212
|
return new Map((entries ?? []).map((entry) => [entry.name, entry]));
|
|
146
213
|
}
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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 = {
|
|
225
|
+
layers: [{ scope: "activity", entries: layerOf(activityFields) }, ...stageEnv.layers]
|
|
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 });
|
|
153
235
|
return {
|
|
154
236
|
...stripUndefined({
|
|
155
|
-
name:
|
|
156
|
-
title:
|
|
157
|
-
description:
|
|
158
|
-
kind:
|
|
159
|
-
filter:
|
|
160
|
-
requirements:
|
|
161
|
-
completeWhen:
|
|
162
|
-
failWhen:
|
|
163
|
-
effects:
|
|
164
|
-
subworkflows:
|
|
237
|
+
name: activity.name,
|
|
238
|
+
title: activity.title,
|
|
239
|
+
description: activity.description,
|
|
240
|
+
kind: activity.kind,
|
|
241
|
+
filter: activity.filter,
|
|
242
|
+
requirements: activity.requirements,
|
|
243
|
+
completeWhen: activity.completeWhen,
|
|
244
|
+
failWhen: activity.failWhen,
|
|
245
|
+
effects: activity.effects,
|
|
246
|
+
subworkflows: activity.subworkflows
|
|
165
247
|
}),
|
|
166
|
-
activation:
|
|
248
|
+
activation: activity.activation ?? "manual",
|
|
167
249
|
...target ? { target } : {},
|
|
168
|
-
...
|
|
250
|
+
...activityFields ? { fields: activityFields } : {},
|
|
169
251
|
...ops ? { ops } : {},
|
|
170
252
|
...actions.length > 0 ? { actions } : {}
|
|
171
253
|
};
|
|
172
254
|
}
|
|
173
255
|
const TARGET_DOC_KINDS = ["doc.ref", "doc.refs", "release.ref"];
|
|
174
|
-
function desugarTarget(
|
|
256
|
+
function desugarTarget({
|
|
257
|
+
target,
|
|
258
|
+
env,
|
|
259
|
+
path,
|
|
260
|
+
ctx
|
|
261
|
+
}) {
|
|
175
262
|
if (target === void 0 || target.type === "url") return target;
|
|
176
|
-
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);
|
|
177
264
|
return entry && !TARGET_DOC_KINDS.includes(entry.type) && ctx.issues.push({
|
|
178
265
|
path: [...path, "field"],
|
|
179
|
-
message: `manual
|
|
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(", ")})`
|
|
180
267
|
}), { type: "field", field };
|
|
181
268
|
}
|
|
182
|
-
function desugarAction(
|
|
269
|
+
function desugarAction({
|
|
270
|
+
action,
|
|
271
|
+
path,
|
|
272
|
+
env,
|
|
273
|
+
activityName,
|
|
274
|
+
ctx
|
|
275
|
+
}) {
|
|
183
276
|
if ("type" in action)
|
|
184
|
-
return desugarClaimAction(action, path, env, ctx);
|
|
185
|
-
const filter = schema.andConditions([rolesCondition(action.roles, ctx.roleAliases), action.filter]), ops = desugarOps(action.ops, [...path, "ops"], env,
|
|
186
|
-
return action.status !== void 0 && ops.push({ type: "status.set",
|
|
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 }) ?? [];
|
|
279
|
+
return action.status !== void 0 && ops.push({ type: "status.set", activity: activityName, status: action.status }), {
|
|
187
280
|
...stripUndefined({
|
|
188
281
|
name: action.name,
|
|
189
282
|
title: action.title,
|
|
@@ -195,14 +288,26 @@ function desugarAction(action, path, env, taskName, ctx) {
|
|
|
195
288
|
...ops.length > 0 ? { ops } : {}
|
|
196
289
|
};
|
|
197
290
|
}
|
|
198
|
-
function desugarClaimAction(
|
|
199
|
-
|
|
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 });
|
|
200
298
|
if (resolved) {
|
|
201
299
|
const entry = entryAt(env, resolved);
|
|
202
|
-
entry && entry.type !== "
|
|
300
|
+
entry && entry.type !== "actor" && ctx.issues.push({
|
|
301
|
+
path: [...path, "field"],
|
|
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)`
|
|
303
|
+
}), checkShadowedClaimTarget({
|
|
304
|
+
actionName: action.name,
|
|
305
|
+
field: ref.field,
|
|
306
|
+
resolved,
|
|
307
|
+
env,
|
|
203
308
|
path: [...path, "field"],
|
|
204
|
-
|
|
205
|
-
}),
|
|
309
|
+
ctx
|
|
310
|
+
}), entry && ctx.claimedFields.add(entry);
|
|
206
311
|
}
|
|
207
312
|
const noSteal = `!defined($fields.${ref.field})`, filter = schema.andConditions([
|
|
208
313
|
noSteal,
|
|
@@ -221,7 +326,14 @@ function desugarClaimAction(action, path, env, ctx) {
|
|
|
221
326
|
...ops.length > 0 ? { ops } : {}
|
|
222
327
|
};
|
|
223
328
|
}
|
|
224
|
-
function checkShadowedClaimTarget(
|
|
329
|
+
function checkShadowedClaimTarget({
|
|
330
|
+
actionName,
|
|
331
|
+
field,
|
|
332
|
+
resolved,
|
|
333
|
+
env,
|
|
334
|
+
path,
|
|
335
|
+
ctx
|
|
336
|
+
}) {
|
|
225
337
|
const nearest = env.layers.find((l) => l.entries.has(field));
|
|
226
338
|
nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
|
|
227
339
|
path,
|
|
@@ -232,11 +344,22 @@ function checkUnclaimedClaimFields(ctx) {
|
|
|
232
344
|
for (const [entry, { name, path }] of ctx.claimFields)
|
|
233
345
|
ctx.claimedFields.has(entry) || ctx.issues.push({
|
|
234
346
|
path,
|
|
235
|
-
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
|
|
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`
|
|
236
348
|
});
|
|
237
349
|
}
|
|
238
|
-
function desugarTransition(
|
|
239
|
-
|
|
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
|
+
});
|
|
240
363
|
return {
|
|
241
364
|
...stripUndefined({
|
|
242
365
|
name: transition.name,
|
|
@@ -245,29 +368,46 @@ function desugarTransition(transition, path, stageEnv, ctx) {
|
|
|
245
368
|
to: transition.to,
|
|
246
369
|
effects: transition.effects
|
|
247
370
|
}),
|
|
248
|
-
filter: transition.filter ?? "$
|
|
371
|
+
filter: transition.filter ?? "$allActivitiesDone",
|
|
249
372
|
...ops ? { ops } : {}
|
|
250
373
|
};
|
|
251
374
|
}
|
|
252
|
-
function desugarOps(
|
|
375
|
+
function desugarOps({
|
|
376
|
+
ops,
|
|
377
|
+
path,
|
|
378
|
+
env,
|
|
379
|
+
firingActivity,
|
|
380
|
+
ctx
|
|
381
|
+
}) {
|
|
253
382
|
if (ops)
|
|
254
|
-
return ops.map((op, i) => desugarOp(op, [...path, i], env,
|
|
255
|
-
}
|
|
256
|
-
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
|
+
}) {
|
|
257
392
|
if (op.type === "status.set") {
|
|
258
|
-
const
|
|
259
|
-
return
|
|
260
|
-
path: [...path, "
|
|
261
|
-
message: "status.set outside an action must name its target
|
|
262
|
-
}), { type: "status.set",
|
|
393
|
+
const activity = op.activity ?? firingActivity;
|
|
394
|
+
return activity === void 0 && ctx.issues.push({
|
|
395
|
+
path: [...path, "activity"],
|
|
396
|
+
message: "status.set outside an action must name its target activity"
|
|
397
|
+
}), { type: "status.set", activity: activity ?? "", status: op.status };
|
|
263
398
|
}
|
|
264
|
-
if (op.type === "audit") return desugarAuditOp(op, path, env, ctx);
|
|
265
|
-
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);
|
|
266
401
|
return { ...op, target };
|
|
267
402
|
}
|
|
268
403
|
const AUDIT_STAMPS = { actor: { type: "actor" }, at: { type: "now" } };
|
|
269
|
-
function desugarAuditOp(
|
|
270
|
-
|
|
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);
|
|
271
411
|
if (op.value.type !== "object")
|
|
272
412
|
return ctx.issues.push({
|
|
273
413
|
path: [...path, "value"],
|
|
@@ -289,7 +429,12 @@ function desugarAuditOp(op, path, env, ctx) {
|
|
|
289
429
|
}
|
|
290
430
|
return { type: "field.append", target, value: { type: "object", fields } };
|
|
291
431
|
}
|
|
292
|
-
function resolveRef(
|
|
432
|
+
function resolveRef({
|
|
433
|
+
ref,
|
|
434
|
+
env,
|
|
435
|
+
path,
|
|
436
|
+
ctx
|
|
437
|
+
}) {
|
|
293
438
|
const layers = ref.scope === void 0 ? env.layers : env.layers.filter((l) => l.scope === ref.scope);
|
|
294
439
|
for (const layer of layers)
|
|
295
440
|
if (layer.entries.has(ref.field)) return { scope: layer.scope, field: ref.field };
|
|
@@ -323,83 +468,115 @@ const RESERVED_CONDITION_VARS = [
|
|
|
323
468
|
"row",
|
|
324
469
|
"now",
|
|
325
470
|
"effects",
|
|
326
|
-
"
|
|
471
|
+
"activities",
|
|
327
472
|
"subworkflows",
|
|
328
473
|
"self",
|
|
329
474
|
"stage",
|
|
330
475
|
"parent",
|
|
331
476
|
"ancestors",
|
|
332
|
-
"
|
|
333
|
-
"
|
|
477
|
+
"allActivitiesDone",
|
|
478
|
+
"anyActivityFailed"
|
|
334
479
|
], PREDICATE_CALLER_VARS = ["actor", "assigned", "can"];
|
|
335
480
|
function knownList(ids) {
|
|
336
481
|
return [...ids].map((s) => `"${s}"`).join(", ");
|
|
337
482
|
}
|
|
338
|
-
function checkDuplicates(
|
|
483
|
+
function checkDuplicates({
|
|
484
|
+
names,
|
|
485
|
+
what,
|
|
486
|
+
issues
|
|
487
|
+
}) {
|
|
339
488
|
const seen = /* @__PURE__ */ new Set();
|
|
340
489
|
for (const { name, path } of names)
|
|
341
490
|
seen.has(name) && issues.push({ path, message: `duplicate ${what} "${name}" (already declared earlier)` }), seen.add(name);
|
|
342
491
|
return seen;
|
|
343
492
|
}
|
|
344
493
|
function checkStages(def, issues) {
|
|
345
|
-
const stageNames = checkDuplicates(
|
|
346
|
-
def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
|
|
347
|
-
"stage name",
|
|
494
|
+
const stageNames = checkDuplicates({
|
|
495
|
+
names: def.stages.map((stage, i) => ({ name: stage.name, path: ["stages", i, "name"] })),
|
|
496
|
+
what: "stage name",
|
|
348
497
|
issues
|
|
349
|
-
);
|
|
498
|
+
});
|
|
350
499
|
for (const [i, stage] of def.stages.entries()) {
|
|
351
|
-
const
|
|
352
|
-
(stage.
|
|
353
|
-
name:
|
|
354
|
-
path: ["stages", i, "
|
|
500
|
+
const activityNames = checkDuplicates({
|
|
501
|
+
names: (stage.activities ?? []).map((activity, j) => ({
|
|
502
|
+
name: activity.name,
|
|
503
|
+
path: ["stages", i, "activities", j, "name"]
|
|
355
504
|
})),
|
|
356
|
-
`
|
|
505
|
+
what: `activity name in stage "${stage.name}"`,
|
|
357
506
|
issues
|
|
358
|
-
);
|
|
359
|
-
checkDuplicates(
|
|
360
|
-
(stage.transitions ?? []).map((t, k) => ({
|
|
507
|
+
});
|
|
508
|
+
checkDuplicates({
|
|
509
|
+
names: (stage.transitions ?? []).map((t, k) => ({
|
|
361
510
|
name: t.name,
|
|
362
511
|
path: ["stages", i, "transitions", k, "name"]
|
|
363
512
|
})),
|
|
364
|
-
`transition name in stage "${stage.name}"`,
|
|
513
|
+
what: `transition name in stage "${stage.name}"`,
|
|
365
514
|
issues
|
|
366
|
-
),
|
|
515
|
+
}), checkActivities({ def, i, activityNames, issues });
|
|
367
516
|
}
|
|
368
517
|
return stageNames;
|
|
369
518
|
}
|
|
370
|
-
function
|
|
519
|
+
function checkActivities({
|
|
520
|
+
def,
|
|
521
|
+
i,
|
|
522
|
+
activityNames,
|
|
523
|
+
issues
|
|
524
|
+
}) {
|
|
371
525
|
const stage = def.stages[i];
|
|
372
|
-
for (const [j,
|
|
373
|
-
const path = ["stages", i, "
|
|
374
|
-
checkDuplicates(
|
|
375
|
-
(
|
|
526
|
+
for (const [j, activity] of (stage.activities ?? []).entries()) {
|
|
527
|
+
const path = ["stages", i, "activities", j];
|
|
528
|
+
checkDuplicates({
|
|
529
|
+
names: (activity.actions ?? []).map((action, a) => ({
|
|
376
530
|
name: action.name,
|
|
377
531
|
path: [...path, "actions", a, "name"]
|
|
378
532
|
})),
|
|
379
|
-
`action name in
|
|
533
|
+
what: `action name in activity "${activity.name}"`,
|
|
380
534
|
issues
|
|
381
|
-
), checkStatusSetTargets(
|
|
535
|
+
}), checkStatusSetTargets({ activity, activityNames, path, issues });
|
|
382
536
|
}
|
|
383
537
|
}
|
|
384
|
-
function checkStatusSetTargets(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
538
|
+
function checkStatusSetTargets({
|
|
539
|
+
activity,
|
|
540
|
+
activityNames,
|
|
541
|
+
path,
|
|
542
|
+
issues
|
|
543
|
+
}) {
|
|
544
|
+
checkStatusSetOps({ ops: activity.ops, activityNames, path: [...path, "ops"], issues });
|
|
545
|
+
for (const [a, action] of (activity.actions ?? []).entries())
|
|
546
|
+
checkStatusSetOps({
|
|
547
|
+
ops: action.ops,
|
|
548
|
+
activityNames,
|
|
549
|
+
path: [...path, "actions", a, "ops"],
|
|
550
|
+
issues
|
|
551
|
+
});
|
|
388
552
|
}
|
|
389
|
-
function checkStatusSetOps(
|
|
553
|
+
function checkStatusSetOps({
|
|
554
|
+
ops,
|
|
555
|
+
activityNames,
|
|
556
|
+
path,
|
|
557
|
+
issues
|
|
558
|
+
}) {
|
|
390
559
|
for (const [o, op] of (ops ?? []).entries())
|
|
391
|
-
op.type !== "status.set" ||
|
|
392
|
-
path: [...path, o, "
|
|
393
|
-
message: `status.set targets
|
|
560
|
+
op.type !== "status.set" || activityNames.has(op.activity) || issues.push({
|
|
561
|
+
path: [...path, o, "activity"],
|
|
562
|
+
message: `status.set targets activity "${op.activity}" which is not declared in this stage. Known activities: ${knownList(activityNames)}`
|
|
394
563
|
});
|
|
395
564
|
}
|
|
396
|
-
function checkInitialStage(
|
|
565
|
+
function checkInitialStage({
|
|
566
|
+
def,
|
|
567
|
+
stageNames,
|
|
568
|
+
issues
|
|
569
|
+
}) {
|
|
397
570
|
stageNames.has(def.initialStage) || issues.push({
|
|
398
571
|
path: ["initialStage"],
|
|
399
572
|
message: `initialStage "${def.initialStage}" is not a declared stage. Known stages: ${knownList(stageNames)}`
|
|
400
573
|
});
|
|
401
574
|
}
|
|
402
|
-
function checkTransitionTargets(
|
|
575
|
+
function checkTransitionTargets({
|
|
576
|
+
def,
|
|
577
|
+
stageNames,
|
|
578
|
+
issues
|
|
579
|
+
}) {
|
|
403
580
|
for (const [i, stage] of def.stages.entries())
|
|
404
581
|
for (const [k, t] of (stage.transitions ?? []).entries())
|
|
405
582
|
stageNames.has(t.to) || issues.push({
|
|
@@ -410,17 +587,33 @@ function checkTransitionTargets(def, stageNames, issues) {
|
|
|
410
587
|
function checkEffectNames(def, issues) {
|
|
411
588
|
const sites = [];
|
|
412
589
|
for (const [i, stage] of def.stages.entries()) {
|
|
413
|
-
for (const [j,
|
|
414
|
-
collectEffects(
|
|
415
|
-
|
|
416
|
-
|
|
590
|
+
for (const [j, activity] of (stage.activities ?? []).entries()) {
|
|
591
|
+
collectEffects({
|
|
592
|
+
effects: activity.effects,
|
|
593
|
+
path: ["stages", i, "activities", j, "effects"],
|
|
594
|
+
sites
|
|
595
|
+
});
|
|
596
|
+
for (const [a, action] of (activity.actions ?? []).entries())
|
|
597
|
+
collectEffects({
|
|
598
|
+
effects: action.effects,
|
|
599
|
+
path: ["stages", i, "activities", j, "actions", a, "effects"],
|
|
600
|
+
sites
|
|
601
|
+
});
|
|
417
602
|
}
|
|
418
603
|
for (const [k, t] of (stage.transitions ?? []).entries())
|
|
419
|
-
collectEffects(t.effects, ["stages", i, "transitions", k, "effects"], sites);
|
|
604
|
+
collectEffects({ effects: t.effects, path: ["stages", i, "transitions", k, "effects"], sites });
|
|
420
605
|
}
|
|
421
|
-
checkDuplicates(
|
|
606
|
+
checkDuplicates({
|
|
607
|
+
names: sites,
|
|
608
|
+
what: "effect name (registry key \u2014 unique per definition)",
|
|
609
|
+
issues
|
|
610
|
+
});
|
|
422
611
|
}
|
|
423
|
-
function collectEffects(
|
|
612
|
+
function collectEffects({
|
|
613
|
+
effects,
|
|
614
|
+
path,
|
|
615
|
+
sites
|
|
616
|
+
}) {
|
|
424
617
|
for (const [e, effect] of (effects ?? []).entries())
|
|
425
618
|
sites.push({ name: effect.name, path: [...path, e, "name"] });
|
|
426
619
|
}
|
|
@@ -431,11 +624,11 @@ function checkGuardNames(def, issues) {
|
|
|
431
624
|
path: ["stages", i, "guards", g, "name"]
|
|
432
625
|
}))
|
|
433
626
|
);
|
|
434
|
-
checkDuplicates(
|
|
435
|
-
sites,
|
|
436
|
-
"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)",
|
|
437
630
|
issues
|
|
438
|
-
);
|
|
631
|
+
});
|
|
439
632
|
}
|
|
440
633
|
function fieldScopes(def) {
|
|
441
634
|
const scopes = [
|
|
@@ -448,12 +641,12 @@ function fieldScopes(def) {
|
|
|
448
641
|
path: ["stages", i, "fields"],
|
|
449
642
|
label: `stage "${stage.name}" fields`
|
|
450
643
|
});
|
|
451
|
-
for (const [j,
|
|
644
|
+
for (const [j, activity] of (stage.activities ?? []).entries())
|
|
452
645
|
scopes.push({
|
|
453
|
-
entries:
|
|
454
|
-
scope: "
|
|
455
|
-
path: ["stages", i, "
|
|
456
|
-
label: `
|
|
646
|
+
entries: activity.fields,
|
|
647
|
+
scope: "activity",
|
|
648
|
+
path: ["stages", i, "activities", j, "fields"],
|
|
649
|
+
label: `activity "${activity.name}" fields`
|
|
457
650
|
});
|
|
458
651
|
}
|
|
459
652
|
return scopes;
|
|
@@ -461,21 +654,28 @@ function fieldScopes(def) {
|
|
|
461
654
|
function checkRequiredField(def, issues) {
|
|
462
655
|
for (const { entries, scope, path, label } of fieldScopes(def))
|
|
463
656
|
for (const [n, entry] of (entries ?? []).entries())
|
|
464
|
-
entry.required === !0
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
657
|
+
if (entry.required === !0) {
|
|
658
|
+
if (scope !== "workflow")
|
|
659
|
+
issues.push({
|
|
660
|
+
path: [...path, n, "required"],
|
|
661
|
+
message: `${label} entry "${entry.name}" is \`required\`, but \`required\` applies only to workflow-scope \`input\` entries \u2014 only those are caller-supplied at start/spawn`
|
|
662
|
+
});
|
|
663
|
+
else if (entry.initialValue?.type !== "input") {
|
|
664
|
+
const seed = entry.initialValue?.type ?? "working memory (no initialValue)";
|
|
665
|
+
issues.push({
|
|
666
|
+
path: [...path, n, "required"],
|
|
667
|
+
message: `field entry "${entry.name}" has initialValue "${seed}" \u2014 \`required\` applies only to \`input\`-sourced entries (the caller fills them at start/spawn)`
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
}
|
|
471
671
|
}
|
|
472
672
|
function checkFieldEntryNames(def, issues) {
|
|
473
673
|
for (const { entries, path, label } of fieldScopes(def))
|
|
474
|
-
checkDuplicates(
|
|
475
|
-
(entries ?? []).map((entry, n) => ({ name: entry.name, path: [...path, n, "name"] })),
|
|
476
|
-
`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}`,
|
|
477
677
|
issues
|
|
478
|
-
);
|
|
678
|
+
});
|
|
479
679
|
}
|
|
480
680
|
function checkPredicates(def, issues) {
|
|
481
681
|
const reserved = new Set(RESERVED_CONDITION_VARS), names = Object.keys(def.predicates ?? {});
|
|
@@ -485,9 +685,14 @@ function checkPredicates(def, issues) {
|
|
|
485
685
|
message: `predicate "${name}" shadows the built-in $${name} \u2014 pick another name`
|
|
486
686
|
});
|
|
487
687
|
for (const [name, groq2] of Object.entries(def.predicates ?? {}))
|
|
488
|
-
checkPredicateBody(name, groq2, names, issues);
|
|
489
|
-
}
|
|
490
|
-
function checkPredicateBody(
|
|
688
|
+
checkPredicateBody({ name, groq: groq2, names, issues });
|
|
689
|
+
}
|
|
690
|
+
function checkPredicateBody({
|
|
691
|
+
name,
|
|
692
|
+
groq: groq2,
|
|
693
|
+
names,
|
|
694
|
+
issues
|
|
695
|
+
}) {
|
|
491
696
|
for (const caller of PREDICATE_CALLER_VARS)
|
|
492
697
|
referencesVar(groq2, caller) && issues.push({
|
|
493
698
|
path: ["predicates", name],
|
|
@@ -517,40 +722,53 @@ function nonActionFilterConditionSites(def) {
|
|
|
517
722
|
groq: t.filter,
|
|
518
723
|
path: ["stages", i, "transitions", k, "filter"],
|
|
519
724
|
label: `transition "${t.name}" filter`
|
|
520
|
-
}), collectBindingSites(
|
|
521
|
-
t.effects,
|
|
522
|
-
["stages", i, "transitions", k, "effects"],
|
|
523
|
-
`transition "${t.name}"`,
|
|
725
|
+
}), collectBindingSites({
|
|
726
|
+
effects: t.effects,
|
|
727
|
+
path: ["stages", i, "transitions", k, "effects"],
|
|
728
|
+
label: `transition "${t.name}"`,
|
|
524
729
|
sites
|
|
525
|
-
);
|
|
526
|
-
for (const [j,
|
|
527
|
-
|
|
730
|
+
});
|
|
731
|
+
for (const [j, activity] of (stage.activities ?? []).entries())
|
|
732
|
+
collectActivityConditionSites({ activity, path: ["stages", i, "activities", j], sites });
|
|
528
733
|
}
|
|
529
734
|
return sites;
|
|
530
735
|
}
|
|
531
|
-
function
|
|
736
|
+
function collectActivityConditionSites({
|
|
737
|
+
activity,
|
|
738
|
+
path,
|
|
739
|
+
sites
|
|
740
|
+
}) {
|
|
532
741
|
for (const field of ["filter", "completeWhen", "failWhen"]) {
|
|
533
|
-
const groq2 =
|
|
534
|
-
groq2 !== void 0 && sites.push({ groq: groq2, path: [...path, field], label: `
|
|
742
|
+
const groq2 = activity[field];
|
|
743
|
+
groq2 !== void 0 && sites.push({ groq: groq2, path: [...path, field], label: `activity "${activity.name}".${field}` });
|
|
535
744
|
}
|
|
536
|
-
collectBindingSites(
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
745
|
+
collectBindingSites({
|
|
746
|
+
effects: activity.effects,
|
|
747
|
+
path: [...path, "effects"],
|
|
748
|
+
label: `activity "${activity.name}"`,
|
|
749
|
+
sites
|
|
750
|
+
});
|
|
751
|
+
for (const [a, action] of (activity.actions ?? []).entries())
|
|
752
|
+
collectBindingSites({
|
|
753
|
+
effects: action.effects,
|
|
754
|
+
path: [...path, "actions", a, "effects"],
|
|
755
|
+
label: `action "${action.name}"`,
|
|
542
756
|
sites
|
|
543
|
-
);
|
|
544
|
-
collectSubworkflowSites(
|
|
545
|
-
}
|
|
546
|
-
function collectSubworkflowSites(
|
|
547
|
-
|
|
757
|
+
});
|
|
758
|
+
collectSubworkflowSites({ activity, path, sites });
|
|
759
|
+
}
|
|
760
|
+
function collectSubworkflowSites({
|
|
761
|
+
activity,
|
|
762
|
+
path,
|
|
763
|
+
sites
|
|
764
|
+
}) {
|
|
765
|
+
const sub = activity.subworkflows;
|
|
548
766
|
if (sub === void 0) return;
|
|
549
767
|
const subPath = [...path, "subworkflows"];
|
|
550
768
|
sites.push({
|
|
551
769
|
groq: sub.forEach,
|
|
552
770
|
path: [...subPath, "forEach"],
|
|
553
|
-
label: `
|
|
771
|
+
label: `activity "${activity.name}".subworkflows.forEach`
|
|
554
772
|
});
|
|
555
773
|
for (const [group, record] of [
|
|
556
774
|
["with", sub.with],
|
|
@@ -560,10 +778,15 @@ function collectSubworkflowSites(task, path, sites) {
|
|
|
560
778
|
sites.push({
|
|
561
779
|
groq: groq2,
|
|
562
780
|
path: [...subPath, group, key],
|
|
563
|
-
label: `
|
|
781
|
+
label: `activity "${activity.name}".subworkflows.${group} "${key}"`
|
|
564
782
|
});
|
|
565
783
|
}
|
|
566
|
-
function collectBindingSites(
|
|
784
|
+
function collectBindingSites({
|
|
785
|
+
effects,
|
|
786
|
+
path,
|
|
787
|
+
label,
|
|
788
|
+
sites
|
|
789
|
+
}) {
|
|
567
790
|
for (const [e, effect] of (effects ?? []).entries())
|
|
568
791
|
for (const [key, groq2] of Object.entries(effect.bindings ?? {}))
|
|
569
792
|
sites.push({
|
|
@@ -579,12 +802,12 @@ function checkAssigneesEntries(def, issues) {
|
|
|
579
802
|
message: "at most one assignees-kind field entry per scope \u2014 the inbox reads it by kind"
|
|
580
803
|
});
|
|
581
804
|
}
|
|
582
|
-
function
|
|
805
|
+
function activityShape(activity) {
|
|
583
806
|
return {
|
|
584
|
-
hasActions: (
|
|
585
|
-
hasEffects: (
|
|
586
|
-
hasCompleteWhen:
|
|
587
|
-
hasSubworkflows:
|
|
807
|
+
hasActions: (activity.actions ?? []).length > 0,
|
|
808
|
+
hasEffects: (activity.effects ?? []).length > 0,
|
|
809
|
+
hasCompleteWhen: activity.completeWhen !== void 0,
|
|
810
|
+
hasSubworkflows: activity.subworkflows !== void 0
|
|
588
811
|
};
|
|
589
812
|
}
|
|
590
813
|
const KIND_SHAPE_RULES = {
|
|
@@ -592,7 +815,7 @@ const KIND_SHAPE_RULES = {
|
|
|
592
815
|
service: (s) => s.hasEffects ? [] : ["needs at least one effect \u2014 the automated work it performs"],
|
|
593
816
|
manual: (s) => [
|
|
594
817
|
s.hasActions || s.hasCompleteWhen ? void 0 : "needs a way to complete \u2014 an action to acknowledge it, or a `completeWhen` predicate to verify it (otherwise it auto-resolves on activation)",
|
|
595
|
-
s.hasSubworkflows ? "is off-system work, not a fan-out \u2014 drop `subworkflows` or move it to its own
|
|
818
|
+
s.hasSubworkflows ? "is off-system work, not a fan-out \u2014 drop `subworkflows` or move it to its own activity" : void 0
|
|
596
819
|
].filter((m) => m !== void 0),
|
|
597
820
|
receive: (s) => [
|
|
598
821
|
s.hasCompleteWhen || s.hasSubworkflows ? void 0 : "needs a `completeWhen` (or `subworkflows`) condition to wait on",
|
|
@@ -604,53 +827,77 @@ const KIND_SHAPE_RULES = {
|
|
|
604
827
|
s.hasSubworkflows ? "resolves on activation, so it cannot fan out with `subworkflows`" : void 0
|
|
605
828
|
].filter((m) => m !== void 0)
|
|
606
829
|
};
|
|
607
|
-
function
|
|
830
|
+
function checkActivityKinds(def, issues) {
|
|
608
831
|
for (const [i, stage] of def.stages.entries())
|
|
609
|
-
for (const [j,
|
|
610
|
-
const path = ["stages", i, "
|
|
611
|
-
if (
|
|
832
|
+
for (const [j, activity] of (stage.activities ?? []).entries()) {
|
|
833
|
+
const path = ["stages", i, "activities", j];
|
|
834
|
+
if (activity.target !== void 0 && activity.kind !== "manual" && issues.push({
|
|
612
835
|
path: [...path, "target"],
|
|
613
|
-
message: `
|
|
614
|
-
}),
|
|
615
|
-
for (const fault of KIND_SHAPE_RULES[
|
|
836
|
+
message: `activity "${activity.name}" has a \`target\` but is not \`kind: "manual"\` \u2014 a target is the deep-link for off-system manual work`
|
|
837
|
+
}), activity.kind !== void 0)
|
|
838
|
+
for (const fault of KIND_SHAPE_RULES[activity.kind](activityShape(activity)))
|
|
616
839
|
issues.push({
|
|
617
840
|
path: [...path, "kind"],
|
|
618
|
-
message: `
|
|
841
|
+
message: `activity "${activity.name}" declares kind "${activity.kind}" but ${fault}`
|
|
619
842
|
});
|
|
620
843
|
}
|
|
621
844
|
}
|
|
622
845
|
function checkWorkflowInvariants(def) {
|
|
623
846
|
const issues = [], stageNames = checkStages(def, issues);
|
|
624
|
-
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),
|
|
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;
|
|
625
848
|
}
|
|
626
849
|
function defineWorkflow(definition) {
|
|
627
|
-
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)];
|
|
628
851
|
if (issues.length > 0) throw new Error(schema.formatValidationError(label, issues));
|
|
629
852
|
return stored;
|
|
630
853
|
}
|
|
631
854
|
function defineStage(stage) {
|
|
632
|
-
return parseOrThrow(
|
|
855
|
+
return parseOrThrow({
|
|
856
|
+
schema: schema.AuthoringStageSchema,
|
|
857
|
+
input: stage,
|
|
858
|
+
label: labelFor("defineStage", stage)
|
|
859
|
+
});
|
|
633
860
|
}
|
|
634
|
-
function
|
|
635
|
-
return parseOrThrow(
|
|
861
|
+
function defineActivity(activity) {
|
|
862
|
+
return parseOrThrow({
|
|
863
|
+
schema: schema.AuthoringActivitySchema,
|
|
864
|
+
input: activity,
|
|
865
|
+
label: labelFor("defineActivity", activity)
|
|
866
|
+
});
|
|
636
867
|
}
|
|
637
868
|
function defineAction(action) {
|
|
638
|
-
return parseOrThrow(
|
|
869
|
+
return parseOrThrow({
|
|
870
|
+
schema: schema.AuthoringActionSchema,
|
|
871
|
+
input: action,
|
|
872
|
+
label: labelFor("defineAction", action)
|
|
873
|
+
});
|
|
639
874
|
}
|
|
640
875
|
function defineTransition(transition) {
|
|
641
|
-
return parseOrThrow(
|
|
876
|
+
return parseOrThrow({
|
|
877
|
+
schema: schema.AuthoringTransitionSchema,
|
|
878
|
+
input: transition,
|
|
879
|
+
label: transitionLabel(transition)
|
|
880
|
+
});
|
|
642
881
|
}
|
|
643
882
|
function defineField(entry) {
|
|
644
|
-
return parseOrThrow(
|
|
883
|
+
return parseOrThrow({
|
|
884
|
+
schema: schema.AuthoringFieldEntrySchema,
|
|
885
|
+
input: entry,
|
|
886
|
+
label: labelFor("defineField", entry)
|
|
887
|
+
});
|
|
645
888
|
}
|
|
646
889
|
function defineOp(op) {
|
|
647
|
-
return parseOrThrow(schema.AuthoringOpSchema, op, "defineOp");
|
|
890
|
+
return parseOrThrow({ schema: schema.AuthoringOpSchema, input: op, label: "defineOp" });
|
|
648
891
|
}
|
|
649
892
|
function defineGuard(guard) {
|
|
650
|
-
return parseOrThrow(schema.GuardSchema, guard, labelFor("defineGuard", guard));
|
|
893
|
+
return parseOrThrow({ schema: schema.GuardSchema, input: guard, label: labelFor("defineGuard", guard) });
|
|
651
894
|
}
|
|
652
895
|
function defineEffect(effect) {
|
|
653
|
-
return parseOrThrow(
|
|
896
|
+
return parseOrThrow({
|
|
897
|
+
schema: schema.EffectSchema,
|
|
898
|
+
input: effect,
|
|
899
|
+
label: labelFor("defineEffect", effect)
|
|
900
|
+
});
|
|
654
901
|
}
|
|
655
902
|
function transitionLabel(transition) {
|
|
656
903
|
const { name, to } = transition;
|
|
@@ -660,7 +907,11 @@ function defineEffectDescriptor(descriptor) {
|
|
|
660
907
|
if (!descriptor.name) throw new Error("EffectDescriptor missing name");
|
|
661
908
|
return descriptor;
|
|
662
909
|
}
|
|
663
|
-
function parseOrThrow(
|
|
910
|
+
function parseOrThrow({
|
|
911
|
+
schema: schema$1,
|
|
912
|
+
input,
|
|
913
|
+
label
|
|
914
|
+
}) {
|
|
664
915
|
const result = v__namespace.safeParse(schema$1, input);
|
|
665
916
|
if (!result.success)
|
|
666
917
|
throw new Error(schema.formatValidationError(label, schema.issuesFromValibot(result.issues)));
|
|
@@ -674,13 +925,13 @@ function labelFor(fn, value) {
|
|
|
674
925
|
return fn;
|
|
675
926
|
}
|
|
676
927
|
exports.defineAction = defineAction;
|
|
928
|
+
exports.defineActivity = defineActivity;
|
|
677
929
|
exports.defineEffect = defineEffect;
|
|
678
930
|
exports.defineEffectDescriptor = defineEffectDescriptor;
|
|
679
931
|
exports.defineField = defineField;
|
|
680
932
|
exports.defineGuard = defineGuard;
|
|
681
933
|
exports.defineOp = defineOp;
|
|
682
934
|
exports.defineStage = defineStage;
|
|
683
|
-
exports.defineTask = defineTask;
|
|
684
935
|
exports.defineTransition = defineTransition;
|
|
685
936
|
exports.defineWorkflow = defineWorkflow;
|
|
686
937
|
exports.groq = groq;
|