@uipath/case-tool 1.203.0-preview.212 → 1.204.0-preview.211

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.
Files changed (85) hide show
  1. package/README.md +6 -1
  2. package/dist/THIRD-PARTY-NOTICES.md +10 -9
  3. package/dist/authoring-0hr88kff.js +623 -0
  4. package/dist/{case-api-v6cjyrfw.js → case-api-gdaj9469.js} +5 -5
  5. package/dist/case-bindings-service-c2mze9vj.js +476 -0
  6. package/dist/{case-debug-studio-web-service-8th9d8sm.js → case-debug-studio-web-service-6q9ch7cq.js} +11 -10
  7. package/dist/case-described-io-service-cpe5h2ks.js +132 -0
  8. package/dist/{case-format-service-q345a2fd.js → case-format-service-qwyjyt0y.js} +2 -2
  9. package/dist/{case-pack-service-29rza2q2.js → case-pack-service-47yrvmg0.js} +11 -11
  10. package/dist/case-shape-reader-mw58avr0.js +13 -0
  11. package/dist/case-splice-service-9zvw19ca.js +312 -0
  12. package/dist/{case-validate-service-84drzwx3.js → case-validate-service-jcdf4n67.js} +415 -1449
  13. package/dist/{connector-enrichment-service-2982ykgb.js → connector-enrichment-service-60wwjarq.js} +20 -18
  14. package/dist/{connector-lookup-service-8ddh4pq2.js → connector-lookup-service-zhf8fz2j.js} +7 -7
  15. package/dist/{connector-task-spec-qs7q7vnv.js → connector-task-spec-96e3wzx7.js} +86 -26
  16. package/dist/{debug-service-8x087xxt.js → debug-service-vf5mw0nr.js} +3 -3
  17. package/dist/{embedded-file-reader-0sjt4nkj.js → embedded-file-reader-v8c2yj2a.js} +2 -2
  18. package/dist/{enrichment-service-7vbxcwge.js → enrichment-service-78b0gqck.js} +8 -7
  19. package/dist/index-hhsf00x8.js +15 -0
  20. package/dist/{index-fz4ttsde.js → index-j2r3jb6c.js} +5 -3
  21. package/dist/{index-yj8fb3q6.js → index-k7gkw7s9.js} +59 -27
  22. package/dist/{index-jxj2jz45.js → index-rgw7caht.js} +416 -87
  23. package/dist/{index-k4xz16db.js → index-wmffgzmr.js} +12522 -7316
  24. package/dist/index.js +15 -11
  25. package/dist/{input-reader-pnh948bq.js → input-reader-bb0ptk2v.js} +2 -2
  26. package/dist/migration-diagnosis-ag2sgd1e.js +71 -0
  27. package/dist/{node-strategy-gc4sg6a2.js → node-strategy-5pz40tee.js} +1 -1
  28. package/dist/{node-sync-service-t193ery3.js → node-sync-service-zwjcwgwc.js} +6 -6
  29. package/dist/out-target-1f4n9vqb.js +70 -0
  30. package/dist/{packager-tool-wefb1zw3.js → packager-tool-0p3td5zv.js} +8 -7
  31. package/dist/packager-tool-21qfsbxn.js +17 -0
  32. package/dist/{strict-sdd-audit-8e2fh9jg.js → packager-tool-4e56rmwe.js} +2771 -1746
  33. package/dist/{packager-tool-sfkyb4kz.js → packager-tool-4rqd21wc.js} +194 -2
  34. package/dist/packager-tool-57pzrd0g.js +32 -0
  35. package/dist/{packager-tool-kpcjnxd1.js → packager-tool-58kx79ta.js} +586 -113
  36. package/dist/{packager-tool-hrdan5ms.js → packager-tool-5qghkdd0.js} +2 -2
  37. package/dist/packager-tool-5qp9xza1.js +10 -0
  38. package/dist/{packager-tool-3qkp2fts.js → packager-tool-76ms0wdw.js} +4 -4
  39. package/dist/packager-tool-8a9yqfq7.js +76 -0
  40. package/dist/packager-tool-b250k6w4.js +75 -0
  41. package/dist/packager-tool-bfgdz1zh.js +73 -0
  42. package/dist/{packager-tool-p7jgrm5r.js → packager-tool-cmwets3m.js} +1 -1
  43. package/dist/{packager-tool-d4sjk46c.js → packager-tool-cv05dwac.js} +18 -21
  44. package/dist/packager-tool-d7jjng8a.js +21 -0
  45. package/dist/{packager-tool-rh07gzxw.js → packager-tool-dqnc61h1.js} +5 -5
  46. package/dist/packager-tool-dthjwajc.js +13 -0
  47. package/dist/packager-tool-f78ntj5g.js +228 -0
  48. package/dist/{packager-tool-r1g8rqcs.js → packager-tool-gjhg49r1.js} +4 -4
  49. package/dist/{packager-tool-cg2j4rma.js → packager-tool-kacqd7h7.js} +4 -4
  50. package/dist/packager-tool-mknccck5.js +24 -0
  51. package/dist/{packager-tool-sv0d6wb6.js → packager-tool-nj4seavy.js} +7 -3
  52. package/dist/{packager-tool-adcaxdhs.js → packager-tool-paepfv5d.js} +1 -1
  53. package/dist/{packager-tool-052kvydg.js → packager-tool-pm646ag4.js} +1 -1
  54. package/dist/{packager-tool-qht4xd0y.js → packager-tool-q86py4rp.js} +320 -200
  55. package/dist/{packager-tool-geaetyks.js → packager-tool-qmeaj10z.js} +669 -100
  56. package/dist/{packager-tool-dd8bq6az.js → packager-tool-rgpdaxbx.js} +548 -108
  57. package/dist/{packager-tool-8q7vzh65.js → packager-tool-s3e2kepj.js} +455 -13
  58. package/dist/{packager-tool-r84ng21s.js → packager-tool-sag9gz55.js} +3 -1
  59. package/dist/{packager-tool-0mj06yen.js → packager-tool-sq931c23.js} +5 -22
  60. package/dist/{packager-tool-7mggwye6.js → packager-tool-tmfbp50w.js} +6 -6
  61. package/dist/{packager-tool-yrsrzz1a.js → packager-tool-v99ygh9f.js} +23 -8
  62. package/dist/packager-tool-wj9d9mqe.js +267 -0
  63. package/dist/{packager-tool-hz1mz8fs.js → packager-tool-wjaya2k2.js} +2 -2
  64. package/dist/packager-tool-xcd87qyx.js +44 -0
  65. package/dist/{packager-tool-0v3s8r01.js → packager-tool-xdxr3ync.js} +4 -2
  66. package/dist/{packager-tool-61hxhgeg.js → packager-tool-xkgq5fkf.js} +3 -3
  67. package/dist/packager-tool.js +6 -6
  68. package/dist/{project-artifacts-8snev67g.js → project-artifacts-wzrhketn.js} +1 -1
  69. package/dist/resolved-check-p99hysaw.js +50 -0
  70. package/dist/{resourcesSyncService-01qr5zp7.js → resourcesSyncService-rjt0tht7.js} +25 -18
  71. package/dist/rule-group-members-zje7n3kf.js +76 -0
  72. package/dist/sdd-convert-service-gp9733qv.js +1962 -0
  73. package/dist/{sdd-lookup-x08j9g9m.js → sdd-lookup-vpjej1kt.js} +2 -2
  74. package/dist/sdd-resolve-service-4hx64x3z.js +288 -0
  75. package/dist/strict-case-rules-ksy8q7pg.js +731 -0
  76. package/dist/strict-entry-points-v14d7y50.js +124 -0
  77. package/dist/strict-sdd-audit-k6hh0mbr.js +23 -0
  78. package/dist/task-selector-8bjn35dv.js +57 -0
  79. package/dist/tool.js +15 -11
  80. package/dist/{trigger-enrichment-service-sddbphf2.js → trigger-enrichment-service-kst89jbe.js} +41 -23
  81. package/package.json +2 -2
  82. package/dist/authoring-kngaggwm.js +0 -360
  83. package/dist/case-bindings-service-1wxfghzd.js +0 -240
  84. package/dist/packager-tool-83qnybab.js +0 -1564
  85. package/dist/strict-case-rules-x6t0vb40.js +0 -409
@@ -0,0 +1,1962 @@
1
+ import {
2
+ CONNECTOR_TASK_TYPES
3
+ } from "./packager-tool-dthjwajc.js";
4
+ import {
5
+ BINDING_REFERENCE_PREFIX,
6
+ NAME_BOUND_TASK_TYPES
7
+ } from "./packager-tool-d7jjng8a.js";
8
+ import {
9
+ FILE_TYPE_JSON_SCHEMA
10
+ } from "./packager-tool-xkgq5fkf.js";
11
+ import {
12
+ CASE_SLA_PROPERTY,
13
+ DEFAULT_GROUP,
14
+ STAGE_SELECTOR_RULES,
15
+ TASK_SELECTOR_RULES,
16
+ VARIABLE_PLACEMENT,
17
+ parseIfCell
18
+ } from "./packager-tool-4e56rmwe.js";
19
+ import"./packager-tool-b250k6w4.js";
20
+ import"./packager-tool-21qfsbxn.js";
21
+ import {
22
+ namedValue,
23
+ withoutTrailingSlug
24
+ } from "./packager-tool-f78ntj5g.js";
25
+ import {
26
+ buildMinimalCaseDocument
27
+ } from "./packager-tool-xcd87qyx.js";
28
+ import {
29
+ prefixedId
30
+ } from "./packager-tool-mknccck5.js";
31
+ import"./packager-tool-nj4seavy.js";
32
+ import {
33
+ byCodeUnit
34
+ } from "./packager-tool-5qp9xza1.js";
35
+ import {
36
+ catchError
37
+ } from "./packager-tool-58kx79ta.js";
38
+ import"./packager-tool-xdxr3ync.js";
39
+ import"./packager-tool-1yh8g550.js";
40
+
41
+ // src/services/exit-condition-types.ts
42
+ var EXIT_CONDITION_TYPES = new Set([
43
+ "exit-only",
44
+ "wait-for-user",
45
+ "return-to-origin"
46
+ ]);
47
+
48
+ // src/services/sdd-convert/ids.ts
49
+ var buildElementId = (stageId, taskId) => `${stageId}-${taskId}`;
50
+ var SLUG_SUFFIX = /^(.*?)\s*\(\s*([^()]+?)\s*\)\s*$/;
51
+ var stageSpellings = (text, position) => {
52
+ const plain = text.replaceAll("`", "").trim();
53
+ const names = [plain];
54
+ const found = SLUG_SUFFIX.exec(plain);
55
+ const bare = found?.[1].trim() ?? "";
56
+ const slug = found?.[2].trim() ?? "";
57
+ if (bare !== "" && bare !== plain)
58
+ names.push(bare);
59
+ return {
60
+ names,
61
+ ...slug !== "" && { slug },
62
+ ordinal: `stage ${position}`
63
+ };
64
+ };
65
+ var referenceSpellings = (text) => {
66
+ const { names, slug } = stageSpellings(text, 0);
67
+ return slug === undefined ? names : [...names, slug];
68
+ };
69
+ var indexKey = (name) => name.replaceAll("`", "").trim().toLowerCase();
70
+ var everySpelling = (name, position) => {
71
+ const { names, slug, ordinal } = stageSpellings(name, position);
72
+ return [...names, ...slug === undefined ? [] : [slug], ordinal].map(indexKey);
73
+ };
74
+ var claim = (index, key, id) => {
75
+ if (!index.has(key))
76
+ index.set(key, id);
77
+ };
78
+ var dedupedId = (base, taken) => {
79
+ let id = base;
80
+ let suffix = 2;
81
+ while (taken.has(id)) {
82
+ id = `${base}${suffix}`;
83
+ suffix += 1;
84
+ }
85
+ taken.add(id);
86
+ return id;
87
+ };
88
+ var exactKey = (name) => name.replaceAll("`", "").trim();
89
+ var claimOutput = (index, key, task, id) => {
90
+ const byTask = index.get(key) ?? new Map;
91
+ index.set(key, byTask);
92
+ if (!byTask.has(exactKey(task)))
93
+ byTask.set(exactKey(task), id);
94
+ };
95
+ var lookupOutput = (index, key, task) => {
96
+ const byTask = index.get(key);
97
+ if (byTask === undefined)
98
+ return;
99
+ const tasksNamed = (name, claim2) => typeof claim2 === "number" ? Array.from({ length: claim2 }, () => name) : [name];
100
+ const exact = byTask.get(exactKey(task));
101
+ if (exact !== undefined) {
102
+ return typeof exact === "number" ? { names: tasksNamed(exactKey(task), exact) } : { id: exact };
103
+ }
104
+ const [onlyName, only] = [...byTask.entries()][0] ?? [];
105
+ if (byTask.size === 1 && onlyName !== undefined && typeof only === "string") {
106
+ return { id: only };
107
+ }
108
+ return {
109
+ names: [...byTask].flatMap(([name, claim2]) => tasksNamed(name, claim2))
110
+ };
111
+ };
112
+ var scopedSlaKey = (scope, title) => `${scope}\x00${title}`;
113
+
114
+ // src/services/sdd-convert/xrefs.ts
115
+ var QUOTED = String.raw`(?:'((?:\\.|[^'\\])*)'|"((?:\\.|[^"\\])*)"|` + "`((?:\\\\.|[^`\\\\])*)`" + String.raw`|\u201c([^\u201d]*)\u201d)`;
116
+ var XREF_CALL = new RegExp(String.raw`vars\.\$xref\(\s*${QUOTED}\s*,\s*${QUOTED}\s*,\s*${QUOTED}\s*\)`, "g");
117
+ var argumentOf = (groups) => groups.find((value) => value !== undefined) ?? "";
118
+ var unresolvedXrefDetail = (whole, found) => {
119
+ if (found === undefined) {
120
+ return `\`${whole}\` names an output this SDD does not declare, so the marker is left in place rather than pointed at a guess`;
121
+ }
122
+ const spellings = new Set(found.names);
123
+ const listed = [...spellings].map((name) => `\`${name}\``).join(", ");
124
+ if (spellings.size < found.names.length) {
125
+ return `\`${whole}\` names a task that ${found.names.length} tasks in that stage answer to (${listed}), so the marker is left in place rather than pointed at one of them. Task names are unique across the case, so rename all but one`;
126
+ }
127
+ return `\`${whole}\` names its task in a spelling that ${found.names.length} tasks answer to (${listed}), so the marker is left in place rather than pointed at one of them — write the task's name as its heading spells it`;
128
+ };
129
+ var DOTTED_READ = /^\.[A-Za-z_$]/;
130
+ var deferredOutputs = new WeakMap;
131
+ var markDeferredOutputs = (index, ids) => {
132
+ deferredOutputs.set(index, ids);
133
+ };
134
+ var expandXrefs = (text, context) => text.replace(XREF_CALL, (whole, ...rest) => {
135
+ const offset = rest[rest.length - 2];
136
+ const captured = rest.slice(0, -2);
137
+ const stage = argumentOf(captured.slice(0, 4));
138
+ const task = argumentOf(captured.slice(4, 8));
139
+ const output = argumentOf(captured.slice(8, 12));
140
+ const found = lookupOutput(context.outputs, `${indexKey(stage)}|${indexKey(task)}|${indexKey(output)}`, task);
141
+ if (found !== undefined && "id" in found) {
142
+ if (deferredOutputs.get(context.outputs)?.has(found.id)) {
143
+ context.unresolved.push({
144
+ kind: "placeholder",
145
+ where: context.where,
146
+ detail: `\`${whole}\` reads an output of a task the resolved file defers, so \`vars.${found.id}\` resolves to nothing until that task is filled`
147
+ });
148
+ }
149
+ const after = text.slice(offset + whole.length);
150
+ return DOTTED_READ.test(after) ? `vars.${found.id}?` : `vars.${found.id}`;
151
+ }
152
+ context.unresolved.push({
153
+ kind: "producer-reference",
154
+ where: context.where,
155
+ detail: unresolvedXrefDetail(whole, found)
156
+ });
157
+ return whole;
158
+ });
159
+ var expandOutputMarkers = (output, context) => {
160
+ const expand = (value2) => typeof value2 === "string" && value2.includes("$xref") ? expandXrefs(value2, context) : value2;
161
+ const value = expand(output.value);
162
+ const source = expand(output.source);
163
+ return value === output.value && source === output.source ? output : { ...output, value, source };
164
+ };
165
+
166
+ // src/services/sdd-convert/io.ts
167
+ var taskMatcher = (model, taskName) => {
168
+ const mine = exactKey(taskName);
169
+ const folded = indexKey(taskName);
170
+ let unique = true;
171
+ for (const stage of model.stages) {
172
+ for (const other of stage.tasks) {
173
+ const name = exactKey(String(other.name ?? ""));
174
+ if (name !== mine && indexKey(name) === folded)
175
+ unique = false;
176
+ }
177
+ }
178
+ return {
179
+ names: (spelled) => exactKey(spelled) === mine || unique && indexKey(spelled) === folded,
180
+ unique
181
+ };
182
+ };
183
+ var declaredOutputs = (model, stageName, position, task) => {
184
+ const taskName = String(task.name ?? "");
185
+ const { names: own, slug, ordinal } = stageSpellings(stageName, position);
186
+ const names = [...own, ...slug === undefined ? [] : [slug], ordinal].map(indexKey);
187
+ const matcher = taskMatcher(model, taskName);
188
+ const mine = (producer) => names.includes(indexKey(producer.stage)) && matcher.names(producer.task);
189
+ const rows = [...task.outputRows ?? []];
190
+ const add = (name) => {
191
+ if (name !== "" && !rows.includes(name))
192
+ rows.push(name);
193
+ };
194
+ for (const producer of model.xrefOutputs) {
195
+ if (mine(producer))
196
+ add(producer.output);
197
+ }
198
+ for (const stage of model.stages) {
199
+ for (const other of stage.tasks) {
200
+ for (const row of other.producerInputs ?? []) {
201
+ const producer = row.producer;
202
+ if (producer !== undefined && mine(producer)) {
203
+ add(producer.output);
204
+ }
205
+ }
206
+ }
207
+ }
208
+ if (matcher.unique) {
209
+ for (const name of model.resourceOutputs[indexKey(taskName)] ?? []) {
210
+ add(name);
211
+ }
212
+ }
213
+ return rows;
214
+ };
215
+ var OUTPUT_TYPES = new Map([
216
+ ["string", "string"],
217
+ ["object", "jsonSchema"],
218
+ ["json", "jsonSchema"],
219
+ ["jsonschema", "jsonSchema"]
220
+ ]);
221
+ var outputTypeFor = (model, stageNames, taskName, output) => {
222
+ const matcher = taskMatcher(model, taskName);
223
+ for (const stage of model.stages) {
224
+ for (const task of stage.tasks) {
225
+ for (const row of task.producerInputs ?? []) {
226
+ const producer = row.producer;
227
+ if (producer === undefined || row.direct !== true || typeof row.type !== "string" || !stageNames.includes(indexKey(producer.stage)) || !matcher.names(producer.task) || indexKey(producer.output) !== indexKey(output)) {
228
+ continue;
229
+ }
230
+ const mapped = OUTPUT_TYPES.get(row.type.trim().toLowerCase().replaceAll(" ", ""));
231
+ if (mapped !== undefined)
232
+ return mapped;
233
+ }
234
+ }
235
+ }
236
+ return;
237
+ };
238
+ var outputFor = (row, elementId, taken, type) => {
239
+ const leaf = row.split(".").at(-1) ?? row;
240
+ const base = leaf === "" ? leaf : `${leaf[0].toLowerCase()}${leaf.slice(1)}`;
241
+ const id = dedupedId(base, taken);
242
+ return {
243
+ name: leaf,
244
+ ...type !== undefined && { type },
245
+ id,
246
+ var: id,
247
+ value: id,
248
+ source: `=${row}`,
249
+ target: `=${id}`,
250
+ elementId
251
+ };
252
+ };
253
+ var variableOutputType = (model, variable) => {
254
+ const declared = model.variableTypes[indexKey(variable)];
255
+ if (typeof declared !== "string" || declared.trim() === "") {
256
+ return;
257
+ }
258
+ const key = declared.trim().toLowerCase().replaceAll(" ", "");
259
+ return OUTPUT_TYPES.get(key) ?? "string";
260
+ };
261
+ var extractOutputFor = (row, elementId, taken, type) => {
262
+ const leaf = row.field.split(".").at(-1) ?? row.field;
263
+ const base = leaf === "" ? leaf : `${leaf[0].toLowerCase()}${leaf.slice(1)}`;
264
+ const id = dedupedId(base, taken);
265
+ return {
266
+ name: leaf,
267
+ ...type !== undefined && { type },
268
+ id,
269
+ var: row.variable,
270
+ value: row.variable,
271
+ source: `=${row.field}`,
272
+ target: `=${id}`,
273
+ originalVar: id,
274
+ elementId
275
+ };
276
+ };
277
+ var customOutputFor = (row, type) => ({
278
+ name: row.variable,
279
+ ...type !== undefined && { type },
280
+ custom: true,
281
+ var: row.variable,
282
+ value: canonicalExpression(unquoteLiteral(row.expression)),
283
+ source: canonicalExpression(unquoteLiteral(row.expression)),
284
+ target: "",
285
+ body: "",
286
+ elementId: "root"
287
+ });
288
+ var canonicalExpression = (value) => value.startsWith("=metadata.") ? `=js:${value.slice(1)}` : value;
289
+ var unquoteLiteral = (cell) => {
290
+ const text = cell.trim();
291
+ const quote = text[0];
292
+ if (quote !== '"' && quote !== "'")
293
+ return cell;
294
+ if (text.length < 2 || text[text.length - 1] !== quote)
295
+ return cell;
296
+ const inner = text.slice(1, -1);
297
+ for (let at = 0;at < inner.length; at += 1) {
298
+ if (inner[at] === "\\") {
299
+ at += 1;
300
+ continue;
301
+ }
302
+ if (inner[at] === quote)
303
+ return cell;
304
+ }
305
+ return inner.replaceAll(`\\${quote}`, quote);
306
+ };
307
+ var RANK_LITERAL = 1;
308
+ var RANK_PRODUCER = 2;
309
+ var RANK_EXPRESSION = 3;
310
+ var unboundProducerDetail = (target, found) => {
311
+ if (found === undefined) {
312
+ return `the Inputs row reads an output (${target}) that no task in this SDD declares`;
313
+ }
314
+ const spellings = new Set(found.names);
315
+ const listed = [...spellings].map((task) => `"${task}"`).join(", ");
316
+ if (spellings.size < found.names.length) {
317
+ return `the Inputs row reads an output (${target}) of a task that ${found.names.length} tasks in that stage answer to (${listed}), so it is left unbound rather than pointed at one of them. Task names are unique across the case, so rename all but one`;
318
+ }
319
+ return `the Inputs row reads an output (${target}) whose task spelling ${found.names.length} tasks answer to (${listed}), so it is left unbound rather than pointed at one of them`;
320
+ };
321
+ var inputsFor = (task, elementId, where, unresolved, outputs) => {
322
+ const ranked = new Map;
323
+ const offer = (name, rank, input) => {
324
+ const existing = ranked.get(name);
325
+ if (existing === undefined || rank > existing.rank) {
326
+ ranked.set(name, { rank, input });
327
+ }
328
+ };
329
+ for (const row of task.literalInputs ?? []) {
330
+ offer(String(row.name ?? ""), RANK_LITERAL, {
331
+ name: String(row.name ?? ""),
332
+ value: unquoteLiteral(String(row.value ?? "")),
333
+ elementId
334
+ });
335
+ }
336
+ for (const row of task.expressionInputs ?? []) {
337
+ offer(String(row.name ?? ""), RANK_EXPRESSION, {
338
+ name: String(row.name ?? ""),
339
+ value: canonicalExpression(expandXrefs(String(row.expression ?? row.value ?? ""), {
340
+ outputs,
341
+ where,
342
+ unresolved
343
+ })),
344
+ elementId
345
+ });
346
+ }
347
+ for (const row of task.producerInputs ?? []) {
348
+ const name = String(row.name ?? "");
349
+ const producer = row.producer;
350
+ const found = producer === undefined ? undefined : lookupOutput(outputs, `${indexKey(producer.stage)}|${indexKey(producer.task)}|${indexKey(producer.output)}`, producer.task);
351
+ if (found === undefined || !("id" in found)) {
352
+ const target = producer === undefined ? "unnamed producer" : `"${producer.stage}"."${producer.task}".${producer.output}`;
353
+ unresolved.push({
354
+ kind: "producer-reference",
355
+ where: `${where}.inputs[${name}]`,
356
+ detail: unboundProducerDetail(target, found)
357
+ });
358
+ continue;
359
+ }
360
+ const id = found.id;
361
+ offer(name, RANK_PRODUCER, {
362
+ name,
363
+ value: row.direct === false ? expandXrefs(String(row.value ?? `=js:vars.${id}`), {
364
+ outputs,
365
+ where,
366
+ unresolved
367
+ }) : `=vars.${id}`,
368
+ elementId
369
+ });
370
+ }
371
+ return [...ranked.values()].map((entry) => entry.input);
372
+ };
373
+
374
+ // src/services/sdd-convert/resources.ts
375
+ var SDD_TASK_TYPES = new Set([
376
+ ...NAME_BOUND_TASK_TYPES,
377
+ ...CONNECTOR_TASK_TYPES,
378
+ "wait-for-timer"
379
+ ]);
380
+ var UNAUTHORABLE_TASK_TYPES = new Set([
381
+ "business-rule",
382
+ "document-extraction",
383
+ "external-agent",
384
+ "external-workflow",
385
+ "flow-process",
386
+ "http-request",
387
+ "script"
388
+ ]);
389
+ var RESOURCE_KINDS = new Map([
390
+ ["agent", { resource: "process", subType: "Agent" }],
391
+ ["process", { resource: "process", subType: "ProcessOrchestration" }],
392
+ ["api-workflow", { resource: "process", subType: "Api" }],
393
+ ["case-management", { resource: "process", subType: "CaseManagement" }],
394
+ ["function", { resource: "process", subType: "Function" }],
395
+ ["rpa", { resource: "process" }],
396
+ ["action", { resource: "app" }]
397
+ ]);
398
+ var bindingPairFor = (resourceName, folderPath, type, ordinal) => {
399
+ const resourceKey = `${folderPath}.${resourceName}`;
400
+ const kind = RESOURCE_KINDS.get(type) ?? { resource: "process" };
401
+ const shared = {
402
+ type: "string",
403
+ resource: kind.resource,
404
+ ...kind.subType !== undefined && { resourceSubType: kind.subType },
405
+ resourceKey
406
+ };
407
+ const nameId = `bN${ordinal}`;
408
+ const folderId = `bF${ordinal}`;
409
+ return {
410
+ nameId,
411
+ folderId,
412
+ name: {
413
+ id: nameId,
414
+ name: "name",
415
+ ...shared,
416
+ default: resourceName,
417
+ propertyAttribute: "name"
418
+ },
419
+ folder: {
420
+ id: folderId,
421
+ name: "folderPath",
422
+ ...shared,
423
+ default: folderPath,
424
+ propertyAttribute: "folderPath"
425
+ }
426
+ };
427
+ };
428
+ var RECIPIENT_TYPES = new Map([["email", 2]]);
429
+ var connectionPairFor = (connectionId, ordinal) => {
430
+ const shared = {
431
+ type: "string",
432
+ resource: "Connection",
433
+ resourceKey: connectionId
434
+ };
435
+ const connectionRef = `bOC${ordinal}`;
436
+ const folderRef = `bOF${ordinal}`;
437
+ return {
438
+ connectionRef,
439
+ folderRef,
440
+ connection: {
441
+ id: connectionRef,
442
+ name: "connection",
443
+ ...shared,
444
+ propertyAttribute: "ConnectionId"
445
+ },
446
+ folder: {
447
+ id: folderRef,
448
+ name: "folderKey",
449
+ ...shared,
450
+ propertyAttribute: "folderKey"
451
+ }
452
+ };
453
+ };
454
+
455
+ // src/services/sdd-convert/connector.ts
456
+ var connectorInputs = (inputs, connector, elementId, where, unresolved) => {
457
+ if (connector === undefined)
458
+ return inputs;
459
+ if (inputs.length === 0) {
460
+ if (String(connector.serviceType ?? "") !== "Intsvc.WaitForEvent") {
461
+ return inputs;
462
+ }
463
+ const id = prefixedId("v", 8);
464
+ return [
465
+ { name: "body", type: "json", value: "", id, var: id, elementId }
466
+ ];
467
+ }
468
+ if (connector.method === undefined) {
469
+ unresolved.push({
470
+ kind: "connector-context",
471
+ where,
472
+ detail: `${inputs.length} connector input(s) stay flat: the document states no method for this activity, so which of pathParameters/queryParameters/body each belongs in is not decidable from it`
473
+ });
474
+ return inputs;
475
+ }
476
+ const bodies = new Map;
477
+ const kept = [];
478
+ for (const input of inputs) {
479
+ const field = String(input.name ?? "");
480
+ const container = containerFor(field, connector);
481
+ if (container === undefined) {
482
+ kept.push(input);
483
+ continue;
484
+ }
485
+ const body = bodies.get(container) ?? {};
486
+ body[field] = unquoteLiteral(String(input.value ?? ""));
487
+ bodies.set(container, body);
488
+ }
489
+ if (bodies.size === 0)
490
+ return kept;
491
+ if (!bodies.has("pathParameters"))
492
+ bodies.set("pathParameters", {});
493
+ const containers = [];
494
+ for (const name of ["pathParameters", "queryParameters", "body"]) {
495
+ const body = bodies.get(name);
496
+ if (body === undefined)
497
+ continue;
498
+ const id = prefixedId("v", 8);
499
+ containers.push({
500
+ name,
501
+ type: "json",
502
+ target: name,
503
+ body,
504
+ id,
505
+ var: id,
506
+ elementId
507
+ });
508
+ }
509
+ return [...containers, ...kept];
510
+ };
511
+ var connectorContextFor = (connector, where, connections, bindings, unresolved) => {
512
+ const entry = (name, value) => typeof value === "string" && value !== "" ? [{ name, type: "string", value }] : [];
513
+ const connectionId = String(connector.connectionId ?? "");
514
+ const context = [
515
+ ...entry("connectorKey", connector.connectorKey),
516
+ ...entry("resourceKey", connectionId),
517
+ ...entry("objectName", connector.objectName),
518
+ ...entry("operation", connector.operation ?? connector.method),
519
+ ...entry("method", connector.method),
520
+ ...entry("path", connector.path)
521
+ ];
522
+ if (connectionId !== "") {
523
+ let ref = connections.get(connectionId);
524
+ if (ref === undefined) {
525
+ const pair = connectionPairFor(connectionId, connections.size + 1);
526
+ bindings.push(pair.connection, pair.folder);
527
+ ref = pair.connectionRef;
528
+ connections.set(connectionId, ref);
529
+ }
530
+ context.push({
531
+ name: "connection",
532
+ type: "string",
533
+ value: `${BINDING_REFERENCE_PREFIX}${ref}`
534
+ });
535
+ } else {
536
+ unresolved.push({
537
+ kind: "connector-connection",
538
+ where,
539
+ detail: "the document names no connection id, so nothing can be bound for this activity"
540
+ });
541
+ }
542
+ const activityTypeId = String(connector.activityTypeId ?? "");
543
+ if (activityTypeId !== "") {
544
+ context.push({
545
+ name: "metadata",
546
+ type: "json",
547
+ body: {
548
+ activityPropertyConfiguration: {
549
+ uiPathActivityTypeId: activityTypeId
550
+ }
551
+ }
552
+ });
553
+ }
554
+ unresolved.push({
555
+ kind: "connector-context",
556
+ where,
557
+ detail: `\`folderKey\` binds the folder's GUID and \`metadata.activityPropertyConfiguration.configuration\` carries the connector version and instance parameters; the document states a folder path and no schema, so ${activityTypeId === "" ? "those and the activity type id" : "both"} come from \`case spec\` against a tenant`
558
+ });
559
+ return context;
560
+ };
561
+ var QUERY_METHODS = new Set(["GET", "HEAD", "DELETE", "OPTIONS"]);
562
+ var containerFor = (field, connector) => {
563
+ const method = String(connector?.method ?? "").toUpperCase();
564
+ if (method === "")
565
+ return;
566
+ const path = String(connector?.path ?? "");
567
+ if (path.includes(`{${field}}`))
568
+ return "pathParameters";
569
+ return QUERY_METHODS.has(method) ? "queryParameters" : "body";
570
+ };
571
+
572
+ // src/services/sdd-convert/rules.ts
573
+ var RULE_VOCABULARY = new Set([
574
+ "wait-for-connector",
575
+ "case-entered",
576
+ "selected-stage-completed",
577
+ "selected-stage-exited",
578
+ "selected-tasks-completed",
579
+ "current-stage-entered",
580
+ "adhoc",
581
+ "required-stages-completed",
582
+ "required-tasks-completed",
583
+ "user-selected-stage",
584
+ "runs-sequentially",
585
+ "sla-status-change",
586
+ "api-event"
587
+ ]);
588
+ var parseWhen = (cell) => {
589
+ const text = cell.replaceAll("`", "").trim();
590
+ const bare = /^([a-z-]+)/i.exec(text);
591
+ const rule = bare ? bare[1] : "";
592
+ const open = text.indexOf("(");
593
+ if (rule === "" || open === -1)
594
+ return { rule, argumentList: [] };
595
+ let depth = 0;
596
+ let close = -1;
597
+ for (let at = open;at < text.length; at += 1) {
598
+ if (text[at] === "(")
599
+ depth += 1;
600
+ else if (text[at] === ")") {
601
+ depth -= 1;
602
+ if (depth === 0) {
603
+ close = at;
604
+ break;
605
+ }
606
+ }
607
+ }
608
+ const inner = text.slice(open + 1, close === -1 ? undefined : close);
609
+ const quoted = [...inner.matchAll(/"([^"]*)"/g)].map((match) => match[1].trim());
610
+ if (quoted.length > 0) {
611
+ return { rule, argumentList: quoted.filter((one) => one !== "") };
612
+ }
613
+ const plain = inner.split("(")[0].trim();
614
+ return { rule, argumentList: plain === "" ? [] : [plain] };
615
+ };
616
+ var resolveStage = (argument, stages) => {
617
+ for (const variant of referenceSpellings(argument)) {
618
+ const found = stages.get(indexKey(variant));
619
+ if (found !== undefined)
620
+ return found;
621
+ }
622
+ const prefix = indexKey(argument);
623
+ const matches = [...stages.entries()].filter(([name]) => name.startsWith(prefix) && /^[\s\-:_]/.test(name.slice(prefix.length)));
624
+ return matches.length === 1 ? matches[0][1] : undefined;
625
+ };
626
+ var ruleFor = (condition, idPrefix, context) => {
627
+ const whenCell = typeof condition.when === "string" ? condition.when : "";
628
+ const { rule, argumentList } = parseWhen(whenCell);
629
+ const parsedIf = parseIfCell(typeof condition.ifExpression === "string" ? condition.ifExpression : "");
630
+ const ifExpression = parsedIf.expression;
631
+ if (!RULE_VOCABULARY.has(rule)) {
632
+ context.unresolved.push({
633
+ kind: "condition-rule",
634
+ where: context.where,
635
+ detail: whenCell === "" ? "the condition row names no WHEN rule, so the condition is left out" : `the WHEN cell "${whenCell}" is not one of the rules the plan accepts, so the condition is left out`
636
+ });
637
+ return;
638
+ }
639
+ const base = { id: prefixedId(`${idPrefix}r`, 6), rule };
640
+ if (ifExpression !== "" && ifExpression !== "—") {
641
+ base.conditionExpression = canonicalExpression(expandXrefs(ifExpression, context));
642
+ }
643
+ const argument = argumentList[0];
644
+ const selectorMiss = (what, named) => {
645
+ context.unresolved.push({
646
+ kind: "selector-target",
647
+ where: context.where,
648
+ detail: `\`${rule}\` selects ${named === undefined ? `no ${what}` : `a ${what} named "${named}", which this SDD does not declare`}`
649
+ });
650
+ };
651
+ if (STAGE_SELECTOR_RULES.has(rule)) {
652
+ const wanted = parsedIf.stage ?? argument;
653
+ const id = wanted === undefined ? undefined : resolveStage(wanted, context.stages);
654
+ if (id === undefined)
655
+ selectorMiss("stage", parsedIf.stage ?? argument);
656
+ else
657
+ base.selectedStageIds = [id];
658
+ } else if (TASK_SELECTOR_RULES.has(rule)) {
659
+ const named = parsedIf.tasks === undefined ? argumentList : parsedIf.tasks.split(",").map((one) => one.trim());
660
+ const ids = [];
661
+ for (const name of named) {
662
+ const exact = context.tasks.get(name);
663
+ const folded = exact === undefined ? context.taskNameConflicts?.get(indexKey(name)) : undefined;
664
+ const id = exact ?? (folded === undefined ? context.tasks.get(indexKey(name)) : undefined);
665
+ if (id !== undefined && context.stageTasks?.has(id) === false) {
666
+ context.unresolved.push({
667
+ kind: "selector-target",
668
+ where: context.where,
669
+ detail: `\`${rule}\` selects a task named "${name}", which is in another stage. A stage's rules and its tasks' rules select only that stage's own tasks, so name one of them`
670
+ });
671
+ continue;
672
+ }
673
+ if (id !== undefined) {
674
+ ids.push(id);
675
+ continue;
676
+ }
677
+ if (folded === undefined) {
678
+ selectorMiss("task", name);
679
+ continue;
680
+ }
681
+ const shared = new Set(folded).size < folded.length;
682
+ if (shared) {
683
+ context.unresolved.push({
684
+ kind: "selector-target",
685
+ where: context.where,
686
+ detail: `\`${rule}\` selects a task named "${name}", and ${folded.length} tasks answer to it (${[
687
+ ...new Set(folded)
688
+ ].map((one) => `"${one}"`).join(", ")}). Task names are unique across the case, so rename all but one and point the selector at the one it means`
689
+ });
690
+ continue;
691
+ }
692
+ context.unresolved.push({
693
+ kind: "selector-target",
694
+ where: context.where,
695
+ detail: `\`${rule}\` selects a task named "${name}", which matches none of this SDD's task names exactly and more than one when case and surrounding space are ignored (${folded.map((one) => `"${one}"`).join(", ")}) — task names are compared exactly, so the selector has to spell one of them`
696
+ });
697
+ }
698
+ if (ids.length === 0 && named.length === 0) {
699
+ selectorMiss("task");
700
+ }
701
+ if (ids.length > 0)
702
+ base.selectedTasksIds = ids;
703
+ } else if (rule === "sla-status-change") {
704
+ const title = argumentList.at(-1);
705
+ const found = title === undefined ? undefined : context.slas?.get(indexKey(title));
706
+ if (found === undefined) {
707
+ context.unresolved.push({
708
+ kind: "selector-target",
709
+ where: context.where,
710
+ detail: `\`sla-status-change\` selects ${title === undefined ? "no SLA" : `an SLA named "${title}", which neither the case nor any stage in this SDD declares`}`
711
+ });
712
+ } else {
713
+ if (argumentList.length < 2) {
714
+ base.slaId = found.id;
715
+ } else {
716
+ const named = argumentList[0];
717
+ const scope = indexKey(named) === "root" ? "root" : resolveStage(named, context.stages);
718
+ if (scope === undefined) {
719
+ selectorMiss("stage", named);
720
+ base.slaId = found.id;
721
+ } else {
722
+ const own = context.slas?.get(scopedSlaKey(scope, indexKey(title ?? "")));
723
+ if (own !== undefined) {
724
+ base.slaId = own.id;
725
+ } else {
726
+ context.unresolved.push({
727
+ kind: "selector-target",
728
+ where: context.where,
729
+ detail: `\`sla-status-change\` names the SLA "${title}" in ${scope === "root" ? "the case" : `stage "${named}"`}, and that SLA belongs to ${found.stageId === "root" ? "the case" : "another stage"}, so the rule is left without an \`slaId\` rather than watching an SLA it was not written for`
730
+ });
731
+ }
732
+ }
733
+ }
734
+ }
735
+ } else if (rule === "wait-for-connector") {
736
+ if (context.connector === undefined || context.connections === undefined || context.bindings === undefined) {
737
+ context.unresolved.push({
738
+ kind: "connector-connection",
739
+ where: context.where,
740
+ detail: "a `wait-for-connector` rule needs its activity's context, and no `**Connector Rule Detail:**` accompanies this stage's entry table"
741
+ });
742
+ } else {
743
+ base.uipath = {
744
+ ...context.connector.serviceType !== undefined && {
745
+ serviceType: context.connector.serviceType
746
+ },
747
+ context: connectorContextFor(context.connector, context.where, context.connections, context.bindings, context.unresolved)
748
+ };
749
+ }
750
+ }
751
+ return base;
752
+ };
753
+ var displayNameOf = (condition) => {
754
+ const name = String(condition.displayName ?? "").trim();
755
+ return name === "" ? {} : { displayName: name };
756
+ };
757
+ var entryConditionFor = (condition, context) => {
758
+ const rule = ruleFor(condition, "Rule_", context);
759
+ if (rule === undefined)
760
+ return;
761
+ return {
762
+ id: prefixedId("Condition_", 6),
763
+ ...displayNameOf(condition),
764
+ isInterrupting: condition.interrupting === true,
765
+ rules: [[rule]]
766
+ };
767
+ };
768
+ var caseExitRuleFor = (condition, context) => {
769
+ const rule = ruleFor(condition, "Rule_", context);
770
+ if (rule === undefined)
771
+ return;
772
+ return {
773
+ id: prefixedId("Condition_", 6),
774
+ ...displayNameOf(condition),
775
+ marksCaseComplete: condition.marksComplete === true,
776
+ rules: [[rule]]
777
+ };
778
+ };
779
+ var exitConditionFor = (condition, context) => {
780
+ const rule = ruleFor(condition, "Rule_", context);
781
+ if (rule === undefined)
782
+ return;
783
+ const declaredExit = typeof condition.exitType === "string" && condition.exitType !== "" ? condition.exitType.trim() : undefined;
784
+ const exitType = declaredExit !== undefined && EXIT_CONDITION_TYPES.has(declaredExit) ? declaredExit : undefined;
785
+ if (declaredExit !== undefined && exitType === undefined) {
786
+ context.unresolved.push({
787
+ kind: "case-exit",
788
+ where: `${context.where}.type`,
789
+ detail: `the exit type "${declaredExit}" is none of ${[...EXIT_CONDITION_TYPES].map((type) => `\`${type}\``).join(", ")}, so no type is written — the rule still exits, and whichever of those three the document meant has to be chosen`
790
+ });
791
+ }
792
+ const exitTo = typeof condition.exitToStage === "string" ? condition.exitToStage : "";
793
+ let exitToStageId;
794
+ if (exitTo !== "") {
795
+ exitToStageId = resolveStage(exitTo, context.stages);
796
+ if (exitToStageId === undefined) {
797
+ context.unresolved.push({
798
+ kind: "selector-target",
799
+ where: context.where,
800
+ detail: `the Exit-To Stage cell names "${exitTo}", which this SDD does not declare as a stage, so the exit routes nowhere`
801
+ });
802
+ }
803
+ }
804
+ return {
805
+ id: prefixedId("Condition_", 6),
806
+ ...displayNameOf(condition),
807
+ ...exitType !== undefined && { type: exitType },
808
+ ...exitToStageId !== undefined && { exitToStageId },
809
+ marksStageComplete: condition.marksComplete === true,
810
+ rules: [[rule]]
811
+ };
812
+ };
813
+
814
+ // src/services/sdd-convert/metadata.ts
815
+ var TIMER_VALUE_FIELDS = new Map([
816
+ ["timeduration", "timeDuration"],
817
+ ["timedate", "timeDate"],
818
+ ["timecycle", "timeCycle"]
819
+ ]);
820
+ var timerData = (task) => {
821
+ const declared = task.timerType;
822
+ if (declared === undefined || declared.trim() === "")
823
+ return {};
824
+ const key = TIMER_VALUE_FIELDS.get(declared.trim().toLowerCase().replaceAll(" ", ""));
825
+ if (key === undefined)
826
+ return {};
827
+ return {
828
+ timerType: key,
829
+ ...task.timerValue !== undefined && task.timerValue.trim() !== "" && { [key]: task.timerValue.trim() }
830
+ };
831
+ };
832
+ var SLA_DURATION = /^(\d+)\s*([a-z]+)$/i;
833
+ var SLA_UNITS = new Map([
834
+ ["min", "min"],
835
+ ["mins", "min"],
836
+ ["minute", "min"],
837
+ ["minutes", "min"],
838
+ ["h", "h"],
839
+ ["hr", "h"],
840
+ ["hrs", "h"],
841
+ ["hour", "h"],
842
+ ["hours", "h"],
843
+ ["d", "d"],
844
+ ["day", "d"],
845
+ ["days", "d"],
846
+ ["w", "w"],
847
+ ["wk", "w"],
848
+ ["wks", "w"],
849
+ ["week", "w"],
850
+ ["weeks", "w"],
851
+ ["m", "m"],
852
+ ["mo", "m"],
853
+ ["month", "m"],
854
+ ["months", "m"]
855
+ ]);
856
+ var slaRuleFor = (displayName, duration, rows, where, unresolved, asked = {}) => {
857
+ const parts = SLA_DURATION.exec(duration.trim());
858
+ if (parts === null)
859
+ return;
860
+ const unit = SLA_UNITS.get(parts[2].toLowerCase());
861
+ if (unit === undefined)
862
+ return;
863
+ const escalations = rows.map((row) => {
864
+ const recipients = row.recipients.map((one) => {
865
+ if (one.kind === "user") {
866
+ return { scope: "User", target: one.value, value: one.value };
867
+ }
868
+ unresolved.push({
869
+ kind: "sla-recipient",
870
+ where,
871
+ detail: `the ${row.label} threshold notifies the group "${one.value}", and the plan addresses a group by the tenant's id — the document carries only the name, so the target is left as a marker`
872
+ });
873
+ return {
874
+ scope: "UserGroup",
875
+ target: `<UNRESOLVED: group-uuid for "${one.value}">`,
876
+ value: one.value
877
+ };
878
+ });
879
+ return {
880
+ id: prefixedId("esc_", 6),
881
+ displayName: `${row.label} notification`,
882
+ action: {
883
+ type: "notification",
884
+ recipients
885
+ },
886
+ triggerInfo: {
887
+ type: row.status,
888
+ ...row.percentage !== undefined && {
889
+ atRiskPercentage: row.percentage
890
+ }
891
+ }
892
+ };
893
+ });
894
+ const owed = [
895
+ {
896
+ status: "at-risk",
897
+ table: asked.table?.atRisk === true,
898
+ map: asked.map?.atRisk === true,
899
+ fromTable: "the SLA table declares an At-Risk action",
900
+ fromMap: "the SLA Response Map gives this SLA an At-Risk response",
901
+ needs: "an at-risk escalation"
902
+ },
903
+ {
904
+ status: "sla-breached",
905
+ table: asked.table?.breach === true,
906
+ map: asked.map?.breach === true,
907
+ fromTable: "the SLA table declares a Breach action that notifies",
908
+ fromMap: "the SLA Response Map gives this SLA a notify-only Breached response",
909
+ needs: "a breach escalation"
910
+ }
911
+ ];
912
+ for (const { status, table, map, fromTable, fromMap, needs } of owed) {
913
+ if (!table && !map)
914
+ continue;
915
+ const covered = rows.some((row) => row.status === status && row.recipients.length > 0);
916
+ if (covered)
917
+ continue;
918
+ const source = table ? fromTable : fromMap;
919
+ const gap = table ? "the cell names no one it notifies" : "no SLA table row names who it notifies; the planner writes that recipient in prose, in the Design Rationale or the map row's Rationale";
920
+ unresolved.push({
921
+ kind: "sla-recipient",
922
+ where,
923
+ detail: `${source}, which needs ${needs}, and ${gap}, so the escalation is left out`
924
+ });
925
+ }
926
+ return {
927
+ id: prefixedId("sla_", 6),
928
+ displayName,
929
+ expression: "=js:true",
930
+ count: Number(parts[1]),
931
+ unit,
932
+ ...escalations.length > 0 && { escalationRule: escalations }
933
+ };
934
+ };
935
+
936
+ // src/services/sdd-convert/triggers.ts
937
+ var MANUAL_TRIGGERS = new Set(["manual", "none", "n/a", "na"]);
938
+ var TRIGGER_SERVICE_TYPES = new Map([
939
+ ["timer", "timer"],
940
+ ["intsvc.timertrigger", "timer"],
941
+ ["intsvc.eventtrigger", "Intsvc.EventTrigger"]
942
+ ]);
943
+ var TRIGGER_TIMER_FIELD = "timeCycle";
944
+ var triggerTimer = (configuration) => {
945
+ const stated = (configuration ?? "").trim();
946
+ if (stated === "")
947
+ return;
948
+ const match = /^([A-Za-z]+)\s*[:=]?\s*(?:"([^"]+)"|\u201c([^\u201d]+)\u201d|'([^']+)'|([^\s,;:=][^\s,;]*))/.exec(stated);
949
+ const field = match === null ? undefined : TIMER_VALUE_FIELDS.get(match[1].toLowerCase());
950
+ if (match === null || field === undefined)
951
+ return { rejected: stated };
952
+ if (field !== TRIGGER_TIMER_FIELD)
953
+ return { rejected: stated };
954
+ const value = match[2] ?? match[3] ?? match[4] ?? match[5] ?? "";
955
+ if (value === "")
956
+ return { rejected: stated };
957
+ return { timerType: field, timeCycle: value };
958
+ };
959
+ var triggerPlans = (model) => (model.triggerRows ?? []).flatMap((row, position) => {
960
+ const declared = row.type.trim();
961
+ const rejected = [];
962
+ const label = row.displayName ?? `Trigger ${position + 1}`;
963
+ if (declared === "") {
964
+ return [
965
+ {
966
+ serviceType: "None",
967
+ row,
968
+ label,
969
+ rejected,
970
+ typeMissing: true
971
+ }
972
+ ];
973
+ }
974
+ const key = indexKey(declared);
975
+ if (MANUAL_TRIGGERS.has(key)) {
976
+ return [{ serviceType: "None", row, label, rejected }];
977
+ }
978
+ const serviceType = TRIGGER_SERVICE_TYPES.get(key);
979
+ if (serviceType === undefined) {
980
+ rejected.push(declared);
981
+ return [{ serviceType: "None", row, label, rejected }];
982
+ }
983
+ if (serviceType !== "timer") {
984
+ return [{ serviceType, row, label, rejected }];
985
+ }
986
+ const timer = triggerTimer(row.configuration);
987
+ if (timer !== undefined && "rejected" in timer) {
988
+ return [
989
+ {
990
+ serviceType,
991
+ row,
992
+ label,
993
+ rejected,
994
+ timerRejected: timer.rejected
995
+ }
996
+ ];
997
+ }
998
+ return [{ serviceType, row, label, ...timer, rejected }];
999
+ });
1000
+
1001
+ // src/services/sdd-convert/variables.ts
1002
+ var boundTriggerFor = (declared, triggers) => {
1003
+ if (triggers.length === 0)
1004
+ return { ambiguous: "the document declares no trigger" };
1005
+ if (triggers.length === 1)
1006
+ return { id: triggers[0].id };
1007
+ const named = (declared ?? "").trim();
1008
+ if (named !== "") {
1009
+ const match = triggers.find((t) => t.tNumber !== undefined && indexKey(t.tNumber) === indexKey(named));
1010
+ return match === undefined ? { ambiguous: `no trigger row carries the id "${named}"` } : { id: match.id };
1011
+ }
1012
+ const callable = triggers.filter((t) => t.serviceType !== "timer");
1013
+ if (callable.length === 1)
1014
+ return { id: callable[0].id };
1015
+ return {
1016
+ ambiguous: callable.length === 0 ? "every declared trigger is a timer, so none of them is the one a caller starts the case through" : `${callable.length} of the declared triggers are non-timer, so which one a blank \`sourceTriggers\` means is not stated`
1017
+ };
1018
+ };
1019
+ var jsonSchemaBody = (name, type, model, unresolved) => {
1020
+ if (type !== "jsonSchema")
1021
+ return;
1022
+ const declared = model.variableBodies?.[indexKey(name)];
1023
+ if (declared === undefined || declared.trim() === "") {
1024
+ unresolved.push({
1025
+ kind: "variable-body",
1026
+ where: `variables[${name}].body`,
1027
+ detail: `"${name}" is a \`jsonSchema\` variable and its row states no \`Body schema:\` — the packager reads \`body ?? _jsonSchema\` to build the entry point's schema for it, so with neither the variable packages as an empty property and a caller has no shape to fill`
1028
+ });
1029
+ return;
1030
+ }
1031
+ const [error, parsed] = catchError(() => JSON.parse(declared));
1032
+ if (error || typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
1033
+ unresolved.push({
1034
+ kind: "variable-body",
1035
+ where: `variables[${name}].body`,
1036
+ detail: `"${name}" states a \`Body schema:\` that is not a JSON object (${JSON.stringify(declared.slice(0, 60))}), so it is left off rather than guessed at — the packager reads it straight through into the entry point's schema`
1037
+ });
1038
+ return;
1039
+ }
1040
+ return parsed;
1041
+ };
1042
+ var caseVariablesFor = (model, triggers = [], unresolved = []) => {
1043
+ const buckets = { inputs: [], outputs: [], inputOutputs: [], bridges: new Map };
1044
+ const categorised = model.variables.filter((name) => model.variableCategories[indexKey(name)] !== undefined).length;
1045
+ if (model.variables.length > 0 && categorised === 0) {
1046
+ unresolved.push({
1047
+ kind: "variable-category",
1048
+ where: "variables",
1049
+ detail: `the \`### Case Variables\` table declares ${model.variables.length} variable(s) and no Category column, so none can be placed: each becomes a pure-state \`Variable\` on the case root, and any row the document means as \`In\` or \`Out\` loses the formal argument slot that a caller writes to`
1050
+ });
1051
+ }
1052
+ for (const name of model.variables) {
1053
+ const key = indexKey(name);
1054
+ const declaredCategory = model.variableCategories[key];
1055
+ if (declaredCategory === undefined && categorised > 0) {
1056
+ unresolved.push({
1057
+ kind: "variable-category",
1058
+ where: `variables[${name}]`,
1059
+ detail: `"${name}" has no Category where other rows in this table do, so it is placed as a pure-state \`Variable\` on the case root — if the document means it as \`In\` or \`Out\` it loses its formal argument slot`
1060
+ });
1061
+ }
1062
+ const category = declaredCategory ?? "variable";
1063
+ const groups = VARIABLE_PLACEMENT.get(category) ?? ["inputOutputs"];
1064
+ const carriesDefault = DEFAULT_GROUP.get(category) ?? "inputOutputs";
1065
+ const type = model.variableTypes[key] ?? "string";
1066
+ const body = jsonSchemaBody(name, type, model, unresolved);
1067
+ const fileBody = category === "in" && type === "file" ? FILE_TYPE_JSON_SCHEMA : undefined;
1068
+ const declared = model.variableDefaults[key] ?? "";
1069
+ const bound = category === "in" ? boundTriggerFor(model.variableSourceTriggers?.[key], triggers) : undefined;
1070
+ if (bound !== undefined && "ambiguous" in bound) {
1071
+ unresolved.push({
1072
+ kind: "in-arg-trigger",
1073
+ where: `variables.inputs[${name}].elementId`,
1074
+ detail: `the \`In\` argument "${name}" attaches to a trigger — its formal slot, its companion and the bridge that copies the caller's value all live on that node — and ${bound.ambiguous}, so it is left on the case root where \`=vars.${name}\` reads nothing at run time`
1075
+ });
1076
+ }
1077
+ const elementId = bound !== undefined && "id" in bound ? bound.id : "root";
1078
+ let formalId;
1079
+ for (const group of groups) {
1080
+ const formal = group !== "inputOutputs";
1081
+ const id = formal ? prefixedId("v", 8) : name;
1082
+ if (formal && category === "in")
1083
+ formalId = id;
1084
+ buckets[group].push({
1085
+ id,
1086
+ name,
1087
+ ...body !== undefined && { body, _jsonSchema: body },
1088
+ ...fileBody !== undefined && { body: fileBody },
1089
+ ...formal && { var: name },
1090
+ type,
1091
+ ...group === carriesDefault && { default: declared },
1092
+ ...category === "variable" && { custom: true },
1093
+ elementId
1094
+ });
1095
+ }
1096
+ if (formalId !== undefined && elementId !== "root") {
1097
+ const list = buckets.bridges.get(elementId) ?? [];
1098
+ list.push({
1099
+ name,
1100
+ type,
1101
+ source: `=vars.${formalId}`,
1102
+ var: name
1103
+ });
1104
+ buckets.bridges.set(elementId, list);
1105
+ }
1106
+ }
1107
+ return buckets;
1108
+ };
1109
+
1110
+ // src/services/sdd-convert/case-level.ts
1111
+ var finishCaseDocument = (document, model, index, unresolved) => {
1112
+ const { planned, stageIds, taskIds, outputIds, bindings, connections } = index;
1113
+ let conditionCount = 0;
1114
+ const plans = triggerPlans(model);
1115
+ const emittedTriggers = [];
1116
+ const scaffolded = document.nodes.find((node) => node.data?.inputs !== undefined);
1117
+ if (plans.length === 0) {
1118
+ unresolved.push({
1119
+ kind: "trigger-type",
1120
+ where: "nodes[trigger 1].data.inputs.serviceType",
1121
+ detail: "the document declares no trigger, so the plan carries the scaffolded manual trigger (`serviceType: None`) — state the case's start in a `### Case Triggers` table (`| Trigger | Type |` with `manual`, `Intsvc.EventTrigger` or `timer`) if it starts any other way"
1122
+ });
1123
+ }
1124
+ for (const [position, plan] of plans.entries()) {
1125
+ if (plan.typeMissing === true) {
1126
+ unresolved.push({
1127
+ kind: "trigger-type",
1128
+ where: `nodes[trigger ${position + 1}].data.inputs.serviceType`,
1129
+ detail: `the Case Triggers row "${plan.label}" states no type, so this trigger carries \`serviceType: None\` — the manual start — which is a guess at what the row meant; state one of the three tokens the case schema names (None, Intsvc.EventTrigger, timer)`
1130
+ });
1131
+ }
1132
+ for (const declared of plan.rejected) {
1133
+ unresolved.push({
1134
+ kind: "trigger-type",
1135
+ where: `nodes[trigger ${position + 1}].data.inputs.serviceType`,
1136
+ detail: `the Case Triggers table declares "${declared}", which is not one of the three tokens the case schema names (None, Intsvc.EventTrigger, timer) — emitting it verbatim would classify the trigger as a connector with no event definition, so it is left as declared in the document and not written to the plan`
1137
+ });
1138
+ }
1139
+ const inputs = { serviceType: plan.serviceType };
1140
+ if (plan.serviceType === "timer") {
1141
+ if (plan.timeCycle === undefined) {
1142
+ unresolved.push({
1143
+ kind: "trigger-timer",
1144
+ where: `nodes[trigger ${position + 1}].data.inputs.timeCycle`,
1145
+ detail: `a timer trigger needs its interval, which the Case Triggers table states in its Configuration cell as \`timeCycle: <ISO 8601 repeating interval>\` or \`timeCycle "<interval>"\` — this row states ${plan.timerRejected === undefined ? "none" : `"${plan.timerRejected}", which names no interval this trigger can carry`}`
1146
+ });
1147
+ } else {
1148
+ inputs.timerType = plan.timerType;
1149
+ inputs.timeCycle = plan.timeCycle;
1150
+ }
1151
+ } else if (plan.serviceType !== "None") {
1152
+ const eventSource = plan.row?.source;
1153
+ if (eventSource !== undefined && eventSource !== "") {
1154
+ inputs.context = [
1155
+ { name: "objectName", type: "string", value: eventSource }
1156
+ ];
1157
+ }
1158
+ unresolved.push({
1159
+ kind: "connector-context",
1160
+ where: `nodes[trigger ${position + 1}].data.inputs.context`,
1161
+ detail: `a "${plan.serviceType}" trigger needs its connection, connector key, event mode and filter, which come from \`case spec\` against a tenant — the document names ${eventSource === undefined || eventSource === "" ? "no source object either" : `only the source object "${eventSource}"`}`
1162
+ });
1163
+ }
1164
+ if (position === 0 && scaffolded !== undefined) {
1165
+ const data = scaffolded.data;
1166
+ data.inputs = inputs;
1167
+ emittedTriggers.push({
1168
+ id: String(scaffolded.id),
1169
+ ...plan.row?.id !== undefined && { tNumber: plan.row.id },
1170
+ serviceType: plan.serviceType
1171
+ });
1172
+ if (plan.row?.displayName !== undefined) {
1173
+ data.display = { label: plan.row.displayName };
1174
+ }
1175
+ continue;
1176
+ }
1177
+ const appendedId = prefixedId("trigger_", 6);
1178
+ emittedTriggers.push({
1179
+ id: appendedId,
1180
+ ...plan.row?.id !== undefined && { tNumber: plan.row.id },
1181
+ serviceType: plan.serviceType
1182
+ });
1183
+ document.nodes.push({
1184
+ id: appendedId,
1185
+ type: "uipath.case.trigger",
1186
+ data: {
1187
+ parentElement: { id: "root", type: "case-management:root" },
1188
+ typeVersion: "1.0.0",
1189
+ display: { label: plan.label },
1190
+ inputs
1191
+ }
1192
+ });
1193
+ }
1194
+ if (bindings.length > 0)
1195
+ document.bindings = bindings;
1196
+ const declaredType = model.caseIdentifierType;
1197
+ const identifierType = declaredType === "constant" || declaredType === "external" ? declaredType : undefined;
1198
+ if (declaredType !== undefined && identifierType === undefined) {
1199
+ unresolved.push({
1200
+ kind: "case-identifier",
1201
+ where: "metadata.caseIdentifierType",
1202
+ detail: `the Case Metadata table declares a case identifier of type "${declaredType}", and the case schema names two — \`constant\` and \`external\` — so the field is left off rather than written as a value nothing accepts`
1203
+ });
1204
+ }
1205
+ const identifier = identifierType === "external" ? model.caseIdentifierSource : model.caseIdentifierPrefix;
1206
+ if (identifierType === "external" && model.caseIdentifierSource === undefined) {
1207
+ unresolved.push({
1208
+ kind: "case-identifier",
1209
+ where: "metadata.caseIdentifier",
1210
+ detail: "the Case Metadata table declares an `external` case identifier and states no `Source:` clause for it, so the plan is left with no identifier at all rather than a constant every instance would share"
1211
+ });
1212
+ }
1213
+ if (identifierType === "constant" && model.caseIdentifierPrefix === undefined) {
1214
+ unresolved.push({
1215
+ kind: "case-identifier",
1216
+ where: "metadata.caseIdentifier",
1217
+ detail: "the Case Metadata table declares a `constant` case identifier and states no `Prefix:` clause for it, so the plan carries no identifier — name it in the same cell (`Type: constant. Prefix: ABC`)"
1218
+ });
1219
+ }
1220
+ const seeded = { ...document.metadata };
1221
+ if (declaredType !== undefined) {
1222
+ delete seeded.caseIdentifier;
1223
+ delete seeded.caseIdentifierType;
1224
+ }
1225
+ document.metadata = {
1226
+ ...seeded,
1227
+ ...identifierType !== undefined && identifier !== undefined && { caseIdentifier: identifier },
1228
+ ...identifierType !== undefined && {
1229
+ caseIdentifierType: identifierType
1230
+ },
1231
+ ...model.caseAppEnabled !== undefined && {
1232
+ caseAppEnabled: model.caseAppEnabled
1233
+ },
1234
+ ...model.directTaskOutputs === true && {
1235
+ caseDirectlyPassTaskOutputs: true
1236
+ },
1237
+ ...connections.size > 0 && { intsvcActivityConfig: "v2" }
1238
+ };
1239
+ const entersOnCaseEntered = planned.some(({ stage }) => stage.entryConditions.some((condition) => {
1240
+ const when = String(condition.when ?? "");
1241
+ return parseWhen(when).rule === "case-entered";
1242
+ }));
1243
+ if (!entersOnCaseEntered && planned.length > 0) {
1244
+ unresolved.push({
1245
+ kind: "case-entry",
1246
+ where: "nodes[].data.entryConditions",
1247
+ detail: "no stage declares a `case-entered` entry condition, so nothing makes a first stage eligible and the case never starts"
1248
+ });
1249
+ }
1250
+ const slaRules = index.caseSla === undefined ? [] : [index.caseSla];
1251
+ if (slaRules.length > 0) {
1252
+ document.metadata = { ...document.metadata, slaRules };
1253
+ } else if (model.caseSla === true || /\d/.test(String(model.caseSlaDuration ?? ""))) {
1254
+ const stated = String(model.caseSlaDuration ?? "").trim();
1255
+ unresolved.push({
1256
+ kind: "case-sla",
1257
+ where: "metadata.slaRules",
1258
+ detail: `this SDD declares a case SLA but no rule could be emitted from it: the duration cell is ${stated === "" ? "absent" : `\`${stated}\`, which gives no count and unit`}. Any conditional rules or escalations it declares outside a recognised SLA heading are not carried either — a combined rule table under a heading like \`SLA Escalation\`, or a condition written as prose rather than an expression, is left for authoring rather than guessed at`
1259
+ });
1260
+ }
1261
+ const caseVariables = caseVariablesFor(model, emittedTriggers, unresolved);
1262
+ for (const [triggerId, bridges] of caseVariables.bridges) {
1263
+ const node = document.nodes.find((one) => one.id === triggerId);
1264
+ if (node === undefined)
1265
+ continue;
1266
+ const data = node.data;
1267
+ const inputs = data.inputs ?? {};
1268
+ inputs.outputs = [
1269
+ ...inputs.outputs ?? [],
1270
+ ...bridges
1271
+ ];
1272
+ data.inputs = inputs;
1273
+ }
1274
+ const variableCount = caseVariables.inputs.length + caseVariables.outputs.length + caseVariables.inputOutputs.length;
1275
+ if (variableCount > 0) {
1276
+ const { bridges: _bridges, ...variableGroups } = caseVariables;
1277
+ document.variables = { ...document.variables, ...variableGroups };
1278
+ }
1279
+ const caseExitRules = model.caseExitConditions.map((condition) => caseExitRuleFor(condition, {
1280
+ where: "metadata.caseExitRules",
1281
+ stages: stageIds,
1282
+ tasks: taskIds,
1283
+ taskNameConflicts: index.taskNameConflicts,
1284
+ outputs: outputIds,
1285
+ unresolved
1286
+ })).filter((condition) => condition !== undefined);
1287
+ if (caseExitRules.length > 0) {
1288
+ document.metadata = { ...document.metadata, caseExitRules };
1289
+ conditionCount += caseExitRules.length;
1290
+ }
1291
+ if (!caseExitRules.some((rule) => rule.marksCaseComplete === true) && planned.length > 0) {
1292
+ unresolved.push({
1293
+ kind: "case-exit",
1294
+ where: "metadata.caseExitRules",
1295
+ detail: model.caseExitConditions.length === 0 ? "the document declares no Case Exit Conditions, so nothing marks the case complete" : "no Case Exit Conditions row answers yes under Marks Case Complete, so nothing marks the case complete"
1296
+ });
1297
+ }
1298
+ if (planned.length === 0) {
1299
+ unresolved.push({
1300
+ kind: "stages",
1301
+ where: "nodes",
1302
+ detail: "the document declares no stages, so the plan has a trigger and nothing to run"
1303
+ });
1304
+ }
1305
+ const userSelected = planned.filter(({ stage }) => stage.entryConditions.some((condition) => parseWhen(String(condition.when ?? "")).rule === "user-selected-stage"));
1306
+ if (userSelected.length > 0) {
1307
+ const handsOver = planned.some(({ stage }) => stage.exitConditions.some((condition) => String(condition.exitType ?? "").trim().toLowerCase() === "wait-for-user"));
1308
+ if (!handsOver) {
1309
+ unresolved.push({
1310
+ kind: "stage-handoff",
1311
+ where: `nodes[${userSelected[0].stage.name}].data.entryConditions`,
1312
+ detail: "a `user-selected-stage` entry rule needs some other stage to hand over to the user — an exit condition with Exit Type `wait-for-user` — and this document declares none"
1313
+ });
1314
+ }
1315
+ }
1316
+ return { conditionCount };
1317
+ };
1318
+
1319
+ // src/services/sdd-convert/emit.ts
1320
+ var isDeferredTask = (resolved, stageName, task) => {
1321
+ const type = typeof task.type === "string" ? task.type : "";
1322
+ return (NAME_BOUND_TASK_TYPES.has(type) || CONNECTOR_TASK_TYPES.has(type)) && resolved?.deferred?.has(`${stageName}\x01${String(task.name ?? "")}`) === true;
1323
+ };
1324
+ var emitTask = (task, taskId, context) => {
1325
+ const { stage, stageId, index, unresolved, stageTasks } = context;
1326
+ const {
1327
+ stageIds,
1328
+ taskIds,
1329
+ outputIds,
1330
+ outputsByTask,
1331
+ bindings,
1332
+ bindingsByKey,
1333
+ connections,
1334
+ slaIds
1335
+ } = index;
1336
+ const where = `nodes[${stage.name}]`;
1337
+ let conditions = 0;
1338
+ const elementId = buildElementId(stageId, taskId);
1339
+ const type = typeof task.type === "string" ? task.type : "";
1340
+ const taskWhere = `${where}.data.tasks[${String(task.name ?? "")}]`;
1341
+ const timer = timerData(task);
1342
+ if (type === "wait-for-timer") {
1343
+ const valueField = timer.timerType === undefined ? undefined : timer[String(timer.timerType)];
1344
+ if (timer.timerType === undefined) {
1345
+ unresolved.push({
1346
+ kind: "trigger-timer",
1347
+ where: `${taskWhere}.data`,
1348
+ detail: "this `wait-for-timer` task declares no timer type the schema names (`timeDuration`, `timeDate` or `timeCycle`), so it emits with no timer fields and `validate` reports `TIMER_TASK_MISSING_TIMER_TYPE`"
1349
+ });
1350
+ } else if (valueField === undefined || String(valueField) === "") {
1351
+ unresolved.push({
1352
+ kind: "trigger-timer",
1353
+ where: `${taskWhere}.data`,
1354
+ detail: `this \`wait-for-timer\` task declares \`${String(timer.timerType)}\` and no value, so \`validate\` reports \`TIMER_TASK_MISSING_VALUE\``
1355
+ });
1356
+ }
1357
+ }
1358
+ if (type === "" || !SDD_TASK_TYPES.has(type)) {
1359
+ unresolved.push({
1360
+ kind: "task-type",
1361
+ where: taskWhere,
1362
+ detail: type === "" ? "the Tasks table row names no type, so the task cannot be emitted with one" : UNAUTHORABLE_TASK_TYPES.has(type) ? `the Tasks table row declares the type "${type}", a caseplan task type an SDD may not declare. Author this task in Studio Web.` : `the Tasks table row declares the type "${type}", which is not one of the ${SDD_TASK_TYPES.size} an SDD may use (${[
1363
+ ...SDD_TASK_TYPES
1364
+ ].sort(byCodeUnit).join(", ")}) — the task is left out rather than emitted with a type nothing resolves`
1365
+ });
1366
+ return { conditions: 0 };
1367
+ }
1368
+ const entryConditionsOf = () => (task.entryConditions ?? []).map((condition) => entryConditionFor(condition, {
1369
+ where: `${taskWhere}.entryConditions`,
1370
+ stages: stageIds,
1371
+ tasks: taskIds,
1372
+ taskNameConflicts: index.taskNameConflicts,
1373
+ stageTasks,
1374
+ outputs: outputIds,
1375
+ slas: slaIds,
1376
+ unresolved
1377
+ })).filter((condition) => condition !== undefined);
1378
+ const skip = typeof task.skipCondition === "string" && task.skipCondition !== "" ? canonicalExpression(expandXrefs(task.skipCondition, {
1379
+ outputs: outputIds,
1380
+ where: `${taskWhere}.skipCondition`,
1381
+ unresolved
1382
+ })) : undefined;
1383
+ if (isDeferredTask(index.resolved, stage.name, task)) {
1384
+ const placeholderConditions = entryConditionsOf();
1385
+ unresolved.push({
1386
+ kind: "placeholder",
1387
+ where: taskWhere,
1388
+ detail: `the resolved file defers this "${type}" task's resource, so it is emitted as a placeholder with an empty \`data\`; resolve it, then fill the task with \`uip maestro case tasks describe\` and \`uip maestro case splice\``
1389
+ });
1390
+ if (placeholderConditions.length === 0) {
1391
+ unresolved.push({
1392
+ kind: "task-entry-condition",
1393
+ where: taskWhere,
1394
+ detail: "no entry condition could be read for this task; a task with no entry rules never becomes eligible, and `case debug` waits on it forever"
1395
+ });
1396
+ }
1397
+ return {
1398
+ task: {
1399
+ id: taskId,
1400
+ type,
1401
+ displayName: String(task.name ?? ""),
1402
+ ...task.prose !== undefined && { description: task.prose },
1403
+ elementId,
1404
+ ...placeholderConditions.length > 0 && {
1405
+ entryConditions: placeholderConditions
1406
+ },
1407
+ isRequired: task.required !== false,
1408
+ shouldRunOnlyOnce: task.runOnlyOnce === true,
1409
+ ...skip !== undefined && { skipCondition: skip },
1410
+ data: {}
1411
+ },
1412
+ conditions: placeholderConditions.length
1413
+ };
1414
+ }
1415
+ const recipient = task.recipient;
1416
+ const recipientType = recipient === undefined ? undefined : RECIPIENT_TYPES.get(recipient.kind);
1417
+ if (recipient !== undefined && recipientType === undefined) {
1418
+ unresolved.push({
1419
+ kind: "task-recipient",
1420
+ where: taskWhere,
1421
+ detail: `the Recipient row names a "${recipient.kind}" recipient, and the plan's numeric \`Type\` code for that kind is not one this command knows`
1422
+ });
1423
+ }
1424
+ const settled = index.resolved?.byTask.get(`${stage.name}\x01${String(task.name ?? "")}`);
1425
+ const resourceName = namedValue(task.resourceName) || (settled?.name ?? "");
1426
+ const folderPath = namedValue(task.folder) || (settled?.folder ?? "");
1427
+ let bound;
1428
+ if (NAME_BOUND_TASK_TYPES.has(type)) {
1429
+ if (resourceName === "" || folderPath === "") {
1430
+ unresolved.push({
1431
+ kind: "resource-binding",
1432
+ where: taskWhere,
1433
+ detail: `a "${type}" task runs a tenant resource, and ${index.resolved === undefined ? `this SDD names ${resourceName === "" && folderPath === "" ? "neither the resource nor its folder" : resourceName === "" ? "no resource (only the folder)" : "no folder (only the resource)"}` : `neither this SDD nor the resolved file supplies ${resourceName === "" && folderPath === "" ? "the resource or its folder" : resourceName === "" ? "the resource (only the folder is named)" : "its folder (only the resource is named)"}`}, so its name/folderPath pair cannot be bound${index.resolved === undefined ? " — `sdd resolve` can supply a missing folder, and `sdd convert --resolved` reads it" : ""}`
1434
+ });
1435
+ } else {
1436
+ const key = JSON.stringify([type, folderPath, resourceName]);
1437
+ const existing = bindingsByKey.get(key);
1438
+ if (existing !== undefined)
1439
+ bound = existing;
1440
+ else {
1441
+ const pair = bindingPairFor(resourceName, folderPath, type, bindingsByKey.size + 1);
1442
+ bindings.push(pair.name, pair.folder);
1443
+ bound = {
1444
+ nameId: pair.nameId,
1445
+ folderId: pair.folderId
1446
+ };
1447
+ bindingsByKey.set(key, bound);
1448
+ }
1449
+ }
1450
+ }
1451
+ const connector = CONNECTOR_TASK_TYPES.has(type) && task.connector !== undefined ? task.connector : undefined;
1452
+ if (CONNECTOR_TASK_TYPES.has(type) && connector === undefined) {
1453
+ unresolved.push({
1454
+ kind: "connector-connection",
1455
+ where: taskWhere,
1456
+ detail: `a "${type}" task needs a connection and the activity's context, and this SDD declares neither`
1457
+ });
1458
+ }
1459
+ let connectorContext;
1460
+ if (connector !== undefined) {
1461
+ connectorContext = connectorContextFor(connector, taskWhere, connections, bindings, unresolved);
1462
+ }
1463
+ const taskConditions = entryConditionsOf();
1464
+ conditions += taskConditions.length;
1465
+ if (taskConditions.length === 0) {
1466
+ unresolved.push({
1467
+ kind: "task-entry-condition",
1468
+ where: taskWhere,
1469
+ detail: "no entry condition could be read for this task; a task with no entry rules never becomes eligible, and `case debug` waits on it forever"
1470
+ });
1471
+ }
1472
+ const emitted = {
1473
+ id: taskId,
1474
+ ...type !== "" && { type },
1475
+ displayName: String(task.name ?? ""),
1476
+ ...task.prose !== undefined && { description: task.prose },
1477
+ elementId,
1478
+ ...taskConditions.length > 0 && {
1479
+ entryConditions: taskConditions
1480
+ },
1481
+ isRequired: task.required !== false,
1482
+ shouldRunOnlyOnce: task.runOnlyOnce === true,
1483
+ ...skip !== undefined && { skipCondition: skip },
1484
+ data: {
1485
+ ...bound !== undefined && {
1486
+ name: `${BINDING_REFERENCE_PREFIX}${bound.nameId}`,
1487
+ folderPath: `${BINDING_REFERENCE_PREFIX}${bound.folderId}`
1488
+ },
1489
+ ...connector?.serviceType !== undefined && {
1490
+ serviceType: connector.serviceType
1491
+ },
1492
+ ...connectorContext !== undefined && {
1493
+ context: connectorContext
1494
+ },
1495
+ inputs: connectorInputs(inputsFor(task, elementId, taskWhere, unresolved, outputIds), connector, elementId, taskWhere, unresolved),
1496
+ outputs: [...outputsByTask.get(taskId)?.values() ?? []].map((output) => expandOutputMarkers(output, {
1497
+ outputs: outputIds,
1498
+ where: taskWhere,
1499
+ unresolved
1500
+ })),
1501
+ ...type === "action" && task.taskTitle !== undefined && {
1502
+ taskTitle: task.taskTitle
1503
+ },
1504
+ ...type === "action" && task.priority !== undefined && { priority: task.priority },
1505
+ ...type === "action" && task.labels !== undefined && { labels: task.labels },
1506
+ ...recipientType !== undefined && recipient !== undefined && {
1507
+ recipient: {
1508
+ Type: recipientType,
1509
+ Value: recipient.value
1510
+ }
1511
+ },
1512
+ ...timer
1513
+ }
1514
+ };
1515
+ return { task: emitted, conditions };
1516
+ };
1517
+ var SHARES_WITH_SIBLING = "parallel-after-predecessor";
1518
+ var taskSets = (tasks, declared) => {
1519
+ if (declared.some((one) => one.index !== undefined)) {
1520
+ const indexes = declared.map((one) => one.index).filter((index) => index !== undefined);
1521
+ const before = Math.min(...indexes) - 1;
1522
+ const keyed = [];
1523
+ let run = before;
1524
+ for (const [position, task] of tasks.entries()) {
1525
+ const index = declared[position]?.index;
1526
+ if (index !== undefined)
1527
+ run = index;
1528
+ keyed.push({
1529
+ run,
1530
+ at: index === undefined ? position + 1 : 0,
1531
+ key: index === undefined ? `at:${position}` : `set:${index}`,
1532
+ task
1533
+ });
1534
+ }
1535
+ keyed.sort((a, b) => a.run - b.run || a.at - b.at);
1536
+ const sets2 = new Map;
1537
+ for (const one of keyed) {
1538
+ sets2.set(one.key, [...sets2.get(one.key) ?? [], one.task]);
1539
+ }
1540
+ return { sets: [...sets2.values()], undeclared: [] };
1541
+ }
1542
+ const sets = [];
1543
+ const undeclaredSets = new Set;
1544
+ let previous;
1545
+ for (const [position, task] of tasks.entries()) {
1546
+ const mode = declared[position]?.mode;
1547
+ const last = sets.at(-1);
1548
+ const shares = mode !== undefined && indexKey(mode) === SHARES_WITH_SIBLING && previous !== undefined && indexKey(previous) === SHARES_WITH_SIBLING;
1549
+ const undeclared = mode === undefined && !startsOnItsOwnRule(task);
1550
+ if (last !== undefined && (shares || undeclared && undeclaredSets.has(last))) {
1551
+ last.push(task);
1552
+ } else {
1553
+ sets.push([task]);
1554
+ if (undeclared)
1555
+ undeclaredSets.add(sets[sets.length - 1]);
1556
+ }
1557
+ previous = mode;
1558
+ }
1559
+ return {
1560
+ sets,
1561
+ undeclared: sets.filter((set) => set.length > 1 && undeclaredSets.has(set))
1562
+ };
1563
+ };
1564
+ var startsOnItsOwnRule = (task) => {
1565
+ const conditions = task.entryConditions ?? [];
1566
+ return conditions.length > 0 && !conditions.some((condition) => (condition.rules ?? []).some((set) => set.some((rule) => rule.rule === "runs-sequentially")));
1567
+ };
1568
+ var emitStages = (document, model, index, unresolved) => {
1569
+ const {
1570
+ planned,
1571
+ stageIds,
1572
+ taskIds,
1573
+ outputIds,
1574
+ outputsByTask,
1575
+ bindings,
1576
+ bindingsByKey,
1577
+ connections,
1578
+ slaIds
1579
+ } = index;
1580
+ let taskCount = 0;
1581
+ let conditionCount = 0;
1582
+ for (const { stage, stageId, tasks: plannedTasks, stageSla } of planned) {
1583
+ const where = `nodes[${stage.name}]`;
1584
+ const tasks = [];
1585
+ const declared = [];
1586
+ const stageTasks = new Set(plannedTasks.map(({ taskId }) => taskId));
1587
+ for (const { task, taskId } of plannedTasks) {
1588
+ const emitted = emitTask(task, taskId, {
1589
+ stage,
1590
+ stageId,
1591
+ model,
1592
+ index,
1593
+ unresolved,
1594
+ stageTasks
1595
+ });
1596
+ conditionCount += emitted.conditions;
1597
+ if (emitted.task === undefined)
1598
+ continue;
1599
+ declared.push({
1600
+ ...typeof task.activationMode === "string" && {
1601
+ mode: task.activationMode
1602
+ },
1603
+ ...typeof task.taskSet === "number" && {
1604
+ index: task.taskSet
1605
+ }
1606
+ });
1607
+ tasks.push(emitted.task);
1608
+ taskCount += 1;
1609
+ }
1610
+ const context = (kind) => ({
1611
+ where: `${where}.data.${kind}`,
1612
+ stages: stageIds,
1613
+ tasks: taskIds,
1614
+ taskNameConflicts: index.taskNameConflicts,
1615
+ stageTasks,
1616
+ outputs: outputIds,
1617
+ slas: slaIds,
1618
+ unresolved,
1619
+ ...kind === "entryConditions" && stage.entryConnector !== undefined && {
1620
+ connector: stage.entryConnector,
1621
+ connections,
1622
+ bindings
1623
+ }
1624
+ });
1625
+ const entryConditions = stage.entryConditions.map((condition) => entryConditionFor(condition, context("entryConditions"))).filter((condition) => condition !== undefined);
1626
+ const exitConditions = stage.exitConditions.map((condition) => exitConditionFor(condition, context("exitConditions"))).filter((condition) => condition !== undefined);
1627
+ conditionCount += entryConditions.length + exitConditions.length;
1628
+ const { sets, undeclared } = taskSets(tasks, declared);
1629
+ for (const set of undeclared) {
1630
+ unresolved.push({
1631
+ kind: "task-grouping",
1632
+ where: `${where}.data.tasks`,
1633
+ detail: `this stage declares no Activation Mode or Task set for ${set.map((task) => `"${String(task.displayName)}"`).join(", ")}, so they share one set and run as parallel siblings; if the document means a strict chain, give each its own set`
1634
+ });
1635
+ }
1636
+ document.nodes.push({
1637
+ id: stageId,
1638
+ type: "case-management:Stage",
1639
+ data: {
1640
+ ...stage.kind === "secondary" && {
1641
+ stageType: "secondary"
1642
+ },
1643
+ label: withoutTrailingSlug(stage.name),
1644
+ ...stage.description !== undefined && {
1645
+ description: stage.description
1646
+ },
1647
+ ...stage.required !== undefined && {
1648
+ isRequired: stage.required
1649
+ },
1650
+ parentElement: { id: "root", type: "case-management:root" },
1651
+ isInvalidDropTarget: false,
1652
+ isPendingParent: false,
1653
+ ...stageSla !== undefined && { slaRules: [stageSla] },
1654
+ tasks: sets,
1655
+ entryConditions,
1656
+ exitConditions
1657
+ }
1658
+ });
1659
+ }
1660
+ return { taskCount, conditionCount };
1661
+ };
1662
+
1663
+ // src/services/sdd-convert/plan.ts
1664
+ var taskNameOf = (task) => typeof task.name === "string" ? task.name : "";
1665
+ var countByName = (entries) => {
1666
+ const counts = new Map;
1667
+ for (const [name] of entries) {
1668
+ counts.set(name, (counts.get(name) ?? 0) + 1);
1669
+ }
1670
+ return counts;
1671
+ };
1672
+ var reportRepeatedTaskNames = (stagesByTaskName, unresolved) => {
1673
+ for (const [name, stages] of stagesByTaskName) {
1674
+ if (stages.length < 2 || name === "")
1675
+ continue;
1676
+ const stageNames = [...new Set(stages)].map((one) => `"${one}"`).join(", ");
1677
+ unresolved.push({
1678
+ kind: "task-name",
1679
+ where: `nodes[${stages[0]}].data.tasks[${name}]`,
1680
+ detail: `${stages.length} tasks are named "${name}" (in ${stageNames}). Task names are unique across the case, so rename all but one`
1681
+ });
1682
+ }
1683
+ };
1684
+ var planCase = (model, unresolved) => {
1685
+ const stageIds = new Map;
1686
+ const taskIds = new Map;
1687
+ const outputIds = new Map;
1688
+ const takenOutputIds = new Set;
1689
+ const tasksByExactName = [];
1690
+ const stagesByTaskName = new Map;
1691
+ const tasksByFolded = new Map;
1692
+ const stagesBySlug = [];
1693
+ const stagesByOrdinal = [];
1694
+ const outputsBySlug = [];
1695
+ const outputsByOrdinal = [];
1696
+ const outputsByTask = new Map;
1697
+ const bindings = [];
1698
+ const bindingsByKey = new Map;
1699
+ const connections = new Map;
1700
+ const slaIds = new Map;
1701
+ const planned = model.stages.map((stage, position) => {
1702
+ const stageId = prefixedId("Stage_");
1703
+ const stageSla = slaRuleFor(String(stage.slaTitle ?? `${stage.name} SLA`), String(stage.slaDuration ?? ""), stage.slaEscalationRows ?? [], `nodes[${stage.name}].data.sla`, unresolved, { table: stage.slaEscalations, map: stage.slaResponses });
1704
+ if (stageSla !== undefined) {
1705
+ const entry = { id: String(stageSla.id), stageId };
1706
+ const title = indexKey(String(stageSla.displayName));
1707
+ slaIds.set(title, entry);
1708
+ slaIds.set(scopedSlaKey(stageId, title), entry);
1709
+ } else if (stage.hasSla === true || /\d/.test(String(stage.slaDuration ?? ""))) {
1710
+ const stated = String(stage.slaDuration ?? "").trim();
1711
+ unresolved.push({
1712
+ kind: "case-sla",
1713
+ where: `nodes[${stage.name}].data.slaRules`,
1714
+ detail: `this stage declares an SLA and no rule could be emitted from it: the duration cell is ${stated === "" ? "absent, so the escalation rows have no duration to be a percentage of" : `\`${stated}\`, which gives no count and a unit the case schema names (min, h, d, w, m, and the spellings that map to them)`}. The stage's SLA title, duration and escalation rows are all dropped together, so authoring the duration is what carries them`
1715
+ });
1716
+ }
1717
+ const spelling = stageSpellings(stage.name, position + 1);
1718
+ for (const name of spelling.names) {
1719
+ claim(stageIds, indexKey(name), stageId);
1720
+ }
1721
+ if (spelling.slug !== undefined) {
1722
+ stagesBySlug.push([indexKey(spelling.slug), stageId]);
1723
+ }
1724
+ stagesByOrdinal.push([indexKey(spelling.ordinal), stageId]);
1725
+ const namesInStage = stage.tasks.map(taskNameOf);
1726
+ const tasksInStage = new Map;
1727
+ for (const name of namesInStage) {
1728
+ tasksInStage.set(name, (tasksInStage.get(name) ?? 0) + 1);
1729
+ }
1730
+ const tasks = stage.tasks.map((task) => {
1731
+ const taskId = prefixedId("t", 8);
1732
+ const taskName = taskNameOf(task);
1733
+ tasksByExactName.push([taskName, taskId]);
1734
+ stagesByTaskName.set(taskName, [
1735
+ ...stagesByTaskName.get(taskName) ?? [],
1736
+ stage.name
1737
+ ]);
1738
+ const folded = tasksByFolded.get(indexKey(taskName)) ?? new Map;
1739
+ folded.set(taskName, taskId);
1740
+ tasksByFolded.set(indexKey(taskName), folded);
1741
+ const own = new Map;
1742
+ const indexOutput = (labels, output) => {
1743
+ const sharing = tasksInStage.get(taskName) ?? 1;
1744
+ const claimed = sharing > 1 ? sharing : String(output.id);
1745
+ for (const label of labels) {
1746
+ const suffix = `${indexKey(taskName)}|${indexKey(label)}`;
1747
+ for (const name of spelling.names) {
1748
+ claimOutput(outputIds, `${indexKey(name)}|${suffix}`, taskName, claimed);
1749
+ }
1750
+ if (spelling.slug !== undefined) {
1751
+ outputsBySlug.push([
1752
+ `${indexKey(spelling.slug)}|${suffix}`,
1753
+ taskName,
1754
+ claimed
1755
+ ]);
1756
+ }
1757
+ outputsByOrdinal.push([
1758
+ `${indexKey(spelling.ordinal)}|${suffix}`,
1759
+ taskName,
1760
+ claimed
1761
+ ]);
1762
+ }
1763
+ };
1764
+ const extractByField = new Map;
1765
+ for (const entry of task.extractRows ?? []) {
1766
+ const field = String(entry.field ?? "");
1767
+ const variable = String(entry.variable ?? "");
1768
+ if (field !== "" && variable !== "") {
1769
+ extractByField.set(field, variable);
1770
+ }
1771
+ }
1772
+ for (const row of declaredOutputs(model, stage.name, position + 1, task)) {
1773
+ const consumerType = outputTypeFor(model, everySpelling(stage.name, position + 1), taskName, row);
1774
+ const variable = extractByField.get(row);
1775
+ const type = consumerType ?? (variable === undefined ? undefined : variableOutputType(model, variable));
1776
+ if (type === undefined) {
1777
+ unresolved.push({
1778
+ kind: "output-type",
1779
+ where: `nodes[${stage.name}].data.tasks[${taskName}].outputs[${row}]`,
1780
+ detail: "no row in this SDD types this output; its shape comes from the resolved resource's own schema, which needs a tenant — `uip maestro case tasks describe --type <type> --id <id>` returns it, and `uip maestro case splice <plan> --task-id <taskId> --described <that result>` writes it in"
1781
+ });
1782
+ }
1783
+ const output = variable === undefined ? outputFor(row, buildElementId(stageId, taskId), takenOutputIds, type) : extractOutputFor({ field: row, variable }, buildElementId(stageId, taskId), takenOutputIds, type);
1784
+ own.set(row, output);
1785
+ indexOutput(new Set([
1786
+ row,
1787
+ String(output.name),
1788
+ ...variable === undefined ? [] : [variable]
1789
+ ]), output);
1790
+ }
1791
+ for (const entry of task.customRows ?? []) {
1792
+ const row = {
1793
+ variable: String(entry.variable ?? ""),
1794
+ expression: String(entry.expression ?? "")
1795
+ };
1796
+ if (row.variable === "")
1797
+ continue;
1798
+ const custom = customOutputFor(row, variableOutputType(model, row.variable));
1799
+ const declared = own.get(row.variable);
1800
+ const output = declared === undefined ? custom : { ...custom, id: declared.id };
1801
+ own.set(declared === undefined ? `custom:${row.variable}` : row.variable, output);
1802
+ indexOutput(new Set([row.variable]), {
1803
+ ...output,
1804
+ id: output.id ?? row.variable
1805
+ });
1806
+ }
1807
+ outputsByTask.set(taskId, own);
1808
+ return { task, taskId };
1809
+ });
1810
+ return { stage, stageId, tasks, stageSla };
1811
+ });
1812
+ const tasksPerName = countByName(tasksByExactName);
1813
+ reportRepeatedTaskNames(stagesByTaskName, unresolved);
1814
+ const taskNameConflicts = new Map;
1815
+ for (const [key, byName] of tasksByFolded) {
1816
+ const names = [...byName.keys()].flatMap((name) => Array.from({ length: tasksPerName.get(name) ?? 1 }, () => name));
1817
+ if (names.length === 1) {
1818
+ const only = [...byName.values()][0];
1819
+ if (only !== undefined)
1820
+ taskIds.set(key, only);
1821
+ } else {
1822
+ taskNameConflicts.set(key, names);
1823
+ }
1824
+ }
1825
+ for (const [name, id] of tasksByExactName) {
1826
+ if (tasksPerName.get(name) === 1)
1827
+ taskIds.set(name, id);
1828
+ }
1829
+ const caseSla = slaRuleFor(model.caseSlaTitle ?? CASE_SLA_PROPERTY, String(model.caseSlaDuration ?? ""), model.caseSlaEscalationRows, "metadata.slaRules", unresolved, { table: model.caseSlaEscalations, map: model.caseSlaResponses });
1830
+ if (caseSla !== undefined) {
1831
+ const key = indexKey(String(caseSla.displayName));
1832
+ const entry = { id: String(caseSla.id), stageId: "root" };
1833
+ if (!slaIds.has(key))
1834
+ slaIds.set(key, entry);
1835
+ slaIds.set(scopedSlaKey("root", key), entry);
1836
+ }
1837
+ for (const [key, id] of stagesBySlug)
1838
+ claim(stageIds, key, id);
1839
+ for (const [key, id] of stagesByOrdinal)
1840
+ claim(stageIds, key, id);
1841
+ for (const [key, task, id] of outputsBySlug)
1842
+ claimOutput(outputIds, key, task, id);
1843
+ for (const [key, task, id] of outputsByOrdinal)
1844
+ claimOutput(outputIds, key, task, id);
1845
+ return {
1846
+ planned,
1847
+ stageIds,
1848
+ taskIds,
1849
+ taskNameConflicts,
1850
+ outputIds,
1851
+ outputsByTask,
1852
+ bindings,
1853
+ bindingsByKey,
1854
+ connections,
1855
+ slaIds,
1856
+ ...caseSla !== undefined && { caseSla }
1857
+ };
1858
+ };
1859
+
1860
+ // src/services/sdd-convert/rule-names.ts
1861
+ var asArray = (value) => Array.isArray(value) ? value : [];
1862
+ var asRow = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
1863
+ var uniquifyConditionNames = (document) => {
1864
+ const owned = [];
1865
+ const collect = (conditions, owner) => {
1866
+ for (const entry of asArray(conditions)) {
1867
+ const condition = asRow(entry);
1868
+ if (condition === undefined)
1869
+ continue;
1870
+ const name = condition.displayName;
1871
+ if (typeof name !== "string" || name.trim() === "")
1872
+ continue;
1873
+ owned.push({ condition, owner });
1874
+ }
1875
+ };
1876
+ for (const node of asArray(document.nodes)) {
1877
+ const data = asRow(asRow(node)?.data);
1878
+ if (data === undefined)
1879
+ continue;
1880
+ const stage = typeof data.label === "string" ? data.label : "";
1881
+ collect(data.entryConditions, stage);
1882
+ collect(data.exitConditions, stage);
1883
+ for (const lane of asArray(data.tasks)) {
1884
+ for (const entry of asArray(lane)) {
1885
+ const task = asRow(entry);
1886
+ const name = typeof task?.displayName === "string" ? task.displayName : "";
1887
+ collect(task?.entryConditions, name === "" ? stage : name);
1888
+ }
1889
+ }
1890
+ }
1891
+ collect(asRow(document.metadata)?.caseExitRules, "case");
1892
+ const taken = new Set;
1893
+ const seen = new Set;
1894
+ for (const { condition } of owned) {
1895
+ taken.add(String(condition.displayName).trim());
1896
+ }
1897
+ let renamed = 0;
1898
+ for (const { condition, owner } of owned) {
1899
+ const name = String(condition.displayName).trim();
1900
+ if (!seen.has(name)) {
1901
+ seen.add(name);
1902
+ continue;
1903
+ }
1904
+ const base = owner === "" ? name : `${name} (${owner})`;
1905
+ let candidate = base;
1906
+ for (let n = 2;taken.has(candidate); n += 1) {
1907
+ candidate = `${base} ${n}`;
1908
+ }
1909
+ taken.add(candidate);
1910
+ seen.add(candidate);
1911
+ condition.displayName = candidate;
1912
+ renamed += 1;
1913
+ }
1914
+ return renamed;
1915
+ };
1916
+
1917
+ // src/services/sdd-convert-service.ts
1918
+ var convertSddToCasePlan = (model, options) => {
1919
+ const document = buildMinimalCaseDocument({
1920
+ name: options.name,
1921
+ schemaVersion: options.schemaVersion,
1922
+ ...options.description !== undefined && {
1923
+ description: options.description
1924
+ }
1925
+ });
1926
+ const unresolved = [];
1927
+ const index = planCase(model, unresolved);
1928
+ if (options.resolved !== undefined)
1929
+ index.resolved = options.resolved;
1930
+ const placeholderOutputs = new Set;
1931
+ for (const planned of index.planned) {
1932
+ for (const { task, taskId } of planned.tasks) {
1933
+ if (!isDeferredTask(index.resolved, planned.stage.name, task)) {
1934
+ continue;
1935
+ }
1936
+ for (const output of index.outputsByTask.get(taskId)?.values() ?? []) {
1937
+ const id = output.id ?? output.var;
1938
+ if (typeof id === "string")
1939
+ placeholderOutputs.add(id);
1940
+ }
1941
+ }
1942
+ }
1943
+ markDeferredOutputs(index.outputIds, placeholderOutputs);
1944
+ const { taskCount, conditionCount } = emitStages(document, model, index, unresolved);
1945
+ const caseLevel = finishCaseDocument(document, model, index, unresolved);
1946
+ uniquifyConditionNames(document);
1947
+ return {
1948
+ document,
1949
+ derived: {
1950
+ stages: model.stages.length,
1951
+ tasks: taskCount,
1952
+ conditions: conditionCount + caseLevel.conditionCount,
1953
+ variables: model.variables.length
1954
+ },
1955
+ unresolved
1956
+ };
1957
+ };
1958
+ export {
1959
+ convertSddToCasePlan
1960
+ };
1961
+
1962
+ //# debugId=39653583D0D6907964756E2164756E21