@usearazzo/runner 1.0.1-alpha.20 → 1.0.1-alpha.22
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 +25 -0
- package/README.md +2 -2
- package/dist/arazzo-runner.browser.js +2750 -412
- package/dist/arazzo-runner.browser.min.js +1 -1
- package/package.json +5 -5
- 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/ArazzoWorkflowLocatorNormalizer.cjs +18 -7
- package/src/executor/ArazzoWorkflowLocatorNormalizer.mjs +18 -7
- package/src/executor/StepExecutor.cjs +90 -24
- package/src/executor/StepExecutor.mjs +90 -24
- package/src/executor/StepRetryRunner.cjs +0 -10
- package/src/executor/StepRetryRunner.mjs +0 -9
- package/src/executor/WorkflowExecutor.cjs +20 -23
- package/src/executor/WorkflowExecutor.mjs +20 -23
- package/src/vendor/swagger-client.cjs +1 -1
- package/src/vendor/swagger-client.mjs +1 -1
- package/types/runner.d.ts +107 -21
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.22",
|
|
4
4
|
"description": "Runner for Arazzo Workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arazzo",
|
|
@@ -69,12 +69,12 @@
|
|
|
69
69
|
"@speclynx/apidom-traverse": "^6.1.2",
|
|
70
70
|
"@swaggerexpert/arazzo-criterion": "^1.0.1",
|
|
71
71
|
"@swaggerexpert/arazzo-runtime-expression": "^3.3.0",
|
|
72
|
-
"@swaggerexpert/cookie": "^2.
|
|
72
|
+
"@swaggerexpert/cookie": "^2.1.1",
|
|
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.22",
|
|
77
|
+
"@usearazzo/resolver": "1.0.1-alpha.22",
|
|
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": "e70dedbb2d249b9a6c16808048d9272609103f71"
|
|
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,
|
|
@@ -52,11 +52,12 @@ var _SourceDescriptionsLocatorNormalizer = _interopRequireDefault(require("./Sou
|
|
|
52
52
|
* The `type` declared on a source description is not trusted (it may be
|
|
53
53
|
* absent or wrong); a source is classified by what it actually parses to,
|
|
54
54
|
* the same convention the OpenAPI operation locator follows. Source
|
|
55
|
-
* documents are acquired from the registry on demand.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
55
|
+
* documents are acquired from the registry on demand. A reference to a
|
|
56
|
+
* workflow the resolved document does not define is rejected here, so every
|
|
57
|
+
* returned locator names an existing workflow; a caller controls when that
|
|
58
|
+
* check happens by when it normalizes (eagerly for a `dependsOn` list
|
|
59
|
+
* validated before any prerequisite runs, lazily for a sub-workflow step
|
|
60
|
+
* resolved on its first attempt).
|
|
60
61
|
* @public
|
|
61
62
|
*/
|
|
62
63
|
class ArazzoWorkflowLocatorNormalizer extends _SourceDescriptionsLocatorNormalizer.default {
|
|
@@ -64,10 +65,20 @@ class ArazzoWorkflowLocatorNormalizer extends _SourceDescriptionsLocatorNormaliz
|
|
|
64
65
|
* Resolves a reference — a plain workflowId or a
|
|
65
66
|
* `$sourceDescriptions.{name}.{workflowId}` expression, as written — to the
|
|
66
67
|
* canonical locator: the Arazzo document that owns the target workflow,
|
|
67
|
-
* and the bare id within it.
|
|
68
|
+
* and the bare id within it. Rejects a workflow that document does not
|
|
69
|
+
* define as `workflow-not-found`, attributed to the referencing context
|
|
70
|
+
* like every other error raised here.
|
|
68
71
|
*/
|
|
69
72
|
async normalize(reference, document, context) {
|
|
70
|
-
|
|
73
|
+
const locator = await this.#resolve(this.#parseReference(reference, context), document, context);
|
|
74
|
+
if (!locator.document.workflowIndex.has(locator.workflowId)) {
|
|
75
|
+
throw new _ExecutionError.default(`workflow reference "${reference}" in workflow "${context.workflowId}" names workflow "${locator.workflowId}", which the Arazzo document at "${locator.document.uri}" does not define`, {
|
|
76
|
+
workflowId: context.workflowId,
|
|
77
|
+
stepId: context.stepId,
|
|
78
|
+
reason: 'workflow-not-found'
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return locator;
|
|
71
82
|
}
|
|
72
83
|
|
|
73
84
|
/**
|
|
@@ -42,11 +42,12 @@ import SourceDescriptionsLocatorNormalizer from "./SourceDescriptionsLocatorNorm
|
|
|
42
42
|
* The `type` declared on a source description is not trusted (it may be
|
|
43
43
|
* absent or wrong); a source is classified by what it actually parses to,
|
|
44
44
|
* the same convention the OpenAPI operation locator follows. Source
|
|
45
|
-
* documents are acquired from the registry on demand.
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
45
|
+
* documents are acquired from the registry on demand. A reference to a
|
|
46
|
+
* workflow the resolved document does not define is rejected here, so every
|
|
47
|
+
* returned locator names an existing workflow; a caller controls when that
|
|
48
|
+
* check happens by when it normalizes (eagerly for a `dependsOn` list
|
|
49
|
+
* validated before any prerequisite runs, lazily for a sub-workflow step
|
|
50
|
+
* resolved on its first attempt).
|
|
50
51
|
* @public
|
|
51
52
|
*/
|
|
52
53
|
class ArazzoWorkflowLocatorNormalizer extends SourceDescriptionsLocatorNormalizer {
|
|
@@ -54,10 +55,20 @@ class ArazzoWorkflowLocatorNormalizer extends SourceDescriptionsLocatorNormalize
|
|
|
54
55
|
* Resolves a reference — a plain workflowId or a
|
|
55
56
|
* `$sourceDescriptions.{name}.{workflowId}` expression, as written — to the
|
|
56
57
|
* canonical locator: the Arazzo document that owns the target workflow,
|
|
57
|
-
* and the bare id within it.
|
|
58
|
+
* and the bare id within it. Rejects a workflow that document does not
|
|
59
|
+
* define as `workflow-not-found`, attributed to the referencing context
|
|
60
|
+
* like every other error raised here.
|
|
58
61
|
*/
|
|
59
62
|
async normalize(reference, document, context) {
|
|
60
|
-
|
|
63
|
+
const locator = await this.#resolve(this.#parseReference(reference, context), document, context);
|
|
64
|
+
if (!locator.document.workflowIndex.has(locator.workflowId)) {
|
|
65
|
+
throw new ExecutionError(`workflow reference "${reference}" in workflow "${context.workflowId}" names workflow "${locator.workflowId}", which the Arazzo document at "${locator.document.uri}" does not define`, {
|
|
66
|
+
workflowId: context.workflowId,
|
|
67
|
+
stepId: context.stepId,
|
|
68
|
+
reason: 'workflow-not-found'
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return locator;
|
|
61
72
|
}
|
|
62
73
|
|
|
63
74
|
/**
|
|
@@ -44,11 +44,27 @@ 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
|
|
50
56
|
*/
|
|
51
57
|
|
|
58
|
+
/**
|
|
59
|
+
* What one attempt at a step produced.
|
|
60
|
+
*
|
|
61
|
+
* Both kinds of step reduce to this — an operation step (whose richer
|
|
62
|
+
* {@link StepExecutionResult} satisfies this shape) and a sub-workflow step
|
|
63
|
+
* (synthesized from the sub-run's outcome) — so the retry loop drives them
|
|
64
|
+
* identically and knows nothing about either.
|
|
65
|
+
* @internal
|
|
66
|
+
*/
|
|
67
|
+
|
|
52
68
|
/**
|
|
53
69
|
* Executes a single Arazzo step that invokes an OpenAPI operation.
|
|
54
70
|
*
|
|
@@ -190,16 +206,22 @@ class StepExecutor {
|
|
|
190
206
|
// evaluate criteria, outputs, and the next action against the post-request
|
|
191
207
|
// context (with $request / $url / $method and $response / $statusCode).
|
|
192
208
|
const postContext = state.toContext(this.#requestContext(response), this.#responseContext(response));
|
|
193
|
-
const
|
|
209
|
+
const successCriteria = this.evaluateCriteria(step, postContext);
|
|
210
|
+
const successful = successCriteria.every(criterion => criterion.met);
|
|
194
211
|
const outputs = this.#outputResolver.resolve(step.outputs, expression => this.#evaluate(postContext, expression), scope);
|
|
195
|
-
const
|
|
212
|
+
const {
|
|
213
|
+
matchedActions,
|
|
214
|
+
actionCriteria
|
|
215
|
+
} = this.selectActions(step, successful, postContext);
|
|
196
216
|
return {
|
|
197
217
|
stepId,
|
|
198
218
|
response,
|
|
199
219
|
successful,
|
|
200
220
|
outputs,
|
|
201
221
|
action: matchedActions[0],
|
|
202
|
-
matchedActions
|
|
222
|
+
matchedActions,
|
|
223
|
+
successCriteria,
|
|
224
|
+
actionCriteria
|
|
203
225
|
};
|
|
204
226
|
}
|
|
205
227
|
|
|
@@ -272,9 +294,12 @@ class StepExecutor {
|
|
|
272
294
|
}
|
|
273
295
|
|
|
274
296
|
/**
|
|
275
|
-
* Evaluates the step's `successCriteria
|
|
276
|
-
*
|
|
277
|
-
*
|
|
297
|
+
* Evaluates the step's `successCriteria`, returning one record per criterion
|
|
298
|
+
* in list order; the step succeeds when every record is met. Every criterion
|
|
299
|
+
* is evaluated, so the records explain each unmet one, not only the first. A
|
|
300
|
+
* step with no criteria returns no records and succeeds on a received
|
|
301
|
+
* response. An unreadable `successCriteria` throws, see
|
|
302
|
+
* {@link StepExecutor.assertSuccessCriteria}.
|
|
278
303
|
*
|
|
279
304
|
* Public for the same reason as {@link StepExecutor.selectActions}: a step
|
|
280
305
|
* targeting a `workflowId` is run by the workflow executor and never reaches
|
|
@@ -284,15 +309,16 @@ class StepExecutor {
|
|
|
284
309
|
evaluateCriteria(step, context) {
|
|
285
310
|
this.assertSuccessCriteria(step);
|
|
286
311
|
const criteria = step.successCriteria;
|
|
287
|
-
if (criteria === undefined) return
|
|
312
|
+
if (criteria === undefined) return [];
|
|
288
313
|
|
|
289
314
|
// assertSuccessCriteria above guarantees every entry is a Criterion Object
|
|
290
|
-
return [...criteria].
|
|
315
|
+
return [...criteria].map(criterion => this.#evaluateCriterion(criterion, context));
|
|
291
316
|
}
|
|
292
317
|
|
|
293
318
|
/**
|
|
294
319
|
* Selects every matching `onSuccess` / `onFailure` action for the outcome, in
|
|
295
|
-
* list order, gating each action's criteria against the context
|
|
320
|
+
* list order, gating each action's criteria against the context, and records
|
|
321
|
+
* the outcome of every action criterion evaluated.
|
|
296
322
|
*
|
|
297
323
|
* The step's own list is the whole story here: a step that declares none of
|
|
298
324
|
* its own already carries the workflow-level defaults, inherited by
|
|
@@ -311,25 +337,65 @@ class StepExecutor {
|
|
|
311
337
|
* the expression context through this one method rather than wiring their own.
|
|
312
338
|
*/
|
|
313
339
|
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
|
-
}
|
|
340
|
+
const actionCriteria = [];
|
|
341
|
+
const isCriterionMet = (criterion, action) => {
|
|
342
|
+
const record = {
|
|
343
|
+
...this.#evaluateCriterion(criterion, context),
|
|
344
|
+
actionName: (0, _apidomCore.toValue)(action.name)
|
|
345
|
+
};
|
|
346
|
+
actionCriteria.push(record);
|
|
347
|
+
return record.met;
|
|
328
348
|
};
|
|
329
349
|
const scope = {
|
|
330
350
|
stepId: (0, _apidomCore.toValue)(step.stepId)
|
|
331
351
|
};
|
|
332
|
-
|
|
352
|
+
const matchedActions = successful ? this.#actionResolver.resolveOnSuccess(step.onSuccess, isCriterionMet, scope) : this.#actionResolver.resolveOnFailure(step.onFailure, isCriterionMet, scope);
|
|
353
|
+
return {
|
|
354
|
+
matchedActions,
|
|
355
|
+
actionCriteria
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Evaluates one criterion into a {@link CriterionEvaluationRecord}. A
|
|
361
|
+
* condition that cannot be evaluated is unmet and records why; any other
|
|
362
|
+
* error propagates.
|
|
363
|
+
*/
|
|
364
|
+
#evaluateCriterion(criterion, context) {
|
|
365
|
+
const condition = (0, _apidomCore.toValue)(criterion.condition);
|
|
366
|
+
try {
|
|
367
|
+
const {
|
|
368
|
+
met,
|
|
369
|
+
error
|
|
370
|
+
} = this.#criterionEvaluator.evaluate(criterion, expression => this.#evaluate(context, expression));
|
|
371
|
+
if (error === undefined) return {
|
|
372
|
+
condition,
|
|
373
|
+
met
|
|
374
|
+
};
|
|
375
|
+
return {
|
|
376
|
+
condition,
|
|
377
|
+
met,
|
|
378
|
+
diagnostic: {
|
|
379
|
+
code: error.reason,
|
|
380
|
+
message: error.message
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
} catch (error) {
|
|
384
|
+
// a step that calls a workflow made no HTTP call, so a condition on one
|
|
385
|
+
// fails like any unevaluable condition; the diagnostic keeps the
|
|
386
|
+
// authoring mistake visible.
|
|
387
|
+
if (error instanceof _RuntimeExpressionError.default && error.reason === 'unavailable-expression') {
|
|
388
|
+
return {
|
|
389
|
+
condition,
|
|
390
|
+
met: false,
|
|
391
|
+
diagnostic: {
|
|
392
|
+
code: error.reason,
|
|
393
|
+
message: error.message
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
333
399
|
}
|
|
334
400
|
|
|
335
401
|
/**
|