@uipath/maestro-builder-sdk 6.35.1 → 6.36.1
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 +31 -29
- package/dist/api-members.md +156 -155
- package/dist/bpmn/bpmn-sdk.d.ts +38 -9
- package/dist/bpmn/bpmn-sdk.js +104 -28
- package/dist/bpmn/declared-vars.js +2 -2
- package/dist/bpmn/decompile.js +24 -4
- package/dist/bpmn/registry-types.json +30 -24
- package/dist/bpmn/resource-key-pattern.d.ts +38 -0
- package/dist/bpmn/resource-key-pattern.js +47 -0
- package/dist/bpmn/typed-node.d.ts +17 -0
- package/dist/bpmn/typed-node.js +19 -0
- package/dist/flow-sdk.d.ts +70 -2
- package/dist/flow-sdk.js +72 -0
- package/package.json +2 -2
package/dist/bpmn/bpmn-sdk.d.ts
CHANGED
|
@@ -2454,6 +2454,17 @@ declare abstract class ScopeBuilder {
|
|
|
2454
2454
|
* is left alone.
|
|
2455
2455
|
*/
|
|
2456
2456
|
private bindRequiredContext;
|
|
2457
|
+
/**
|
|
2458
|
+
* A binding field's resource key from its `resourceKeyPattern`, with the declared
|
|
2459
|
+
* bindings the key was read through — or `undefined` when the pattern does not
|
|
2460
|
+
* resolve from this context (see `resolveResourceKeyPattern`), in which case the
|
|
2461
|
+
* caller keys the binding by the value, as it always has.
|
|
2462
|
+
*
|
|
2463
|
+
* @throws when the pattern resolves except for a `=bindings.<b>` reference that no
|
|
2464
|
+
* `.binding()` before this node declares with a value: that key would otherwise be
|
|
2465
|
+
* built, so the author is told what to declare rather than given a wrong pair.
|
|
2466
|
+
*/
|
|
2467
|
+
private resourceKeyFromPattern;
|
|
2457
2468
|
/** @internal Shared body of the Orchestrator process-invocation methods. */
|
|
2458
2469
|
private orchestratorNode;
|
|
2459
2470
|
/**
|
|
@@ -2530,12 +2541,23 @@ declare abstract class ScopeBuilder {
|
|
|
2530
2541
|
*
|
|
2531
2542
|
* @remarks
|
|
2532
2543
|
* **Not a DMN decision table**, despite the element and the label. The registry spec
|
|
2533
|
-
* is an Orchestrator process invocation — `
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2536
|
-
* package
|
|
2537
|
-
*
|
|
2538
|
-
*
|
|
2544
|
+
* is an Orchestrator process invocation — `name`/`folderPath` plus `JobArguments` —
|
|
2545
|
+
* structurally a {@link ScopeBuilder.startProcess}. `process` names a package whose
|
|
2546
|
+
* Orchestrator process type is `BusinessRules`; whatever decision logic exists lives
|
|
2547
|
+
* INSIDE that package, not in the `.bpmn`. So this is the job-start family's sixth
|
|
2548
|
+
* member, not a rules subsystem.
|
|
2549
|
+
*
|
|
2550
|
+
* Where it departs from the family, the registry says so and this follows it:
|
|
2551
|
+
*
|
|
2552
|
+
* - the task is `version="v3"` — below v3 the engine cannot run the `.uirule`
|
|
2553
|
+
* package a BusinessRules project deploys — so a rule is always addressed by
|
|
2554
|
+
* name, and `releaseKey` / `folderKey` are refused;
|
|
2555
|
+
* - `name` and `folderPath` are each bound to a `BusinessRule` resource
|
|
2556
|
+
* (`propertyAttribute` `name` / `folderPath`), both keyed `<folder>.<name>`
|
|
2557
|
+
* (`<name>` alone when the folder is empty), declared on your behalf as
|
|
2558
|
+
* `<id>_name` / `<id>_folderPath`; an unbound `_label` carries the rule's name;
|
|
2559
|
+
* - two output rows: `output` (`=result`, in `outputVar`) and `Error` (`=Error`,
|
|
2560
|
+
* in `<id>_Error`), both `jsonSchema`.
|
|
2539
2561
|
*
|
|
2540
2562
|
* Distinct from the Case SDK's `rule()`, which declares DNF lifecycle conditions
|
|
2541
2563
|
* (`case-entered`, `required-tasks-completed`, …) deciding when a stage enters or
|
|
@@ -2555,7 +2577,7 @@ declare abstract class ScopeBuilder {
|
|
|
2555
2577
|
* process: 'DiscountTier',
|
|
2556
2578
|
* folder: 'Finance',
|
|
2557
2579
|
* input: { amount: 4200 },
|
|
2558
|
-
* outputs: { tier: '=
|
|
2580
|
+
* outputs: { tier: '=result.DiscountTier.tier' },
|
|
2559
2581
|
* })
|
|
2560
2582
|
* .endEvent('done')
|
|
2561
2583
|
* .sequenceFlow('start', 'tier')
|
|
@@ -2564,9 +2586,16 @@ declare abstract class ScopeBuilder {
|
|
|
2564
2586
|
* ```
|
|
2565
2587
|
*
|
|
2566
2588
|
* @param id - The element id, unique in the process and used by `sequenceFlow`.
|
|
2589
|
+
*
|
|
2590
|
+
* **The result is keyed by decision name.** The platform's `output` row is the whole
|
|
2591
|
+
* result (`source="=result"`) and a decision's column reads as
|
|
2592
|
+
* `=result.<Decision>.<column>` — `vars.<id>_businessRuleResponse.<Decision>.<column>`
|
|
2593
|
+
* downstream — never `=result.<column>` (canvas spec `outputNotes`; `uip rules describe
|
|
2594
|
+
* <name>` lists the decisions and columns, and only a decision-keyed rule, one whose
|
|
2595
|
+
* `OutputArguments` carry `x-uipath-decision-keyed`, fits this row).
|
|
2567
2596
|
* @param opts - Which rule package, folder, and input arguments. `outputVar` defaults
|
|
2568
|
-
* to `<id>_businessRuleResponse`
|
|
2569
|
-
*
|
|
2597
|
+
* to `<id>_businessRuleResponse`. `releaseKey` and `folderKey` are refused: a v3 rule
|
|
2598
|
+
* is addressed by name.
|
|
2570
2599
|
* @param body - Boundary events attached to this activity, declared on the {@link ActivityBuilder} it receives.
|
|
2571
2600
|
* @returns This builder, so calls chain.
|
|
2572
2601
|
*/
|
package/dist/bpmn/bpmn-sdk.js
CHANGED
|
@@ -3,6 +3,7 @@ import { checkBpmnExpressions, BpmnBuildError } from './bpmn-expr-check.js';
|
|
|
3
3
|
import { BPMN_SCHEMA_VERSIONS } from './format-profile.js';
|
|
4
4
|
import { schemaVersionRefusal } from '../schema-version.js';
|
|
5
5
|
import { bindingRequiredFields, REGISTRY_GAPS, registryType } from './typed-node.js';
|
|
6
|
+
import { resolveResourceKeyPattern } from './resource-key-pattern.js';
|
|
6
7
|
import { DATA_SERVICE_ACTIVITY_TYPE, DATA_SERVICE_CONNECTOR_KEY, dataServiceWire } from './data-service.js';
|
|
7
8
|
import { ownEntry } from '../core/own-entry.js';
|
|
8
9
|
export { BpmnBuildError } from './bpmn-expr-check.js';
|
|
@@ -1213,22 +1214,75 @@ class ScopeBuilder {
|
|
|
1213
1214
|
if (typeof value !== 'string' || value.startsWith('='))
|
|
1214
1215
|
continue;
|
|
1215
1216
|
const bindingId = `${id}_${field.name}`;
|
|
1217
|
+
// The key a pattern builds from the context values — a `=bindings.<b>` value as
|
|
1218
|
+
// the DECLARED value of `b`, since a key is never evaluated as an expression.
|
|
1219
|
+
// Resolved only for the fields the pattern names, and refused only when the
|
|
1220
|
+
// pattern would otherwise resolve: a pattern that names nothing the context has
|
|
1221
|
+
// (`${metadata.key}`, the live registry's pattern on a job start, whose context
|
|
1222
|
+
// has no `key`) leaves the key to the value, as before. This snapshot carries no
|
|
1223
|
+
// pattern for the job starts at all; `resource-key-pattern.ts` is tested on both.
|
|
1224
|
+
const keyed = this.resourceKeyFromPattern(id, type, field, context);
|
|
1216
1225
|
this._bindingRegistry.declare({
|
|
1217
1226
|
id: bindingId,
|
|
1218
1227
|
name: field.displayName ?? field.name,
|
|
1219
1228
|
resource: field.bindingInfo?.resource ?? 'process',
|
|
1220
1229
|
propertyAttribute: field.bindingInfo?.propertyAttribute ?? field.name,
|
|
1221
|
-
// A fact the registry omits and the validator enforces — see REGISTRY_GAPS.
|
|
1222
1230
|
resourceSubType: ownEntry(REGISTRY_GAPS, type)?.resourceSubType,
|
|
1223
1231
|
default: value,
|
|
1224
|
-
resourceKey: value,
|
|
1232
|
+
resourceKey: keyed?.key ?? value,
|
|
1225
1233
|
});
|
|
1234
|
+
// A declared binding the key was read from shares it when the author left its own
|
|
1235
|
+
// key unset, so the pair names one resource — only when the pattern resolved. One
|
|
1236
|
+
// that already carries a DIFFERENT key (a folder binding two rules share, or an
|
|
1237
|
+
// author's own key) would make this node's pair name two resources: refused, with
|
|
1238
|
+
// the binding to declare instead.
|
|
1239
|
+
if (keyed) {
|
|
1240
|
+
for (const decl of keyed.referenced) {
|
|
1241
|
+
if (decl.resourceKey === undefined)
|
|
1242
|
+
decl.resourceKey = keyed.key;
|
|
1243
|
+
else if (decl.resourceKey !== keyed.key) {
|
|
1244
|
+
const resource = field.bindingInfo?.resource ?? 'process';
|
|
1245
|
+
throw new Error(`${type} "${id}": its ${resource} key "${keyed.key}" is read through =bindings.${decl.id}, whose resource key is already ` +
|
|
1246
|
+
`"${decl.resourceKey}" (another node's pair, or the binding's own), so the pair would name two resources. ` +
|
|
1247
|
+
`A ${resource} binding names one: declare one per node, e.g. ` +
|
|
1248
|
+
`\`.binding('${decl.id}_${id}', { resource: '${decl.resource}', propertyAttribute: '${decl.propertyAttribute}', value: '${decl.default}' })\`.`);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1226
1252
|
out[field.name] = `=bindings.${bindingId}`;
|
|
1227
1253
|
}
|
|
1228
1254
|
return out;
|
|
1229
1255
|
}
|
|
1256
|
+
/**
|
|
1257
|
+
* A binding field's resource key from its `resourceKeyPattern`, with the declared
|
|
1258
|
+
* bindings the key was read through — or `undefined` when the pattern does not
|
|
1259
|
+
* resolve from this context (see `resolveResourceKeyPattern`), in which case the
|
|
1260
|
+
* caller keys the binding by the value, as it always has.
|
|
1261
|
+
*
|
|
1262
|
+
* @throws when the pattern resolves except for a `=bindings.<b>` reference that no
|
|
1263
|
+
* `.binding()` before this node declares with a value: that key would otherwise be
|
|
1264
|
+
* built, so the author is told what to declare rather than given a wrong pair.
|
|
1265
|
+
*/
|
|
1266
|
+
resourceKeyFromPattern(id, type, field, context) {
|
|
1267
|
+
const pattern = field.bindingInfo?.resourceKeyPattern;
|
|
1268
|
+
const byId = (bindingId) => this._bindingRegistry.bindings.find((b) => b.id === bindingId);
|
|
1269
|
+
const resolved = resolveResourceKeyPattern(pattern, context, byId);
|
|
1270
|
+
if (resolved === undefined)
|
|
1271
|
+
return undefined;
|
|
1272
|
+
if ('blocked' in resolved) {
|
|
1273
|
+
const { field: blockedField, ref } = resolved.blocked;
|
|
1274
|
+
const refId = ref.slice('=bindings.'.length);
|
|
1275
|
+
const resource = field.bindingInfo?.resource ?? 'process';
|
|
1276
|
+
throw new Error(`${type} "${id}": ${blockedField} reads ${ref}, which no .binding() declares with a value before this node, ` +
|
|
1277
|
+
`so the ${resource} key \`${pattern}\` it is paired under cannot be built. Declare ` +
|
|
1278
|
+
`\`.binding('${refId}', { resource: '${resource}', propertyAttribute: '${blockedField}', value: '…' })\` first, or pass the value itself.`);
|
|
1279
|
+
}
|
|
1280
|
+
return { key: resolved.key, referenced: resolved.referenced.map((bid) => byId(bid)).filter((d) => d !== undefined) };
|
|
1281
|
+
}
|
|
1230
1282
|
/** @internal Shared body of the Orchestrator process-invocation methods. */
|
|
1231
|
-
orchestratorNode(id, type, opts, body
|
|
1283
|
+
orchestratorNode(id, type, opts, body,
|
|
1284
|
+
/** A member's own departures from the family: the business rule's v3 stamp and `_label`. */
|
|
1285
|
+
own = {}) {
|
|
1232
1286
|
// The `uipath:type` version selects the engine's addressing branch — see
|
|
1233
1287
|
// OrchestratorOpts.process. By name → v2 (`name` + `folderPath`); by key → v1
|
|
1234
1288
|
// (`releaseKey` + `folderKey`). A literal release key becomes a `process`/`Key`
|
|
@@ -1254,12 +1308,13 @@ class ScopeBuilder {
|
|
|
1254
1308
|
id,
|
|
1255
1309
|
name: opts.name,
|
|
1256
1310
|
type,
|
|
1257
|
-
typeVersion: byKey ? 'v1' : 'v2',
|
|
1311
|
+
typeVersion: own.typeVersion ?? (byKey ? 'v1' : 'v2'),
|
|
1258
1312
|
context: this.bindRequiredContext(id, type, {
|
|
1259
1313
|
name: opts.process,
|
|
1260
1314
|
...(opts.folder !== undefined ? { folderPath: opts.folder } : {}),
|
|
1261
1315
|
...(releaseKey !== undefined ? { releaseKey } : {}),
|
|
1262
1316
|
...(byKey && opts.folderKey !== undefined ? { folderKey: opts.folderKey } : {}),
|
|
1317
|
+
...(own.context ?? {}),
|
|
1263
1318
|
}),
|
|
1264
1319
|
inputs: opts.input ?? {},
|
|
1265
1320
|
outputs: opts.outputs,
|
|
@@ -1355,12 +1410,23 @@ class ScopeBuilder {
|
|
|
1355
1410
|
*
|
|
1356
1411
|
* @remarks
|
|
1357
1412
|
* **Not a DMN decision table**, despite the element and the label. The registry spec
|
|
1358
|
-
* is an Orchestrator process invocation — `
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1361
|
-
* package
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1413
|
+
* is an Orchestrator process invocation — `name`/`folderPath` plus `JobArguments` —
|
|
1414
|
+
* structurally a {@link ScopeBuilder.startProcess}. `process` names a package whose
|
|
1415
|
+
* Orchestrator process type is `BusinessRules`; whatever decision logic exists lives
|
|
1416
|
+
* INSIDE that package, not in the `.bpmn`. So this is the job-start family's sixth
|
|
1417
|
+
* member, not a rules subsystem.
|
|
1418
|
+
*
|
|
1419
|
+
* Where it departs from the family, the registry says so and this follows it:
|
|
1420
|
+
*
|
|
1421
|
+
* - the task is `version="v3"` — below v3 the engine cannot run the `.uirule`
|
|
1422
|
+
* package a BusinessRules project deploys — so a rule is always addressed by
|
|
1423
|
+
* name, and `releaseKey` / `folderKey` are refused;
|
|
1424
|
+
* - `name` and `folderPath` are each bound to a `BusinessRule` resource
|
|
1425
|
+
* (`propertyAttribute` `name` / `folderPath`), both keyed `<folder>.<name>`
|
|
1426
|
+
* (`<name>` alone when the folder is empty), declared on your behalf as
|
|
1427
|
+
* `<id>_name` / `<id>_folderPath`; an unbound `_label` carries the rule's name;
|
|
1428
|
+
* - two output rows: `output` (`=result`, in `outputVar`) and `Error` (`=Error`,
|
|
1429
|
+
* in `<id>_Error`), both `jsonSchema`.
|
|
1364
1430
|
*
|
|
1365
1431
|
* Distinct from the Case SDK's `rule()`, which declares DNF lifecycle conditions
|
|
1366
1432
|
* (`case-entered`, `required-tasks-completed`, …) deciding when a stage enters or
|
|
@@ -1380,7 +1446,7 @@ class ScopeBuilder {
|
|
|
1380
1446
|
* process: 'DiscountTier',
|
|
1381
1447
|
* folder: 'Finance',
|
|
1382
1448
|
* input: { amount: 4200 },
|
|
1383
|
-
* outputs: { tier: '=
|
|
1449
|
+
* outputs: { tier: '=result.DiscountTier.tier' },
|
|
1384
1450
|
* })
|
|
1385
1451
|
* .endEvent('done')
|
|
1386
1452
|
* .sequenceFlow('start', 'tier')
|
|
@@ -1389,28 +1455,38 @@ class ScopeBuilder {
|
|
|
1389
1455
|
* ```
|
|
1390
1456
|
*
|
|
1391
1457
|
* @param id - The element id, unique in the process and used by `sequenceFlow`.
|
|
1458
|
+
*
|
|
1459
|
+
* **The result is keyed by decision name.** The platform's `output` row is the whole
|
|
1460
|
+
* result (`source="=result"`) and a decision's column reads as
|
|
1461
|
+
* `=result.<Decision>.<column>` — `vars.<id>_businessRuleResponse.<Decision>.<column>`
|
|
1462
|
+
* downstream — never `=result.<column>` (canvas spec `outputNotes`; `uip rules describe
|
|
1463
|
+
* <name>` lists the decisions and columns, and only a decision-keyed rule, one whose
|
|
1464
|
+
* `OutputArguments` carry `x-uipath-decision-keyed`, fits this row).
|
|
1392
1465
|
* @param opts - Which rule package, folder, and input arguments. `outputVar` defaults
|
|
1393
|
-
* to `<id>_businessRuleResponse`
|
|
1394
|
-
*
|
|
1466
|
+
* to `<id>_businessRuleResponse`. `releaseKey` and `folderKey` are refused: a v3 rule
|
|
1467
|
+
* is addressed by name.
|
|
1395
1468
|
* @param body - Boundary events attached to this activity, declared on the {@link ActivityBuilder} it receives.
|
|
1396
1469
|
* @returns This builder, so calls chain.
|
|
1397
1470
|
*/
|
|
1398
1471
|
businessRule(id, opts, body) {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
//
|
|
1404
|
-
//
|
|
1405
|
-
//
|
|
1406
|
-
// against
|
|
1407
|
-
//
|
|
1408
|
-
|
|
1409
|
-
//
|
|
1410
|
-
//
|
|
1411
|
-
//
|
|
1412
|
-
//
|
|
1413
|
-
|
|
1472
|
+
if (opts.releaseKey !== undefined || opts.folderKey !== undefined) {
|
|
1473
|
+
throw new Error(`businessRule('${id}'): a business rule is addressed by name and folder (version v3 binds the ` +
|
|
1474
|
+
'BusinessRule resource by `name` + `folderPath`); drop `releaseKey` / `folderKey`.');
|
|
1475
|
+
}
|
|
1476
|
+
// The default output variable is pinned rather than derived. Derived, it would come
|
|
1477
|
+
// from the registry's `OutputName`, which was once the designer LABEL, `Execute
|
|
1478
|
+
// business rule [Preview]` — a `[Preview]` marker in a name authors write expressions
|
|
1479
|
+
// against, and one that changed when the marker dropped. Pinning keeps every
|
|
1480
|
+
// `vars.<id>_businessRuleResponse` reference valid across that kind of spec edit.
|
|
1481
|
+
return this.orchestratorNode(id, 'Orchestrator.BusinessRules',
|
|
1482
|
+
// `folderPath` is a REQUIRED binding of the type: a rule in the running job's own
|
|
1483
|
+
// folder is bound with an empty path, so the pair is keyed by the name alone
|
|
1484
|
+
// (`uip maestro bpmn validate` accepts it); leaving the field out instead drew
|
|
1485
|
+
// BINDING_REQUIRED and EMPTY_REQUIRED_FIELD from `check`.
|
|
1486
|
+
{ ...opts, folder: opts.folder ?? '', outputVar: opts.outputVar ?? `${id}_businessRuleResponse` }, body,
|
|
1487
|
+
// `_label` is the one unbound context field: the rule's name, which the canvas
|
|
1488
|
+
// shows while `name` itself is a binding reference.
|
|
1489
|
+
{ typeVersion: 'v3', context: { _label: opts.process } });
|
|
1414
1490
|
}
|
|
1415
1491
|
/**
|
|
1416
1492
|
* Add an item to an Orchestrator **queue** (`Orchestrator.CreateQueueItem`, or
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { typedNodeOutputVar } from './typed-node.js';
|
|
1
|
+
import { typedNodeAdditionalOutputVars, typedNodeOutputVar } from './typed-node.js';
|
|
2
2
|
/**
|
|
3
3
|
* The variables a connector task's output rows land in.
|
|
4
4
|
*
|
|
@@ -38,7 +38,7 @@ export function typedNodeDeclaredVars(n) {
|
|
|
38
38
|
if (n.outputRows)
|
|
39
39
|
return n.outputRows.map((r) => r.var).filter((v) => v !== undefined);
|
|
40
40
|
const v = typedNodeOutputVar(n.id, n.type, n.outputVar, n.spec);
|
|
41
|
-
return [...(v ? [v] : []), ...Object.keys(n.outputs ?? {})];
|
|
41
|
+
return [...(v ? [v] : []), ...typedNodeAdditionalOutputVars(n.id, n.type, n.spec), ...Object.keys(n.outputs ?? {})];
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
* Every variable name a node DECLARES by writing to it — the platform counts a
|
package/dist/bpmn/decompile.js
CHANGED
|
@@ -419,18 +419,32 @@ function outputsOf(payload, _id, type) {
|
|
|
419
419
|
const rows = payload?.output ?? [];
|
|
420
420
|
const extras = {};
|
|
421
421
|
let outputVar;
|
|
422
|
-
const
|
|
422
|
+
const spec = type ? registryType(type) : undefined;
|
|
423
|
+
const specName = spec?.output?.name;
|
|
424
|
+
// A row the registry declares beside the main one (a business rule's `Error`) is
|
|
425
|
+
// re-emitted by the builder, so lifting it as an extra would write it twice on the
|
|
426
|
+
// way back. Matched by NAME (and source): an export that binds it to a variable
|
|
427
|
+
// other than the derived `<id>_<name>` is spelled out verbatim instead
|
|
428
|
+
// (`outputRowsNeedSpellingOut`), which carries that variable through exactly.
|
|
429
|
+
const declaredBeside = new Map((spec?.additionalOutputs ?? []).map((o) => [o.name, o.source ?? undefined]));
|
|
423
430
|
for (const row of rows) {
|
|
424
431
|
if (specName !== undefined && row.name === specName) {
|
|
425
432
|
// Only worth emitting when it differs from the default the builder derives.
|
|
426
433
|
outputVar = row.var;
|
|
427
434
|
continue;
|
|
428
435
|
}
|
|
436
|
+
if (declaredBeside.has(row.name) && (declaredBeside.get(row.name) === undefined || declaredBeside.get(row.name) === row.source))
|
|
437
|
+
continue;
|
|
429
438
|
if (row.source !== undefined)
|
|
430
439
|
extras[row.var ?? row.name] = row.source;
|
|
431
440
|
}
|
|
432
441
|
return { outputVar, extras };
|
|
433
442
|
}
|
|
443
|
+
/** The variable the builder derives for each row the registry declares beside the main one. */
|
|
444
|
+
function derivedExtraVars(id, type) {
|
|
445
|
+
const spec = type ? registryType(type) : undefined;
|
|
446
|
+
return new Map((spec?.additionalOutputs ?? []).map((o) => [o.name, `${id}_${o.name}`]));
|
|
447
|
+
}
|
|
434
448
|
/**
|
|
435
449
|
* Whether these rows can be reproduced by the compact `outputVar` + `outputs` pair,
|
|
436
450
|
* or need spelling out.
|
|
@@ -445,10 +459,16 @@ function outputsOf(payload, _id, type) {
|
|
|
445
459
|
* form stays in use wherever it is exact, so the 30 other extension types decompile
|
|
446
460
|
* to exactly the source they did before, and only a row that genuinely needs the
|
|
447
461
|
* long form gets it.
|
|
462
|
+
*
|
|
463
|
+
* A row the registry declares beside the main one (`derivedBeside`: a business rule's
|
|
464
|
+
* `Error`) that an export binds to a variable other than the derived `<id>_<name>`
|
|
465
|
+
* needs it too: the compact form cannot rename that row, and lifting it as an extra
|
|
466
|
+
* would have the builder add its own beside it.
|
|
448
467
|
*/
|
|
449
|
-
function outputRowsNeedSpellingOut(payload) {
|
|
468
|
+
function outputRowsNeedSpellingOut(payload, derivedBeside = new Map()) {
|
|
450
469
|
const rows = payload?.output ?? [];
|
|
451
|
-
return rows.some((row) => row.
|
|
470
|
+
return rows.some((row) => (derivedBeside.has(row.name) && row.var !== undefined && row.var !== derivedBeside.get(row.name)) ||
|
|
471
|
+
row.body !== undefined ||
|
|
452
472
|
row.custom !== undefined ||
|
|
453
473
|
row.description !== undefined ||
|
|
454
474
|
row.target !== undefined ||
|
|
@@ -522,7 +542,7 @@ function emitTypedNode(chain, el, payload, type) {
|
|
|
522
542
|
const verbatimContext = contextRowsNeedSpellingOut(payload, type) ? emitContextRows(payload) : undefined;
|
|
523
543
|
const { outputVar, extras } = outputsOf(payload, id, type);
|
|
524
544
|
const defaultVar = spec.output ? `${id}_${identifierize(spec.output.name)}` : undefined;
|
|
525
|
-
const verbatimRows = outputRowsNeedSpellingOut(payload) ? emitOutputRows(payload) : undefined;
|
|
545
|
+
const verbatimRows = outputRowsNeedSpellingOut(payload, derivedExtraVars(id, type)) ? emitOutputRows(payload) : undefined;
|
|
526
546
|
chain.add(`.activity(${tsText(id)}, ${tsText(type)}${optionalArg(opts([
|
|
527
547
|
['name', el.name !== undefined ? tsText(el.name) : undefined],
|
|
528
548
|
// Only when it differs from the registry's own template, so an
|
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
],
|
|
8
8
|
"provenance": {
|
|
9
9
|
"typeCount": 30,
|
|
10
|
-
"uipVersion": "1.203.0-preview.180"
|
|
10
|
+
"uipVersion": "1.203.0-preview.180",
|
|
11
|
+
"refreshed": {
|
|
12
|
+
"Orchestrator.BusinessRules": "1.205.0-preview.256"
|
|
13
|
+
}
|
|
11
14
|
},
|
|
12
15
|
"types": {
|
|
13
16
|
"A2A.AgentExecution": {
|
|
@@ -1277,40 +1280,35 @@
|
|
|
1277
1280
|
"inputTarget": "bodyField",
|
|
1278
1281
|
"context": [
|
|
1279
1282
|
{
|
|
1280
|
-
"name": "
|
|
1281
|
-
"displayName": "
|
|
1283
|
+
"name": "name",
|
|
1284
|
+
"displayName": "Business rule",
|
|
1282
1285
|
"type": "string",
|
|
1283
|
-
"required":
|
|
1286
|
+
"required": true,
|
|
1284
1287
|
"hidden": true,
|
|
1285
|
-
"binding":
|
|
1288
|
+
"binding": true,
|
|
1286
1289
|
"default": null,
|
|
1287
1290
|
"bindingInfo": {
|
|
1288
|
-
"resource": "
|
|
1289
|
-
"propertyAttribute": "
|
|
1291
|
+
"resource": "BusinessRule",
|
|
1292
|
+
"propertyAttribute": "name",
|
|
1293
|
+
"resourceKeyPattern": "${metadata.folderPath}.${metadata.name}"
|
|
1290
1294
|
}
|
|
1291
1295
|
},
|
|
1292
|
-
{
|
|
1293
|
-
"name": "folderId",
|
|
1294
|
-
"displayName": null,
|
|
1295
|
-
"type": "string",
|
|
1296
|
-
"required": false,
|
|
1297
|
-
"hidden": true,
|
|
1298
|
-
"binding": false,
|
|
1299
|
-
"default": null,
|
|
1300
|
-
"bindingInfo": null
|
|
1301
|
-
},
|
|
1302
1296
|
{
|
|
1303
1297
|
"name": "folderPath",
|
|
1304
1298
|
"displayName": null,
|
|
1305
1299
|
"type": "string",
|
|
1306
|
-
"required":
|
|
1300
|
+
"required": true,
|
|
1307
1301
|
"hidden": true,
|
|
1308
|
-
"binding":
|
|
1302
|
+
"binding": true,
|
|
1309
1303
|
"default": null,
|
|
1310
|
-
"bindingInfo":
|
|
1304
|
+
"bindingInfo": {
|
|
1305
|
+
"resource": "BusinessRule",
|
|
1306
|
+
"propertyAttribute": "folderPath",
|
|
1307
|
+
"resourceKeyPattern": "${metadata.folderPath}.${metadata.name}"
|
|
1308
|
+
}
|
|
1311
1309
|
},
|
|
1312
1310
|
{
|
|
1313
|
-
"name": "
|
|
1311
|
+
"name": "_label",
|
|
1314
1312
|
"displayName": null,
|
|
1315
1313
|
"type": "string",
|
|
1316
1314
|
"required": false,
|
|
@@ -1322,11 +1320,19 @@
|
|
|
1322
1320
|
],
|
|
1323
1321
|
"inputs": [],
|
|
1324
1322
|
"output": {
|
|
1325
|
-
"name": "
|
|
1326
|
-
"type": "
|
|
1327
|
-
"source":
|
|
1323
|
+
"name": "output",
|
|
1324
|
+
"type": "jsonSchema",
|
|
1325
|
+
"source": "=result",
|
|
1328
1326
|
"relative": true
|
|
1329
1327
|
},
|
|
1328
|
+
"additionalOutputs": [
|
|
1329
|
+
{
|
|
1330
|
+
"name": "Error",
|
|
1331
|
+
"type": "jsonSchema",
|
|
1332
|
+
"source": "=Error",
|
|
1333
|
+
"relative": true
|
|
1334
|
+
}
|
|
1335
|
+
],
|
|
1330
1336
|
"eventDefinition": null,
|
|
1331
1337
|
"requiresDiscovery": true,
|
|
1332
1338
|
"bindingPattern": "businessRule"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A binding field's resource key from the registry's `resourceKeyPattern`
|
|
3
|
+
* (`${metadata.folderPath}.${metadata.name}` on a business rule), resolved from the
|
|
4
|
+
* node's context values. Pure: the builder supplies the declared bindings a
|
|
5
|
+
* `=bindings.<b>` reference is read through.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* What a pattern resolves to from one node's context: the key and the ids of the
|
|
9
|
+
* declared bindings it was read through; `blocked` when it would resolve except for a
|
|
10
|
+
* `=bindings.<b>` reference no declared binding supplies a value for (the author is
|
|
11
|
+
* told what to declare rather than given a wrong pair); `undefined` when the pattern
|
|
12
|
+
* does not apply to this context at all, so the caller keys the binding by the value,
|
|
13
|
+
* as it always has.
|
|
14
|
+
*/
|
|
15
|
+
export type ResourceKeyResolution = {
|
|
16
|
+
key: string;
|
|
17
|
+
referenced: string[];
|
|
18
|
+
} | {
|
|
19
|
+
blocked: {
|
|
20
|
+
field: string;
|
|
21
|
+
ref: string;
|
|
22
|
+
};
|
|
23
|
+
} | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve `pattern` from `context`. A placeholder that is not `metadata.<field>`, a
|
|
26
|
+
* context field that is absent or not a string, or an `=` expression that is not a
|
|
27
|
+
* `=bindings.<b>` reference each make the pattern inapplicable (`undefined`) — so
|
|
28
|
+
* `${metadata.key}` on a job start, whose context has no `key`, leaves the key to the
|
|
29
|
+
* value. A `=bindings.<b>` value contributes the DECLARED value of `b`, never the
|
|
30
|
+
* expression text: a key is never evaluated.
|
|
31
|
+
*
|
|
32
|
+
* @param pattern - The field's `resourceKeyPattern`, or `undefined` for none.
|
|
33
|
+
* @param context - The node's context values as the author gave them.
|
|
34
|
+
* @param lookup - The declared binding for an id, with its `default` value, or `undefined`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveResourceKeyPattern(pattern: string | undefined, context: Record<string, unknown>, lookup: (bindingId: string) => {
|
|
37
|
+
default?: unknown;
|
|
38
|
+
} | undefined): ResourceKeyResolution;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A binding field's resource key from the registry's `resourceKeyPattern`
|
|
3
|
+
* (`${metadata.folderPath}.${metadata.name}` on a business rule), resolved from the
|
|
4
|
+
* node's context values. Pure: the builder supplies the declared bindings a
|
|
5
|
+
* `=bindings.<b>` reference is read through.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Resolve `pattern` from `context`. A placeholder that is not `metadata.<field>`, a
|
|
9
|
+
* context field that is absent or not a string, or an `=` expression that is not a
|
|
10
|
+
* `=bindings.<b>` reference each make the pattern inapplicable (`undefined`) — so
|
|
11
|
+
* `${metadata.key}` on a job start, whose context has no `key`, leaves the key to the
|
|
12
|
+
* value. A `=bindings.<b>` value contributes the DECLARED value of `b`, never the
|
|
13
|
+
* expression text: a key is never evaluated.
|
|
14
|
+
*
|
|
15
|
+
* @param pattern - The field's `resourceKeyPattern`, or `undefined` for none.
|
|
16
|
+
* @param context - The node's context values as the author gave them.
|
|
17
|
+
* @param lookup - The declared binding for an id, with its `default` value, or `undefined`.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveResourceKeyPattern(pattern, context, lookup) {
|
|
20
|
+
if (pattern === undefined)
|
|
21
|
+
return undefined;
|
|
22
|
+
const placeholders = [...pattern.matchAll(/\$\{([\w.]+)\}/g)].map((m) => m[1]);
|
|
23
|
+
const values = new Map();
|
|
24
|
+
const referenced = [];
|
|
25
|
+
for (const name of placeholders) {
|
|
26
|
+
if (!name.startsWith('metadata.'))
|
|
27
|
+
return undefined;
|
|
28
|
+
const contextField = name.slice('metadata.'.length);
|
|
29
|
+
const v = context[contextField];
|
|
30
|
+
if (typeof v !== 'string')
|
|
31
|
+
return undefined;
|
|
32
|
+
if (!v.startsWith('=')) {
|
|
33
|
+
values.set(name, v);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (!v.startsWith('=bindings.'))
|
|
37
|
+
return undefined;
|
|
38
|
+
const refId = v.slice('=bindings.'.length);
|
|
39
|
+
const decl = lookup(refId);
|
|
40
|
+
if (decl === undefined || typeof decl.default !== 'string')
|
|
41
|
+
return { blocked: { field: contextField, ref: v } };
|
|
42
|
+
values.set(name, decl.default);
|
|
43
|
+
referenced.push(refId);
|
|
44
|
+
}
|
|
45
|
+
const key = pattern.replace(/\$\{([\w.]+)\}/g, (_m, name) => values.get(name) ?? '');
|
|
46
|
+
return { key: key.startsWith('.') ? key.slice(1) : key, referenced };
|
|
47
|
+
}
|
|
@@ -36,6 +36,13 @@ export interface RegistryContextField {
|
|
|
36
36
|
bindingInfo: {
|
|
37
37
|
resource: string | null;
|
|
38
38
|
propertyAttribute: string | null;
|
|
39
|
+
/**
|
|
40
|
+
* How the binding's `resourceKey` is built from the node's context values, e.g.
|
|
41
|
+
* `${metadata.folderPath}.${metadata.name}` for a business rule. Absent on
|
|
42
|
+
* entries materialized before the field was carried; the emitter then keys the
|
|
43
|
+
* binding by the bound value itself, as it always did.
|
|
44
|
+
*/
|
|
45
|
+
resourceKeyPattern?: string;
|
|
39
46
|
} | null;
|
|
40
47
|
}
|
|
41
48
|
/**
|
|
@@ -88,6 +95,11 @@ export interface RegistryTypeSpec {
|
|
|
88
95
|
/** The payload fields the registry declares; empty for types with dynamic inputs. */
|
|
89
96
|
inputs: RegistryInputField[];
|
|
90
97
|
output: RegistryOutput | null;
|
|
98
|
+
/**
|
|
99
|
+
* Output rows the type writes besides `output` — a business rule's `Error` row
|
|
100
|
+
* (`source="=Error"`). Each lands in `<id>_<name>`. Absent when the type has none.
|
|
101
|
+
*/
|
|
102
|
+
additionalOutputs?: RegistryOutput[];
|
|
91
103
|
/** e.g. `bpmn:messageEventDefinition` — what makes a message event a message event. */
|
|
92
104
|
eventDefinition: string | null;
|
|
93
105
|
/** True when authoring needs a tenant read (a connection, a process, a queue). */
|
|
@@ -347,6 +359,11 @@ export interface TypedNodeInput {
|
|
|
347
359
|
/** The type's emission spec, supplied inline — see `ActivityNodeOpts.spec`. */
|
|
348
360
|
spec?: RegistryTypeSpec;
|
|
349
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* The variables a typed node's ADDITIONAL output rows write (`<id>_<name>`), in
|
|
364
|
+
* registry order — a business rule's `<id>_Error`. Empty for every type without them.
|
|
365
|
+
*/
|
|
366
|
+
export declare function typedNodeAdditionalOutputVars(id: string, type: string, inline?: RegistryTypeSpec): string[];
|
|
350
367
|
/** The variable a typed node's output row writes, or `undefined` when it has none. */
|
|
351
368
|
export declare function typedNodeOutputVar(id: string, type: string, outputVar?: string, inline?: RegistryTypeSpec): string | undefined;
|
|
352
369
|
/** `uipath:input` payload rows exactly as the caller spelled them, deriving nothing. */
|
package/dist/bpmn/typed-node.js
CHANGED
|
@@ -191,6 +191,15 @@ function identifierize(name) {
|
|
|
191
191
|
.map((w, i) => (i === 0 ? w.charAt(0).toLowerCase() + w.slice(1) : w.charAt(0).toUpperCase() + w.slice(1)))
|
|
192
192
|
.join('');
|
|
193
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* The variables a typed node's ADDITIONAL output rows write (`<id>_<name>`), in
|
|
196
|
+
* registry order — a business rule's `<id>_Error`. Empty for every type without them.
|
|
197
|
+
*/
|
|
198
|
+
export function typedNodeAdditionalOutputVars(id, type, inline) {
|
|
199
|
+
// The row's name as it is, not identifierized: `Error` → `<id>_Error`, the variable a
|
|
200
|
+
// connector task's error row has always landed in.
|
|
201
|
+
return (registryType(type, inline).additionalOutputs ?? []).map((o) => `${id}_${o.name}`);
|
|
202
|
+
}
|
|
194
203
|
/** The variable a typed node's output row writes, or `undefined` when it has none. */
|
|
195
204
|
export function typedNodeOutputVar(id, type, outputVar, inline) {
|
|
196
205
|
const spec = registryType(type, inline);
|
|
@@ -536,6 +545,16 @@ varType) {
|
|
|
536
545
|
const out = outVar ? outputRow(m, spec, outVar) : undefined;
|
|
537
546
|
if (out)
|
|
538
547
|
rows.push(out);
|
|
548
|
+
// The rows the registry declares beside the main one, in its order and at the
|
|
549
|
+
// default variable each — a business rule's `Error` row. They sit between the
|
|
550
|
+
// type's own row and the author's, which is where every real export puts them.
|
|
551
|
+
const extraVars = typedNodeAdditionalOutputVars(id, type, spec);
|
|
552
|
+
(spec.additionalOutputs ?? []).forEach((o, i) => {
|
|
553
|
+
const props = { name: o.name, type: o.type, var: extraVars[i] };
|
|
554
|
+
if (o.source)
|
|
555
|
+
props.source = o.source;
|
|
556
|
+
rows.push(m.create('uipath:Output', props));
|
|
557
|
+
});
|
|
539
558
|
for (const [varId, source] of Object.entries(input.outputs ?? {})) {
|
|
540
559
|
// Type the row from the variable it writes, not `'string'` unconditionally.
|
|
541
560
|
//
|