@uipath/maestro-builder-sdk 6.18.9 → 6.19.0
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 +185 -184
- package/dist/api-members.md +504 -473
- package/dist/bpmn/uipath-moddle.v1.json +5 -0
- package/dist/case/decompile-cli.js +2 -8
- package/dist/check.js +177 -650
- package/dist/core/actions.d.ts +119 -760
- package/dist/core/actions.js +0 -306
- package/dist/core/error-port.d.ts +6 -0
- package/dist/core/error-port.js +9 -0
- package/dist/core/node-classes.d.ts +4 -63
- package/dist/core/node-classes.js +0 -112
- package/dist/core/nodes/family.d.ts +36 -0
- package/dist/core/nodes/family.js +1 -0
- package/dist/core/nodes/node-type.d.ts +136 -0
- package/dist/core/nodes/node-type.js +1 -0
- package/dist/core/nodes/registry.d.ts +57 -0
- package/dist/core/nodes/registry.js +122 -0
- package/dist/core/nodes/versioned.d.ts +50 -0
- package/dist/core/nodes/versioned.js +46 -0
- package/dist/core/typed-raw-node.d.ts +13 -62
- package/dist/core/typed-raw-node.js +40 -154
- package/dist/decompile-cli.js +2 -9
- package/dist/decompile.js +92 -271
- package/dist/flow-definitions.d.ts +10 -0
- package/dist/flow-definitions.js +35 -0
- package/dist/flow-node-registry.d.ts +13 -0
- package/dist/flow-node-registry.js +19 -0
- package/dist/flow-node-type.d.ts +192 -0
- package/dist/flow-node-type.js +1 -0
- package/dist/flow-sdk.d.ts +7 -0
- package/dist/flow-sdk.js +8 -0
- package/dist/nodes/data-fabric/flow/check.d.ts +13 -0
- package/dist/nodes/data-fabric/flow/check.js +164 -0
- package/dist/nodes/data-fabric/flow/factories.d.ts +113 -0
- package/dist/nodes/data-fabric/flow/factories.js +134 -0
- package/dist/nodes/data-fabric/flow/family.d.ts +7 -0
- package/dist/nodes/data-fabric/flow/family.js +9 -0
- package/dist/nodes/data-fabric/flow/index.d.ts +8 -0
- package/dist/nodes/data-fabric/flow/index.js +8 -0
- package/dist/nodes/data-fabric/flow/raw.d.ts +32 -0
- package/dist/nodes/data-fabric/flow/raw.js +100 -0
- package/dist/nodes/data-fabric/flow/shared.d.ts +77 -0
- package/dist/nodes/data-fabric/flow/shared.js +174 -0
- package/dist/nodes/data-fabric/flow/spec.d.ts +238 -0
- package/dist/nodes/data-fabric/flow/spec.js +1 -0
- package/dist/nodes/data-fabric/flow/verbs.d.ts +29 -0
- package/dist/nodes/data-fabric/flow/verbs.js +239 -0
- package/dist/nodes/delay/flow/check.d.ts +16 -0
- package/dist/nodes/delay/flow/check.js +86 -0
- package/dist/nodes/delay/flow/factories.d.ts +28 -0
- package/dist/nodes/delay/flow/factories.js +38 -0
- package/dist/nodes/delay/flow/family.d.ts +3 -0
- package/dist/nodes/delay/flow/family.js +8 -0
- package/dist/nodes/delay/flow/index.d.ts +3 -0
- package/dist/nodes/delay/flow/index.js +3 -0
- package/dist/nodes/delay/flow/node-type.d.ts +13 -0
- package/dist/nodes/delay/flow/node-type.js +71 -0
- package/dist/nodes/delay/flow/spec.d.ts +43 -0
- package/dist/nodes/delay/flow/spec.js +16 -0
- package/dist/nodes/document/flow/factories.d.ts +27 -0
- package/dist/nodes/document/flow/factories.js +30 -0
- package/dist/nodes/document/flow/family.d.ts +3 -0
- package/dist/nodes/document/flow/family.js +7 -0
- package/dist/nodes/document/flow/index.d.ts +3 -0
- package/dist/nodes/document/flow/index.js +3 -0
- package/dist/nodes/document/flow/node-type.d.ts +14 -0
- package/dist/nodes/document/flow/node-type.js +150 -0
- package/dist/nodes/document/flow/spec.d.ts +65 -0
- package/dist/nodes/document/flow/spec.js +1 -0
- package/dist/nodes/mock/flow/factories.d.ts +51 -0
- package/dist/nodes/mock/flow/factories.js +47 -0
- package/dist/nodes/mock/flow/family.d.ts +3 -0
- package/dist/nodes/mock/flow/family.js +7 -0
- package/dist/nodes/mock/flow/index.d.ts +2 -0
- package/dist/nodes/mock/flow/index.js +2 -0
- package/dist/nodes/mock/flow/node-type.d.ts +11 -0
- package/dist/nodes/mock/flow/node-type.js +51 -0
- package/dist/nodes/script/flow/check.d.ts +19 -0
- package/dist/nodes/script/flow/check.js +49 -0
- package/dist/nodes/script/flow/factories.d.ts +14 -0
- package/dist/nodes/script/flow/factories.js +15 -0
- package/dist/nodes/script/flow/family.d.ts +3 -0
- package/dist/nodes/script/flow/family.js +8 -0
- package/dist/nodes/script/flow/index.d.ts +3 -0
- package/dist/nodes/script/flow/index.js +3 -0
- package/dist/nodes/script/flow/node-type.d.ts +7 -0
- package/dist/nodes/script/flow/node-type.js +125 -0
- package/dist/nodes/script/flow/spec.d.ts +52 -0
- package/dist/nodes/script/flow/spec.js +1 -0
- package/dist/nodes/transform/flow/check.d.ts +6 -0
- package/dist/nodes/transform/flow/check.js +229 -0
- package/dist/nodes/transform/flow/factories.d.ts +52 -0
- package/dist/nodes/transform/flow/factories.js +53 -0
- package/dist/nodes/transform/flow/family.d.ts +3 -0
- package/dist/nodes/transform/flow/family.js +8 -0
- package/dist/nodes/transform/flow/index.d.ts +3 -0
- package/dist/nodes/transform/flow/index.js +3 -0
- package/dist/nodes/transform/flow/node-type.d.ts +7 -0
- package/dist/nodes/transform/flow/node-type.js +244 -0
- package/dist/nodes/transform/flow/spec.d.ts +116 -0
- package/dist/nodes/transform/flow/spec.js +10 -0
- package/dist/raw-node-advice.d.ts +16 -0
- package/dist/raw-node-advice.js +36 -0
- package/dist/raw-node.d.ts +71 -0
- package/dist/raw-node.js +116 -0
- package/dist/registry/uip/launch.d.ts +11 -1
- package/dist/registry/uip/launch.js +50 -43
- package/dist/registry/uip/pipeline-front-door.d.ts +2 -0
- package/dist/registry/uip/pipeline-front-door.js +88 -0
- package/dist/serialize.js +138 -492
- package/package.json +2 -2
package/dist/decompile.js
CHANGED
|
@@ -28,13 +28,11 @@
|
|
|
28
28
|
* display labels on plain steps, and formatting are not preserved (layout is
|
|
29
29
|
* re-attached by `flow-merge`; see `docs/FLOW_PARITY.md`).
|
|
30
30
|
*/
|
|
31
|
-
import { readFileSync } from 'node:fs';
|
|
32
31
|
import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
|
|
33
32
|
import { preserveSchemaVersion } from './schema-version.js';
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import { DEFAULT_TRIGGER_ID } from './core/expr.js';
|
|
33
|
+
import { BUNDLED_DEFINITIONS, bundledVersions, hasBundledDefinition } from './flow-definitions.js';
|
|
34
|
+
import { DEFAULT_TRIGGER_ID, Expr } from './core/expr.js';
|
|
35
|
+
import { FLOW_NODE_TYPES } from './flow-node-registry.js';
|
|
38
36
|
import { commentText } from './core/comment-text.js';
|
|
39
37
|
import { tsLiteral, tsNumber, tsText } from './core/ts-literal.js';
|
|
40
38
|
import { parseIxpProjectType } from './core/actions.js';
|
|
@@ -89,16 +87,6 @@ function warnOnce(message) {
|
|
|
89
87
|
runWarned.add(message);
|
|
90
88
|
runWarn?.(message);
|
|
91
89
|
}
|
|
92
|
-
/**
|
|
93
|
-
* The `<nodeType>@<version>` pairs this SDK bundles for core nodes — the same
|
|
94
|
-
* file `serialize` resolves an explicit `{ version }` against (design §2.6:
|
|
95
|
-
* exact, no floating). Decompile preserves the file's pair (design §5.3), so
|
|
96
|
-
* when the file pins a version the bundle lacks, `compile` WILL refuse the
|
|
97
|
-
* emitted source; saying so here is the difference between a loop that fails
|
|
98
|
-
* at step 2 with a hint and one that fails at step 2 with a puzzle.
|
|
99
|
-
*/
|
|
100
|
-
const CORE_DEFINITIONS = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'core-definitions.json'), 'utf8'));
|
|
101
|
-
const CORE_DEFINITION_KEYS = new Set(Object.keys(CORE_DEFINITIONS));
|
|
102
90
|
/**
|
|
103
91
|
* The label the canvas gives a freshly dropped `node`: its definition's
|
|
104
92
|
* `display.label`, from the file's own `definitions[]`, else the bundled core
|
|
@@ -106,7 +94,7 @@ const CORE_DEFINITION_KEYS = new Set(Object.keys(CORE_DEFINITIONS));
|
|
|
106
94
|
*/
|
|
107
95
|
function definitionLabel(node) {
|
|
108
96
|
const key = `${node.type}@${node.typeVersion}`;
|
|
109
|
-
const def = runDefs.get(key) ??
|
|
97
|
+
const def = runDefs.get(key) ?? BUNDLED_DEFINITIONS[key] ?? runDefs.get(node.type);
|
|
110
98
|
const label = def?.display?.label;
|
|
111
99
|
return typeof label === 'string' ? label : undefined;
|
|
112
100
|
}
|
|
@@ -124,11 +112,17 @@ function verClause(node) {
|
|
|
124
112
|
+ `the file's definitions[] disagrees with the instance.`);
|
|
125
113
|
}
|
|
126
114
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
115
|
+
// Decompile preserves the file's pair (design §5.3), but `serialize` resolves an
|
|
116
|
+
// explicit { version } against the bundle exactly (design §2.6), so a pin the
|
|
117
|
+
// bundle lacks WILL fail `compile`; saying so here is the difference between a
|
|
118
|
+
// loop that fails at step 2 with a hint and one that fails with a puzzle.
|
|
119
|
+
// A registered type resolves against its registered versions, which the bundle
|
|
120
|
+
// may exceed; every other core type against the bundle.
|
|
121
|
+
const registered = FLOW_NODE_TYPES.byTypeName(node.type);
|
|
122
|
+
const shipped = registered ? Object.keys(registered.type.versions)
|
|
123
|
+
: node.type.startsWith('core.') && !hasBundledDefinition(node.type, tv) ? bundledVersions(node.type) : undefined;
|
|
124
|
+
if (shipped && !shipped.includes(tv)) {
|
|
125
|
+
warnOnce(`node ${tsLiteral(node.id)} pins ${node.type}@${tv}, but this SDK ${registered ? 'registers' : 'bundles'} ${node.type}@${shipped.join(', ') || '<none>'} only; `
|
|
132
126
|
+ `\`compile\` will refuse the emitted { version: ${tsLiteral(tv)} } (versions resolve exactly, flow-builder-sdk#71). `
|
|
133
127
|
+ `The source keeps the file's pair; to recompile, drop that { version } and the node takes the SDK's pinned version.`);
|
|
134
128
|
}
|
|
@@ -210,21 +204,11 @@ const T = {
|
|
|
210
204
|
endCall: 'uipath.conversational.voice.end-call',
|
|
211
205
|
http: 'core.action.http',
|
|
212
206
|
httpV2: 'core.action.http.v2',
|
|
213
|
-
script: 'core.action.script',
|
|
214
|
-
transform: 'core.action.transform',
|
|
215
|
-
delay: 'core.logic.delay',
|
|
216
|
-
mock: 'core.logic.mock',
|
|
217
207
|
decision: 'core.logic.decision',
|
|
218
208
|
switch: 'core.logic.switch',
|
|
219
209
|
merge: 'core.logic.merge',
|
|
220
210
|
loop: 'core.logic.loop',
|
|
221
211
|
doWhile: 'core.logic.dowhile',
|
|
222
|
-
dataFabricRead: 'core.datafabric.read',
|
|
223
|
-
dataFabricCreate: 'core.datafabric.create',
|
|
224
|
-
dataFabricDelete: 'core.datafabric.delete',
|
|
225
|
-
documentClassify: 'uipath.document.classify',
|
|
226
|
-
dynamicExtract: 'uipath.ixp.extract-document-builder',
|
|
227
|
-
dataFabricUpdate: 'core.datafabric.update',
|
|
228
212
|
subflow: 'core.subflow',
|
|
229
213
|
terminate: 'core.logic.terminate',
|
|
230
214
|
end: 'core.control.end',
|
|
@@ -503,147 +487,91 @@ class Graph {
|
|
|
503
487
|
}
|
|
504
488
|
}
|
|
505
489
|
// ─── Node → step-spec source ──────────────────────────────────────────────────
|
|
490
|
+
/**
|
|
491
|
+
* A serialized value back as a spec holds it: `=js:` text (bare, or in a
|
|
492
|
+
* `{ type: 'jsExpression', expression }` object) becomes an `Expr`; anything else
|
|
493
|
+
* is a literal and stays itself.
|
|
494
|
+
*/
|
|
495
|
+
function specValue(raw) {
|
|
496
|
+
if (typeof raw === 'string')
|
|
497
|
+
return raw.startsWith('=js:') ? new Expr(raw.slice(4)) : raw;
|
|
498
|
+
const o = raw;
|
|
499
|
+
if (o && typeof o === 'object' && o.type === 'jsExpression' && typeof o.expression === 'string')
|
|
500
|
+
return new Expr(o.expression);
|
|
501
|
+
return raw;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Print a node whose type is registered (flow-node-registry.ts): the node type
|
|
505
|
+
* deserializes it to its spec and prints the factory call. A node at a version
|
|
506
|
+
* the type does not register is lifted by its default version's implementation —
|
|
507
|
+
* as every built-in family lifts any version today — and keeps its own
|
|
508
|
+
* `{ version }` on the step, which compile then refuses; `verClause` warns at
|
|
509
|
+
* decompile time that it will. `undefined` when the type is not registered, or the node type declines
|
|
510
|
+
* the node; the caller's branches take it from there.
|
|
511
|
+
*/
|
|
512
|
+
function emitRegisteredSpec(node, imp, inputNames) {
|
|
513
|
+
const entry = typeof node.type === 'string' ? FLOW_NODE_TYPES.byTypeName(node.type) : undefined;
|
|
514
|
+
if (!entry)
|
|
515
|
+
return undefined;
|
|
516
|
+
const version = String(node.typeVersion ?? '');
|
|
517
|
+
const impl = (Object.hasOwn(entry.type.versions, version)
|
|
518
|
+
? entry.type.versions[version]
|
|
519
|
+
: entry.type.versions[entry.type.defaultVersion]);
|
|
520
|
+
const ctx = {
|
|
521
|
+
nodeId: node.id,
|
|
522
|
+
expr: specValue,
|
|
523
|
+
sourceText: unwrapSource,
|
|
524
|
+
plainValue: unwrapPlain,
|
|
525
|
+
stepName: (nodeId) => nodeId,
|
|
526
|
+
definition: () => runDefs.get(`${node.type}@${version}`) ?? runDefs.get(node.type),
|
|
527
|
+
warn: warnOnce,
|
|
528
|
+
};
|
|
529
|
+
const spec = impl.deserialize(node, ctx);
|
|
530
|
+
if (spec === undefined)
|
|
531
|
+
return undefined;
|
|
532
|
+
// A spec value as source, recursing into arrays and plain objects so an Expr
|
|
533
|
+
// nested in one (a filter row's value) prints as the helper an author writes —
|
|
534
|
+
// in the `{ k: v }` / `[a, b]` spelling the hand-written printers use.
|
|
535
|
+
const printValue = (v) => {
|
|
536
|
+
if (v instanceof Expr)
|
|
537
|
+
return v.literal ? tsLiteral(v.value) : emitRef(v.js, imp, inputNames);
|
|
538
|
+
if (Array.isArray(v))
|
|
539
|
+
return `[${v.map(printValue).join(', ')}]`;
|
|
540
|
+
if (v && typeof v === 'object') {
|
|
541
|
+
const parts = Object.entries(v).filter(([, x]) => x !== undefined).map(([k, x]) => `${key(k)}: ${printValue(x)}`);
|
|
542
|
+
return parts.length ? `{ ${parts.join(', ')} }` : '{}';
|
|
543
|
+
}
|
|
544
|
+
return tsLiteral(v);
|
|
545
|
+
};
|
|
546
|
+
const print = {
|
|
547
|
+
value: printValue,
|
|
548
|
+
string: (t) => tsLiteral(t),
|
|
549
|
+
json: (v) => tsLiteral(v),
|
|
550
|
+
key: (k) => key(k),
|
|
551
|
+
helper: (name) => imp.use(name),
|
|
552
|
+
};
|
|
553
|
+
const call = impl.print?.(spec, print) ?? {
|
|
554
|
+
factory: impl.factory,
|
|
555
|
+
options: Object.entries(spec.inputs ?? {})
|
|
556
|
+
.map(([k, v]) => [k, v === undefined ? undefined : print.value(v)]),
|
|
557
|
+
};
|
|
558
|
+
const options = opts((call.options ?? []).map(([k, v]) => [k, v]));
|
|
559
|
+
const args = [...(call.positional ?? []), ...(options ? [options] : [])];
|
|
560
|
+
return `${imp.use(call.factory)}(${args.join(', ')})`;
|
|
561
|
+
}
|
|
506
562
|
/**
|
|
507
563
|
* Emit the action-spec argument for a `.step(id, <spec>)` call — e.g.
|
|
508
564
|
* `script({ code: "…" })`. Returns `undefined` for a node that is not a plain
|
|
509
565
|
* action (control-flow / trigger / end), which the traversal handles specially.
|
|
510
566
|
*/
|
|
511
567
|
function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
568
|
+
// A registered node type lifts itself; every other type falls through to the
|
|
569
|
+
// branches below until its family is ported (FB014's pins are the list).
|
|
570
|
+
const lifted = emitRegisteredSpec(node, imp, inputNames);
|
|
571
|
+
if (lifted !== undefined)
|
|
572
|
+
return lifted;
|
|
512
573
|
const inputs = node.inputs ?? {};
|
|
513
574
|
switch (node.type) {
|
|
514
|
-
case T.mock:
|
|
515
|
-
return `${imp.use('mock')}()`;
|
|
516
|
-
case T.script: {
|
|
517
|
-
const code = typeof inputs.script === 'string' ? inputs.script : '';
|
|
518
|
-
// `returns` is emitted only when the node's declared output type is
|
|
519
|
-
// something re-compiling the body would NOT produce on its own. Serialize
|
|
520
|
-
// infers from the body first (see `scriptOutputs`), so a script whose type
|
|
521
|
-
// is already plain in its code round-trips without it — emitting one there
|
|
522
|
-
// would add an argument the author never wrote to every such step.
|
|
523
|
-
return `${imp.use('script')}(${opts([['code', tsLiteral(code)], ...scriptReturnsOpt(node, code)])})`;
|
|
524
|
-
}
|
|
525
|
-
case T.delay: {
|
|
526
|
-
// serialize's `delayInputs` writes `{timerType, timerPreset, timerValue?}`
|
|
527
|
-
// for a duration and `{timerType:'timeDate', timerDate}` for an absolute
|
|
528
|
-
// wait. Invert all three spellings.
|
|
529
|
-
if (inputs.timerType === 'timeDate') {
|
|
530
|
-
const until = typeof inputs.timerDate === 'string' ? inputs.timerDate : '';
|
|
531
|
-
return `${imp.use('delay')}(${opts([['until', tsLiteral(until)]])})`;
|
|
532
|
-
}
|
|
533
|
-
const duration = inputs.timerPreset === 'custom'
|
|
534
|
-
? (typeof inputs.timerValue === 'string' ? inputs.timerValue : '')
|
|
535
|
-
: (typeof inputs.timerPreset === 'string' ? inputs.timerPreset : '');
|
|
536
|
-
return `${imp.use('delay')}(${opts([['duration', tsLiteral(duration)]])})`;
|
|
537
|
-
}
|
|
538
|
-
case T.documentClassify:
|
|
539
|
-
case T.dynamicExtract: {
|
|
540
|
-
const fr = unwrapSource(inputs.fileRef) ?? '';
|
|
541
|
-
const fileSrc = fr.startsWith('=js:') ? emitBareExpr(fr.slice(4), imp, inputNames) : tsLiteral(fr);
|
|
542
|
-
const pageRange = typeof inputs.pageRange === 'string' && inputs.pageRange !== '' ? tsLiteral(inputs.pageRange) : undefined;
|
|
543
|
-
if (node.type === T.documentClassify) {
|
|
544
|
-
const split = unwrapPlain(inputs.splitPages);
|
|
545
|
-
return `${imp.use('documentClassify')}(${opts([
|
|
546
|
-
['fileRef', fileSrc],
|
|
547
|
-
['pageRange', pageRange],
|
|
548
|
-
['splitPages', split === true ? 'true' : undefined],
|
|
549
|
-
])})`;
|
|
550
|
-
}
|
|
551
|
-
const schema = inputs.schemaDocument !== undefined ? tsLiteral(inputs.schemaDocument) : undefined;
|
|
552
|
-
return `${imp.use('dynamicExtract')}(${opts([
|
|
553
|
-
['fileRef', fileSrc],
|
|
554
|
-
['schema', schema],
|
|
555
|
-
['pageRange', pageRange],
|
|
556
|
-
])})`;
|
|
557
|
-
}
|
|
558
|
-
case T.dataFabricRead:
|
|
559
|
-
case T.dataFabricCreate:
|
|
560
|
-
case T.dataFabricUpdate:
|
|
561
|
-
case T.dataFabricDelete: {
|
|
562
|
-
const cfg = (inputs.entityConfig ?? {});
|
|
563
|
-
const entity = tsText(cfg.entityName);
|
|
564
|
-
const folder = typeof cfg._folderKey === 'string' ? tsLiteral(cfg._folderKey) : undefined;
|
|
565
|
-
const resourceKey = typeof cfg._resourceKey === 'string' ? tsLiteral(cfg._resourceKey) : undefined;
|
|
566
|
-
const val = (v) => {
|
|
567
|
-
// 1.3 let `recordId` and a create's field value be a `{ type:
|
|
568
|
-
// 'jsExpression', expression }` object as well as a `=js:` string. A
|
|
569
|
-
// product-authored node can carry either; both recover as an expression.
|
|
570
|
-
const obj = v;
|
|
571
|
-
if (obj && typeof obj === 'object' && obj.type === 'jsExpression') {
|
|
572
|
-
return emitBareExpr(String(obj.expression ?? ''), imp, inputNames);
|
|
573
|
-
}
|
|
574
|
-
const raw = typeof v === 'string' ? v : String(v ?? '');
|
|
575
|
-
return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames) : tsLiteral(raw);
|
|
576
|
-
};
|
|
577
|
-
const fieldObject = (rows) => {
|
|
578
|
-
const list = Array.isArray(rows) ? rows : [];
|
|
579
|
-
return `{ ${list.map((r) => `${key(String(r.field ?? ''))}: ${val(r.value)}`).join(', ')} }`;
|
|
580
|
-
};
|
|
581
|
-
const record = cfg.recordSource === 'fromRead'
|
|
582
|
-
? `{ fromRead: ${tsText(cfg.readEntityNodeId)} }`
|
|
583
|
-
: `{ byId: ${val(cfg.recordId)} }`;
|
|
584
|
-
if (node.type === T.dataFabricRead) {
|
|
585
|
-
// The array is what the platform serializer reads and what compile
|
|
586
|
-
// writes; the grouped object is the newer authoring shape, tolerated
|
|
587
|
-
// here so a canvas-authored file still decompiles. Both flatten to the
|
|
588
|
-
// builder's row list, where `or: true` marks each new OR alternative.
|
|
589
|
-
const filterRow = (r, or = false) => opts([
|
|
590
|
-
['field', tsText(r.field)],
|
|
591
|
-
['operator', r.operator !== undefined && r.operator !== '=' ? tsLiteral(String(r.operator)) : undefined],
|
|
592
|
-
['value', val(r.value)],
|
|
593
|
-
['or', or ? 'true' : undefined],
|
|
594
|
-
]);
|
|
595
|
-
const q = cfg._filters;
|
|
596
|
-
let rows = [];
|
|
597
|
-
if (Array.isArray(q)) {
|
|
598
|
-
rows = q.map((r, i) => filterRow(r, i > 0 && r['join'] === 'OR'));
|
|
599
|
-
}
|
|
600
|
-
else if (q && typeof q === 'object') {
|
|
601
|
-
// Grouped: each root row and each group is one alternative, so every
|
|
602
|
-
// one but the first opens with `or: true`.
|
|
603
|
-
const alts = [
|
|
604
|
-
...(Array.isArray(q.rows) ? q.rows.map((r) => [r]) : []),
|
|
605
|
-
...(Array.isArray(q.groups) ? q.groups : [])
|
|
606
|
-
.map((g) => (Array.isArray(g.rows) ? g.rows : [])),
|
|
607
|
-
].filter((a) => a.length);
|
|
608
|
-
rows = alts.flatMap((alt, ai) => alt.map((r, ri) => filterRow(r, ai > 0 && ri === 0)));
|
|
609
|
-
}
|
|
610
|
-
const filters = rows.length ? `[${rows.join(', ')}]` : undefined;
|
|
611
|
-
// `resultMode` only exists from 1.4, and recovering it re-selects 1.4 on
|
|
612
|
-
// the way back out — so a 1.0 node stays a 1.0 node through the round trip.
|
|
613
|
-
const mode = cfg.resultMode === 'single' || cfg.resultMode === 'multiple'
|
|
614
|
-
? tsLiteral(cfg.resultMode) : undefined;
|
|
615
|
-
const sort = cfg._sort && typeof cfg._sort === 'object'
|
|
616
|
-
? opts([
|
|
617
|
-
['field', tsText(cfg._sort.field)],
|
|
618
|
-
['direction', cfg._sort.direction === 'desc' ? tsLiteral('desc') : undefined],
|
|
619
|
-
])
|
|
620
|
-
: undefined;
|
|
621
|
-
const fields = Array.isArray(cfg._selectedFieldNames) && cfg._selectedFieldNames.length
|
|
622
|
-
? `[${cfg._selectedFieldNames.map((f) => tsLiteral(String(f))).join(', ')}]`
|
|
623
|
-
: undefined;
|
|
624
|
-
return `${imp.use('dataFabricRead')}(${opts([
|
|
625
|
-
['entity', entity], ['filters', filters], ['resultMode', mode],
|
|
626
|
-
['limit', typeof cfg._recordLimit === 'number' ? String(cfg._recordLimit) : undefined],
|
|
627
|
-
['skip', typeof cfg._skip === 'number' ? String(cfg._skip) : undefined],
|
|
628
|
-
['sort', sort], ['fields', fields],
|
|
629
|
-
['folderKey', folder], ['resourceKey', resourceKey],
|
|
630
|
-
])})`;
|
|
631
|
-
}
|
|
632
|
-
if (node.type === T.dataFabricCreate) {
|
|
633
|
-
return `${imp.use('dataFabricCreate')}(${opts([
|
|
634
|
-
['entity', entity], ['values', fieldObject(cfg.fieldValues)], ['folderKey', folder], ['resourceKey', resourceKey],
|
|
635
|
-
])})`;
|
|
636
|
-
}
|
|
637
|
-
if (node.type === T.dataFabricDelete) {
|
|
638
|
-
return `${imp.use('dataFabricDelete')}(${opts([
|
|
639
|
-
['entity', entity], ['record', record], ['folderKey', folder], ['resourceKey', resourceKey],
|
|
640
|
-
])})`;
|
|
641
|
-
}
|
|
642
|
-
return `${imp.use('dataFabricUpdate')}(${opts([
|
|
643
|
-
['entity', entity], ['record', record], ['set', fieldObject(cfg.fieldUpdates)],
|
|
644
|
-
['folderKey', folder], ['resourceKey', resourceKey],
|
|
645
|
-
])})`;
|
|
646
|
-
}
|
|
647
575
|
case T.createOutgoingCall:
|
|
648
576
|
case T.endCall: {
|
|
649
577
|
const i = (node.inputs ?? {});
|
|
@@ -766,8 +694,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
766
694
|
case T.httpV2:
|
|
767
695
|
return emitHttp(node, true, imp, inputNames);
|
|
768
696
|
default:
|
|
769
|
-
if (node.type.startsWith('core.action.transform'))
|
|
770
|
-
return emitTransform(node, imp, inputNames);
|
|
771
697
|
// A connector action node: `uipath.connector.<key>.<action>` (but NOT the
|
|
772
698
|
// event nodes `uipath.connector.event.*` / `.trigger.*`, which are triggers).
|
|
773
699
|
if (node.type.startsWith('uipath.connector.') && !node.type.startsWith('uipath.connector.event.') && !node.type.startsWith('uipath.connector.trigger.')) {
|
|
@@ -823,49 +749,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
823
749
|
return unsupportedSpec(node, imp, o);
|
|
824
750
|
}
|
|
825
751
|
}
|
|
826
|
-
/**
|
|
827
|
-
* The `returns` argument for a script step, or nothing.
|
|
828
|
-
*
|
|
829
|
-
* Recovers what the author declared by DIFFERENCE: the node says what its output
|
|
830
|
-
* is, `inferScriptShape` says what re-compiling the body would declare on its
|
|
831
|
-
* own, and only a gap between the two needs writing down. Fields are recovered
|
|
832
|
-
* the same way — a property map the body does not produce is one the author gave
|
|
833
|
-
* as `returns: {…}`.
|
|
834
|
-
*/
|
|
835
|
-
function scriptReturnsOpt(node, code) {
|
|
836
|
-
const out = node.outputs?.output;
|
|
837
|
-
const declared = typeof out?.type === 'string' ? out.type : undefined;
|
|
838
|
-
if (!declared)
|
|
839
|
-
return [];
|
|
840
|
-
const props = out?.properties;
|
|
841
|
-
// What re-compiling this body with NO `returns` would declare. Mirror
|
|
842
|
-
// `scriptOutputs` exactly: an inference of a bare `object` (or none at all)
|
|
843
|
-
// leaves the definition's own `{type:'object'}` standing, untouched.
|
|
844
|
-
const inferred = inferScriptShape(code);
|
|
845
|
-
const effective = inferred && !(inferred.type === 'object' && !inferred.properties)
|
|
846
|
-
? inferred
|
|
847
|
-
: { type: 'object', properties: undefined };
|
|
848
|
-
const same = effective.type === declared
|
|
849
|
-
&& JSON.stringify(sortKeys(effective.properties ?? {})) === JSON.stringify(sortKeys(props ?? {}));
|
|
850
|
-
if (same)
|
|
851
|
-
return [];
|
|
852
|
-
// Not what the body alone would say — so the author declared it, and it has to
|
|
853
|
-
// be written back or the round-trip loses it. That includes declaring the OPEN
|
|
854
|
-
// object over a body that looks typed, which is a real thing to want.
|
|
855
|
-
if (props && Object.keys(props).length > 0) {
|
|
856
|
-
// A field map is the richer statement, so it wins when there is one.
|
|
857
|
-
const entries = Object.entries(props)
|
|
858
|
-
.filter(([, v]) => typeof v?.type === 'string')
|
|
859
|
-
.map(([k, v]) => [k, tsLiteral(v.type)]);
|
|
860
|
-
if (entries.length > 0)
|
|
861
|
-
return [['returns', opts(entries)]];
|
|
862
|
-
}
|
|
863
|
-
return [['returns', tsLiteral(declared)]];
|
|
864
|
-
}
|
|
865
|
-
/** Key-sorted copy, so a property map compares by content and not by order. */
|
|
866
|
-
function sortKeys(o) {
|
|
867
|
-
return Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b)));
|
|
868
|
-
}
|
|
869
752
|
/**
|
|
870
753
|
* Invert an HTTP node. The plain node (`core.action.http`) keeps its request at
|
|
871
754
|
* the top level (`url` / `method` / `headers` / `queryParams` / `body` /
|
|
@@ -926,68 +809,6 @@ function emitHttp(node, managed, imp, inputNames) {
|
|
|
926
809
|
]);
|
|
927
810
|
return `${imp.use('http')}(${spec})`;
|
|
928
811
|
}
|
|
929
|
-
/**
|
|
930
|
-
* Invert a Transform node (generic `core.action.transform` or a `.map` / `.filter`
|
|
931
|
-
* / `.group-by` variant). The `collection` is a bare `$vars.…` path; each
|
|
932
|
-
* operation's serialized `{id,type,config}` becomes a builder operation object.
|
|
933
|
-
* (The variant node types carry a `groupBy` operation spelled with a hyphen in
|
|
934
|
-
* the type — `group-by` — but `groupBy` in the operation, the platform's own
|
|
935
|
-
* mismatch, mirrored here.)
|
|
936
|
-
*/
|
|
937
|
-
function emitTransform(node, imp, inputNames) {
|
|
938
|
-
const inputs = node.inputs ?? {};
|
|
939
|
-
const suffix = node.type.slice('core.action.transform'.length).replace(/^\./, '');
|
|
940
|
-
const variant = suffix || undefined; // 'map' | 'filter' | 'group-by' | undefined
|
|
941
|
-
const collRaw = unwrapSource(inputs.collection);
|
|
942
|
-
const collection = collRaw !== undefined
|
|
943
|
-
? emitBareExpr(collRaw.startsWith('=js:') ? collRaw.slice(4) : collRaw, imp, inputNames)
|
|
944
|
-
: `${imp.use('lit')}([])`;
|
|
945
|
-
const ops = Array.isArray(inputs.operations) ? inputs.operations : [];
|
|
946
|
-
const opSrcs = ops.map((op) => {
|
|
947
|
-
const cfg = op?.config ?? {};
|
|
948
|
-
if (op?.type === 'filter') {
|
|
949
|
-
const filters = (cfg.filters ?? []).map((f) => objLit([
|
|
950
|
-
['field', tsLiteral(f.field)],
|
|
951
|
-
['condition', tsLiteral(f.condition)],
|
|
952
|
-
...(f.value !== undefined ? [['value', tsLiteral(f.value)]] : []),
|
|
953
|
-
]));
|
|
954
|
-
return objLit([
|
|
955
|
-
['type', tsLiteral('filter')],
|
|
956
|
-
...(cfg.operation !== undefined ? [['operation', tsLiteral(cfg.operation)]] : []),
|
|
957
|
-
['filters', `[${filters.join(', ')}]`],
|
|
958
|
-
]);
|
|
959
|
-
}
|
|
960
|
-
if (op?.type === 'map') {
|
|
961
|
-
const mappings = (cfg.mappings ?? []).map((m) => objLit([
|
|
962
|
-
['field', tsLiteral(m.field)],
|
|
963
|
-
...(m.transformation && m.transformation !== 'copy' ? [['transformation', tsLiteral(m.transformation)]] : []),
|
|
964
|
-
...(m.renameTo ? [['renameTo', tsLiteral(m.renameTo)]] : []),
|
|
965
|
-
]));
|
|
966
|
-
return objLit([
|
|
967
|
-
['type', tsLiteral('map')],
|
|
968
|
-
...(cfg.keepOriginalFields ? [['keepOriginalFields', boolLit(cfg.keepOriginalFields)]] : []),
|
|
969
|
-
['mappings', `[${mappings.join(', ')}]`],
|
|
970
|
-
]);
|
|
971
|
-
}
|
|
972
|
-
// groupBy
|
|
973
|
-
const aggs = (cfg.aggregations ?? []).map((a) => objLit([
|
|
974
|
-
['operation', tsLiteral(a.operation)],
|
|
975
|
-
['alias', tsLiteral(a.alias)],
|
|
976
|
-
...(a.field ? [['field', tsLiteral(a.field)]] : []),
|
|
977
|
-
]));
|
|
978
|
-
return objLit([
|
|
979
|
-
['type', tsLiteral('groupBy')],
|
|
980
|
-
['groupByField', tsLiteral(cfg.groupByField)],
|
|
981
|
-
['aggregations', `[${aggs.join(', ')}]`],
|
|
982
|
-
]);
|
|
983
|
-
});
|
|
984
|
-
const spec = opts([
|
|
985
|
-
['collection', collection],
|
|
986
|
-
['variant', variant ? tsLiteral(variant) : undefined],
|
|
987
|
-
['operations', `[${opSrcs.join(', ')}]`],
|
|
988
|
-
]);
|
|
989
|
-
return `${imp.use('transform')}(${spec})`;
|
|
990
|
-
}
|
|
991
812
|
/**
|
|
992
813
|
* Split a connector `nodeType` (`uipath.connector.<key>.<action>`) into key +
|
|
993
814
|
* action. Mirrors `core/connectors.ts`'s `splitConnectorNodeType`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bundled definitions, keyed `<nodeType>@<version>`. Deep-frozen: every reader
|
|
3
|
+
* shares this one copy, so a write meant for one node must clone first, and one
|
|
4
|
+
* that does not throws at its own site instead of leaking into another reader.
|
|
5
|
+
*/
|
|
6
|
+
export declare const BUNDLED_DEFINITIONS: Readonly<Record<string, any>>;
|
|
7
|
+
/** Whether the SDK bundles `<typeName>@<version>`. */
|
|
8
|
+
export declare function hasBundledDefinition(typeName: string, version: string): boolean;
|
|
9
|
+
/** The versions of `typeName` the SDK bundles, in bundle order. */
|
|
10
|
+
export declare function bundledVersions(typeName: string): string[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The node definitions this SDK bundles for Flow (`core-definitions.json`, keyed
|
|
3
|
+
* `<nodeType>@<version>`): the one parse of the bundle, shared by `serialize`,
|
|
4
|
+
* `decompile` and the node-type registry's validation.
|
|
5
|
+
*
|
|
6
|
+
* Kept apart from `serialize.ts` so the registry can depend on the bundle without
|
|
7
|
+
* importing the serializer that depends on the registry.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { dirname, join } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
/**
|
|
13
|
+
* The bundled definitions, keyed `<nodeType>@<version>`. Deep-frozen: every reader
|
|
14
|
+
* shares this one copy, so a write meant for one node must clone first, and one
|
|
15
|
+
* that does not throws at its own site instead of leaking into another reader.
|
|
16
|
+
*/
|
|
17
|
+
export const BUNDLED_DEFINITIONS = deepFreeze(JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'core-definitions.json'), 'utf8')));
|
|
18
|
+
function deepFreeze(value) {
|
|
19
|
+
if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
20
|
+
Object.freeze(value);
|
|
21
|
+
for (const child of Object.values(value))
|
|
22
|
+
deepFreeze(child);
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
const BUNDLED_KEYS = new Set(Object.keys(BUNDLED_DEFINITIONS));
|
|
27
|
+
/** Whether the SDK bundles `<typeName>@<version>`. */
|
|
28
|
+
export function hasBundledDefinition(typeName, version) {
|
|
29
|
+
return BUNDLED_KEYS.has(`${typeName}@${version}`);
|
|
30
|
+
}
|
|
31
|
+
/** The versions of `typeName` the SDK bundles, in bundle order. */
|
|
32
|
+
export function bundledVersions(typeName) {
|
|
33
|
+
const prefix = `${typeName}@`;
|
|
34
|
+
return [...BUNDLED_KEYS].filter((k) => k.startsWith(prefix)).map((k) => k.slice(prefix.length));
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow's node-type registry: every Flow node family, listed explicitly
|
|
3
|
+
* (docs/NODE_TYPE_ARCHITECTURE_DESIGN.md §4.5).
|
|
4
|
+
*
|
|
5
|
+
* While a kind is not listed here, `serialize`, `check` and `decompile` handle it
|
|
6
|
+
* with their existing branches — the FB014 pins in `tests/lint/pins.txt` are what
|
|
7
|
+
* is left to port.
|
|
8
|
+
*/
|
|
9
|
+
import { NodeTypeRegistry } from './core/nodes/registry.js';
|
|
10
|
+
import type { FlowContexts, FlowNodeFamily } from './flow-node-type.js';
|
|
11
|
+
/** The families, in no significant order. Adding one is the whole of registering it. */
|
|
12
|
+
export declare const FLOW_NODE_FAMILIES: readonly FlowNodeFamily[];
|
|
13
|
+
export declare const FLOW_NODE_TYPES: NodeTypeRegistry<FlowContexts>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow's node-type registry: every Flow node family, listed explicitly
|
|
3
|
+
* (docs/NODE_TYPE_ARCHITECTURE_DESIGN.md §4.5).
|
|
4
|
+
*
|
|
5
|
+
* While a kind is not listed here, `serialize`, `check` and `decompile` handle it
|
|
6
|
+
* with their existing branches — the FB014 pins in `tests/lint/pins.txt` are what
|
|
7
|
+
* is left to port.
|
|
8
|
+
*/
|
|
9
|
+
import { NodeTypeRegistry } from './core/nodes/registry.js';
|
|
10
|
+
import { hasBundledDefinition } from './flow-definitions.js';
|
|
11
|
+
import { dataFabricFlowFamily } from './nodes/data-fabric/flow/family.js';
|
|
12
|
+
import { delayFlowFamily } from './nodes/delay/flow/family.js';
|
|
13
|
+
import { documentFlowFamily } from './nodes/document/flow/family.js';
|
|
14
|
+
import { mockFlowFamily } from './nodes/mock/flow/family.js';
|
|
15
|
+
import { scriptFlowFamily } from './nodes/script/flow/family.js';
|
|
16
|
+
import { transformFlowFamily } from './nodes/transform/flow/family.js';
|
|
17
|
+
/** The families, in no significant order. Adding one is the whole of registering it. */
|
|
18
|
+
export const FLOW_NODE_FAMILIES = [dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, mockFlowFamily, scriptFlowFamily, transformFlowFamily];
|
|
19
|
+
export const FLOW_NODE_TYPES = new NodeTypeRegistry('flow', FLOW_NODE_FAMILIES, { hasBundledDefinition });
|