@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
@@ -1,62 +1,181 @@
1
1
  "use strict";
2
+ var ConditionService_1;
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.ConditionService = void 0;
4
5
  const tslib_1 = require("tslib");
5
6
  const common_1 = require("@nestjs/common");
6
- let celEngine = null;
7
+ const bpm_core_shared_1 = require("@rytass/bpm-core-shared");
8
+ const expression_errors_1 = require("./expression-errors");
9
+ const expression_budget_1 = require("./expression-budget");
10
+ const expression_engine_failure_1 = require("./expression-engine-failure");
11
+ const expression_runtime_1 = require("./expression-runtime");
12
+ const cel_legacy_adapter_1 = require("./adapters/cel-legacy.adapter");
13
+ const cel_v2_adapter_1 = require("./adapters/cel-v2.adapter");
14
+ const expression_function_registry_1 = require("../expression-function/expression-function.registry");
15
+ const expression_function_types_1 = require("../expression-function/expression-function.types");
16
+ const expression_dialect_1 = require("./expression-dialect");
17
+ const expression_ast_1 = require("./expression-ast");
7
18
  /**
8
- * Loads `cel-js` on first use rather than when this module is imported.
9
- *
10
- * `cel-js` is ESM-only and its `chevrotain` dependency ships an exports map
11
- * that `jest-resolve` cannot follow. While the import sat at the top of this
12
- * file, the package root pulled it in through
13
- * `index → bpm-root → delegation → condition`, so *any* consumer test that
14
- * imported anything from `@rytass/bpm-core-nestjs-module` failed to load with
15
- * `Cannot find module 'chevrotain'` — pointing deep into `node_modules`, far
16
- * from the code under test. Hosts had to stub `cel-js` before they could write
17
- * a single test.
18
- *
19
- * Deferring the load means a host that never evaluates a CEL expression never
20
- * resolves the package at all. `require` (not `await import`) keeps every
21
- * caller in this file synchronous.
19
+ * The warm-up expression: a root read, a comparison and arithmetic, so the
20
+ * engine's parser, interpreter, member access and the budget's `vm` timeout
21
+ * all run once. It calls no function, so a host registry is only read (to
22
+ * build the environment), never invoked.
22
23
  */
23
- function loadCelEngine() {
24
- if (celEngine === null) {
24
+ const WARM_UP_EXPRESSION = 'form.warmUp + 1 == 2';
25
+ const WARM_UP_CONTEXT = { form: { warmUp: 1 } };
26
+ const WARM_UP_LABEL = 'warmUp';
27
+ // Generous on purpose: the cold first evaluation is exactly what is slow
28
+ // (Phase 23 P3 measured about 90 ms against the 100 ms budget).
29
+ const WARM_UP_BUDGET = { cumulativeMs: 5_000, perExpressionMs: 5_000 };
30
+ const WARM_UP_DIALECTS = ['cel-legacy', 'cel-v2'];
31
+ /** `code=EXPRESSION_WARM_UP_DONE cel-legacy=1.2ms cel-v2=3.4ms`. */
32
+ const formatWarmUpLine = (result) => [
33
+ 'code=EXPRESSION_WARM_UP_DONE',
34
+ ...WARM_UP_DIALECTS.map((dialect) => {
35
+ const elapsed = result[dialect];
36
+ return `${dialect}=${elapsed === null ? 'failed' : `${elapsed.toFixed(1)}ms`}`;
37
+ }),
38
+ ].join(' ');
39
+ const DEFAULT_MAX_EXPRESSION_LENGTH = 2000;
40
+ // `has` and `size` are CEL macros, not context identifiers; the root-identifier
41
+ // lint must not report them as unknown. `size` is required by the table field
42
+ // IS_FILLED / IS_EMPTY expressions (ADR 16 §3.8).
43
+ const CEL_KEYWORDS = new Set(['false', 'has', 'in', 'null', 'size', 'true']);
44
+ let ConditionService = ConditionService_1 = class ConditionService {
45
+ /**
46
+ * Evaluates and lints with the expression function registry
47
+ * (`BPM_EXPRESSION_FUNCTION_REGISTRY`, ADR 22 §3.5): both dialects call its
48
+ * functions and the cel-v2 lint checks against it. The injection is
49
+ * optional and `ConditionService` is also built with `new` in hosts and
50
+ * tests, so `new ConditionService()` still works: only the nine built-ins.
51
+ */
52
+ constructor(functionRegistry) {
53
+ this.logger = new common_1.Logger(ConditionService_1.name);
54
+ this.functionRegistry =
55
+ functionRegistry ?? expression_function_registry_1.BUILT_IN_EXPRESSION_FUNCTION_REGISTRY;
56
+ // The built-ins-only registry gets the shared default adapters.
57
+ this.runtime = expression_runtime_1.ExpressionRuntime.withFunctions(this.functionRegistry);
58
+ }
59
+ /**
60
+ * Warms both engines at boot so the first case does not pay for it (Phase 23
61
+ * P3 live finding: the first evaluation after a restart took about 90 ms of
62
+ * its 100 ms budget, against about 1 ms warm).
63
+ *
64
+ * A warm-up that succeeded for any dialect writes one `log` line with each
65
+ * dialect's time (a failed one reads `failed` and has already warned with
66
+ * `EXPRESSION_WARM_UP_FAILED`), so a deployment can see it ran. The line
67
+ * holds only fixed words and milliseconds: no expression, no data. It is
68
+ * written here, not in `warmUp()`, so calling `warmUp()` stays silent.
69
+ */
70
+ onApplicationBootstrap() {
71
+ const result = this.warmUp();
72
+ if (WARM_UP_DIALECTS.some((dialect) => result[dialect] !== null)) {
73
+ this.logger.log(formatWarmUpLine(result));
74
+ }
75
+ }
76
+ /**
77
+ * Loads each dialect's engine and this registry's environment, then parses,
78
+ * lints and evaluates one expression per dialect under a generous budget of
79
+ * its own, so module loading, the cel-v2 environment clone and the `vm`
80
+ * context are paid here. Never throws: a dialect that fails (a host
81
+ * registry that cannot be read, say) is logged with a fixed code and left
82
+ * cold, and the evaluations it serves fail closed as before.
83
+ */
84
+ warmUp() {
85
+ const entries = WARM_UP_DIALECTS.map((dialect) => {
86
+ const startedAt = performance.now();
87
+ try {
88
+ this.prepareEngine(dialect);
89
+ this.lintExpressionIssues(WARM_UP_EXPRESSION, WARM_UP_LABEL, {
90
+ dialect,
91
+ });
92
+ this.evaluateValue(WARM_UP_EXPRESSION, WARM_UP_CONTEXT, WARM_UP_LABEL, {
93
+ budget: (0, expression_budget_1.createExpressionBudget)(WARM_UP_BUDGET),
94
+ dialect,
95
+ });
96
+ return [dialect, performance.now() - startedAt];
97
+ }
98
+ catch {
99
+ // The error may carry host text; only a fixed code is written.
100
+ this.logger.warn(`code=EXPRESSION_WARM_UP_FAILED dialect=${dialect}`);
101
+ return [dialect, null];
102
+ }
103
+ });
104
+ return Object.fromEntries(entries);
105
+ }
106
+ /**
107
+ * Loads the dialect's engine and builds this registry's function
108
+ * environment now, outside any budget. Callers that are about to start a
109
+ * budgeted run (the dry run) call this first so an interrupt cannot land
110
+ * halfway through module loading or function registration.
111
+ */
112
+ prepareEngine(dialect = expression_dialect_1.DEFAULT_EXPRESSION_DIALECT) {
113
+ const readDialect = (0, expression_dialect_1.readExpressionDialect)(dialect, 'expressionDialect');
25
114
  try {
26
- celEngine = require('cel-js');
115
+ if (readDialect === 'cel-v2') {
116
+ (0, cel_v2_adapter_1.loadCelV2Environment)(this.functionRegistry);
117
+ return;
118
+ }
119
+ (0, cel_legacy_adapter_1.loadCelEngine)();
120
+ (0, cel_legacy_adapter_1.readCelLegacyFunctions)(this.functionRegistry);
27
121
  }
28
122
  catch (error) {
29
- // Deferring the load also defers this failure: it used to surface at
30
- // boot as a bare ERR_REQUIRE_ESM, and would now surface as a 500 on
31
- // whichever request first evaluated a condition. Name the cause where it
32
- // is thrown.
33
- if (isRequireEsmError(error)) {
34
- throw new Error(`[@rytass/bpm-core-nestjs-module] This Node version cannot require the ESM-only 'cel-js'. BPM needs Node >=20.19 or >=22.12 to evaluate CEL conditions. Original error: ${error instanceof Error ? error.message : String(error)}`);
123
+ // A registry that throws or answers out of shape is
124
+ // `EXPRESSION_FUNCTION_FAILED`, never the host's own error. An engine
125
+ // that fails to load is a configuration error and passes through.
126
+ if (error instanceof expression_engine_failure_1.ExpressionEngineFailure) {
127
+ throw (0, expression_errors_1.toExpressionRuntimeError)(error, 'expressionFunctions');
35
128
  }
36
129
  throw error;
37
130
  }
38
131
  }
39
- return celEngine;
40
- }
41
- function isRequireEsmError(error) {
42
- return (typeof error === 'object' &&
43
- error !== null &&
44
- 'code' in error &&
45
- error.code === 'ERR_REQUIRE_ESM');
46
- }
47
- const DEFAULT_MAX_EXPRESSION_LENGTH = 2000;
48
- // `has` and `size` are CEL macros, not context identifiers; the root-identifier
49
- // lint must not report them as unknown. `size` is required by the table field
50
- // IS_FILLED / IS_EMPTY expressions (ADR 16 §3.8).
51
- const CEL_KEYWORDS = new Set(['false', 'has', 'in', 'null', 'size', 'true']);
52
- let ConditionService = class ConditionService {
53
132
  lintExpressions(expressions, options = {}) {
54
133
  return expressions.flatMap(({ expression, label }) => this.lintExpression(expression, label, options));
55
134
  }
135
+ /**
136
+ * The lint as structured findings, warnings included (docs/24 §2.2): what
137
+ * the designer's preview and the publish lint read. `lintExpression` is the
138
+ * error half of it, as the lines publish has always returned.
139
+ */
140
+ lintExpressionIssues(expression, label, options = {}) {
141
+ if (typeof expression === 'undefined' || expression === null) {
142
+ return [];
143
+ }
144
+ const trimmedExpression = expression.trim();
145
+ const maxExpressionLength = options.maxExpressionLength ?? DEFAULT_MAX_EXPRESSION_LENGTH;
146
+ if (!trimmedExpression) {
147
+ return [lintIssue('EXPR_PARSE_FAILED', label)];
148
+ }
149
+ if (trimmedExpression.length > maxExpressionLength) {
150
+ return [lintIssue('EXPR_COMPLEXITY_EXCEEDED', label)];
151
+ }
152
+ if (options.dialect !== undefined &&
153
+ !(0, expression_dialect_1.isExpressionDialect)(options.dialect)) {
154
+ return [lintIssue('EXPR_PARSE_FAILED', label)];
155
+ }
156
+ if (options.dialect === 'cel-v2') {
157
+ return (0, expression_ast_1.lintCelV2Expression)(trimmedExpression, label, {
158
+ ...options,
159
+ functionRegistry: options.functionRegistry ?? this.functionRegistry,
160
+ }, this.functionRegistry);
161
+ }
162
+ if ((0, cel_legacy_adapter_1.parseCelLegacy)(trimmedExpression) === null) {
163
+ return [lintIssue('EXPR_PARSE_FAILED', label)];
164
+ }
165
+ return readUnsupportedRootIdentifiers(trimmedExpression, readLintRoots(options), 'cel-legacy').map((identifier) => lintIssue('EXPR_ROOT_NOT_ALLOWED', label, identifier));
166
+ }
56
167
  lintExpression(expression, label, options = {}) {
57
168
  if (typeof expression === 'undefined' || expression === null) {
58
169
  return [];
59
170
  }
171
+ // cel-v2 is linted on its AST (ADR 22 §3.4) and answers with the codes
172
+ // the preview reads (docs/24 §2.2), blank and over-long included; only
173
+ // the errors refuse, each as one `<label>: <code>` line.
174
+ if (options.dialect === 'cel-v2') {
175
+ return this.lintExpressionIssues(expression, label, options)
176
+ .filter((finding) => finding.severity === 'ERROR')
177
+ .map(bpm_core_shared_1.formatExpressionLintIssue);
178
+ }
60
179
  const trimmedExpression = expression.trim();
61
180
  const maxExpressionLength = options.maxExpressionLength ?? DEFAULT_MAX_EXPRESSION_LENGTH;
62
181
  if (!trimmedExpression) {
@@ -65,60 +184,157 @@ let ConditionService = class ConditionService {
65
184
  if (trimmedExpression.length > maxExpressionLength) {
66
185
  return [`${label} must be ${maxExpressionLength} characters or fewer`];
67
186
  }
68
- const parseResult = loadCelEngine().parse(trimmedExpression);
69
- if (isParseFailure(parseResult)) {
70
- return parseResult.errors.map((error) => `${label}: ${error}`);
187
+ // A dialect this version does not know is not guessed at: parsing with
188
+ // the wrong engine could pass what the right one refuses.
189
+ if (options.dialect !== undefined &&
190
+ !(0, expression_dialect_1.isExpressionDialect)(options.dialect)) {
191
+ return [`${label}: EXPRESSION_SYNTAX_ERROR`];
71
192
  }
72
- return lintRootIdentifiers(trimmedExpression, label, options);
193
+ // The engine's parse message is not returned: it can echo the expression,
194
+ // and the lint result reaches GraphQL clients (ADR 22 §3.2).
195
+ if ((0, cel_legacy_adapter_1.parseCelLegacy)(trimmedExpression) === null) {
196
+ return [`${label}: EXPRESSION_SYNTAX_ERROR`];
197
+ }
198
+ return lintRootIdentifiers(trimmedExpression, label, readLintRoots(options), 'cel-legacy');
73
199
  }
74
- evaluateBoolean(expression, context, label) {
200
+ evaluateBoolean(expression, context, label, options = {}) {
75
201
  if (typeof expression !== 'string' || !expression.trim()) {
76
202
  return true;
77
203
  }
78
- const value = this.evaluateValue(expression, context, label);
204
+ const value = this.evaluateValue(expression, context, label, options);
79
205
  if (typeof value === 'boolean') {
80
206
  return value;
81
207
  }
82
- throw new common_1.BadRequestException(`${label} must evaluate to a boolean`);
208
+ throw new expression_errors_1.ExpressionRuntimeError('EXPRESSION_TYPE_ERROR', label, {
209
+ detail: 'must evaluate to a boolean',
210
+ });
83
211
  }
84
- evaluateValue(expression, context, label) {
212
+ evaluateValue(expression, context, label, options = {}) {
85
213
  const trimmedExpression = expression.trim();
86
- const lengthErrors = this.lintExpression(trimmedExpression, label);
87
- if (lengthErrors.length) {
88
- throw new common_1.BadRequestException(lengthErrors.join('; '));
89
- }
90
- const engine = loadCelEngine();
91
- const parseResult = engine.parse(trimmedExpression);
92
- if (isParseFailure(parseResult)) {
93
- throw new common_1.BadRequestException(parseResult.errors.map((error) => `${label}: ${error}`).join('; '));
94
- }
95
- try {
96
- return engine.evaluate(parseResult.cst, { ...context });
97
- }
98
- catch (error) {
99
- throw new common_1.BadRequestException(error instanceof Error ? `${label}: ${error.message}` : label);
100
- }
214
+ const dialect = (0, expression_dialect_1.readExpressionDialect)(options.dialect, label);
215
+ assertEvaluable(trimmedExpression, label, options.allowedRootIdentifiers, dialect);
216
+ return this.runtime.evaluate({
217
+ budget: options.budget ??
218
+ (0, expression_budget_1.currentExpressionBudget)() ??
219
+ (0, expression_budget_1.createExpressionBudget)(expression_budget_1.DEFAULT_EXPRESSION_BUDGET),
220
+ dialect,
221
+ expression: trimmedExpression,
222
+ label,
223
+ roots: pickAllowedRoots(context, options.allowedRootIdentifiers),
224
+ });
101
225
  }
102
226
  };
103
227
  exports.ConditionService = ConditionService;
104
- exports.ConditionService = ConditionService = tslib_1.__decorate([
105
- (0, common_1.Injectable)()
228
+ exports.ConditionService = ConditionService = ConditionService_1 = tslib_1.__decorate([
229
+ (0, common_1.Injectable)(),
230
+ tslib_1.__param(0, (0, common_1.Optional)()),
231
+ tslib_1.__param(0, (0, common_1.Inject)(expression_function_types_1.BPM_EXPRESSION_FUNCTION_REGISTRY)),
232
+ tslib_1.__metadata("design:paramtypes", [Object])
106
233
  ], ConditionService);
107
- function isParseFailure(parseResult) {
108
- return !parseResult.isSuccess;
234
+ /**
235
+ * The roots handed to the engine: only the allowed ones when the use point has
236
+ * an allowlist. The textual root check cannot see a macro variable's scope (it
237
+ * skips the bound name everywhere in the expression), so this is what keeps a
238
+ * root the use point may not read out of reach, whatever else the caller's
239
+ * context holds. Without an allowlist the context is passed as given.
240
+ */
241
+ function pickAllowedRoots(context, allowedRootIdentifiers) {
242
+ if (!allowedRootIdentifiers?.length) {
243
+ return context;
244
+ }
245
+ return Object.fromEntries(allowedRootIdentifiers
246
+ .filter((identifier) => Object.prototype.hasOwnProperty.call(context, identifier))
247
+ .map((identifier) => [
248
+ identifier,
249
+ context[identifier],
250
+ ]));
109
251
  }
110
- function lintRootIdentifiers(expression, label, options) {
111
- const allowedRootIdentifiers = options.allowedRootIdentifiers;
252
+ /**
253
+ * Guards that run before anything is parsed or evaluated. A refusal is an
254
+ * `EXPRESSION_SYNTAX_ERROR`: the expression is not one this runtime will run.
255
+ */
256
+ function assertEvaluable(expression, label, allowedRootIdentifiers, dialect) {
257
+ if (!expression || expression.length > DEFAULT_MAX_EXPRESSION_LENGTH) {
258
+ throw new expression_errors_1.ExpressionRuntimeError('EXPRESSION_SYNTAX_ERROR', label);
259
+ }
260
+ if (lintRootIdentifiers(expression, label, allowedRootIdentifiers, dialect)
261
+ .length > 0) {
262
+ throw new expression_errors_1.ExpressionRuntimeError('EXPRESSION_SYNTAX_ERROR', label);
263
+ }
264
+ }
265
+ function lintIssue(code, label, subject) {
266
+ return {
267
+ code,
268
+ label,
269
+ severity: (0, bpm_core_shared_1.readExpressionLintSeverity)(code),
270
+ ...(subject === undefined ? {} : { subject }),
271
+ };
272
+ }
273
+ /**
274
+ * The cel-legacy lint's roots. A use point that is set but is not one (a
275
+ * client may send `toString`) is never used as an index: it allows nothing
276
+ * beyond the keywords the scan always skips, so every root is reported. An
277
+ * empty list would not do that: `readUnsupportedRootIdentifiers` reads it as
278
+ * "do not check".
279
+ */
280
+ function readLintRoots(options) {
281
+ if (options.allowedRootIdentifiers?.length) {
282
+ return options.allowedRootIdentifiers;
283
+ }
284
+ if (options.usagePoint !== undefined &&
285
+ options.usagePoint !== null &&
286
+ !(0, bpm_core_shared_1.isExpressionUsagePoint)(options.usagePoint)) {
287
+ return [...CEL_KEYWORDS];
288
+ }
289
+ return options.usagePoint
290
+ ? bpm_core_shared_1.EXPRESSION_ROOT_IDENTIFIERS_BY_USAGE_POINT[options.usagePoint]
291
+ : options.allowedRootIdentifiers;
292
+ }
293
+ // cel-v2 macros that bind a variable as their first argument
294
+ // (`list.map(x, ...)`, `list.exists(x, ...)` ...).
295
+ const CEL_V2_BINDING_MACRO_PATTERN = /\.\s*(?:all|exists|exists_one|filter|map)\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,/gu;
296
+ /**
297
+ * Root identifiers the expression reads that its use point does not allow,
298
+ * found by a textual scan.
299
+ *
300
+ * The lint uses this for cel-legacy only, which has no AST to read (docs/24
301
+ * §1); cel-v2 is linted on its AST (`lintCelV2Expression`), where a name a
302
+ * macro binds is in scope only inside that macro.
303
+ *
304
+ * Evaluation still runs this scan before handing an expression to either
305
+ * engine (`assertEvaluable`). For cel-v2 it skips what that dialect adds and
306
+ * is not a root: names a macro binds (`a` in `form.l.map(a, a.qty)`) and
307
+ * global function calls (`int(form.x)`). A bound name is skipped everywhere in
308
+ * the expression, not only inside its macro, so
309
+ * `[1].exists(lastDecision, true) && lastDecision.d == ""` passes the scan
310
+ * where `lastDecision` is not allowed. The publish lint refuses that on the
311
+ * AST; at evaluation `evaluateValue` hands the engine only the allowed roots
312
+ * (`pickAllowedRoots`), so the name outside the macro is a missing key.
313
+ */
314
+ function readUnsupportedRootIdentifiers(expression, allowedRootIdentifiers, dialect = expression_dialect_1.DEFAULT_EXPRESSION_DIALECT) {
112
315
  if (!allowedRootIdentifiers?.length) {
113
316
  return [];
114
317
  }
115
- const allowed = new Set([...allowedRootIdentifiers, ...CEL_KEYWORDS]);
116
318
  const sanitizedExpression = stripStringLiterals(expression);
117
- const identifiers = Array.from(sanitizedExpression.matchAll(/(^|[^A-Za-z0-9_.])([A-Za-z_][A-Za-z0-9_]*)/gu)).map((match) => match[2]);
118
- const unknownIdentifiers = [
319
+ const isV2 = dialect === 'cel-v2';
320
+ const boundNames = isV2
321
+ ? Array.from(sanitizedExpression.matchAll(CEL_V2_BINDING_MACRO_PATTERN)).map((match) => match[1])
322
+ : [];
323
+ const allowed = new Set([
324
+ ...allowedRootIdentifiers,
325
+ ...CEL_KEYWORDS,
326
+ ...boundNames,
327
+ ]);
328
+ const identifiers = Array.from(sanitizedExpression.matchAll(/(^|[^A-Za-z0-9_.])([A-Za-z_][A-Za-z0-9_]*)/gu))
329
+ .filter((match) => !isV2 ||
330
+ !/^\s*\(/u.test(sanitizedExpression.slice((match.index ?? 0) + match[0].length)))
331
+ .map((match) => match[2]);
332
+ return [
119
333
  ...new Set(identifiers.filter((identifier) => !allowed.has(identifier))),
120
334
  ];
121
- return unknownIdentifiers.map((identifier) => `${label} references unsupported identifier ${identifier}`);
335
+ }
336
+ function lintRootIdentifiers(expression, label, allowedRootIdentifiers, dialect = expression_dialect_1.DEFAULT_EXPRESSION_DIALECT) {
337
+ return readUnsupportedRootIdentifiers(expression, allowedRootIdentifiers, dialect).map((identifier) => `${label} references unsupported identifier ${identifier}`);
122
338
  }
123
339
  function stripStringLiterals(expression) {
124
340
  return expression.replace(/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/gu, '""');
@@ -1 +1 @@
1
- {"version":3,"file":"condition.service.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/condition/condition.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"condition.service.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/condition/condition.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ import { ExpressionLintIssue, ExpressionUsagePoint } from '@rytass/bpm-core-shared';
2
+ import { FormDefinitionSchema, FormFieldDefinition } from '@rytass/bpm-core-shared/form';
3
+ import type { BPMExpressionFunctionRegistry } from '../expression-function/expression-function.types';
4
+ import { ExpressionDialect } from './expression-dialect';
5
+ /**
6
+ * A chain of member and index steps from a root: `form.items[0].qty` is
7
+ * `{ root: 'form', segments: ['items', '0', 'qty'] }`. `segments` stops at the
8
+ * first step that is not a literal (a computed index or a method call), and
9
+ * `complete` is then `false`.
10
+ */
11
+ export interface ExpressionFieldPath {
12
+ readonly complete: boolean;
13
+ readonly root: string;
14
+ readonly segments: readonly string[];
15
+ }
16
+ export interface ExpressionFunctionCall {
17
+ readonly argumentCount: number;
18
+ readonly name: string;
19
+ /** `true` for a method call (`x.contains(y)`), `false` for `f(x)`. */
20
+ readonly receiver: boolean;
21
+ }
22
+ /**
23
+ * A method or macro called directly on a path from a root:
24
+ * `form.items.exists(r, ...)` is `{ name: 'exists', path: form.items }`.
25
+ */
26
+ export interface ExpressionReceiverPath {
27
+ readonly name: string;
28
+ readonly path: ExpressionFieldPath;
29
+ }
30
+ /**
31
+ * A key that is not a literal: an index (`form[k]`, `form.a[form.b]`) or a map
32
+ * literal key (`{form.k: 1}`). `root` is the root the indexed chain starts at,
33
+ * `null` for map keys and chains that start elsewhere.
34
+ */
35
+ export interface ExpressionComputedKey {
36
+ readonly kind: 'INDEX' | 'MAP_KEY';
37
+ readonly root: string | null;
38
+ }
39
+ export interface ExpressionReferences {
40
+ /** Highest nesting of `all`/`exists`/`exists_one`/`map`/`filter`. */
41
+ readonly comprehensionDepth: number;
42
+ readonly computedKeys: readonly ExpressionComputedKey[];
43
+ readonly dialect: ExpressionDialect;
44
+ /** Paths read on the right of a `/`. */
45
+ readonly divisorFieldPaths: readonly ExpressionFieldPath[];
46
+ readonly fieldPaths: readonly ExpressionFieldPath[];
47
+ /** Top-level form field keys read through `form` or `formData`. */
48
+ readonly formFieldKeys: readonly string[];
49
+ readonly functionCalls: readonly ExpressionFunctionCall[];
50
+ /** Paths tested by `has(...)` or compared with `null`, `""` or `[]`. */
51
+ readonly guardedFieldPaths: readonly ExpressionFieldPath[];
52
+ /** The arguments of `has(...)`. */
53
+ readonly hasArguments: readonly ExpressionFieldPath[];
54
+ /**
55
+ * Parsed nodes. cel-v2 counts AST nodes (the engine refuses more than
56
+ * 200); cel-legacy counts CST atoms, steps and operators, which is a
57
+ * different measure and only comparable with itself.
58
+ */
59
+ readonly nodeCount: number;
60
+ /** Paths read inside an operand of `||`. */
61
+ readonly orOperandFieldPaths: readonly ExpressionFieldPath[];
62
+ readonly receiverPaths: readonly ExpressionReceiverPath[];
63
+ /** `__proto__`, `constructor` or `prototype` used as a member, key or map key. */
64
+ readonly reservedSegments: readonly string[];
65
+ /** Free identifiers: names the expression reads that nothing in it binds. */
66
+ readonly roots: readonly string[];
67
+ /** Roots used as a value themselves, not as the start of a path. */
68
+ readonly wholeRootReferences: readonly string[];
69
+ }
70
+ /**
71
+ * What `readExpressionReferences` found. `UNAVAILABLE` is a cel-legacy
72
+ * expression whose parser returned no CST to walk (the unit tests' `cel-js`
73
+ * shim does that): per docs/24 §1 the old dialect then keeps its textual lint.
74
+ */
75
+ export type ExpressionReferencesResult = {
76
+ readonly references: ExpressionReferences;
77
+ readonly status: 'OK';
78
+ } | {
79
+ readonly limitExceeded: boolean;
80
+ readonly status: 'PARSE_FAILED';
81
+ } | {
82
+ readonly status: 'UNAVAILABLE';
83
+ };
84
+ export declare const RESERVED_PATH_SEGMENTS: ReadonlySet<string>;
85
+ /** ADR 22 §3.4 / docs/24 §2.7. */
86
+ export declare const EXPRESSION_MAX_COMPREHENSION_DEPTH = 2;
87
+ /** Unique top-level keys of the paths rooted at `form` or `formData`, in first-seen order. */
88
+ export declare const readFormFieldKeys: (paths: readonly ExpressionFieldPath[]) => readonly string[];
89
+ /**
90
+ * The roots, field paths, function calls and structure an expression uses,
91
+ * read from its AST without evaluating it. Names a comprehension binds (`x`
92
+ * in `form.items.exists(x, x.qty > 0)`) are only in scope inside it: the same
93
+ * name outside it is a root.
94
+ *
95
+ * Works for both dialects. cel-v2 reads the engine's AST; cel-legacy walks the
96
+ * CST of `cel-js` and answers `UNAVAILABLE` when there is none to walk.
97
+ */
98
+ export declare function readExpressionReferences(expression: string, dialect?: ExpressionDialect): ExpressionReferencesResult;
99
+ /** Whether the expression reads the top-level form field `fieldKey`. */
100
+ export declare const readsFormField: (references: ExpressionReferences, fieldKey: string) => boolean;
101
+ /**
102
+ * Whether the expression steps inside the table field `tableKey`
103
+ * (`form.items.qty`, `form.items[0]`, `form.items.exists(r, ...)`), the AST
104
+ * twin of `referencesTableInternals` (ADR 16 §3.8). The table as a whole
105
+ * (`size(form.items)`, `form.items.size()`, `form.items == null`) is not.
106
+ */
107
+ export declare const readsTableInternals: (references: ExpressionReferences, tableKey: string) => boolean;
108
+ /** The slice of the function registry the lint uses (docs/24 §3: P3 implements it). */
109
+ export type ExpressionFunctionAvailability = Pick<BPMExpressionFunctionRegistry, 'assertPublishable' | 'get'>;
110
+ export interface ExpressionLintContext {
111
+ /** Overrides the use point's roots. Without either, roots are not checked. */
112
+ readonly allowedRootIdentifiers?: readonly string[];
113
+ /**
114
+ * The bound form. With it, field keys are checked against the schema and
115
+ * the type check knows each field's type; without it every field is `dyn`.
116
+ */
117
+ readonly formSchema?: FormDefinitionSchema | null;
118
+ /**
119
+ * The registry that answers which functions are available. Absent means
120
+ * only the nine built-ins exist (`BPM_BUILT_IN_EXPRESSION_FUNCTION_NAMES`);
121
+ * `ConditionService` fills it with the registry it was given. Host code:
122
+ * a throw or a malformed answer is isolated and refuses the names asked
123
+ * about (`EXPR_FUNCTION_NOT_REGISTERED`), never its message.
124
+ */
125
+ readonly functionRegistry?: ExpressionFunctionAvailability | null;
126
+ /** The field a `SET_FORM_FIELD` writes; decides its result type. */
127
+ readonly targetField?: FormFieldDefinition | null;
128
+ readonly usagePoint?: ExpressionUsagePoint;
129
+ }
130
+ /**
131
+ * The CEL types a form field is declared with for the lint's type check
132
+ * (docs/24-design/p2-p3 §2.2). Only names the engine accepts are produced;
133
+ * anything else is `dyn`. Never `optional(...)`: the engine cannot convert it.
134
+ */
135
+ export declare const readExpressionFieldType: (field: FormFieldDefinition) => string;
136
+ /**
137
+ * The called function names the registry cannot vouch for, in first-seen
138
+ * order and without duplicates (ADR 22 §5.3; publish and rollback share it).
139
+ *
140
+ * Only names {@link isRegistryFunctionName} accepts — `…_vN` and the nine
141
+ * built-ins — are put to `assertPublishable`; any other name can never be
142
+ * registered and is always reported. Without a registry only the built-ins
143
+ * exist.
144
+ *
145
+ * The registry is host code and is isolated: an `assertPublishable` that
146
+ * throws or answers something other than a list of strings makes every name
147
+ * asked about unavailable. The result only ever holds names the expression
148
+ * itself called, never a value the registry returned.
149
+ */
150
+ export declare function readUnavailableExpressionFunctions(names: readonly string[], registry: ExpressionFunctionAvailability | null | undefined): readonly string[];
151
+ /**
152
+ * The cel-v2 lint of one expression (ADR 22 §3.4, docs/24 §2.2): errors that
153
+ * refuse a publish and warnings that do not, in that order. The expression is
154
+ * expected trimmed and within the length limit (`ConditionService` checks
155
+ * both first).
156
+ *
157
+ * `environmentRegistry` is the registry evaluation will run with (the one
158
+ * `ConditionService` was given): the expression is parsed and type-checked in
159
+ * its cel-v2 environment, so the built-ins and the host's functions are
160
+ * type-checked like the engine's own. Absent means the built-ins only. It is
161
+ * separate from `context.functionRegistry`, which only answers availability
162
+ * (`assertPublishable`, `get`) and need not be able to build an environment.
163
+ *
164
+ * The type check (`env.check()`) runs only when nothing structural is wrong
165
+ * and every function called is one that environment knows; a call to one it
166
+ * does not know is covered by `EXPR_FUNCTION_NOT_REGISTERED` instead.
167
+ */
168
+ export declare function lintCelV2Expression(expression: string, label: string, context?: ExpressionLintContext, environmentRegistry?: BPMExpressionFunctionRegistry | null): readonly ExpressionLintIssue[];
169
+ /**
170
+ * The global function names an expression calls that cel-v2 does not provide
171
+ * itself: the built-ins and host functions a rollback must find registered
172
+ * (docs/24 §1). `null` when the expression cannot be read. Hand the result to
173
+ * {@link readUnavailableExpressionFunctions}, which applies the same name
174
+ * rule and registry isolation as the publish lint.
175
+ */
176
+ export declare function readExpressionHostFunctionNames(expression: string, dialect?: ExpressionDialect): readonly string[] | null;