@rytass/bpm-core-nestjs-module 0.19.0 → 0.20.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.
Files changed (151) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/package.json +3 -2
  3. package/src/index.d.ts +1 -0
  4. package/src/index.js +1 -0
  5. package/src/index.js.map +1 -1
  6. package/src/lib/bpm/bpm-root-options.d.ts +13 -0
  7. package/src/lib/bpm/bpm-root-options.js.map +1 -1
  8. package/src/lib/bpm/bpm-root.module.d.ts +12 -0
  9. package/src/lib/bpm/bpm-root.module.js +5 -0
  10. package/src/lib/bpm/bpm-root.module.js.map +1 -1
  11. package/src/lib/condition/adapters/cel-legacy.adapter.d.ts +62 -0
  12. package/src/lib/condition/adapters/cel-legacy.adapter.js +141 -0
  13. package/src/lib/condition/adapters/cel-legacy.adapter.js.map +1 -0
  14. package/src/lib/condition/adapters/cel-v2.adapter.d.ts +76 -0
  15. package/src/lib/condition/adapters/cel-v2.adapter.js +371 -0
  16. package/src/lib/condition/adapters/cel-v2.adapter.js.map +1 -0
  17. package/src/lib/condition/condition.service.d.ts +90 -5
  18. package/src/lib/condition/condition.service.js +287 -71
  19. package/src/lib/condition/condition.service.js.map +1 -1
  20. package/src/lib/condition/expression-ast.d.ts +176 -0
  21. package/src/lib/condition/expression-ast.js +1254 -0
  22. package/src/lib/condition/expression-ast.js.map +1 -0
  23. package/src/lib/condition/expression-budget.d.ts +44 -0
  24. package/src/lib/condition/expression-budget.js +61 -0
  25. package/src/lib/condition/expression-budget.js.map +1 -0
  26. package/src/lib/condition/expression-dialect.d.ts +29 -0
  27. package/src/lib/condition/expression-dialect.js +44 -0
  28. package/src/lib/condition/expression-dialect.js.map +1 -0
  29. package/src/lib/condition/expression-differential.corpus.d.ts +34 -0
  30. package/src/lib/condition/expression-differential.corpus.js +995 -0
  31. package/src/lib/condition/expression-differential.corpus.js.map +1 -0
  32. package/src/lib/condition/expression-differential.d.ts +33 -0
  33. package/src/lib/condition/expression-differential.js +48 -0
  34. package/src/lib/condition/expression-differential.js.map +1 -0
  35. package/src/lib/condition/expression-engine-failure.d.ts +15 -0
  36. package/src/lib/condition/expression-engine-failure.js +22 -0
  37. package/src/lib/condition/expression-engine-failure.js.map +1 -0
  38. package/src/lib/condition/expression-errors.d.ts +40 -0
  39. package/src/lib/condition/expression-errors.js +121 -0
  40. package/src/lib/condition/expression-errors.js.map +1 -0
  41. package/src/lib/condition/expression-function-invocation.d.ts +50 -0
  42. package/src/lib/condition/expression-function-invocation.js +290 -0
  43. package/src/lib/condition/expression-function-invocation.js.map +1 -0
  44. package/src/lib/condition/expression-result.walker.d.ts +18 -0
  45. package/src/lib/condition/expression-result.walker.js +152 -0
  46. package/src/lib/condition/expression-result.walker.js.map +1 -0
  47. package/src/lib/condition/expression-runtime.d.ts +70 -0
  48. package/src/lib/condition/expression-runtime.js +134 -0
  49. package/src/lib/condition/expression-runtime.js.map +1 -0
  50. package/src/lib/condition/index.d.ts +4 -0
  51. package/src/lib/condition/index.js +8 -0
  52. package/src/lib/condition/index.js.map +1 -1
  53. package/src/lib/delegation/delegation-rule.entity.d.ts +7 -0
  54. package/src/lib/delegation/delegation-rule.entity.js +10 -0
  55. package/src/lib/delegation/delegation-rule.entity.js.map +1 -1
  56. package/src/lib/delegation/delegation.service.d.ts +7 -1
  57. package/src/lib/delegation/delegation.service.js +22 -5
  58. package/src/lib/delegation/delegation.service.js.map +1 -1
  59. package/src/lib/delegation/dto/delegation-rule.input.d.ts +2 -0
  60. package/src/lib/delegation/dto/delegation-rule.input.js +10 -0
  61. package/src/lib/delegation/dto/delegation-rule.input.js.map +1 -1
  62. package/src/lib/expression-function/expression-function.built-ins.d.ts +9 -0
  63. package/src/lib/expression-function/expression-function.built-ins.js +117 -0
  64. package/src/lib/expression-function/expression-function.built-ins.js.map +1 -0
  65. package/src/lib/expression-function/expression-function.module.d.ts +19 -0
  66. package/src/lib/expression-function/expression-function.module.js +34 -0
  67. package/src/lib/expression-function/expression-function.module.js.map +1 -0
  68. package/src/lib/expression-function/expression-function.provider.d.ts +17 -0
  69. package/src/lib/expression-function/expression-function.provider.js +39 -0
  70. package/src/lib/expression-function/expression-function.provider.js.map +1 -0
  71. package/src/lib/expression-function/expression-function.registry.d.ts +36 -0
  72. package/src/lib/expression-function/expression-function.registry.js +231 -0
  73. package/src/lib/expression-function/expression-function.registry.js.map +1 -0
  74. package/src/lib/expression-function/expression-function.types.d.ts +30 -0
  75. package/src/lib/expression-function/expression-function.types.js +8 -0
  76. package/src/lib/expression-function/expression-function.types.js.map +1 -0
  77. package/src/lib/expression-function/index.d.ts +5 -0
  78. package/src/lib/expression-function/index.js +9 -0
  79. package/src/lib/expression-function/index.js.map +1 -0
  80. package/src/lib/form/form-schema.validator.js +53 -6
  81. package/src/lib/form/form-schema.validator.js.map +1 -1
  82. package/src/lib/form-data-source/form-data-source-value-resolver.service.d.ts +12 -1
  83. package/src/lib/form-data-source/form-data-source-value-resolver.service.js +45 -26
  84. package/src/lib/form-data-source/form-data-source-value-resolver.service.js.map +1 -1
  85. package/src/lib/form-data-source/form-data-source.expression.d.ts +95 -0
  86. package/src/lib/form-data-source/form-data-source.expression.js +267 -0
  87. package/src/lib/form-data-source/form-data-source.expression.js.map +1 -0
  88. package/src/lib/form-data-source/form-data-source.module.js +4 -0
  89. package/src/lib/form-data-source/form-data-source.module.js.map +1 -1
  90. package/src/lib/form-data-source/form-data-source.service.d.ts +22 -3
  91. package/src/lib/form-data-source/form-data-source.service.js +78 -18
  92. package/src/lib/form-data-source/form-data-source.service.js.map +1 -1
  93. package/src/lib/form-data-source/form-data-source.validation.d.ts +47 -4
  94. package/src/lib/form-data-source/form-data-source.validation.js +151 -23
  95. package/src/lib/form-data-source/form-data-source.validation.js.map +1 -1
  96. package/src/lib/migrations/0000000030000-delegation-scope-condition-dialect.d.ts +22 -0
  97. package/src/lib/migrations/0000000030000-delegation-scope-condition-dialect.js +76 -0
  98. package/src/lib/migrations/0000000030000-delegation-scope-condition-dialect.js.map +1 -0
  99. package/src/lib/migrations/index.d.ts +1 -0
  100. package/src/lib/migrations/index.js +3 -0
  101. package/src/lib/migrations/index.js.map +1 -1
  102. package/src/lib/notification/notification.service.d.ts +1 -1
  103. package/src/lib/notification/notification.service.js +7 -3
  104. package/src/lib/notification/notification.service.js.map +1 -1
  105. package/src/lib/template/dto/expression-designer.dto.d.ts +107 -0
  106. package/src/lib/template/dto/expression-designer.dto.js +415 -0
  107. package/src/lib/template/dto/expression-designer.dto.js.map +1 -0
  108. package/src/lib/template/expression-designer.queries.d.ts +16 -0
  109. package/src/lib/template/expression-designer.queries.js +66 -0
  110. package/src/lib/template/expression-designer.queries.js.map +1 -0
  111. package/src/lib/template/expression-designer.service.d.ts +72 -0
  112. package/src/lib/template/expression-designer.service.js +543 -0
  113. package/src/lib/template/expression-designer.service.js.map +1 -0
  114. package/src/lib/template/index.d.ts +2 -0
  115. package/src/lib/template/index.js +2 -0
  116. package/src/lib/template/index.js.map +1 -1
  117. package/src/lib/template/template.module.js +4 -0
  118. package/src/lib/template/template.module.js.map +1 -1
  119. package/src/lib/template/template.service.d.ts +37 -1
  120. package/src/lib/template/template.service.js +317 -29
  121. package/src/lib/template/template.service.js.map +1 -1
  122. package/src/lib/template/workflow-definition.validator.d.ts +7 -0
  123. package/src/lib/template/workflow-definition.validator.js +26 -2
  124. package/src/lib/template/workflow-definition.validator.js.map +1 -1
  125. package/src/lib/workflow-engine/time-budget.d.ts +13 -0
  126. package/src/lib/workflow-engine/time-budget.js +58 -0
  127. package/src/lib/workflow-engine/time-budget.js.map +1 -0
  128. package/src/lib/workflow-engine/workflow-condition-evaluator.js +12 -12
  129. package/src/lib/workflow-engine/workflow-condition-evaluator.js.map +1 -1
  130. package/src/lib/workflow-engine/workflow-engine.service.d.ts +24 -0
  131. package/src/lib/workflow-engine/workflow-engine.service.js +311 -88
  132. package/src/lib/workflow-engine/workflow-engine.service.js.map +1 -1
  133. package/src/lib/workflow-engine/workflow-form-value.d.ts +11 -0
  134. package/src/lib/workflow-engine/workflow-form-value.js +33 -0
  135. package/src/lib/workflow-engine/workflow-form-value.js.map +1 -0
  136. package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.js +4 -0
  137. package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.js.map +1 -1
  138. package/src/lib/workflow-webhook/workflow-webhook-delivery.service.d.ts +3 -1
  139. package/src/lib/workflow-webhook/workflow-webhook-delivery.service.js +11 -2
  140. package/src/lib/workflow-webhook/workflow-webhook-delivery.service.js.map +1 -1
  141. package/src/lib/workflow-webhook/workflow-webhook-enqueue.d.ts +8 -1
  142. package/src/lib/workflow-webhook/workflow-webhook-enqueue.js +70 -27
  143. package/src/lib/workflow-webhook/workflow-webhook-enqueue.js.map +1 -1
  144. package/src/lib/workflow-webhook/workflow-webhook-expression.d.ts +57 -0
  145. package/src/lib/workflow-webhook/workflow-webhook-expression.js +123 -0
  146. package/src/lib/workflow-webhook/workflow-webhook-expression.js.map +1 -0
  147. package/src/lib/workflow-webhook/workflow-webhook.module.js +4 -0
  148. package/src/lib/workflow-webhook/workflow-webhook.module.js.map +1 -1
  149. package/src/lib/workflow-webhook/workflow-webhook.validator.d.ts +7 -0
  150. package/src/lib/workflow-webhook/workflow-webhook.validator.js +29 -6
  151. package/src/lib/workflow-webhook/workflow-webhook.validator.js.map +1 -1
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var ExpressionFunctionModule_1;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ExpressionFunctionModule = void 0;
5
+ const tslib_1 = require("tslib");
6
+ const common_1 = require("@nestjs/common");
7
+ const expression_function_provider_1 = require("./expression-function.provider");
8
+ const expression_function_types_1 = require("./expression-function.types");
9
+ /**
10
+ * Publishes the expression function registry (ADR 22 §3.5) under
11
+ * `BPM_EXPRESSION_FUNCTION_REGISTRY`. Global, because every module that
12
+ * evaluates or lints an expression (`ConditionModule` consumers: templates,
13
+ * the workflow engine, delegation) reads the same registry.
14
+ */
15
+ let ExpressionFunctionModule = ExpressionFunctionModule_1 = class ExpressionFunctionModule {
16
+ static forRoot(options = {}) {
17
+ return {
18
+ exports: [expression_function_types_1.BPM_EXPRESSION_FUNCTION_REGISTRY],
19
+ global: true,
20
+ imports: [...(options.imports ?? [])],
21
+ module: ExpressionFunctionModule_1,
22
+ providers: [
23
+ ...(options.functionsProvider ? [options.functionsProvider] : []),
24
+ expression_function_provider_1.expressionFunctionRegistryProvider,
25
+ ],
26
+ };
27
+ }
28
+ };
29
+ exports.ExpressionFunctionModule = ExpressionFunctionModule;
30
+ exports.ExpressionFunctionModule = ExpressionFunctionModule = ExpressionFunctionModule_1 = tslib_1.__decorate([
31
+ (0, common_1.Global)(),
32
+ (0, common_1.Module)({})
33
+ ], ExpressionFunctionModule);
34
+ //# sourceMappingURL=expression-function.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression-function.module.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/expression-function/expression-function.module.ts"],"names":[],"mappings":";;;;;AAAA,2CAMwB;AACxB,iFAAoF;AACpF,2EAGqC;AAcrC;;;;;GAKG;AAGI,IAAM,wBAAwB,gCAA9B,MAAM,wBAAwB;IACnC,MAAM,CAAC,OAAO,CAAC,UAA2C,EAAE;QAC1D,OAAO;YACL,OAAO,EAAE,CAAC,4DAAgC,CAAC;YAC3C,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YACrC,MAAM,EAAE,0BAAwB;YAChC,SAAS,EAAE;gBACT,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,iEAAkC;aACnC;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAbY,4DAAwB;mCAAxB,wBAAwB;IAFpC,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,wBAAwB,CAapC"}
@@ -0,0 +1,17 @@
1
+ import { Provider } from '@nestjs/common';
2
+ import { BPMExpressionFunctionRegistry } from './expression-function.types';
3
+ /**
4
+ * Resolves the registry every BPM module injects under
5
+ * `BPM_EXPRESSION_FUNCTION_REGISTRY`: the nine built-ins plus the host
6
+ * functions from `BPMRootModule`'s `expressionFunctions` runtime option and
7
+ * from a `BPM_EXPRESSION_FUNCTIONS` provider, in that order. With neither, only
8
+ * the built-ins are available.
9
+ *
10
+ * Every function is validated here, so a bad name, an async handler or an
11
+ * unsupported type fails the host's boot — for `forRoot` and `forRootAsync`
12
+ * alike — instead of the first evaluation that would reach it.
13
+ *
14
+ * Both sources are injected optionally so the module also resolves on its own,
15
+ * outside `BPMRootModule`.
16
+ */
17
+ export declare const expressionFunctionRegistryProvider: Provider<BPMExpressionFunctionRegistry>;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.expressionFunctionRegistryProvider = void 0;
4
+ const bpm_root_options_1 = require("../bpm/bpm-root-options");
5
+ const expression_function_registry_1 = require("./expression-function.registry");
6
+ const expression_function_types_1 = require("./expression-function.types");
7
+ /**
8
+ * Resolves the registry every BPM module injects under
9
+ * `BPM_EXPRESSION_FUNCTION_REGISTRY`: the nine built-ins plus the host
10
+ * functions from `BPMRootModule`'s `expressionFunctions` runtime option and
11
+ * from a `BPM_EXPRESSION_FUNCTIONS` provider, in that order. With neither, only
12
+ * the built-ins are available.
13
+ *
14
+ * Every function is validated here, so a bad name, an async handler or an
15
+ * unsupported type fails the host's boot — for `forRoot` and `forRootAsync`
16
+ * alike — instead of the first evaluation that would reach it.
17
+ *
18
+ * Both sources are injected optionally so the module also resolves on its own,
19
+ * outside `BPMRootModule`.
20
+ */
21
+ exports.expressionFunctionRegistryProvider = {
22
+ inject: [
23
+ { optional: true, token: bpm_root_options_1.BPM_ROOT_OPTIONS },
24
+ { optional: true, token: expression_function_types_1.BPM_EXPRESSION_FUNCTIONS },
25
+ ],
26
+ provide: expression_function_types_1.BPM_EXPRESSION_FUNCTION_REGISTRY,
27
+ useFactory: (rootOptions, hostFunctions) => {
28
+ const functions = [
29
+ ...(rootOptions?.expressionFunctions ?? []),
30
+ ...(hostFunctions ?? []),
31
+ ];
32
+ // Without host functions every consumer shares the built-ins-only
33
+ // registry, and with it the default engine environments.
34
+ return functions.length === 0
35
+ ? expression_function_registry_1.BUILT_IN_EXPRESSION_FUNCTION_REGISTRY
36
+ : new expression_function_registry_1.StaticBPMExpressionFunctionRegistry(functions);
37
+ },
38
+ };
39
+ //# sourceMappingURL=expression-function.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression-function.provider.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/expression-function/expression-function.provider.ts"],"names":[],"mappings":";;;AACA,8DAGiC;AACjC,iFAGwC;AACxC,2EAKqC;AAErC;;;;;;;;;;;;;GAaG;AACU,QAAA,kCAAkC,GAC7C;IACE,MAAM,EAAE;QACN,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,mCAAgB,EAAE;QAC3C,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,oDAAwB,EAAE;KACpD;IACD,OAAO,EAAE,4DAAgC;IACzC,UAAU,EAAE,CACV,WAA8C,EAC9C,aAA2D,EAC5B,EAAE;QACjC,MAAM,SAAS,GAAG;YAChB,GAAG,CAAC,WAAW,EAAE,mBAAmB,IAAI,EAAE,CAAC;YAC3C,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;SACzB,CAAC;QAEF,kEAAkE;QAClE,yDAAyD;QACzD,OAAO,SAAS,CAAC,MAAM,KAAK,CAAC;YAC3B,CAAC,CAAC,oEAAqC;YACvC,CAAC,CAAC,IAAI,kEAAmC,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;CACF,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { type BPMExpressionFunctionDescriptor, type BPMExpressionValueType } from '@rytass/bpm-core-shared';
2
+ import type { BPMExpressionFunction, BPMExpressionFunctionRegistry } from './expression-function.types';
3
+ /** Every value type a parameter or a result may declare (ADR 22 §3.5). */
4
+ export declare const BPM_EXPRESSION_VALUE_TYPES: readonly BPMExpressionValueType[];
5
+ /**
6
+ * Validates every host function (ADR 22 §3.5) and returns frozen copies:
7
+ * the name matches `BPM_EXPRESSION_FUNCTION_NAME_PATTERN` and is neither a
8
+ * built-in nor registered twice; the handler is a plain synchronous function;
9
+ * every parameter and the result declare a supported type.
10
+ *
11
+ * Throws a plain `Error` naming the function and the reason, so a host that
12
+ * registers a bad function does not boot.
13
+ */
14
+ export declare const validateExpressionFunctions: (functions: readonly unknown[]) => readonly BPMExpressionFunction[];
15
+ /**
16
+ * A fixed set of functions: the nine built-ins plus the host functions given
17
+ * at construction, validated there. Lookups are by own key only, so a name
18
+ * such as `constructor` or `toString` is never found on a prototype.
19
+ */
20
+ export declare class StaticBPMExpressionFunctionRegistry implements BPMExpressionFunctionRegistry {
21
+ private readonly functions;
22
+ private readonly descriptors;
23
+ constructor(hostFunctions?: readonly BPMExpressionFunction[]);
24
+ get(name: string): BPMExpressionFunction | null;
25
+ list(): readonly BPMExpressionFunctionDescriptor[];
26
+ assertPublishable(names: readonly string[]): readonly string[];
27
+ }
28
+ /** Only the nine built-ins: what BPM uses when the host registers no function. */
29
+ export declare class EmptyBPMExpressionFunctionRegistry extends StaticBPMExpressionFunctionRegistry {
30
+ constructor();
31
+ }
32
+ /**
33
+ * The shared built-ins-only registry. Evaluation falls back to it wherever no
34
+ * registry was handed in, so the built-ins are always available.
35
+ */
36
+ export declare const BUILT_IN_EXPRESSION_FUNCTION_REGISTRY: BPMExpressionFunctionRegistry;
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BUILT_IN_EXPRESSION_FUNCTION_REGISTRY = exports.EmptyBPMExpressionFunctionRegistry = exports.StaticBPMExpressionFunctionRegistry = exports.validateExpressionFunctions = exports.BPM_EXPRESSION_VALUE_TYPES = void 0;
4
+ const node_util_1 = require("node:util");
5
+ const bpm_core_shared_1 = require("@rytass/bpm-core-shared");
6
+ const expression_function_built_ins_1 = require("./expression-function.built-ins");
7
+ /** Every value type a parameter or a result may declare (ADR 22 §3.5). */
8
+ exports.BPM_EXPRESSION_VALUE_TYPES = Object.freeze([
9
+ 'bool',
10
+ 'double',
11
+ 'dyn',
12
+ 'int',
13
+ 'list',
14
+ 'map',
15
+ 'null',
16
+ 'string',
17
+ ]);
18
+ const VALUE_TYPES = new Set(exports.BPM_EXPRESSION_VALUE_TYPES);
19
+ const BUILT_IN_NAMES = new Set(bpm_core_shared_1.BPM_BUILT_IN_EXPRESSION_FUNCTION_NAMES);
20
+ const PARAMETER_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/u;
21
+ /*
22
+ * cel-js 0.8.2 (cel-legacy) lexes `true`, `false` and `null` without a word
23
+ * boundary and ahead of identifiers, so `nullable_v1(1)` is read as `null`
24
+ * followed by `able_v1` — a syntax error. cel-v2 has no such problem, but a
25
+ * host function must work in both dialects, so the name is refused here.
26
+ * (`in` is lexed with a boundary; `inRange_v1` is fine.)
27
+ */
28
+ const CEL_LEGACY_KEYWORD_PREFIX = /^(?:true|false|null)/u;
29
+ /*
30
+ * `async function`, `function*` and `async function*` all return something a
31
+ * synchronous evaluation cannot use.
32
+ *
33
+ * The primary check is the engine's own function kind (`util.types`): it is
34
+ * fixed when the function is created, so neither `Object.setPrototypeOf` nor
35
+ * an own `Symbol.toStringTag` changes it, and it holds across realms. It does
36
+ * not see through `bind`, so the prototype chain is checked too: every such
37
+ * function inherits from the intrinsic `AsyncFunction.prototype`,
38
+ * `GeneratorFunction.prototype` or `AsyncGeneratorFunction.prototype` of this
39
+ * realm, and a bound copy keeps that prototype. The tag is a last check for a
40
+ * bound handler from another realm.
41
+ *
42
+ * A bound copy whose prototype was also moved to `Function.prototype` and
43
+ * re-tagged still passes all three; such a handler returns a promise, which
44
+ * the call wrapper refuses as `EXPRESSION_FUNCTION_FAILED` (fail closed).
45
+ */
46
+ const REFUSED_FUNCTION_PROTOTYPES = [
47
+ Object.getPrototypeOf(async () => undefined),
48
+ Object.getPrototypeOf(function* refusedGenerator() {
49
+ // Never called: only its prototype is read.
50
+ }),
51
+ Object.getPrototypeOf(async function* refusedAsyncGenerator() {
52
+ // Never called: only its prototype is read.
53
+ }),
54
+ // A build that compiled these down to plain functions would yield
55
+ // `Function.prototype`, which every handler inherits from: never compare to it.
56
+ ].filter((prototype) => prototype !== Function.prototype);
57
+ const REFUSED_FUNCTION_TAGS = new Set([
58
+ '[object AsyncFunction]',
59
+ '[object AsyncGeneratorFunction]',
60
+ '[object GeneratorFunction]',
61
+ ]);
62
+ const isAsyncOrGenerator = (handler) => node_util_1.types.isAsyncFunction(handler) ||
63
+ node_util_1.types.isGeneratorFunction(handler) ||
64
+ REFUSED_FUNCTION_PROTOTYPES.some((prototype) => Object.prototype.isPrototypeOf.call(prototype, handler)) ||
65
+ REFUSED_FUNCTION_TAGS.has(Object.prototype.toString.call(handler));
66
+ const PREFIX = '[@rytass/bpm-core-nestjs-module]';
67
+ const refuse = (name, reason) => {
68
+ throw new Error(`${PREFIX} Expression function "${name}" ${reason}.`);
69
+ };
70
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
71
+ const readDisplayName = (candidate, index) => isRecord(candidate) && typeof candidate.name === 'string'
72
+ ? candidate.name
73
+ : `#${index}`;
74
+ const readParameter = (name, candidate, index) => {
75
+ if (!isRecord(candidate)) {
76
+ return refuse(name, `has parameter ${index} that is not an object`);
77
+ }
78
+ if (typeof candidate.name !== 'string' ||
79
+ !PARAMETER_NAME_PATTERN.test(candidate.name)) {
80
+ return refuse(name, `has parameter ${index} without a valid name`);
81
+ }
82
+ if (typeof candidate.type !== 'string' || !VALUE_TYPES.has(candidate.type)) {
83
+ return refuse(name, `declares parameter "${candidate.name}" with an unsupported type (expected one of ${exports.BPM_EXPRESSION_VALUE_TYPES.join(', ')})`);
84
+ }
85
+ const { description } = candidate;
86
+ if (description !== undefined && typeof description !== 'string') {
87
+ return refuse(name, `declares parameter "${candidate.name}" with a description that is not a string`);
88
+ }
89
+ return Object.freeze({
90
+ ...(typeof description === 'string' ? { description } : {}),
91
+ name: candidate.name,
92
+ type: candidate.type,
93
+ });
94
+ };
95
+ /**
96
+ * Checks one host function and returns a frozen copy of it. Throws a plain
97
+ * `Error` naming the function and the reason; the host's boot fails with it.
98
+ * Uniqueness across the list is checked by {@link validateExpressionFunctions}.
99
+ */
100
+ const validateExpressionFunction = (candidate, index) => {
101
+ const displayName = readDisplayName(candidate, index);
102
+ if (!isRecord(candidate)) {
103
+ return refuse(displayName, 'is not an object');
104
+ }
105
+ const { description, handler, label, name, parameters, returnType } = candidate;
106
+ if (typeof name !== 'string') {
107
+ return refuse(displayName, 'has no name');
108
+ }
109
+ if (BUILT_IN_NAMES.has(name)) {
110
+ return refuse(name, 'uses the name of a built-in function');
111
+ }
112
+ // The pattern also keeps a host name clear of every cel-v2 built-in and CEL
113
+ // keyword: none of them ends in `_v<digits>`.
114
+ if (!bpm_core_shared_1.BPM_EXPRESSION_FUNCTION_NAME_PATTERN.test(name)) {
115
+ return refuse(name, 'has an invalid name (lower camel segments joined by "_", ending in a version such as "_v1")');
116
+ }
117
+ if (CEL_LEGACY_KEYWORD_PREFIX.test(name)) {
118
+ return refuse(name, 'starts with "true", "false" or "null", which cel-legacy reads as a keyword; such a name can never be called there');
119
+ }
120
+ if (typeof handler !== 'function') {
121
+ return refuse(name, 'has no handler function');
122
+ }
123
+ if (isAsyncOrGenerator(handler)) {
124
+ return refuse(name, 'has an async or generator handler; handlers must be synchronous');
125
+ }
126
+ if (typeof label !== 'string' || !label.trim()) {
127
+ return refuse(name, 'has no label');
128
+ }
129
+ if (typeof description !== 'string') {
130
+ return refuse(name, 'has no description');
131
+ }
132
+ if (!Array.isArray(parameters)) {
133
+ return refuse(name, 'has no parameter list');
134
+ }
135
+ if (typeof returnType !== 'string' || !VALUE_TYPES.has(returnType)) {
136
+ return refuse(name, `declares an unsupported return type (expected one of ${exports.BPM_EXPRESSION_VALUE_TYPES.join(', ')})`);
137
+ }
138
+ const checkedParameters = Object.freeze(parameters.map((parameter, parameterIndex) => readParameter(name, parameter, parameterIndex)));
139
+ const parameterNames = checkedParameters.map((parameter) => parameter.name);
140
+ if (new Set(parameterNames).size !== parameterNames.length) {
141
+ return refuse(name, 'declares the same parameter name twice');
142
+ }
143
+ return Object.freeze({
144
+ description,
145
+ handler: handler,
146
+ label,
147
+ name,
148
+ parameters: checkedParameters,
149
+ returnType: returnType,
150
+ });
151
+ };
152
+ /**
153
+ * Validates every host function (ADR 22 §3.5) and returns frozen copies:
154
+ * the name matches `BPM_EXPRESSION_FUNCTION_NAME_PATTERN` and is neither a
155
+ * built-in nor registered twice; the handler is a plain synchronous function;
156
+ * every parameter and the result declare a supported type.
157
+ *
158
+ * Throws a plain `Error` naming the function and the reason, so a host that
159
+ * registers a bad function does not boot.
160
+ */
161
+ const validateExpressionFunctions = (functions) => {
162
+ if (!Array.isArray(functions)) {
163
+ throw new Error(`${PREFIX} Expression functions must be given as an array.`);
164
+ }
165
+ const checked = functions.map(validateExpressionFunction);
166
+ checked.reduce((seen, fn) => {
167
+ if (seen.has(fn.name)) {
168
+ refuse(fn.name, 'is registered more than once');
169
+ }
170
+ return new Set([...seen, fn.name]);
171
+ }, new Set());
172
+ return Object.freeze(checked);
173
+ };
174
+ exports.validateExpressionFunctions = validateExpressionFunctions;
175
+ const toDescriptor = (fn, builtIn) => Object.freeze({
176
+ builtIn,
177
+ description: fn.description,
178
+ label: fn.label,
179
+ name: fn.name,
180
+ parameters: fn.parameters,
181
+ returnType: fn.returnType,
182
+ });
183
+ const BUILT_INS = validateBuiltIns();
184
+ /**
185
+ * The built-ins go through the same shape checks as host functions, except
186
+ * the name rule they are exempt from, so a mistake in them fails at import.
187
+ */
188
+ function validateBuiltIns() {
189
+ return Object.freeze(expression_function_built_ins_1.BPM_BUILT_IN_EXPRESSION_FUNCTIONS.map((fn) => Object.freeze({
190
+ ...fn,
191
+ parameters: Object.freeze(fn.parameters.map((parameter, index) => readParameter(fn.name, parameter, index))),
192
+ })));
193
+ }
194
+ /**
195
+ * A fixed set of functions: the nine built-ins plus the host functions given
196
+ * at construction, validated there. Lookups are by own key only, so a name
197
+ * such as `constructor` or `toString` is never found on a prototype.
198
+ */
199
+ class StaticBPMExpressionFunctionRegistry {
200
+ constructor(hostFunctions = []) {
201
+ const host = (0, exports.validateExpressionFunctions)(hostFunctions);
202
+ this.functions = new Map([...BUILT_INS, ...host].map((fn) => [fn.name, fn]));
203
+ this.descriptors = Object.freeze([
204
+ ...BUILT_INS.map((fn) => toDescriptor(fn, true)),
205
+ ...host.map((fn) => toDescriptor(fn, false)),
206
+ ]);
207
+ }
208
+ get(name) {
209
+ return this.functions.get(name) ?? null;
210
+ }
211
+ list() {
212
+ return this.descriptors;
213
+ }
214
+ assertPublishable(names) {
215
+ return [...new Set(names)].filter((name) => !this.functions.has(name));
216
+ }
217
+ }
218
+ exports.StaticBPMExpressionFunctionRegistry = StaticBPMExpressionFunctionRegistry;
219
+ /** Only the nine built-ins: what BPM uses when the host registers no function. */
220
+ class EmptyBPMExpressionFunctionRegistry extends StaticBPMExpressionFunctionRegistry {
221
+ constructor() {
222
+ super([]);
223
+ }
224
+ }
225
+ exports.EmptyBPMExpressionFunctionRegistry = EmptyBPMExpressionFunctionRegistry;
226
+ /**
227
+ * The shared built-ins-only registry. Evaluation falls back to it wherever no
228
+ * registry was handed in, so the built-ins are always available.
229
+ */
230
+ exports.BUILT_IN_EXPRESSION_FUNCTION_REGISTRY = new EmptyBPMExpressionFunctionRegistry();
231
+ //# sourceMappingURL=expression-function.registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression-function.registry.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/expression-function/expression-function.registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { BPMExpressionFunctionDescriptor, BPMExpressionValue } from '@rytass/bpm-core-shared';
2
+ /**
3
+ * A function an expression may call (ADR 22 §3.5). The handler is host code:
4
+ * it must be synchronous and pure, and only ever sees deep-frozen copies of
5
+ * its arguments. The core never passes it an auth context.
6
+ */
7
+ export interface BPMExpressionFunction extends Omit<BPMExpressionFunctionDescriptor, 'builtIn'> {
8
+ readonly handler: (...args: readonly BPMExpressionValue[]) => BPMExpressionValue;
9
+ }
10
+ /**
11
+ * The functions available to expressions: the core built-ins plus whatever
12
+ * the host registered. Shared contract between the publish lint (P2) and the
13
+ * registry implementation (P3); see docs/24 §3.
14
+ */
15
+ export interface BPMExpressionFunctionRegistry {
16
+ /** The function registered under `name`, or `null`. */
17
+ get(name: string): BPMExpressionFunction | null;
18
+ /** Descriptors of every available function, built-ins first. */
19
+ list(): readonly BPMExpressionFunctionDescriptor[];
20
+ /**
21
+ * The names among `names` that are not available, in their first-seen
22
+ * order and without duplicates. An empty result means all are available;
23
+ * publish and rollback refuse a version whose result is not empty.
24
+ */
25
+ assertPublishable(names: readonly string[]): readonly string[];
26
+ }
27
+ /** Host-provided functions, as a multi-value list. Unset means none. */
28
+ export declare const BPM_EXPRESSION_FUNCTIONS: unique symbol;
29
+ /** The resolved registry the core injects. */
30
+ export declare const BPM_EXPRESSION_FUNCTION_REGISTRY: unique symbol;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BPM_EXPRESSION_FUNCTION_REGISTRY = exports.BPM_EXPRESSION_FUNCTIONS = void 0;
4
+ /** Host-provided functions, as a multi-value list. Unset means none. */
5
+ exports.BPM_EXPRESSION_FUNCTIONS = Symbol('BPM_EXPRESSION_FUNCTIONS');
6
+ /** The resolved registry the core injects. */
7
+ exports.BPM_EXPRESSION_FUNCTION_REGISTRY = Symbol('BPM_EXPRESSION_FUNCTION_REGISTRY');
8
+ //# sourceMappingURL=expression-function.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression-function.types.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/expression-function/expression-function.types.ts"],"names":[],"mappings":";;;AAqCA,wEAAwE;AAC3D,QAAA,wBAAwB,GAAG,MAAM,CAAC,0BAA0B,CAAC,CAAC;AAE3E,8CAA8C;AACjC,QAAA,gCAAgC,GAAG,MAAM,CACpD,kCAAkC,CACnC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './expression-function.built-ins';
2
+ export * from './expression-function.module';
3
+ export * from './expression-function.provider';
4
+ export * from './expression-function.registry';
5
+ export * from './expression-function.types';
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./expression-function.built-ins"), exports);
5
+ tslib_1.__exportStar(require("./expression-function.module"), exports);
6
+ tslib_1.__exportStar(require("./expression-function.provider"), exports);
7
+ tslib_1.__exportStar(require("./expression-function.registry"), exports);
8
+ tslib_1.__exportStar(require("./expression-function.types"), exports);
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/expression-function/index.ts"],"names":[],"mappings":";;;AAAA,0EAAgD;AAChD,uEAA6C;AAC7C,yEAA+C;AAC/C,yEAA+C;AAC/C,sEAA4C"}
@@ -6,6 +6,9 @@ exports.lintFormSchemaJson = lintFormSchemaJson;
6
6
  const form_1 = require("@rytass/bpm-core-shared/form");
7
7
  const form_org_unit_value_validator_1 = require("./form-org-unit-value.validator");
8
8
  const form_table_reference_1 = require("./form-table-reference");
9
+ const form_data_source_expression_1 = require("../form-data-source/form-data-source.expression");
10
+ /** The longest `EXPRESSION` binding the runtime evaluates (ConditionService). */
11
+ const MAX_EXPRESSION_BINDING_LENGTH = 2000;
9
12
  const SUPPORTED_FIELD_TYPES = [
10
13
  'boolean',
11
14
  'checkbox',
@@ -466,7 +469,30 @@ function lintDataSourceBinding(value, path, scope) {
466
469
  : []),
467
470
  ];
468
471
  }
469
- return [...errors, `${path}.from.kind must be FIELD, CONSTANT, or ROW_FIELD`];
472
+ // Only the shape here: a draft with a half-written expression must still
473
+ // save. Its cel-v2 lint (roots, functions, field types, the parameter's
474
+ // type) needs the DataSource descriptor and runs with the registry check at
475
+ // publish (`FormDataSourceService.lintDefinitionSchemaEnvironment`).
476
+ if (from.kind === 'EXPRESSION') {
477
+ // A blank expression is a draft the designer has not written yet; the
478
+ // publish lint refuses it (`EXPR_PARSE_FAILED`).
479
+ return [
480
+ ...errors,
481
+ ...(typeof from.expression === 'string'
482
+ ? []
483
+ : [`${path}.from.expression must be a string`]),
484
+ ...(typeof from.expression === 'string' &&
485
+ from.expression.trim().length > MAX_EXPRESSION_BINDING_LENGTH
486
+ ? [
487
+ `${path}.from.expression must be ${MAX_EXPRESSION_BINDING_LENGTH} characters or fewer`,
488
+ ]
489
+ : []),
490
+ ];
491
+ }
492
+ return [
493
+ ...errors,
494
+ `${path}.from.kind must be FIELD, CONSTANT, ROW_FIELD, or EXPRESSION`,
495
+ ];
470
496
  }
471
497
  function lintFieldBindingTarget(fieldKey, path, scope) {
472
498
  if (typeof fieldKey !== 'string') {
@@ -752,8 +778,7 @@ function lintHiddenDataSourceDependencies(fields) {
752
778
  .filter((fieldKey) => typeof fieldKey === 'string'));
753
779
  const message = (path, dependencyKey) => `${path}.dataSource 所屬欄位為 hidden,只能綁定同為 hidden 的欄位,不可綁定顯示中的欄位:${dependencyKey}`;
754
780
  const readVisibleDependencies = (owner) => readBindingSources(owner)
755
- .filter((from) => from.kind === 'FIELD')
756
- .map((from) => from.fieldKey)
781
+ .flatMap(readTopLevelBindingDependencies)
757
782
  .filter((dependencyKey) => typeof dependencyKey === 'string' && visibleKeys.has(dependencyKey));
758
783
  return fields.flatMap((field, index) => {
759
784
  if (!isRecord(field) || field.hidden !== true) {
@@ -791,13 +816,26 @@ function readFieldDependencyEntries(field) {
791
816
  [
792
817
  `top:${fieldKey}`,
793
818
  readBindingSources(field)
794
- .filter((from) => from.kind === 'FIELD')
795
- .map((from) => from.fieldKey)
796
- .filter((dependencyKey) => typeof dependencyKey === 'string')
819
+ .flatMap(readTopLevelBindingDependencies)
797
820
  .map((dependencyKey) => `top:${dependencyKey}`),
798
821
  ],
799
822
  ];
800
823
  }
824
+ /**
825
+ * The top-level fields a binding reads: a `FIELD`'s key, or every `form.<key>`
826
+ * an `EXPRESSION` reads, from its AST (ADR 22 §3.7). The lint refuses dynamic
827
+ * access, so this is the whole dependency set; an expression that does not
828
+ * parse adds no edge here and is refused by the publish lint instead.
829
+ */
830
+ function readTopLevelBindingDependencies(from) {
831
+ if (from.kind === 'FIELD') {
832
+ return typeof from.fieldKey === 'string' ? [from.fieldKey] : [];
833
+ }
834
+ if (from.kind === 'EXPRESSION' && typeof from.expression === 'string') {
835
+ return (0, form_data_source_expression_1.readExpressionBindingDependencies)(from.expression)?.formFieldKeys ?? [];
836
+ }
837
+ return [];
838
+ }
801
839
  function readColumnDependencyNode(from, tableKey) {
802
840
  if (from.kind === 'FIELD' && typeof from.fieldKey === 'string') {
803
841
  return [`top:${from.fieldKey}`];
@@ -805,6 +843,15 @@ function readColumnDependencyNode(from, tableKey) {
805
843
  if (from.kind === 'ROW_FIELD' && typeof from.columnKey === 'string') {
806
844
  return [`col:${tableKey}.${from.columnKey}`];
807
845
  }
846
+ if (from.kind === 'EXPRESSION' && typeof from.expression === 'string') {
847
+ const dependencies = (0, form_data_source_expression_1.readExpressionBindingDependencies)(from.expression);
848
+ return dependencies
849
+ ? [
850
+ ...dependencies.formFieldKeys.map((key) => `top:${key}`),
851
+ ...dependencies.rowColumnKeys.map((key) => `col:${tableKey}.${key}`),
852
+ ]
853
+ : [];
854
+ }
808
855
  return [];
809
856
  }
810
857
  function readBindingSources(field) {