@usearazzo/runner 1.0.1-alpha.19 → 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 +31 -0
- package/README.md +2 -2
- package/dist/arazzo-runner.browser.js +376 -156
- 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/CriterionErrorReason.cjs +51 -0
- package/src/criterion/CriterionErrorReason.mjs +46 -0
- package/src/criterion/CriterionEvaluator.cjs +83 -38
- package/src/criterion/CriterionEvaluator.mjs +82 -38
- package/src/criterion/JSONPathCriterionEvaluator.cjs +8 -4
- package/src/criterion/JSONPathCriterionEvaluator.mjs +9 -5
- package/src/criterion/RegexCriterionEvaluator.cjs +7 -4
- package/src/criterion/RegexCriterionEvaluator.mjs +7 -4
- package/src/criterion/SimpleCriterionEvaluator.cjs +5 -4
- package/src/criterion/SimpleCriterionEvaluator.mjs +5 -4
- package/src/criterion/XPathCriterionEvaluator.cjs +16 -12
- package/src/criterion/XPathCriterionEvaluator.mjs +16 -12
- package/src/errors/CriterionEvaluationError.cjs +18 -0
- package/src/errors/CriterionEvaluationError.mjs +11 -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/src/index.cjs +14 -0
- package/src/index.mjs +2 -0
- package/types/runner.d.ts +180 -22
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;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* The `reason` a {@link CriterionError} carries.
|
|
9
|
+
*
|
|
10
|
+
* Structural reasons mark a criterion that is malformed as written; they are
|
|
11
|
+
* thrown as a plain `CriterionError`. Evaluation reasons (`InvalidSimple`,
|
|
12
|
+
* `InvalidRegex`, `InvalidJSONPath`, `InvalidXPath`, `InvalidXPathContext`) mark
|
|
13
|
+
* a condition that cannot be evaluated; they are thrown as a
|
|
14
|
+
* {@link CriterionEvaluationError}, which `CriterionEvaluator` turns into an
|
|
15
|
+
* unmet criterion.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
const CriterionErrorReason = {
|
|
19
|
+
/** The element is not a Criterion Object. */
|
|
20
|
+
InvalidCriterion: 'invalid-criterion',
|
|
21
|
+
/** The `condition` is missing or empty. */
|
|
22
|
+
MissingCondition: 'missing-condition',
|
|
23
|
+
/** The `type` is present but unreadable. */
|
|
24
|
+
InvalidType: 'invalid-type',
|
|
25
|
+
/** The `type` names no known criterion type. */
|
|
26
|
+
UnknownType: 'unknown-type',
|
|
27
|
+
/** The expression type `version` is present but not a string. */
|
|
28
|
+
InvalidVersion: 'invalid-version',
|
|
29
|
+
/** The expression type `version` is not the one this runner supports. */
|
|
30
|
+
UnsupportedVersion: 'unsupported-version',
|
|
31
|
+
/** The `context` is not a runtime expression. */
|
|
32
|
+
InvalidContext: 'invalid-context',
|
|
33
|
+
/** A `regex`, `jsonpath` or `xpath` criterion has no `context`. */
|
|
34
|
+
MissingContext: 'missing-context',
|
|
35
|
+
/** The `simple` condition cannot be parsed. */
|
|
36
|
+
InvalidSimple: 'invalid-simple',
|
|
37
|
+
/** The `regex` condition is not a valid regular expression. */
|
|
38
|
+
InvalidRegex: 'invalid-regex',
|
|
39
|
+
/** The `jsonpath` condition is not a valid JSONPath query. */
|
|
40
|
+
InvalidJSONPath: 'invalid-jsonpath',
|
|
41
|
+
/** The `xpath` condition is invalid or fails to evaluate. */
|
|
42
|
+
InvalidXPath: 'invalid-xpath',
|
|
43
|
+
/** The resolved `xpath` context is not XML. */
|
|
44
|
+
InvalidXPathContext: 'invalid-xpath-context'
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* One of the `CriterionErrorReason` values.
|
|
49
|
+
* @public
|
|
50
|
+
*/
|
|
51
|
+
var _default = exports.default = CriterionErrorReason;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `reason` a {@link CriterionError} carries.
|
|
3
|
+
*
|
|
4
|
+
* Structural reasons mark a criterion that is malformed as written; they are
|
|
5
|
+
* thrown as a plain `CriterionError`. Evaluation reasons (`InvalidSimple`,
|
|
6
|
+
* `InvalidRegex`, `InvalidJSONPath`, `InvalidXPath`, `InvalidXPathContext`) mark
|
|
7
|
+
* a condition that cannot be evaluated; they are thrown as a
|
|
8
|
+
* {@link CriterionEvaluationError}, which `CriterionEvaluator` turns into an
|
|
9
|
+
* unmet criterion.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
const CriterionErrorReason = {
|
|
13
|
+
/** The element is not a Criterion Object. */
|
|
14
|
+
InvalidCriterion: 'invalid-criterion',
|
|
15
|
+
/** The `condition` is missing or empty. */
|
|
16
|
+
MissingCondition: 'missing-condition',
|
|
17
|
+
/** The `type` is present but unreadable. */
|
|
18
|
+
InvalidType: 'invalid-type',
|
|
19
|
+
/** The `type` names no known criterion type. */
|
|
20
|
+
UnknownType: 'unknown-type',
|
|
21
|
+
/** The expression type `version` is present but not a string. */
|
|
22
|
+
InvalidVersion: 'invalid-version',
|
|
23
|
+
/** The expression type `version` is not the one this runner supports. */
|
|
24
|
+
UnsupportedVersion: 'unsupported-version',
|
|
25
|
+
/** The `context` is not a runtime expression. */
|
|
26
|
+
InvalidContext: 'invalid-context',
|
|
27
|
+
/** A `regex`, `jsonpath` or `xpath` criterion has no `context`. */
|
|
28
|
+
MissingContext: 'missing-context',
|
|
29
|
+
/** The `simple` condition cannot be parsed. */
|
|
30
|
+
InvalidSimple: 'invalid-simple',
|
|
31
|
+
/** The `regex` condition is not a valid regular expression. */
|
|
32
|
+
InvalidRegex: 'invalid-regex',
|
|
33
|
+
/** The `jsonpath` condition is not a valid JSONPath query. */
|
|
34
|
+
InvalidJSONPath: 'invalid-jsonpath',
|
|
35
|
+
/** The `xpath` condition is invalid or fails to evaluate. */
|
|
36
|
+
InvalidXPath: 'invalid-xpath',
|
|
37
|
+
/** The resolved `xpath` context is not XML. */
|
|
38
|
+
InvalidXPathContext: 'invalid-xpath-context'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* One of the `CriterionErrorReason` values.
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
export default CriterionErrorReason;
|
|
@@ -10,6 +10,8 @@ var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
|
10
10
|
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
11
11
|
var _arazzoRuntimeExpression = require("@swaggerexpert/arazzo-runtime-expression");
|
|
12
12
|
var _CriterionError = _interopRequireDefault(require("../errors/CriterionError.cjs"));
|
|
13
|
+
var _CriterionEvaluationError = _interopRequireDefault(require("../errors/CriterionEvaluationError.cjs"));
|
|
14
|
+
var _CriterionErrorReason = _interopRequireDefault(require("./CriterionErrorReason.cjs"));
|
|
13
15
|
var _RegexCriterionEvaluator = _interopRequireDefault(require("./RegexCriterionEvaluator.cjs"));
|
|
14
16
|
var _SimpleCriterionEvaluator = _interopRequireDefault(require("./SimpleCriterionEvaluator.cjs"));
|
|
15
17
|
var _JSONPathCriterionEvaluator = _interopRequireDefault(require("./JSONPathCriterionEvaluator.cjs"));
|
|
@@ -26,13 +28,22 @@ var _XPathCriterionEvaluator = _interopRequireDefault(require("./XPathCriterionE
|
|
|
26
28
|
* @public
|
|
27
29
|
*/
|
|
28
30
|
|
|
31
|
+
/**
|
|
32
|
+
* The outcome of evaluating one criterion.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
|
|
29
36
|
/**
|
|
30
37
|
* Options for the CriterionEvaluator.
|
|
38
|
+
*
|
|
39
|
+
* An injected evaluator signals a condition it cannot evaluate by throwing a
|
|
40
|
+
* {@link CriterionEvaluationError}, which fails the criterion; any other error
|
|
41
|
+
* it throws, a plain {@link CriterionError} included, propagates.
|
|
31
42
|
* @public
|
|
32
43
|
*/
|
|
33
44
|
|
|
34
45
|
/**
|
|
35
|
-
* Evaluates an Arazzo Criterion Object to a
|
|
46
|
+
* Evaluates an Arazzo Criterion Object to a {@link CriterionOutcome}.
|
|
36
47
|
*
|
|
37
48
|
* Dispatches on the criterion's `type` (defaulting to `simple` when omitted):
|
|
38
49
|
* - `simple` — evaluates the condition directly, resolving the runtime
|
|
@@ -41,12 +52,27 @@ var _XPathCriterionEvaluator = _interopRequireDefault(require("./XPathCriterionE
|
|
|
41
52
|
* pattern to the resolved value.
|
|
42
53
|
* - `jsonpath` — resolves the `context` runtime expression, then applies the
|
|
43
54
|
* JSONPath query to the resolved value (met when the query matches). Only the
|
|
44
|
-
* `rfc9535` version is supported
|
|
45
|
-
* throws.
|
|
55
|
+
* `rfc9535` version is supported; an explicit other version throws.
|
|
46
56
|
* - `xpath` — resolves the `context` runtime expression, then applies the XPath
|
|
47
57
|
* 3.1 query to the resolved XML value (met by the Effective Boolean Value).
|
|
48
|
-
* Only the `xpath-31` version is supported
|
|
49
|
-
*
|
|
58
|
+
* Only the `xpath-31` version is supported; an explicit other version throws.
|
|
59
|
+
*
|
|
60
|
+
* Versions follow Arazzo 1.1.0's Expression Type Object: `rfc9535` and
|
|
61
|
+
* `xpath-31` are allowed values, and an omitted `version` defaults to them.
|
|
62
|
+
* Arazzo 1.0.x lists neither and requires `version`; this evaluator applies
|
|
63
|
+
* the 1.1.0 rule to every document, which accepts more but never evaluates a
|
|
64
|
+
* query under the wrong dialect.
|
|
65
|
+
*
|
|
66
|
+
* A condition that cannot be evaluated fails the criterion (`met: false`), as
|
|
67
|
+
* Arazzo 1.1.0 requires: a syntax error in the condition, a context the
|
|
68
|
+
* condition cannot apply to (non-XML data for `xpath`), or an XPath evaluation
|
|
69
|
+
* error. The type-specific evaluators report these as a
|
|
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
|
|
73
|
+
* missing `condition`, an unknown or unreadable `type`, an unsupported
|
|
74
|
+
* expression `version`, or a `context` that is missing or not a runtime
|
|
75
|
+
* expression.
|
|
50
76
|
*
|
|
51
77
|
* The evaluator is agnostic about how runtime expressions are resolved: the
|
|
52
78
|
* caller supplies a {@link CriterionContextResolver} per evaluation, keeping
|
|
@@ -67,7 +93,8 @@ class CriterionEvaluator {
|
|
|
67
93
|
}
|
|
68
94
|
|
|
69
95
|
/**
|
|
70
|
-
* 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.
|
|
71
98
|
*
|
|
72
99
|
* `resolve` turns a runtime expression into a value: for `simple` it resolves
|
|
73
100
|
* the expressions embedded in the condition; for the other types it resolves
|
|
@@ -76,7 +103,7 @@ class CriterionEvaluator {
|
|
|
76
103
|
evaluate(criterion, resolve) {
|
|
77
104
|
if (!(0, _apidomNsArazzo.isCriterionElement)(criterion)) {
|
|
78
105
|
throw new _CriterionError.default('Element is not a Criterion Object', {
|
|
79
|
-
reason:
|
|
106
|
+
reason: _CriterionErrorReason.default.InvalidCriterion
|
|
80
107
|
});
|
|
81
108
|
}
|
|
82
109
|
const condition = (0, _apidomDatamodel.isStringElement)(criterion.condition) ? (0, _apidomCore.toValue)(criterion.condition) : undefined;
|
|
@@ -84,34 +111,52 @@ class CriterionEvaluator {
|
|
|
84
111
|
// (e.g. an empty regex would match unconditionally), so reject it too.
|
|
85
112
|
if (condition === undefined || condition === '') {
|
|
86
113
|
throw new _CriterionError.default('Criterion is missing a "condition"', {
|
|
87
|
-
reason:
|
|
114
|
+
reason: _CriterionErrorReason.default.MissingCondition
|
|
88
115
|
});
|
|
89
116
|
}
|
|
90
117
|
const type = this.#resolveType(criterion);
|
|
91
118
|
this.#requireValidContext(criterion, type);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
type,
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
let met;
|
|
120
|
+
try {
|
|
121
|
+
switch (type) {
|
|
122
|
+
case 'simple':
|
|
123
|
+
met = this.#simple.evaluate(condition, resolve);
|
|
124
|
+
break;
|
|
125
|
+
case 'regex':
|
|
126
|
+
met = this.#regex.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
127
|
+
break;
|
|
128
|
+
case 'jsonpath':
|
|
129
|
+
// only rfc9535 is supported, Arazzo 1.1.0's default, so an omitted
|
|
130
|
+
// version is accepted. draft-goessner has different semantics and is
|
|
131
|
+
// rejected rather than mis-evaluated.
|
|
132
|
+
this.#requireVersion(criterion, type, condition, 'rfc9535');
|
|
133
|
+
met = this.#jsonpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
134
|
+
break;
|
|
135
|
+
case 'xpath':
|
|
136
|
+
// only XPath 3.1 is supported; xpath-31 is Arazzo 1.1.0's default, so
|
|
137
|
+
// an omitted version is accepted. Older versions are rejected.
|
|
138
|
+
this.#requireVersion(criterion, type, condition, 'xpath-31');
|
|
139
|
+
met = this.#xpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
140
|
+
break;
|
|
141
|
+
default:
|
|
142
|
+
throw new _CriterionError.default(`Unknown criterion type "${type}"`, {
|
|
143
|
+
condition,
|
|
144
|
+
type,
|
|
145
|
+
reason: _CriterionErrorReason.default.UnknownType
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
} catch (error) {
|
|
149
|
+
// Arazzo 1.1.0: a condition that cannot be evaluated MUST evaluate to fail.
|
|
150
|
+
// The structural checks throw a plain CriterionError and still propagate.
|
|
151
|
+
if (error instanceof _CriterionEvaluationError.default) return {
|
|
152
|
+
met: false,
|
|
153
|
+
error
|
|
154
|
+
};
|
|
155
|
+
throw error;
|
|
114
156
|
}
|
|
157
|
+
return {
|
|
158
|
+
met
|
|
159
|
+
};
|
|
115
160
|
}
|
|
116
161
|
|
|
117
162
|
/**
|
|
@@ -128,15 +173,15 @@ class CriterionEvaluator {
|
|
|
128
173
|
}
|
|
129
174
|
if ((0, _apidomDatamodel.isStringElement)(type)) return (0, _apidomCore.toValue)(type);
|
|
130
175
|
throw new _CriterionError.default('Criterion has an invalid "type"', {
|
|
131
|
-
reason:
|
|
176
|
+
reason: _CriterionErrorReason.default.InvalidType
|
|
132
177
|
});
|
|
133
178
|
}
|
|
134
179
|
|
|
135
180
|
/**
|
|
136
181
|
* Extracts the expression `version` from a Criterion Expression Type Object,
|
|
137
182
|
* or `undefined` when no version is declared (a bare-string `type`, or a type
|
|
138
|
-
* object without a `version`) — in which case
|
|
139
|
-
* applies. A `version` that is present but not a string is malformed and
|
|
183
|
+
* object without a `version`) — in which case Arazzo 1.1.0's default for the
|
|
184
|
+
* type applies. A `version` that is present but not a string is malformed and
|
|
140
185
|
* throws a {@link CriterionError} rather than silently defaulting.
|
|
141
186
|
*/
|
|
142
187
|
#resolveVersion(criterion) {
|
|
@@ -148,13 +193,13 @@ class CriterionEvaluator {
|
|
|
148
193
|
return (0, _apidomCore.toValue)(type.version);
|
|
149
194
|
}
|
|
150
195
|
throw new _CriterionError.default('Criterion has an invalid expression type "version"', {
|
|
151
|
-
reason:
|
|
196
|
+
reason: _CriterionErrorReason.default.InvalidVersion
|
|
152
197
|
});
|
|
153
198
|
}
|
|
154
199
|
|
|
155
200
|
/**
|
|
156
201
|
* Enforces that a versioned condition type declares only the one version this
|
|
157
|
-
* runner supports. An omitted version is accepted (
|
|
202
|
+
* runner supports. An omitted version is accepted (Arazzo 1.1.0's default);
|
|
158
203
|
* any other declared version throws a {@link CriterionError}.
|
|
159
204
|
*/
|
|
160
205
|
#requireVersion(criterion, type, condition, supported) {
|
|
@@ -163,7 +208,7 @@ class CriterionEvaluator {
|
|
|
163
208
|
throw new _CriterionError.default(`Unsupported ${type} version "${version}" (only ${supported})`, {
|
|
164
209
|
condition,
|
|
165
210
|
type,
|
|
166
|
-
reason:
|
|
211
|
+
reason: _CriterionErrorReason.default.UnsupportedVersion
|
|
167
212
|
});
|
|
168
213
|
}
|
|
169
214
|
}
|
|
@@ -181,7 +226,7 @@ class CriterionEvaluator {
|
|
|
181
226
|
if (!(0, _apidomDatamodel.isStringElement)(context) || !(0, _arazzoRuntimeExpression.test)((0, _apidomCore.toValue)(context))) {
|
|
182
227
|
throw new _CriterionError.default('Criterion has a "context" that is not a valid runtime expression', {
|
|
183
228
|
type,
|
|
184
|
-
reason:
|
|
229
|
+
reason: _CriterionErrorReason.default.InvalidContext
|
|
185
230
|
});
|
|
186
231
|
}
|
|
187
232
|
}
|
|
@@ -196,7 +241,7 @@ class CriterionEvaluator {
|
|
|
196
241
|
if (!(0, _apidomDatamodel.isStringElement)(criterion.context)) {
|
|
197
242
|
throw new _CriterionError.default(`Criterion type "${type}" requires a "context"`, {
|
|
198
243
|
type,
|
|
199
|
-
reason:
|
|
244
|
+
reason: _CriterionErrorReason.default.MissingContext
|
|
200
245
|
});
|
|
201
246
|
}
|
|
202
247
|
return resolve((0, _apidomCore.toValue)(criterion.context));
|
|
@@ -3,6 +3,8 @@ import { isStringElement } from '@speclynx/apidom-datamodel';
|
|
|
3
3
|
import { isCriterionElement, isCriterionExpressionTypeElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
4
4
|
import { test as isRuntimeExpression } from '@swaggerexpert/arazzo-runtime-expression';
|
|
5
5
|
import CriterionError from "../errors/CriterionError.mjs";
|
|
6
|
+
import CriterionEvaluationError from "../errors/CriterionEvaluationError.mjs";
|
|
7
|
+
import CriterionErrorReason from "./CriterionErrorReason.mjs";
|
|
6
8
|
import RegexCriterionEvaluator from "./RegexCriterionEvaluator.mjs";
|
|
7
9
|
import SimpleCriterionEvaluator from "./SimpleCriterionEvaluator.mjs";
|
|
8
10
|
import JSONPathCriterionEvaluator from "./JSONPathCriterionEvaluator.mjs";
|
|
@@ -18,12 +20,20 @@ import XPathCriterionEvaluator from "./XPathCriterionEvaluator.mjs";
|
|
|
18
20
|
* lenient evaluator).
|
|
19
21
|
* @public
|
|
20
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* The outcome of evaluating one criterion.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
21
27
|
/**
|
|
22
28
|
* Options for the CriterionEvaluator.
|
|
29
|
+
*
|
|
30
|
+
* An injected evaluator signals a condition it cannot evaluate by throwing a
|
|
31
|
+
* {@link CriterionEvaluationError}, which fails the criterion; any other error
|
|
32
|
+
* it throws, a plain {@link CriterionError} included, propagates.
|
|
23
33
|
* @public
|
|
24
34
|
*/
|
|
25
35
|
/**
|
|
26
|
-
* Evaluates an Arazzo Criterion Object to a
|
|
36
|
+
* Evaluates an Arazzo Criterion Object to a {@link CriterionOutcome}.
|
|
27
37
|
*
|
|
28
38
|
* Dispatches on the criterion's `type` (defaulting to `simple` when omitted):
|
|
29
39
|
* - `simple` — evaluates the condition directly, resolving the runtime
|
|
@@ -32,12 +42,27 @@ import XPathCriterionEvaluator from "./XPathCriterionEvaluator.mjs";
|
|
|
32
42
|
* pattern to the resolved value.
|
|
33
43
|
* - `jsonpath` — resolves the `context` runtime expression, then applies the
|
|
34
44
|
* JSONPath query to the resolved value (met when the query matches). Only the
|
|
35
|
-
* `rfc9535` version is supported
|
|
36
|
-
* throws.
|
|
45
|
+
* `rfc9535` version is supported; an explicit other version throws.
|
|
37
46
|
* - `xpath` — resolves the `context` runtime expression, then applies the XPath
|
|
38
47
|
* 3.1 query to the resolved XML value (met by the Effective Boolean Value).
|
|
39
|
-
* Only the `xpath-31` version is supported
|
|
40
|
-
*
|
|
48
|
+
* Only the `xpath-31` version is supported; an explicit other version throws.
|
|
49
|
+
*
|
|
50
|
+
* Versions follow Arazzo 1.1.0's Expression Type Object: `rfc9535` and
|
|
51
|
+
* `xpath-31` are allowed values, and an omitted `version` defaults to them.
|
|
52
|
+
* Arazzo 1.0.x lists neither and requires `version`; this evaluator applies
|
|
53
|
+
* the 1.1.0 rule to every document, which accepts more but never evaluates a
|
|
54
|
+
* query under the wrong dialect.
|
|
55
|
+
*
|
|
56
|
+
* A condition that cannot be evaluated fails the criterion (`met: false`), as
|
|
57
|
+
* Arazzo 1.1.0 requires: a syntax error in the condition, a context the
|
|
58
|
+
* condition cannot apply to (non-XML data for `xpath`), or an XPath evaluation
|
|
59
|
+
* error. The type-specific evaluators report these as a
|
|
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
|
|
63
|
+
* missing `condition`, an unknown or unreadable `type`, an unsupported
|
|
64
|
+
* expression `version`, or a `context` that is missing or not a runtime
|
|
65
|
+
* expression.
|
|
41
66
|
*
|
|
42
67
|
* The evaluator is agnostic about how runtime expressions are resolved: the
|
|
43
68
|
* caller supplies a {@link CriterionContextResolver} per evaluation, keeping
|
|
@@ -58,7 +83,8 @@ class CriterionEvaluator {
|
|
|
58
83
|
}
|
|
59
84
|
|
|
60
85
|
/**
|
|
61
|
-
* 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.
|
|
62
88
|
*
|
|
63
89
|
* `resolve` turns a runtime expression into a value: for `simple` it resolves
|
|
64
90
|
* the expressions embedded in the condition; for the other types it resolves
|
|
@@ -67,7 +93,7 @@ class CriterionEvaluator {
|
|
|
67
93
|
evaluate(criterion, resolve) {
|
|
68
94
|
if (!isCriterionElement(criterion)) {
|
|
69
95
|
throw new CriterionError('Element is not a Criterion Object', {
|
|
70
|
-
reason:
|
|
96
|
+
reason: CriterionErrorReason.InvalidCriterion
|
|
71
97
|
});
|
|
72
98
|
}
|
|
73
99
|
const condition = isStringElement(criterion.condition) ? toValue(criterion.condition) : undefined;
|
|
@@ -75,34 +101,52 @@ class CriterionEvaluator {
|
|
|
75
101
|
// (e.g. an empty regex would match unconditionally), so reject it too.
|
|
76
102
|
if (condition === undefined || condition === '') {
|
|
77
103
|
throw new CriterionError('Criterion is missing a "condition"', {
|
|
78
|
-
reason:
|
|
104
|
+
reason: CriterionErrorReason.MissingCondition
|
|
79
105
|
});
|
|
80
106
|
}
|
|
81
107
|
const type = this.#resolveType(criterion);
|
|
82
108
|
this.#requireValidContext(criterion, type);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
type,
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
let met;
|
|
110
|
+
try {
|
|
111
|
+
switch (type) {
|
|
112
|
+
case 'simple':
|
|
113
|
+
met = this.#simple.evaluate(condition, resolve);
|
|
114
|
+
break;
|
|
115
|
+
case 'regex':
|
|
116
|
+
met = this.#regex.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
117
|
+
break;
|
|
118
|
+
case 'jsonpath':
|
|
119
|
+
// only rfc9535 is supported, Arazzo 1.1.0's default, so an omitted
|
|
120
|
+
// version is accepted. draft-goessner has different semantics and is
|
|
121
|
+
// rejected rather than mis-evaluated.
|
|
122
|
+
this.#requireVersion(criterion, type, condition, 'rfc9535');
|
|
123
|
+
met = this.#jsonpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
124
|
+
break;
|
|
125
|
+
case 'xpath':
|
|
126
|
+
// only XPath 3.1 is supported; xpath-31 is Arazzo 1.1.0's default, so
|
|
127
|
+
// an omitted version is accepted. Older versions are rejected.
|
|
128
|
+
this.#requireVersion(criterion, type, condition, 'xpath-31');
|
|
129
|
+
met = this.#xpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
throw new CriterionError(`Unknown criterion type "${type}"`, {
|
|
133
|
+
condition,
|
|
134
|
+
type,
|
|
135
|
+
reason: CriterionErrorReason.UnknownType
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
// Arazzo 1.1.0: a condition that cannot be evaluated MUST evaluate to fail.
|
|
140
|
+
// The structural checks throw a plain CriterionError and still propagate.
|
|
141
|
+
if (error instanceof CriterionEvaluationError) return {
|
|
142
|
+
met: false,
|
|
143
|
+
error
|
|
144
|
+
};
|
|
145
|
+
throw error;
|
|
105
146
|
}
|
|
147
|
+
return {
|
|
148
|
+
met
|
|
149
|
+
};
|
|
106
150
|
}
|
|
107
151
|
|
|
108
152
|
/**
|
|
@@ -119,15 +163,15 @@ class CriterionEvaluator {
|
|
|
119
163
|
}
|
|
120
164
|
if (isStringElement(type)) return toValue(type);
|
|
121
165
|
throw new CriterionError('Criterion has an invalid "type"', {
|
|
122
|
-
reason:
|
|
166
|
+
reason: CriterionErrorReason.InvalidType
|
|
123
167
|
});
|
|
124
168
|
}
|
|
125
169
|
|
|
126
170
|
/**
|
|
127
171
|
* Extracts the expression `version` from a Criterion Expression Type Object,
|
|
128
172
|
* or `undefined` when no version is declared (a bare-string `type`, or a type
|
|
129
|
-
* object without a `version`) — in which case
|
|
130
|
-
* applies. A `version` that is present but not a string is malformed and
|
|
173
|
+
* object without a `version`) — in which case Arazzo 1.1.0's default for the
|
|
174
|
+
* type applies. A `version` that is present but not a string is malformed and
|
|
131
175
|
* throws a {@link CriterionError} rather than silently defaulting.
|
|
132
176
|
*/
|
|
133
177
|
#resolveVersion(criterion) {
|
|
@@ -139,13 +183,13 @@ class CriterionEvaluator {
|
|
|
139
183
|
return toValue(type.version);
|
|
140
184
|
}
|
|
141
185
|
throw new CriterionError('Criterion has an invalid expression type "version"', {
|
|
142
|
-
reason:
|
|
186
|
+
reason: CriterionErrorReason.InvalidVersion
|
|
143
187
|
});
|
|
144
188
|
}
|
|
145
189
|
|
|
146
190
|
/**
|
|
147
191
|
* Enforces that a versioned condition type declares only the one version this
|
|
148
|
-
* runner supports. An omitted version is accepted (
|
|
192
|
+
* runner supports. An omitted version is accepted (Arazzo 1.1.0's default);
|
|
149
193
|
* any other declared version throws a {@link CriterionError}.
|
|
150
194
|
*/
|
|
151
195
|
#requireVersion(criterion, type, condition, supported) {
|
|
@@ -154,7 +198,7 @@ class CriterionEvaluator {
|
|
|
154
198
|
throw new CriterionError(`Unsupported ${type} version "${version}" (only ${supported})`, {
|
|
155
199
|
condition,
|
|
156
200
|
type,
|
|
157
|
-
reason:
|
|
201
|
+
reason: CriterionErrorReason.UnsupportedVersion
|
|
158
202
|
});
|
|
159
203
|
}
|
|
160
204
|
}
|
|
@@ -172,7 +216,7 @@ class CriterionEvaluator {
|
|
|
172
216
|
if (!isStringElement(context) || !isRuntimeExpression(toValue(context))) {
|
|
173
217
|
throw new CriterionError('Criterion has a "context" that is not a valid runtime expression', {
|
|
174
218
|
type,
|
|
175
|
-
reason:
|
|
219
|
+
reason: CriterionErrorReason.InvalidContext
|
|
176
220
|
});
|
|
177
221
|
}
|
|
178
222
|
}
|
|
@@ -187,7 +231,7 @@ class CriterionEvaluator {
|
|
|
187
231
|
if (!isStringElement(criterion.context)) {
|
|
188
232
|
throw new CriterionError(`Criterion type "${type}" requires a "context"`, {
|
|
189
233
|
type,
|
|
190
|
-
reason:
|
|
234
|
+
reason: CriterionErrorReason.MissingContext
|
|
191
235
|
});
|
|
192
236
|
}
|
|
193
237
|
return resolve(toValue(criterion.context));
|