@uipath/maestro-builder-sdk 6.70.6 → 6.70.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-index.md +71 -70
- package/dist/api-members.md +216 -216
- package/dist/case/case-expr-check.js +81 -11
- package/dist/case/case-sdk.d.ts +44 -3
- package/dist/case/case-sdk.js +47 -3
- package/dist/case/decompile.js +31 -0
- package/dist/case/serialize.js +117 -7
- package/dist/case/task-output-ref.d.ts +111 -0
- package/dist/case/task-output-ref.js +212 -0
- package/dist/core/refusals.d.ts +1 -0
- package/dist/core/refusals.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading another task's output in place: the SDD's `vars.$xref('<stage>',
|
|
3
|
+
* '<task>', '<output>')` marker, and `taskOutput()`, the typed way to write it
|
|
4
|
+
* (builder-sdk#1241).
|
|
5
|
+
*
|
|
6
|
+
* A task's own output is a variable of its own: the Case Designer saves it as
|
|
7
|
+
* `{ name: 'AgentExpenseRequest', id: 'agentExpenseRequest', var:
|
|
8
|
+
* 'agentExpenseRequest' }`, with no root `variables` entry, and a later task
|
|
9
|
+
* reads it as `=vars.agentExpenseRequest`. The id is the plan's, not the
|
|
10
|
+
* author's: it is unique across the plan, so a second task's `Action` output
|
|
11
|
+
* is `action2`. An SDD therefore names an output by where it is produced, and
|
|
12
|
+
* `uip maestro case sdd convert` lowers each marker to `vars.<output id>`
|
|
13
|
+
* (`sdd-convert/xrefs.ts`). Without the lowering here, an author had to copy
|
|
14
|
+
* the value into a case variable the SDD does not declare, and `validate
|
|
15
|
+
* --strict --sdd` refuses each one (`STRICT_SDD_VARIABLE_EXTRA`).
|
|
16
|
+
*
|
|
17
|
+
* The rule lives here so `check` (at `build()`) and `serialize` read a marker
|
|
18
|
+
* the same way. `build()` cannot see the ids, which `serialize` mints, so it
|
|
19
|
+
* resolves the stage and the task, and the output where the task's rows are
|
|
20
|
+
* all authored (a reference-mode task). `serialize` resolves every marker
|
|
21
|
+
* against the rows it wrote and refuses one that names no output.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* One argument, read by its own delimiter: `'…'`, `"…"`, `` `…` `` or the curly
|
|
25
|
+
* pair, the four `sdd convert` accepts. A curly pair is two code points, so it
|
|
26
|
+
* gets its own branch instead of a backreference.
|
|
27
|
+
*/
|
|
28
|
+
const QUOTED = String.raw `(?:'((?:\\.|[^'\\])*)'|"((?:\\.|[^"\\])*)"|` +
|
|
29
|
+
'`((?:\\\\.|[^`\\\\])*)`' +
|
|
30
|
+
String.raw `|\u201c([^\u201d]*)\u201d)`;
|
|
31
|
+
/** A `vars.$xref(stage, task, output)` marker. Global: use with `replace`/`matchAll` only. */
|
|
32
|
+
const XREF_CALL = new RegExp(String.raw `vars\.\$xref\(\s*${QUOTED}\s*,\s*${QUOTED}\s*,\s*${QUOTED}\s*\)`, 'g');
|
|
33
|
+
/**
|
|
34
|
+
* A property read glued to the marker (`vars.$xref(…).unusualClauses`). The
|
|
35
|
+
* producer may not have run when the reader does, so inside a `=js:`
|
|
36
|
+
* expression the lowering writes the optional chain
|
|
37
|
+
* `vars.<id>?.unusualClauses`, as `sdd convert` does. Only there: `?.` is
|
|
38
|
+
* JavaScript, and nothing shows that the platform's non-js `=vars.<path>`
|
|
39
|
+
* binding reads it, so any other value keeps the plain `.`.
|
|
40
|
+
*/
|
|
41
|
+
const DOTTED_READ = /^\.[A-Za-z_$]/;
|
|
42
|
+
const unescape = (value) => value.replace(/\\(.)/g, '$1');
|
|
43
|
+
/** Each marker in `text`, in order, with where it sits. */
|
|
44
|
+
export function taskOutputRefs(text) {
|
|
45
|
+
if (!text.includes('$xref'))
|
|
46
|
+
return [];
|
|
47
|
+
return [...text.matchAll(XREF_CALL)].map((m) => {
|
|
48
|
+
const arg = (from) => unescape(m.slice(from, from + 4).find((v) => v !== undefined) ?? '');
|
|
49
|
+
return { stage: arg(1), task: arg(5), output: arg(9), whole: m[0], index: m.index ?? 0 };
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Replace every marker in `text` with what `lower` returns for it. In a `=js:`
|
|
54
|
+
* expression, a marker followed by a property read gets the optional chain
|
|
55
|
+
* (`vars.<id>?.field`); any other value keeps the plain read (`vars.<id>.field`).
|
|
56
|
+
*
|
|
57
|
+
* @param text - The expression.
|
|
58
|
+
* @param lower - The variable a marker reads (`agentExpenseRequest`), or `undefined` to keep the marker.
|
|
59
|
+
*/
|
|
60
|
+
export function lowerTaskOutputRefs(text, lower) {
|
|
61
|
+
if (!text.includes('$xref'))
|
|
62
|
+
return text;
|
|
63
|
+
const js = /^\s*=js:/.test(text);
|
|
64
|
+
let out = '';
|
|
65
|
+
let at = 0;
|
|
66
|
+
for (const ref of taskOutputRefs(text)) {
|
|
67
|
+
const after = text.slice(ref.index + ref.whole.length);
|
|
68
|
+
const variable = lower(ref);
|
|
69
|
+
// `undefined` keeps the marker as written (a reference to a stand-in; see `resolveInPlan`).
|
|
70
|
+
out += variable === undefined ? text.slice(at, ref.index) + ref.whole : `${text.slice(at, ref.index)}vars.${variable}${js && DOTTED_READ.test(after) ? '?' : ''}`;
|
|
71
|
+
at = ref.index + ref.whole.length;
|
|
72
|
+
}
|
|
73
|
+
return out + text.slice(at);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The one candidate `name` picks out: an exact match first, then a
|
|
77
|
+
* case-insensitive one (an SDD addresses a stage or an output in any case).
|
|
78
|
+
* `undefined` when none does; `'ambiguous'` when more than one does.
|
|
79
|
+
*/
|
|
80
|
+
export function pickByName(items, name, names) {
|
|
81
|
+
for (const same of [(a) => a === name, (a) => a.toLowerCase() === name.toLowerCase()]) {
|
|
82
|
+
const hits = [...new Set(items.filter((item) => names(item).some((n) => n !== undefined && same(n))))];
|
|
83
|
+
if (hits.length === 1)
|
|
84
|
+
return hits[0];
|
|
85
|
+
if (hits.length > 1)
|
|
86
|
+
return 'ambiguous';
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The row an output reference names among one task's rows: by the field it
|
|
92
|
+
* reads (`name`) or by the variable it writes (`var`).
|
|
93
|
+
*/
|
|
94
|
+
export function pickOutputRow(rows, output) {
|
|
95
|
+
return pickByName(rows, output, (row) => [row.name, row.var]);
|
|
96
|
+
}
|
|
97
|
+
/** The refusal message for a marker that resolves to nothing. */
|
|
98
|
+
export function unresolvedTaskOutputRef(ref, why) {
|
|
99
|
+
return `taskOutput(${JSON.stringify(ref.stage)}, ${JSON.stringify(ref.task)}, ${JSON.stringify(ref.output)}) ${why}. ` +
|
|
100
|
+
'A task-output reference names the stage label, the task name and the output (the result field it reads, or the key it has in `.outputs()`).';
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The marker for a reference: `vars.$xref('<stage>','<task>','<output>')`,
|
|
104
|
+
* each argument single-quoted with its quotes and backslashes escaped. What
|
|
105
|
+
* `taskOutput()` returns, and what decompile writes back.
|
|
106
|
+
*/
|
|
107
|
+
export function taskOutputMarker(stage, task, output) {
|
|
108
|
+
const quote = (value) => `'${value.replace(/[\\']/g, '\\$&')}'`;
|
|
109
|
+
return `vars.$xref(${quote(stage)},${quote(task)},${quote(output)})`;
|
|
110
|
+
}
|
|
111
|
+
/** Every stage task's output rows in a written caseplan, in document order. */
|
|
112
|
+
export function planTaskOutputs(plan) {
|
|
113
|
+
const found = [];
|
|
114
|
+
const nodes = plan?.nodes;
|
|
115
|
+
for (const node of Array.isArray(nodes) ? nodes : []) {
|
|
116
|
+
const data = node?.data;
|
|
117
|
+
if (typeof data?.label !== 'string' || !Array.isArray(data.tasks))
|
|
118
|
+
continue;
|
|
119
|
+
for (const lane of data.tasks)
|
|
120
|
+
for (const task of Array.isArray(lane) ? lane : []) {
|
|
121
|
+
if (typeof task?.displayName !== 'string')
|
|
122
|
+
continue;
|
|
123
|
+
const rows = Array.isArray(task.data?.outputs) ? task.data.outputs : [];
|
|
124
|
+
found.push({
|
|
125
|
+
stage: data.label,
|
|
126
|
+
task: task.displayName,
|
|
127
|
+
rows: rows.filter((row) => row && typeof row === 'object'),
|
|
128
|
+
...(task.data?.standIn === true ? { standIn: true } : {}),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return found;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* What a reference reads in a written plan: the variable of the row it names
|
|
136
|
+
* (`vars.<id>`, or a custom row's `var`, which has no id), or why it names none.
|
|
137
|
+
*/
|
|
138
|
+
export function resolveInPlan(tasks, ref) {
|
|
139
|
+
const stage = pickByName([...new Set(tasks.map((t) => t.stage))], ref.stage, (label) => [label]);
|
|
140
|
+
if (stage === undefined)
|
|
141
|
+
return { why: `names no stage labelled ${JSON.stringify(ref.stage)}` };
|
|
142
|
+
if (stage === 'ambiguous')
|
|
143
|
+
return { why: `names a stage label that more than one stage answers to` };
|
|
144
|
+
const task = pickByName(tasks.filter((t) => t.stage === stage), ref.task, (t) => [t.task]);
|
|
145
|
+
if (task === undefined)
|
|
146
|
+
return { why: `names no task ${JSON.stringify(ref.task)} in stage ${JSON.stringify(stage)}` };
|
|
147
|
+
if (task === 'ambiguous')
|
|
148
|
+
return { why: `names a task that more than one task in stage ${JSON.stringify(stage)} answers to` };
|
|
149
|
+
// The named task was refused and stood in (collect mode). Its refusal is the
|
|
150
|
+
// finding; its outputs were never written, so there is nothing to judge the
|
|
151
|
+
// reference against here (`build()` already judged it against the authored ones).
|
|
152
|
+
if (task.standIn)
|
|
153
|
+
return { standIn: true };
|
|
154
|
+
const row = pickOutputRow(task.rows, ref.output);
|
|
155
|
+
const offered = [...new Set(task.rows.map((r) => r.name).filter((n) => typeof n === 'string'))];
|
|
156
|
+
if (row === undefined)
|
|
157
|
+
return { why: `names no output of task ${JSON.stringify(task.task)}, whose outputs are ${offered.length ? offered.map((n) => JSON.stringify(n)).join(', ') : 'none'}` };
|
|
158
|
+
if (row === 'ambiguous')
|
|
159
|
+
return { why: `names more than one output of task ${JSON.stringify(task.task)}; name it by the variable it writes instead` };
|
|
160
|
+
const variable = typeof row.id === 'string' && row.id ? row.id : row.var;
|
|
161
|
+
if (typeof variable !== 'string' || !variable)
|
|
162
|
+
return { why: `names an output of task ${JSON.stringify(task.task)} that writes no variable` };
|
|
163
|
+
return { variable };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Turn each `vars.<output id>` read in `text` that only a task-output reference
|
|
167
|
+
* can say back into `vars.$xref(…)`, for decompile. `byId` maps such an id to
|
|
168
|
+
* the reference that names it.
|
|
169
|
+
*/
|
|
170
|
+
export function raiseTaskOutputReads(text, byId) {
|
|
171
|
+
if (!byId.size || !text.includes('vars.'))
|
|
172
|
+
return text;
|
|
173
|
+
return text.replace(/(?<![\w$.])vars\.([A-Za-z_$][\w$]*)(?![\w$])/g, (whole, id) => {
|
|
174
|
+
const ref = byId.get(id);
|
|
175
|
+
return ref ? taskOutputMarker(ref.stage, ref.task, ref.output) : whole;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The output ids a decompiled source can only read back by reference: a row
|
|
180
|
+
* whose id is not the variable it writes (a reassigned extract, a Designer row
|
|
181
|
+
* such as `{ id: 'oA1b2C3d4', var: 'AgentExpenseRequest' }`). Recompiling mints
|
|
182
|
+
* that id afresh, and no declaration makes `vars.<id>` readable, so a
|
|
183
|
+
* `vars.<id>` read in the plan goes back to the source as the reference that
|
|
184
|
+
* resolves to the same row. A read of an id that is also a variable (an
|
|
185
|
+
* own-name row, a root variable) is left as written. A row the reference
|
|
186
|
+
* could not name uniquely is left as written too.
|
|
187
|
+
*/
|
|
188
|
+
export function referableOutputIds(plan, rootNames) {
|
|
189
|
+
const tasks = planTaskOutputs(plan);
|
|
190
|
+
const vars = new Set(rootNames);
|
|
191
|
+
for (const task of tasks)
|
|
192
|
+
for (const row of task.rows)
|
|
193
|
+
if (typeof row.var === 'string')
|
|
194
|
+
vars.add(row.var);
|
|
195
|
+
const byId = new Map();
|
|
196
|
+
for (const task of tasks)
|
|
197
|
+
for (const row of task.rows) {
|
|
198
|
+
if (typeof row.id !== 'string' || !row.id || row.id === row.var || vars.has(row.id))
|
|
199
|
+
continue;
|
|
200
|
+
for (const output of [row.name, row.var]) {
|
|
201
|
+
if (typeof output !== 'string' || !output)
|
|
202
|
+
continue;
|
|
203
|
+
const ref = { stage: task.stage, task: task.task, output };
|
|
204
|
+
const resolved = resolveInPlan(tasks, ref);
|
|
205
|
+
if ('variable' in resolved && resolved.variable === row.id) {
|
|
206
|
+
byId.set(row.id, ref);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return byId;
|
|
212
|
+
}
|
package/dist/core/refusals.d.ts
CHANGED
|
@@ -640,6 +640,7 @@ export declare const REFUSALS: {
|
|
|
640
640
|
readonly TASK_OUTPUTS_NO_RESPONSE: "lowering";
|
|
641
641
|
readonly TASK_OUTPUTS_PLACEHOLDER_EVENT: "lowering";
|
|
642
642
|
readonly TASK_OUTPUTS_UNSUPPORTED: "lowering";
|
|
643
|
+
readonly TASK_OUTPUT_REF_UNRESOLVED: "lowering";
|
|
643
644
|
readonly TASK_OUTPUT_SOURCE_AND_ASSIGN: "lowering";
|
|
644
645
|
readonly TASK_REENTRY_IGNORED: "lint";
|
|
645
646
|
readonly TASK_TIMER_OUT_OF_RANGE: "lint";
|
package/dist/core/refusals.js
CHANGED
|
@@ -692,6 +692,7 @@ export const REFUSALS = {
|
|
|
692
692
|
TASK_OUTPUTS_NO_RESPONSE: 'lowering',
|
|
693
693
|
TASK_OUTPUTS_PLACEHOLDER_EVENT: 'lowering',
|
|
694
694
|
TASK_OUTPUTS_UNSUPPORTED: 'lowering',
|
|
695
|
+
TASK_OUTPUT_REF_UNRESOLVED: 'lowering',
|
|
695
696
|
TASK_OUTPUT_SOURCE_AND_ASSIGN: 'lowering',
|
|
696
697
|
TASK_REENTRY_IGNORED: 'lint',
|
|
697
698
|
TASK_TIMER_OUT_OF_RANGE: 'lint',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.70.
|
|
3
|
+
"version": "6.70.7",
|
|
4
4
|
"description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://docs.uipath.com/maestro",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"@types/node": "^22.7.0",
|
|
101
101
|
"esbuild": "^0.28.1"
|
|
102
102
|
},
|
|
103
|
-
"gitref": "
|
|
103
|
+
"gitref": "31471f814e8ca706a02e96e3dbceb39641584de6"
|
|
104
104
|
}
|