@uipath/maestro-builder-sdk 6.36.1 → 6.38.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 +85 -83
- package/dist/api-members.md +339 -335
- package/dist/bpmn/bpmn-sdk.d.ts +33 -0
- package/dist/bpmn/bpmn-sdk.js +4 -0
- package/dist/bpmn/check.js +79 -0
- package/dist/bpmn/connector-lift-verify.d.ts +32 -0
- package/dist/bpmn/connector-lift-verify.js +220 -0
- package/dist/bpmn/connector.d.ts +12 -0
- package/dist/bpmn/connector.js +19 -1
- package/dist/bpmn/declared-vars.js +10 -3
- package/dist/bpmn/decompile-cli.js +68 -6
- package/dist/bpmn/decompile.d.ts +43 -0
- package/dist/bpmn/decompile.js +274 -9
- package/dist/bpmn/intsvc.d.ts +9 -10
- package/dist/bpmn/intsvc.js +31 -18
- package/dist/bpmn/serialize.js +31 -24
- package/dist/cli-library.js +3 -1
- package/dist/core/cli-library.d.ts +8 -2
- package/dist/core/cli-library.js +6 -4
- package/dist/core/connector-resolve-error.d.ts +7 -1
- package/dist/core/event-checks.js +2 -2
- package/dist/core/lookups.d.ts +22 -0
- package/dist/core/lookups.js +34 -1
- package/dist/core/synthesized-definition.d.ts +15 -0
- package/dist/core/synthesized-definition.js +22 -0
- package/dist/registry/library-build/context.d.ts +16 -0
- package/dist/registry/library-build/context.js +32 -5
- package/dist/registry/prepare/actions.d.ts +15 -0
- package/dist/registry/prepare/actions.js +12 -1
- package/dist/registry/prepare/integration-service.d.ts +105 -0
- package/dist/registry/prepare/integration-service.js +218 -0
- package/dist/registry/prepare/messages.d.ts +41 -1
- package/dist/registry/prepare/messages.js +82 -1
- package/dist/registry/prepare/pipeline.js +73 -15
- package/dist/registry/uip/commands.d.ts +8 -0
- package/dist/registry/uip/commands.js +12 -0
- package/dist/serialize.js +11 -0
- package/lib/library-json.samples/index.json +9 -0
- package/lib/library-json.samples/uipath-uipath-dataservice/update-entity-record@1.0.0.json +132 -0
- package/lib/library-json.samples/uipath-uipath-dataservice/update-entity-record@1.0.0.v1def.json +254 -0
- package/package.json +2 -2
package/dist/bpmn/decompile.d.ts
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
|
+
import type { Library } from '../core/library.js';
|
|
1
2
|
/** Options for {@link decompile}. */
|
|
2
3
|
export interface BpmnDecompileOptions {
|
|
3
4
|
/** Module specifier for the emitted `import { bpmn }` line. */
|
|
4
5
|
importSpecifier?: string;
|
|
6
|
+
/**
|
|
7
|
+
* The connector library. With one, an `Intsvc.ActivityExecution` the library can
|
|
8
|
+
* name comes back as `.connector(key, action, inputs, { connection, folder, … })` —
|
|
9
|
+
* the call an author writes — instead of the verbatim `.activity()` form; see
|
|
10
|
+
* {@link BpmnDecompileOptions.connectors}. Without one, every connector task stays
|
|
11
|
+
* verbatim, as before.
|
|
12
|
+
*/
|
|
13
|
+
library?: Library;
|
|
14
|
+
/**
|
|
15
|
+
* How a connector task is written back when a library is given. `'lift'` (the
|
|
16
|
+
* default) names the operation through the library and drops what the SDK
|
|
17
|
+
* regenerates on compile — the `metadata` blob the canvas writes
|
|
18
|
+
* (`designTimeMetadata`, `metadataState`), the CRUD `operation` verb, row types,
|
|
19
|
+
* the response row's schema body. `'verbatim'` keeps every row as the file spells
|
|
20
|
+
* it. A lift is best effort by construction and safe only with the check
|
|
21
|
+
* `decompile-cli` runs (`verifyConnectorLifts`): the lifted call must compile to the
|
|
22
|
+
* same task, those regenerated fields aside, or the element is written verbatim.
|
|
23
|
+
*/
|
|
24
|
+
connectors?: 'lift' | 'verbatim';
|
|
25
|
+
/** Connector tasks to write verbatim whatever `connectors` says — the ones a verify refused. */
|
|
26
|
+
verbatimConnectors?: ReadonlySet<string>;
|
|
27
|
+
/** Called with what the connector lift did, after decompiling. */
|
|
28
|
+
onConnectorLift?: (summary: ConnectorLiftSummary) => void;
|
|
5
29
|
/**
|
|
6
30
|
* `'explicit'` (the default) renders the graph flat: one call per element, one
|
|
7
31
|
* `.sequenceFlow()` per edge. `'nested'` LIFTS the regions that the builder's
|
|
@@ -103,4 +127,23 @@ export interface LiftSummary {
|
|
|
103
127
|
/** Whether the top level was written in `.flowMode('sequence')`. */
|
|
104
128
|
sequence: boolean;
|
|
105
129
|
}
|
|
130
|
+
/** What the connector lift did on one decompile — see `BpmnDecompileOptions.connectors`. */
|
|
131
|
+
export interface ConnectorLiftSummary {
|
|
132
|
+
/** Element ids written as `.connector()`. */
|
|
133
|
+
lifted: string[];
|
|
134
|
+
/** Connector tasks written verbatim, each with the reason. */
|
|
135
|
+
verbatim: Array<{
|
|
136
|
+
id: string;
|
|
137
|
+
reason: string;
|
|
138
|
+
}>;
|
|
139
|
+
/**
|
|
140
|
+
* The source up to the first element — the import, the process call, its metadata,
|
|
141
|
+
* schemas, bindings and variables — so a verifier can compile one lifted call on its
|
|
142
|
+
* own (`verifyConnectorLifts`) instead of the whole process, where one refused lift
|
|
143
|
+
* would take every other down with it.
|
|
144
|
+
*/
|
|
145
|
+
preamble: string;
|
|
146
|
+
/** Each lifted call's source line, by element id. */
|
|
147
|
+
calls: Map<string, string>;
|
|
148
|
+
}
|
|
106
149
|
export declare function decompile(xml: string, options?: BpmnDecompileOptions): Promise<string>;
|
package/dist/bpmn/decompile.js
CHANGED
|
@@ -244,7 +244,225 @@ function localName(type) {
|
|
|
244
244
|
const local = type.split(':')[1] ?? type;
|
|
245
245
|
return local.charAt(0).toLowerCase() + local.slice(1);
|
|
246
246
|
}
|
|
247
|
+
// The connector lift's state for one `decompile()` call. Planned in a pre-pass so the
|
|
248
|
+
// variable block, which is written before any element, already knows which tasks come
|
|
249
|
+
// back as `.connector()` — their declarations derive differently (`derivedVariableIds`).
|
|
250
|
+
// The lift's per-decompile state. Module-level `let`s, reset at the top of `decompile()`
|
|
251
|
+
// and read while it emits: nothing awaits between the reset and the last emit, and the
|
|
252
|
+
// module is not re-entered, which is the invariant this relies on. A per-call context
|
|
253
|
+
// object is the right shape if that ever changes.
|
|
254
|
+
let runLibrary;
|
|
255
|
+
let runLiftPlans = new Map();
|
|
256
|
+
let runLiftSkipped = [];
|
|
257
|
+
let runLiftCalls = new Map();
|
|
247
258
|
/** The `uipath:*` payload element on an element, if it has one. */
|
|
259
|
+
/** Context rows a connector task carries that `.connector()` writes itself, or that the lift reads. */
|
|
260
|
+
const CONNECTOR_CONTEXT_ROWS = new Set([
|
|
261
|
+
'connectorKey', 'operation', 'objectName', 'method', 'path', 'connection', 'folderKey', 'resourceKey',
|
|
262
|
+
'metadata', 'activityConfigurationVersion', 'activity',
|
|
263
|
+
]);
|
|
264
|
+
/** Row targets `.connector()` can address — the library's parameter locations plus the body. */
|
|
265
|
+
const CONNECTOR_ROW_TARGETS = new Set(['path', 'query', 'body', 'multipart', 'file']);
|
|
266
|
+
/**
|
|
267
|
+
* Plan every connector task's lift in `container` (sub-processes included): the id →
|
|
268
|
+
* plan for the ones `.connector()` can express, and a reason for each one it cannot.
|
|
269
|
+
*/
|
|
270
|
+
function planConnectorLifts(container, skip) {
|
|
271
|
+
for (const el of container.flowElements ?? []) {
|
|
272
|
+
if (el.$type === 'bpmn:SubProcess')
|
|
273
|
+
planConnectorLifts(el, skip);
|
|
274
|
+
const payload = payloadOf(el);
|
|
275
|
+
if (!payload || extensionTypeOf(payload) !== 'Intsvc.ActivityExecution')
|
|
276
|
+
continue;
|
|
277
|
+
if (skip.has(el.id)) {
|
|
278
|
+
runLiftSkipped.push({ id: el.id, reason: 'the lift did not verify' });
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const outcome = planConnectorLift(el, payload);
|
|
282
|
+
if (typeof outcome === 'string')
|
|
283
|
+
runLiftSkipped.push({ id: el.id, reason: outcome });
|
|
284
|
+
else
|
|
285
|
+
runLiftPlans.set(el.id, outcome);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/** The `=bindings.<id>` a context value references, or `undefined` for anything else. */
|
|
289
|
+
function bindingIdOf(value) {
|
|
290
|
+
const m = typeof value === 'string' ? /^=bindings\.([A-Za-z0-9_]+)$/.exec(value) : null;
|
|
291
|
+
return m ? m[1] : undefined;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* A row's value as `.connector()` takes it: an `=`-expression as the string it is;
|
|
295
|
+
* otherwise the literal, coerced to the type the library declares for the parameter,
|
|
296
|
+
* because the file writes every scalar row as `type="string"` (`value="false"`,
|
|
297
|
+
* `value="0"`) and the shared validator refuses a string where it declares a boolean
|
|
298
|
+
* or an integer.
|
|
299
|
+
*/
|
|
300
|
+
function liftedInputValue(raw, dataType) {
|
|
301
|
+
if (raw.startsWith('='))
|
|
302
|
+
return raw;
|
|
303
|
+
switch ((dataType ?? 'string').toLowerCase()) {
|
|
304
|
+
case 'boolean':
|
|
305
|
+
return raw === 'true' ? true : raw === 'false' ? false : raw;
|
|
306
|
+
case 'integer':
|
|
307
|
+
case 'number':
|
|
308
|
+
return raw.trim() !== '' && Number.isFinite(Number(raw)) ? Number(raw) : raw;
|
|
309
|
+
default:
|
|
310
|
+
return raw;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* The `.connector()` call for one task, or why there is none. Everything here is a
|
|
315
|
+
* fact the lift needs and the generic form carries; what the SDK regenerates on
|
|
316
|
+
* compile is deliberately not read (see `BpmnDecompileOptions.connectors`).
|
|
317
|
+
*/
|
|
318
|
+
function planConnectorLift(el, payload) {
|
|
319
|
+
const library = runLibrary;
|
|
320
|
+
if (!library)
|
|
321
|
+
return 'no connector library';
|
|
322
|
+
const ctx = contextOf(payload);
|
|
323
|
+
const rows = payload.context?.input ?? [];
|
|
324
|
+
const unknownCtx = rows.map((r) => r.name).filter((n) => !CONNECTOR_CONTEXT_ROWS.has(n));
|
|
325
|
+
if (unknownCtx.length)
|
|
326
|
+
return `context row(s) .connector() does not write: ${unknownCtx.join(', ')}`;
|
|
327
|
+
if (rows.some((r) => r.required !== undefined || r.target !== undefined))
|
|
328
|
+
return 'a context row carries attributes the record form cannot';
|
|
329
|
+
const ctxString = (k) => (typeof ctx[k] === 'string' ? ctx[k] : undefined);
|
|
330
|
+
const connectorKey = ctxString('connectorKey');
|
|
331
|
+
if (!connectorKey)
|
|
332
|
+
return 'no connectorKey';
|
|
333
|
+
let identity;
|
|
334
|
+
try {
|
|
335
|
+
identity = library.identifyAction({
|
|
336
|
+
connectorKey,
|
|
337
|
+
httpMethod: ctxString('method'),
|
|
338
|
+
endpoint: ctxString('path'),
|
|
339
|
+
objectName: ctxString('objectName'),
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
return `not in the library: ${e.message}`;
|
|
344
|
+
}
|
|
345
|
+
const connection = bindingIdOf(ctx.connection);
|
|
346
|
+
if (!connection)
|
|
347
|
+
return `connection is ${ctx.connection === undefined ? 'absent' : JSON.stringify(ctx.connection)}, not a =bindings.<id> reference`;
|
|
348
|
+
const folder = ctx.folderKey === undefined ? undefined : bindingIdOf(ctx.folderKey);
|
|
349
|
+
if (ctx.folderKey !== undefined && folder === undefined)
|
|
350
|
+
return `folderKey is ${JSON.stringify(ctx.folderKey)}, not a =bindings.<id> reference`;
|
|
351
|
+
let params;
|
|
352
|
+
let declared;
|
|
353
|
+
try {
|
|
354
|
+
const resolved = library.resolve(identity.key, identity.action, identity.version, identity.object);
|
|
355
|
+
params = new Map((resolved.entry.operation?.parameters ?? []).map((p) => [p.name, p.dataType]));
|
|
356
|
+
declared = new Set([...params.keys(), ...resolved.fields.map((f) => f.name)]);
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
return `the library cannot resolve ${identity.key}/${identity.action}: ${e.message}`;
|
|
360
|
+
}
|
|
361
|
+
const inputs = {};
|
|
362
|
+
for (const row of payload.input ?? []) {
|
|
363
|
+
const target = row.target;
|
|
364
|
+
if (target === undefined || !CONNECTOR_ROW_TARGETS.has(target)) {
|
|
365
|
+
return `payload row "${row.name}" has ${target === undefined ? 'no target' : `target "${target}"`}`;
|
|
366
|
+
}
|
|
367
|
+
if (target === 'body') {
|
|
368
|
+
if (row.name !== 'body')
|
|
369
|
+
return `body row is named "${row.name}"`;
|
|
370
|
+
const body = safeJson(row.body ?? '{}');
|
|
371
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
372
|
+
return 'the body row is not a JSON object';
|
|
373
|
+
for (const [k, v] of Object.entries(body)) {
|
|
374
|
+
if (k in inputs)
|
|
375
|
+
return `"${k}" appears both as a parameter row and in the body`;
|
|
376
|
+
// `.connector()` validates every input against the library, and a field the
|
|
377
|
+
// static library does not declare — an entity's own columns on a Data Fabric
|
|
378
|
+
// update, a form's fields — is refused until `registry prepare` loads it.
|
|
379
|
+
if (!declared.has(k) && !declared.has(k.split('.')[0])) {
|
|
380
|
+
return `body field "${k}" is not in the library for ${identity.key}/${identity.action} (connection-specific; \`registry prepare\` loads it)`;
|
|
381
|
+
}
|
|
382
|
+
inputs[k] = v;
|
|
383
|
+
}
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (row.value === undefined)
|
|
387
|
+
return `payload row "${row.name}" carries no value attribute`;
|
|
388
|
+
if (row.name in inputs)
|
|
389
|
+
return `payload row "${row.name}" appears twice`;
|
|
390
|
+
inputs[row.name] = liftedInputValue(String(row.value), params.get(row.name));
|
|
391
|
+
}
|
|
392
|
+
let outputVar;
|
|
393
|
+
let errorVar;
|
|
394
|
+
const outputs = {};
|
|
395
|
+
for (const row of payload.output ?? []) {
|
|
396
|
+
const standard = (row.name === 'response' && row.source === '=response' && outputVar === undefined) ||
|
|
397
|
+
(row.name === 'Error' && row.source === '=Error' && errorVar === undefined);
|
|
398
|
+
// The two standard rows may carry a schema body — the SDK writes the library's
|
|
399
|
+
// response schema there, and regenerates it. Any other row's body, or a target or
|
|
400
|
+
// description on any row, is something `.connector()` cannot say.
|
|
401
|
+
if (row.target !== undefined || row.description !== undefined || (row.body !== undefined && !standard)) {
|
|
402
|
+
return `output row "${row.name}" carries attributes .connector() does not write`;
|
|
403
|
+
}
|
|
404
|
+
if (standard && row.name === 'response')
|
|
405
|
+
outputVar = row.var;
|
|
406
|
+
else if (standard)
|
|
407
|
+
errorVar = row.var;
|
|
408
|
+
else {
|
|
409
|
+
// An extra mapped row: `outputs` keys it by its variable, so one without a
|
|
410
|
+
// variable or a source, or a second row on the same variable, cannot be said.
|
|
411
|
+
if (typeof row.var !== 'string' || typeof row.source !== 'string')
|
|
412
|
+
return `output row "${row.name}" has no variable or no source`;
|
|
413
|
+
if (row.var in outputs)
|
|
414
|
+
return `two output rows write "${row.var}"`;
|
|
415
|
+
const plain = row.name === row.var && (row.type ?? 'string') === 'string' && !row.custom;
|
|
416
|
+
outputs[row.var] = plain
|
|
417
|
+
? row.source
|
|
418
|
+
: { source: row.source, ...(row.name !== row.var ? { name: row.name } : {}), ...((row.type ?? 'string') !== 'string' ? { type: row.type } : {}), ...(row.custom ? { custom: true } : {}) };
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return {
|
|
422
|
+
key: identity.key,
|
|
423
|
+
action: identity.action,
|
|
424
|
+
version: identity.version === '1.0.0' ? undefined : identity.version,
|
|
425
|
+
object: identity.object,
|
|
426
|
+
inputs,
|
|
427
|
+
connection,
|
|
428
|
+
folder,
|
|
429
|
+
outputVar: outputVar !== undefined && outputVar !== `${el.id}_response` ? outputVar : undefined,
|
|
430
|
+
errorVar: errorVar !== undefined && errorVar !== `${el.id}_Error` ? errorVar : undefined,
|
|
431
|
+
outputs: Object.keys(outputs).length ? outputs : undefined,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
/** The `outputs` option of a lifted connector as source. */
|
|
435
|
+
function connectorOutputsSource(outputs) {
|
|
436
|
+
return `{ ${Object.entries(outputs)
|
|
437
|
+
.map(([v, spec]) => `${key(v)}: ${typeof spec === 'string' ? tsText(spec) : opts([
|
|
438
|
+
['source', tsText(spec.source)],
|
|
439
|
+
['name', spec.name !== undefined ? tsText(spec.name) : undefined],
|
|
440
|
+
['type', spec.type !== undefined ? tsText(spec.type) : undefined],
|
|
441
|
+
['custom', spec.custom ? 'true' : undefined],
|
|
442
|
+
])}`)
|
|
443
|
+
.join(', ')} }`;
|
|
444
|
+
}
|
|
445
|
+
/** A planned connector task as its `.connector()` call. */
|
|
446
|
+
function emitConnectorLift(chain, el, payload, plan) {
|
|
447
|
+
const options = opts([
|
|
448
|
+
['name', el.name !== undefined ? tsText(el.name) : undefined],
|
|
449
|
+
['connection', tsText(plan.connection)],
|
|
450
|
+
['folder', plan.folder !== undefined ? tsText(plan.folder) : undefined],
|
|
451
|
+
['version', plan.version !== undefined ? tsText(plan.version) : undefined],
|
|
452
|
+
['object', plan.object !== undefined ? tsText(plan.object) : undefined],
|
|
453
|
+
['outputVar', plan.outputVar !== undefined ? tsText(plan.outputVar) : undefined],
|
|
454
|
+
['errorVar', plan.errorVar !== undefined ? tsText(plan.errorVar) : undefined],
|
|
455
|
+
['outputs', plan.outputs ? connectorOutputsSource(plan.outputs) : undefined],
|
|
456
|
+
['skipCondition', payload.skipCondition !== undefined ? tsText(payload.skipCondition) : undefined],
|
|
457
|
+
['tags', tagsOf(el)],
|
|
458
|
+
['retry', emitRetry(retryOf(el))],
|
|
459
|
+
['errorMapping', emitErrorMapping(errorMappingOf(el))],
|
|
460
|
+
['loop', emitLoop(el)],
|
|
461
|
+
]);
|
|
462
|
+
const call = `.connector(${tsText(el.id)}, ${tsText(plan.key)}, ${tsText(plan.action)}, ${record(plan.inputs) ?? '{}'}${optionalArg(options)})`;
|
|
463
|
+
runLiftCalls.set(el.id, call);
|
|
464
|
+
chain.add(call);
|
|
465
|
+
}
|
|
248
466
|
function payloadOf(el) {
|
|
249
467
|
for (const ext of el.extensionElements?.values ?? []) {
|
|
250
468
|
if (ext.$type === 'uipath:Activity' || ext.$type === 'uipath:Event' || ext.$type === 'uipath:Mapping')
|
|
@@ -1584,6 +1802,11 @@ function emitElement(chain, el, depth, indent) {
|
|
|
1584
1802
|
if (kind === 'startEvent' && startEventDefinitionCarriesConfig(el)) {
|
|
1585
1803
|
return emitTriggerStartEvent(chain, el, payload, type);
|
|
1586
1804
|
}
|
|
1805
|
+
// A connector task the library can name, planned in the pre-pass — see
|
|
1806
|
+
// `BpmnDecompileOptions.connectors` for what the lift gives up and how it is checked.
|
|
1807
|
+
const plan = runLiftPlans.get(el.id);
|
|
1808
|
+
if (plan)
|
|
1809
|
+
return emitConnectorLift(chain, el, payload, plan);
|
|
1587
1810
|
return emitTypedNode(chain, el, payload, type);
|
|
1588
1811
|
}
|
|
1589
1812
|
switch (kind) {
|
|
@@ -1930,7 +2153,16 @@ export async function decompile(xml, options = {}) {
|
|
|
1930
2153
|
// found none, so NOTHING was recognised as derived and every declaration was echoed
|
|
1931
2154
|
// by hand. That was invisible — an echoed declaration takes the id before
|
|
1932
2155
|
// `implicitNodeVars` can claim it, so the output was correct, just 112 lines of it.
|
|
1933
|
-
|
|
2156
|
+
// The connector lift, planned first: the variable block below needs to know which
|
|
2157
|
+
// tasks come back as `.connector()`, whose declarations derive as a connector's.
|
|
2158
|
+
runLibrary = options.library;
|
|
2159
|
+
runLiftPlans = new Map();
|
|
2160
|
+
runLiftSkipped = [];
|
|
2161
|
+
runLiftCalls = new Map();
|
|
2162
|
+
if (options.library && (options.connectors ?? 'lift') === 'lift') {
|
|
2163
|
+
planConnectorLifts(process, options.verbatimConnectors ?? new Set());
|
|
2164
|
+
}
|
|
2165
|
+
const { ids: derived, folds } = derivedVariableIds(process, varsExt, host.rehome, new Set(runLiftPlans.keys()));
|
|
1934
2166
|
const schemaPlan = planSchemas([
|
|
1935
2167
|
...(varsExt?.input ?? []),
|
|
1936
2168
|
...(varsExt?.inputOutput ?? []),
|
|
@@ -1951,12 +2183,14 @@ export async function decompile(xml, options = {}) {
|
|
|
1951
2183
|
// hand-editing". Only when something was actually folded: a document of explicit
|
|
1952
2184
|
// `.var()` calls already states its order by their position, and the extra line would
|
|
1953
2185
|
// be noise.
|
|
2186
|
+
let preambleLines = 0;
|
|
1954
2187
|
if (derived.size) {
|
|
1955
2188
|
const ids = [...(varsExt?.input ?? []), ...(varsExt?.inputOutput ?? []), ...(varsExt?.output ?? [])].map((v) => v.id);
|
|
1956
2189
|
chain.add(`.preserve({ variableOrder: [${ids.map(tsText).join(', ')}] })`);
|
|
1957
2190
|
}
|
|
1958
2191
|
try {
|
|
1959
2192
|
emitVariablesInto(chain, host.container, host.rehome?.to ?? host.container.id, derived, host.rehome, schemaPlan, publicDeclarationScopeOf(process, host.rehome?.to ?? host.container.id));
|
|
2193
|
+
preambleLines = chain.all.length;
|
|
1960
2194
|
if (options.style === 'nested') {
|
|
1961
2195
|
const sequence = options.sequenceMode ?? true;
|
|
1962
2196
|
const summary = { handlers: 0, branches: 0, nets: 0, leftFlat: [], renamedFlows: [], sequence };
|
|
@@ -1975,11 +2209,18 @@ export async function decompile(xml, options = {}) {
|
|
|
1975
2209
|
}
|
|
1976
2210
|
finally {
|
|
1977
2211
|
foldedVarSchemas = undefined;
|
|
2212
|
+
runLibrary = undefined;
|
|
1978
2213
|
}
|
|
1979
2214
|
const importFrom = options.importSpecifier ?? './bpmn-sdk.js';
|
|
1980
2215
|
const imported = ['bpmn', ...[...schemaPlan.imports].sort()].join(', ');
|
|
1981
2216
|
const head = `import { ${imported} } from ${tsText(importFrom)};\n\nexport default bpmn(${tsText(process.id)})`;
|
|
1982
2217
|
const name = process.name !== undefined ? `\n${indent}.name(${tsText(process.name)})` : '';
|
|
2218
|
+
options.onConnectorLift?.({
|
|
2219
|
+
lifted: [...runLiftPlans.keys()],
|
|
2220
|
+
verbatim: runLiftSkipped,
|
|
2221
|
+
preamble: `${host.note}${head}${name}\n${chain.all.slice(0, preambleLines).join('\n')}`,
|
|
2222
|
+
calls: runLiftCalls,
|
|
2223
|
+
});
|
|
1983
2224
|
return `${host.note}${head}${name}\n${chain.all.join('\n')}\n${indent}.build();\n`;
|
|
1984
2225
|
}
|
|
1985
2226
|
/**
|
|
@@ -2010,7 +2251,9 @@ export async function decompile(xml, options = {}) {
|
|
|
2010
2251
|
*/
|
|
2011
2252
|
function derivedVariableIds(process, varsExt,
|
|
2012
2253
|
/** The collaboration→process re-parenting, so `elementId` is compared post-move. */
|
|
2013
|
-
rehome
|
|
2254
|
+
rehome,
|
|
2255
|
+
/** Connector tasks the lift writes as `.connector()`, whose declarations `implicitNodeVars` derives as a connector's. */
|
|
2256
|
+
lifted = new Set()) {
|
|
2014
2257
|
// var id -> the declaration `implicitNodeVars` would derive for it
|
|
2015
2258
|
const candidates = new Map();
|
|
2016
2259
|
const walk = (container) => {
|
|
@@ -2032,15 +2275,37 @@ rehome) {
|
|
|
2032
2275
|
// a bodied declaration through: ten `error<n>` declarations owned by boundary
|
|
2033
2276
|
// events in `claims-triage` were skipped as derived and then nobody derived them
|
|
2034
2277
|
// — they vanished from the recompiled process.
|
|
2035
|
-
|
|
2278
|
+
// A script task's default payload type is `BPMN.Variables` — the same type a
|
|
2279
|
+
// variable-assignment task carries, which derives nothing. The script task with
|
|
2280
|
+
// spelled-out rows is admitted by its element, not its type: those rows are the
|
|
2281
|
+
// declaration on the way back in (`implicitNodeVars`' script arm), so they are
|
|
2282
|
+
// skipped here too, or the source redeclares every one of them in `.vars()`.
|
|
2283
|
+
const spelledOutScriptRows = localName(el.$type) === 'scriptTask' && type === 'BPMN.Variables' && outputRowsNeedSpellingOut(payload);
|
|
2284
|
+
if (payload && type && (spelledOutScriptRows || (type !== 'BPMN.Variables' && typeDescribesElement(localName(el.$type), type)))) {
|
|
2036
2285
|
for (const row of payload.output ?? []) {
|
|
2037
2286
|
if (!row.var)
|
|
2038
2287
|
continue;
|
|
2039
|
-
// A
|
|
2040
|
-
//
|
|
2041
|
-
//
|
|
2042
|
-
//
|
|
2043
|
-
|
|
2288
|
+
// A lifted connector's two variables are claimed the way `.connector()` claims
|
|
2289
|
+
// them — `json`, named after the id, no schema — so a file's own `jsonSchema`
|
|
2290
|
+
// declaration with a body stays an explicit `.var()` rather than being folded
|
|
2291
|
+
// onto a row the lifted call no longer has.
|
|
2292
|
+
if (lifted.has(el.id)) {
|
|
2293
|
+
// A `.connector()` call has no row to fold a declaration's schema onto, so
|
|
2294
|
+
// a declaration that carries one stays explicit whatever its wire type —
|
|
2295
|
+
// `noFold` below — rather than vanishing into `foldedVarSchemas`, which the
|
|
2296
|
+
// lift never reads.
|
|
2297
|
+
// The wire type the row implies: `json` for the response and Error rows, the
|
|
2298
|
+
// row's own for an extra mapped row (`integer`), as `implicitNodeVars` declares.
|
|
2299
|
+
candidates.set(row.var, { owner: el.id, wire: rowDeclaration({ name: row.name, type: row.type }).wire, noFold: true });
|
|
2300
|
+
continue;
|
|
2301
|
+
}
|
|
2302
|
+
// A script task's rows come back as `outputs` when that form reproduces
|
|
2303
|
+
// them, and `implicitNodeVars` then derives their declarations from the
|
|
2304
|
+
// keys: id as the name, that arm's own wire type. Rows that need spelling
|
|
2305
|
+
// out (`emitScriptTask` writes `outputRows` exactly when this holds) are
|
|
2306
|
+
// declared through `rowDeclaration` on the way back in, like every other
|
|
2307
|
+
// typed node's, so they are matched the same way here.
|
|
2308
|
+
candidates.set(row.var, type === 'BPMN.ScriptTask' && !outputRowsNeedSpellingOut(payload)
|
|
2044
2309
|
? { owner: el.id, wire: 'string' }
|
|
2045
2310
|
: { owner: el.id, ...rowDeclaration({ name: row.name, type: row.type, schema: row.body }) });
|
|
2046
2311
|
}
|
|
@@ -2084,7 +2349,7 @@ rehome) {
|
|
|
2084
2349
|
// against 28 rows, so without the fold almost every structured output stays an
|
|
2085
2350
|
// explicit `.var()`.
|
|
2086
2351
|
if (String(v.body ?? '') !== String(c.schema ?? '')) {
|
|
2087
|
-
if (c.schema !== undefined || v.body === undefined)
|
|
2352
|
+
if (c.schema !== undefined || v.body === undefined || c.noFold)
|
|
2088
2353
|
continue;
|
|
2089
2354
|
folds.set(v.id, v.body);
|
|
2090
2355
|
}
|
package/dist/bpmn/intsvc.d.ts
CHANGED
|
@@ -35,11 +35,11 @@ type ExternalNode = Extract<BpmnNode, {
|
|
|
35
35
|
/**
|
|
36
36
|
* The extension type a Phase 3d node lowers to, WITHOUT consulting the library.
|
|
37
37
|
*
|
|
38
|
-
* The
|
|
39
|
-
* `
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
38
|
+
* The method the author called decides the placement — `.eventTrigger()` a start
|
|
39
|
+
* event, `.waitForEvent()` a receive task — so the type is known from the node alone,
|
|
40
|
+
* and the serializer can declare the node's output variable before it has resolved
|
|
41
|
+
* anything. The emitter uses this same value; the library only has to say the
|
|
42
|
+
* operation is a connector event.
|
|
43
43
|
*/
|
|
44
44
|
export declare function intsvcServiceType(n: EventNode | ExternalNode): string;
|
|
45
45
|
/**
|
|
@@ -55,11 +55,10 @@ export declare function intsvcOutputVar(n: EventNode | ExternalNode): string | u
|
|
|
55
55
|
/**
|
|
56
56
|
* A connector event node — `Intsvc.EventTrigger` or `Intsvc.WaitForEvent`.
|
|
57
57
|
*
|
|
58
|
-
* The extension type comes from the
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* receive task — a mismatch both offline validators accept.
|
|
58
|
+
* The extension type comes from the method the author called; the library only has
|
|
59
|
+
* to say the operation is a connector event (`runtime.serviceType` is one of the
|
|
60
|
+
* event types). A prepared descriptor carries the START form's runtime whichever
|
|
61
|
+
* method reaches it, so the placement, not the descriptor, decides the type.
|
|
63
62
|
*
|
|
64
63
|
* @param ctx - Serializer context: moddle, library, bindings, binding sink.
|
|
65
64
|
* @param n - The authored node.
|
package/dist/bpmn/intsvc.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createTypedNode, typedNodeOutputVar } from './typed-node.js';
|
|
2
2
|
import { connectorBindingRef } from './connector.js';
|
|
3
3
|
import { eventFilterJmes, eventFilterProblem, jmesString, jmesStringProblem, readEventFilter } from '../core/event-filters.js';
|
|
4
|
+
import { resolveEventWhere } from '../core/lookups.js';
|
|
4
5
|
/**
|
|
5
6
|
* Which extension type an external invocation lowers to.
|
|
6
7
|
*
|
|
@@ -19,11 +20,11 @@ const EVENT_SERVICE_TYPE = { trigger: 'Intsvc.EventTrigger', event: 'Intsvc.Wait
|
|
|
19
20
|
/**
|
|
20
21
|
* The extension type a Phase 3d node lowers to, WITHOUT consulting the library.
|
|
21
22
|
*
|
|
22
|
-
* The
|
|
23
|
-
* `
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* The method the author called decides the placement — `.eventTrigger()` a start
|
|
24
|
+
* event, `.waitForEvent()` a receive task — so the type is known from the node alone,
|
|
25
|
+
* and the serializer can declare the node's output variable before it has resolved
|
|
26
|
+
* anything. The emitter uses this same value; the library only has to say the
|
|
27
|
+
* operation is a connector event.
|
|
27
28
|
*/
|
|
28
29
|
export function intsvcServiceType(n) {
|
|
29
30
|
return n.kind === 'connectorEvent'
|
|
@@ -45,11 +46,10 @@ export function intsvcOutputVar(n) {
|
|
|
45
46
|
/**
|
|
46
47
|
* A connector event node — `Intsvc.EventTrigger` or `Intsvc.WaitForEvent`.
|
|
47
48
|
*
|
|
48
|
-
* The extension type comes from the
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* receive task — a mismatch both offline validators accept.
|
|
49
|
+
* The extension type comes from the method the author called; the library only has
|
|
50
|
+
* to say the operation is a connector event (`runtime.serviceType` is one of the
|
|
51
|
+
* event types). A prepared descriptor carries the START form's runtime whichever
|
|
52
|
+
* method reaches it, so the placement, not the descriptor, decides the type.
|
|
53
53
|
*
|
|
54
54
|
* @param ctx - Serializer context: moddle, library, bindings, binding sink.
|
|
55
55
|
* @param n - The authored node.
|
|
@@ -67,14 +67,20 @@ export function createConnectorEvent(ctx, n) {
|
|
|
67
67
|
throw new Error(`connector event ${n.key}/${n.eventName} has no runtime.serviceType in the library; ` +
|
|
68
68
|
`it cannot be authored as a BPMN node.`);
|
|
69
69
|
}
|
|
70
|
-
// The
|
|
71
|
-
//
|
|
72
|
-
//
|
|
70
|
+
// The PLACEMENT decides the extension type — `.eventTrigger()` starts the
|
|
71
|
+
// process (`Intsvc.EventTrigger`), `.waitForEvent()` pauses it (`Intsvc.WaitForEvent`)
|
|
72
|
+
// — and the serializer has already declared this node's output variable from it
|
|
73
|
+
// (`intsvcServiceType`). The library's `runtime.serviceType` only has to agree
|
|
74
|
+
// that the operation IS a connector event: the platform ships one operation for
|
|
75
|
+
// both placements, the baked library carries the wait form under `.event.`, and
|
|
76
|
+
// `prepare` writes the same entry with the START form's runtime block (measured
|
|
77
|
+
// on `uipath-microsoft-outlook365/email-received`, 2026-10-16) — so reading the
|
|
78
|
+
// placement off that field refused every prepared `.waitForEvent()` with "use
|
|
79
|
+
// .eventTrigger() instead", while the unprepared same node compiled.
|
|
73
80
|
const expected = intsvcServiceType(n);
|
|
74
|
-
if (type !==
|
|
81
|
+
if (type !== 'Intsvc.EventTrigger' && type !== 'Intsvc.WaitForEvent') {
|
|
75
82
|
throw new Error(`connector event "${n.id}" was authored as a ${n.subscribe} (${expected}), but the library ` +
|
|
76
|
-
`describes ${n.key}/${n.eventName} as ${type}
|
|
77
|
-
`${type === 'Intsvc.EventTrigger' ? '.eventTrigger()' : '.waitForEvent()'} instead.`);
|
|
83
|
+
`describes ${n.key}/${n.eventName} as ${type}, which is not a connector event.`);
|
|
78
84
|
}
|
|
79
85
|
const conn = connectorBindingRef(ctx, n.connection, 'Connection', 'ConnectionId', `${rc.connectorKey} connection`);
|
|
80
86
|
const folder = connectorBindingRef(ctx, n.folder, 'Connection', 'folderKey', 'FolderKey', conn?.resourceKey);
|
|
@@ -108,10 +114,17 @@ export function createConnectorEvent(ctx, n) {
|
|
|
108
114
|
// The expression is the scope's equality clauses AND-joined with the authored
|
|
109
115
|
// `filters`, each lowered by the designer's own grammar (`core/event-filters.ts`) — the
|
|
110
116
|
// same lowering the Flow serializer does for `onEvent`/`waitForEvent`.
|
|
111
|
-
|
|
117
|
+
// A `lookup()` token in the scope is replaced by the id `prepare --resolve`
|
|
118
|
+
// recorded, as Flow's and Case's serializers do; an unrecorded one is refused
|
|
119
|
+
// with the command that records it. Stringified, a token was `[object Object]`.
|
|
120
|
+
const scope = resolveEventWhere(n.filter, ctx.library.lookupResolutions, `connector event "${n.id}"`);
|
|
121
|
+
inputs.body = eventFilterBody(n.id, scope, n.filters);
|
|
112
122
|
if (n.parameters !== undefined)
|
|
113
123
|
inputs.parameters = n.parameters;
|
|
114
|
-
return createTypedNode(ctx.m, n.id,
|
|
124
|
+
return createTypedNode(ctx.m, n.id,
|
|
125
|
+
// The placement's type, so a prepared `.event.` entry carrying the start form's
|
|
126
|
+
// runtime cannot turn a wait into a start event (see the check above).
|
|
127
|
+
expected, {
|
|
115
128
|
name: n.name ?? rc.entry.display?.label ?? n.eventName,
|
|
116
129
|
inputs,
|
|
117
130
|
outputVar: n.outputVar,
|
package/dist/bpmn/serialize.js
CHANGED
|
@@ -85,6 +85,7 @@ export async function serialize(built, opts = {}) {
|
|
|
85
85
|
schemas: built.schemas,
|
|
86
86
|
variableOrder: built.preservation?.variableOrder,
|
|
87
87
|
bindingSink: new Map(),
|
|
88
|
+
declaredBindings: new Map(built.bindings.map((b) => [b.id, { name: b.name, default: b.default, resourceKey: b.resourceKey }])),
|
|
88
89
|
varTypeOf: (varId) => authoredVarType.get(varId),
|
|
89
90
|
};
|
|
90
91
|
// `.name()` was accepted by the builder, stored on the built graph, and never
|
|
@@ -154,14 +155,7 @@ export async function serialize(built, opts = {}) {
|
|
|
154
155
|
version: meta.caseManagement.version,
|
|
155
156
|
value: meta.caseManagement.value,
|
|
156
157
|
}));
|
|
157
|
-
//
|
|
158
|
-
// Derived from the GRAPH, not from whether connector wiring happened to produce
|
|
159
|
-
// a binding: a connector with no connection/folder produced no binding and so
|
|
160
|
-
// used to lose the marker, and a DECOMPILED connector — which carries explicit
|
|
161
|
-
// `.binding()` calls rather than derived ones — lost it too.
|
|
162
|
-
if (allNodes(built.nodes).some(isIntsvcConnectorNode)) {
|
|
163
|
-
processExt.push(m.create('uipath:IntsvcActivityConfig', { version: 'v2' }));
|
|
164
|
-
}
|
|
158
|
+
// No process `intsvcActivityConfig`: the CLI packs Connection rows only for V1 nodes (https://github.com/UiPath/builder-sdk/issues/1298 tracks V2).
|
|
165
159
|
if (processExt.length)
|
|
166
160
|
processProps.extensionElements = m.create('bpmn:ExtensionElements', { values: processExt });
|
|
167
161
|
processProps.flowElements = flowElements;
|
|
@@ -671,6 +665,14 @@ export function implicitNodeVars(nodes, declared) {
|
|
|
671
665
|
const { response, error } = connectorOutputVars(n);
|
|
672
666
|
claim(response, n.id);
|
|
673
667
|
claim(error, n.id);
|
|
668
|
+
// An extra mapped row declares its variable as the row is typed (`string` when the
|
|
669
|
+
// row says nothing), not as `object`: `{ poCount: { source, type: 'integer' } }`
|
|
670
|
+
// writes an `integer` row and must declare an integer.
|
|
671
|
+
for (const [varId, spec] of Object.entries(n.outputs ?? {})) {
|
|
672
|
+
const row = typeof spec === 'string' ? { source: spec } : spec;
|
|
673
|
+
const d = rowDeclaration({ name: row.name ?? varId, type: row.type ?? 'string' });
|
|
674
|
+
claim(varId, n.id, d.type, d);
|
|
675
|
+
}
|
|
674
676
|
}
|
|
675
677
|
else if (n.kind === 'typed') {
|
|
676
678
|
// Shared with the expression checker rather than repeated here. Repeating it is
|
|
@@ -711,13 +713,27 @@ export function implicitNodeVars(nodes, declared) {
|
|
|
711
713
|
claim(typedNodeOutputVar(n.id, n.trigger.type, n.trigger.outputVar), n.id);
|
|
712
714
|
}
|
|
713
715
|
else if (n.kind === 'scriptTask') {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
716
|
+
if (n.outputRows) {
|
|
717
|
+
// Spelled-out rows state their declaration, as a typed node's do — the same
|
|
718
|
+
// `rowDeclaration` call, so `nodeDeclaredVars`, this, and decompile's skip set
|
|
719
|
+
// agree. Deriving from `outputs` alone here left a script task authored with
|
|
720
|
+
// `outputRows` declaring nothing on the wire: the checker (once it counted the
|
|
721
|
+
// rows) passed, and `uip maestro bpmn validate` reported MISSING_ROOT_VARIABLE
|
|
722
|
+
// on the task and VARIABLE_DOES_NOT_EXIST on every read of its variables.
|
|
723
|
+
for (const row of n.outputRows) {
|
|
724
|
+
const d = rowDeclaration(row);
|
|
725
|
+
claim(row.var, n.id, d.type, d);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
// `object` (emitted as `json`), not `string`. Under the v3 contract a script
|
|
730
|
+
// returns `{ response: <whatever it returned> }`, so an output nobody declared
|
|
731
|
+
// holds arbitrary JSON — declaring a number or an object as `string` is the
|
|
732
|
+
// mis-declaration this fallback exists to avoid. An output the AUTHOR declared
|
|
733
|
+
// keeps its own type: `claim` skips an id already taken.
|
|
734
|
+
for (const varId of Object.keys(n.outputs))
|
|
735
|
+
claim(varId, n.id);
|
|
736
|
+
}
|
|
721
737
|
}
|
|
722
738
|
}
|
|
723
739
|
return out;
|
|
@@ -950,15 +966,6 @@ export function publicDeclarationScope(nodes, processId) {
|
|
|
950
966
|
function cap(s) {
|
|
951
967
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
952
968
|
}
|
|
953
|
-
/**
|
|
954
|
-
* Whether a node is an Integration Service connector activity — the `.connector()`
|
|
955
|
-
* method, or the same extension types reached through `.activity()`.
|
|
956
|
-
*/
|
|
957
|
-
function isIntsvcConnectorNode(n) {
|
|
958
|
-
if (n.kind === 'connector')
|
|
959
|
-
return true;
|
|
960
|
-
return n.kind === 'typed' && (n.type === 'Intsvc.ActivityExecution' || n.type === 'Intsvc.AsyncExecution');
|
|
961
|
-
}
|
|
962
969
|
/** Flatten a scope's nodes (recursing sub-processes) for global scans. */
|
|
963
970
|
export function allNodes(nodes) {
|
|
964
971
|
const out = [];
|
package/dist/cli-library.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { connectorCheckOpts } from './core/cli-library.js';
|
|
2
|
+
import { synthesizedDefinitionRefusal } from './core/synthesized-definition.js';
|
|
2
3
|
import { connectorInputErrors } from './serialize.js';
|
|
3
4
|
export { openCliLibrary, connectorCheckOpts, eventResolveErrorFor, byoaCheckOpts } from './core/cli-library.js';
|
|
4
5
|
/**
|
|
@@ -10,7 +11,8 @@ export { openCliLibrary, connectorCheckOpts, eventResolveErrorFor, byoaCheckOpts
|
|
|
10
11
|
* cannot disagree.
|
|
11
12
|
*/
|
|
12
13
|
export function flowCheckOpts(library, bindings) {
|
|
13
|
-
|
|
14
|
+
// Flow's own refusal of an operation `prepare` synthesized from Integration Service (BPMN-only).
|
|
15
|
+
const shared = connectorCheckOpts(library, bindings, connectorInputErrors, synthesizedDefinitionRefusal);
|
|
14
16
|
if (!library)
|
|
15
17
|
return shared;
|
|
16
18
|
return {
|