@usearazzo/runner 1.0.1-alpha.20 → 1.0.1-alpha.21
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/CHANGELOG.md +19 -0
- package/README.md +2 -2
- package/dist/arazzo-runner.browser.js +139 -44
- package/dist/arazzo-runner.browser.min.js +1 -1
- package/package.json +4 -4
- package/src/action/ActionResolver.cjs +8 -4
- package/src/action/ActionResolver.mjs +8 -4
- package/src/criterion/CriterionEvaluator.cjs +28 -10
- package/src/criterion/CriterionEvaluator.mjs +27 -10
- package/src/criterion/JSONPathCriterionEvaluator.cjs +4 -1
- package/src/criterion/JSONPathCriterionEvaluator.mjs +5 -2
- package/src/criterion/RegexCriterionEvaluator.cjs +3 -1
- package/src/criterion/RegexCriterionEvaluator.mjs +3 -1
- package/src/criterion/XPathCriterionEvaluator.cjs +3 -0
- package/src/criterion/XPathCriterionEvaluator.mjs +3 -0
- package/src/executor/StepExecutor.cjs +80 -24
- package/src/executor/StepExecutor.mjs +80 -24
- package/src/executor/WorkflowExecutor.cjs +13 -4
- package/src/executor/WorkflowExecutor.mjs +13 -4
- package/types/runner.d.ts +98 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usearazzo/runner",
|
|
3
|
-
"version": "1.0.1-alpha.
|
|
3
|
+
"version": "1.0.1-alpha.21",
|
|
4
4
|
"description": "Runner for Arazzo Workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arazzo",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"@swaggerexpert/json-pointer": "^3.0.2",
|
|
74
74
|
"@swaggerexpert/jsonpath": "^4.0.5",
|
|
75
75
|
"@swaggerexpert/media-types": "^1.0.2",
|
|
76
|
-
"@usearazzo/parser": "1.0.1-alpha.
|
|
77
|
-
"@usearazzo/resolver": "1.0.1-alpha.
|
|
76
|
+
"@usearazzo/parser": "1.0.1-alpha.21",
|
|
77
|
+
"@usearazzo/resolver": "1.0.1-alpha.21",
|
|
78
78
|
"@xmldom/xmldom": "^0.9.12",
|
|
79
79
|
"fontoxpath": "^3.34.0",
|
|
80
80
|
"ramda": "^0.32.0",
|
|
@@ -94,5 +94,5 @@
|
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"swagger-client": "^3.38.4"
|
|
96
96
|
},
|
|
97
|
-
"gitHead": "
|
|
97
|
+
"gitHead": "d342b02adbd11f5362aa4850b2417521e59448ce"
|
|
98
98
|
}
|
|
@@ -9,10 +9,11 @@ var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
|
9
9
|
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
10
10
|
var _ResolverError = _interopRequireDefault(require("../errors/ResolverError.cjs"));
|
|
11
11
|
/**
|
|
12
|
-
* Determines whether a single criterion is met.
|
|
12
|
+
* Determines whether a single criterion of an action is met. Receives the
|
|
13
|
+
* action declaring the criterion, so a caller can attribute the outcome to it.
|
|
13
14
|
*
|
|
14
15
|
* Bridged to a criterion evaluator
|
|
15
|
-
* (`(criterion) => criterionEvaluator.evaluate(criterion, resolve)`); an
|
|
16
|
+
* (`(criterion) => criterionEvaluator.evaluate(criterion, resolve).met`); an
|
|
16
17
|
* unresolvable/failing criterion is `false`, not an error.
|
|
17
18
|
* @public
|
|
18
19
|
*/
|
|
@@ -144,6 +145,7 @@ class ActionResolver {
|
|
|
144
145
|
reason: 'malformed-criteria'
|
|
145
146
|
});
|
|
146
147
|
}
|
|
148
|
+
let met = true;
|
|
147
149
|
for (const criterion of criteria) {
|
|
148
150
|
if (!(0, _apidomNsArazzo.isCriterionElement)(criterion)) {
|
|
149
151
|
throw new _ResolverError.default("An action's `criteria` contains an entry that is not a Criterion Object", {
|
|
@@ -152,9 +154,11 @@ class ActionResolver {
|
|
|
152
154
|
reason: 'malformed-criterion'
|
|
153
155
|
});
|
|
154
156
|
}
|
|
155
|
-
|
|
157
|
+
// every criterion is evaluated, not only up to the first unmet one, so
|
|
158
|
+
// a predicate that records outcomes sees the whole list.
|
|
159
|
+
if (!isCriterionMet(criterion, action)) met = false;
|
|
156
160
|
}
|
|
157
|
-
return
|
|
161
|
+
return met;
|
|
158
162
|
}
|
|
159
163
|
}
|
|
160
164
|
var _default = exports.default = ActionResolver;
|
|
@@ -2,10 +2,11 @@ import { isArrayElement } from '@speclynx/apidom-datamodel';
|
|
|
2
2
|
import { isSuccessActionElement, isFailureActionElement, isCriterionElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
3
3
|
import ResolverError from "../errors/ResolverError.mjs";
|
|
4
4
|
/**
|
|
5
|
-
* Determines whether a single criterion is met.
|
|
5
|
+
* Determines whether a single criterion of an action is met. Receives the
|
|
6
|
+
* action declaring the criterion, so a caller can attribute the outcome to it.
|
|
6
7
|
*
|
|
7
8
|
* Bridged to a criterion evaluator
|
|
8
|
-
* (`(criterion) => criterionEvaluator.evaluate(criterion, resolve)`); an
|
|
9
|
+
* (`(criterion) => criterionEvaluator.evaluate(criterion, resolve).met`); an
|
|
9
10
|
* unresolvable/failing criterion is `false`, not an error.
|
|
10
11
|
* @public
|
|
11
12
|
*/
|
|
@@ -134,6 +135,7 @@ class ActionResolver {
|
|
|
134
135
|
reason: 'malformed-criteria'
|
|
135
136
|
});
|
|
136
137
|
}
|
|
138
|
+
let met = true;
|
|
137
139
|
for (const criterion of criteria) {
|
|
138
140
|
if (!isCriterionElement(criterion)) {
|
|
139
141
|
throw new ResolverError("An action's `criteria` contains an entry that is not a Criterion Object", {
|
|
@@ -142,9 +144,11 @@ class ActionResolver {
|
|
|
142
144
|
reason: 'malformed-criterion'
|
|
143
145
|
});
|
|
144
146
|
}
|
|
145
|
-
|
|
147
|
+
// every criterion is evaluated, not only up to the first unmet one, so
|
|
148
|
+
// a predicate that records outcomes sees the whole list.
|
|
149
|
+
if (!isCriterionMet(criterion, action)) met = false;
|
|
146
150
|
}
|
|
147
|
-
return
|
|
151
|
+
return met;
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
export default ActionResolver;
|
|
@@ -28,6 +28,11 @@ var _XPathCriterionEvaluator = _interopRequireDefault(require("./XPathCriterionE
|
|
|
28
28
|
* @public
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* The outcome of evaluating one criterion.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
|
|
31
36
|
/**
|
|
32
37
|
* Options for the CriterionEvaluator.
|
|
33
38
|
*
|
|
@@ -38,7 +43,7 @@ var _XPathCriterionEvaluator = _interopRequireDefault(require("./XPathCriterionE
|
|
|
38
43
|
*/
|
|
39
44
|
|
|
40
45
|
/**
|
|
41
|
-
* Evaluates an Arazzo Criterion Object to a
|
|
46
|
+
* Evaluates an Arazzo Criterion Object to a {@link CriterionOutcome}.
|
|
42
47
|
*
|
|
43
48
|
* Dispatches on the criterion's `type` (defaulting to `simple` when omitted):
|
|
44
49
|
* - `simple` — evaluates the condition directly, resolving the runtime
|
|
@@ -58,12 +63,13 @@ var _XPathCriterionEvaluator = _interopRequireDefault(require("./XPathCriterionE
|
|
|
58
63
|
* the 1.1.0 rule to every document, which accepts more but never evaluates a
|
|
59
64
|
* query under the wrong dialect.
|
|
60
65
|
*
|
|
61
|
-
* A condition that cannot be evaluated fails the criterion (`false`), as
|
|
66
|
+
* A condition that cannot be evaluated fails the criterion (`met: false`), as
|
|
62
67
|
* Arazzo 1.1.0 requires: a syntax error in the condition, a context the
|
|
63
68
|
* condition cannot apply to (non-XML data for `xpath`), or an XPath evaluation
|
|
64
69
|
* error. The type-specific evaluators report these as a
|
|
65
|
-
* {@link CriterionEvaluationError}, which this facade
|
|
66
|
-
*
|
|
70
|
+
* {@link CriterionEvaluationError}, which this facade returns as the
|
|
71
|
+
* outcome's `error` so the caller can report it; any other error they raise
|
|
72
|
+
* propagates. A criterion that is malformed as written still throws: a
|
|
67
73
|
* missing `condition`, an unknown or unreadable `type`, an unsupported
|
|
68
74
|
* expression `version`, or a `context` that is missing or not a runtime
|
|
69
75
|
* expression.
|
|
@@ -87,7 +93,8 @@ class CriterionEvaluator {
|
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
/**
|
|
90
|
-
* Evaluates a criterion element, returning whether the condition is met
|
|
96
|
+
* Evaluates a criterion element, returning whether the condition is met and,
|
|
97
|
+
* when it cannot be evaluated, why.
|
|
91
98
|
*
|
|
92
99
|
* `resolve` turns a runtime expression into a value: for `simple` it resolves
|
|
93
100
|
* the expressions embedded in the condition; for the other types it resolves
|
|
@@ -109,23 +116,28 @@ class CriterionEvaluator {
|
|
|
109
116
|
}
|
|
110
117
|
const type = this.#resolveType(criterion);
|
|
111
118
|
this.#requireValidContext(criterion, type);
|
|
119
|
+
let met;
|
|
112
120
|
try {
|
|
113
121
|
switch (type) {
|
|
114
122
|
case 'simple':
|
|
115
|
-
|
|
123
|
+
met = this.#simple.evaluate(condition, resolve);
|
|
124
|
+
break;
|
|
116
125
|
case 'regex':
|
|
117
|
-
|
|
126
|
+
met = this.#regex.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
127
|
+
break;
|
|
118
128
|
case 'jsonpath':
|
|
119
129
|
// only rfc9535 is supported, Arazzo 1.1.0's default, so an omitted
|
|
120
130
|
// version is accepted. draft-goessner has different semantics and is
|
|
121
131
|
// rejected rather than mis-evaluated.
|
|
122
132
|
this.#requireVersion(criterion, type, condition, 'rfc9535');
|
|
123
|
-
|
|
133
|
+
met = this.#jsonpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
134
|
+
break;
|
|
124
135
|
case 'xpath':
|
|
125
136
|
// only XPath 3.1 is supported; xpath-31 is Arazzo 1.1.0's default, so
|
|
126
137
|
// an omitted version is accepted. Older versions are rejected.
|
|
127
138
|
this.#requireVersion(criterion, type, condition, 'xpath-31');
|
|
128
|
-
|
|
139
|
+
met = this.#xpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
140
|
+
break;
|
|
129
141
|
default:
|
|
130
142
|
throw new _CriterionError.default(`Unknown criterion type "${type}"`, {
|
|
131
143
|
condition,
|
|
@@ -136,9 +148,15 @@ class CriterionEvaluator {
|
|
|
136
148
|
} catch (error) {
|
|
137
149
|
// Arazzo 1.1.0: a condition that cannot be evaluated MUST evaluate to fail.
|
|
138
150
|
// The structural checks throw a plain CriterionError and still propagate.
|
|
139
|
-
if (error instanceof _CriterionEvaluationError.default) return
|
|
151
|
+
if (error instanceof _CriterionEvaluationError.default) return {
|
|
152
|
+
met: false,
|
|
153
|
+
error
|
|
154
|
+
};
|
|
140
155
|
throw error;
|
|
141
156
|
}
|
|
157
|
+
return {
|
|
158
|
+
met
|
|
159
|
+
};
|
|
142
160
|
}
|
|
143
161
|
|
|
144
162
|
/**
|
|
@@ -20,6 +20,10 @@ import XPathCriterionEvaluator from "./XPathCriterionEvaluator.mjs";
|
|
|
20
20
|
* lenient evaluator).
|
|
21
21
|
* @public
|
|
22
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* The outcome of evaluating one criterion.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
23
27
|
/**
|
|
24
28
|
* Options for the CriterionEvaluator.
|
|
25
29
|
*
|
|
@@ -29,7 +33,7 @@ import XPathCriterionEvaluator from "./XPathCriterionEvaluator.mjs";
|
|
|
29
33
|
* @public
|
|
30
34
|
*/
|
|
31
35
|
/**
|
|
32
|
-
* Evaluates an Arazzo Criterion Object to a
|
|
36
|
+
* Evaluates an Arazzo Criterion Object to a {@link CriterionOutcome}.
|
|
33
37
|
*
|
|
34
38
|
* Dispatches on the criterion's `type` (defaulting to `simple` when omitted):
|
|
35
39
|
* - `simple` — evaluates the condition directly, resolving the runtime
|
|
@@ -49,12 +53,13 @@ import XPathCriterionEvaluator from "./XPathCriterionEvaluator.mjs";
|
|
|
49
53
|
* the 1.1.0 rule to every document, which accepts more but never evaluates a
|
|
50
54
|
* query under the wrong dialect.
|
|
51
55
|
*
|
|
52
|
-
* A condition that cannot be evaluated fails the criterion (`false`), as
|
|
56
|
+
* A condition that cannot be evaluated fails the criterion (`met: false`), as
|
|
53
57
|
* Arazzo 1.1.0 requires: a syntax error in the condition, a context the
|
|
54
58
|
* condition cannot apply to (non-XML data for `xpath`), or an XPath evaluation
|
|
55
59
|
* error. The type-specific evaluators report these as a
|
|
56
|
-
* {@link CriterionEvaluationError}, which this facade
|
|
57
|
-
*
|
|
60
|
+
* {@link CriterionEvaluationError}, which this facade returns as the
|
|
61
|
+
* outcome's `error` so the caller can report it; any other error they raise
|
|
62
|
+
* propagates. A criterion that is malformed as written still throws: a
|
|
58
63
|
* missing `condition`, an unknown or unreadable `type`, an unsupported
|
|
59
64
|
* expression `version`, or a `context` that is missing or not a runtime
|
|
60
65
|
* expression.
|
|
@@ -78,7 +83,8 @@ class CriterionEvaluator {
|
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
|
81
|
-
* Evaluates a criterion element, returning whether the condition is met
|
|
86
|
+
* Evaluates a criterion element, returning whether the condition is met and,
|
|
87
|
+
* when it cannot be evaluated, why.
|
|
82
88
|
*
|
|
83
89
|
* `resolve` turns a runtime expression into a value: for `simple` it resolves
|
|
84
90
|
* the expressions embedded in the condition; for the other types it resolves
|
|
@@ -100,23 +106,28 @@ class CriterionEvaluator {
|
|
|
100
106
|
}
|
|
101
107
|
const type = this.#resolveType(criterion);
|
|
102
108
|
this.#requireValidContext(criterion, type);
|
|
109
|
+
let met;
|
|
103
110
|
try {
|
|
104
111
|
switch (type) {
|
|
105
112
|
case 'simple':
|
|
106
|
-
|
|
113
|
+
met = this.#simple.evaluate(condition, resolve);
|
|
114
|
+
break;
|
|
107
115
|
case 'regex':
|
|
108
|
-
|
|
116
|
+
met = this.#regex.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
117
|
+
break;
|
|
109
118
|
case 'jsonpath':
|
|
110
119
|
// only rfc9535 is supported, Arazzo 1.1.0's default, so an omitted
|
|
111
120
|
// version is accepted. draft-goessner has different semantics and is
|
|
112
121
|
// rejected rather than mis-evaluated.
|
|
113
122
|
this.#requireVersion(criterion, type, condition, 'rfc9535');
|
|
114
|
-
|
|
123
|
+
met = this.#jsonpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
124
|
+
break;
|
|
115
125
|
case 'xpath':
|
|
116
126
|
// only XPath 3.1 is supported; xpath-31 is Arazzo 1.1.0's default, so
|
|
117
127
|
// an omitted version is accepted. Older versions are rejected.
|
|
118
128
|
this.#requireVersion(criterion, type, condition, 'xpath-31');
|
|
119
|
-
|
|
129
|
+
met = this.#xpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
130
|
+
break;
|
|
120
131
|
default:
|
|
121
132
|
throw new CriterionError(`Unknown criterion type "${type}"`, {
|
|
122
133
|
condition,
|
|
@@ -127,9 +138,15 @@ class CriterionEvaluator {
|
|
|
127
138
|
} catch (error) {
|
|
128
139
|
// Arazzo 1.1.0: a condition that cannot be evaluated MUST evaluate to fail.
|
|
129
140
|
// The structural checks throw a plain CriterionError and still propagate.
|
|
130
|
-
if (error instanceof CriterionEvaluationError) return
|
|
141
|
+
if (error instanceof CriterionEvaluationError) return {
|
|
142
|
+
met: false,
|
|
143
|
+
error
|
|
144
|
+
};
|
|
131
145
|
throw error;
|
|
132
146
|
}
|
|
147
|
+
return {
|
|
148
|
+
met
|
|
149
|
+
};
|
|
133
150
|
}
|
|
134
151
|
|
|
135
152
|
/**
|
|
@@ -34,7 +34,10 @@ class JSONPathCriterionEvaluator {
|
|
|
34
34
|
return (0, _jsonpath.evaluate)(context, condition).length > 0;
|
|
35
35
|
} catch (error) {
|
|
36
36
|
if (error instanceof _jsonpath.JSONPathError) {
|
|
37
|
-
|
|
37
|
+
// a parse error describes the query only; an evaluation error ran
|
|
38
|
+
// against the context, so its message is not surfaced.
|
|
39
|
+
const detail = error instanceof _jsonpath.JSONPathParseError ? `: ${error.message}` : '';
|
|
40
|
+
throw new _CriterionEvaluationError.default(`Invalid jsonpath criterion condition "${condition}"${detail}`, {
|
|
38
41
|
cause: error,
|
|
39
42
|
condition,
|
|
40
43
|
type: 'jsonpath',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { evaluate as evaluateJSONPath, JSONPathError } from '@swaggerexpert/jsonpath';
|
|
1
|
+
import { evaluate as evaluateJSONPath, JSONPathError, JSONPathParseError } from '@swaggerexpert/jsonpath';
|
|
2
2
|
import CriterionEvaluationError from "../errors/CriterionEvaluationError.mjs";
|
|
3
3
|
import CriterionErrorReason from "./CriterionErrorReason.mjs";
|
|
4
4
|
/**
|
|
@@ -27,7 +27,10 @@ class JSONPathCriterionEvaluator {
|
|
|
27
27
|
return evaluateJSONPath(context, condition).length > 0;
|
|
28
28
|
} catch (error) {
|
|
29
29
|
if (error instanceof JSONPathError) {
|
|
30
|
-
|
|
30
|
+
// a parse error describes the query only; an evaluation error ran
|
|
31
|
+
// against the context, so its message is not surfaced.
|
|
32
|
+
const detail = error instanceof JSONPathParseError ? `: ${error.message}` : '';
|
|
33
|
+
throw new CriterionEvaluationError(`Invalid jsonpath criterion condition "${condition}"${detail}`, {
|
|
31
34
|
cause: error,
|
|
32
35
|
condition,
|
|
33
36
|
type: 'jsonpath',
|
|
@@ -43,7 +43,9 @@ class RegexCriterionEvaluator {
|
|
|
43
43
|
try {
|
|
44
44
|
regExp = new RegExp(condition);
|
|
45
45
|
} catch (error) {
|
|
46
|
-
|
|
46
|
+
// the engine has seen only the pattern, never the context, so its
|
|
47
|
+
// message is safe to surface.
|
|
48
|
+
throw new _CriterionEvaluationError.default(`Invalid regex criterion condition "${condition}": ${error.message}`, {
|
|
47
49
|
cause: error,
|
|
48
50
|
condition,
|
|
49
51
|
type: 'regex',
|
|
@@ -36,7 +36,9 @@ class RegexCriterionEvaluator {
|
|
|
36
36
|
try {
|
|
37
37
|
regExp = new RegExp(condition);
|
|
38
38
|
} catch (error) {
|
|
39
|
-
|
|
39
|
+
// the engine has seen only the pattern, never the context, so its
|
|
40
|
+
// message is safe to surface.
|
|
41
|
+
throw new CriterionEvaluationError(`Invalid regex criterion condition "${condition}": ${error.message}`, {
|
|
40
42
|
cause: error,
|
|
41
43
|
condition,
|
|
42
44
|
type: 'regex',
|
|
@@ -48,6 +48,9 @@ class XPathCriterionEvaluator {
|
|
|
48
48
|
language: evaluateXPath.XPATH_3_1_LANGUAGE
|
|
49
49
|
});
|
|
50
50
|
} catch (error) {
|
|
51
|
+
// no engine detail: the query has run against the context, and it can
|
|
52
|
+
// put context values into its own error (a dynamic error, or fn:error
|
|
53
|
+
// with a code and description of the query's choosing).
|
|
51
54
|
throw new _CriterionEvaluationError.default(`Invalid xpath criterion condition "${condition}"`, {
|
|
52
55
|
cause: error,
|
|
53
56
|
condition,
|
|
@@ -40,6 +40,9 @@ class XPathCriterionEvaluator {
|
|
|
40
40
|
language: evaluateXPath.XPATH_3_1_LANGUAGE
|
|
41
41
|
});
|
|
42
42
|
} catch (error) {
|
|
43
|
+
// no engine detail: the query has run against the context, and it can
|
|
44
|
+
// put context values into its own error (a dynamic error, or fn:error
|
|
45
|
+
// with a code and description of the query's choosing).
|
|
43
46
|
throw new CriterionEvaluationError(`Invalid xpath criterion condition "${condition}"`, {
|
|
44
47
|
cause: error,
|
|
45
48
|
condition,
|
|
@@ -44,6 +44,12 @@ const STEP_TARGET_FIELDS = exports.STEP_TARGET_FIELDS = ['operationId', 'operati
|
|
|
44
44
|
* @public
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* The outcome of one criterion a step evaluated: one of its `successCriteria`,
|
|
49
|
+
* or one of the `criteria` of an action it considered.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
|
|
47
53
|
/**
|
|
48
54
|
* The outcome of executing a single step.
|
|
49
55
|
* @public
|
|
@@ -190,16 +196,22 @@ class StepExecutor {
|
|
|
190
196
|
// evaluate criteria, outputs, and the next action against the post-request
|
|
191
197
|
// context (with $request / $url / $method and $response / $statusCode).
|
|
192
198
|
const postContext = state.toContext(this.#requestContext(response), this.#responseContext(response));
|
|
193
|
-
const
|
|
199
|
+
const successCriteria = this.evaluateCriteria(step, postContext);
|
|
200
|
+
const successful = successCriteria.every(criterion => criterion.met);
|
|
194
201
|
const outputs = this.#outputResolver.resolve(step.outputs, expression => this.#evaluate(postContext, expression), scope);
|
|
195
|
-
const
|
|
202
|
+
const {
|
|
203
|
+
matchedActions,
|
|
204
|
+
actionCriteria
|
|
205
|
+
} = this.selectActions(step, successful, postContext);
|
|
196
206
|
return {
|
|
197
207
|
stepId,
|
|
198
208
|
response,
|
|
199
209
|
successful,
|
|
200
210
|
outputs,
|
|
201
211
|
action: matchedActions[0],
|
|
202
|
-
matchedActions
|
|
212
|
+
matchedActions,
|
|
213
|
+
successCriteria,
|
|
214
|
+
actionCriteria
|
|
203
215
|
};
|
|
204
216
|
}
|
|
205
217
|
|
|
@@ -272,9 +284,12 @@ class StepExecutor {
|
|
|
272
284
|
}
|
|
273
285
|
|
|
274
286
|
/**
|
|
275
|
-
* Evaluates the step's `successCriteria
|
|
276
|
-
*
|
|
277
|
-
*
|
|
287
|
+
* Evaluates the step's `successCriteria`, returning one record per criterion
|
|
288
|
+
* in list order; the step succeeds when every record is met. Every criterion
|
|
289
|
+
* is evaluated, so the records explain each unmet one, not only the first. A
|
|
290
|
+
* step with no criteria returns no records and succeeds on a received
|
|
291
|
+
* response. An unreadable `successCriteria` throws, see
|
|
292
|
+
* {@link StepExecutor.assertSuccessCriteria}.
|
|
278
293
|
*
|
|
279
294
|
* Public for the same reason as {@link StepExecutor.selectActions}: a step
|
|
280
295
|
* targeting a `workflowId` is run by the workflow executor and never reaches
|
|
@@ -284,15 +299,16 @@ class StepExecutor {
|
|
|
284
299
|
evaluateCriteria(step, context) {
|
|
285
300
|
this.assertSuccessCriteria(step);
|
|
286
301
|
const criteria = step.successCriteria;
|
|
287
|
-
if (criteria === undefined) return
|
|
302
|
+
if (criteria === undefined) return [];
|
|
288
303
|
|
|
289
304
|
// assertSuccessCriteria above guarantees every entry is a Criterion Object
|
|
290
|
-
return [...criteria].
|
|
305
|
+
return [...criteria].map(criterion => this.#evaluateCriterion(criterion, context));
|
|
291
306
|
}
|
|
292
307
|
|
|
293
308
|
/**
|
|
294
309
|
* Selects every matching `onSuccess` / `onFailure` action for the outcome, in
|
|
295
|
-
* list order, gating each action's criteria against the context
|
|
310
|
+
* list order, gating each action's criteria against the context, and records
|
|
311
|
+
* the outcome of every action criterion evaluated.
|
|
296
312
|
*
|
|
297
313
|
* The step's own list is the whole story here: a step that declares none of
|
|
298
314
|
* its own already carries the workflow-level defaults, inherited by
|
|
@@ -311,25 +327,65 @@ class StepExecutor {
|
|
|
311
327
|
* the expression context through this one method rather than wiring their own.
|
|
312
328
|
*/
|
|
313
329
|
selectActions(step, successful, context) {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
// abort over a default written for the operation steps.
|
|
323
|
-
if (error instanceof _RuntimeExpressionError.default && error.reason === 'unavailable-expression') {
|
|
324
|
-
return false;
|
|
325
|
-
}
|
|
326
|
-
throw error;
|
|
327
|
-
}
|
|
330
|
+
const actionCriteria = [];
|
|
331
|
+
const isCriterionMet = (criterion, action) => {
|
|
332
|
+
const record = {
|
|
333
|
+
...this.#evaluateCriterion(criterion, context),
|
|
334
|
+
actionName: (0, _apidomCore.toValue)(action.name)
|
|
335
|
+
};
|
|
336
|
+
actionCriteria.push(record);
|
|
337
|
+
return record.met;
|
|
328
338
|
};
|
|
329
339
|
const scope = {
|
|
330
340
|
stepId: (0, _apidomCore.toValue)(step.stepId)
|
|
331
341
|
};
|
|
332
|
-
|
|
342
|
+
const matchedActions = successful ? this.#actionResolver.resolveOnSuccess(step.onSuccess, isCriterionMet, scope) : this.#actionResolver.resolveOnFailure(step.onFailure, isCriterionMet, scope);
|
|
343
|
+
return {
|
|
344
|
+
matchedActions,
|
|
345
|
+
actionCriteria
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Evaluates one criterion into a {@link CriterionEvaluationRecord}. A
|
|
351
|
+
* condition that cannot be evaluated is unmet and records why; any other
|
|
352
|
+
* error propagates.
|
|
353
|
+
*/
|
|
354
|
+
#evaluateCriterion(criterion, context) {
|
|
355
|
+
const condition = (0, _apidomCore.toValue)(criterion.condition);
|
|
356
|
+
try {
|
|
357
|
+
const {
|
|
358
|
+
met,
|
|
359
|
+
error
|
|
360
|
+
} = this.#criterionEvaluator.evaluate(criterion, expression => this.#evaluate(context, expression));
|
|
361
|
+
if (error === undefined) return {
|
|
362
|
+
condition,
|
|
363
|
+
met
|
|
364
|
+
};
|
|
365
|
+
return {
|
|
366
|
+
condition,
|
|
367
|
+
met,
|
|
368
|
+
diagnostic: {
|
|
369
|
+
code: error.reason,
|
|
370
|
+
message: error.message
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
} catch (error) {
|
|
374
|
+
// a step that calls a workflow made no HTTP call, so a condition on one
|
|
375
|
+
// fails like any unevaluable condition; the diagnostic keeps the
|
|
376
|
+
// authoring mistake visible.
|
|
377
|
+
if (error instanceof _RuntimeExpressionError.default && error.reason === 'unavailable-expression') {
|
|
378
|
+
return {
|
|
379
|
+
condition,
|
|
380
|
+
met: false,
|
|
381
|
+
diagnostic: {
|
|
382
|
+
code: error.reason,
|
|
383
|
+
message: error.message
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
333
389
|
}
|
|
334
390
|
|
|
335
391
|
/**
|