@uipath/maestro-builder-sdk 6.14.0 → 6.14.2
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 +90 -86
- package/dist/api-members.md +420 -401
- package/dist/bpmn/bpmn-sdk.d.ts +218 -7
- package/dist/bpmn/bpmn-sdk.js +90 -2
- package/dist/bpmn/check.js +86 -0
- package/dist/bpmn/decompile-cli.js +14 -5
- package/dist/bpmn/decompile.d.ts +29 -0
- package/dist/bpmn/decompile.js +193 -39
- package/dist/bpmn/serialize.js +52 -9
- package/dist/bpmn/typed-node.d.ts +52 -0
- package/dist/bpmn/typed-node.js +43 -0
- package/dist/check.js +31 -14
- package/dist/flow-sdk.d.ts +5 -6
- package/dist/serialize.js +11 -9
- package/package.json +2 -2
package/dist/bpmn/bpmn-sdk.d.ts
CHANGED
|
@@ -378,6 +378,12 @@ export interface BpmnVarDecl {
|
|
|
378
378
|
schema?: unknown;
|
|
379
379
|
/** Mark the declaration `required="true"`, as a process input can be. */
|
|
380
380
|
required?: boolean;
|
|
381
|
+
/** The product's "an author added this" flag — see {@link VarOpts.custom}. */
|
|
382
|
+
custom?: boolean;
|
|
383
|
+
/** The product's "the platform owns this" flag — see {@link VarOpts.internal}. */
|
|
384
|
+
internal?: boolean;
|
|
385
|
+
/** A refinement of `type` the designer carries — see {@link VarOpts.subType}. */
|
|
386
|
+
subType?: string;
|
|
381
387
|
}
|
|
382
388
|
/**
|
|
383
389
|
* A declared external identifier the process needs supplied at deploy time — a
|
|
@@ -393,9 +399,9 @@ export interface BindingDecl {
|
|
|
393
399
|
resource: string;
|
|
394
400
|
/** Which property of that resource is wanted, e.g. `'ConnectionId'`, `'Key'`. */
|
|
395
401
|
propertyAttribute: string;
|
|
396
|
-
/** The value
|
|
402
|
+
/** The value `=bindings.<id>` resolves to — see {@link BindingOpts.value}, the `value` option. */
|
|
397
403
|
default?: string;
|
|
398
|
-
/**
|
|
404
|
+
/** Which resource this is bound to; never resolved — see {@link BindingOpts.resourceKey}. */
|
|
399
405
|
resourceKey?: string;
|
|
400
406
|
/**
|
|
401
407
|
* Narrows the resource, e.g. `'Agent'` for an agent process. Required by some
|
|
@@ -403,6 +409,11 @@ export interface BindingDecl {
|
|
|
403
409
|
*/
|
|
404
410
|
resourceSubType?: string;
|
|
405
411
|
}
|
|
412
|
+
/** One entry of {@link BpmnBuilder.bindings} — a `.binding()` call written as data. */
|
|
413
|
+
export interface BindingEntry extends BindingOpts {
|
|
414
|
+
/** The binding's id — what `=bindings.<id>` refers to. */
|
|
415
|
+
id: string;
|
|
416
|
+
}
|
|
406
417
|
/** A definitions-level `bpmn:message` declaration, referenced by message events. */
|
|
407
418
|
export interface MessageDecl {
|
|
408
419
|
/** The declaration's id — what an event's `messageRef` points at. */
|
|
@@ -419,6 +430,50 @@ export interface ErrorDecl {
|
|
|
419
430
|
/** The error code the runtime matches on. */
|
|
420
431
|
code?: string;
|
|
421
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Non-authoring state retained by decompile/recompile.
|
|
435
|
+
*
|
|
436
|
+
* The BPMN counterpart of the Case SDK's `CaseJsonPreservation`, and named to match it:
|
|
437
|
+
* one block, carried rather than authored, that a reader can skip.
|
|
438
|
+
*
|
|
439
|
+
* Everything here is data the source document carried that NOTHING derives and nothing
|
|
440
|
+
* executes. It is not a feature to reach for: `decompile` writes it, an author leaves
|
|
441
|
+
* it alone, and deleting it changes no behaviour — only whether the file still matches
|
|
442
|
+
* the one it came from.
|
|
443
|
+
*
|
|
444
|
+
* It deliberately cannot carry anything authorable. A position, a type, a condition, a
|
|
445
|
+
* schema — those are the typed builder's job, and hiding one here would make it
|
|
446
|
+
* invisible to `check` and to whoever reads the source.
|
|
447
|
+
*
|
|
448
|
+
* Distinct from LAYOUT, which this does not hold. A diagram is content: a person reads
|
|
449
|
+
* it, and the Flow SDK lets an author set it (`.layout()`). The members here have no
|
|
450
|
+
* meaning apart from "what the file said".
|
|
451
|
+
*/
|
|
452
|
+
export interface BpmnPreservation {
|
|
453
|
+
/**
|
|
454
|
+
* The order declarations are written in, by id.
|
|
455
|
+
*
|
|
456
|
+
* Needed because a declaration folded onto the output row that fills it has no line
|
|
457
|
+
* of its own to carry its position, and derived declarations would otherwise land
|
|
458
|
+
* after every declared one. No rule recovers the real order: it is the designer's
|
|
459
|
+
* creation order, and it follows the owning element's document order in none of the
|
|
460
|
+
* five exports in `research/bpmn-roundtrip/corpus/` (47, 36, 19, 16 and 22
|
|
461
|
+
* inversions).
|
|
462
|
+
*
|
|
463
|
+
* Nothing reads it at run time — the engine seeds declarations into one scope by id,
|
|
464
|
+
* and a process input is matched by display `name`, not position. `uip maestro bpmn
|
|
465
|
+
* validate` answers `Success` on a reordered block. What it buys is the variables
|
|
466
|
+
* panel listing things as the source did, and a `bpmn merge` whose diff covers what
|
|
467
|
+
* was edited rather than all hundred declarations.
|
|
468
|
+
*
|
|
469
|
+
* It applies WITHIN each direction group — `uipath:input`, then `uipath:inputOutput`,
|
|
470
|
+
* then `uipath:output` — which is how the product writes them. Ids it omits keep
|
|
471
|
+
* their relative order, after the ones it names, and an id it does not know is
|
|
472
|
+
* ignored. `check` reports all three ways of getting it wrong, because every one of
|
|
473
|
+
* them used to be silent.
|
|
474
|
+
*/
|
|
475
|
+
variableOrder?: string[];
|
|
476
|
+
}
|
|
422
477
|
/**
|
|
423
478
|
* The built in-memory process graph `.build()` returns — the IR `serialize()`
|
|
424
479
|
* walks into `.bpmn` XML.
|
|
@@ -444,6 +499,8 @@ export interface BuiltBpmn {
|
|
|
444
499
|
metadata?: ProcessMetadata;
|
|
445
500
|
/** Named schemas from `.schema()`, which a row's `schema` may reference by id. */
|
|
446
501
|
schemas: Map<string, unknown>;
|
|
502
|
+
/** Non-authoring state carried from the source — see {@link BpmnBuilder.preserve}. */
|
|
503
|
+
preservation?: BpmnPreservation;
|
|
447
504
|
}
|
|
448
505
|
/**
|
|
449
506
|
* Process-level metadata — the `uipath:*` children of the process's own
|
|
@@ -887,13 +944,45 @@ export interface SubProcessOpts extends ActivityOpts {
|
|
|
887
944
|
*/
|
|
888
945
|
payload?: ExtensionPayload;
|
|
889
946
|
}
|
|
947
|
+
/**
|
|
948
|
+
* One entry of {@link ScopeBuilder.vars} — a `.var()` / `.input()` / `.output()` call
|
|
949
|
+
* written as data.
|
|
950
|
+
*/
|
|
951
|
+
export interface VarEntry extends VarOpts {
|
|
952
|
+
/** The variable's id — what expressions read as `vars.<id>`. */
|
|
953
|
+
id: string;
|
|
954
|
+
/** A `types.*` descriptor. */
|
|
955
|
+
type: TypeDesc;
|
|
956
|
+
/** Which declaration this is. Defaults to `'inputOutput'`, the `.var()` kind. */
|
|
957
|
+
direction?: VarDirection;
|
|
958
|
+
}
|
|
959
|
+
/** One entry of {@link BpmnBuilder.schemas} — a `.schema()` call written as data. */
|
|
960
|
+
export interface SchemaEntry {
|
|
961
|
+
/** The schema's id, referenced by a `schema: '<id>'` option. */
|
|
962
|
+
id: string;
|
|
963
|
+
/** The JSON Schema itself. */
|
|
964
|
+
body: unknown;
|
|
965
|
+
}
|
|
890
966
|
/** Options for `.binding()`. */
|
|
891
967
|
export interface BindingOpts {
|
|
892
968
|
/** Display name the designer shows. Defaults to the binding's id. */
|
|
893
969
|
name?: string;
|
|
894
970
|
/**
|
|
895
|
-
* The value
|
|
896
|
-
*
|
|
971
|
+
* **The value.** What `=bindings.<id>` evaluates to, and the only field of a binding
|
|
972
|
+
* the runtime reads.
|
|
973
|
+
*
|
|
974
|
+
* Resolution is `supplied[id] ?? supplied[name] ?? value` — a deploy, or
|
|
975
|
+
* `flow-debug --bindings`, overrides it; absent an override this is used; with
|
|
976
|
+
* neither the binding is UNRESOLVED and a dispatching run refuses to start, naming
|
|
977
|
+
* every one (`local-engine/src/v2/dispatch/bindings.ts`). So a binding with no
|
|
978
|
+
* `value` is a promise that something else will supply it.
|
|
979
|
+
*
|
|
980
|
+
* Real exports leave it out for exactly one thing: a `folderPath`, which is not
|
|
981
|
+
* knowable when the resource is picked. 524 of the 528 bindings in
|
|
982
|
+
* `research/bpmn-roundtrip/corpus/` follow "no `value` iff `propertyAttribute` is
|
|
983
|
+
* `folderPath`".
|
|
984
|
+
*
|
|
985
|
+
* Not to be confused with {@link BindingOpts.resourceKey}, which is never resolved.
|
|
897
986
|
*/
|
|
898
987
|
value?: string;
|
|
899
988
|
/**
|
|
@@ -905,7 +994,33 @@ export interface BindingOpts {
|
|
|
905
994
|
resource?: string;
|
|
906
995
|
/** Which property of that resource is wanted. Defaults to `'value'`. */
|
|
907
996
|
propertyAttribute?: string;
|
|
908
|
-
/**
|
|
997
|
+
/**
|
|
998
|
+
* **Which resource this is bound to** — design-time provenance, never resolved.
|
|
999
|
+
*
|
|
1000
|
+
* Nothing at run time reads it: it identifies the tenant resource the binding was
|
|
1001
|
+
* bound to, so a deploy can re-resolve {@link BindingOpts.value} against the target
|
|
1002
|
+
* tenant and the canvas can show what the binding points at.
|
|
1003
|
+
*
|
|
1004
|
+
* It equals `value` exactly when the property asked for IS the resource's identity —
|
|
1005
|
+
* a queue is identified by its name, so a `name` binding's key and value are the
|
|
1006
|
+
* same string (196 of 202 in the corpus). It differs whenever they are different
|
|
1007
|
+
* things:
|
|
1008
|
+
*
|
|
1009
|
+
* - a `folderKey` binding's key is the CONNECTION's key, because the folder is
|
|
1010
|
+
* resolved through the connection, while its value is the folder's own key
|
|
1011
|
+
* (9 of 9; `folderCompanionKeys` in `serialize.ts` exists to write this);
|
|
1012
|
+
* - a compound process key `<folderPath>.<name>` projects onto the pair of bindings
|
|
1013
|
+
* as its two halves — the `folderPath` binding's value is the folder, the `name`
|
|
1014
|
+
* binding's value is the name;
|
|
1015
|
+
* - a renamed resource keeps the key it was bound under and tracks the new name in
|
|
1016
|
+
* `value`.
|
|
1017
|
+
*
|
|
1018
|
+
* **The author-side `bindings.json` uses this field the other way round** — there
|
|
1019
|
+
* `resourceKey` is the real tenant value to inline and `default` is an offline
|
|
1020
|
+
* placeholder, which is why `Bindings.resolve()` prefers `resourceKey` while the
|
|
1021
|
+
* engine reads only `value`. Both are right for their own file; `connector.ts`
|
|
1022
|
+
* translates between them. This option is the WIRE meaning.
|
|
1023
|
+
*/
|
|
909
1024
|
resourceKey?: string;
|
|
910
1025
|
/**
|
|
911
1026
|
* Narrows the resource, e.g. `'Agent'` for an agent process.
|
|
@@ -1414,6 +1529,33 @@ export interface VarOpts {
|
|
|
1414
1529
|
schema?: unknown;
|
|
1415
1530
|
/** Mark the declaration `required="true"`, as a process input can be. */
|
|
1416
1531
|
required?: boolean;
|
|
1532
|
+
/**
|
|
1533
|
+
* The product's `custom="true"` flag: an author added this declaration, as opposed
|
|
1534
|
+
* to its coming with a node's contract.
|
|
1535
|
+
*
|
|
1536
|
+
* The designer writes it on every variable a person typed into the variables panel
|
|
1537
|
+
* and on no variable it derived from a node's output row, which makes it the one
|
|
1538
|
+
* attribute that says which of the two a declaration is. Measured over
|
|
1539
|
+
* `research/bpmn-roundtrip/corpus/`: 119 of 842 declarations carry it, and the split
|
|
1540
|
+
* is clean — a node-output declaration never does.
|
|
1541
|
+
*
|
|
1542
|
+
* Nothing executes differently either way; it is designer bookkeeping, carried so an
|
|
1543
|
+
* import round-trips and so `implicitNodeVars` has an explicit signal rather than an
|
|
1544
|
+
* inferred one.
|
|
1545
|
+
*/
|
|
1546
|
+
custom?: boolean;
|
|
1547
|
+
/**
|
|
1548
|
+
* The product's `internal="true"` flag: the platform owns this declaration, not the
|
|
1549
|
+
* author — `internalCustomInstanceId` and its kind. 3 in the corpus. Carried, not
|
|
1550
|
+
* interpreted.
|
|
1551
|
+
*/
|
|
1552
|
+
internal?: boolean;
|
|
1553
|
+
/**
|
|
1554
|
+
* A refinement of `type` the designer carries, e.g. `subType="object"` on a
|
|
1555
|
+
* `jsonSchema` variable that holds an object rather than an array. 5 in the corpus.
|
|
1556
|
+
* Carried, not interpreted.
|
|
1557
|
+
*/
|
|
1558
|
+
subType?: string;
|
|
1417
1559
|
}
|
|
1418
1560
|
/**
|
|
1419
1561
|
* Boundary events declared on the activity they attach to — the callback every
|
|
@@ -2772,6 +2914,32 @@ declare abstract class ScopeBuilder {
|
|
|
2772
2914
|
* @returns This builder, so calls chain.
|
|
2773
2915
|
*/
|
|
2774
2916
|
output(id: string, type: TypeDesc, opts?: VarOpts): this;
|
|
2917
|
+
/**
|
|
2918
|
+
* Several declarations as one call — the array form of `.var()` / `.input()` /
|
|
2919
|
+
* `.output()`.
|
|
2920
|
+
*
|
|
2921
|
+
* Identical in effect, and there for how it READS: a real process declares dozens,
|
|
2922
|
+
* and one `.var(…)` per line is a wall of repeated method names that the eye has to
|
|
2923
|
+
* scan past to find the data. As an array the block indents, the prefix is written
|
|
2924
|
+
* once, and the declarations line up as the table they are. `decompile` emits this
|
|
2925
|
+
* form; the singular calls are unchanged and can be mixed with it freely.
|
|
2926
|
+
*
|
|
2927
|
+
* Each entry's `direction` picks which of the three it is, defaulting to
|
|
2928
|
+
* `inputOutput` — so one block can carry a process's inputs, its internal state and
|
|
2929
|
+
* its outputs in the order the document had them.
|
|
2930
|
+
*
|
|
2931
|
+
* ```ts
|
|
2932
|
+
* .vars([
|
|
2933
|
+
* { id: 'invoiceId', type: 'string', direction: 'input', required: true },
|
|
2934
|
+
* { id: 'total', type: 'number', default: 0 },
|
|
2935
|
+
* { id: 'approved', type: 'boolean', direction: 'output' },
|
|
2936
|
+
* ])
|
|
2937
|
+
* ```
|
|
2938
|
+
*
|
|
2939
|
+
* @param entries - The declarations, in the order they should be written.
|
|
2940
|
+
* @returns This builder, so calls chain.
|
|
2941
|
+
*/
|
|
2942
|
+
vars(entries: VarEntry[]): this;
|
|
2775
2943
|
private declareVar;
|
|
2776
2944
|
}
|
|
2777
2945
|
/**
|
|
@@ -3042,6 +3210,24 @@ export declare class BpmnBuilder extends ScopeBuilder {
|
|
|
3042
3210
|
private readonly _id;
|
|
3043
3211
|
private _name?;
|
|
3044
3212
|
private _metadata?;
|
|
3213
|
+
/** Non-authoring state pinned by `.preserve()`. */
|
|
3214
|
+
private _preservation?;
|
|
3215
|
+
/**
|
|
3216
|
+
* Carry non-authoring state from a source document — **written by `decompile`; a
|
|
3217
|
+
* greenfield author never needs this.**
|
|
3218
|
+
*
|
|
3219
|
+
* See {@link BpmnPreservation} for what belongs here and why. In one line: data the
|
|
3220
|
+
* document carried that no rule derives and nothing executes, kept so a
|
|
3221
|
+
* decompile/edit/recompile loop produces the file it started from. An agent editing
|
|
3222
|
+
* such a file should leave the call alone — there is nothing in it to reason about,
|
|
3223
|
+
* and no behaviour to change by changing it.
|
|
3224
|
+
*
|
|
3225
|
+
* Calling it twice REPLACES the block, matching `.layout()` on the Flow side.
|
|
3226
|
+
*
|
|
3227
|
+
* @param preservation - The carried state — see {@link BpmnPreservation}.
|
|
3228
|
+
* @returns This builder, so calls chain.
|
|
3229
|
+
*/
|
|
3230
|
+
preserve(preservation: BpmnPreservation): this;
|
|
3045
3231
|
/**
|
|
3046
3232
|
* @param _id - The process id, as passed to `bpmn()`.
|
|
3047
3233
|
* @returns The top-level builder.
|
|
@@ -3127,10 +3313,23 @@ export declare class BpmnBuilder extends ScopeBuilder {
|
|
|
3127
3313
|
* ```
|
|
3128
3314
|
*/
|
|
3129
3315
|
schema(id: string, schema: unknown): this;
|
|
3316
|
+
/**
|
|
3317
|
+
* Several named schemas as one call — the array form of {@link BpmnBuilder.schema}.
|
|
3318
|
+
*
|
|
3319
|
+
* Same reason as {@link ScopeBuilder.vars}: a process that repeats one shape across
|
|
3320
|
+
* twenty nodes declares a handful of these, and the array indents them into a block
|
|
3321
|
+
* instead of a column of repeated prefixes. `decompile` emits this form.
|
|
3322
|
+
*
|
|
3323
|
+
* @param entries - The schemas to declare.
|
|
3324
|
+
* @returns This builder, so calls chain.
|
|
3325
|
+
*/
|
|
3326
|
+
schemas(entries: SchemaEntry[]): this;
|
|
3130
3327
|
/**
|
|
3131
3328
|
* Declare an external identifier the process needs supplied — a base URL, a
|
|
3132
3329
|
* folder path, a process name (`uipath:binding`). Expressions read it as
|
|
3133
|
-
* `=bindings.<id>`, and
|
|
3330
|
+
* `=bindings.<id>`, and it resolves to `value` unless a deploy or `--bindings`
|
|
3331
|
+
* overrides it — with neither, the binding is unresolved and a dispatching run
|
|
3332
|
+
* refuses to start.
|
|
3134
3333
|
*
|
|
3135
3334
|
* @remarks
|
|
3136
3335
|
* A connector's `connection`/`folder` already produce their own bindings at
|
|
@@ -3148,10 +3347,22 @@ export declare class BpmnBuilder extends ScopeBuilder {
|
|
|
3148
3347
|
* ```
|
|
3149
3348
|
*
|
|
3150
3349
|
* @param id - The binding's id — what `=bindings.<id>` refers to.
|
|
3151
|
-
* @param opts - Display `name`, the `value` it
|
|
3350
|
+
* @param opts - Display `name`, the `value` it resolves to, and which resource it addresses.
|
|
3152
3351
|
* @returns This builder, so calls chain.
|
|
3153
3352
|
*/
|
|
3154
3353
|
binding(id: string, opts?: BindingOpts): this;
|
|
3354
|
+
/**
|
|
3355
|
+
* Several bindings as one call — the array form of {@link BpmnBuilder.binding}.
|
|
3356
|
+
*
|
|
3357
|
+
* This is the block the array form was wanted for: bindings come in pairs, one per
|
|
3358
|
+
* resource the process touches, and a real export carries dozens — 73 in
|
|
3359
|
+
* `InvoiceApproval.bpmn.ts`, which was the single largest run of repeated method
|
|
3360
|
+
* names in the file. `decompile` emits this form.
|
|
3361
|
+
*
|
|
3362
|
+
* @param entries - The bindings to declare, in document order.
|
|
3363
|
+
* @returns This builder, so calls chain.
|
|
3364
|
+
*/
|
|
3365
|
+
bindings(entries: BindingEntry[]): this;
|
|
3155
3366
|
/**
|
|
3156
3367
|
* Finish the process and return the graph the serializer turns into XML.
|
|
3157
3368
|
*
|
package/dist/bpmn/bpmn-sdk.js
CHANGED
|
@@ -2097,6 +2097,36 @@ class ScopeBuilder {
|
|
|
2097
2097
|
output(id, type, opts = {}) {
|
|
2098
2098
|
return this.declareVar(id, type, 'output', opts);
|
|
2099
2099
|
}
|
|
2100
|
+
/**
|
|
2101
|
+
* Several declarations as one call — the array form of `.var()` / `.input()` /
|
|
2102
|
+
* `.output()`.
|
|
2103
|
+
*
|
|
2104
|
+
* Identical in effect, and there for how it READS: a real process declares dozens,
|
|
2105
|
+
* and one `.var(…)` per line is a wall of repeated method names that the eye has to
|
|
2106
|
+
* scan past to find the data. As an array the block indents, the prefix is written
|
|
2107
|
+
* once, and the declarations line up as the table they are. `decompile` emits this
|
|
2108
|
+
* form; the singular calls are unchanged and can be mixed with it freely.
|
|
2109
|
+
*
|
|
2110
|
+
* Each entry's `direction` picks which of the three it is, defaulting to
|
|
2111
|
+
* `inputOutput` — so one block can carry a process's inputs, its internal state and
|
|
2112
|
+
* its outputs in the order the document had them.
|
|
2113
|
+
*
|
|
2114
|
+
* ```ts
|
|
2115
|
+
* .vars([
|
|
2116
|
+
* { id: 'invoiceId', type: 'string', direction: 'input', required: true },
|
|
2117
|
+
* { id: 'total', type: 'number', default: 0 },
|
|
2118
|
+
* { id: 'approved', type: 'boolean', direction: 'output' },
|
|
2119
|
+
* ])
|
|
2120
|
+
* ```
|
|
2121
|
+
*
|
|
2122
|
+
* @param entries - The declarations, in the order they should be written.
|
|
2123
|
+
* @returns This builder, so calls chain.
|
|
2124
|
+
*/
|
|
2125
|
+
vars(entries) {
|
|
2126
|
+
for (const e of entries)
|
|
2127
|
+
this.declareVar(e.id, e.type, e.direction ?? 'inputOutput', e);
|
|
2128
|
+
return this;
|
|
2129
|
+
}
|
|
2100
2130
|
declareVar(id, type, direction, opts) {
|
|
2101
2131
|
this._vars.push({
|
|
2102
2132
|
id,
|
|
@@ -2107,6 +2137,9 @@ class ScopeBuilder {
|
|
|
2107
2137
|
elementId: opts.elementId,
|
|
2108
2138
|
schema: opts.schema,
|
|
2109
2139
|
required: opts.required,
|
|
2140
|
+
custom: opts.custom,
|
|
2141
|
+
internal: opts.internal,
|
|
2142
|
+
subType: opts.subType,
|
|
2110
2143
|
});
|
|
2111
2144
|
return this;
|
|
2112
2145
|
}
|
|
@@ -2433,6 +2466,27 @@ export class BpmnBuilder extends ScopeBuilder {
|
|
|
2433
2466
|
_id;
|
|
2434
2467
|
_name;
|
|
2435
2468
|
_metadata;
|
|
2469
|
+
/** Non-authoring state pinned by `.preserve()`. */
|
|
2470
|
+
_preservation;
|
|
2471
|
+
/**
|
|
2472
|
+
* Carry non-authoring state from a source document — **written by `decompile`; a
|
|
2473
|
+
* greenfield author never needs this.**
|
|
2474
|
+
*
|
|
2475
|
+
* See {@link BpmnPreservation} for what belongs here and why. In one line: data the
|
|
2476
|
+
* document carried that no rule derives and nothing executes, kept so a
|
|
2477
|
+
* decompile/edit/recompile loop produces the file it started from. An agent editing
|
|
2478
|
+
* such a file should leave the call alone — there is nothing in it to reason about,
|
|
2479
|
+
* and no behaviour to change by changing it.
|
|
2480
|
+
*
|
|
2481
|
+
* Calling it twice REPLACES the block, matching `.layout()` on the Flow side.
|
|
2482
|
+
*
|
|
2483
|
+
* @param preservation - The carried state — see {@link BpmnPreservation}.
|
|
2484
|
+
* @returns This builder, so calls chain.
|
|
2485
|
+
*/
|
|
2486
|
+
preserve(preservation) {
|
|
2487
|
+
this._preservation = preservation;
|
|
2488
|
+
return this;
|
|
2489
|
+
}
|
|
2436
2490
|
/**
|
|
2437
2491
|
* @param _id - The process id, as passed to `bpmn()`.
|
|
2438
2492
|
* @returns The top-level builder.
|
|
@@ -2536,10 +2590,27 @@ export class BpmnBuilder extends ScopeBuilder {
|
|
|
2536
2590
|
this._schemas.set(id, schema);
|
|
2537
2591
|
return this;
|
|
2538
2592
|
}
|
|
2593
|
+
/**
|
|
2594
|
+
* Several named schemas as one call — the array form of {@link BpmnBuilder.schema}.
|
|
2595
|
+
*
|
|
2596
|
+
* Same reason as {@link ScopeBuilder.vars}: a process that repeats one shape across
|
|
2597
|
+
* twenty nodes declares a handful of these, and the array indents them into a block
|
|
2598
|
+
* instead of a column of repeated prefixes. `decompile` emits this form.
|
|
2599
|
+
*
|
|
2600
|
+
* @param entries - The schemas to declare.
|
|
2601
|
+
* @returns This builder, so calls chain.
|
|
2602
|
+
*/
|
|
2603
|
+
schemas(entries) {
|
|
2604
|
+
for (const e of entries)
|
|
2605
|
+
this._schemas.set(e.id, e.body);
|
|
2606
|
+
return this;
|
|
2607
|
+
}
|
|
2539
2608
|
/**
|
|
2540
2609
|
* Declare an external identifier the process needs supplied — a base URL, a
|
|
2541
2610
|
* folder path, a process name (`uipath:binding`). Expressions read it as
|
|
2542
|
-
* `=bindings.<id>`, and
|
|
2611
|
+
* `=bindings.<id>`, and it resolves to `value` unless a deploy or `--bindings`
|
|
2612
|
+
* overrides it — with neither, the binding is unresolved and a dispatching run
|
|
2613
|
+
* refuses to start.
|
|
2543
2614
|
*
|
|
2544
2615
|
* @remarks
|
|
2545
2616
|
* A connector's `connection`/`folder` already produce their own bindings at
|
|
@@ -2557,7 +2628,7 @@ export class BpmnBuilder extends ScopeBuilder {
|
|
|
2557
2628
|
* ```
|
|
2558
2629
|
*
|
|
2559
2630
|
* @param id - The binding's id — what `=bindings.<id>` refers to.
|
|
2560
|
-
* @param opts - Display `name`, the `value` it
|
|
2631
|
+
* @param opts - Display `name`, the `value` it resolves to, and which resource it addresses.
|
|
2561
2632
|
* @returns This builder, so calls chain.
|
|
2562
2633
|
*/
|
|
2563
2634
|
binding(id, opts = {}) {
|
|
@@ -2575,6 +2646,22 @@ export class BpmnBuilder extends ScopeBuilder {
|
|
|
2575
2646
|
});
|
|
2576
2647
|
return this;
|
|
2577
2648
|
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Several bindings as one call — the array form of {@link BpmnBuilder.binding}.
|
|
2651
|
+
*
|
|
2652
|
+
* This is the block the array form was wanted for: bindings come in pairs, one per
|
|
2653
|
+
* resource the process touches, and a real export carries dozens — 73 in
|
|
2654
|
+
* `InvoiceApproval.bpmn.ts`, which was the single largest run of repeated method
|
|
2655
|
+
* names in the file. `decompile` emits this form.
|
|
2656
|
+
*
|
|
2657
|
+
* @param entries - The bindings to declare, in document order.
|
|
2658
|
+
* @returns This builder, so calls chain.
|
|
2659
|
+
*/
|
|
2660
|
+
bindings(entries) {
|
|
2661
|
+
for (const e of entries)
|
|
2662
|
+
this.binding(e.id, e);
|
|
2663
|
+
return this;
|
|
2664
|
+
}
|
|
2578
2665
|
/**
|
|
2579
2666
|
* Finish the process and return the graph the serializer turns into XML.
|
|
2580
2667
|
*
|
|
@@ -2643,6 +2730,7 @@ export class BpmnBuilder extends ScopeBuilder {
|
|
|
2643
2730
|
nodes: this._nodes,
|
|
2644
2731
|
flows: this._flows,
|
|
2645
2732
|
schemas: this._schemas,
|
|
2733
|
+
preservation: this._preservation,
|
|
2646
2734
|
};
|
|
2647
2735
|
// First-level validation, intrinsic to running the SDK: catch a reference to
|
|
2648
2736
|
// an undeclared `vars.<name>` HERE — the one thing `uip maestro bpmn validate`
|
package/dist/bpmn/check.js
CHANGED
|
@@ -64,6 +64,7 @@ export function check(built) {
|
|
|
64
64
|
const seenIds = new Set();
|
|
65
65
|
checkScope(built.nodes, built.flows, 'process', diags, seenIds, true);
|
|
66
66
|
checkScopedVars(built, diags);
|
|
67
|
+
checkVariableOrder(built, diags);
|
|
67
68
|
checkDocumentIds(built, diags);
|
|
68
69
|
checkFolderBindings(built, diags);
|
|
69
70
|
checkEntryPointId(built, diags);
|
|
@@ -304,6 +305,91 @@ function checkDocumentIds(built, diags) {
|
|
|
304
305
|
for (const e of built.errors)
|
|
305
306
|
claim(e.id, `error "${e.name}"`);
|
|
306
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* A pinned declaration order must name the declarations it is ordering.
|
|
310
|
+
*
|
|
311
|
+
* `.preserve({ variableOrder })` is round-trip bookkeeping — `decompile` writes it because a
|
|
312
|
+
* declaration folded onto its output row has no line of its own to carry its
|
|
313
|
+
* position, and nothing derives that position (it is the designer's creation order,
|
|
314
|
+
* which follows the owning element's document order in none of the five exports in
|
|
315
|
+
* `research/bpmn-roundtrip/corpus/`). An author never writes one.
|
|
316
|
+
*
|
|
317
|
+
* Which is exactly why it needs checking. Every malformed list is applied in silence:
|
|
318
|
+
* an id no declaration has is ignored, a DUPLICATE is harmless, and a PARTIAL list
|
|
319
|
+
* promotes what it names and demotes everything else — the mistake an author editing
|
|
320
|
+
* a decompiled file makes by adding a variable and not the array. Nothing else
|
|
321
|
+
* reports it: the order changes no behaviour, `uip maestro bpmn validate` answers
|
|
322
|
+
* `Success` on a reordered block, and the only symptom is a variables panel that
|
|
323
|
+
* lists things differently than the file it came from.
|
|
324
|
+
*
|
|
325
|
+
* Warnings, not errors, because nothing it can say makes the process invalid.
|
|
326
|
+
*/
|
|
327
|
+
function checkVariableOrder(built, diags) {
|
|
328
|
+
const order = built.preservation?.variableOrder;
|
|
329
|
+
if (!order?.length)
|
|
330
|
+
return;
|
|
331
|
+
// Two sets, because the order applies to ONE `uipath:variables` block. `root` is what
|
|
332
|
+
// the order governs and so what it has to be complete over; `anywhere` also holds the
|
|
333
|
+
// sub-process blocks, whose ids are legal to name (they rank last and keep their
|
|
334
|
+
// relative order) and must not be reported as unknown.
|
|
335
|
+
//
|
|
336
|
+
// Without that split, every process with a sub-process block was INCOMPLETE by
|
|
337
|
+
// construction — `billing-disputes` reported its 24 sub-process declarations as left
|
|
338
|
+
// out, when a sub-process declaration is never folded and so already states its
|
|
339
|
+
// position by its line.
|
|
340
|
+
const root = new Set();
|
|
341
|
+
// A derived declaration is not in `built.variables` — it is created at serialize
|
|
342
|
+
// time from the row that fills it — so ask the derivation itself rather than
|
|
343
|
+
// re-deriving the rule here, which is how the two sets drifted apart before.
|
|
344
|
+
for (const v of [...built.variables, ...implicitNodeVars(built.nodes, built.variables)])
|
|
345
|
+
root.add(v.id);
|
|
346
|
+
const anywhere = new Set(root);
|
|
347
|
+
const collectNested = (nodes) => {
|
|
348
|
+
for (const n of nodes) {
|
|
349
|
+
if (n.kind !== 'subProcess')
|
|
350
|
+
continue;
|
|
351
|
+
for (const v of n.variables)
|
|
352
|
+
anywhere.add(v.id);
|
|
353
|
+
for (const v of implicitNodeVars(n.nodes, n.variables))
|
|
354
|
+
anywhere.add(v.id);
|
|
355
|
+
collectNested(n.nodes);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
collectNested(built.nodes);
|
|
359
|
+
const seen = new Set();
|
|
360
|
+
for (const id of order) {
|
|
361
|
+
if (!anywhere.has(id))
|
|
362
|
+
diags.push({
|
|
363
|
+
level: 'warning',
|
|
364
|
+
code: 'VARIABLE_ORDER_UNKNOWN_ID',
|
|
365
|
+
message: `.preserve({ variableOrder }) names "${id}", which no declaration has. It is ignored — ` +
|
|
366
|
+
`the order is round-trip bookkeeping written by decompile, so a stale id usually means ` +
|
|
367
|
+
`a variable was renamed or removed without updating the list.`,
|
|
368
|
+
where: id,
|
|
369
|
+
});
|
|
370
|
+
if (seen.has(id))
|
|
371
|
+
diags.push({
|
|
372
|
+
level: 'warning',
|
|
373
|
+
code: 'VARIABLE_ORDER_DUPLICATE_ID',
|
|
374
|
+
message: `.preserve({ variableOrder }) names "${id}" more than once. The first position wins; drop the rest.`,
|
|
375
|
+
where: id,
|
|
376
|
+
});
|
|
377
|
+
seen.add(id);
|
|
378
|
+
}
|
|
379
|
+
// The dangerous shape: a list that names SOME of them. Everything it leaves out is
|
|
380
|
+
// written after everything it names, which reorders declarations the author never
|
|
381
|
+
// touched — and looks like nothing went wrong.
|
|
382
|
+
const missing = [...root].filter((id) => !seen.has(id));
|
|
383
|
+
if (missing.length)
|
|
384
|
+
diags.push({
|
|
385
|
+
level: 'warning',
|
|
386
|
+
code: 'VARIABLE_ORDER_INCOMPLETE',
|
|
387
|
+
message: `.preserve({ variableOrder }) leaves out ${missing.length} declaration(s) — ${missing.slice(0, 5).join(', ')}` +
|
|
388
|
+
`${missing.length > 5 ? `, and ${missing.length - 5} more` : ''}. ` +
|
|
389
|
+
`They are written after every id the list names, which reorders the block. List them all, or drop the call.`,
|
|
390
|
+
where: missing[0],
|
|
391
|
+
});
|
|
392
|
+
}
|
|
307
393
|
/**
|
|
308
394
|
* A variable scoped with `elementId` must name an element that exists.
|
|
309
395
|
*
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* decompile-cli — `<Name>.bpmn` → `<Name>.bpmn.ts`
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
|
-
* node --experimental-strip-types decompile-cli.js <Name.bpmn> [-o Name.bpmn.ts] [--import <specifier>] [--style explicit|nested] [--keep-flow-ids]
|
|
6
|
+
* node --experimental-strip-types decompile-cli.js <Name.bpmn> [-o Name.bpmn.ts] [--import <specifier>] [--style explicit|nested] [--keep-flow-ids] [--keep-unused-bindings]
|
|
7
7
|
*
|
|
8
8
|
* The reverse of compile-cli: reads a `.bpmn` and emits builder source whose
|
|
9
9
|
* default export re-serializes to the same XML. `--import` sets the module
|
|
@@ -42,7 +42,7 @@ function opt(argv, name) {
|
|
|
42
42
|
*/
|
|
43
43
|
export async function run(argv) {
|
|
44
44
|
if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
|
|
45
|
-
console.error('usage: decompile <Name.bpmn> [-o Name.bpmn.ts] [--import <specifier>] [--style explicit|nested] [--keep-flow-ids]');
|
|
45
|
+
console.error('usage: decompile <Name.bpmn> [-o Name.bpmn.ts] [--import <specifier>] [--style explicit|nested] [--keep-flow-ids] [--keep-unused-bindings]');
|
|
46
46
|
return 2;
|
|
47
47
|
}
|
|
48
48
|
const style = opt(argv, '--style') ?? 'explicit';
|
|
@@ -67,15 +67,19 @@ export async function run(argv) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
const keepFlowIds = argv.includes('--keep-flow-ids');
|
|
70
|
+
const keepUnusedBindings = argv.includes('--keep-unused-bindings');
|
|
70
71
|
const flags = new Set(['-o', '--import', '--style']);
|
|
71
|
-
const
|
|
72
|
+
const bare = new Set(['--keep-flow-ids', '--keep-unused-bindings']);
|
|
73
|
+
const input = argv.find((a, i) => !bare.has(a) && !flags.has(a) && !flags.has(argv[i - 1]));
|
|
72
74
|
if (!input) {
|
|
73
75
|
console.error('decompile: missing <Name.bpmn>');
|
|
74
76
|
return 2;
|
|
75
77
|
}
|
|
76
78
|
const xml = readFileSync(input, 'utf8');
|
|
77
79
|
const importSpecifier = opt(argv, '--import') ?? BPMN_IMPORT;
|
|
78
|
-
let
|
|
80
|
+
let pruned = [];
|
|
81
|
+
const base0 = { importSpecifier, keepUnusedBindings, onPrune: (ids) => (pruned = ids) };
|
|
82
|
+
let source = await decompile(xml, base0);
|
|
79
83
|
let lifted;
|
|
80
84
|
let fallback;
|
|
81
85
|
if (style === 'nested') {
|
|
@@ -86,7 +90,7 @@ export async function run(argv) {
|
|
|
86
90
|
const sdkEntry = fileURLToPath(new URL('./bpmn-sdk.js', import.meta.url));
|
|
87
91
|
for (const sequenceMode of [true, false]) {
|
|
88
92
|
let summary;
|
|
89
|
-
const nested = await decompile(xml, {
|
|
93
|
+
const nested = await decompile(xml, { ...base0, style: 'nested', relabelFlows: !keepFlowIds, sequenceMode, onLift: (s) => (summary = s) });
|
|
90
94
|
const renamed = new Map((summary?.renamedFlows ?? []).map((r) => [r.from, r.to]));
|
|
91
95
|
const verdict = await sameGraph(source, nested, sdkEntry, renamed);
|
|
92
96
|
if (verdict.same) {
|
|
@@ -102,6 +106,11 @@ export async function run(argv) {
|
|
|
102
106
|
const out = opt(argv, '-o') ?? defaultSourceOut(`${base}.bpmn.ts`);
|
|
103
107
|
writeFileSync(out, source);
|
|
104
108
|
console.log(`decompile: wrote ${out}`);
|
|
109
|
+
if (pruned.length) {
|
|
110
|
+
// Never silent: these are declarations the source had and the output does not.
|
|
111
|
+
console.log(`decompile: dropped ${pruned.length} binding(s) nothing references — ${pruned.slice(0, 8).join(', ')}` +
|
|
112
|
+
`${pruned.length > 8 ? `, and ${pruned.length - 8} more` : ''}. Pass --keep-unused-bindings to echo them.`);
|
|
113
|
+
}
|
|
105
114
|
if (lifted) {
|
|
106
115
|
const flat = lifted.leftFlat.length ? `; left flat: ${lifted.leftFlat.map((r) => `${r.id} (${r.reason})`).join('; ')}` : '';
|
|
107
116
|
const renamed = lifted.renamedFlows.length
|
package/dist/bpmn/decompile.d.ts
CHANGED
|
@@ -48,6 +48,35 @@ export interface BpmnDecompileOptions {
|
|
|
48
48
|
sequenceMode?: boolean;
|
|
49
49
|
/** Receives what the nested style lifted and what it left flat, and why. */
|
|
50
50
|
onLift?: (summary: LiftSummary) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Echo binding declarations that NOTHING in the document references. Defaults to
|
|
53
|
+
* `false` — they are dropped, and {@link BpmnDecompileOptions.onPrune} is told.
|
|
54
|
+
*
|
|
55
|
+
* The designer writes a binding pair every time a resource is picked and collects
|
|
56
|
+
* none of them, so a real export accumulates rows that no `=bindings.<id>` reads:
|
|
57
|
+
* 298 of 528 across `research/bpmn-roundtrip/corpus/`, including four `folderPath`
|
|
58
|
+
* rows for one queue and a whole earlier naming of two others. There is no way to
|
|
59
|
+
* remove one from the canvas, so an author who never decompiles is stuck with them.
|
|
60
|
+
*
|
|
61
|
+
* They are not inert. A binding with no `value` is UNRESOLVED, and the engine
|
|
62
|
+
* refuses to start a dispatching run listing every one of them
|
|
63
|
+
* (`local-engine/src/v2/dispatch/bindings.ts`, `describeMissingBindings`) — 105 on
|
|
64
|
+
* `billing-disputes`, 74 of which nothing references. `uip maestro bpmn validate`
|
|
65
|
+
* reports none of this: it answers `Success` on every corpus file.
|
|
66
|
+
*
|
|
67
|
+
* Dropping one is safe in the direction that matters. Solution resources are
|
|
68
|
+
* derived by walking NODES and matching each one's connection back to a binding
|
|
69
|
+
* (`connectionResources` in `bindings-v2.ts`), so a row no node uses provisions
|
|
70
|
+
* nothing. And "referenced" is decided over the whole document text, so any mention
|
|
71
|
+
* at all keeps the row — the failure mode is keeping a dead binding, never dropping
|
|
72
|
+
* a live one.
|
|
73
|
+
*
|
|
74
|
+
* Set `true` (`--keep-unused-bindings`) for a byte-exact round trip, which is what
|
|
75
|
+
* `research/bpmn-roundtrip/roundtrip.sh` measures.
|
|
76
|
+
*/
|
|
77
|
+
keepUnusedBindings?: boolean;
|
|
78
|
+
/** Receives the binding ids dropped as unreferenced — see {@link BpmnDecompileOptions.keepUnusedBindings}. */
|
|
79
|
+
onPrune?: (droppedBindingIds: string[]) => void;
|
|
51
80
|
}
|
|
52
81
|
/** What `style: 'nested'` did — see {@link BpmnDecompileOptions.style}. */
|
|
53
82
|
export interface LiftSummary {
|