@uipath/maestro-builder-sdk 6.20.0 → 6.20.1
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/decompile.js +105 -19
- package/package.json +2 -2
package/dist/decompile.js
CHANGED
|
@@ -2227,6 +2227,83 @@ function sweepDroppedEdges(graph, skip) {
|
|
|
2227
2227
|
}
|
|
2228
2228
|
return lines;
|
|
2229
2229
|
}
|
|
2230
|
+
/** Every out-edge of `id` on port `port`, in edge order. */
|
|
2231
|
+
function portEdges(graph, id, port) {
|
|
2232
|
+
return graph.outEdges(id).filter((e) => e.sourcePort === port);
|
|
2233
|
+
}
|
|
2234
|
+
/** `id`'s successor edges whose target is inside `scope` (the edges `scopeSucc` follows). */
|
|
2235
|
+
function scopeSuccEdges(graph, id, scope) {
|
|
2236
|
+
return graph.successorEdges(id).filter((e) => e.targetPort !== 'loopBack' && scope.has(e.targetNodeId));
|
|
2237
|
+
}
|
|
2238
|
+
/**
|
|
2239
|
+
* The nearest node that post-dominates EVERY one of `targets` — where the paths
|
|
2240
|
+
* that start at them all meet again — or `undefined` when they only meet at the
|
|
2241
|
+
* scope exit. Walks each target's `ipdom` chain (the target itself first).
|
|
2242
|
+
*/
|
|
2243
|
+
function commonPostDominator(targets, ipdom) {
|
|
2244
|
+
const chain = (t) => {
|
|
2245
|
+
const out = [];
|
|
2246
|
+
for (let n = t; n !== undefined && n !== EXIT && !out.includes(n); n = ipdom.get(n))
|
|
2247
|
+
out.push(n);
|
|
2248
|
+
return out;
|
|
2249
|
+
};
|
|
2250
|
+
const [head, ...rest] = targets.map(chain);
|
|
2251
|
+
const others = rest.map((c) => new Set(c));
|
|
2252
|
+
return head?.find((n) => others.every((c) => c.has(n)));
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* The region that starts with `edges`, the edges ONE source port (or a
|
|
2256
|
+
* trigger) has.
|
|
2257
|
+
*
|
|
2258
|
+
* One edge is an ordinary region (`edgeRegion`). Two or more are a fork, which
|
|
2259
|
+
* is what serialize emits for a `.parallel(...)` that is the first thing in a
|
|
2260
|
+
* flow, a subflow, an entry point's prefix or a branch / switch arm: the trigger
|
|
2261
|
+
* (or the arm's port) gets one edge per parallel arm, and the arms meet at the
|
|
2262
|
+
* parallel's merge node. When the targets meet at a merge node the fork
|
|
2263
|
+
* decompiles to that `.parallel(...)`, then the region continues from the
|
|
2264
|
+
* merge's output (flow-builder-sdk#1155).
|
|
2265
|
+
*
|
|
2266
|
+
* Every edge in `edges` is accounted (edge accounting, #1125): the fold
|
|
2267
|
+
* recreates each one. A fork whose arms never meet at a merge node has no
|
|
2268
|
+
* builder spelling. Like the same shape mid-flow (`region`), it throws under
|
|
2269
|
+
* `bestEffort: false`, and otherwise keeps the first arm behind a
|
|
2270
|
+
* `TODO: unstructured fan-out` marker, which is what reports the other edges.
|
|
2271
|
+
*/
|
|
2272
|
+
function forkRegion(edges, stop, scope, ipdom, ctx, refInto) {
|
|
2273
|
+
if (edges.length <= 1)
|
|
2274
|
+
return edgeRegion(edges[0], stop, scope, ipdom, ctx, refInto);
|
|
2275
|
+
const targets = edges.map((e) => e.targetNodeId);
|
|
2276
|
+
const join = commonPostDominator(targets, ipdom);
|
|
2277
|
+
const joinNode = join !== undefined ? ctx.graph.byId.get(join) : undefined;
|
|
2278
|
+
if (join === undefined || join === stop || joinNode?.type !== T.merge) {
|
|
2279
|
+
if (ctx.o.bestEffort === false)
|
|
2280
|
+
throw new Error(`decompile: unstructured fan-out (${edges.length} edges).`);
|
|
2281
|
+
for (const e of edges)
|
|
2282
|
+
ctx.graph.accounted.add(e);
|
|
2283
|
+
return [
|
|
2284
|
+
`/* TODO: unstructured fan-out (${commentText(edges.length)} edges) */`,
|
|
2285
|
+
...region(targets[0], stop, scope, ipdom, ctx, refInto),
|
|
2286
|
+
];
|
|
2287
|
+
}
|
|
2288
|
+
for (const e of edges)
|
|
2289
|
+
ctx.graph.accounted.add(e);
|
|
2290
|
+
const fork = parallelSeg(join, joinNode, targets, scope, ipdom, ctx, refInto);
|
|
2291
|
+
if (fork.next.brk || fork.next.cont)
|
|
2292
|
+
return [fork.seg, fork.next.brk ? '.break()' : '.continue()'];
|
|
2293
|
+
return [fork.seg, ...region(fork.next.cursor, stop, scope, ipdom, ctx, refInto)];
|
|
2294
|
+
}
|
|
2295
|
+
/**
|
|
2296
|
+
* The `.parallel(join, [arms])` segment for a fork whose `targets` (one per
|
|
2297
|
+
* edge; the caller accounts those edges) meet at the merge node `join`. Each
|
|
2298
|
+
* arm is the region up to `join`. `next` is where the walk goes after the
|
|
2299
|
+
* merge: its `output` edge, accounted by `continueOn` (`brk` / `cont` when
|
|
2300
|
+
* that edge leaves through the enclosing loop's `break` / spelled `continue`).
|
|
2301
|
+
*/
|
|
2302
|
+
function parallelSeg(join, joinNode, targets, scope, ipdom, ctx, refInto) {
|
|
2303
|
+
const arms = targets.map((t, i) => armCb(`a${i}`, region(t, join, scope, ipdom, ctx, refInto)));
|
|
2304
|
+
const seg = `.parallel(${tsLiteral(join)}, [\n${arms.map((a) => reindent(a, ' ')).join(',\n')},\n]${verArg(joinNode)})`;
|
|
2305
|
+
return { seg, next: continueOn(joinNode, 'output', ctx, refInto) };
|
|
2306
|
+
}
|
|
2230
2307
|
/** Re-indent every non-empty line of a (possibly multi-line) segment by `pad`. */
|
|
2231
2308
|
function reindent(seg, pad) {
|
|
2232
2309
|
return seg.split('\n').map((l) => (l === '' ? l : pad + l)).join('\n');
|
|
@@ -2385,8 +2462,8 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2385
2462
|
if (node.type === T.decision) {
|
|
2386
2463
|
const r = ipdom.get(node.id) ?? stop;
|
|
2387
2464
|
const cond = emitBareExpr(String((node.inputs ?? {}).expression ?? ''), ctx.imp, ctx.inputNames);
|
|
2388
|
-
const thenSegs =
|
|
2389
|
-
const elseSegs =
|
|
2465
|
+
const thenSegs = forkRegion(portEdges(ctx.graph, node.id, 'true'), r, scope, ipdom, ctx, refInto);
|
|
2466
|
+
const elseSegs = forkRegion(portEdges(ctx.graph, node.id, 'false'), r, scope, ipdom, ctx, refInto);
|
|
2390
2467
|
const labels = armLabels(node);
|
|
2391
2468
|
if (labels.trueLabel)
|
|
2392
2469
|
thenSegs.unshift(`.label(${tsLiteral(labels.trueLabel)})`);
|
|
@@ -2574,16 +2651,16 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2574
2651
|
}
|
|
2575
2652
|
// Parallel: the fork's ipdom is the merge join; each successor is one arm.
|
|
2576
2653
|
const join = ipdom.get(node.id);
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2654
|
+
const joinNode = join !== undefined ? ctx.graph.byId.get(join) : undefined;
|
|
2655
|
+
if (join && join !== EXIT && joinNode?.type === T.merge) {
|
|
2656
|
+
const fork = parallelSeg(join, joinNode, succ.map((t) => follow(ctx.graph, node.id, t)), scope, ipdom, ctx, refInto);
|
|
2657
|
+
segs.push(fork.seg);
|
|
2580
2658
|
flagDropped(node, ctx, segs);
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
segs.push(next.brk ? '.break()' : '.continue()');
|
|
2659
|
+
if (fork.next.brk || fork.next.cont) {
|
|
2660
|
+
segs.push(fork.next.brk ? '.break()' : '.continue()');
|
|
2584
2661
|
return segs;
|
|
2585
2662
|
}
|
|
2586
|
-
cursor = next.cursor;
|
|
2663
|
+
cursor = fork.next.cursor;
|
|
2587
2664
|
continue;
|
|
2588
2665
|
}
|
|
2589
2666
|
// Unstructured fan-out we can't fold — best-effort marker. Its successor
|
|
@@ -2803,7 +2880,7 @@ function emitSwitch(node, ipdom, scope, ctx, stop, refInto) {
|
|
|
2803
2880
|
}
|
|
2804
2881
|
}
|
|
2805
2882
|
}
|
|
2806
|
-
const armSegs =
|
|
2883
|
+
const armSegs = forkRegion(portEdges(ctx.graph, node.id, `case-${c.id}`), r, scope, ipdom, ctx, refInto);
|
|
2807
2884
|
const defaultLabel = `Case ${valueLiteral}`;
|
|
2808
2885
|
const labelPart = c.label && c.label !== defaultLabel ? `, label: ${tsLiteral(c.label)}` : '';
|
|
2809
2886
|
// The file's case id comes back when it is not the positional one serialize
|
|
@@ -2816,7 +2893,7 @@ function emitSwitch(node, ipdom, scope, ctx, stop, refInto) {
|
|
|
2816
2893
|
const on = emitBareExpr(disc ?? '', ctx.imp, ctx.inputNames);
|
|
2817
2894
|
const hasDefault = (node.inputs ?? {}).hasDefault === true || portEdge(ctx.graph, node.id, 'default') !== undefined;
|
|
2818
2895
|
const defArm = hasDefault
|
|
2819
|
-
? `, ${armCb('d',
|
|
2896
|
+
? `, ${armCb('d', forkRegion(portEdges(ctx.graph, node.id, 'default'), r, scope, ipdom, ctx, refInto))}`
|
|
2820
2897
|
: '';
|
|
2821
2898
|
const caseList = `[\n${caseSrcs.map((c) => reindent(c, ' ')).join(',\n')},\n]`;
|
|
2822
2899
|
// The builder's `.switch(on, [{value}])` models `on === value` only. A flow whose
|
|
@@ -3020,9 +3097,11 @@ function emitChildFlow(name, child, ctx) {
|
|
|
3020
3097
|
// Body: the child's trigger is its own manual Start; walk from its successor.
|
|
3021
3098
|
const trigger = (child.nodes ?? []).find((n) => isTrigger(n.type) && !(child.edges ?? []).some((e) => e.targetNodeId === n.id));
|
|
3022
3099
|
const scope = scopeIds(child.nodes ?? [], undefined);
|
|
3023
|
-
const
|
|
3024
|
-
const ipdom =
|
|
3025
|
-
|
|
3100
|
+
const entries = trigger ? scopeSuccEdges(childCtx.graph, trigger.id, scope) : [];
|
|
3101
|
+
const ipdom = entries.length
|
|
3102
|
+
? postDominators(entries.length > 1 ? trigger.id : entries[0].targetNodeId, scope, childCtx.graph)
|
|
3103
|
+
: new Map();
|
|
3104
|
+
const bodySegs = entries.length ? forkRegion(entries, EXIT, scope, ipdom, childCtx) : [];
|
|
3026
3105
|
parts.push(...bodySegs);
|
|
3027
3106
|
parts.push(...sweepDroppedEdges(childCtx.graph, new Set()));
|
|
3028
3107
|
// A subflow carries its own scoped layout, resolved against its own node ids.
|
|
@@ -3144,9 +3223,13 @@ export function decompile(flow, options = {}) {
|
|
|
3144
3223
|
const ctx = { graph, flow, imp, inputNames, o: options, emitted: new Set(), shared };
|
|
3145
3224
|
const scope = scopeIds(flow.nodes ?? [], undefined);
|
|
3146
3225
|
const startId = trigger?.id ?? 'start';
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
const
|
|
3226
|
+
// Walked from the trigger's successors together: a `.parallel` placed first
|
|
3227
|
+
// gives the trigger one edge per arm (#1155).
|
|
3228
|
+
const firsts = scopeSuccEdges(graph, startId, scope);
|
|
3229
|
+
const ipdom = firsts.length
|
|
3230
|
+
? postDominators(firsts.length > 1 ? startId : firsts[0].targetNodeId, scope, graph)
|
|
3231
|
+
: new Map();
|
|
3232
|
+
const bodySegs = firsts.length ? forkRegion(firsts, EXIT, scope, ipdom, ctx) : [];
|
|
3150
3233
|
// Additional roots decompile to .entryPoint(...): scoped inputs from the
|
|
3151
3234
|
// globals bound to them, and a prefix region that hands off into the shared
|
|
3152
3235
|
// body — the shared nodes are in ctx.emitted by now, so the walk naturally
|
|
@@ -3236,8 +3319,11 @@ function entryPointSeg(t, scope, ipdom, ctx) {
|
|
|
3236
3319
|
optParts.push(`inputs: { ${scoped.map((g) => `${key(g.name ?? g.id)}: ${declExpr(g, true, ctx.imp, sharedOf(g))}`).join(', ')} }`);
|
|
3237
3320
|
}
|
|
3238
3321
|
optParts.push(...triggerOptParts(t));
|
|
3239
|
-
const
|
|
3240
|
-
|
|
3322
|
+
const firsts = scopeSuccEdges(ctx.graph, t.id, scope);
|
|
3323
|
+
// A prefix that forks needs post-dominators over ITS nodes, which the root's
|
|
3324
|
+
// map (computed from the default trigger) does not cover.
|
|
3325
|
+
const epIpdom = firsts.length > 1 ? postDominators(t.id, scope, ctx.graph) : ipdom;
|
|
3326
|
+
const prefixSegs = firsts.length ? forkRegion(firsts, EXIT, scope, epIpdom, ctx) : [];
|
|
3241
3327
|
const optArgText = optParts.length ? `, { ${optParts.join(', ')} }` : (prefixSegs.length ? ', undefined' : '');
|
|
3242
3328
|
const prefix = prefixSegs.length ? `, ${armCb('b', prefixSegs)}` : '';
|
|
3243
3329
|
return `.entryPoint(${tsLiteral(t.id)}, ${factory}${optArgText}${prefix})`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.20.
|
|
3
|
+
"version": "6.20.1",
|
|
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",
|
|
@@ -92,5 +92,5 @@
|
|
|
92
92
|
"@types/node": "^22.7.0",
|
|
93
93
|
"esbuild": "^0.28.1"
|
|
94
94
|
},
|
|
95
|
-
"gitref": "
|
|
95
|
+
"gitref": "5440c25e8e833aced459eb5a0ae9109ac3c973ae"
|
|
96
96
|
}
|