@sanity/workflow-engine 0.14.0 → 0.15.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/CHANGELOG.md +743 -0
- package/DATAMODEL.md +183 -0
- package/README.md +2 -2
- package/dist/_chunks-cjs/invariants.cjs +2461 -0
- package/dist/_chunks-es/invariants.js +2251 -0
- package/dist/define.cjs +673 -906
- package/dist/define.d.cts +192 -26
- package/dist/define.d.ts +192 -26
- package/dist/define.js +650 -905
- package/dist/index.cjs +9728 -5210
- package/dist/index.d.cts +2462 -323
- package/dist/index.d.ts +2462 -323
- package/dist/index.js +9358 -5273
- package/package.json +9 -5
- package/dist/_chunks-cjs/schema.cjs +0 -1289
- package/dist/_chunks-cjs/schema.cjs.map +0 -1
- package/dist/_chunks-es/schema.js +0 -1274
- package/dist/_chunks-es/schema.js.map +0 -1
- package/dist/define.cjs.map +0 -1
- package/dist/define.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/define.cjs
CHANGED
|
@@ -1,979 +1,746 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
10
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
11
|
-
enumerable: !0,
|
|
12
|
-
get: function() {
|
|
13
|
-
return e[k];
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
}), n.default = e, Object.freeze(n);
|
|
18
|
-
}
|
|
19
|
-
var v__namespace = /* @__PURE__ */ _interopNamespaceCompat(v);
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: !0
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var invariants = require("./_chunks-cjs/invariants.cjs");
|
|
8
|
+
|
|
20
9
|
function groq(strings, ...values) {
|
|
21
|
-
|
|
10
|
+
return strings.reduce((out, part, i) => i === 0 ? part : `${out}${serializeGroqValue(values[i - 1])}${part}`, "");
|
|
22
11
|
}
|
|
12
|
+
|
|
23
13
|
function serializeGroqValue(value) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
`groq tag cannot serialize ${typeof value} \u2014 interpolate JSON-representable values only`
|
|
28
|
-
);
|
|
29
|
-
return serialized;
|
|
14
|
+
const serialized = JSON.stringify(value);
|
|
15
|
+
if (serialized === void 0) throw new Error(`groq tag cannot serialize ${typeof value} — interpolate JSON-representable values only`);
|
|
16
|
+
return serialized;
|
|
30
17
|
}
|
|
18
|
+
|
|
31
19
|
function desugarWorkflow(authoring) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
20
|
+
const issues = [];
|
|
21
|
+
checkReservedRoleAliasKeys(authoring.roleAliases, issues);
|
|
22
|
+
const roleAliases = invariants.normalizeRoleAliases(authoring.roleAliases), ctx = {
|
|
23
|
+
issues: issues,
|
|
24
|
+
claimFields: /* @__PURE__ */ new Map,
|
|
25
|
+
claimedFields: /* @__PURE__ */ new Set,
|
|
26
|
+
roleAliases: roleAliases
|
|
27
|
+
}, workflowFields = desugarFieldEntries({
|
|
28
|
+
entries: authoring.fields,
|
|
29
|
+
path: [ "fields" ],
|
|
30
|
+
ctx: ctx
|
|
31
|
+
}), workflowLayer = layerOf(workflowFields), stages = authoring.stages.map((stage, i) => {
|
|
32
|
+
const path = [ "stages", i ], stageFields = desugarFieldEntries({
|
|
33
|
+
entries: stage.fields,
|
|
34
|
+
path: [ ...path, "fields" ],
|
|
35
|
+
ctx: ctx
|
|
36
|
+
}), stageEnv = {
|
|
37
|
+
layers: [ {
|
|
38
|
+
scope: "stage",
|
|
39
|
+
entries: layerOf(stageFields)
|
|
40
|
+
}, {
|
|
41
|
+
scope: "workflow",
|
|
42
|
+
entries: workflowLayer
|
|
43
|
+
} ]
|
|
44
|
+
}, activities = (stage.activities ?? []).map((activity, j) => desugarActivity({
|
|
45
|
+
activity: activity,
|
|
46
|
+
path: [ ...path, "activities", j ],
|
|
47
|
+
stageEnv: stageEnv,
|
|
48
|
+
ctx: ctx
|
|
49
|
+
})), transitions = (stage.transitions ?? []).map((transition, k) => desugarTransition({
|
|
50
|
+
transition: transition,
|
|
51
|
+
path: [ ...path, "transitions", k ],
|
|
52
|
+
stageEnv: stageEnv,
|
|
53
|
+
ctx: ctx
|
|
54
|
+
})), editable = desugarStageEditable({
|
|
55
|
+
overrides: stage.editable,
|
|
56
|
+
inScope: editableFieldNames({
|
|
57
|
+
workflowFields: workflowFields,
|
|
58
|
+
stageFields: stageFields,
|
|
59
|
+
activities: activities
|
|
60
|
+
}),
|
|
61
|
+
path: [ ...path, "editable" ],
|
|
62
|
+
ctx: ctx
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
...stripUndefined({
|
|
66
|
+
name: stage.name,
|
|
67
|
+
title: stage.title,
|
|
68
|
+
description: stage.description,
|
|
69
|
+
groups: stage.groups,
|
|
70
|
+
guards: stage.guards?.map(desugarGuard)
|
|
71
|
+
}),
|
|
72
|
+
...stageFields ? {
|
|
73
|
+
fields: stageFields
|
|
74
|
+
} : {},
|
|
75
|
+
...activities.length > 0 ? {
|
|
76
|
+
activities: activities
|
|
77
|
+
} : {},
|
|
78
|
+
...transitions.length > 0 ? {
|
|
79
|
+
transitions: transitions
|
|
80
|
+
} : {},
|
|
81
|
+
...editable ? {
|
|
82
|
+
editable: editable
|
|
83
|
+
} : {}
|
|
84
|
+
};
|
|
54
85
|
});
|
|
55
|
-
return {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
86
|
+
return checkUnclaimedClaimFields(ctx), {
|
|
87
|
+
definition: {
|
|
88
|
+
...stripUndefined({
|
|
89
|
+
name: authoring.name,
|
|
90
|
+
title: authoring.title,
|
|
91
|
+
description: authoring.description,
|
|
92
|
+
groups: authoring.groups,
|
|
93
|
+
lifecycle: authoring.lifecycle,
|
|
94
|
+
applicableWhen: authoring.applicableWhen,
|
|
95
|
+
initialStage: authoring.initialStage,
|
|
96
|
+
predicates: authoring.predicates,
|
|
97
|
+
roleAliases: roleAliases
|
|
98
|
+
}),
|
|
99
|
+
...workflowFields ? {
|
|
100
|
+
fields: workflowFields
|
|
101
|
+
} : {},
|
|
102
|
+
stages: stages
|
|
103
|
+
},
|
|
104
|
+
issues: ctx.issues
|
|
66
105
|
};
|
|
67
|
-
});
|
|
68
|
-
return checkUnclaimedClaimFields(ctx), { definition: {
|
|
69
|
-
...stripUndefined({
|
|
70
|
-
name: authoring.name,
|
|
71
|
-
title: authoring.title,
|
|
72
|
-
description: authoring.description,
|
|
73
|
-
lifecycle: authoring.lifecycle,
|
|
74
|
-
initialStage: authoring.initialStage,
|
|
75
|
-
predicates: authoring.predicates,
|
|
76
|
-
roleAliases
|
|
77
|
-
}),
|
|
78
|
-
...workflowFields ? { fields: workflowFields } : {},
|
|
79
|
-
stages
|
|
80
|
-
}, issues: ctx.issues };
|
|
81
106
|
}
|
|
107
|
+
|
|
82
108
|
function checkReservedRoleAliasKeys(aliases, issues) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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.`
|
|
109
|
+
for (const key of Object.keys(aliases ?? {})) key.startsWith("$") && issues.push({
|
|
110
|
+
path: [ "roleAliases", key ],
|
|
111
|
+
message: `role alias key "${key}" uses the reserved "$" prefix — that namespace is the engine's stored spelling for the universal fulfiller. Use "*" to mean "fulfills any gate", or rename the role.`
|
|
87
112
|
});
|
|
88
113
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
}) {
|
|
164
|
-
if (editable === void 0 || editable === !0) return editable;
|
|
165
|
-
if (Array.isArray(editable)) {
|
|
166
|
-
const condition = rolesCondition(editable, ctx.roleAliases);
|
|
167
|
-
if (condition === void 0) {
|
|
168
|
-
ctx.issues.push({
|
|
169
|
-
path,
|
|
170
|
-
message: "editable: [] names no roles \u2014 use `true` to open the field to anyone in its scope, or list at least one role"
|
|
171
|
-
});
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
return condition;
|
|
175
|
-
}
|
|
176
|
-
return editable;
|
|
177
|
-
}
|
|
178
|
-
function editableFieldNames({
|
|
179
|
-
workflowFields,
|
|
180
|
-
stageFields,
|
|
181
|
-
activities
|
|
182
|
-
}) {
|
|
183
|
-
const names = /* @__PURE__ */ new Set(), collect = (entries) => {
|
|
184
|
-
for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
|
|
185
|
-
};
|
|
186
|
-
collect(workflowFields), collect(stageFields);
|
|
187
|
-
for (const activity of activities) collect(activity.fields);
|
|
188
|
-
return names;
|
|
189
|
-
}
|
|
190
|
-
function desugarStageEditable({
|
|
191
|
-
overrides,
|
|
192
|
-
inScope,
|
|
193
|
-
path,
|
|
194
|
-
ctx
|
|
195
|
-
}) {
|
|
196
|
-
if (overrides === void 0) return;
|
|
197
|
-
const out = {};
|
|
198
|
-
for (const [name, value] of Object.entries(overrides)) {
|
|
199
|
-
if (!inScope.has(name)) {
|
|
200
|
-
ctx.issues.push({
|
|
201
|
-
path: [...path, name],
|
|
202
|
-
message: `stage editable override "${name}" does not narrow an editable field in scope \u2014 name a workflow/stage/activity field of this stage that declares \`editable\``
|
|
203
|
-
});
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
const normalized = normalizeEditable({ editable: value, path: [...path, name], ctx });
|
|
207
|
-
normalized !== void 0 && (out[name] = normalized);
|
|
208
|
-
}
|
|
209
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
210
|
-
}
|
|
211
|
-
function layerOf(entries) {
|
|
212
|
-
return new Map((entries ?? []).map((entry) => [entry.name, entry]));
|
|
213
|
-
}
|
|
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 });
|
|
235
|
-
return {
|
|
236
|
-
...stripUndefined({
|
|
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
|
|
247
|
-
}),
|
|
248
|
-
activation: activity.activation ?? "manual",
|
|
249
|
-
...target ? { target } : {},
|
|
250
|
-
...activityFields ? { fields: activityFields } : {},
|
|
251
|
-
...ops ? { ops } : {},
|
|
252
|
-
...actions.length > 0 ? { actions } : {}
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
const TARGET_DOC_KINDS = ["doc.ref", "doc.refs", "release.ref"];
|
|
256
|
-
function desugarTarget({
|
|
257
|
-
target,
|
|
258
|
-
env,
|
|
259
|
-
path,
|
|
260
|
-
ctx
|
|
261
|
-
}) {
|
|
262
|
-
if (target === void 0 || target.type === "url") return target;
|
|
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);
|
|
264
|
-
return entry && !TARGET_DOC_KINDS.includes(entry.type) && ctx.issues.push({
|
|
265
|
-
path: [...path, "field"],
|
|
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(", ")})`
|
|
267
|
-
}), { type: "field", field };
|
|
268
|
-
}
|
|
269
|
-
function desugarAction({
|
|
270
|
-
action,
|
|
271
|
-
path,
|
|
272
|
-
env,
|
|
273
|
-
activityName,
|
|
274
|
-
ctx
|
|
275
|
-
}) {
|
|
276
|
-
if ("type" in action)
|
|
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 }), {
|
|
280
|
-
...stripUndefined({
|
|
281
|
-
name: action.name,
|
|
282
|
-
title: action.title,
|
|
283
|
-
description: action.description,
|
|
284
|
-
params: action.params,
|
|
285
|
-
effects: action.effects
|
|
286
|
-
}),
|
|
287
|
-
...filter ? { filter } : {},
|
|
288
|
-
...ops.length > 0 ? { ops } : {}
|
|
289
|
-
};
|
|
290
|
-
}
|
|
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 });
|
|
298
|
-
if (resolved) {
|
|
299
|
-
const entry = entryAt(env, resolved);
|
|
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,
|
|
308
|
-
path: [...path, "field"],
|
|
309
|
-
ctx
|
|
310
|
-
}), entry && ctx.claimedFields.add(entry);
|
|
311
|
-
}
|
|
312
|
-
const noSteal = `!defined($fields.${ref.field})`, filter = schema.andConditions([
|
|
313
|
-
noSteal,
|
|
314
|
-
rolesCondition(action.roles, ctx.roleAliases),
|
|
315
|
-
action.filter
|
|
316
|
-
]), ops = resolved ? [{ type: "field.set", target: resolved, value: { type: "actor" } }] : [];
|
|
317
|
-
return {
|
|
318
|
-
...stripUndefined({
|
|
319
|
-
name: action.name,
|
|
320
|
-
title: action.title,
|
|
321
|
-
description: action.description,
|
|
322
|
-
params: action.params,
|
|
323
|
-
effects: action.effects
|
|
324
|
-
}),
|
|
325
|
-
filter,
|
|
326
|
-
...ops.length > 0 ? { ops } : {}
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
function checkShadowedClaimTarget({
|
|
330
|
-
actionName,
|
|
331
|
-
field,
|
|
332
|
-
resolved,
|
|
333
|
-
env,
|
|
334
|
-
path,
|
|
335
|
-
ctx
|
|
336
|
-
}) {
|
|
337
|
-
const nearest = env.layers.find((l) => l.entries.has(field));
|
|
338
|
-
nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
|
|
339
|
-
path,
|
|
340
|
-
message: `claim action "${actionName}" targets "${field}" at scope "${resolved.scope}", but a nearer ${nearest.scope}-scope entry of the same name shadows it in $fields \u2014 the no-steal filter would read the shadowing entry while the claim writes the "${resolved.scope}" one. Rename one of the entries or claim the nearer one`
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
function checkUnclaimedClaimFields(ctx) {
|
|
344
|
-
for (const [entry, { name, path }] of ctx.claimFields)
|
|
345
|
-
ctx.claimedFields.has(entry) || ctx.issues.push({
|
|
346
|
-
path,
|
|
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`
|
|
114
|
+
|
|
115
|
+
const TODOLIST_OF = [ {
|
|
116
|
+
type: "string",
|
|
117
|
+
name: "label",
|
|
118
|
+
title: "Label"
|
|
119
|
+
}, {
|
|
120
|
+
type: "string",
|
|
121
|
+
name: "status",
|
|
122
|
+
title: "Status"
|
|
123
|
+
}, {
|
|
124
|
+
type: "assignee",
|
|
125
|
+
name: "assignee",
|
|
126
|
+
title: "Assignee"
|
|
127
|
+
}, {
|
|
128
|
+
type: "date",
|
|
129
|
+
name: "dueDate",
|
|
130
|
+
title: "Due date"
|
|
131
|
+
} ], NOTES_OF = [ {
|
|
132
|
+
type: "text",
|
|
133
|
+
name: "body",
|
|
134
|
+
title: "Body"
|
|
135
|
+
}, {
|
|
136
|
+
type: "actor",
|
|
137
|
+
name: "actor",
|
|
138
|
+
title: "Actor"
|
|
139
|
+
}, {
|
|
140
|
+
type: "datetime",
|
|
141
|
+
name: "at",
|
|
142
|
+
title: "At"
|
|
143
|
+
} ];
|
|
144
|
+
|
|
145
|
+
function desugarFieldEntries({entries: entries, path: path, ctx: ctx}) {
|
|
146
|
+
return !entries || entries.length === 0 ? entries === void 0 ? void 0 : [] : entries.map((entry, i) => desugarFieldEntry({
|
|
147
|
+
entry: entry,
|
|
148
|
+
path: [ ...path, i ],
|
|
149
|
+
ctx: ctx
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function desugarFieldEntry({entry: entry, path: path, ctx: ctx}) {
|
|
154
|
+
if (entry.type === "claim") return desugarClaimField({
|
|
155
|
+
entry: entry,
|
|
156
|
+
path: path,
|
|
157
|
+
ctx: ctx
|
|
158
|
+
});
|
|
159
|
+
if (entry.type === "todoList" || entry.type === "notes") return desugarListField({
|
|
160
|
+
entry: entry,
|
|
161
|
+
path: path,
|
|
162
|
+
ctx: ctx
|
|
348
163
|
});
|
|
164
|
+
const editable = normalizeEditable({
|
|
165
|
+
editable: entry.editable,
|
|
166
|
+
path: [ ...path, "editable" ],
|
|
167
|
+
ctx: ctx
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
...stripUndefined({
|
|
171
|
+
type: entry.type,
|
|
172
|
+
name: entry.name,
|
|
173
|
+
title: entry.title,
|
|
174
|
+
description: entry.description,
|
|
175
|
+
group: normalizeGroup(entry.group),
|
|
176
|
+
required: entry.required,
|
|
177
|
+
initialValue: entry.initialValue,
|
|
178
|
+
editable: editable,
|
|
179
|
+
types: entry.types,
|
|
180
|
+
fields: entry.fields,
|
|
181
|
+
of: entry.of
|
|
182
|
+
})
|
|
183
|
+
};
|
|
349
184
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
ctx
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
185
|
+
|
|
186
|
+
function desugarClaimField({entry: entry, path: path, ctx: ctx}) {
|
|
187
|
+
const desugared = {
|
|
188
|
+
...stripUndefined({
|
|
189
|
+
name: entry.name,
|
|
190
|
+
title: entry.title,
|
|
191
|
+
description: entry.description,
|
|
192
|
+
group: normalizeGroup(entry.group)
|
|
193
|
+
}),
|
|
194
|
+
type: "actor"
|
|
195
|
+
};
|
|
196
|
+
return ctx.claimFields.set(desugared, {
|
|
197
|
+
name: entry.name,
|
|
198
|
+
path: path
|
|
199
|
+
}), desugared;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function desugarListField({entry: entry, path: path, ctx: ctx}) {
|
|
203
|
+
const editable = normalizeEditable({
|
|
204
|
+
editable: entry.editable,
|
|
205
|
+
path: [ ...path, "editable" ],
|
|
206
|
+
ctx: ctx
|
|
207
|
+
});
|
|
208
|
+
return {
|
|
209
|
+
...stripUndefined({
|
|
210
|
+
name: entry.name,
|
|
211
|
+
title: entry.title,
|
|
212
|
+
description: entry.description,
|
|
213
|
+
group: normalizeGroup(entry.group),
|
|
214
|
+
required: entry.required,
|
|
215
|
+
initialValue: entry.initialValue,
|
|
216
|
+
editable: editable
|
|
217
|
+
}),
|
|
218
|
+
type: "array",
|
|
219
|
+
of: entry.type === "todoList" ? TODOLIST_OF : NOTES_OF
|
|
220
|
+
};
|
|
374
221
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
function desugarOps({
|
|
391
|
-
ops,
|
|
392
|
-
path,
|
|
393
|
-
env,
|
|
394
|
-
firingActivity,
|
|
395
|
-
ctx
|
|
396
|
-
}) {
|
|
397
|
-
if (ops)
|
|
398
|
-
return ops.map((op, i) => desugarOp({ op, path: [...path, i], env, firingActivity, ctx }));
|
|
399
|
-
}
|
|
400
|
-
function desugarOp({
|
|
401
|
-
op,
|
|
402
|
-
path,
|
|
403
|
-
env,
|
|
404
|
-
firingActivity,
|
|
405
|
-
ctx
|
|
406
|
-
}) {
|
|
407
|
-
if (op.type === "status.set") {
|
|
408
|
-
const activity = op.activity ?? firingActivity;
|
|
409
|
-
return activity === void 0 && ctx.issues.push({
|
|
410
|
-
path: [...path, "activity"],
|
|
411
|
-
message: "status.set outside an action must name its target activity"
|
|
412
|
-
}), { type: "status.set", activity: activity ?? "", status: op.status };
|
|
413
|
-
}
|
|
414
|
-
if (op.type === "audit") return desugarAuditOp({ op, path, env, ctx });
|
|
415
|
-
const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
|
|
416
|
-
return { ...op, target };
|
|
417
|
-
}
|
|
418
|
-
const AUDIT_STAMPS = { actor: { type: "actor" }, at: { type: "now" } };
|
|
419
|
-
function desugarAuditOp({
|
|
420
|
-
op,
|
|
421
|
-
path,
|
|
422
|
-
env,
|
|
423
|
-
ctx
|
|
424
|
-
}) {
|
|
425
|
-
const target = resolveRef({ ref: op.target, env, path: [...path, "target"], ctx }) ?? fallbackRef(op.target);
|
|
426
|
-
if (op.value.type !== "object")
|
|
427
|
-
return ctx.issues.push({
|
|
428
|
-
path: [...path, "value"],
|
|
429
|
-
message: `audit value must be an object source carrying the domain fields (got "${op.value.type}")`
|
|
430
|
-
}), { type: "field.append", target, value: op.value };
|
|
431
|
-
const actorField = op.stampFields?.actor ?? "actor", atField = op.stampFields?.at ?? "at", fields = { ...op.value.fields };
|
|
432
|
-
for (const [stamp, source] of [
|
|
433
|
-
[actorField, AUDIT_STAMPS.actor],
|
|
434
|
-
[atField, AUDIT_STAMPS.at]
|
|
435
|
-
]) {
|
|
436
|
-
if (stamp in fields) {
|
|
437
|
-
ctx.issues.push({
|
|
438
|
-
path: [...path, "value", "fields", stamp],
|
|
439
|
-
message: `audit stamp field "${stamp}" collides with an authored domain field \u2014 rename yours or remap the stamp via stampFields`
|
|
440
|
-
});
|
|
441
|
-
continue;
|
|
222
|
+
|
|
223
|
+
function normalizeEditable({editable: editable, path: path, ctx: ctx}) {
|
|
224
|
+
if (editable === void 0 || editable === !0) return editable;
|
|
225
|
+
if (Array.isArray(editable)) {
|
|
226
|
+
const condition = rolesCondition(editable, ctx.roleAliases);
|
|
227
|
+
if (condition === void 0) {
|
|
228
|
+
ctx.issues.push({
|
|
229
|
+
path: path,
|
|
230
|
+
message: "editable: [] names no roles — use `true` to open the field to anyone in its scope, or list at least one role"
|
|
231
|
+
});
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
return condition;
|
|
442
235
|
}
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
return { type: "field.append", target, value: { type: "object", fields } };
|
|
446
|
-
}
|
|
447
|
-
function resolveRef({
|
|
448
|
-
ref,
|
|
449
|
-
env,
|
|
450
|
-
path,
|
|
451
|
-
ctx
|
|
452
|
-
}) {
|
|
453
|
-
const layers = ref.scope === void 0 ? env.layers : env.layers.filter((l) => l.scope === ref.scope);
|
|
454
|
-
for (const layer of layers)
|
|
455
|
-
if (layer.entries.has(ref.field)) return { scope: layer.scope, field: ref.field };
|
|
456
|
-
const reachable = env.layers.flatMap((l) => [...l.entries.keys()].map((n) => `${l.scope}:${n}`));
|
|
457
|
-
ctx.issues.push({
|
|
458
|
-
path,
|
|
459
|
-
message: `field reference "${ref.field}"${ref.scope ? ` (scope "${ref.scope}")` : ""} does not resolve to a declared entry. Reachable: ${reachable.join(", ") || "(none)"}`
|
|
460
|
-
});
|
|
236
|
+
return editable;
|
|
461
237
|
}
|
|
462
|
-
|
|
463
|
-
|
|
238
|
+
|
|
239
|
+
function editableFieldNames({workflowFields: workflowFields, stageFields: stageFields, activities: activities}) {
|
|
240
|
+
const names = /* @__PURE__ */ new Set, collect = entries => {
|
|
241
|
+
for (const entry of entries ?? []) entry.editable !== void 0 && names.add(entry.name);
|
|
242
|
+
};
|
|
243
|
+
collect(workflowFields), collect(stageFields);
|
|
244
|
+
for (const activity of activities) collect(activity.fields);
|
|
245
|
+
return names;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function desugarStageEditable({overrides: overrides, inScope: inScope, path: path, ctx: ctx}) {
|
|
249
|
+
if (overrides === void 0) return;
|
|
250
|
+
const out = {};
|
|
251
|
+
for (const [name, value] of Object.entries(overrides)) {
|
|
252
|
+
if (!inScope.has(name)) {
|
|
253
|
+
ctx.issues.push({
|
|
254
|
+
path: [ ...path, name ],
|
|
255
|
+
message: `stage editable override "${name}" does not narrow an editable field in scope — name a workflow/stage/activity field of this stage that declares \`editable\``
|
|
256
|
+
});
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const normalized = normalizeEditable({
|
|
260
|
+
editable: value,
|
|
261
|
+
path: [ ...path, name ],
|
|
262
|
+
ctx: ctx
|
|
263
|
+
});
|
|
264
|
+
normalized !== void 0 && (out[name] = normalized);
|
|
265
|
+
}
|
|
266
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
464
267
|
}
|
|
465
|
-
|
|
466
|
-
|
|
268
|
+
|
|
269
|
+
function layerOf(entries) {
|
|
270
|
+
return new Map((entries ?? []).map(entry => [ entry.name, entry ]));
|
|
467
271
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
return
|
|
272
|
+
|
|
273
|
+
function normalizeGroup(group) {
|
|
274
|
+
return group === void 0 || Array.isArray(group) ? group : [ group ];
|
|
471
275
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
for (const [i, stage] of def.stages.entries()) {
|
|
501
|
-
const activityNames = checkDuplicates({
|
|
502
|
-
names: (stage.activities ?? []).map((activity, j) => ({
|
|
503
|
-
name: activity.name,
|
|
504
|
-
path: ["stages", i, "activities", j, "name"]
|
|
505
|
-
})),
|
|
506
|
-
what: `activity name in stage "${stage.name}"`,
|
|
507
|
-
issues
|
|
508
|
-
});
|
|
509
|
-
checkDuplicates({
|
|
510
|
-
names: (stage.transitions ?? []).map((t, k) => ({
|
|
511
|
-
name: t.name,
|
|
512
|
-
path: ["stages", i, "transitions", k, "name"]
|
|
513
|
-
})),
|
|
514
|
-
what: `transition name in stage "${stage.name}"`,
|
|
515
|
-
issues
|
|
516
|
-
}), checkActivities({ def, i, activityNames, issues });
|
|
517
|
-
}
|
|
518
|
-
return stageNames;
|
|
519
|
-
}
|
|
520
|
-
function checkActivities({
|
|
521
|
-
def,
|
|
522
|
-
i,
|
|
523
|
-
activityNames,
|
|
524
|
-
issues
|
|
525
|
-
}) {
|
|
526
|
-
const stage = def.stages[i];
|
|
527
|
-
for (const [j, activity] of (stage.activities ?? []).entries()) {
|
|
528
|
-
const path = ["stages", i, "activities", j];
|
|
529
|
-
checkDuplicates({
|
|
530
|
-
names: (activity.actions ?? []).map((action, a) => ({
|
|
531
|
-
name: action.name,
|
|
532
|
-
path: [...path, "actions", a, "name"]
|
|
533
|
-
})),
|
|
534
|
-
what: `action name in activity "${activity.name}"`,
|
|
535
|
-
issues
|
|
536
|
-
}), checkStatusSetTargets({ activity, activityNames, path, issues });
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
function checkStatusSetTargets({
|
|
540
|
-
activity,
|
|
541
|
-
activityNames,
|
|
542
|
-
path,
|
|
543
|
-
issues
|
|
544
|
-
}) {
|
|
545
|
-
checkStatusSetOps({ ops: activity.ops, activityNames, path: [...path, "ops"], issues });
|
|
546
|
-
for (const [a, action] of (activity.actions ?? []).entries())
|
|
547
|
-
checkStatusSetOps({
|
|
548
|
-
ops: action.ops,
|
|
549
|
-
activityNames,
|
|
550
|
-
path: [...path, "actions", a, "ops"],
|
|
551
|
-
issues
|
|
276
|
+
|
|
277
|
+
function desugarActivity({activity: activity, path: path, stageEnv: stageEnv, ctx: ctx}) {
|
|
278
|
+
const activityFields = desugarFieldEntries({
|
|
279
|
+
entries: activity.fields,
|
|
280
|
+
path: [ ...path, "fields" ],
|
|
281
|
+
ctx: ctx
|
|
282
|
+
}), env = {
|
|
283
|
+
layers: [ {
|
|
284
|
+
scope: "activity",
|
|
285
|
+
entries: layerOf(activityFields)
|
|
286
|
+
}, ...stageEnv.layers ]
|
|
287
|
+
}, ops = desugarOps({
|
|
288
|
+
ops: activity.ops,
|
|
289
|
+
path: [ ...path, "ops" ],
|
|
290
|
+
env: env,
|
|
291
|
+
firingActivity: activity.name,
|
|
292
|
+
ctx: ctx
|
|
293
|
+
}), actions = (activity.actions ?? []).map((action, a) => desugarAction({
|
|
294
|
+
action: action,
|
|
295
|
+
path: [ ...path, "actions", a ],
|
|
296
|
+
env: env,
|
|
297
|
+
activityName: activity.name,
|
|
298
|
+
ctx: ctx
|
|
299
|
+
})), target = desugarTarget({
|
|
300
|
+
target: activity.target,
|
|
301
|
+
env: env,
|
|
302
|
+
path: [ ...path, "target" ],
|
|
303
|
+
ctx: ctx
|
|
552
304
|
});
|
|
305
|
+
return {
|
|
306
|
+
...stripUndefined({
|
|
307
|
+
name: activity.name,
|
|
308
|
+
title: activity.title,
|
|
309
|
+
description: activity.description,
|
|
310
|
+
groups: activity.groups,
|
|
311
|
+
group: normalizeGroup(activity.group),
|
|
312
|
+
kind: activity.kind,
|
|
313
|
+
filter: activity.filter,
|
|
314
|
+
requirements: activity.requirements,
|
|
315
|
+
completeWhen: activity.completeWhen,
|
|
316
|
+
failWhen: activity.failWhen,
|
|
317
|
+
effects: activity.effects,
|
|
318
|
+
subworkflows: activity.subworkflows
|
|
319
|
+
}),
|
|
320
|
+
activation: activity.activation ?? "manual",
|
|
321
|
+
...target ? {
|
|
322
|
+
target: target
|
|
323
|
+
} : {},
|
|
324
|
+
...activityFields ? {
|
|
325
|
+
fields: activityFields
|
|
326
|
+
} : {},
|
|
327
|
+
...ops ? {
|
|
328
|
+
ops: ops
|
|
329
|
+
} : {},
|
|
330
|
+
...actions.length > 0 ? {
|
|
331
|
+
actions: actions
|
|
332
|
+
} : {}
|
|
333
|
+
};
|
|
553
334
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
335
|
+
|
|
336
|
+
const TARGET_DOC_KINDS = [ "doc.ref", "doc.refs", "release.ref" ];
|
|
337
|
+
|
|
338
|
+
function desugarTarget({target: target, env: env, path: path, ctx: ctx}) {
|
|
339
|
+
if (target === void 0 || target.type === "url") return target;
|
|
340
|
+
const ref = typeof target.field == "string" ? {
|
|
341
|
+
field: target.field
|
|
342
|
+
} : target.field, field = resolveRef({
|
|
343
|
+
ref: ref,
|
|
344
|
+
env: env,
|
|
345
|
+
path: [ ...path, "field" ],
|
|
346
|
+
ctx: ctx
|
|
347
|
+
}) ?? fallbackRef(ref), entry = entryAt(env, field);
|
|
348
|
+
return entry && !TARGET_DOC_KINDS.includes(entry.type) && ctx.issues.push({
|
|
349
|
+
path: [ ...path, "field" ],
|
|
350
|
+
message: `manual activity target references "${field.field}" of kind "${entry.type}" — a deep-link target needs a document-valued entry (${TARGET_DOC_KINDS.join(", ")})`
|
|
351
|
+
}), {
|
|
352
|
+
type: "field",
|
|
353
|
+
field: field
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function desugarAction({action: action, path: path, env: env, activityName: activityName, ctx: ctx}) {
|
|
358
|
+
if ("type" in action) return desugarClaimAction({
|
|
359
|
+
action: action,
|
|
360
|
+
path: path,
|
|
361
|
+
env: env,
|
|
362
|
+
ctx: ctx
|
|
564
363
|
});
|
|
364
|
+
const filter = invariants.andConditions([ rolesCondition(action.roles, ctx.roleAliases), action.filter ]), ops = desugarOps({
|
|
365
|
+
ops: action.ops,
|
|
366
|
+
path: [ ...path, "ops" ],
|
|
367
|
+
env: env,
|
|
368
|
+
firingActivity: activityName,
|
|
369
|
+
ctx: ctx
|
|
370
|
+
}) ?? [];
|
|
371
|
+
return action.status !== void 0 && ops.push({
|
|
372
|
+
type: "status.set",
|
|
373
|
+
activity: activityName,
|
|
374
|
+
status: action.status
|
|
375
|
+
}), {
|
|
376
|
+
...stripUndefined({
|
|
377
|
+
name: action.name,
|
|
378
|
+
title: action.title,
|
|
379
|
+
description: action.description,
|
|
380
|
+
group: normalizeGroup(action.group),
|
|
381
|
+
params: action.params,
|
|
382
|
+
effects: action.effects
|
|
383
|
+
}),
|
|
384
|
+
...filter ? {
|
|
385
|
+
filter: filter
|
|
386
|
+
} : {},
|
|
387
|
+
...ops.length > 0 ? {
|
|
388
|
+
ops: ops
|
|
389
|
+
} : {}
|
|
390
|
+
};
|
|
565
391
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
function checkTransitionTargets({
|
|
577
|
-
def,
|
|
578
|
-
stageNames,
|
|
579
|
-
issues
|
|
580
|
-
}) {
|
|
581
|
-
for (const [i, stage] of def.stages.entries())
|
|
582
|
-
for (const [k, t] of (stage.transitions ?? []).entries())
|
|
583
|
-
stageNames.has(t.to) || issues.push({
|
|
584
|
-
path: ["stages", i, "transitions", k, "to"],
|
|
585
|
-
message: `transition target "${t.to}" is not a declared stage. Known stages: ${knownList(stageNames)}`
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
function checkEffectNames(def, issues) {
|
|
589
|
-
const sites = [];
|
|
590
|
-
for (const [i, stage] of def.stages.entries()) {
|
|
591
|
-
for (const [j, activity] of (stage.activities ?? []).entries()) {
|
|
592
|
-
collectEffects({
|
|
593
|
-
effects: activity.effects,
|
|
594
|
-
path: ["stages", i, "activities", j, "effects"],
|
|
595
|
-
sites
|
|
596
|
-
});
|
|
597
|
-
for (const [a, action] of (activity.actions ?? []).entries())
|
|
598
|
-
collectEffects({
|
|
599
|
-
effects: action.effects,
|
|
600
|
-
path: ["stages", i, "activities", j, "actions", a, "effects"],
|
|
601
|
-
sites
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
for (const [k, t] of (stage.transitions ?? []).entries())
|
|
605
|
-
collectEffects({ effects: t.effects, path: ["stages", i, "transitions", k, "effects"], sites });
|
|
606
|
-
}
|
|
607
|
-
checkDuplicates({
|
|
608
|
-
names: sites,
|
|
609
|
-
what: "effect name (registry key \u2014 unique per definition)",
|
|
610
|
-
issues
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
function collectEffects({
|
|
614
|
-
effects,
|
|
615
|
-
path,
|
|
616
|
-
sites
|
|
617
|
-
}) {
|
|
618
|
-
for (const [e, effect] of (effects ?? []).entries())
|
|
619
|
-
sites.push({ name: effect.name, path: [...path, e, "name"] });
|
|
620
|
-
}
|
|
621
|
-
function checkGuardNames(def, issues) {
|
|
622
|
-
const sites = def.stages.flatMap(
|
|
623
|
-
(stage, i) => (stage.guards ?? []).map((guard, g) => ({
|
|
624
|
-
name: guard.name,
|
|
625
|
-
path: ["stages", i, "guards", g, "name"]
|
|
626
|
-
}))
|
|
627
|
-
);
|
|
628
|
-
checkDuplicates({
|
|
629
|
-
names: sites,
|
|
630
|
-
what: "guard name (the guard lake _id derives from it \u2014 unique per definition)",
|
|
631
|
-
issues
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
function fieldScopes(def) {
|
|
635
|
-
const scopes = [
|
|
636
|
-
{ entries: def.fields, scope: "workflow", path: ["fields"], label: "workflow fields" }
|
|
637
|
-
];
|
|
638
|
-
for (const [i, stage] of def.stages.entries()) {
|
|
639
|
-
scopes.push({
|
|
640
|
-
entries: stage.fields,
|
|
641
|
-
scope: "stage",
|
|
642
|
-
path: ["stages", i, "fields"],
|
|
643
|
-
label: `stage "${stage.name}" fields`
|
|
392
|
+
|
|
393
|
+
function desugarClaimAction({action: action, path: path, env: env, ctx: ctx}) {
|
|
394
|
+
const ref = typeof action.field == "string" ? {
|
|
395
|
+
field: action.field
|
|
396
|
+
} : action.field, resolved = resolveRef({
|
|
397
|
+
ref: ref,
|
|
398
|
+
env: env,
|
|
399
|
+
path: [ ...path, "field" ],
|
|
400
|
+
ctx: ctx
|
|
644
401
|
});
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
else if (entry.initialValue?.type !== "input") {
|
|
665
|
-
const seed = entry.initialValue?.type ?? "working memory (no initialValue)";
|
|
666
|
-
issues.push({
|
|
667
|
-
path: [...path, n, "required"],
|
|
668
|
-
message: `field entry "${entry.name}" has initialValue "${seed}" \u2014 \`required\` applies only to \`input\`-sourced entries (the caller fills them at start/spawn)`
|
|
669
|
-
});
|
|
402
|
+
if (resolved) {
|
|
403
|
+
const entry = entryAt(env, resolved);
|
|
404
|
+
entry && entry.type !== "actor" && ctx.issues.push({
|
|
405
|
+
path: [ ...path, "field" ],
|
|
406
|
+
message: `claim action "${action.name}" references "${resolved.field}" of kind "${entry.type}" — a claim pair needs an actor-valued entry (a "claim" or "actor" field declaration)`
|
|
407
|
+
}), checkShadowedClaimTarget({
|
|
408
|
+
actionName: action.name,
|
|
409
|
+
field: ref.field,
|
|
410
|
+
resolved: resolved,
|
|
411
|
+
env: env,
|
|
412
|
+
path: [ ...path, "field" ],
|
|
413
|
+
ctx: ctx
|
|
414
|
+
}), entry && ctx.claimedFields.add(entry);
|
|
415
|
+
}
|
|
416
|
+
const noSteal = `!defined($fields.${ref.field})`, filter = invariants.andConditions([ noSteal, rolesCondition(action.roles, ctx.roleAliases), action.filter ]), ops = resolved ? [ {
|
|
417
|
+
type: "field.set",
|
|
418
|
+
target: resolved,
|
|
419
|
+
value: {
|
|
420
|
+
type: "actor"
|
|
670
421
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
422
|
+
} ] : [];
|
|
423
|
+
return {
|
|
424
|
+
...stripUndefined({
|
|
425
|
+
name: action.name,
|
|
426
|
+
title: action.title,
|
|
427
|
+
description: action.description,
|
|
428
|
+
group: normalizeGroup(action.group),
|
|
429
|
+
params: action.params,
|
|
430
|
+
effects: action.effects
|
|
431
|
+
}),
|
|
432
|
+
filter: filter,
|
|
433
|
+
...ops.length > 0 ? {
|
|
434
|
+
ops: ops
|
|
435
|
+
} : {}
|
|
436
|
+
};
|
|
680
437
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
});
|
|
688
|
-
for (const [name, groq2] of Object.entries(def.predicates ?? {}))
|
|
689
|
-
checkPredicateBody({ name, groq: groq2, names, issues });
|
|
690
|
-
}
|
|
691
|
-
function checkPredicateBody({
|
|
692
|
-
name,
|
|
693
|
-
groq: groq2,
|
|
694
|
-
names,
|
|
695
|
-
issues
|
|
696
|
-
}) {
|
|
697
|
-
for (const caller of PREDICATE_CALLER_VARS)
|
|
698
|
-
referencesVar(groq2, caller) && issues.push({
|
|
699
|
-
path: ["predicates", name],
|
|
700
|
-
message: `predicate "${name}" reads $${caller} \u2014 predicates are instance-level (pre-evaluated once, without a caller); compose caller gates at the condition site instead`
|
|
438
|
+
|
|
439
|
+
function checkShadowedClaimTarget({actionName: actionName, field: field, resolved: resolved, env: env, path: path, ctx: ctx}) {
|
|
440
|
+
const nearest = env.layers.find(l => l.entries.has(field));
|
|
441
|
+
nearest === void 0 || nearest.scope === resolved.scope || ctx.issues.push({
|
|
442
|
+
path: path,
|
|
443
|
+
message: `claim action "${actionName}" targets "${field}" at scope "${resolved.scope}", but a nearer ${nearest.scope}-scope entry of the same name shadows it in $fields — the no-steal filter would read the shadowing entry while the claim writes the "${resolved.scope}" one. Rename one of the entries or claim the nearer one`
|
|
701
444
|
});
|
|
702
|
-
for (const other of names)
|
|
703
|
-
other === name || !referencesVar(groq2, other) || issues.push({
|
|
704
|
-
path: ["predicates", name],
|
|
705
|
-
message: `predicate "${name}" references predicate $${other} \u2014 predicates may read built-in vars only (no cross-references; compose at the condition site instead)`
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
function referencesVar(groq2, name) {
|
|
709
|
-
return schema.GROQ_IDENTIFIER.test(name) ? new RegExp(`\\$${name}\\b`).test(groq2) : !1;
|
|
710
445
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
446
|
+
|
|
447
|
+
function checkUnclaimedClaimFields(ctx) {
|
|
448
|
+
for (const [entry, {name: name, path: path}] of ctx.claimFields) ctx.claimedFields.has(entry) || ctx.issues.push({
|
|
449
|
+
path: path,
|
|
450
|
+
message: `claim field "${name}" is never referenced by a claim action — you announced the pattern and wrote half of it. Declare a defineAction({ type: "claim", field: "${name}" }) or use a raw actor entry`
|
|
716
451
|
});
|
|
717
452
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
}), collectBindingSites({
|
|
727
|
-
effects: t.effects,
|
|
728
|
-
path: ["stages", i, "transitions", k, "effects"],
|
|
729
|
-
label: `transition "${t.name}"`,
|
|
730
|
-
sites
|
|
731
|
-
}), collectOpWhereSites({
|
|
732
|
-
ops: t.ops,
|
|
733
|
-
path: ["stages", i, "transitions", k, "ops"],
|
|
734
|
-
label: `transition "${t.name}"`,
|
|
735
|
-
sites
|
|
736
|
-
});
|
|
737
|
-
for (const [j, activity] of (stage.activities ?? []).entries())
|
|
738
|
-
collectActivityConditionSites({ activity, path: ["stages", i, "activities", j], sites });
|
|
739
|
-
}
|
|
740
|
-
return sites;
|
|
741
|
-
}
|
|
742
|
-
function collectOpWhereSites({
|
|
743
|
-
ops,
|
|
744
|
-
path,
|
|
745
|
-
label,
|
|
746
|
-
sites
|
|
747
|
-
}) {
|
|
748
|
-
for (const [o, op] of (ops ?? []).entries())
|
|
749
|
-
op.where !== void 0 && sites.push({
|
|
750
|
-
groq: op.where,
|
|
751
|
-
path: [...path, o, "where"],
|
|
752
|
-
label: `${label} ${op.type} where`
|
|
453
|
+
|
|
454
|
+
function desugarTransition({transition: transition, path: path, stageEnv: stageEnv, ctx: ctx}) {
|
|
455
|
+
const ops = desugarOps({
|
|
456
|
+
ops: transition.ops,
|
|
457
|
+
path: [ ...path, "ops" ],
|
|
458
|
+
env: stageEnv,
|
|
459
|
+
firingActivity: void 0,
|
|
460
|
+
ctx: ctx
|
|
753
461
|
});
|
|
462
|
+
return {
|
|
463
|
+
...stripUndefined({
|
|
464
|
+
name: transition.name,
|
|
465
|
+
title: transition.title,
|
|
466
|
+
description: transition.description,
|
|
467
|
+
to: transition.to,
|
|
468
|
+
effects: transition.effects
|
|
469
|
+
}),
|
|
470
|
+
filter: transition.filter ?? "$allActivitiesDone",
|
|
471
|
+
...ops ? {
|
|
472
|
+
ops: ops
|
|
473
|
+
} : {}
|
|
474
|
+
};
|
|
754
475
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
path: [...subPath, "forEach"],
|
|
800
|
-
label: `activity "${activity.name}".subworkflows.forEach`
|
|
801
|
-
});
|
|
802
|
-
for (const [group, record] of [
|
|
803
|
-
["with", sub.with],
|
|
804
|
-
["context", sub.context]
|
|
805
|
-
])
|
|
806
|
-
for (const [key, groq2] of Object.entries(record ?? {}))
|
|
807
|
-
sites.push({
|
|
808
|
-
groq: groq2,
|
|
809
|
-
path: [...subPath, group, key],
|
|
810
|
-
label: `activity "${activity.name}".subworkflows.${group} "${key}"`
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
function collectBindingSites({
|
|
814
|
-
effects,
|
|
815
|
-
path,
|
|
816
|
-
label,
|
|
817
|
-
sites
|
|
818
|
-
}) {
|
|
819
|
-
for (const [e, effect] of (effects ?? []).entries())
|
|
820
|
-
for (const [key, groq2] of Object.entries(effect.bindings ?? {}))
|
|
821
|
-
sites.push({
|
|
822
|
-
groq: groq2,
|
|
823
|
-
path: [...path, e, "bindings", key],
|
|
824
|
-
label: `${label} effect "${effect.name}" binding "${key}"`
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
function checkAssigneesEntries(def, issues) {
|
|
828
|
-
for (const { entries, path } of fieldScopes(def))
|
|
829
|
-
(entries ?? []).filter((e) => e.type === "assignees").length <= 1 || issues.push({
|
|
830
|
-
path,
|
|
831
|
-
message: "at most one assignees-kind field entry per scope \u2014 the inbox reads it by kind"
|
|
476
|
+
|
|
477
|
+
function desugarGuard(guard) {
|
|
478
|
+
const {match: match, metadata: metadata, ...rest} = guard, {idRefs: idRefs, ...matchRest} = match;
|
|
479
|
+
return {
|
|
480
|
+
...rest,
|
|
481
|
+
match: {
|
|
482
|
+
...matchRest,
|
|
483
|
+
...idRefs !== void 0 ? {
|
|
484
|
+
idRefs: idRefs.map(invariants.printGuardRead)
|
|
485
|
+
} : {}
|
|
486
|
+
},
|
|
487
|
+
...metadata !== void 0 ? {
|
|
488
|
+
metadata: Object.fromEntries(Object.entries(metadata).map(([key, read]) => [ key, invariants.printGuardRead(read) ]))
|
|
489
|
+
} : {}
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function desugarOps({ops: ops, path: path, env: env, firingActivity: firingActivity, ctx: ctx}) {
|
|
494
|
+
if (ops) return ops.map((op, i) => desugarOp({
|
|
495
|
+
op: op,
|
|
496
|
+
path: [ ...path, i ],
|
|
497
|
+
env: env,
|
|
498
|
+
firingActivity: firingActivity,
|
|
499
|
+
ctx: ctx
|
|
500
|
+
}));
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function desugarOp({op: op, path: path, env: env, firingActivity: firingActivity, ctx: ctx}) {
|
|
504
|
+
if (op.type === "status.set") {
|
|
505
|
+
const activity = op.activity ?? firingActivity;
|
|
506
|
+
return activity === void 0 && ctx.issues.push({
|
|
507
|
+
path: [ ...path, "activity" ],
|
|
508
|
+
message: "status.set outside an action must name its target activity"
|
|
509
|
+
}), {
|
|
510
|
+
type: "status.set",
|
|
511
|
+
activity: activity ?? "",
|
|
512
|
+
status: op.status
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
if (op.type === "audit") return desugarAuditOp({
|
|
516
|
+
op: op,
|
|
517
|
+
path: path,
|
|
518
|
+
env: env,
|
|
519
|
+
ctx: ctx
|
|
832
520
|
});
|
|
521
|
+
const target = resolveRef({
|
|
522
|
+
ref: op.target,
|
|
523
|
+
env: env,
|
|
524
|
+
path: [ ...path, "target" ],
|
|
525
|
+
ctx: ctx
|
|
526
|
+
}) ?? fallbackRef(op.target);
|
|
527
|
+
return {
|
|
528
|
+
...op,
|
|
529
|
+
target: target
|
|
530
|
+
};
|
|
833
531
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
}
|
|
842
|
-
const KIND_SHAPE_RULES = {
|
|
843
|
-
user: (s) => s.hasActions ? [] : ["needs at least one action for a person to fire"],
|
|
844
|
-
service: (s) => s.hasEffects ? [] : ["needs at least one effect \u2014 the automated work it performs"],
|
|
845
|
-
manual: (s) => [
|
|
846
|
-
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)",
|
|
847
|
-
s.hasSubworkflows ? "is off-system work, not a fan-out \u2014 drop `subworkflows` or move it to its own activity" : void 0
|
|
848
|
-
].filter((m) => m !== void 0),
|
|
849
|
-
receive: (s) => [
|
|
850
|
-
s.hasCompleteWhen || s.hasSubworkflows ? void 0 : "needs a `completeWhen` (or `subworkflows`) condition to wait on",
|
|
851
|
-
s.hasActions ? "has no actor, so it cannot carry actions" : void 0
|
|
852
|
-
].filter((m) => m !== void 0),
|
|
853
|
-
script: (s) => [
|
|
854
|
-
s.hasActions ? "runs inline with no actor, so it cannot carry actions" : void 0,
|
|
855
|
-
s.hasCompleteWhen ? "resolves on activation, so it cannot carry a `completeWhen` (that is a `receive`/`service` wait)" : void 0,
|
|
856
|
-
s.hasSubworkflows ? "resolves on activation, so it cannot fan out with `subworkflows`" : void 0
|
|
857
|
-
].filter((m) => m !== void 0)
|
|
532
|
+
|
|
533
|
+
const AUDIT_STAMPS = {
|
|
534
|
+
actor: {
|
|
535
|
+
type: "actor"
|
|
536
|
+
},
|
|
537
|
+
at: {
|
|
538
|
+
type: "now"
|
|
539
|
+
}
|
|
858
540
|
};
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
path: [...path, "target"],
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
541
|
+
|
|
542
|
+
function desugarAuditOp({op: op, path: path, env: env, ctx: ctx}) {
|
|
543
|
+
const target = resolveRef({
|
|
544
|
+
ref: op.target,
|
|
545
|
+
env: env,
|
|
546
|
+
path: [ ...path, "target" ],
|
|
547
|
+
ctx: ctx
|
|
548
|
+
}) ?? fallbackRef(op.target);
|
|
549
|
+
if (op.value.type !== "object") return ctx.issues.push({
|
|
550
|
+
path: [ ...path, "value" ],
|
|
551
|
+
message: `audit value must be an object source carrying the domain fields (got "${op.value.type}")`
|
|
552
|
+
}), {
|
|
553
|
+
type: "field.append",
|
|
554
|
+
target: target,
|
|
555
|
+
value: op.value
|
|
556
|
+
};
|
|
557
|
+
const actorField = op.stampFields?.actor ?? "actor", atField = op.stampFields?.at ?? "at", fields = {
|
|
558
|
+
...op.value.fields
|
|
559
|
+
};
|
|
560
|
+
for (const [stamp, source] of [ [ actorField, AUDIT_STAMPS.actor ], [ atField, AUDIT_STAMPS.at ] ]) {
|
|
561
|
+
if (stamp in fields) {
|
|
562
|
+
ctx.issues.push({
|
|
563
|
+
path: [ ...path, "value", "fields", stamp ],
|
|
564
|
+
message: `audit stamp field "${stamp}" collides with an authored domain field — rename yours or remap the stamp via stampFields`
|
|
565
|
+
});
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
fields[stamp] = source;
|
|
872
569
|
}
|
|
570
|
+
return {
|
|
571
|
+
type: "field.append",
|
|
572
|
+
target: target,
|
|
573
|
+
value: {
|
|
574
|
+
type: "object",
|
|
575
|
+
fields: fields
|
|
576
|
+
}
|
|
577
|
+
};
|
|
873
578
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
579
|
+
|
|
580
|
+
function resolveRef({ref: ref, env: env, path: path, ctx: ctx}) {
|
|
581
|
+
const layers = ref.scope === void 0 ? env.layers : env.layers.filter(l => l.scope === ref.scope);
|
|
582
|
+
for (const layer of layers) if (layer.entries.has(ref.field)) return {
|
|
583
|
+
scope: layer.scope,
|
|
584
|
+
field: ref.field
|
|
585
|
+
};
|
|
586
|
+
const reachable = env.layers.flatMap(l => [ ...l.entries.keys() ].map(n => `${l.scope}:${n}`));
|
|
587
|
+
ctx.issues.push({
|
|
588
|
+
path: path,
|
|
589
|
+
message: `field reference "${ref.field}"${ref.scope ? ` (scope "${ref.scope}")` : ""} does not resolve to a declared entry. Reachable: ${reachable.join(", ") || "(none)"}`
|
|
590
|
+
});
|
|
877
591
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
592
|
+
|
|
593
|
+
function entryAt(env, ref) {
|
|
594
|
+
return env.layers.find(l => l.scope === ref.scope)?.entries.get(ref.field);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function fallbackRef(ref) {
|
|
598
|
+
return {
|
|
599
|
+
scope: ref.scope ?? "workflow",
|
|
600
|
+
field: ref.field
|
|
601
|
+
};
|
|
882
602
|
}
|
|
603
|
+
|
|
604
|
+
function rolesCondition(roles, aliases) {
|
|
605
|
+
if (!(!roles || roles.length === 0)) return groq`count($actor.roles[@ in ${invariants.expandRequiredRoles(roles, aliases)}]) > 0`;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function stripUndefined(obj) {
|
|
609
|
+
const out = {};
|
|
610
|
+
for (const [k, value] of Object.entries(obj)) value !== void 0 && (out[k] = value);
|
|
611
|
+
return out;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function defineWorkflow(definition) {
|
|
615
|
+
const label = invariants.labelFor("defineWorkflow", definition), parsed = invariants.parseOrThrow({
|
|
616
|
+
schema: invariants.AuthoringWorkflowSchema,
|
|
617
|
+
input: definition,
|
|
618
|
+
label: label
|
|
619
|
+
}), {definition: stored, issues: desugarIssues} = desugarWorkflow(parsed), issues = [ ...desugarIssues, ...invariants.checkWorkflowInvariants(stored) ];
|
|
620
|
+
if (issues.length > 0) throw new Error(invariants.formatValidationError(label, issues));
|
|
621
|
+
return stored;
|
|
622
|
+
}
|
|
623
|
+
|
|
883
624
|
function defineWorkflowConfig(config) {
|
|
884
|
-
|
|
625
|
+
return invariants.parseOrThrow({
|
|
626
|
+
schema: invariants.WorkflowConfigSchema,
|
|
627
|
+
input: config,
|
|
628
|
+
label: "defineWorkflowConfig"
|
|
629
|
+
});
|
|
885
630
|
}
|
|
631
|
+
|
|
886
632
|
function defineStage(stage) {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
633
|
+
return invariants.parseOrThrow({
|
|
634
|
+
schema: invariants.AuthoringStageSchema,
|
|
635
|
+
input: stage,
|
|
636
|
+
label: invariants.labelFor("defineStage", stage)
|
|
637
|
+
});
|
|
892
638
|
}
|
|
639
|
+
|
|
893
640
|
function defineActivity(activity) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
641
|
+
return invariants.parseOrThrow({
|
|
642
|
+
schema: invariants.AuthoringActivitySchema,
|
|
643
|
+
input: activity,
|
|
644
|
+
label: invariants.labelFor("defineActivity", activity)
|
|
645
|
+
});
|
|
899
646
|
}
|
|
647
|
+
|
|
900
648
|
function defineAction(action) {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
649
|
+
return invariants.parseOrThrow({
|
|
650
|
+
schema: invariants.AuthoringActionSchema,
|
|
651
|
+
input: action,
|
|
652
|
+
label: invariants.labelFor("defineAction", action)
|
|
653
|
+
});
|
|
906
654
|
}
|
|
655
|
+
|
|
907
656
|
function defineTransition(transition) {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
657
|
+
return invariants.parseOrThrow({
|
|
658
|
+
schema: invariants.AuthoringTransitionSchema,
|
|
659
|
+
input: transition,
|
|
660
|
+
label: transitionLabel(transition)
|
|
661
|
+
});
|
|
913
662
|
}
|
|
663
|
+
|
|
914
664
|
function defineField(entry) {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
665
|
+
return invariants.parseOrThrow({
|
|
666
|
+
schema: invariants.AuthoringFieldEntrySchema,
|
|
667
|
+
input: entry,
|
|
668
|
+
label: invariants.labelFor("defineField", entry)
|
|
669
|
+
});
|
|
920
670
|
}
|
|
671
|
+
|
|
921
672
|
function defineOp(op) {
|
|
922
|
-
|
|
673
|
+
return invariants.parseOrThrow({
|
|
674
|
+
schema: invariants.AuthoringOpSchema,
|
|
675
|
+
input: op,
|
|
676
|
+
label: "defineOp"
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function defineGroup(group) {
|
|
681
|
+
return invariants.parseOrThrow({
|
|
682
|
+
schema: invariants.GroupSchema,
|
|
683
|
+
input: group,
|
|
684
|
+
label: invariants.labelFor("defineGroup", group)
|
|
685
|
+
});
|
|
923
686
|
}
|
|
687
|
+
|
|
924
688
|
function defineGuard(guard) {
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
689
|
+
return invariants.parseOrThrow({
|
|
690
|
+
schema: invariants.AuthoringGuardSchema,
|
|
691
|
+
input: guard,
|
|
692
|
+
label: invariants.labelFor("defineGuard", guard)
|
|
693
|
+
});
|
|
930
694
|
}
|
|
695
|
+
|
|
931
696
|
function defineEffect(effect) {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
697
|
+
return invariants.parseOrThrow({
|
|
698
|
+
schema: invariants.EffectSchema,
|
|
699
|
+
input: effect,
|
|
700
|
+
label: invariants.labelFor("defineEffect", effect)
|
|
701
|
+
});
|
|
937
702
|
}
|
|
703
|
+
|
|
938
704
|
function transitionLabel(transition) {
|
|
939
|
-
|
|
940
|
-
|
|
705
|
+
const {name: name, to: to} = transition;
|
|
706
|
+
return typeof name == "string" ? `defineTransition("${name}")` : typeof to == "string" ? `defineTransition(→ "${to}")` : "defineTransition";
|
|
941
707
|
}
|
|
708
|
+
|
|
942
709
|
function defineEffectDescriptor(descriptor) {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}
|
|
956
|
-
function labelFor(fn, value) {
|
|
957
|
-
if (value && typeof value == "object" && "name" in value) {
|
|
958
|
-
const raw = value.name;
|
|
959
|
-
if (typeof raw == "string") return `${fn}("${raw}")`;
|
|
960
|
-
}
|
|
961
|
-
return fn;
|
|
962
|
-
}
|
|
963
|
-
exports.CONDITION_VARS = schema.CONDITION_VARS;
|
|
964
|
-
exports.FILTER_SCOPE_VARS = schema.FILTER_SCOPE_VARS;
|
|
965
|
-
exports.GUARD_PREDICATE_VARS = schema.GUARD_PREDICATE_VARS;
|
|
966
|
-
exports.RESERVED_CONDITION_VARS = schema.RESERVED_CONDITION_VARS;
|
|
710
|
+
if (!descriptor.name) throw new Error("EffectDescriptor missing name");
|
|
711
|
+
return descriptor;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
exports.CONDITION_VARS = invariants.CONDITION_VARS;
|
|
715
|
+
|
|
716
|
+
exports.FILTER_SCOPE_VARS = invariants.FILTER_SCOPE_VARS;
|
|
717
|
+
|
|
718
|
+
exports.GUARD_PREDICATE_VARS = invariants.GUARD_PREDICATE_VARS;
|
|
719
|
+
|
|
720
|
+
exports.RESERVED_CONDITION_VARS = invariants.RESERVED_CONDITION_VARS;
|
|
721
|
+
|
|
967
722
|
exports.defineAction = defineAction;
|
|
723
|
+
|
|
968
724
|
exports.defineActivity = defineActivity;
|
|
725
|
+
|
|
969
726
|
exports.defineEffect = defineEffect;
|
|
727
|
+
|
|
970
728
|
exports.defineEffectDescriptor = defineEffectDescriptor;
|
|
729
|
+
|
|
971
730
|
exports.defineField = defineField;
|
|
731
|
+
|
|
732
|
+
exports.defineGroup = defineGroup;
|
|
733
|
+
|
|
972
734
|
exports.defineGuard = defineGuard;
|
|
735
|
+
|
|
973
736
|
exports.defineOp = defineOp;
|
|
737
|
+
|
|
974
738
|
exports.defineStage = defineStage;
|
|
739
|
+
|
|
975
740
|
exports.defineTransition = defineTransition;
|
|
741
|
+
|
|
976
742
|
exports.defineWorkflow = defineWorkflow;
|
|
743
|
+
|
|
977
744
|
exports.defineWorkflowConfig = defineWorkflowConfig;
|
|
745
|
+
|
|
978
746
|
exports.groq = groq;
|
|
979
|
-
//# sourceMappingURL=define.cjs.map
|