@usearazzo/runner 0.0.0-stage → 1.0.1-alpha.10
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/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +777 -2
- package/dist/arazzo-runner.browser.js +113254 -0
- package/dist/arazzo-runner.browser.min.js +1 -0
- package/package.json +91 -4
- package/src/action/ActionResolver.cjs +160 -0
- package/src/action/ActionResolver.mjs +150 -0
- package/src/assembler/OpenAPI2DocumentAssembler.cjs +111 -0
- package/src/assembler/OpenAPI2DocumentAssembler.mjs +104 -0
- package/src/assembler/OpenAPI30DocumentAssembler.cjs +110 -0
- package/src/assembler/OpenAPI30DocumentAssembler.mjs +103 -0
- package/src/assembler/OpenAPI31DocumentAssembler.cjs +111 -0
- package/src/assembler/OpenAPI31DocumentAssembler.mjs +104 -0
- package/src/assembler/OpenAPIDocumentAssembler.cjs +58 -0
- package/src/assembler/OpenAPIDocumentAssembler.mjs +50 -0
- package/src/client/HTTPClient.cjs +5 -0
- package/src/client/HTTPClient.mjs +1 -0
- package/src/client/HTTPClientFetch.cjs +16 -0
- package/src/client/HTTPClientFetch.mjs +10 -0
- package/src/client/OpenAPIOperationRequest.cjs +5 -0
- package/src/client/OpenAPIOperationRequest.mjs +1 -0
- package/src/client/OpenAPIOperationResponse.cjs +42 -0
- package/src/client/OpenAPIOperationResponse.mjs +36 -0
- package/src/client/OpenAPIOperationResponseNormalizer.cjs +48 -0
- package/src/client/OpenAPIOperationResponseNormalizer.mjs +40 -0
- package/src/client/ParameterDelivery.cjs +119 -0
- package/src/client/ParameterDelivery.mjs +113 -0
- package/src/constants.cjs +9 -0
- package/src/constants.mjs +3 -0
- package/src/criterion/CriterionEvaluator.cjs +205 -0
- package/src/criterion/CriterionEvaluator.mjs +196 -0
- package/src/criterion/JSONPathCriterionEvaluator.cjs +47 -0
- package/src/criterion/JSONPathCriterionEvaluator.mjs +40 -0
- package/src/criterion/RegexCriterionEvaluator.cjs +67 -0
- package/src/criterion/RegexCriterionEvaluator.mjs +60 -0
- package/src/criterion/SimpleCriterionEvaluator.cjs +50 -0
- package/src/criterion/SimpleCriterionEvaluator.mjs +43 -0
- package/src/criterion/XPathCriterionEvaluator.cjs +117 -0
- package/src/criterion/XPathCriterionEvaluator.mjs +109 -0
- package/src/document/APIDocument.cjs +35 -0
- package/src/document/APIDocument.mjs +30 -0
- package/src/document/ArazzoDocument.cjs +81 -0
- package/src/document/ArazzoDocument.mjs +74 -0
- package/src/document/ArazzoSourceDescriptionIndex.cjs +26 -0
- package/src/document/ArazzoSourceDescriptionIndex.mjs +20 -0
- package/src/document/ArazzoStepIndex.cjs +25 -0
- package/src/document/ArazzoStepIndex.mjs +19 -0
- package/src/document/ArazzoWorkflowIndex.cjs +17 -0
- package/src/document/ArazzoWorkflowIndex.mjs +11 -0
- package/src/document/OpenAPIDocument.cjs +28 -0
- package/src/document/OpenAPIDocument.mjs +21 -0
- package/src/document/OpenAPIOperationIndex.cjs +24 -0
- package/src/document/OpenAPIOperationIndex.mjs +18 -0
- package/src/document/ParameterIdentity.cjs +93 -0
- package/src/document/ParameterIdentity.mjs +88 -0
- package/src/document/openapi-types.cjs +5 -0
- package/src/document/openapi-types.mjs +1 -0
- package/src/errors/ArazzoRunnerError.cjs +10 -0
- package/src/errors/ArazzoRunnerError.mjs +5 -0
- package/src/errors/AssemblerError.cjs +11 -0
- package/src/errors/AssemblerError.mjs +4 -0
- package/src/errors/ClientError.cjs +11 -0
- package/src/errors/ClientError.mjs +4 -0
- package/src/errors/CriterionError.cjs +11 -0
- package/src/errors/CriterionError.mjs +4 -0
- package/src/errors/ExecutionError.cjs +11 -0
- package/src/errors/ExecutionError.mjs +4 -0
- package/src/errors/ExtractionError.cjs +11 -0
- package/src/errors/ExtractionError.mjs +4 -0
- package/src/errors/InvalidEntryDocumentError.cjs +11 -0
- package/src/errors/InvalidEntryDocumentError.mjs +4 -0
- package/src/errors/NormalizationError.cjs +11 -0
- package/src/errors/NormalizationError.mjs +4 -0
- package/src/errors/ResolverError.cjs +11 -0
- package/src/errors/ResolverError.mjs +4 -0
- package/src/errors/RuntimeExpressionError.cjs +11 -0
- package/src/errors/RuntimeExpressionError.mjs +4 -0
- package/src/errors/UnmatchedProviderError.cjs +11 -0
- package/src/errors/UnmatchedProviderError.mjs +4 -0
- package/src/executor/ArazzoWorkflowLocatorNormalizer.cjs +147 -0
- package/src/executor/ArazzoWorkflowLocatorNormalizer.mjs +137 -0
- package/src/executor/OpenAPIOperationExecutor.cjs +458 -0
- package/src/executor/OpenAPIOperationExecutor.mjs +447 -0
- package/src/executor/OpenAPIOperationLocatorNormalizer.cjs +197 -0
- package/src/executor/OpenAPIOperationLocatorNormalizer.mjs +189 -0
- package/src/executor/SourceDescriptionsLocatorNormalizer.cjs +44 -0
- package/src/executor/SourceDescriptionsLocatorNormalizer.mjs +38 -0
- package/src/executor/StepExecutor.cjs +333 -0
- package/src/executor/StepExecutor.mjs +326 -0
- package/src/executor/StepRetryRunner.cjs +226 -0
- package/src/executor/StepRetryRunner.mjs +215 -0
- package/src/executor/StepTransitionInterpreter.cjs +159 -0
- package/src/executor/StepTransitionInterpreter.mjs +151 -0
- package/src/executor/WorkflowCallStack.cjs +116 -0
- package/src/executor/WorkflowCallStack.mjs +106 -0
- package/src/executor/WorkflowExecutor.cjs +1091 -0
- package/src/executor/WorkflowExecutor.mjs +1077 -0
- package/src/executor/abort.cjs +70 -0
- package/src/executor/abort.mjs +60 -0
- package/src/expression/RuntimeExpressionContext.cjs +5 -0
- package/src/expression/RuntimeExpressionContext.mjs +1 -0
- package/src/expression/RuntimeExpressionEvaluator.cjs +337 -0
- package/src/expression/RuntimeExpressionEvaluator.mjs +328 -0
- package/src/extractor/ArazzoStepExtractor.cjs +48 -0
- package/src/extractor/ArazzoStepExtractor.mjs +41 -0
- package/src/extractor/ArazzoWorkflowExtractor.cjs +50 -0
- package/src/extractor/ArazzoWorkflowExtractor.mjs +43 -0
- package/src/extractor/OpenAPIOperationExtractor.cjs +84 -0
- package/src/extractor/OpenAPIOperationExtractor.mjs +77 -0
- package/src/index.cjs +419 -0
- package/src/index.mjs +73 -0
- package/src/normalizer/ArazzoStepNormalizer.cjs +23 -0
- package/src/normalizer/ArazzoStepNormalizer.mjs +17 -0
- package/src/normalizer/ArazzoWorkflowNormalizer.cjs +214 -0
- package/src/normalizer/ArazzoWorkflowNormalizer.mjs +206 -0
- package/src/normalizer/OpenAPI2OperationNormalizer.cjs +128 -0
- package/src/normalizer/OpenAPI2OperationNormalizer.mjs +120 -0
- package/src/normalizer/OpenAPI30OperationNormalizer.cjs +129 -0
- package/src/normalizer/OpenAPI30OperationNormalizer.mjs +121 -0
- package/src/normalizer/OpenAPI31OperationNormalizer.cjs +131 -0
- package/src/normalizer/OpenAPI31OperationNormalizer.mjs +123 -0
- package/src/normalizer/OpenAPIOperationNormalizer.cjs +58 -0
- package/src/normalizer/OpenAPIOperationNormalizer.mjs +50 -0
- package/src/registry/DocumentRegistry.cjs +160 -0
- package/src/registry/DocumentRegistry.mjs +151 -0
- package/src/registry/providers/ArazzoDocumentRegistryProvider.cjs +154 -0
- package/src/registry/providers/ArazzoDocumentRegistryProvider.mjs +146 -0
- package/src/registry/providers/DocumentRegistryProvider.cjs +31 -0
- package/src/registry/providers/DocumentRegistryProvider.mjs +25 -0
- package/src/registry/providers/OpenAPIDocumentRegistryProvider.cjs +122 -0
- package/src/registry/providers/OpenAPIDocumentRegistryProvider.mjs +114 -0
- package/src/resolver/ArazzoValueResolver.cjs +42 -0
- package/src/resolver/ArazzoValueResolver.mjs +37 -0
- package/src/resolver/OpenAPIOperationParameterResolver.cjs +117 -0
- package/src/resolver/OpenAPIOperationParameterResolver.mjs +110 -0
- package/src/resolver/OutputResolver.cjs +71 -0
- package/src/resolver/OutputResolver.mjs +64 -0
- package/src/resolver/RequestBodyResolver.cjs +227 -0
- package/src/resolver/RequestBodyResolver.mjs +220 -0
- package/src/resolver/ResolverScope.cjs +5 -0
- package/src/resolver/ResolverScope.mjs +1 -0
- package/src/resolver/StepParameterResolver.cjs +22 -0
- package/src/resolver/StepParameterResolver.mjs +15 -0
- package/src/resolver/WorkflowParameterResolver.cjs +73 -0
- package/src/resolver/WorkflowParameterResolver.mjs +66 -0
- package/src/state/WorkflowExecutionState.cjs +99 -0
- package/src/state/WorkflowExecutionState.mjs +93 -0
- package/src/vendor/swagger-client.cjs +1 -0
- package/src/vendor/swagger-client.mjs +1 -0
- package/types/runner.d.ts +2341 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
2
|
+
import { isStringElement } from '@speclynx/apidom-datamodel';
|
|
3
|
+
import { isCriterionElement, isCriterionExpressionTypeElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
4
|
+
import { test as isRuntimeExpression } from '@swaggerexpert/arazzo-runtime-expression';
|
|
5
|
+
import CriterionError from "../errors/CriterionError.mjs";
|
|
6
|
+
import RegexCriterionEvaluator from "./RegexCriterionEvaluator.mjs";
|
|
7
|
+
import SimpleCriterionEvaluator from "./SimpleCriterionEvaluator.mjs";
|
|
8
|
+
import JSONPathCriterionEvaluator from "./JSONPathCriterionEvaluator.mjs";
|
|
9
|
+
import XPathCriterionEvaluator from "./XPathCriterionEvaluator.mjs";
|
|
10
|
+
/**
|
|
11
|
+
* Resolves a runtime expression to a value during criterion evaluation.
|
|
12
|
+
*
|
|
13
|
+
* Used both for a criterion's `context` (regex/jsonpath/xpath) and for the
|
|
14
|
+
* expressions embedded in a `simple` condition. It should resolve leniently —
|
|
15
|
+
* an unresolvable reference returning `undefined` fails the criterion rather
|
|
16
|
+
* than throwing (a common way to drive it is
|
|
17
|
+
* `(expression) => runtimeExpressionEvaluator.evaluate(expression)` with a
|
|
18
|
+
* lenient evaluator).
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Options for the CriterionEvaluator.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Evaluates an Arazzo Criterion Object to a boolean.
|
|
27
|
+
*
|
|
28
|
+
* Dispatches on the criterion's `type` (defaulting to `simple` when omitted):
|
|
29
|
+
* - `simple` — evaluates the condition directly, resolving the runtime
|
|
30
|
+
* expressions embedded in it.
|
|
31
|
+
* - `regex` — resolves the `context` runtime expression, then applies the
|
|
32
|
+
* pattern to the resolved value.
|
|
33
|
+
* - `jsonpath` — resolves the `context` runtime expression, then applies the
|
|
34
|
+
* JSONPath query to the resolved value (met when the query matches). Only the
|
|
35
|
+
* `rfc9535` version is supported (the spec default); an explicit other version
|
|
36
|
+
* throws.
|
|
37
|
+
* - `xpath` — resolves the `context` runtime expression, then applies the XPath
|
|
38
|
+
* 3.1 query to the resolved XML value (met by the Effective Boolean Value).
|
|
39
|
+
* Only the `xpath-31` version is supported (the spec default); an explicit
|
|
40
|
+
* other version throws.
|
|
41
|
+
*
|
|
42
|
+
* The evaluator is agnostic about how runtime expressions are resolved: the
|
|
43
|
+
* caller supplies a {@link CriterionContextResolver} per evaluation, keeping
|
|
44
|
+
* runtime-state, document, and registry concerns in the runtime expression
|
|
45
|
+
* evaluator rather than duplicated here.
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
class CriterionEvaluator {
|
|
49
|
+
#simple;
|
|
50
|
+
#regex;
|
|
51
|
+
#jsonpath;
|
|
52
|
+
#xpath;
|
|
53
|
+
constructor(options = {}) {
|
|
54
|
+
this.#simple = options.simple ?? new SimpleCriterionEvaluator();
|
|
55
|
+
this.#regex = options.regex ?? new RegexCriterionEvaluator();
|
|
56
|
+
this.#jsonpath = options.jsonpath ?? new JSONPathCriterionEvaluator();
|
|
57
|
+
this.#xpath = options.xpath ?? new XPathCriterionEvaluator();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Evaluates a criterion element, returning whether the condition is met.
|
|
62
|
+
*
|
|
63
|
+
* `resolve` turns a runtime expression into a value: for `simple` it resolves
|
|
64
|
+
* the expressions embedded in the condition; for the other types it resolves
|
|
65
|
+
* the criterion's `context` expression that the condition is applied to.
|
|
66
|
+
*/
|
|
67
|
+
evaluate(criterion, resolve) {
|
|
68
|
+
if (!isCriterionElement(criterion)) {
|
|
69
|
+
throw new CriterionError('Element is not a Criterion Object', {
|
|
70
|
+
reason: 'invalid-criterion'
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const condition = isStringElement(criterion.condition) ? toValue(criterion.condition) : undefined;
|
|
74
|
+
// `condition` is required; an empty string is not a meaningful condition
|
|
75
|
+
// (e.g. an empty regex would match unconditionally), so reject it too.
|
|
76
|
+
if (condition === undefined || condition === '') {
|
|
77
|
+
throw new CriterionError('Criterion is missing a "condition"', {
|
|
78
|
+
reason: 'missing-condition'
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const type = this.#resolveType(criterion);
|
|
82
|
+
this.#requireValidContext(criterion, type);
|
|
83
|
+
switch (type) {
|
|
84
|
+
case 'simple':
|
|
85
|
+
return this.#simple.evaluate(condition, resolve);
|
|
86
|
+
case 'regex':
|
|
87
|
+
return this.#regex.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
88
|
+
case 'jsonpath':
|
|
89
|
+
// only rfc9535 is supported; it is the spec default, so an omitted
|
|
90
|
+
// version is accepted. draft-goessner has different semantics and is
|
|
91
|
+
// rejected rather than mis-evaluated.
|
|
92
|
+
this.#requireVersion(criterion, type, condition, 'rfc9535');
|
|
93
|
+
return this.#jsonpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
94
|
+
case 'xpath':
|
|
95
|
+
// only XPath 3.1 is supported; xpath-31 is the spec default, so an
|
|
96
|
+
// omitted version is accepted. Older versions are rejected.
|
|
97
|
+
this.#requireVersion(criterion, type, condition, 'xpath-31');
|
|
98
|
+
return this.#xpath.evaluate(condition, this.#resolveContext(criterion, type, resolve));
|
|
99
|
+
default:
|
|
100
|
+
throw new CriterionError(`Unknown criterion type "${type}"`, {
|
|
101
|
+
condition,
|
|
102
|
+
type,
|
|
103
|
+
reason: 'unknown-type'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Determines the criterion `type`, defaulting to `simple` only when the field
|
|
110
|
+
* is omitted. The `type` field may be a bare string or a Criterion Expression
|
|
111
|
+
* Type Object (whose own `type` names the flavor). A present-but-unreadable
|
|
112
|
+
* `type` throws a {@link CriterionError} rather than silently defaulting.
|
|
113
|
+
*/
|
|
114
|
+
#resolveType(criterion) {
|
|
115
|
+
const type = criterion.type;
|
|
116
|
+
if (type === undefined) return 'simple';
|
|
117
|
+
if (isCriterionExpressionTypeElement(type) && isStringElement(type.type)) {
|
|
118
|
+
return toValue(type.type);
|
|
119
|
+
}
|
|
120
|
+
if (isStringElement(type)) return toValue(type);
|
|
121
|
+
throw new CriterionError('Criterion has an invalid "type"', {
|
|
122
|
+
reason: 'invalid-type'
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Extracts the expression `version` from a Criterion Expression Type Object,
|
|
128
|
+
* or `undefined` when no version is declared (a bare-string `type`, or a type
|
|
129
|
+
* object without a `version`) — in which case the spec default for the type
|
|
130
|
+
* applies. A `version` that is present but not a string is malformed and
|
|
131
|
+
* throws a {@link CriterionError} rather than silently defaulting.
|
|
132
|
+
*/
|
|
133
|
+
#resolveVersion(criterion) {
|
|
134
|
+
const type = criterion.type;
|
|
135
|
+
if (!isCriterionExpressionTypeElement(type) || type.version === undefined) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
if (isStringElement(type.version)) {
|
|
139
|
+
return toValue(type.version);
|
|
140
|
+
}
|
|
141
|
+
throw new CriterionError('Criterion has an invalid expression type "version"', {
|
|
142
|
+
reason: 'invalid-version'
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Enforces that a versioned condition type declares only the one version this
|
|
148
|
+
* runner supports. An omitted version is accepted (it is the spec default);
|
|
149
|
+
* any other declared version throws a {@link CriterionError}.
|
|
150
|
+
*/
|
|
151
|
+
#requireVersion(criterion, type, condition, supported) {
|
|
152
|
+
const version = this.#resolveVersion(criterion);
|
|
153
|
+
if (version !== undefined && version !== supported) {
|
|
154
|
+
throw new CriterionError(`Unsupported ${type} version "${version}" (only ${supported})`, {
|
|
155
|
+
condition,
|
|
156
|
+
type,
|
|
157
|
+
reason: 'unsupported-version'
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Enforces that a present `context` is a valid runtime expression, for every
|
|
164
|
+
* criterion type: the spec types it `{expression}`, and `simple` ignores it,
|
|
165
|
+
* so a malformed one would otherwise go unnoticed there.
|
|
166
|
+
*/
|
|
167
|
+
#requireValidContext(criterion, type) {
|
|
168
|
+
const {
|
|
169
|
+
context
|
|
170
|
+
} = criterion;
|
|
171
|
+
if (context === undefined) return;
|
|
172
|
+
if (!isStringElement(context) || !isRuntimeExpression(toValue(context))) {
|
|
173
|
+
throw new CriterionError('Criterion has a "context" that is not a valid runtime expression', {
|
|
174
|
+
type,
|
|
175
|
+
reason: 'invalid-context'
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Resolves the criterion's `context` runtime expression to the value the
|
|
182
|
+
* condition is applied to. The condition types that need a context (`regex`,
|
|
183
|
+
* `jsonpath`, `xpath`) must declare one; a criterion of such a type without a
|
|
184
|
+
* `context` throws a {@link CriterionError}.
|
|
185
|
+
*/
|
|
186
|
+
#resolveContext(criterion, type, resolve) {
|
|
187
|
+
if (!isStringElement(criterion.context)) {
|
|
188
|
+
throw new CriterionError(`Criterion type "${type}" requires a "context"`, {
|
|
189
|
+
type,
|
|
190
|
+
reason: 'missing-context'
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return resolve(toValue(criterion.context));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
export default CriterionEvaluator;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _jsonpath = require("@swaggerexpert/jsonpath");
|
|
9
|
+
var _CriterionError = _interopRequireDefault(require("../errors/CriterionError.cjs"));
|
|
10
|
+
/**
|
|
11
|
+
* Evaluates a `jsonpath` Arazzo criterion condition against a resolved context value.
|
|
12
|
+
*
|
|
13
|
+
* The condition is a JSONPath query (RFC 9535, per the Criterion Expression
|
|
14
|
+
* Type Object's pinned version) applied to the resolved `context`. The criterion
|
|
15
|
+
* is met when the query yields a non-empty node list.
|
|
16
|
+
*
|
|
17
|
+
* Per Arazzo 1.1.0, a `null` or `undefined` context fails the condition. The
|
|
18
|
+
* context is a plain runtime value (the runtime expression evaluator has already
|
|
19
|
+
* converted any ApiDOM element), so the default JSON evaluation realm applies.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
class JSONPathCriterionEvaluator {
|
|
23
|
+
/**
|
|
24
|
+
* Runs the JSONPath `condition` against the resolved context value, returning
|
|
25
|
+
* whether it matched anything.
|
|
26
|
+
*
|
|
27
|
+
* Returns `false` when the context is `null` or `undefined`. Throws
|
|
28
|
+
* {@link CriterionError} when the condition is not a valid JSONPath query.
|
|
29
|
+
*/
|
|
30
|
+
evaluate(condition, context) {
|
|
31
|
+
if (context === null || context === undefined) return false;
|
|
32
|
+
try {
|
|
33
|
+
return (0, _jsonpath.evaluate)(context, condition).length > 0;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (error instanceof _jsonpath.JSONPathError) {
|
|
36
|
+
throw new _CriterionError.default(`Invalid jsonpath criterion condition "${condition}"`, {
|
|
37
|
+
cause: error,
|
|
38
|
+
condition,
|
|
39
|
+
type: 'jsonpath',
|
|
40
|
+
reason: 'invalid-jsonpath'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
var _default = exports.default = JSONPathCriterionEvaluator;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { evaluate as evaluateJSONPath, JSONPathError } from '@swaggerexpert/jsonpath';
|
|
2
|
+
import CriterionError from "../errors/CriterionError.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Evaluates a `jsonpath` Arazzo criterion condition against a resolved context value.
|
|
5
|
+
*
|
|
6
|
+
* The condition is a JSONPath query (RFC 9535, per the Criterion Expression
|
|
7
|
+
* Type Object's pinned version) applied to the resolved `context`. The criterion
|
|
8
|
+
* is met when the query yields a non-empty node list.
|
|
9
|
+
*
|
|
10
|
+
* Per Arazzo 1.1.0, a `null` or `undefined` context fails the condition. The
|
|
11
|
+
* context is a plain runtime value (the runtime expression evaluator has already
|
|
12
|
+
* converted any ApiDOM element), so the default JSON evaluation realm applies.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
class JSONPathCriterionEvaluator {
|
|
16
|
+
/**
|
|
17
|
+
* Runs the JSONPath `condition` against the resolved context value, returning
|
|
18
|
+
* whether it matched anything.
|
|
19
|
+
*
|
|
20
|
+
* Returns `false` when the context is `null` or `undefined`. Throws
|
|
21
|
+
* {@link CriterionError} when the condition is not a valid JSONPath query.
|
|
22
|
+
*/
|
|
23
|
+
evaluate(condition, context) {
|
|
24
|
+
if (context === null || context === undefined) return false;
|
|
25
|
+
try {
|
|
26
|
+
return evaluateJSONPath(context, condition).length > 0;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (error instanceof JSONPathError) {
|
|
29
|
+
throw new CriterionError(`Invalid jsonpath criterion condition "${condition}"`, {
|
|
30
|
+
cause: error,
|
|
31
|
+
condition,
|
|
32
|
+
type: 'jsonpath',
|
|
33
|
+
reason: 'invalid-jsonpath'
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export default JSONPathCriterionEvaluator;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _CriterionError = _interopRequireDefault(require("../errors/CriterionError.cjs"));
|
|
9
|
+
/**
|
|
10
|
+
* Evaluates a `regex` Arazzo criterion condition against a resolved context value.
|
|
11
|
+
*
|
|
12
|
+
* The Arazzo specification does not pin a regular expression dialect for the
|
|
13
|
+
* `regex` criterion type. This evaluator uses ECMA-262 (the native `RegExp`
|
|
14
|
+
* dialect), matching OpenAPI, which pins ECMA-262 for `pattern` via JSON Schema.
|
|
15
|
+
* The pattern is applied with search (not full-match) semantics — anchoring is
|
|
16
|
+
* the author's responsibility via `^`/`$`, consistent with the spec's `^200$`
|
|
17
|
+
* example.
|
|
18
|
+
*
|
|
19
|
+
* Per Arazzo 1.1.0, a `null` or `undefined` context fails the condition. A
|
|
20
|
+
* non-scalar context is serialized with `JSON.stringify` (matching how the
|
|
21
|
+
* runtime expression evaluator stringifies values for interpolation), so a
|
|
22
|
+
* pattern can match against an object/array body; scalars are coerced with
|
|
23
|
+
* `String()`.
|
|
24
|
+
*
|
|
25
|
+
* The pattern is a native `RegExp`, which has no execution timeout; a
|
|
26
|
+
* pathological author pattern (catastrophic backtracking) against a long
|
|
27
|
+
* context can stall. Patterns originate from the Arazzo document, so this is
|
|
28
|
+
* treated as trusted input rather than guarded here.
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
class RegexCriterionEvaluator {
|
|
32
|
+
/**
|
|
33
|
+
* Tests the resolved context value against the regular expression `condition`.
|
|
34
|
+
*
|
|
35
|
+
* The context is coerced to a string before matching. Returns `false` when the
|
|
36
|
+
* context is `null` or `undefined`. Throws {@link CriterionError} when the
|
|
37
|
+
* condition is not a valid regular expression.
|
|
38
|
+
*/
|
|
39
|
+
evaluate(condition, context) {
|
|
40
|
+
if (context === null || context === undefined) return false;
|
|
41
|
+
let regExp;
|
|
42
|
+
try {
|
|
43
|
+
regExp = new RegExp(condition);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new _CriterionError.default(`Invalid regex criterion condition "${condition}"`, {
|
|
46
|
+
cause: error,
|
|
47
|
+
condition,
|
|
48
|
+
type: 'regex',
|
|
49
|
+
reason: 'invalid-regex'
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return regExp.test(this.#stringify(context));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Coerces a non-null context value to the string the pattern is tested
|
|
57
|
+
* against, matching the runtime expression evaluator's interpolation
|
|
58
|
+
* stringify: strings as-is, objects/arrays as JSON, everything else via
|
|
59
|
+
* `String()`. A value whose `JSON.stringify` is `undefined` becomes `''`.
|
|
60
|
+
*/
|
|
61
|
+
#stringify(context) {
|
|
62
|
+
if (typeof context === 'string') return context;
|
|
63
|
+
if (typeof context === 'object') return JSON.stringify(context) ?? '';
|
|
64
|
+
return String(context);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
var _default = exports.default = RegexCriterionEvaluator;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import CriterionError from "../errors/CriterionError.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Evaluates a `regex` Arazzo criterion condition against a resolved context value.
|
|
4
|
+
*
|
|
5
|
+
* The Arazzo specification does not pin a regular expression dialect for the
|
|
6
|
+
* `regex` criterion type. This evaluator uses ECMA-262 (the native `RegExp`
|
|
7
|
+
* dialect), matching OpenAPI, which pins ECMA-262 for `pattern` via JSON Schema.
|
|
8
|
+
* The pattern is applied with search (not full-match) semantics — anchoring is
|
|
9
|
+
* the author's responsibility via `^`/`$`, consistent with the spec's `^200$`
|
|
10
|
+
* example.
|
|
11
|
+
*
|
|
12
|
+
* Per Arazzo 1.1.0, a `null` or `undefined` context fails the condition. A
|
|
13
|
+
* non-scalar context is serialized with `JSON.stringify` (matching how the
|
|
14
|
+
* runtime expression evaluator stringifies values for interpolation), so a
|
|
15
|
+
* pattern can match against an object/array body; scalars are coerced with
|
|
16
|
+
* `String()`.
|
|
17
|
+
*
|
|
18
|
+
* The pattern is a native `RegExp`, which has no execution timeout; a
|
|
19
|
+
* pathological author pattern (catastrophic backtracking) against a long
|
|
20
|
+
* context can stall. Patterns originate from the Arazzo document, so this is
|
|
21
|
+
* treated as trusted input rather than guarded here.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
class RegexCriterionEvaluator {
|
|
25
|
+
/**
|
|
26
|
+
* Tests the resolved context value against the regular expression `condition`.
|
|
27
|
+
*
|
|
28
|
+
* The context is coerced to a string before matching. Returns `false` when the
|
|
29
|
+
* context is `null` or `undefined`. Throws {@link CriterionError} when the
|
|
30
|
+
* condition is not a valid regular expression.
|
|
31
|
+
*/
|
|
32
|
+
evaluate(condition, context) {
|
|
33
|
+
if (context === null || context === undefined) return false;
|
|
34
|
+
let regExp;
|
|
35
|
+
try {
|
|
36
|
+
regExp = new RegExp(condition);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw new CriterionError(`Invalid regex criterion condition "${condition}"`, {
|
|
39
|
+
cause: error,
|
|
40
|
+
condition,
|
|
41
|
+
type: 'regex',
|
|
42
|
+
reason: 'invalid-regex'
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return regExp.test(this.#stringify(context));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Coerces a non-null context value to the string the pattern is tested
|
|
50
|
+
* against, matching the runtime expression evaluator's interpolation
|
|
51
|
+
* stringify: strings as-is, objects/arrays as JSON, everything else via
|
|
52
|
+
* `String()`. A value whose `JSON.stringify` is `undefined` becomes `''`.
|
|
53
|
+
*/
|
|
54
|
+
#stringify(context) {
|
|
55
|
+
if (typeof context === 'string') return context;
|
|
56
|
+
if (typeof context === 'object') return JSON.stringify(context) ?? '';
|
|
57
|
+
return String(context);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export default RegexCriterionEvaluator;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _arazzoCriterion = require("@swaggerexpert/arazzo-criterion");
|
|
9
|
+
var _CriterionError = _interopRequireDefault(require("../errors/CriterionError.cjs"));
|
|
10
|
+
/**
|
|
11
|
+
* Evaluates a `simple` Arazzo criterion condition.
|
|
12
|
+
*
|
|
13
|
+
* A simple condition embeds runtime expressions directly in the condition
|
|
14
|
+
* (e.g. `$statusCode == 200 && $response.body.status == 'available'`), so —
|
|
15
|
+
* unlike `regex`/`jsonpath`/`xpath` — it has no separate `context`. Parsing,
|
|
16
|
+
* loose/case-insensitive comparison, and member/index navigation are delegated
|
|
17
|
+
* to `@swaggerexpert/arazzo-criterion`; each embedded runtime expression is
|
|
18
|
+
* resolved through the supplied resolver.
|
|
19
|
+
*
|
|
20
|
+
* An operand that resolves to `undefined` (a lenient miss) does not throw; it is
|
|
21
|
+
* compared per the library's rules (e.g. `undefined == x` and relational
|
|
22
|
+
* comparisons are false, matching the spec's "null equals only null"), so a
|
|
23
|
+
* negated or disjunctive condition may still pass. A malformed condition throws
|
|
24
|
+
* {@link CriterionError}.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
class SimpleCriterionEvaluator {
|
|
28
|
+
/**
|
|
29
|
+
* Evaluates the simple `condition`, resolving each embedded runtime
|
|
30
|
+
* expression via `resolve`.
|
|
31
|
+
*/
|
|
32
|
+
evaluate(condition, resolve) {
|
|
33
|
+
try {
|
|
34
|
+
return (0, _arazzoCriterion.evaluate)(condition, {
|
|
35
|
+
resolve
|
|
36
|
+
});
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error instanceof _arazzoCriterion.ArazzoCriterionError) {
|
|
39
|
+
throw new _CriterionError.default(`Invalid simple criterion condition "${condition}"`, {
|
|
40
|
+
cause: error,
|
|
41
|
+
condition,
|
|
42
|
+
type: 'simple',
|
|
43
|
+
reason: 'invalid-simple'
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var _default = exports.default = SimpleCriterionEvaluator;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { evaluate as evaluateSimpleCriterion, ArazzoCriterionError } from '@swaggerexpert/arazzo-criterion';
|
|
2
|
+
import CriterionError from "../errors/CriterionError.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Evaluates a `simple` Arazzo criterion condition.
|
|
5
|
+
*
|
|
6
|
+
* A simple condition embeds runtime expressions directly in the condition
|
|
7
|
+
* (e.g. `$statusCode == 200 && $response.body.status == 'available'`), so —
|
|
8
|
+
* unlike `regex`/`jsonpath`/`xpath` — it has no separate `context`. Parsing,
|
|
9
|
+
* loose/case-insensitive comparison, and member/index navigation are delegated
|
|
10
|
+
* to `@swaggerexpert/arazzo-criterion`; each embedded runtime expression is
|
|
11
|
+
* resolved through the supplied resolver.
|
|
12
|
+
*
|
|
13
|
+
* An operand that resolves to `undefined` (a lenient miss) does not throw; it is
|
|
14
|
+
* compared per the library's rules (e.g. `undefined == x` and relational
|
|
15
|
+
* comparisons are false, matching the spec's "null equals only null"), so a
|
|
16
|
+
* negated or disjunctive condition may still pass. A malformed condition throws
|
|
17
|
+
* {@link CriterionError}.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
class SimpleCriterionEvaluator {
|
|
21
|
+
/**
|
|
22
|
+
* Evaluates the simple `condition`, resolving each embedded runtime
|
|
23
|
+
* expression via `resolve`.
|
|
24
|
+
*/
|
|
25
|
+
evaluate(condition, resolve) {
|
|
26
|
+
try {
|
|
27
|
+
return evaluateSimpleCriterion(condition, {
|
|
28
|
+
resolve
|
|
29
|
+
});
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error instanceof ArazzoCriterionError) {
|
|
32
|
+
throw new CriterionError(`Invalid simple criterion condition "${condition}"`, {
|
|
33
|
+
cause: error,
|
|
34
|
+
condition,
|
|
35
|
+
type: 'simple',
|
|
36
|
+
reason: 'invalid-simple'
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export default SimpleCriterionEvaluator;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _fontoxpath = _interopRequireDefault(require("fontoxpath"));
|
|
9
|
+
var _xmldom = require("@xmldom/xmldom");
|
|
10
|
+
var _CriterionError = _interopRequireDefault(require("../errors/CriterionError.cjs"));
|
|
11
|
+
// fontoxpath is CommonJS and its named exports are not statically resolvable
|
|
12
|
+
// under ESM, so import the default and destructure.
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
evaluateXPathToBoolean,
|
|
16
|
+
evaluateXPath
|
|
17
|
+
} = _fontoxpath.default;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Evaluates an `xpath` Arazzo criterion condition against a resolved context value.
|
|
21
|
+
*
|
|
22
|
+
* The condition is an XPath 3.1 query applied to the resolved `context`, which
|
|
23
|
+
* must be XML. A string context is parsed as XML; an already-parsed DOM node is
|
|
24
|
+
* used as-is. The criterion is met by the query's Effective Boolean Value
|
|
25
|
+
* (XPath 3.1 §19.1.2), as the Arazzo specification mandates — so a boolean
|
|
26
|
+
* predicate (`//status = 'ok'`), a non-empty node set, a non-zero number, and a
|
|
27
|
+
* non-empty string all evaluate to `true`.
|
|
28
|
+
*
|
|
29
|
+
* Only XPath 3.1 is supported (`fontoxpath`'s engine); version gating happens in
|
|
30
|
+
* the facade. Per Arazzo 1.1.0, a `null` or `undefined` context fails the
|
|
31
|
+
* condition. An invalid query throws {@link CriterionError}.
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
class XPathCriterionEvaluator {
|
|
35
|
+
/**
|
|
36
|
+
* Evaluates the XPath `condition` against the resolved context value, returning
|
|
37
|
+
* its Effective Boolean Value.
|
|
38
|
+
*
|
|
39
|
+
* Returns `false` when the context is `null` or `undefined`. Throws
|
|
40
|
+
* {@link CriterionError} when the context is not XML or the query is invalid.
|
|
41
|
+
*/
|
|
42
|
+
evaluate(condition, context) {
|
|
43
|
+
if (context === null || context === undefined) return false;
|
|
44
|
+
const node = this.#toNode(condition, context);
|
|
45
|
+
try {
|
|
46
|
+
return evaluateXPathToBoolean(condition, node, null, null, {
|
|
47
|
+
language: evaluateXPath.XPATH_3_1_LANGUAGE
|
|
48
|
+
});
|
|
49
|
+
} catch (error) {
|
|
50
|
+
throw new _CriterionError.default(`Invalid xpath criterion condition "${condition}"`, {
|
|
51
|
+
cause: error,
|
|
52
|
+
condition,
|
|
53
|
+
type: 'xpath',
|
|
54
|
+
reason: 'invalid-xpath'
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Coerces the resolved context to an XML DOM node: an already-parsed node is
|
|
61
|
+
* used as-is, a string is parsed as XML. Any other value cannot be an XPath
|
|
62
|
+
* context and throws.
|
|
63
|
+
*/
|
|
64
|
+
#toNode(condition, context) {
|
|
65
|
+
if (this.#isNode(context)) return context;
|
|
66
|
+
if (typeof context !== 'string') {
|
|
67
|
+
throw new _CriterionError.default('xpath criterion context is not XML', {
|
|
68
|
+
condition,
|
|
69
|
+
type: 'xpath',
|
|
70
|
+
reason: 'invalid-context'
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// capture parse errors via `onError` rather than the default handler: this
|
|
75
|
+
// both suppresses the parser writing to the console and catches *recoverable*
|
|
76
|
+
// errors (e.g. an undefined entity, stray text) that do not throw but would
|
|
77
|
+
// otherwise yield a degraded document evaluated silently.
|
|
78
|
+
let parseError;
|
|
79
|
+
try {
|
|
80
|
+
const document = new _xmldom.DOMParser({
|
|
81
|
+
onError: (_level, message) => {
|
|
82
|
+
parseError ??= message;
|
|
83
|
+
}
|
|
84
|
+
}).parseFromString(context, 'text/xml');
|
|
85
|
+
if (parseError !== undefined) {
|
|
86
|
+
throw new _CriterionError.default('xpath criterion context is not valid XML', {
|
|
87
|
+
cause: parseError,
|
|
88
|
+
condition,
|
|
89
|
+
type: 'xpath',
|
|
90
|
+
reason: 'invalid-context'
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return document;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error instanceof _CriterionError.default) throw error;
|
|
96
|
+
throw new _CriterionError.default('xpath criterion context is not valid XML', {
|
|
97
|
+
cause: error,
|
|
98
|
+
condition,
|
|
99
|
+
type: 'xpath',
|
|
100
|
+
reason: 'invalid-context'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Duck-types a DOM node, so a caller may pass an already-parsed document
|
|
107
|
+
* instead of an XML string. Requires both a numeric `nodeType` and a string
|
|
108
|
+
* `nodeName` so a plain JSON value that happens to carry a `nodeType` property
|
|
109
|
+
* is not mistaken for a node (and is instead rejected as a non-XML context).
|
|
110
|
+
*/
|
|
111
|
+
#isNode(value) {
|
|
112
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
113
|
+
const node = value;
|
|
114
|
+
return typeof node.nodeType === 'number' && typeof node.nodeName === 'string';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
var _default = exports.default = XPathCriterionEvaluator;
|