@uipath/maestro-builder-sdk 6.11.6 → 6.12.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 +83 -56
- package/dist/api-members.md +362 -261
- package/dist/bpmn/bpmn-expr-check.js +8 -1
- package/dist/bpmn/bpmn-sdk.d.ts +1026 -27
- package/dist/bpmn/bpmn-sdk.js +1328 -83
- package/dist/bpmn/check-cli.js +19 -4
- package/dist/bpmn/check.d.ts +1 -1
- package/dist/bpmn/check.js +529 -13
- package/dist/bpmn/connector.d.ts +2 -2
- package/dist/bpmn/connector.js +74 -37
- package/dist/bpmn/data-service.d.ts +124 -0
- package/dist/bpmn/data-service.js +98 -0
- package/dist/bpmn/decompile-cli.js +70 -8
- package/dist/bpmn/decompile.d.ts +71 -0
- package/dist/bpmn/decompile.js +845 -31
- package/dist/bpmn/graph.d.ts +69 -0
- package/dist/bpmn/graph.js +98 -0
- package/dist/bpmn/intsvc.js +2 -2
- package/dist/bpmn/known-methods.d.ts +15 -0
- package/dist/bpmn/known-methods.js +271 -0
- package/dist/bpmn/lift-verify.d.ts +40 -0
- package/dist/bpmn/lift-verify.js +133 -0
- package/dist/bpmn/serialize.d.ts +65 -1
- package/dist/bpmn/serialize.js +169 -22
- package/dist/bpmn/typed-node.d.ts +37 -6
- package/dist/bpmn/typed-node.js +81 -19
- package/dist/cli/commands/bpmn.js +7 -1
- package/dist/core-definitions.json +3 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -0
- package/package.json +2 -2
package/dist/bpmn/serialize.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BuiltBpmn } from './bpmn-sdk.js';
|
|
1
|
+
import { type BuiltBpmn, type BpmnNode, type BpmnVarDecl } from './bpmn-sdk.js';
|
|
2
2
|
import type { Library } from '../core/library.js';
|
|
3
3
|
import type { Bindings } from '../core/bindings.js';
|
|
4
4
|
/** Optional wiring for connector service tasks. */
|
|
@@ -26,3 +26,67 @@ export declare function serialize(built: BuiltBpmn, opts?: BpmnSerializeOpts): P
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function finalizeBpmnXml(xml: string): string;
|
|
28
28
|
export declare function processId(id: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* The variable declarations a scope's output-bearing nodes imply.
|
|
31
|
+
*
|
|
32
|
+
* A connector's or typed node's output row names a variable the author never declared
|
|
33
|
+
* (`<id>_response`, `<id>_Error`). Studio Web carries a matching variable for every
|
|
34
|
+
* such row, and without it the canvas validator warns `MISSING_ROOT_VARIABLE`; declaring
|
|
35
|
+
* them keeps the artifact indistinguishable from a designed one. A SCRIPT task's
|
|
36
|
+
* `outputs` need it more than that: `uip maestro bpmn validate` does NOT treat a
|
|
37
|
+
* `BPMN.ScriptTask` row's `var` as a declaration — a `vars.<output>` read downstream is
|
|
38
|
+
* `VARIABLE_DOES_NOT_EXIST` on 1.202 and 1.203 alike (measured on a gateway condition
|
|
39
|
+
* reading a script's `confidence`) — so those rows get one too, typed `string` like the
|
|
40
|
+
* row itself. Author-declared names win: an explicit `.var()` for the same name is left
|
|
41
|
+
* exactly as written.
|
|
42
|
+
*
|
|
43
|
+
* Each derived declaration belongs to the node whose row fills it (`elementId`), the
|
|
44
|
+
* way the product declares a node's own outputs. `decompile` recognises exactly this
|
|
45
|
+
* shape (`derivedVariableIds`) and does not echo it, so the two sides stay a round trip.
|
|
46
|
+
*/
|
|
47
|
+
export declare function implicitNodeVars(nodes: BpmnNode[], declared: BpmnVarDecl[]): BpmnVarDecl[];
|
|
48
|
+
/**
|
|
49
|
+
* The `resourceKey` each author-declared FOLDER binding should carry: the key of the
|
|
50
|
+
* connection it is the companion of.
|
|
51
|
+
*
|
|
52
|
+
* A `folderKey` binding is not a resource of its own. Every real export writes the
|
|
53
|
+
* pair as `ConnectionId` binding `{resourceKey: <connection>, default: <connection>}`
|
|
54
|
+
* and `folderKey` binding `{resourceKey: <connection>, default: <folder>}` — the folder
|
|
55
|
+
* is where the CONNECTION is resolved, so its resource key is the connection's. A
|
|
56
|
+
* binding declared through `.binding('f', { propertyAttribute: 'folderKey', value })`
|
|
57
|
+
* used to collapse `resourceKey` onto `value`, the folder's own key, and
|
|
58
|
+
* `uip maestro bpmn validate` reported `MISSING_BINDING` for it — on every process the
|
|
59
|
+
* run-6 agents authored against Data Fabric or Test Manager.
|
|
60
|
+
*
|
|
61
|
+
* Pairing comes from the nodes: a node whose context reads `=bindings.<c>` as its
|
|
62
|
+
* `connection` and `=bindings.<f>` as its `folderKey` pairs `f` with `c`. A folder no
|
|
63
|
+
* node pairs falls back to the only `ConnectionId` binding when there is exactly one.
|
|
64
|
+
* An explicit `resourceKey` on the declaration is never overridden.
|
|
65
|
+
*/
|
|
66
|
+
export declare function folderCompanionKeys(built: BuiltBpmn, sink: Map<string, Record<string, unknown>>): Map<string, string>;
|
|
67
|
+
/**
|
|
68
|
+
* Where an unscoped PUBLIC declaration belongs at the top level of a process.
|
|
69
|
+
*
|
|
70
|
+
* Every real artifact agrees: across the 97 Studio Web exports and converter outputs
|
|
71
|
+
* measured (`research/bpmn-roundtrip/corpus/`, the run-6 `v1` arm), all 107 public
|
|
72
|
+
* `uipath:input` declarations are scoped to the process's manual START event and all
|
|
73
|
+
* 37 `uipath:output` declarations to the END event whose mapping writes them — none to
|
|
74
|
+
* the process. The engine does not need it (`BpmnDataManager.EvaluateProcessVariables`
|
|
75
|
+
* seeds every declaration into one variables scope by id, and an expression resolves
|
|
76
|
+
* `vars.<id>` there whatever the declaration's `elementId`), but the canvas, the
|
|
77
|
+
* entry-point derivation and the graders that read a process's contract do: a process
|
|
78
|
+
* input is "the start event's input". Until this, the SDK wrote the process id, which
|
|
79
|
+
* validated and ran and was the one placement nothing else on the platform produces —
|
|
80
|
+
* cluster D of docs/BPMN_AUTHORING_ERGONOMICS_DESIGN.md §1b.
|
|
81
|
+
*
|
|
82
|
+
* The rule, mirrored by `bpmn-decompile` so an unscoped declaration round-trips without
|
|
83
|
+
* an explicit `elementId`:
|
|
84
|
+
* - `input` → the one root start event with no event definition and no trigger,
|
|
85
|
+
* when there is exactly one; else the process.
|
|
86
|
+
* - `output` → the one root end event whose payload writes `var="<id>"`; else the one
|
|
87
|
+
* root end event, when there is exactly one; else the process.
|
|
88
|
+
* - `inputOutput` → the process (an internal variable is process-level state; the
|
|
89
|
+
* engine's debug variables report lists exactly those).
|
|
90
|
+
* An explicit `elementId` always wins, and `null` still means "write none".
|
|
91
|
+
*/
|
|
92
|
+
export declare function publicDeclarationScope(nodes: BpmnNode[], processId: string): (v: BpmnVarDecl) => string;
|
package/dist/bpmn/serialize.js
CHANGED
|
@@ -104,13 +104,14 @@ export async function serialize(built, opts = {}) {
|
|
|
104
104
|
// effect — then assemble the process extensionElements from the result.
|
|
105
105
|
const flowElements = buildScope(ctx, built.nodes, built.flows);
|
|
106
106
|
const processExt = [];
|
|
107
|
-
const varsExt = buildVariablesExt(ctx, rootVars);
|
|
107
|
+
const varsExt = buildVariablesExt(ctx, rootVars, built.id, publicDeclarationScope(built.nodes, built.id));
|
|
108
108
|
if (varsExt)
|
|
109
109
|
processExt.push(varsExt);
|
|
110
110
|
// Author-declared bindings first, then the ones connector wiring derived —
|
|
111
111
|
// one `uipath:bindings` block either way, since the runtime reads one registry.
|
|
112
112
|
// An author declaration wins on an id collision: it is the more specific intent.
|
|
113
113
|
const declaredIds = new Set(built.bindings.map((b) => b.id));
|
|
114
|
+
const companionKey = folderCompanionKeys(built, ctx.bindingSink);
|
|
114
115
|
const bindingRows = [
|
|
115
116
|
...built.bindings.map((b) => ({
|
|
116
117
|
id: b.id,
|
|
@@ -118,7 +119,7 @@ export async function serialize(built, opts = {}) {
|
|
|
118
119
|
type: 'string',
|
|
119
120
|
resource: b.resource,
|
|
120
121
|
resourceSubType: b.resourceSubType,
|
|
121
|
-
resourceKey: b.resourceKey,
|
|
122
|
+
resourceKey: b.resourceKey ?? companionKey.get(b.id) ?? b.default,
|
|
122
123
|
default: b.default,
|
|
123
124
|
propertyAttribute: b.propertyAttribute,
|
|
124
125
|
})),
|
|
@@ -286,6 +287,11 @@ function createNode(ctx, n) {
|
|
|
286
287
|
return el;
|
|
287
288
|
}
|
|
288
289
|
const el = m.create(`bpmn:${cap(n.kind)}`, { id: n.id, name: n.name });
|
|
290
|
+
// Only the exception is written: BPMN's default is interrupting, and an
|
|
291
|
+
// `isInterrupting="true"` the author never asked for would change the bytes
|
|
292
|
+
// of every existing process.
|
|
293
|
+
if (n.kind === 'startEvent' && n.interrupting === false)
|
|
294
|
+
el.isInterrupting = false;
|
|
289
295
|
attachExtensionPayload(ctx, el, n.payload);
|
|
290
296
|
const def = eventDefinition(ctx, n.event);
|
|
291
297
|
if (def)
|
|
@@ -326,6 +332,8 @@ function createNode(ctx, n) {
|
|
|
326
332
|
context: n.context,
|
|
327
333
|
contextRows: n.contextRows,
|
|
328
334
|
inputs: n.inputs,
|
|
335
|
+
inputRows: n.inputRows,
|
|
336
|
+
spec: n.spec,
|
|
329
337
|
typeVersion: n.typeVersion,
|
|
330
338
|
inputSchema: n.inputSchema,
|
|
331
339
|
outputVar: n.outputVar,
|
|
@@ -463,8 +471,12 @@ function createScriptTask(ctx, n) {
|
|
|
463
471
|
// these as a sequence and both orders validate, but matching the product's
|
|
464
472
|
// means an imported script task round-trips without a reordered diff, which
|
|
465
473
|
// the brownfield `edit/*` eval tasks grade on.
|
|
474
|
+
//
|
|
475
|
+
// The VALUE is the node's, not a constant: it selects the runtime's result shape
|
|
476
|
+
// (v2+ wraps the return value, v1 spreads it), so stamping every script task `v3`
|
|
477
|
+
// silently changed what an imported v1 task's outputs resolved to.
|
|
466
478
|
extensionElements: m.create('bpmn:ExtensionElements', {
|
|
467
|
-
values: [mapping, m.create('uipath:ScriptVersion', { value:
|
|
479
|
+
values: [mapping, m.create('uipath:ScriptVersion', { value: n.scriptVersion })],
|
|
468
480
|
}),
|
|
469
481
|
script: n.script,
|
|
470
482
|
});
|
|
@@ -489,7 +501,13 @@ function createSubProcess(ctx, n) {
|
|
|
489
501
|
if (n.triggeredByEvent)
|
|
490
502
|
props.triggeredByEvent = true;
|
|
491
503
|
const values = [];
|
|
492
|
-
|
|
504
|
+
// The ENCLOSING scopes' declarations count as taken too. Passing only the
|
|
505
|
+
// sub-process's own meant a script task inside it re-declared an output variable the
|
|
506
|
+
// root already declares — same id, twice in one document, which is the
|
|
507
|
+
// DUPLICATE_DOCUMENT_ID the emitter goes out of its way to avoid everywhere else
|
|
508
|
+
// (the XML parser drops the second element that reuses an id).
|
|
509
|
+
const enclosing = [...n.variables, ...[...ctx.varType.keys()].map((id) => ({ id }))];
|
|
510
|
+
const varsExt = buildVariablesExt(ctx, [...n.variables, ...implicitNodeVars(n.nodes, enclosing)], n.id);
|
|
493
511
|
if (varsExt)
|
|
494
512
|
values.push(varsExt);
|
|
495
513
|
if (values.length)
|
|
@@ -594,27 +612,34 @@ function assignmentSource(value) {
|
|
|
594
612
|
* The variable declarations a scope's output-bearing nodes imply.
|
|
595
613
|
*
|
|
596
614
|
* A connector's or typed node's output row names a variable the author never declared
|
|
597
|
-
* (`<id>_response`, `<id>_Error`).
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
*
|
|
615
|
+
* (`<id>_response`, `<id>_Error`). Studio Web carries a matching variable for every
|
|
616
|
+
* such row, and without it the canvas validator warns `MISSING_ROOT_VARIABLE`; declaring
|
|
617
|
+
* them keeps the artifact indistinguishable from a designed one. A SCRIPT task's
|
|
618
|
+
* `outputs` need it more than that: `uip maestro bpmn validate` does NOT treat a
|
|
619
|
+
* `BPMN.ScriptTask` row's `var` as a declaration — a `vars.<output>` read downstream is
|
|
620
|
+
* `VARIABLE_DOES_NOT_EXIST` on 1.202 and 1.203 alike (measured on a gateway condition
|
|
621
|
+
* reading a script's `confidence`) — so those rows get one too, typed `string` like the
|
|
622
|
+
* row itself. Author-declared names win: an explicit `.var()` for the same name is left
|
|
623
|
+
* exactly as written.
|
|
624
|
+
*
|
|
625
|
+
* Each derived declaration belongs to the node whose row fills it (`elementId`), the
|
|
626
|
+
* way the product declares a node's own outputs. `decompile` recognises exactly this
|
|
627
|
+
* shape (`derivedVariableIds`) and does not echo it, so the two sides stay a round trip.
|
|
603
628
|
*/
|
|
604
|
-
function implicitNodeVars(nodes, declared) {
|
|
629
|
+
export function implicitNodeVars(nodes, declared) {
|
|
605
630
|
const taken = new Set(declared.map((v) => v.id));
|
|
606
631
|
const out = [];
|
|
607
|
-
const claim = (id) => {
|
|
632
|
+
const claim = (id, ownerId, type = 'object') => {
|
|
608
633
|
if (!id || taken.has(id))
|
|
609
634
|
return;
|
|
610
635
|
taken.add(id);
|
|
611
|
-
out.push({ id, name: id, type
|
|
636
|
+
out.push({ id, name: id, type, direction: 'inputOutput', elementId: ownerId });
|
|
612
637
|
};
|
|
613
638
|
for (const n of nodes) {
|
|
614
639
|
if (n.kind === 'connector') {
|
|
615
640
|
const { response, error } = connectorOutputVars(n);
|
|
616
|
-
claim(response);
|
|
617
|
-
claim(error);
|
|
641
|
+
claim(response, n.id);
|
|
642
|
+
claim(error, n.id);
|
|
618
643
|
}
|
|
619
644
|
else if (n.kind === 'typed') {
|
|
620
645
|
// Shared with the expression checker rather than repeated here. Repeating it is
|
|
@@ -623,25 +648,94 @@ function implicitNodeVars(nodes, declared) {
|
|
|
623
648
|
// side vanishes from the recompiled process. Measured on a Slack connector —
|
|
624
649
|
// `send_Error` was declared in the original and absent after the round trip.
|
|
625
650
|
for (const varId of typedNodeDeclaredVars(n))
|
|
626
|
-
claim(varId);
|
|
651
|
+
claim(varId, n.id);
|
|
627
652
|
}
|
|
628
653
|
else if (n.kind === 'connectorEvent' || n.kind === 'externalTask') {
|
|
629
654
|
// Same reason as the typed and connector arms: the node's output rows
|
|
630
655
|
// reference variables the process must declare, or the canvas validator
|
|
631
656
|
// reports MISSING_ROOT_VARIABLE.
|
|
632
|
-
claim(intsvcOutputVar(n));
|
|
657
|
+
claim(intsvcOutputVar(n), n.id);
|
|
633
658
|
for (const varId of Object.keys(n.outputs ?? {}))
|
|
634
|
-
claim(varId);
|
|
659
|
+
claim(varId, n.id);
|
|
635
660
|
}
|
|
636
661
|
else if (n.kind === 'startEvent' && n.trigger) {
|
|
637
662
|
// A trigger's payload row writes a variable like any typed node's, so it
|
|
638
663
|
// needs the same implicit declaration — without it the row references a
|
|
639
664
|
// variable the process never declares (MISSING_ROOT_VARIABLE).
|
|
640
|
-
claim(typedNodeOutputVar(n.id, n.trigger.type, n.trigger.outputVar));
|
|
665
|
+
claim(typedNodeOutputVar(n.id, n.trigger.type, n.trigger.outputVar), n.id);
|
|
666
|
+
}
|
|
667
|
+
else if (n.kind === 'scriptTask') {
|
|
668
|
+
// `object` (emitted as `json`), not `string`. Under the v3 contract a script
|
|
669
|
+
// returns `{ response: <whatever it returned> }`, so an output nobody declared
|
|
670
|
+
// holds arbitrary JSON — declaring a number or an object as `string` is the
|
|
671
|
+
// mis-declaration this fallback exists to avoid. An output the AUTHOR declared
|
|
672
|
+
// keeps its own type: `claim` skips an id already taken.
|
|
673
|
+
for (const varId of Object.keys(n.outputs))
|
|
674
|
+
claim(varId, n.id);
|
|
641
675
|
}
|
|
642
676
|
}
|
|
643
677
|
return out;
|
|
644
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* The `resourceKey` each author-declared FOLDER binding should carry: the key of the
|
|
681
|
+
* connection it is the companion of.
|
|
682
|
+
*
|
|
683
|
+
* A `folderKey` binding is not a resource of its own. Every real export writes the
|
|
684
|
+
* pair as `ConnectionId` binding `{resourceKey: <connection>, default: <connection>}`
|
|
685
|
+
* and `folderKey` binding `{resourceKey: <connection>, default: <folder>}` — the folder
|
|
686
|
+
* is where the CONNECTION is resolved, so its resource key is the connection's. A
|
|
687
|
+
* binding declared through `.binding('f', { propertyAttribute: 'folderKey', value })`
|
|
688
|
+
* used to collapse `resourceKey` onto `value`, the folder's own key, and
|
|
689
|
+
* `uip maestro bpmn validate` reported `MISSING_BINDING` for it — on every process the
|
|
690
|
+
* run-6 agents authored against Data Fabric or Test Manager.
|
|
691
|
+
*
|
|
692
|
+
* Pairing comes from the nodes: a node whose context reads `=bindings.<c>` as its
|
|
693
|
+
* `connection` and `=bindings.<f>` as its `folderKey` pairs `f` with `c`. A folder no
|
|
694
|
+
* node pairs falls back to the only `ConnectionId` binding when there is exactly one.
|
|
695
|
+
* An explicit `resourceKey` on the declaration is never overridden.
|
|
696
|
+
*/
|
|
697
|
+
export function folderCompanionKeys(built, sink) {
|
|
698
|
+
const keyOf = new Map();
|
|
699
|
+
const connectionIds = [];
|
|
700
|
+
const isConnectionId = (attr) => String(attr ?? '').toLowerCase() === 'connectionid';
|
|
701
|
+
for (const b of built.bindings) {
|
|
702
|
+
const key = b.resourceKey ?? b.default;
|
|
703
|
+
if (key !== undefined)
|
|
704
|
+
keyOf.set(b.id, key);
|
|
705
|
+
if (isConnectionId(b.propertyAttribute))
|
|
706
|
+
connectionIds.push(b.id);
|
|
707
|
+
}
|
|
708
|
+
for (const b of sink.values()) {
|
|
709
|
+
const key = b.resourceKey ?? b.default;
|
|
710
|
+
if (key !== undefined && !keyOf.has(b.id))
|
|
711
|
+
keyOf.set(b.id, key);
|
|
712
|
+
if (isConnectionId(b.propertyAttribute) && !connectionIds.includes(b.id))
|
|
713
|
+
connectionIds.push(b.id);
|
|
714
|
+
}
|
|
715
|
+
const bindingId = (value) => typeof value === 'string' && value.startsWith('=bindings.') ? value.slice('=bindings.'.length) : undefined;
|
|
716
|
+
const pairs = new Map();
|
|
717
|
+
for (const n of allNodes(built.nodes)) {
|
|
718
|
+
if (n.kind !== 'typed')
|
|
719
|
+
continue;
|
|
720
|
+
const view = { ...n.context };
|
|
721
|
+
for (const row of n.contextRows ?? [])
|
|
722
|
+
view[row.name] = row.value ?? row.body;
|
|
723
|
+
const connection = bindingId(view.connection ?? view.connectionId);
|
|
724
|
+
const folder = bindingId(view.folderKey);
|
|
725
|
+
if (connection && folder && !pairs.has(folder))
|
|
726
|
+
pairs.set(folder, connection);
|
|
727
|
+
}
|
|
728
|
+
const out = new Map();
|
|
729
|
+
for (const b of built.bindings) {
|
|
730
|
+
if (String(b.propertyAttribute ?? '').toLowerCase() !== 'folderkey' || b.resourceKey !== undefined)
|
|
731
|
+
continue;
|
|
732
|
+
const companion = pairs.get(b.id) ?? (connectionIds.length === 1 ? connectionIds[0] : undefined);
|
|
733
|
+
const key = companion !== undefined ? keyOf.get(companion) : undefined;
|
|
734
|
+
if (key !== undefined)
|
|
735
|
+
out.set(b.id, key);
|
|
736
|
+
}
|
|
737
|
+
return out;
|
|
738
|
+
}
|
|
645
739
|
/**
|
|
646
740
|
* `uipath:retry` — a retry policy, as a sibling of the activity's mapping/activity
|
|
647
741
|
* element rather than inside it, which is why it works on every activity kind.
|
|
@@ -700,8 +794,21 @@ function buildLoopCharacteristics(ctx, loop) {
|
|
|
700
794
|
function defaultAttr(value, mappedType) {
|
|
701
795
|
return mappedType === 'json' ? JSON.stringify(value) : String(value);
|
|
702
796
|
}
|
|
703
|
-
/**
|
|
704
|
-
|
|
797
|
+
/**
|
|
798
|
+
* A `uipath:variables` extension element grouping declarations by direction.
|
|
799
|
+
*
|
|
800
|
+
* `ownerId` is the scope the block sits in — the process or sub-process id — and is
|
|
801
|
+
* what a declaration with no `elementId` of its own is written as belonging to. The
|
|
802
|
+
* product writes every scope-level variable that way, and `uip maestro bpmn validate`
|
|
803
|
+
* 1.203 refuses one without it (`ROOT_VARIABLE_MISSING_ELEMENT_ID`: "no expression can
|
|
804
|
+
* resolve it"); a declaration inside a sub-process is resolved by both 1.202 and 1.203
|
|
805
|
+
* only when it carries one (measured: `vars.decision` declared in the sub-process block
|
|
806
|
+
* was `VARIABLE_DOES_NOT_EXIST` until `elementId` named the sub-process). `null` means
|
|
807
|
+
* the author — in practice `decompile`, echoing an older export — wants none written.
|
|
808
|
+
*/
|
|
809
|
+
function buildVariablesExt(ctx, vars, ownerId,
|
|
810
|
+
/** The default scope of a declaration the author left unscoped; the owner when absent. */
|
|
811
|
+
scopeOf = () => ownerId) {
|
|
705
812
|
const { m } = ctx;
|
|
706
813
|
if (!vars.length)
|
|
707
814
|
return undefined;
|
|
@@ -711,7 +818,7 @@ function buildVariablesExt(ctx, vars) {
|
|
|
711
818
|
id: v.id,
|
|
712
819
|
name: v.name,
|
|
713
820
|
type: mapType(v.type),
|
|
714
|
-
elementId: v.elementId,
|
|
821
|
+
elementId: v.elementId === null ? undefined : (v.elementId ?? scopeOf(v)),
|
|
715
822
|
default: v.default === undefined ? undefined : defaultAttr(v.default, mapType(v.type)),
|
|
716
823
|
// Carried, never interpreted — a schema field this SDK does not model survives.
|
|
717
824
|
body: schemaBody(ctx, v.schema),
|
|
@@ -728,6 +835,46 @@ function buildVariablesExt(ctx, vars) {
|
|
|
728
835
|
props.output = groups.output;
|
|
729
836
|
return m.create('uipath:Variables', props);
|
|
730
837
|
}
|
|
838
|
+
/**
|
|
839
|
+
* Where an unscoped PUBLIC declaration belongs at the top level of a process.
|
|
840
|
+
*
|
|
841
|
+
* Every real artifact agrees: across the 97 Studio Web exports and converter outputs
|
|
842
|
+
* measured (`research/bpmn-roundtrip/corpus/`, the run-6 `v1` arm), all 107 public
|
|
843
|
+
* `uipath:input` declarations are scoped to the process's manual START event and all
|
|
844
|
+
* 37 `uipath:output` declarations to the END event whose mapping writes them — none to
|
|
845
|
+
* the process. The engine does not need it (`BpmnDataManager.EvaluateProcessVariables`
|
|
846
|
+
* seeds every declaration into one variables scope by id, and an expression resolves
|
|
847
|
+
* `vars.<id>` there whatever the declaration's `elementId`), but the canvas, the
|
|
848
|
+
* entry-point derivation and the graders that read a process's contract do: a process
|
|
849
|
+
* input is "the start event's input". Until this, the SDK wrote the process id, which
|
|
850
|
+
* validated and ran and was the one placement nothing else on the platform produces —
|
|
851
|
+
* cluster D of docs/BPMN_AUTHORING_ERGONOMICS_DESIGN.md §1b.
|
|
852
|
+
*
|
|
853
|
+
* The rule, mirrored by `bpmn-decompile` so an unscoped declaration round-trips without
|
|
854
|
+
* an explicit `elementId`:
|
|
855
|
+
* - `input` → the one root start event with no event definition and no trigger,
|
|
856
|
+
* when there is exactly one; else the process.
|
|
857
|
+
* - `output` → the one root end event whose payload writes `var="<id>"`; else the one
|
|
858
|
+
* root end event, when there is exactly one; else the process.
|
|
859
|
+
* - `inputOutput` → the process (an internal variable is process-level state; the
|
|
860
|
+
* engine's debug variables report lists exactly those).
|
|
861
|
+
* An explicit `elementId` always wins, and `null` still means "write none".
|
|
862
|
+
*/
|
|
863
|
+
export function publicDeclarationScope(nodes, processId) {
|
|
864
|
+
const manualStarts = nodes.filter((n) => n.kind === 'startEvent' && n.event === undefined && n.trigger === undefined);
|
|
865
|
+
const ends = nodes.filter((n) => n.kind === 'endEvent');
|
|
866
|
+
return (v) => {
|
|
867
|
+
if (v.direction === 'input')
|
|
868
|
+
return manualStarts.length === 1 ? manualStarts[0].id : processId;
|
|
869
|
+
if (v.direction === 'output') {
|
|
870
|
+
const writers = ends.filter((e) => (e.payload?.outputRows ?? []).some((r) => r.var === v.id));
|
|
871
|
+
if (writers.length === 1)
|
|
872
|
+
return writers[0].id;
|
|
873
|
+
return ends.length === 1 ? ends[0].id : processId;
|
|
874
|
+
}
|
|
875
|
+
return processId;
|
|
876
|
+
};
|
|
877
|
+
}
|
|
731
878
|
// ─── Small helpers ────────────────────────────────────────────────────────────
|
|
732
879
|
function cap(s) {
|
|
733
880
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
@@ -108,11 +108,12 @@ export declare function registryTypeNames(): string[];
|
|
|
108
108
|
* `FLOW_SDK_BPMN_REGISTRY_FALLBACK=0` to keep resolution snapshot-only.
|
|
109
109
|
*
|
|
110
110
|
* @param type - The extension type, e.g. `'Intsvc.UnifiedHttpRequest'`.
|
|
111
|
+
* @param inline - A spec supplied by the author, which is used as is.
|
|
111
112
|
* @returns Its emission spec.
|
|
112
113
|
* @throws If the type is in neither the snapshot nor the registry — which means a
|
|
113
114
|
* typo, or no `uip` to ask.
|
|
114
115
|
*/
|
|
115
|
-
export declare function registryType(type: string): RegistryTypeSpec;
|
|
116
|
+
export declare function registryType(type: string, inline?: RegistryTypeSpec): RegistryTypeSpec;
|
|
116
117
|
/** True when the snapshot itself carries the type — no tenant needed to emit it. */
|
|
117
118
|
export declare function isSnapshotType(type: string): boolean;
|
|
118
119
|
/**
|
|
@@ -138,6 +139,7 @@ export declare function isSnapshotType(type: string): boolean;
|
|
|
138
139
|
export declare const REGISTRY_GAPS: Record<string, {
|
|
139
140
|
resourceSubType?: string;
|
|
140
141
|
extraContext?: string[];
|
|
142
|
+
requiredContext?: string[];
|
|
141
143
|
outputRowsFixed?: boolean;
|
|
142
144
|
notEnforcedInputs?: string[];
|
|
143
145
|
}>;
|
|
@@ -181,6 +183,29 @@ export interface TypedContextRow {
|
|
|
181
183
|
/** The row's `required` attribute — 11 context rows in the corpus carry one. */
|
|
182
184
|
required?: boolean;
|
|
183
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* One `uipath:input` payload row spelled out — the `separateInputs` counterpart of
|
|
188
|
+
* {@link TypedContextRow}.
|
|
189
|
+
*
|
|
190
|
+
* `inputs` is a name→value record, so a row's `type` and `target` are derived: the
|
|
191
|
+
* registry's declaration when the type has one, else `json` for a structured value,
|
|
192
|
+
* `string` for a scalar, and the KEY as the target. A real artifact often carries what
|
|
193
|
+
* that cannot express — a connector's `<uipath:input name="start" type="string"
|
|
194
|
+
* value="0" target="query"/>` has a target that is not its name, and a type the
|
|
195
|
+
* registry does not declare. These rows carry their own.
|
|
196
|
+
*/
|
|
197
|
+
export interface TypedInputRow {
|
|
198
|
+
/** Row name — the wire parameter name, e.g. `entityName` or `body`. */
|
|
199
|
+
name: string;
|
|
200
|
+
/** The row's type. Defaults to `string`; `json` rows carry their value in `body`. */
|
|
201
|
+
type?: string;
|
|
202
|
+
/** The `target` attribute — `path`, `query`, `body`, `file`, `bodyField`, … */
|
|
203
|
+
target?: string;
|
|
204
|
+
/** The `value` attribute, for a scalar row. Omitted entirely when absent. */
|
|
205
|
+
value?: string;
|
|
206
|
+
/** The row's CDATA body, for a `json` row — the value itself, or a string when the exact bytes matter. */
|
|
207
|
+
body?: unknown;
|
|
208
|
+
}
|
|
184
209
|
export interface TypedOutputRow {
|
|
185
210
|
/** Row name, e.g. `response` or `Error`. */
|
|
186
211
|
name: string;
|
|
@@ -216,6 +241,8 @@ export interface TypedNodeInput {
|
|
|
216
241
|
contextRows?: TypedContextRow[];
|
|
217
242
|
/** The payload, shaped per the type's `inputPattern`. */
|
|
218
243
|
inputs?: Record<string, unknown>;
|
|
244
|
+
/** Payload rows spelled out, replacing `inputs` — see {@link TypedInputRow}. */
|
|
245
|
+
inputRows?: TypedInputRow[];
|
|
219
246
|
/** The `uipath:type` `version` attribute — see `ActivityNodeOpts.typeVersion`. */
|
|
220
247
|
typeVersion?: string;
|
|
221
248
|
/** The `uipath:inputSchema` body inside `uipath:context` — see `ActivityNodeOpts.inputSchema`. */
|
|
@@ -265,9 +292,13 @@ export interface TypedNodeInput {
|
|
|
265
292
|
* what it had, breaks a byte-exact round-trip. `bpmn-decompile` sets this.
|
|
266
293
|
*/
|
|
267
294
|
contextVerbatim?: boolean;
|
|
295
|
+
/** The type's emission spec, supplied inline — see `ActivityNodeOpts.spec`. */
|
|
296
|
+
spec?: RegistryTypeSpec;
|
|
268
297
|
}
|
|
269
298
|
/** The variable a typed node's output row writes, or `undefined` when it has none. */
|
|
270
|
-
export declare function typedNodeOutputVar(id: string, type: string, outputVar?: string): string | undefined;
|
|
299
|
+
export declare function typedNodeOutputVar(id: string, type: string, outputVar?: string, inline?: RegistryTypeSpec): string | undefined;
|
|
300
|
+
/** `uipath:input` payload rows exactly as the caller spelled them, deriving nothing. */
|
|
301
|
+
export declare function verbatimInputRows(m: BpmnModdle, rows: TypedInputRow[]): El[];
|
|
271
302
|
/**
|
|
272
303
|
* Emit a registry-backed typed node.
|
|
273
304
|
*
|
|
@@ -320,7 +351,7 @@ export declare function createExtensionPayload(m: BpmnModdle, type: string, rows
|
|
|
320
351
|
* @param type - The extension type.
|
|
321
352
|
* @returns Its fields that must be bound, with the target each binding needs.
|
|
322
353
|
*/
|
|
323
|
-
export declare function bindingRequiredFields(type: string): RegistryContextField[];
|
|
354
|
+
export declare function bindingRequiredFields(type: string, inline?: RegistryTypeSpec): RegistryContextField[];
|
|
324
355
|
/**
|
|
325
356
|
* Required context fields the author left unset and the registry cannot default.
|
|
326
357
|
*
|
|
@@ -332,7 +363,7 @@ export declare function bindingRequiredFields(type: string): RegistryContextFiel
|
|
|
332
363
|
* @param context - The context values the author supplied.
|
|
333
364
|
* @returns The names of required fields with no value and no default.
|
|
334
365
|
*/
|
|
335
|
-
export declare function missingRequiredContext(type: string, context?: Record<string, unknown
|
|
366
|
+
export declare function missingRequiredContext(type: string, context?: Record<string, unknown>, inline?: RegistryTypeSpec): string[];
|
|
336
367
|
/**
|
|
337
368
|
* Required PAYLOAD fields the author left unset.
|
|
338
369
|
*
|
|
@@ -357,7 +388,7 @@ export declare function missingRequiredInputs(type: string, inputs?: Record<stri
|
|
|
357
388
|
* genuinely does not spell (it writes `connection`). Reading both makes this
|
|
358
389
|
* agree with the CLI instead of guessing on either side of it.
|
|
359
390
|
*/
|
|
360
|
-
context?: Record<string, unknown
|
|
391
|
+
context?: Record<string, unknown>, inline?: RegistryTypeSpec): string[];
|
|
361
392
|
/**
|
|
362
393
|
* Whether this type's required payload fields are UNSATISFIABLE on the wire.
|
|
363
394
|
*
|
|
@@ -389,5 +420,5 @@ context?: Record<string, unknown>): string[];
|
|
|
389
420
|
* @param type - The extension type.
|
|
390
421
|
* @returns The required payload field names that cannot be expressed, or `[]`.
|
|
391
422
|
*/
|
|
392
|
-
export declare function unsatisfiableRequiredInputs(type: string): string[];
|
|
423
|
+
export declare function unsatisfiableRequiredInputs(type: string, inline?: RegistryTypeSpec): string[];
|
|
393
424
|
export {};
|