@uipath/maestro-builder-sdk 6.66.6 → 6.66.8
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/bindings-v2.d.ts +15 -1
- package/dist/bindings-v2.js +29 -6
- package/dist/bpmn/check.js +16 -113
- package/dist/bpmn/serialize.d.ts +41 -0
- package/dist/bpmn/serialize.js +103 -1
- package/dist/bpmn/typed-node.d.ts +12 -0
- package/dist/bpmn/typed-node.js +24 -0
- package/dist/case/check.js +5 -40
- package/dist/case/serialize.js +6 -0
- package/dist/case/task-shape.d.ts +31 -0
- package/dist/case/task-shape.js +48 -0
- package/dist/check.js +7 -43
- package/dist/core/agent-sidecar.d.ts +13 -3
- package/dist/core/agent-sidecar.js +10 -0
- package/dist/core/compile-refusal.d.ts +25 -0
- package/dist/core/compile-refusal.js +19 -0
- package/dist/core/process-resource.d.ts +9 -0
- package/dist/core/process-resource.js +4 -0
- package/dist/core/refusals.d.ts +47 -44
- package/dist/core/refusals.js +47 -44
- package/dist/nodes/agent/flow/check.js +14 -42
- package/dist/nodes/agent/flow/inline-agent.js +62 -1
- package/dist/nodes/agent/flow/spec.d.ts +1 -1
- package/dist/nodes/connector/flow/node-type.js +5 -3
- package/dist/nodes/data-fabric/flow/check.js +2 -4
- package/dist/nodes/data-fabric/flow/shared.d.ts +9 -4
- package/dist/nodes/data-fabric/flow/shared.js +14 -4
- package/dist/nodes/document/flow/ixp.js +20 -9
- package/dist/nodes/hitl/flow/check.js +29 -110
- package/dist/nodes/hitl/flow/node-type.js +170 -3
- package/dist/nodes/process/flow/check.js +15 -80
- package/dist/nodes/process/flow/node-type.js +4 -0
- package/dist/nodes/process/flow/refusals.d.ts +8 -0
- package/dist/nodes/process/flow/refusals.js +92 -0
- package/dist/nodes/queue/flow/check.d.ts +25 -0
- package/dist/nodes/queue/flow/check.js +48 -18
- package/dist/nodes/queue/flow/node-type.js +13 -1
- package/dist/nodes/transform/flow/check.js +31 -43
- package/dist/nodes/transform/flow/node-type.js +35 -9
- package/dist/serialize.js +172 -20
- package/package.json +2 -2
package/dist/serialize.js
CHANGED
|
@@ -11,7 +11,7 @@ import { LOOP_DEFAULT_VERSION, bodyUsesBreak, loopDeclaredInputs, loopHasInnerHa
|
|
|
11
11
|
import { Expr, toExpr, SCHEDULE_PRESETS, flatNameSegmentsOf, parallelFork } from './flow-sdk.js';
|
|
12
12
|
import { FlowAction, FlowTrigger } from './core/node-classes.js';
|
|
13
13
|
import { connectorRawNodeRefusal } from './core/connector-raw-node.js';
|
|
14
|
-
import { CompileRefusal } from './core/compile-refusal.js';
|
|
14
|
+
import { CompileRefusal, LibraryRequiredRefusal } from './core/compile-refusal.js';
|
|
15
15
|
import { nearestName } from './core/edit-distance.js';
|
|
16
16
|
import { rawNodeInputProblem, registeredRawType } from './raw-node-advice.js';
|
|
17
17
|
import { planContributionBindings } from './core/contribution-bindings.js';
|
|
@@ -736,17 +736,31 @@ function resolveEvent(library, kind, sub, where) {
|
|
|
736
736
|
/**
|
|
737
737
|
* LIBRARY_REQUIRED for an event subscription at `site`, after the refusals that
|
|
738
738
|
* need no library: its binding labels, judged as `eventDetail` judges them, so a
|
|
739
|
-
* run without a library (`check`'s inner loop) still hears about them.
|
|
739
|
+
* run without a library (`check`'s inner loop) still hears about them. The
|
|
740
|
+
* refusal carries the connection the node is bound to, so its collect-mode
|
|
741
|
+
* stand-in still takes part in the file-wide connection rule (`connectionConnectors`).
|
|
740
742
|
*/
|
|
741
743
|
function libraryRequiredForEvent(opts, sub, nodeId, site, call) {
|
|
744
|
+
let use;
|
|
742
745
|
if (sub !== null && typeof sub === 'object') {
|
|
746
|
+
// With no library no parameter is declared, so every `where` key lands in
|
|
747
|
+
// eventParameters and folds into the match expression, exactly as
|
|
748
|
+
// `eventDetail` places an undeclared key. A lookup token is a value only
|
|
749
|
+
// a library resolves; it is not judged here.
|
|
750
|
+
if (sub.where !== null && typeof sub.where === 'object') {
|
|
751
|
+
const scope = Object.fromEntries(Object.entries(sub.where).filter(([, v]) => !isLookupToken(v)));
|
|
752
|
+
eventScopeClauses(flattenWhere(scope, new Set()), nodeId);
|
|
753
|
+
}
|
|
743
754
|
if (Array.isArray(sub.filters))
|
|
744
755
|
eventFilterReads(sub.filters, nodeId);
|
|
745
756
|
requireBindingPair(site, sub, eventTarget(sub));
|
|
746
|
-
resolveBinding(opts, sub.connection, 'connection', `event node "${nodeId}"`, eventTarget(sub));
|
|
757
|
+
const connection = resolveBinding(opts, sub.connection, 'connection', `event node "${nodeId}"`, eventTarget(sub));
|
|
747
758
|
resolveBinding(opts, sub.folder, 'folder', `event node "${nodeId}"`, eventTarget(sub));
|
|
759
|
+
const connector = eventTarget(sub)?.key;
|
|
760
|
+
if (connection !== undefined && connector !== undefined)
|
|
761
|
+
use = { connector, connection };
|
|
748
762
|
}
|
|
749
|
-
return new
|
|
763
|
+
return new LibraryRequiredRefusal(`${call} needs a library (pass --library / set $FLOW_SDK_LIBRARY_JSON).`, use);
|
|
750
764
|
}
|
|
751
765
|
/** The trigger kinds a `.trigger()` or `.entryPoint()` spec may carry. */
|
|
752
766
|
const TRIGGER_KINDS = new Set(['manual', 'scheduled', 'event', 'form', 'conversation', 'voice']);
|
|
@@ -916,6 +930,36 @@ function eventFilterReads(filters, nodeId) {
|
|
|
916
930
|
return read;
|
|
917
931
|
});
|
|
918
932
|
}
|
|
933
|
+
/**
|
|
934
|
+
* The match-expression clauses of a subscription's EVENT parameters, one
|
|
935
|
+
* `k == '<value>'` per value, or the refusal of the first value compile cannot
|
|
936
|
+
* write there. The clause compares against a JMESPath string, so the value must
|
|
937
|
+
* be a string, number or boolean: an object or array would be stringified to
|
|
938
|
+
* `'[object Object]'` (or a comma list), a subscription that matches nothing
|
|
939
|
+
* (EVENT_WHERE_NOT_SCALAR). A string with a backslash JMESPath engines read
|
|
940
|
+
* apart is EVENT_FILTER_BACKSLASH. An absent or empty value (`''` or `[]`, so a
|
|
941
|
+
* `where` built from a possibly-empty list) writes no clause.
|
|
942
|
+
*
|
|
943
|
+
* Only event parameters fold into the expression; a query or path parameter is
|
|
944
|
+
* sent with the request that registers the subscription and is never read as
|
|
945
|
+
* JMESPath, so neither rule applies to it.
|
|
946
|
+
*/
|
|
947
|
+
function eventScopeClauses(eventParameters, nodeId) {
|
|
948
|
+
return Object.entries(eventParameters)
|
|
949
|
+
.filter(([, v]) => v !== undefined && v !== null && v !== '' && !(Array.isArray(v) && v.length === 0))
|
|
950
|
+
.map(([k, v]) => {
|
|
951
|
+
if (typeof v !== 'string' && typeof v !== 'number' && typeof v !== 'boolean') {
|
|
952
|
+
throw new CompileRefusal('EVENT_WHERE_NOT_SCALAR', `event node "${nodeId}": \`where.${k}\` is ${Array.isArray(v) ? 'an array' : isLookupToken(v) ? 'an unresolved lookup() nested inside an object' : 'an object'}, `
|
|
953
|
+
+ `and an event parameter is matched as one text value (\`${k} == '<value>'\`): written as it is, `
|
|
954
|
+
+ `the subscription would compare against ${JSON.stringify(String(v))} and match nothing. `
|
|
955
|
+
+ `Give \`${k}\` a string, number or boolean.`, `where: { '${k}': '<value>' }`);
|
|
956
|
+
}
|
|
957
|
+
const problem = jmesStringProblem(String(v));
|
|
958
|
+
if (problem)
|
|
959
|
+
throw new CompileRefusal('EVENT_FILTER_BACKSLASH', `event node "${nodeId}": \`where.${k}\`: ${problem}`);
|
|
960
|
+
return `${k} == ${jmesString(String(v))}`;
|
|
961
|
+
});
|
|
962
|
+
}
|
|
919
963
|
function eventDetail(rc, sub, nodeId, opts, site) {
|
|
920
964
|
requireBindingPair(site, sub, eventTarget(sub));
|
|
921
965
|
const conn = resolveBinding(opts, sub.connection, 'connection', `event node "${nodeId}"`, eventTarget(sub));
|
|
@@ -976,14 +1020,7 @@ function eventDetail(rc, sub, nodeId, opts, site) {
|
|
|
976
1020
|
// subscription's own scope — the mandatory clause the platform AND-joins —
|
|
977
1021
|
// whereas a query or path parameter is part of the request that registers
|
|
978
1022
|
// the subscription, not a property of the events it matches.
|
|
979
|
-
const scopeClauses =
|
|
980
|
-
.filter(([, v]) => v !== undefined && v !== null && String(v) !== '')
|
|
981
|
-
.map(([k, v]) => {
|
|
982
|
-
const problem = jmesStringProblem(String(v));
|
|
983
|
-
if (problem)
|
|
984
|
-
throw new CompileRefusal('EVENT_FILTER_BACKSLASH', `event node "${nodeId}": \`where.${k}\`: ${problem}`);
|
|
985
|
-
return `${k} == ${jmesString(String(v))}`;
|
|
986
|
-
});
|
|
1023
|
+
const scopeClauses = eventScopeClauses(eventParameters, nodeId);
|
|
987
1024
|
// Each authored filter is read structurally (which operator, which value) and
|
|
988
1025
|
// lowered with the designer's own grammar — see `event-filters.ts` for the
|
|
989
1026
|
// measured table.
|
|
@@ -1499,6 +1536,21 @@ function terminateOutputs(scope) {
|
|
|
1499
1536
|
}
|
|
1500
1537
|
return outs;
|
|
1501
1538
|
}
|
|
1539
|
+
/**
|
|
1540
|
+
* A step or entry point named `start` in a scope where `$vars.start` is
|
|
1541
|
+
* rewritten to the scope's start node (#1518): the root while `.triggerId()`
|
|
1542
|
+
* renames the trigger (`renamedTrigger`), or any subflow body (its start node
|
|
1543
|
+
* is `<caller>Start`). The rewrite would point the node's own readers at that
|
|
1544
|
+
* start node, so the name is refused instead. A step-level refusal: `check`
|
|
1545
|
+
* reports it on the step (or entry point), so the message names no scope.
|
|
1546
|
+
*/
|
|
1547
|
+
function startReadRefusal(what, renamedTrigger, code = 'STEP_ID_COLLISION') {
|
|
1548
|
+
const owner = renamedTrigger !== undefined
|
|
1549
|
+
? `the trigger, which .triggerId("${renamedTrigger}") renamed: compile rewrites \`$vars.start\` to \`$vars.${renamedTrigger}\``
|
|
1550
|
+
: "this subflow body's own start node: compile rewrites `$vars.start` to it";
|
|
1551
|
+
return new CompileRefusal(code, `[${code}] ${what}: \`$vars.start\` (what \`input()\` reads) names ${owner}, so reads of `
|
|
1552
|
+
+ `${what} would go there. Give it another name.`);
|
|
1553
|
+
}
|
|
1502
1554
|
/**
|
|
1503
1555
|
* Rewrite `$vars.<step>` references through a scope's rename map.
|
|
1504
1556
|
*
|
|
@@ -1716,6 +1768,13 @@ function serializeFlow(built, opts) {
|
|
|
1716
1768
|
* placeholder check exempts them.
|
|
1717
1769
|
*/
|
|
1718
1770
|
const unboundDrafts = new Set();
|
|
1771
|
+
/**
|
|
1772
|
+
* The connection each collect-mode stand-in was bound to, by node id: a node
|
|
1773
|
+
* refused only for want of a library (`LibraryRequiredRefusal`) has no
|
|
1774
|
+
* `detail` to read, so the file-wide connection rule (`connectionConnectors`)
|
|
1775
|
+
* is handed it here. Empty outside collect mode.
|
|
1776
|
+
*/
|
|
1777
|
+
const standInConnections = new Map();
|
|
1719
1778
|
/**
|
|
1720
1779
|
* RESOURCE bindings collected while emitting, keyed by binding id — `resource:
|
|
1721
1780
|
* 'process'` for the rpa family, `resource: 'queue'` for the queue family.
|
|
@@ -1877,9 +1936,16 @@ function serializeFlow(built, opts) {
|
|
|
1877
1936
|
// trigger node's default id. When the flow renames the trigger, register that
|
|
1878
1937
|
// rename so the SAME pass that rewrites step-name references rewrites these
|
|
1879
1938
|
// too, rather than teaching every call site about the trigger.
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1939
|
+
//
|
|
1940
|
+
// That rewrite cannot tell an `input()` read from a read of a node that is
|
|
1941
|
+
// really named `start` (`entryInput('start', 'x')` and `$vars.start.output.x`
|
|
1942
|
+
// in a step's code are the same text), so while the trigger is renamed the
|
|
1943
|
+
// name `start` is the trigger's: a step or an entry point that takes it is
|
|
1944
|
+
// refused (`startReadRefusal`), never rewritten to point at the trigger. A
|
|
1945
|
+
// subflow body renames `start` the same way, so its steps are held to it too.
|
|
1946
|
+
const renamedTrigger = built.triggerId && built.triggerId !== 'start' ? built.triggerId : undefined;
|
|
1947
|
+
if (renamedTrigger)
|
|
1948
|
+
root.rename.nodeIds.set('start', [renamedTrigger]);
|
|
1883
1949
|
// Every node id emitted anywhere in the file. `start` is taken before
|
|
1884
1950
|
// anything else: the root trigger's id is fixed, so a step named like the
|
|
1885
1951
|
// trigger is refused (claimStepIds).
|
|
@@ -1984,7 +2050,9 @@ function serializeFlow(built, opts) {
|
|
|
1984
2050
|
* thrown before any node is emitted). Renaming the second to `x2` left
|
|
1985
2051
|
* `.stepToRef('x')` and `$vars.x` pointing at the first, with no word said.
|
|
1986
2052
|
* - In the flow itself, a step named like the trigger is refused the same
|
|
1987
|
-
* way (STEP_ID_COLLISION).
|
|
2053
|
+
* way (STEP_ID_COLLISION). So is a step named `start` wherever
|
|
2054
|
+
* `$vars.start` is rewritten to a start node: the flow while `.triggerId()`
|
|
2055
|
+
* renames the trigger, and every subflow body (#1518, `startReadRefusal`).
|
|
1988
2056
|
* - A subflow body whose ids are already taken (a second copy of the same
|
|
1989
2057
|
* child, or a child step sharing a name with a caller's step) is the one
|
|
1990
2058
|
* place ids move: the whole copy is prefixed with the calling step's name,
|
|
@@ -2019,6 +2087,10 @@ function serializeFlow(built, opts) {
|
|
|
2019
2087
|
// A subflow copy's named Ends (`alsoIds`) decide the prefix with its steps (#1253).
|
|
2020
2088
|
const prefix = copyPrefix !== undefined && [...seen.keys(), ...alsoIds].some((id) => takenIds.has(id)) ? copyPrefix : '';
|
|
2021
2089
|
for (const [safe, n] of seen) {
|
|
2090
|
+
// `$vars.start` names this scope's start node, not a step (see `renamedTrigger`).
|
|
2091
|
+
if (safe === 'start' && (copyPrefix !== undefined || renamedTrigger)) {
|
|
2092
|
+
refuseOn(scope, n, startReadRefusal(`step "${n}"`, copyPrefix !== undefined ? undefined : renamedTrigger));
|
|
2093
|
+
}
|
|
2022
2094
|
if (!prefix && takenIds.has(safe)) {
|
|
2023
2095
|
throw new CompileRefusal('STEP_ID_COLLISION', `${where}: [STEP_ID_COLLISION] step "${n}" has the trigger's node id "${safe}", and compile will not `
|
|
2024
2096
|
+ `rename it "${safe}2". Rename the step.`);
|
|
@@ -2244,6 +2316,34 @@ function serializeFlow(built, opts) {
|
|
|
2244
2316
|
|| scope.pendingEdges.some((p) => p.from.node === node && isOutcome(p.from.port));
|
|
2245
2317
|
return tails.filter((t) => capsOpenTail.has(t.node) && !hasOutcomeEdge(t.node));
|
|
2246
2318
|
}
|
|
2319
|
+
/**
|
|
2320
|
+
* A subflow body is started by its caller, through the one manual Start node
|
|
2321
|
+
* `emitSubflowBodyIn` writes. So a child's own way of starting has nowhere to
|
|
2322
|
+
* go in the `.flow`, and writing the body without it would silently drop what
|
|
2323
|
+
* the author wrote (#1067): a `.trigger(scheduled(…))` would never fire, and an
|
|
2324
|
+
* `.entryPoint()` root and its steps would vanish. Both are refused.
|
|
2325
|
+
* `.trigger(manual(), { label, version })` is allowed: it names the child's
|
|
2326
|
+
* Start node (#1050), and it is the form decompile writes for a renamed one.
|
|
2327
|
+
*/
|
|
2328
|
+
function refuseChildRoots(child, step) {
|
|
2329
|
+
// `subflow(undefined, …)` is `check`'s SUBFLOW_NO_CHILD.
|
|
2330
|
+
if (!child || !Array.isArray(child.steps))
|
|
2331
|
+
return;
|
|
2332
|
+
const kind = child.trigger?.kind;
|
|
2333
|
+
if (child.trigger !== undefined && kind !== 'manual') {
|
|
2334
|
+
const noun = kind === 'scheduled' ? 'schedule' : kind === 'event' ? 'event subscription' : 'trigger';
|
|
2335
|
+
throw new CompileRefusal('SUBFLOW_CHILD_TRIGGER', `Subflow "${step}" runs a flow with its own \`.trigger(…)\`. A subflow is started by its caller, never by a `
|
|
2336
|
+
+ `trigger of its own — the ${noun} would be dropped. Remove the .trigger() from "${child.id}" `
|
|
2337
|
+
+ `(\`.trigger(manual(), { label })\` is allowed, to name the child's start node).`);
|
|
2338
|
+
}
|
|
2339
|
+
const roots = child.entryPoints ?? [];
|
|
2340
|
+
if (roots.length > 0) {
|
|
2341
|
+
throw new CompileRefusal('SUBFLOW_CHILD_ENTRY_POINT', `Subflow "${step}" runs a flow with ${roots.length === 1 ? 'an entry point' : 'entry points'} `
|
|
2342
|
+
+ `(${roots.map((r) => `"${r.id}"`).join(', ')}). A subflow has one root, its caller, so the entry `
|
|
2343
|
+
+ `${roots.length === 1 ? 'point and its steps' : 'points and their steps'} would be dropped. Call a flow `
|
|
2344
|
+
+ `without .entryPoint(), or move each entry point's steps into a flow of its own.`);
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2247
2347
|
/**
|
|
2248
2348
|
* Emit a child flow into its own scope and register it under the calling
|
|
2249
2349
|
* node's id — that key is how the format names a subflow body, and how
|
|
@@ -2252,7 +2352,7 @@ function serializeFlow(built, opts) {
|
|
|
2252
2352
|
* The child gets its own manual Start node (a subflow always starts manually
|
|
2253
2353
|
* — nothing schedules a subflow; its caller is the trigger) and its own
|
|
2254
2354
|
* variables. A child's `.trigger(manual(), { label, version })` sets that
|
|
2255
|
-
* node's canvas label and exact version; `
|
|
2355
|
+
* node's canvas label and exact version; `refuseChildRoots` refuses any other kind.
|
|
2256
2356
|
* Every `in` variable carries `triggerNodeId` pointing at that
|
|
2257
2357
|
* Start: it is what binds the caller's value, and omitting it is the single
|
|
2258
2358
|
* defect that makes a subflow validate clean and then fault at run time with
|
|
@@ -2803,8 +2903,9 @@ function serializeFlow(built, opts) {
|
|
|
2803
2903
|
}
|
|
2804
2904
|
// A type that owns a family of names (`typeNamePrefix`) is placed under the
|
|
2805
2905
|
// name its definition carries — `uipath.core.function.<key>`, not the prefix.
|
|
2806
|
-
// The bare prefix is
|
|
2807
|
-
//
|
|
2906
|
+
// The bare prefix is a name the type owns, so it is not an internal error
|
|
2907
|
+
// here; a type refuses a blank key itself when that is what builds it (the
|
|
2908
|
+
// process family's `*_NO_KEY`, nodes/process/flow/refusals.ts).
|
|
2808
2909
|
const prefix = entry.type.typeNamePrefix;
|
|
2809
2910
|
const nodeType = prefix !== undefined ? def?.nodeType : impl.typeName;
|
|
2810
2911
|
if (prefix !== undefined && (typeof nodeType !== 'string' || !nodeType.startsWith(prefix)
|
|
@@ -2889,6 +2990,43 @@ function serializeFlow(built, opts) {
|
|
|
2889
2990
|
throw refusal;
|
|
2890
2991
|
record(refusal, stepName, scope.stepNodeId.get(stepName) ?? scope.pending.get(stepName));
|
|
2891
2992
|
}
|
|
2993
|
+
/**
|
|
2994
|
+
* Refuse a `.switch()` case the node cannot hold as written (#1518). Each
|
|
2995
|
+
* case becomes one `{ id, expression }` row and one `case-<id>` port, so:
|
|
2996
|
+
* - SWITCH_CASE_FORM: a case needs exactly one of `value` (compared with
|
|
2997
|
+
* `on`) and `when` (its own condition). With both, only `when` would be
|
|
2998
|
+
* written and the value dropped; a `value` with no `on` would be written as
|
|
2999
|
+
* `undefined === 1`, and a case with neither as `undefined === undefined`,
|
|
3000
|
+
* which is always taken.
|
|
3001
|
+
* - SWITCH_CASE_ID: an id must be a non-empty string, and one per case. Two
|
|
3002
|
+
* cases on one id (an explicit `case_2` beside the positional one, #1130)
|
|
3003
|
+
* would share one `case-case_2` port, edges to both arms; a blank or
|
|
3004
|
+
* non-string id writes a `case-` / `case-5` port.
|
|
3005
|
+
* In collect mode each one is reported on the switch, and the node is still
|
|
3006
|
+
* written as authored, so the arms are judged.
|
|
3007
|
+
*/
|
|
3008
|
+
function refuseSwitchCases(scope, step) {
|
|
3009
|
+
const s = step.name;
|
|
3010
|
+
const seenIds = new Set();
|
|
3011
|
+
step.cases.forEach((c, i) => {
|
|
3012
|
+
const hasValue = c.value !== undefined;
|
|
3013
|
+
const hasWhen = c.when !== undefined;
|
|
3014
|
+
if (hasValue === hasWhen || (hasValue && !step.on)) {
|
|
3015
|
+
refuseOn(scope, s, new CompileRefusal('SWITCH_CASE_FORM', hasValue && hasWhen
|
|
3016
|
+
? `Switch "${s}" case ${i + 1} has both \`value\` and \`when\`. Give it one: \`value\` is compared with \`on\`, \`when\` is the case's own condition.`
|
|
3017
|
+
: hasValue
|
|
3018
|
+
? `Switch "${s}" case ${i + 1} has a \`value\` but the switch has no \`on\` to compare it with. Pass \`on\`, or give the case a \`when\` condition.`
|
|
3019
|
+
: `Switch "${s}" case ${i + 1} has neither \`value\` nor \`when\`.`));
|
|
3020
|
+
}
|
|
3021
|
+
const caseId = c.id ?? `case_${i + 1}`;
|
|
3022
|
+
if (typeof caseId !== 'string' || caseId === '' || seenIds.has(caseId)) {
|
|
3023
|
+
refuseOn(scope, s, new CompileRefusal('SWITCH_CASE_ID', typeof caseId !== 'string' || caseId === ''
|
|
3024
|
+
? `Switch "${s}" case ${i + 1} has an id that is not a non-empty string. Leave \`id\` out for the positional case_<n>.`
|
|
3025
|
+
: `Switch "${s}" has two cases with the id "${caseId}", so both would leave from one 'case-${caseId}' port. Give one a different \`id\`.`));
|
|
3026
|
+
}
|
|
3027
|
+
seenIds.add(String(caseId));
|
|
3028
|
+
});
|
|
3029
|
+
}
|
|
2892
3030
|
/** The step whose node `nodeId` is, in `scope`. */
|
|
2893
3031
|
function stepOfNode(scope, nodeId) {
|
|
2894
3032
|
for (const [name, id] of scope.stepNodeId)
|
|
@@ -2911,6 +3049,8 @@ function serializeFlow(built, opts) {
|
|
|
2911
3049
|
catch (error) {
|
|
2912
3050
|
const refusal = stepRefusal(error);
|
|
2913
3051
|
record(refusal, name, id);
|
|
3052
|
+
if (refusal instanceof LibraryRequiredRefusal && refusal.connection)
|
|
3053
|
+
standInConnections.set(id, refusal.connection);
|
|
2914
3054
|
root.nodes.length = mark.nodes;
|
|
2915
3055
|
for (const key of [...resourceBindings.keys()])
|
|
2916
3056
|
if (!mark.resources.has(key))
|
|
@@ -2947,6 +3087,8 @@ function serializeFlow(built, opts) {
|
|
|
2947
3087
|
const refusal = stepRefusal(error);
|
|
2948
3088
|
const id = scope.stepNodeId.get(step.name) ?? stepUid(scope, step.name);
|
|
2949
3089
|
record(refusal, step.name, id);
|
|
3090
|
+
if (refusal instanceof LibraryRequiredRefusal && refusal.connection)
|
|
3091
|
+
standInConnections.set(id, refusal.connection);
|
|
2950
3092
|
scope.nodes.length = mark.nodes;
|
|
2951
3093
|
scope.edges.length = mark.edges;
|
|
2952
3094
|
scope.pendingEdges.length = mark.pendingEdges;
|
|
@@ -3026,6 +3168,7 @@ function serializeFlow(built, opts) {
|
|
|
3026
3168
|
if (registered)
|
|
3027
3169
|
return emitRegistered(registered, step, tails, scope, parentId);
|
|
3028
3170
|
if (spec.kind === 'subflow') {
|
|
3171
|
+
refuseChildRoots(spec.child, step.name);
|
|
3029
3172
|
const id = stepUid(scope, step.name);
|
|
3030
3173
|
// `subflows` is ONE flat map for the whole file, keyed by the calling
|
|
3031
3174
|
// node's id. `stepUid` draws from the file-wide allocator, including in
|
|
@@ -3387,6 +3530,7 @@ function serializeFlow(built, opts) {
|
|
|
3387
3530
|
// the runtime — so no `=js:` prefix, same as a decision's `expression`.
|
|
3388
3531
|
const id = stepUid(scope, step.name);
|
|
3389
3532
|
const node = makeNode(NODE_TYPE.switch, id, step.options?.label ?? step.label ?? step.name, { parentId, requestedVersion: step.options?.version });
|
|
3533
|
+
refuseSwitchCases(scope, step);
|
|
3390
3534
|
// `id` is the author's when given (a decompiled switch keeps the
|
|
3391
3535
|
// canvas's `default-1`, …: merge keeps the original node, so the edges
|
|
3392
3536
|
// must leave from ITS handles), else positional (#1130).
|
|
@@ -3785,6 +3929,14 @@ function serializeFlow(built, opts) {
|
|
|
3785
3929
|
const firstShared = built.steps.find((st) => 'name' in st && st.kind !== 'return');
|
|
3786
3930
|
const sharedTarget = firstShared && 'name' in firstShared ? root.stepNodeId.get(firstShared.name) : undefined;
|
|
3787
3931
|
for (const ep of entryPoints) {
|
|
3932
|
+
if (ep.id === 'start' && renamedTrigger) {
|
|
3933
|
+
// Reported on the entry point; in collect mode it is still emitted (the
|
|
3934
|
+
// id `start` is free in the file), so its prefix is judged too.
|
|
3935
|
+
const refusal = startReadRefusal(`.entryPoint("${ep.id}")`, renamedTrigger, 'ENTRY_POINT_DUP_ID');
|
|
3936
|
+
if (!opts.collect)
|
|
3937
|
+
throw refusal;
|
|
3938
|
+
record(refusal, ep.id, ep.id);
|
|
3939
|
+
}
|
|
3788
3940
|
if (takenIds.has(ep.id)) {
|
|
3789
3941
|
throw new CompileRefusal('ENTRY_POINT_DUP_ID', `.entryPoint("${ep.id}"): the id collides with a step, the trigger, or another entry point.`);
|
|
3790
3942
|
}
|
|
@@ -3955,7 +4107,7 @@ function serializeFlow(built, opts) {
|
|
|
3955
4107
|
assertBindingPlaceholdersResolve(flow, unboundDrafts);
|
|
3956
4108
|
assertFileWideIdsUnique(flow);
|
|
3957
4109
|
assertConnectorConfigurationRestorable(flow);
|
|
3958
|
-
connectionConnectors(flow);
|
|
4110
|
+
connectionConnectors(flow, standInConnections);
|
|
3959
4111
|
return flow;
|
|
3960
4112
|
}
|
|
3961
4113
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.66.
|
|
3
|
+
"version": "6.66.8",
|
|
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": "4800f0ca4d2a58eed272d12640145fc039e43a16"
|
|
104
104
|
}
|