@0dep/bpmn-extensions 0.0.4 → 0.0.5

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @0dep/bpmn-extensions
2
2
 
3
- [![Built latest](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml/badge.svg)](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml)[![Coverage Status](https://coveralls.io/repos/github/zerodep/bpmn-extensions/badge.svg?branch=main)](https://coveralls.io/github/zerodep/bpmn-extensions?branch=main)[![npm version](https://img.shields.io/npm/v/@0dep/bpmn-extensions)](https://www.npmjs.com/package/@0dep/bpmn-extensions)
3
+ [![Built latest](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml/badge.svg)](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml)[![Coverage Status](https://coveralls.io/repos/github/zerodep/bpmn-extensions/badge.svg?branch=main)](https://coveralls.io/github/zerodep/bpmn-extensions?branch=main)
4
4
 
5
5
  Flow extensions for [bpmn-elements](https://github.com/paed01/bpmn-elements) with
6
6
  [FEEL](https://www.omg.org/dmn/) expression support.
@@ -38,6 +38,9 @@ npm install @0dep/bpmn-extensions bpmn-elements
38
38
  process's input becomes variables local to its children.
39
39
  - **`zeebe:taskHeaders`** / **`zeebe:properties`** — exposed on the element content.
40
40
  - **`zeebe:assignmentDefinition`** — assignee / candidate users / groups for user tasks.
41
+ - **`zeebe:priorityDefinition`** / **`zeebe:taskSchedule`** — a user task's `priority` and
42
+ `dueDate` / `followUpDate` resolved onto the element content for a task list to order and
43
+ remind by; FEEL date results are exposed as ISO 8601 strings.
41
44
  - **`zeebe:formDefinition`** — resolves a user task's form (`formId` / `formKey` / `externalReference`,
42
45
  `bindingType`) onto the element content for a task list to render.
43
46
  - **`zeebe:executionListeners`** — blocking start/end job workers around an element, called as
@@ -54,6 +57,9 @@ npm install @0dep/bpmn-extensions bpmn-elements
54
57
  ## API
55
58
 
56
59
  - `extensions(element, context)` — the flow extensions factory; pass it as an environment extension.
60
+ Elements that carry no zeebe extension data (and nothing else to format) get no extension attached
61
+ at all and run untouched; call activities and processes are always attached, since they propagate
62
+ io across process boundaries.
57
63
  - `extendFn(behaviour)` — moddle-context-serializer behaviour extender (lifts the extension data
58
64
  bpmn-elements expects on the behaviour: call activity process id and multi-instance collection).
59
65
  - `FeelExpressions()` — a bpmn-elements `IExpressions` implementation backed by FEEL.
@@ -69,7 +75,7 @@ Wire it into a bpmn-elements definition (see `test/helpers/testHelpers.js` for t
69
75
  ```javascript
70
76
  import { createRequire } from 'node:module';
71
77
  import { strict as assert } from 'node:assert';
72
- import BpmnModdle from 'bpmn-moddle';
78
+ import { BpmnModdle } from 'bpmn-moddle';
73
79
  import * as elements from 'bpmn-elements';
74
80
  import { Serializer, TypeResolver } from 'moddle-context-serializer';
75
81
  import { extensions, extendFn, FeelExpressions, FeelScripts } from '@0dep/bpmn-extensions';
package/dist/index.js CHANGED
@@ -11609,9 +11609,9 @@ function getSpecializer(spec) {
11609
11609
  *
11610
11610
  * @return {T[]}
11611
11611
  */
11612
- const nativeHasOwnProperty$1 = Object.prototype.hasOwnProperty;
11612
+ const nativeHasOwnProperty = Object.prototype.hasOwnProperty;
11613
11613
 
11614
- function isNil$2(obj) {
11614
+ function isNil$1(obj) {
11615
11615
  return obj == null;
11616
11616
  }
11617
11617
 
@@ -11623,8 +11623,8 @@ function isNil$2(obj) {
11623
11623
  *
11624
11624
  * @return {Boolean}
11625
11625
  */
11626
- function has$1(target, key) {
11627
- return !isNil$2(target) && nativeHasOwnProperty$1.call(target, key);
11626
+ function has(target, key) {
11627
+ return !isNil$1(target) && nativeHasOwnProperty.call(target, key);
11628
11628
  }
11629
11629
 
11630
11630
  let nextTagID = 0;
@@ -13107,7 +13107,7 @@ class VariableContext {
13107
13107
  continue;
13108
13108
  }
13109
13109
 
13110
- if (has$1(merged, key)) {
13110
+ if (has(merged, key)) {
13111
13111
 
13112
13112
  // deep merge nested contexts
13113
13113
  merged[key] = this.__merge(merged[key], value);
@@ -13241,7 +13241,7 @@ class Variables {
13241
13241
  return null;
13242
13242
  }
13243
13243
 
13244
- if (!isNil$2(scope.value)) {
13244
+ if (!isNil$1(scope.value)) {
13245
13245
  return scope.value;
13246
13246
  }
13247
13247
  }
@@ -13871,33 +13871,6 @@ const parser = LRParser.deserialize({
13871
13871
  tokenPrec: 2660
13872
13872
  });
13873
13873
 
13874
- /**
13875
- * Flatten array, one level deep.
13876
- *
13877
- * @template T
13878
- *
13879
- * @param {T[][] | T[] | null} [arr]
13880
- *
13881
- * @return {T[]}
13882
- */
13883
- const nativeHasOwnProperty = Object.prototype.hasOwnProperty;
13884
-
13885
- function isNil$1(obj) {
13886
- return obj == null;
13887
- }
13888
-
13889
- /**
13890
- * Return true, if target owns a property with the given key.
13891
- *
13892
- * @param {Object} target
13893
- * @param {String} key
13894
- *
13895
- * @return {Boolean}
13896
- */
13897
- function has(target, key) {
13898
- return !isNil$1(target) && nativeHasOwnProperty.call(target, key);
13899
- }
13900
-
13901
13874
  function isNil(e) {
13902
13875
  return e === null || e === undefined;
13903
13876
  }
@@ -16239,16 +16212,21 @@ function getFeelScope(environment, localVariables) {
16239
16212
 
16240
16213
  /**
16241
16214
  * Format an activity on enter from its behaviour and extensions: documentation and,
16242
- * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
16215
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
16216
+ * `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
16243
16217
  */
16244
16218
  class FormatActivity {
16245
16219
  /**
16246
16220
  * @param {import('bpmn-elements').Activity} activity
16247
16221
  * @param {any} assignmentDefinition
16222
+ * @param {any} [priorityDefinition]
16223
+ * @param {any} [taskSchedule]
16248
16224
  */
16249
- constructor(activity, assignmentDefinition) {
16225
+ constructor(activity, assignmentDefinition, priorityDefinition, taskSchedule) {
16250
16226
  this.activity = activity;
16251
16227
  this.assignmentDefinition = assignmentDefinition;
16228
+ this.priorityDefinition = priorityDefinition;
16229
+ this.taskSchedule = taskSchedule;
16252
16230
  }
16253
16231
  /**
16254
16232
  * @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
@@ -16260,7 +16238,7 @@ class FormatActivity {
16260
16238
  const documentation = this.activity.behaviour.documentation;
16261
16239
  if (documentation && !elementApi.content.description) {
16262
16240
  const text = documentation[0]?.text;
16263
- if (text) result.description = resolveValue(text, scope);
16241
+ if (text) result.description = /** @type {string} */ (resolveValue(text, scope));
16264
16242
  }
16265
16243
 
16266
16244
  const assignment = this.assignmentDefinition;
@@ -16273,6 +16251,22 @@ class FormatActivity {
16273
16251
  if (groups) result.candidateGroups = groups;
16274
16252
  }
16275
16253
 
16254
+ const priority = this.priorityDefinition?.priority;
16255
+ if (priority !== undefined) {
16256
+ const resolved = resolveValue(priority, scope);
16257
+ // A static attribute value is a string — expose a numeric one as a number (like retries).
16258
+ const num = Number(resolved);
16259
+ /** @type {Number | string | undefined} */
16260
+ result.priority = typeof resolved === 'string' && resolved.trim() !== '' && Number.isFinite(num) ? num : resolved;
16261
+ }
16262
+
16263
+ const schedule = this.taskSchedule;
16264
+ if (schedule) {
16265
+ const { dueDate, followUpDate } = schedule;
16266
+ if (dueDate !== undefined) result.dueDate = resolveDate(dueDate, scope);
16267
+ if (followUpDate !== undefined) result.followUpDate = resolveDate(followUpDate, scope);
16268
+ }
16269
+
16276
16270
  return result;
16277
16271
  }
16278
16272
  }
@@ -16295,15 +16289,33 @@ class FormatProcess {
16295
16289
  const documentation = this.process.behaviour.documentation;
16296
16290
  if (documentation && !elementApi.content.description) {
16297
16291
  const text = documentation[0]?.text;
16298
- if (text) result.description = resolveValue(text, getFeelScope(elementApi.environment));
16292
+ if (text) result.description = /** @type {string} */ (resolveValue(text, getFeelScope(elementApi.environment)));
16299
16293
  }
16300
16294
  return result;
16301
16295
  }
16302
16296
  }
16303
16297
 
16298
+ /**
16299
+ * Resolve a due/follow-up date to an ISO 8601 string. A FEEL temporal result (a luxon
16300
+ * DateTime) or a Date is ISO-stringified — content is JSON-serialized on `getState()`, so a
16301
+ * string is the shape that survives a recover round trip. Anything else passes through as-is.
16302
+ * @param {any} value
16303
+ * @param {any} scope
16304
+ * @returns {string | undefined} Date as iso string
16305
+ */
16306
+ function resolveDate(value, scope) {
16307
+ const resolved = resolveValue(value, scope);
16308
+ if (typeof resolved?.toISO === 'function') return resolved.toISO();
16309
+ if (resolved instanceof Date) return resolved.toISOString();
16310
+ return resolved;
16311
+ }
16312
+
16304
16313
  /**
16305
16314
  * Resolve a candidate users/groups value to a string array. A FEEL expression may yield an
16306
16315
  * array directly, otherwise a comma-separated string is split.
16316
+ * @param {any} value
16317
+ * @param {any} scope
16318
+ * @returns {string[] | undefined}
16307
16319
  */
16308
16320
  function resolveList(value, scope) {
16309
16321
  if (!value) return undefined;
@@ -16652,6 +16664,7 @@ class Subscription {
16652
16664
  * @property {any} [calledDecision]
16653
16665
  * @property {Function} [Service]
16654
16666
  * @property {Subscription} [subscription]
16667
+ * @property {boolean} [isEmpty] no zeebe extension data found and nothing to format — the element needs no extension
16655
16668
  */
16656
16669
 
16657
16670
  /**
@@ -16664,10 +16677,15 @@ function getExtensions(element, context) {
16664
16677
  const result = {};
16665
16678
  const isProcess = element.type === 'bpmn:Process';
16666
16679
 
16667
- let assignmentDefinition;
16680
+ let assignmentDefinition, priorityDefinition, taskSchedule;
16681
+ let foundZeebe = false;
16668
16682
  const values = element.behaviour.extensionElements?.values;
16669
16683
  if (values) {
16670
16684
  for (const ext of values) {
16685
+ // Any zeebe-namespaced extension element counts as found — including ones with no
16686
+ // handler (e.g. the bare `zeebe:userTask` marker), which keep the element extension
16687
+ // loaded so e.g. a native user task's completion payload is merged.
16688
+ if (ext.$type.startsWith('zeebe:')) foundZeebe = true;
16671
16689
  switch (ext.$type) {
16672
16690
  case 'zeebe:IoMapping':
16673
16691
  result.io = new IoMapping(element, ext);
@@ -16681,6 +16699,12 @@ function getExtensions(element, context) {
16681
16699
  case 'zeebe:AssignmentDefinition':
16682
16700
  assignmentDefinition = ext;
16683
16701
  break;
16702
+ case 'zeebe:PriorityDefinition':
16703
+ priorityDefinition = ext;
16704
+ break;
16705
+ case 'zeebe:TaskSchedule':
16706
+ taskSchedule = ext;
16707
+ break;
16684
16708
  case 'zeebe:ExecutionListeners':
16685
16709
  if (ext.listeners?.length) result.listeners = new ExecutionListeners(element, ext);
16686
16710
  break;
@@ -16722,7 +16746,16 @@ function getExtensions(element, context) {
16722
16746
  );
16723
16747
  if (loopExtension?.outputCollection) result.loop = new LoopCharacteristics(loopExtension);
16724
16748
 
16725
- result.format = isProcess ? new FormatProcess(element) : new FormatActivity(element, assignmentDefinition);
16749
+ // Nothing zeebe-flavoured and nothing to format — the element needs no extension. A call
16750
+ // activity is never inert: its output unwrap/merge is type-driven (the standard BPMN
16751
+ // `calledElement` attribute needs no zeebe elements). Ignored for processes — a called
16752
+ // process always needs its inbound input promoted, whatever it carries itself.
16753
+ result.isEmpty =
16754
+ !foundZeebe && !result.subscription && !loopExtension && !element.behaviour.documentation && element.type !== 'bpmn:CallActivity';
16755
+
16756
+ result.format = isProcess
16757
+ ? new FormatProcess(element)
16758
+ : new FormatActivity(element, assignmentDefinition, priorityDefinition, taskSchedule);
16726
16759
 
16727
16760
  return result;
16728
16761
  }
@@ -17099,20 +17132,32 @@ function getScriptExpression(activity) {
17099
17132
 
17100
17133
  /**
17101
17134
  * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
17135
+ *
17136
+ * Returns undefined for an element that carries no zeebe extension data and nothing else to
17137
+ * format (no documentation, not a call activity) — bpmn-elements skips falsy extensions, so
17138
+ * plain elements run untouched, with no broker subscriptions or format-queue traffic.
17102
17139
  * @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
17103
17140
  * @param {import('bpmn-elements').ContextInstance} context
17104
- * @returns {FlowExtension}
17141
+ * @returns {FlowExtension | undefined}
17105
17142
  */
17106
17143
  function extensions(element, context) {
17107
17144
  switch (element.type) {
17108
17145
  case 'bpmn:Process':
17146
+ // A process is always attached: a called process needs its inbound input promoted
17147
+ // even when it carries no zeebe extension data of its own.
17109
17148
  return new ProcessExtensions(element, context);
17110
17149
  case 'bpmn:SubProcess':
17111
17150
  case 'bpmn:AdHocSubProcess':
17112
- case 'bpmn:Transaction':
17113
- return new SubProcessExtensions(element, context);
17114
- default:
17115
- return new ElementExtensions(element, context);
17151
+ case 'bpmn:Transaction': {
17152
+ const subProcessExtensions = new SubProcessExtensions(element, context);
17153
+ if (subProcessExtensions.extensions.isEmpty) return undefined;
17154
+ return subProcessExtensions;
17155
+ }
17156
+ default: {
17157
+ const elementExtensions = new ElementExtensions(element, context);
17158
+ if (elementExtensions.extensions.isEmpty) return undefined;
17159
+ return elementExtensions;
17160
+ }
17116
17161
  }
17117
17162
  }
17118
17163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0dep/bpmn-extensions",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Flow extensions for bpmn-elements: FEEL expressions and the zeebe-namespace BPMN extension elements",
5
5
  "type": "module",
6
6
  "module": "src/index.js",
@@ -69,7 +69,7 @@
69
69
  "@types/mocha": "^10.0.10",
70
70
  "@types/node": "^26.1.1",
71
71
  "bpmn-elements": "^18.0.12",
72
- "bpmn-moddle": "^9.0.1",
72
+ "bpmn-moddle": "^10.1.0",
73
73
  "c8": "^12.0.0",
74
74
  "chai": "^6.2.2",
75
75
  "debug": "^4.4.3",
@@ -2,16 +2,21 @@ import { resolveValue, getFeelScope } from '../feel.js';
2
2
 
3
3
  /**
4
4
  * Format an activity on enter from its behaviour and extensions: documentation and,
5
- * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
5
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
6
+ * `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
6
7
  */
7
8
  export class FormatActivity {
8
9
  /**
9
10
  * @param {import('bpmn-elements').Activity} activity
10
11
  * @param {any} assignmentDefinition
12
+ * @param {any} [priorityDefinition]
13
+ * @param {any} [taskSchedule]
11
14
  */
12
- constructor(activity, assignmentDefinition) {
15
+ constructor(activity, assignmentDefinition, priorityDefinition, taskSchedule) {
13
16
  this.activity = activity;
14
17
  this.assignmentDefinition = assignmentDefinition;
18
+ this.priorityDefinition = priorityDefinition;
19
+ this.taskSchedule = taskSchedule;
15
20
  }
16
21
  /**
17
22
  * @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
@@ -23,7 +28,7 @@ export class FormatActivity {
23
28
  const documentation = this.activity.behaviour.documentation;
24
29
  if (documentation && !elementApi.content.description) {
25
30
  const text = documentation[0]?.text;
26
- if (text) result.description = resolveValue(text, scope);
31
+ if (text) result.description = /** @type {string} */ (resolveValue(text, scope));
27
32
  }
28
33
 
29
34
  const assignment = this.assignmentDefinition;
@@ -36,6 +41,22 @@ export class FormatActivity {
36
41
  if (groups) result.candidateGroups = groups;
37
42
  }
38
43
 
44
+ const priority = this.priorityDefinition?.priority;
45
+ if (priority !== undefined) {
46
+ const resolved = resolveValue(priority, scope);
47
+ // A static attribute value is a string — expose a numeric one as a number (like retries).
48
+ const num = Number(resolved);
49
+ /** @type {Number | string | undefined} */
50
+ result.priority = typeof resolved === 'string' && resolved.trim() !== '' && Number.isFinite(num) ? num : resolved;
51
+ }
52
+
53
+ const schedule = this.taskSchedule;
54
+ if (schedule) {
55
+ const { dueDate, followUpDate } = schedule;
56
+ if (dueDate !== undefined) result.dueDate = resolveDate(dueDate, scope);
57
+ if (followUpDate !== undefined) result.followUpDate = resolveDate(followUpDate, scope);
58
+ }
59
+
39
60
  return result;
40
61
  }
41
62
  }
@@ -58,15 +79,33 @@ export class FormatProcess {
58
79
  const documentation = this.process.behaviour.documentation;
59
80
  if (documentation && !elementApi.content.description) {
60
81
  const text = documentation[0]?.text;
61
- if (text) result.description = resolveValue(text, getFeelScope(elementApi.environment));
82
+ if (text) result.description = /** @type {string} */ (resolveValue(text, getFeelScope(elementApi.environment)));
62
83
  }
63
84
  return result;
64
85
  }
65
86
  }
66
87
 
88
+ /**
89
+ * Resolve a due/follow-up date to an ISO 8601 string. A FEEL temporal result (a luxon
90
+ * DateTime) or a Date is ISO-stringified — content is JSON-serialized on `getState()`, so a
91
+ * string is the shape that survives a recover round trip. Anything else passes through as-is.
92
+ * @param {any} value
93
+ * @param {any} scope
94
+ * @returns {string | undefined} Date as iso string
95
+ */
96
+ function resolveDate(value, scope) {
97
+ const resolved = resolveValue(value, scope);
98
+ if (typeof resolved?.toISO === 'function') return resolved.toISO();
99
+ if (resolved instanceof Date) return resolved.toISOString();
100
+ return resolved;
101
+ }
102
+
67
103
  /**
68
104
  * Resolve a candidate users/groups value to a string array. A FEEL expression may yield an
69
105
  * array directly, otherwise a comma-separated string is split.
106
+ * @param {any} value
107
+ * @param {any} scope
108
+ * @returns {string[] | undefined}
70
109
  */
71
110
  function resolveList(value, scope) {
72
111
  if (!value) return undefined;
@@ -22,6 +22,7 @@ import { Subscription } from './extensions/Subscription.js';
22
22
  * @property {any} [calledDecision]
23
23
  * @property {Function} [Service]
24
24
  * @property {Subscription} [subscription]
25
+ * @property {boolean} [isEmpty] no zeebe extension data found and nothing to format — the element needs no extension
25
26
  */
26
27
 
27
28
  /**
@@ -34,10 +35,15 @@ export function getExtensions(element, context) {
34
35
  const result = {};
35
36
  const isProcess = element.type === 'bpmn:Process';
36
37
 
37
- let assignmentDefinition;
38
+ let assignmentDefinition, priorityDefinition, taskSchedule;
39
+ let foundZeebe = false;
38
40
  const values = element.behaviour.extensionElements?.values;
39
41
  if (values) {
40
42
  for (const ext of values) {
43
+ // Any zeebe-namespaced extension element counts as found — including ones with no
44
+ // handler (e.g. the bare `zeebe:userTask` marker), which keep the element extension
45
+ // loaded so e.g. a native user task's completion payload is merged.
46
+ if (ext.$type.startsWith('zeebe:')) foundZeebe = true;
41
47
  switch (ext.$type) {
42
48
  case 'zeebe:IoMapping':
43
49
  result.io = new IoMapping(element, ext);
@@ -51,6 +57,12 @@ export function getExtensions(element, context) {
51
57
  case 'zeebe:AssignmentDefinition':
52
58
  assignmentDefinition = ext;
53
59
  break;
60
+ case 'zeebe:PriorityDefinition':
61
+ priorityDefinition = ext;
62
+ break;
63
+ case 'zeebe:TaskSchedule':
64
+ taskSchedule = ext;
65
+ break;
54
66
  case 'zeebe:ExecutionListeners':
55
67
  if (ext.listeners?.length) result.listeners = new ExecutionListeners(element, ext);
56
68
  break;
@@ -92,7 +104,16 @@ export function getExtensions(element, context) {
92
104
  );
93
105
  if (loopExtension?.outputCollection) result.loop = new LoopCharacteristics(loopExtension);
94
106
 
95
- result.format = isProcess ? new FormatProcess(element) : new FormatActivity(element, assignmentDefinition);
107
+ // Nothing zeebe-flavoured and nothing to format — the element needs no extension. A call
108
+ // activity is never inert: its output unwrap/merge is type-driven (the standard BPMN
109
+ // `calledElement` attribute needs no zeebe elements). Ignored for processes — a called
110
+ // process always needs its inbound input promoted, whatever it carries itself.
111
+ result.isEmpty =
112
+ !foundZeebe && !result.subscription && !loopExtension && !element.behaviour.documentation && element.type !== 'bpmn:CallActivity';
113
+
114
+ result.format = isProcess
115
+ ? new FormatProcess(element)
116
+ : new FormatActivity(element, assignmentDefinition, priorityDefinition, taskSchedule);
96
117
 
97
118
  return result;
98
119
  }
package/src/index.js CHANGED
@@ -18,20 +18,32 @@ export { ServiceError, FormatError } from './Errors.js';
18
18
 
19
19
  /**
20
20
  * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
21
+ *
22
+ * Returns undefined for an element that carries no zeebe extension data and nothing else to
23
+ * format (no documentation, not a call activity) — bpmn-elements skips falsy extensions, so
24
+ * plain elements run untouched, with no broker subscriptions or format-queue traffic.
21
25
  * @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
22
26
  * @param {import('bpmn-elements').ContextInstance} context
23
- * @returns {FlowExtension}
27
+ * @returns {FlowExtension | undefined}
24
28
  */
25
29
  export function extensions(element, context) {
26
30
  switch (element.type) {
27
31
  case 'bpmn:Process':
32
+ // A process is always attached: a called process needs its inbound input promoted
33
+ // even when it carries no zeebe extension data of its own.
28
34
  return new ProcessExtensions(element, context);
29
35
  case 'bpmn:SubProcess':
30
36
  case 'bpmn:AdHocSubProcess':
31
- case 'bpmn:Transaction':
32
- return new SubProcessExtensions(element, context);
33
- default:
34
- return new ElementExtensions(element, context);
37
+ case 'bpmn:Transaction': {
38
+ const subProcessExtensions = new SubProcessExtensions(element, context);
39
+ if (subProcessExtensions.extensions.isEmpty) return undefined;
40
+ return subProcessExtensions;
41
+ }
42
+ default: {
43
+ const elementExtensions = new ElementExtensions(element, context);
44
+ if (elementExtensions.extensions.isEmpty) return undefined;
45
+ return elementExtensions;
46
+ }
35
47
  }
36
48
  }
37
49
 
package/types/index.d.ts CHANGED
@@ -4,8 +4,12 @@ declare module '@0dep/bpmn-extensions' {
4
4
  * */
5
5
  /**
6
6
  * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
7
+ *
8
+ * Returns undefined for an element that carries no zeebe extension data and nothing else to
9
+ * format (no documentation, not a call activity) — bpmn-elements skips falsy extensions, so
10
+ * plain elements run untouched, with no broker subscriptions or format-queue traffic.
7
11
  * */
8
- export function extensions(element: import("bpmn-elements").Activity | import("bpmn-elements").Process, context: import("bpmn-elements").ContextInstance): FlowExtension;
12
+ export function extensions(element: import("bpmn-elements").Activity | import("bpmn-elements").Process, context: import("bpmn-elements").ContextInstance): FlowExtension | undefined;
9
13
  /**
10
14
  * Behaviour extend function for moddle-context-serializer.
11
15
  *
@@ -210,22 +214,33 @@ declare module '@0dep/bpmn-extensions' {
210
214
  calledDecision?: any;
211
215
  Service?: Function | undefined;
212
216
  subscription?: Subscription | undefined;
217
+ /**
218
+ * no zeebe extension data found and nothing to format — the element needs no extension
219
+ */
220
+ isEmpty?: boolean | undefined;
213
221
  };
214
222
  /**
215
223
  * Format an activity on enter from its behaviour and extensions: documentation and,
216
- * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
224
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
225
+ * `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
217
226
  */
218
227
  class FormatActivity {
219
228
 
220
- constructor(activity: import("bpmn-elements").Activity, assignmentDefinition: any);
229
+ constructor(activity: import("bpmn-elements").Activity, assignmentDefinition: any, priorityDefinition?: any, taskSchedule?: any);
221
230
  activity: import("bpmn-elements").Activity;
222
231
  assignmentDefinition: any;
232
+ priorityDefinition: any;
233
+ taskSchedule: any;
223
234
 
224
235
  resolve(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Activity>): {
225
- description: any;
236
+ description: string;
226
237
  assignee: any;
227
- candidateUsers: any[];
228
- candidateGroups: any[];
238
+ candidateUsers: string[];
239
+ candidateGroups: string[];
240
+
241
+ priority: number | string | undefined;
242
+ dueDate: string | undefined;
243
+ followUpDate: string | undefined;
229
244
  };
230
245
  }
231
246
  /**
@@ -237,7 +252,7 @@ declare module '@0dep/bpmn-extensions' {
237
252
  process: import("bpmn-elements").Process;
238
253
 
239
254
  resolve(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Process>): {
240
- description: any;
255
+ description: string;
241
256
  };
242
257
  }
243
258
  /**
@@ -66,6 +66,6 @@
66
66
  null,
67
67
  null
68
68
  ],
69
- "mappings": ";;;;;;;iBAwBgBA,UAAUA;;;;;;;;iBAqBVC,QAAQA;;;;;;;;;;;;;;;;iBClCRC,eAAeA;;;;;;;;;;;;;;iBCEfC,WAAWA;;;;;;;;;;;;;;;iBCIXC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCEbC,iBAAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCZjBC,iBAAiBA;;;;;;;;;;;;;;;;;;;cCIjBC,oBAAoBA;;;;;;;iBCEjBC,gBAAgBA;;;;iBAShBC,SAASA;;;;;;iBAUTC,YAAYA;;;;;;;;iBAYZC,qBAAqBA;;;;;;iBAYrBC,YAAYA;;;;;;;;;;iBAgBZC,YAAYA;cCxEfC,YAAYA;;;;;;;cAQZC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;OCFXC,cAAcA;;;;;;;;;;;;;;;;OAuCdC,aAAaA;;;;;;;;;;;;;;;;;;;;OChCbC,SAASA;;;;;;;;;;;;;;;;;;;;;;;OCPTC,WAAWA;;;;;;;;;;;OCEXC,UAAUA;;;;;;;;;;;;;;;OCIVC,kBAAkBA;;;;;;;;;;;;;;;;;;;OCFlBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;OCGJC,mBAAmBA;;;;;;;;;;;;;;;;;;;OCHnBC,YAAYA",
69
+ "mappings": ";;;;;;;;;;;iBA4BgBA,UAAUA;;;;;;;;iBA6BVC,QAAQA;;;;;;;;;;;;;;;;iBC9CRC,eAAeA;;;;;;;;;;;;;;iBCEfC,WAAWA;;;;;;;;;;;;;;;iBCIXC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCEbC,iBAAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCZjBC,iBAAiBA;;;;;;;;;;;;;;;;;;;cCIjBC,oBAAoBA;;;;;;;iBCEjBC,gBAAgBA;;;;iBAShBC,SAASA;;;;;;iBAUTC,YAAYA;;;;;;;;iBAYZC,qBAAqBA;;;;;;iBAYrBC,YAAYA;;;;;;;;;;iBAgBZC,YAAYA;cCxEfC,YAAYA;;;;;;;cAQZC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCDXC,cAAcA;;;;;;;;;;;;;;;;;;;;;;OA2DdC,aAAaA;;;;;;;;;;;;;;;;;;;;OCrDbC,SAASA;;;;;;;;;;;;;;;;;;;;;;;OCPTC,WAAWA;;;;;;;;;;;OCEXC,UAAUA;;;;;;;;;;;;;;;OCIVC,kBAAkBA;;;;;;;;;;;;;;;;;;;OCFlBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;OCGJC,mBAAmBA;;;;;;;;;;;;;;;;;;;OCHnBC,YAAYA",
70
70
  "ignoreList": []
71
71
  }