@uipath/maestro-builder-sdk 6.32.3 → 6.32.4
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/check.js +33 -0
- package/dist/serialize.js +116 -38
- package/package.json +2 -2
package/dist/check.js
CHANGED
|
@@ -51,6 +51,36 @@ export function check(built, opts = {}) {
|
|
|
51
51
|
}
|
|
52
52
|
return diags;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* A step's node id is its name with every character outside `[A-Za-z0-9_]`
|
|
56
|
+
* made `_`, and `compile` never renames one to make it unique (#1249). So two
|
|
57
|
+
* different names that give one id (`a b` and `a_b`), or a step of the flow
|
|
58
|
+
* itself named like its trigger, are an error here, as the same name twice is
|
|
59
|
+
* DUP_STEP. `serialize` refuses both too, for the paths that skip `check`.
|
|
60
|
+
* A subflow's own start is the SDK's to name, so `trigger` is the flow's only.
|
|
61
|
+
*/
|
|
62
|
+
function checkStepIds(stepNames, trigger, diags) {
|
|
63
|
+
const byId = new Map();
|
|
64
|
+
for (const name of stepNames) {
|
|
65
|
+
const id = name.replace(/[^A-Za-z0-9_]/g, '_') || 'node';
|
|
66
|
+
const first = byId.get(id);
|
|
67
|
+
if (first !== undefined) {
|
|
68
|
+
diags.push({
|
|
69
|
+
level: 'error', code: 'STEP_ID_COLLISION', step: name,
|
|
70
|
+
message: `Steps "${first}" and "${name}" would both get node id "${id}". Give them names that differ in `
|
|
71
|
+
+ 'letters, digits or "_".',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else if (id === trigger) {
|
|
75
|
+
diags.push({
|
|
76
|
+
level: 'error', code: 'STEP_ID_COLLISION', step: name,
|
|
77
|
+
message: `Step "${name}" has the trigger's node id "${id}". Rename the step.`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (first === undefined)
|
|
81
|
+
byId.set(id, name);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
54
84
|
/**
|
|
55
85
|
* `ancestors` is the chain of child flows currently being checked, innermost
|
|
56
86
|
* last — used to prefix a child's diagnostics with the step that runs it, and
|
|
@@ -898,6 +928,9 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
898
928
|
}
|
|
899
929
|
walk(ep.steps);
|
|
900
930
|
}
|
|
931
|
+
// After the entry-point loop, so prefix steps are in `stepNames`: serialize
|
|
932
|
+
// claims body and prefix step ids together (#1249).
|
|
933
|
+
checkStepIds(stepNames, ancestors.length === 0 ? triggerId : undefined, diags);
|
|
901
934
|
if (built.entryPoints?.length && !built.steps.some((st) => 'name' in st && st.kind !== 'return')) {
|
|
902
935
|
diags.push({
|
|
903
936
|
level: 'error', code: 'ENTRY_POINT_NO_SHARED_BODY',
|
package/dist/serialize.js
CHANGED
|
@@ -4166,9 +4166,9 @@ function terminateOutputs(scope) {
|
|
|
4166
4166
|
/**
|
|
4167
4167
|
* Rewrite `$vars.<step>` references through a scope's rename map.
|
|
4168
4168
|
*
|
|
4169
|
-
* A name maps to the
|
|
4170
|
-
*
|
|
4171
|
-
*
|
|
4169
|
+
* A name maps to the id claimed for it (a list only for the type's sake: a
|
|
4170
|
+
* scope with two steps of one name is refused before anything renders, #1249);
|
|
4171
|
+
* a reference resolves to the first.
|
|
4172
4172
|
*/
|
|
4173
4173
|
function renameRefs(text, rename) {
|
|
4174
4174
|
if (rename.nodeIds.size === 0 && rename.errorEnvelopes.size === 0 && !rename.vars?.size)
|
|
@@ -4189,29 +4189,38 @@ function renameRefs(text, rename) {
|
|
|
4189
4189
|
return `$vars.${nodeId}.${envelope}`;
|
|
4190
4190
|
}));
|
|
4191
4191
|
}
|
|
4192
|
-
/**
|
|
4193
|
-
|
|
4192
|
+
/**
|
|
4193
|
+
* Every step name a flow declares in its own scope (not its children's),
|
|
4194
|
+
* port paths (`.stepToList`, `.onError`) included: their steps are nodes of
|
|
4195
|
+
* this scope too, so they need an id claimed with the rest.
|
|
4196
|
+
*/
|
|
4197
|
+
function stepNamesOf(steps, out = [], terminates) {
|
|
4194
4198
|
for (const s of steps) {
|
|
4195
4199
|
// `return` carries a synthetic `name` but creates no node named after it (an
|
|
4196
4200
|
// End id is claimed as `end`); `stepToRef` has no `name` at all (it is one edge).
|
|
4197
4201
|
if ('name' in s && s.kind !== 'return')
|
|
4198
4202
|
out.push(s.name);
|
|
4203
|
+
// How many `.terminate`s hold each name, so a clash gets the right remedy (#1239).
|
|
4204
|
+
if (s.kind === 'terminate' && terminates)
|
|
4205
|
+
terminates.set(s.name, (terminates.get(s.name) ?? 0) + 1);
|
|
4206
|
+
if (s.kind === 'stepToList')
|
|
4207
|
+
stepNamesOf(s.body, out, terminates);
|
|
4199
4208
|
if (s.kind === 'branch') {
|
|
4200
|
-
stepNamesOf(s.then, out);
|
|
4201
|
-
stepNamesOf(s.otherwise, out);
|
|
4209
|
+
stepNamesOf(s.then, out, terminates);
|
|
4210
|
+
stepNamesOf(s.otherwise, out, terminates);
|
|
4202
4211
|
}
|
|
4203
4212
|
else if (s.kind === 'switch') {
|
|
4204
|
-
s.cases.forEach((c) => stepNamesOf(c.body, out));
|
|
4205
|
-
stepNamesOf(s.default ?? [], out);
|
|
4213
|
+
s.cases.forEach((c) => stepNamesOf(c.body, out, terminates));
|
|
4214
|
+
stepNamesOf(s.default ?? [], out, terminates);
|
|
4206
4215
|
}
|
|
4207
4216
|
else if (s.kind === 'stepSwitch')
|
|
4208
|
-
s.cases.forEach((c) => stepNamesOf(c.body, out));
|
|
4217
|
+
s.cases.forEach((c) => stepNamesOf(c.body, out, terminates));
|
|
4209
4218
|
else if (s.kind === 'parallel')
|
|
4210
|
-
s.arms.forEach((a) => stepNamesOf(a, out));
|
|
4219
|
+
s.arms.forEach((a) => stepNamesOf(a, out, terminates));
|
|
4211
4220
|
else if (s.kind === 'loop')
|
|
4212
|
-
stepNamesOf(s.body, out);
|
|
4221
|
+
stepNamesOf(s.body, out, terminates);
|
|
4213
4222
|
else if (s.kind === 'doWhile')
|
|
4214
|
-
stepNamesOf(s.body, out);
|
|
4223
|
+
stepNamesOf(s.body, out, terminates);
|
|
4215
4224
|
}
|
|
4216
4225
|
return out;
|
|
4217
4226
|
}
|
|
@@ -4412,19 +4421,22 @@ export function serialize(built, opts = {}) {
|
|
|
4412
4421
|
root.rename.nodeIds.set('start', [built.triggerId]);
|
|
4413
4422
|
}
|
|
4414
4423
|
// Every node id emitted anywhere in the file. `start` is taken before
|
|
4415
|
-
// anything else: the root trigger's id is fixed, so a step named
|
|
4416
|
-
//
|
|
4424
|
+
// anything else: the root trigger's id is fixed, so a step named like the
|
|
4425
|
+
// trigger is refused (claimStepIds).
|
|
4417
4426
|
const takenIds = new Set([built.triggerId ?? 'start']);
|
|
4418
4427
|
/** Per scope, each named `.return` End emitted so far and its content. */
|
|
4419
4428
|
const namedEnds = new Map();
|
|
4420
4429
|
/** Per scope, the names a `.terminate` claimed: which remedy a later clash gets (#1239). */
|
|
4421
4430
|
const terminateNames = new Map();
|
|
4422
4431
|
let edgeSeq = 0;
|
|
4423
|
-
/**
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4432
|
+
/**
|
|
4433
|
+
* Claim a globally unique node id for a node the SDK names itself: an End,
|
|
4434
|
+
* a subflow's Start, an agent's context or tool node, an error-port End.
|
|
4435
|
+
* Those ids are the SDK's to choose, so a clash is settled by `claimId`'s
|
|
4436
|
+
* numeric suffix (`end`, `end2`, …). A step's id never comes from here; see
|
|
4437
|
+
* `stepUid`.
|
|
4438
|
+
*/
|
|
4439
|
+
function uid(_scope, base) {
|
|
4428
4440
|
return claimId(base);
|
|
4429
4441
|
}
|
|
4430
4442
|
function claimId(base) {
|
|
@@ -4499,18 +4511,82 @@ export function serialize(built, opts = {}) {
|
|
|
4499
4511
|
}
|
|
4500
4512
|
}
|
|
4501
4513
|
/**
|
|
4502
|
-
*
|
|
4514
|
+
* Claim the node ids for every step of one scope, BEFORE any node of the
|
|
4515
|
+
* scope (or of a subflow it calls) is emitted, so an author's step name
|
|
4516
|
+
* always gets its id ahead of the ids the SDK makes up (#1249).
|
|
4517
|
+
*
|
|
4518
|
+
* A step's id is its name: the author's name, or a decompiled file's own
|
|
4519
|
+
* node id. It is never quietly renamed:
|
|
4520
|
+
*
|
|
4521
|
+
* - Two steps whose names give the same id (`.step('x')` twice, or `a b`
|
|
4522
|
+
* beside `a_b`) are refused. `check` reports them as DUP_STEP /
|
|
4523
|
+
* STEP_ID_COLLISION; this is the backstop for every path that skips it
|
|
4524
|
+
* (`compile --no-check`, the draft-tolerant merge compile, a direct
|
|
4525
|
+
* `serialize()`). Renaming the second to `x2` left `.stepToRef('x')` and
|
|
4526
|
+
* `$vars.x` pointing at the first, with no word said.
|
|
4527
|
+
* - In the flow itself, a step named like the trigger is refused the same
|
|
4528
|
+
* way (STEP_ID_COLLISION).
|
|
4529
|
+
* - A subflow body whose ids are already taken (a second copy of the same
|
|
4530
|
+
* child, or a child step sharing a name with a caller's step) is the one
|
|
4531
|
+
* place ids move: the whole copy is prefixed with the calling step's name,
|
|
4532
|
+
* and `rename` points its expressions at the prefixed ids.
|
|
4533
|
+
*/
|
|
4534
|
+
function claimStepIds(scope, names, where, copyPrefix, alsoIds = [], terminates = new Map()) {
|
|
4535
|
+
const seen = new Map();
|
|
4536
|
+
for (const n of names) {
|
|
4537
|
+
const safe = n.replace(/[^A-Za-z0-9_]/g, '_') || 'node';
|
|
4538
|
+
const first = seen.get(safe);
|
|
4539
|
+
if (first !== undefined) {
|
|
4540
|
+
// A name a `.terminate` holds gets the same words `check` gives (#1239):
|
|
4541
|
+
// two Terminates -> end the other paths at one; a step and a Terminate
|
|
4542
|
+
// -> rename one.
|
|
4543
|
+
const t = first === n ? (terminates.get(n) ?? 0) : 0;
|
|
4544
|
+
throw new Error(first !== n
|
|
4545
|
+
? `${where}: [STEP_ID_COLLISION] steps "${first}" and "${n}" would both get node id "${safe}". Give them `
|
|
4546
|
+
+ 'names that differ in letters, digits or "_".'
|
|
4547
|
+
: t >= 2 ? `${where}: [DUP_STEP] ${terminateTwiceMessage(n)}`
|
|
4548
|
+
: t === 1 ? `${where}: [DUP_STEP] ${terminateStepClashMessage(n)}`
|
|
4549
|
+
: `${where}: [DUP_STEP] two steps are named "${n}". A step name is its node's id and \`.stepToRef\` / `
|
|
4550
|
+
+ `\`$vars\` name it, so compile will not rename the second one "${n}2". Give each step its own name; to `
|
|
4551
|
+
+ `send several paths to one step, keep one and end the others with .stepToRef('${n}').`);
|
|
4552
|
+
}
|
|
4553
|
+
seen.set(safe, n);
|
|
4554
|
+
}
|
|
4555
|
+
// A subflow copy's named Ends (`alsoIds`) decide the prefix with its steps (#1253).
|
|
4556
|
+
const prefix = copyPrefix !== undefined && [...seen.keys(), ...alsoIds].some((id) => takenIds.has(id)) ? copyPrefix : '';
|
|
4557
|
+
for (const [safe, n] of seen) {
|
|
4558
|
+
if (!prefix && takenIds.has(safe)) {
|
|
4559
|
+
throw new Error(`${where}: [STEP_ID_COLLISION] step "${n}" has the trigger's node id "${safe}", and compile will not `
|
|
4560
|
+
+ `rename it "${safe}2". Rename the step.`);
|
|
4561
|
+
}
|
|
4562
|
+
const id = claimId(prefix + safe);
|
|
4563
|
+
if (copyPrefix !== undefined)
|
|
4564
|
+
(scope.rename.nodeIds.get(n) ?? scope.rename.nodeIds.set(n, []).get(n)).push(id);
|
|
4565
|
+
scope.pending.set(n, id);
|
|
4566
|
+
}
|
|
4567
|
+
return prefix;
|
|
4568
|
+
}
|
|
4569
|
+
/**
|
|
4570
|
+
* The node id of an author's step: the one `claimStepIds` claimed for it,
|
|
4571
|
+
* recorded so `.stepToRef('<step>')` can find it.
|
|
4503
4572
|
*
|
|
4504
4573
|
* `.stepToRef('<step>')` names a step, and the id it was emitted under is not
|
|
4505
|
-
*
|
|
4506
|
-
*
|
|
4507
|
-
*
|
|
4508
|
-
* — the derived-names lesson (G-20), one layer in.
|
|
4574
|
+
* always the name: a subflow COPY's steps are prefixed. So the mapping is
|
|
4575
|
+
* recorded where it is decided rather than reconstructed later — the
|
|
4576
|
+
* derived-names lesson (G-20), one layer in.
|
|
4509
4577
|
*/
|
|
4510
4578
|
function stepUid(scope, stepName) {
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4579
|
+
// Unreachable after `claimStepIds`, which refuses a repeated name first;
|
|
4580
|
+
// kept so no future emission path can bring back the silent `<name>2`.
|
|
4581
|
+
if (scope.stepNodeId.has(stepName)) {
|
|
4582
|
+
throw new Error(`step "${stepName}" is emitted twice in one scope (internal: DUP_STEP reached stepUid).`);
|
|
4583
|
+
}
|
|
4584
|
+
const id = scope.pending.get(stepName);
|
|
4585
|
+
if (id === undefined) {
|
|
4586
|
+
throw new Error(`step "${stepName}" has no claimed node id (internal: stepNamesOf missed a step kind).`);
|
|
4587
|
+
}
|
|
4588
|
+
scope.pending.delete(stepName);
|
|
4589
|
+
scope.stepNodeId.set(stepName, id);
|
|
4514
4590
|
return id;
|
|
4515
4591
|
}
|
|
4516
4592
|
/**
|
|
@@ -4680,14 +4756,9 @@ export function serialize(built, opts = {}) {
|
|
|
4680
4756
|
// namespace the `subflows` map keeps.
|
|
4681
4757
|
// A child's named Ends belong to the copy too, so they decide the prefix
|
|
4682
4758
|
// with its steps and move with it (#1253).
|
|
4683
|
-
const names = stepNamesOf(child.steps);
|
|
4684
4759
|
const childNodes = namedNodesOf(child.steps);
|
|
4685
|
-
const
|
|
4686
|
-
|
|
4687
|
-
const id = claimId(prefix + n);
|
|
4688
|
-
(scope.rename.nodeIds.get(n) ?? scope.rename.nodeIds.set(n, []).get(n)).push(id);
|
|
4689
|
-
(scope.pending.get(n) ?? scope.pending.set(n, []).get(n)).push(id);
|
|
4690
|
-
}
|
|
4760
|
+
const childTerminates = new Map();
|
|
4761
|
+
const prefix = claimStepIds(scope, stepNamesOf(child.steps, [], childTerminates), `subflow "${nodeId}"`, `${nodeId}_`, childNodes.ends.map(safeNodeId), childTerminates);
|
|
4691
4762
|
claimEndIds(scope, childNodes, `subflow "${nodeId}"`, [], prefix);
|
|
4692
4763
|
const startId = uid(scope, `${nodeId}Start`);
|
|
4693
4764
|
// A CHILD's inputs are published as the child's own start node, whose id is
|
|
@@ -6653,10 +6724,17 @@ export function serialize(built, opts = {}) {
|
|
|
6653
6724
|
}
|
|
6654
6725
|
return tails;
|
|
6655
6726
|
}
|
|
6656
|
-
// The flow's
|
|
6657
|
-
// root scope) are claimed before anything
|
|
6658
|
-
//
|
|
6727
|
+
// The flow's own step ids (entry-point prefixes included: they emit into the
|
|
6728
|
+
// root scope) are claimed before anything else but the trigger, so a subflow
|
|
6729
|
+
// body or an SDK-made node that shares a step's name is the one that moves.
|
|
6730
|
+
// Its named Ends are claimed right after, before anything is emitted, so an
|
|
6731
|
+
// id the SDK makes up is the one that moves (#1253).
|
|
6659
6732
|
{
|
|
6733
|
+
const rootTerminates = new Map();
|
|
6734
|
+
const rootSteps = stepNamesOf(built.steps, [], rootTerminates);
|
|
6735
|
+
for (const ep of built.entryPoints ?? [])
|
|
6736
|
+
stepNamesOf(ep.steps, rootSteps, rootTerminates);
|
|
6737
|
+
claimStepIds(root, rootSteps, `flow "${built.id}"`, undefined, [], rootTerminates);
|
|
6660
6738
|
const seenEnds = new Set();
|
|
6661
6739
|
const rootNodes = namedNodesOf(built.steps, undefined, seenEnds);
|
|
6662
6740
|
for (const ep of built.entryPoints ?? [])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.32.
|
|
3
|
+
"version": "6.32.4",
|
|
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",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"@types/node": "^22.7.0",
|
|
94
94
|
"esbuild": "^0.28.1"
|
|
95
95
|
},
|
|
96
|
-
"gitref": "
|
|
96
|
+
"gitref": "9a7e5f98ca054b05f74ac655b8725bf4e3b50e89"
|
|
97
97
|
}
|