@uipath/maestro-builder-sdk 6.44.1 → 6.44.3
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 +2 -1
- package/dist/core/vars-read.d.ts +6 -0
- package/dist/core/vars-read.js +6 -0
- package/dist/decompile.js +37 -3
- package/dist/flow-node-type.d.ts +2 -0
- package/dist/nodes/http/flow/node-type.js +22 -1
- package/dist/nodes/process/flow/node-type.js +17 -8
- package/package.json +2 -2
package/dist/check.js
CHANGED
|
@@ -22,6 +22,7 @@ import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
|
|
|
22
22
|
import { compareSchemaVersions, schemaVersionRefusal } from './schema-version.js';
|
|
23
23
|
import { planFlowGlobals, planSharedInputs, sharedInputRoots } from './flow-variables.js';
|
|
24
24
|
import { planOutputBacking } from './flow-output-backing.js';
|
|
25
|
+
import { VARS_READ_RE } from './core/vars-read.js';
|
|
25
26
|
import { terminateStepClashMessage, terminateTwiceMessage } from './flow-terminate-names.js';
|
|
26
27
|
import { endContentKey } from './flow-end-content.js';
|
|
27
28
|
import { FLOW_NODE_TYPES } from './flow-node-registry.js';
|
|
@@ -1056,7 +1057,7 @@ function checkFlow(built, ancestors, opts = {}, ledger = newResourceIdLedger())
|
|
|
1056
1057
|
// subflow read, where the value lives one level deeper
|
|
1057
1058
|
// (`$vars.<call>.output.<childOutput>`). Every other rule reads only the
|
|
1058
1059
|
// first two segments, exactly as before.
|
|
1059
|
-
for (const m of js.matchAll(
|
|
1060
|
+
for (const m of js.matchAll(VARS_READ_RE)) {
|
|
1060
1061
|
const [, name, field] = m;
|
|
1061
1062
|
// `?.` reads the same path as `.`, and the rules below parse the tail as `.a.b`.
|
|
1062
1063
|
const rest = m[3].replace(/\?\./g, '.');
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A dotted `$vars` read: `$vars.<name>`, an optional `.<field>`, then the dotted
|
|
3
|
+
* `rest`, each dot optionally `?.`. It stops at the first bracket. Check and
|
|
4
|
+
* decompile both scan with it, so decompile declares the body fields check reads.
|
|
5
|
+
*/
|
|
6
|
+
export declare const VARS_READ_RE: RegExp;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A dotted `$vars` read: `$vars.<name>`, an optional `.<field>`, then the dotted
|
|
3
|
+
* `rest`, each dot optionally `?.`. It stops at the first bracket. Check and
|
|
4
|
+
* decompile both scan with it, so decompile declares the body fields check reads.
|
|
5
|
+
*/
|
|
6
|
+
export const VARS_READ_RE = /\$vars\.([A-Za-z0-9_]+)(?:\??\.([A-Za-z0-9_]+))?((?:\??\.[A-Za-z0-9_]+)*)/g;
|
package/dist/decompile.js
CHANGED
|
@@ -42,6 +42,7 @@ import { parseIxpProjectType } from './core/actions.js';
|
|
|
42
42
|
import { readFlowGlobals } from './flow-variables.js';
|
|
43
43
|
import { outputBackingGlobal, outputBackingName } from './flow-output-backing.js';
|
|
44
44
|
import { mapJsCode } from './core/js-code-spans.js';
|
|
45
|
+
import { VARS_READ_RE } from './core/vars-read.js';
|
|
45
46
|
import { missingBindingLabels } from './core/binding-messages.js';
|
|
46
47
|
import { prepareCommand } from './core/cli-spelling.js';
|
|
47
48
|
import { OUTCOME_HANDLE_NODE_TYPES } from './core/hitl-routing.js';
|
|
@@ -459,6 +460,30 @@ function emitValMap(m, imp, inputNames) {
|
|
|
459
460
|
*/
|
|
460
461
|
const ARTIFACT_PORTS = new Set(['tool', 'context', 'escalation', 'memory']);
|
|
461
462
|
// ─── Graph model ──────────────────────────────────────────────────────────────
|
|
463
|
+
/** An index right after a read: `[0]`, `[i]`, `?.["k"]`. */
|
|
464
|
+
const INDEX_NEXT_RE = /^\s*(?:\?\.)?\[/;
|
|
465
|
+
/** A read's tail when an index follows it, whatever the index: `.output.body.items[]`. */
|
|
466
|
+
const INDEX_MARK = '[]';
|
|
467
|
+
/** Every `$vars` read in `values`' strings, by id, with `?.` read as `.`. */
|
|
468
|
+
function scopeReads(values) {
|
|
469
|
+
const reads = new Map();
|
|
470
|
+
const visit = (v) => {
|
|
471
|
+
if (typeof v === 'string') {
|
|
472
|
+
for (const m of v.matchAll(VARS_READ_RE)) {
|
|
473
|
+
const [read, id, field, rest] = m;
|
|
474
|
+
const path = field === undefined ? '' : `.${field}${rest.replace(/\?\./g, '.')}`;
|
|
475
|
+
const indexed = INDEX_NEXT_RE.test(v.slice(m.index + read.length));
|
|
476
|
+
(reads.get(id) ?? reads.set(id, []).get(id)).push(indexed ? path + INDEX_MARK : path);
|
|
477
|
+
}
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (v && typeof v === 'object')
|
|
481
|
+
for (const x of Object.values(v))
|
|
482
|
+
visit(x);
|
|
483
|
+
};
|
|
484
|
+
visit(values);
|
|
485
|
+
return reads;
|
|
486
|
+
}
|
|
462
487
|
class Graph {
|
|
463
488
|
byId = new Map();
|
|
464
489
|
out = new Map();
|
|
@@ -474,8 +499,11 @@ class Graph {
|
|
|
474
499
|
*/
|
|
475
500
|
accounted = new Set();
|
|
476
501
|
edges;
|
|
477
|
-
|
|
502
|
+
variables;
|
|
503
|
+
reads;
|
|
504
|
+
constructor(nodes, edges, variables) {
|
|
478
505
|
this.edges = edges;
|
|
506
|
+
this.variables = variables;
|
|
479
507
|
for (const n of nodes)
|
|
480
508
|
this.byId.set(n.id, n);
|
|
481
509
|
for (const e of edges) {
|
|
@@ -483,6 +511,11 @@ class Graph {
|
|
|
483
511
|
(this.inc.get(e.targetNodeId) ?? this.inc.set(e.targetNodeId, []).get(e.targetNodeId)).push(e);
|
|
484
512
|
}
|
|
485
513
|
}
|
|
514
|
+
/** The tails this scope's inputs, outputs and updates read off `$vars.<id>`, e.g. `.output.body.current`. */
|
|
515
|
+
readsOf(id) {
|
|
516
|
+
this.reads ??= scopeReads([...[...this.byId.values()].flatMap((n) => [n.inputs, n.outputs]), this.variables?.variableUpdates]);
|
|
517
|
+
return this.reads.get(id) ?? [];
|
|
518
|
+
}
|
|
486
519
|
outEdges(id) {
|
|
487
520
|
return this.out.get(id) ?? [];
|
|
488
521
|
}
|
|
@@ -666,6 +699,7 @@ function liftRegistered(node, impl = registeredImpl(node), graph) {
|
|
|
666
699
|
absorb: (id, compiledId) => { runAbsorbed.set(id, compiledId); },
|
|
667
700
|
outPorts: () => (graph?.outEdges(node.id) ?? []).map((e) => e.sourcePort),
|
|
668
701
|
convergedFanOut: () => graph?.convergedFanOut(node.id) === true,
|
|
702
|
+
reads: () => graph?.readsOf(node.id) ?? [],
|
|
669
703
|
};
|
|
670
704
|
const spec = impl.deserialize(node, ctx);
|
|
671
705
|
return spec === undefined ? undefined : { impl, spec };
|
|
@@ -2556,7 +2590,7 @@ function readChildStartAsStart(child, startId) {
|
|
|
2556
2590
|
function emitChildFlowIn(name, child, trigger, ctx) {
|
|
2557
2591
|
const globals = readFlowGlobals(child.variables, runStrict);
|
|
2558
2592
|
const childCtx = {
|
|
2559
|
-
graph: new Graph(child.nodes ?? [], child.edges ?? []),
|
|
2593
|
+
graph: new Graph(child.nodes ?? [], child.edges ?? [], child.variables),
|
|
2560
2594
|
flow: child,
|
|
2561
2595
|
imp: ctx.imp,
|
|
2562
2596
|
inputNames: new Set(globals.filter((g) => g.direction === 'in').map((g) => g.name ?? g.id)),
|
|
@@ -2721,7 +2755,7 @@ export function decompile(flow, options = {}) {
|
|
|
2721
2755
|
}
|
|
2722
2756
|
runCarried = carriedPairs(flow);
|
|
2723
2757
|
const imp = new Imports();
|
|
2724
|
-
const graph = new Graph(flow.nodes ?? [], flow.edges ?? []);
|
|
2758
|
+
const graph = new Graph(flow.nodes ?? [], flow.edges ?? [], flow.variables);
|
|
2725
2759
|
const globals = readFlowGlobals(flow.variables, runStrict);
|
|
2726
2760
|
const inputNames = new Set(globals.filter((g) => g.direction === 'in').map((g) => g.name ?? g.id));
|
|
2727
2761
|
// Trigger-bound globals name the node they came from; fall back to the graph's
|
package/dist/flow-node-type.d.ts
CHANGED
|
@@ -281,6 +281,8 @@ export interface FlowDeserializeContext {
|
|
|
281
281
|
* the type's `exits()`, so it is `false` for any other node.
|
|
282
282
|
*/
|
|
283
283
|
convergedFanOut(): boolean;
|
|
284
|
+
/** The tails the node's scope reads off `$vars.<nodeId>`, e.g. `.output.body.current`, `.output.body.items[]` for an indexed read. */
|
|
285
|
+
reads(): readonly string[];
|
|
284
286
|
}
|
|
285
287
|
/** What `print` may ask of the decompiler. Every method returns source text. */
|
|
286
288
|
export interface FlowPrintContext {
|
|
@@ -245,6 +245,27 @@ function liftReturns(node) {
|
|
|
245
245
|
.map(([k, v]) => [k, v.type]);
|
|
246
246
|
return entries.length ? Object.fromEntries(entries) : undefined;
|
|
247
247
|
}
|
|
248
|
+
/** A read of a body field: the field, then whatever the read goes on to. */
|
|
249
|
+
const BODY_READ_RE = /^\.output\.body\.([A-Za-z0-9_]+)(.*)$/;
|
|
250
|
+
/**
|
|
251
|
+
* The `returns` a node with no body schema needs for the body fields its flow
|
|
252
|
+
* already reads, so the source decompile prints compiles. A field read further
|
|
253
|
+
* in (`body.current.time`) is an `object`; a field read whole is a `string`, the
|
|
254
|
+
* type the check suggests. Undefined when nothing reads the body.
|
|
255
|
+
*/
|
|
256
|
+
function returnsFromReads(reads) {
|
|
257
|
+
const fields = new Map();
|
|
258
|
+
for (const read of reads) {
|
|
259
|
+
const m = BODY_READ_RE.exec(read);
|
|
260
|
+
if (!m)
|
|
261
|
+
continue;
|
|
262
|
+
if (m[2] !== '')
|
|
263
|
+
fields.set(m[1], 'object');
|
|
264
|
+
else if (!fields.has(m[1]))
|
|
265
|
+
fields.set(m[1], 'string');
|
|
266
|
+
}
|
|
267
|
+
return fields.size ? Object.fromEntries(fields) : undefined;
|
|
268
|
+
}
|
|
248
269
|
/**
|
|
249
270
|
* Invert an HTTP node. The plain node keeps its request at the top level
|
|
250
271
|
* (`url` / `method` / `headers` / `queryParams` / `body` / `contentType`); the
|
|
@@ -275,7 +296,7 @@ function liftHttp(node, ctx, managed) {
|
|
|
275
296
|
throw new Error(`decompile: expected a number, got ${JSON.stringify(inputs.retryCount)}.`);
|
|
276
297
|
}
|
|
277
298
|
const branchRows = Array.isArray(inputs.branches) ? inputs.branches : [];
|
|
278
|
-
const returns = liftReturns(node);
|
|
299
|
+
const returns = liftReturns(node) ?? returnsFromReads(ctx.reads());
|
|
279
300
|
const spec = {
|
|
280
301
|
url: value(req.url ?? ''),
|
|
281
302
|
...(text(req.method) !== undefined && req.method !== 'GET' ? { method: req.method } : {}),
|
|
@@ -698,10 +698,13 @@ function liftProcess(node, ctx, prefix, kind, form) {
|
|
|
698
698
|
const n = node;
|
|
699
699
|
const key = n.type.slice(prefix.length);
|
|
700
700
|
const def = ctx.definition();
|
|
701
|
-
|
|
701
|
+
// Descriptor rows (`[{ name, default }]`), or the early `{ name, folderPath }` object.
|
|
702
|
+
const values = def?.model?.bindings?.values;
|
|
702
703
|
const binding = (name) => {
|
|
703
|
-
const
|
|
704
|
-
|
|
704
|
+
const v = Array.isArray(values)
|
|
705
|
+
? values.find((r) => r?.name === name)?.default
|
|
706
|
+
: values !== null && typeof values === 'object' ? values[name] : undefined;
|
|
707
|
+
return typeof v === 'string' ? v : undefined;
|
|
705
708
|
};
|
|
706
709
|
const name = binding('name');
|
|
707
710
|
const folderPath = binding('folderPath');
|
|
@@ -712,11 +715,13 @@ function liftProcess(node, ctx, prefix, kind, form) {
|
|
|
712
715
|
const projectId = typeof def?.model?.projectId === 'string' ? def.model.projectId : undefined;
|
|
713
716
|
const inSolution = def?.model?.isInSolution === true || projectId !== undefined;
|
|
714
717
|
const inputs = { ...(n.inputs ?? {}) };
|
|
715
|
-
// The design-time fire-and-forget switch is an OPTION on
|
|
716
|
-
// process argument — serialize adds it to `inputs` after rendering the
|
|
717
|
-
// author's map, so it comes back off here.
|
|
718
|
-
|
|
719
|
-
|
|
718
|
+
// The design-time fire-and-forget switch is an OPTION on agenticProcess(),
|
|
719
|
+
// not a process argument — serialize adds it to `inputs` after rendering the
|
|
720
|
+
// author's map, so it comes back off here. No other factory has the option, so
|
|
721
|
+
// on another kind the key stays an ordinary input and round-trips as one.
|
|
722
|
+
const fireAndForget = kind === 'agenticProcess' && ctx.plainValue(inputs.fireAndForget) === true;
|
|
723
|
+
if (kind === 'agenticProcess')
|
|
724
|
+
delete inputs.fireAndForget;
|
|
720
725
|
if (kind === 'agent' && (def?.model?.isInSolution === true || def?.model?.projectId !== undefined)) {
|
|
721
726
|
for (const [k, v] of Object.entries(inputs))
|
|
722
727
|
inputs[k] = legacyAgentTemplateInput(v);
|
|
@@ -748,6 +753,9 @@ function liftProcess(node, ctx, prefix, kind, form) {
|
|
|
748
753
|
...(returns !== undefined && !fireAndForget ? { returns } : {}),
|
|
749
754
|
...(form !== undefined ? { form } : {}),
|
|
750
755
|
...(fireAndForget ? { completion: 'fire-and-forget' } : {}),
|
|
756
|
+
// The only field a coded agent's definition differs in (see agentDef);
|
|
757
|
+
// 'lowcode' is the default, so only 'coded' is written.
|
|
758
|
+
...(kind === 'agent' && def?.display?.icon === 'coded-agent' ? { flavour: 'coded' } : {}),
|
|
751
759
|
};
|
|
752
760
|
return { kind, inputs: spec };
|
|
753
761
|
}
|
|
@@ -767,6 +775,7 @@ function printProcess(spec, ctx, factory) {
|
|
|
767
775
|
['returns', p.returns !== undefined ? obj(Object.entries(p.returns).map(([k, t]) => [k, ctx.string(t)])) : undefined],
|
|
768
776
|
['form', p.form !== undefined ? ctx.string(p.form) : undefined],
|
|
769
777
|
['completion', p.completion !== undefined ? ctx.string(p.completion) : undefined],
|
|
778
|
+
['flavour', p.flavour !== undefined ? ctx.string(p.flavour) : undefined],
|
|
770
779
|
],
|
|
771
780
|
};
|
|
772
781
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.44.
|
|
3
|
+
"version": "6.44.3",
|
|
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": "89512b0912180900bd6b3c62191b7beb090af3cc"
|
|
97
97
|
}
|