@usearazzo/runner 0.0.0-stage → 1.0.1-alpha.11
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 +37 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +163 -2
- package/dist/arazzo-runner.browser.js +113245 -0
- package/dist/arazzo-runner.browser.min.js +1 -0
- package/package.json +95 -4
- package/src/ArazzoRunner.cjs +122 -0
- package/src/ArazzoRunner.mjs +113 -0
- 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 +426 -0
- package/src/index.mjs +75 -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 +2410 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { parseRuntimeExpression } from '@usearazzo/parser';
|
|
2
|
+
import { test, interpolate } from '@swaggerexpert/arazzo-runtime-expression';
|
|
3
|
+
import { compile, composeRealms, evaluate as evaluateJSONPointer, JSONPointerEvaluateError } from '@swaggerexpert/json-pointer';
|
|
4
|
+
import JSONEvaluationRealm from '@swaggerexpert/json-pointer/evaluate/realms/json';
|
|
5
|
+
import { ApiDOMEvaluationRealm } from '@speclynx/apidom-json-pointer';
|
|
6
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
7
|
+
import RuntimeExpressionError from "../errors/RuntimeExpressionError.mjs";
|
|
8
|
+
import ArazzoDocument from "../document/ArazzoDocument.mjs";
|
|
9
|
+
import OpenAPIDocument from "../document/OpenAPIDocument.mjs";
|
|
10
|
+
/**
|
|
11
|
+
* Options for the RuntimeExpressionEvaluator.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The request/response side of the context a `$request`/`$response` source is
|
|
16
|
+
* evaluated against. Both request and response contexts are assignable to this
|
|
17
|
+
* shape; sources absent from a side (e.g. `$response.query`) resolve to
|
|
18
|
+
* `undefined` naturally.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Realm for drilling JSON Pointers into payload values. Composing the ApiDOM
|
|
22
|
+
* realm ahead of the JSON realm lets a single `evaluate` call handle plain JS
|
|
23
|
+
* values, ApiDOM elements, and mixed trees: the ApiDOM realm claims elements
|
|
24
|
+
* and falls through to the JSON realm for plain values. Order matters — the
|
|
25
|
+
* JSON realm would otherwise greedily claim ApiDOM elements and fail.
|
|
26
|
+
*/
|
|
27
|
+
const pointerRealm = composeRealms(new ApiDOMEvaluationRealm(), new JSONEvaluationRealm());
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The expression roots that describe one HTTP exchange — unavailable in a step
|
|
31
|
+
* that calls a workflow, which makes none.
|
|
32
|
+
*/
|
|
33
|
+
const HTTP_EXCHANGE_NODES = new Set(['UrlExpression', 'MethodExpression', 'StatusCodeExpression', 'RequestExpression', 'ResponseExpression']);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Evaluates Arazzo runtime expressions against a context.
|
|
37
|
+
*
|
|
38
|
+
* A single evaluator is bound to one context and can evaluate many expressions
|
|
39
|
+
* against it — matching how a step executor resolves a step's parameters,
|
|
40
|
+
* success criteria, and outputs from the same state.
|
|
41
|
+
*
|
|
42
|
+
* The context holds only runtime state (`$inputs`, `$steps`, `$request`,
|
|
43
|
+
* `$response`, …). Static, document-sourced expressions are resolved on demand:
|
|
44
|
+
* `$components` and `$workflows.{workflowId}.steps.{stepId}` from the
|
|
45
|
+
* evaluator's document, and `$sourceDescriptions` from the external document
|
|
46
|
+
* (via the registry) the source name points at. A step reference resolves to
|
|
47
|
+
* the Step Object as authored — a locator, not the step's execution result.
|
|
48
|
+
*
|
|
49
|
+
* A reference resolves to `undefined` when it is absent. Runtime values
|
|
50
|
+
* originate from JSON (or ApiDOM), which cannot represent `undefined` — an
|
|
51
|
+
* absent value is a missing property and an explicit null is `null` — so
|
|
52
|
+
* `undefined` unambiguously marks "unresolved".
|
|
53
|
+
*
|
|
54
|
+
* Three modes are supported:
|
|
55
|
+
* - {@link RuntimeExpressionEvaluator.evaluate} resolves a pure expression
|
|
56
|
+
* (e.g. `$response.body#/id`) to its typed value.
|
|
57
|
+
* - {@link RuntimeExpressionEvaluator.interpolate} renders a template with
|
|
58
|
+
* embedded `{expression}` occurrences to a string.
|
|
59
|
+
* - {@link RuntimeExpressionEvaluator.resolve} applies Arazzo "value" semantics:
|
|
60
|
+
* a value that is itself a complete expression resolves to a typed value,
|
|
61
|
+
* otherwise the value is interpolated to a string.
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
class RuntimeExpressionEvaluator {
|
|
65
|
+
#context;
|
|
66
|
+
#strict;
|
|
67
|
+
#document;
|
|
68
|
+
#registry;
|
|
69
|
+
constructor(context, options = {}) {
|
|
70
|
+
this.#context = context;
|
|
71
|
+
this.#strict = options.strict ?? true;
|
|
72
|
+
this.#document = options.document;
|
|
73
|
+
this.#registry = options.registry;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Evaluates a pure runtime expression to its typed value.
|
|
78
|
+
*
|
|
79
|
+
* The expression must be the bare form without surrounding braces
|
|
80
|
+
* (e.g. `$inputs.username`, `$response.body#/pets/0/id`). In strict mode an
|
|
81
|
+
* unresolvable reference throws; otherwise it returns `undefined`.
|
|
82
|
+
*/
|
|
83
|
+
evaluate(expression) {
|
|
84
|
+
const node = this.#parse(expression);
|
|
85
|
+
this.#assertAvailable(node, expression);
|
|
86
|
+
const value = this.#evaluateNode(node, expression);
|
|
87
|
+
if (value === undefined && this.#strict) {
|
|
88
|
+
throw new RuntimeExpressionError(`Runtime expression "${expression}" could not be resolved against the context`, {
|
|
89
|
+
expression,
|
|
90
|
+
reason: 'unresolved-reference'
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Renders a template string, replacing each embedded `{expression}` with the
|
|
98
|
+
* string form of its evaluated value. Returns a string.
|
|
99
|
+
*
|
|
100
|
+
* Object and array values are serialized with `JSON.stringify`. In non-strict
|
|
101
|
+
* mode, unresolvable references render as an empty string. A `{…}` that is not
|
|
102
|
+
* a valid embedded expression (e.g. a literal JSON payload) is left unchanged.
|
|
103
|
+
*/
|
|
104
|
+
interpolate(template) {
|
|
105
|
+
return interpolate(template, expression => this.evaluate(expression));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Resolves an Arazzo "value" string.
|
|
110
|
+
*
|
|
111
|
+
* A value that is itself a complete runtime expression (the unbraced form,
|
|
112
|
+
* e.g. `$inputs.userId`) resolves to its typed value — "runtime expressions
|
|
113
|
+
* preserve the type of the referenced value". Any other string is an
|
|
114
|
+
* expression-string template: embedded `{expression}` occurrences are
|
|
115
|
+
* interpolated and a string is returned, so a whole-string `{expression}`
|
|
116
|
+
* yields the string representation of its value, not the typed value. A
|
|
117
|
+
* string containing no expressions is returned unchanged.
|
|
118
|
+
*/
|
|
119
|
+
resolve(value) {
|
|
120
|
+
// `test` returns true only when the entire string is a valid runtime
|
|
121
|
+
// expression, so a braced or mixed string falls through to interpolation.
|
|
122
|
+
return test(value) ? this.evaluate(value) : this.interpolate(value);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Parses an expression to its AST, throwing on failure regardless of strict mode.
|
|
127
|
+
*/
|
|
128
|
+
#parse(expression) {
|
|
129
|
+
let result;
|
|
130
|
+
try {
|
|
131
|
+
result = parseRuntimeExpression(expression);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
throw new RuntimeExpressionError(`Failed to parse runtime expression "${expression}"`, {
|
|
134
|
+
cause: error,
|
|
135
|
+
expression,
|
|
136
|
+
reason: 'parse-error'
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (!result.result.success || result.tree === undefined) {
|
|
140
|
+
throw new RuntimeExpressionError(`Invalid runtime expression "${expression}"`, {
|
|
141
|
+
expression,
|
|
142
|
+
reason: 'invalid-expression'
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return result.tree;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Rejects an HTTP-exchange expression in a step that calls a workflow. Such a
|
|
150
|
+
* step made no HTTP call, so the expression is an authoring error there — not
|
|
151
|
+
* a reference that merely did not resolve — and throws regardless of `strict`.
|
|
152
|
+
*/
|
|
153
|
+
#assertAvailable(node, expression) {
|
|
154
|
+
const {
|
|
155
|
+
calledWorkflow
|
|
156
|
+
} = this.#context;
|
|
157
|
+
if (calledWorkflow === undefined || !HTTP_EXCHANGE_NODES.has(node.type)) return;
|
|
158
|
+
throw new RuntimeExpressionError(`Runtime expression "${expression}" is not available: step "${calledWorkflow.stepId}" calls workflow "${calledWorkflow.workflowId}", not an operation, so it has no HTTP request or response`, {
|
|
159
|
+
expression,
|
|
160
|
+
reason: 'unavailable-expression'
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Walks an AST node against the context, returning the referenced value or
|
|
166
|
+
* `undefined` when the reference does not resolve.
|
|
167
|
+
*/
|
|
168
|
+
#evaluateNode(node, expression) {
|
|
169
|
+
switch (node.type) {
|
|
170
|
+
case 'UrlExpression':
|
|
171
|
+
return this.#context.request?.url;
|
|
172
|
+
case 'MethodExpression':
|
|
173
|
+
return this.#context.request?.method;
|
|
174
|
+
case 'StatusCodeExpression':
|
|
175
|
+
return this.#context.response?.statusCode;
|
|
176
|
+
case 'RequestExpression':
|
|
177
|
+
return this.#source(node.source, this.#context.request);
|
|
178
|
+
case 'ResponseExpression':
|
|
179
|
+
return this.#source(node.source, this.#context.response);
|
|
180
|
+
case 'InputsExpression':
|
|
181
|
+
return this.#drill(this.#get(this.#context.inputs, node.name));
|
|
182
|
+
case 'OutputsExpression':
|
|
183
|
+
return this.#drill(this.#get(this.#context.outputs, node.name));
|
|
184
|
+
case 'StepsExpression':
|
|
185
|
+
return this.#drill(this.#get(this.#context.steps?.[node.stepId]?.outputs, node.outputName), node.jsonPointer?.value);
|
|
186
|
+
case 'WorkflowsExpression':
|
|
187
|
+
return this.#drill(this.#get(this.#context.workflows?.[node.workflowId]?.[node.field], node.fieldName), node.jsonPointer?.value);
|
|
188
|
+
case 'WorkflowsStepsExpression':
|
|
189
|
+
return this.#step(this.#document, node.workflowId, node.stepId);
|
|
190
|
+
case 'SourceDescriptionsExpression':
|
|
191
|
+
return this.#sourceDescription(node);
|
|
192
|
+
case 'ComponentsExpression':
|
|
193
|
+
return this.#component(node.componentType, node.componentName);
|
|
194
|
+
default:
|
|
195
|
+
throw new RuntimeExpressionError(`Unsupported runtime expression node "${node.type}"`, {
|
|
196
|
+
expression,
|
|
197
|
+
reason: 'unsupported-node'
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Evaluates a `$request`/`$response` source reference against the request or
|
|
204
|
+
* response side of the context.
|
|
205
|
+
*/
|
|
206
|
+
#source(source, message) {
|
|
207
|
+
const {
|
|
208
|
+
reference
|
|
209
|
+
} = source;
|
|
210
|
+
switch (reference.type) {
|
|
211
|
+
case 'HeaderReference':
|
|
212
|
+
return this.#header(message?.header, reference.token);
|
|
213
|
+
case 'QueryReference':
|
|
214
|
+
return this.#get(message?.query, reference.name);
|
|
215
|
+
case 'PathReference':
|
|
216
|
+
return this.#get(message?.path, reference.name);
|
|
217
|
+
case 'BodyReference':
|
|
218
|
+
return this.#drill(message?.body, reference.jsonPointer?.value);
|
|
219
|
+
default:
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Resolves `$components.{field}.{name}` by drilling into the evaluator's
|
|
226
|
+
* document. Returns `undefined` when no document is configured or the
|
|
227
|
+
* component is absent.
|
|
228
|
+
*/
|
|
229
|
+
#component(field, name) {
|
|
230
|
+
return this.#drillDocument(this.#document, compile(['components', field, name]));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Resolves `{workflowId}.steps.{stepId}` to the Step Object in an Arazzo
|
|
235
|
+
* document. Returns `undefined` when the document is absent or not Arazzo, or
|
|
236
|
+
* the workflow or step is unknown.
|
|
237
|
+
*/
|
|
238
|
+
#step(document, workflowId, stepId) {
|
|
239
|
+
if (document === undefined || !ArazzoDocument.is(document)) return undefined;
|
|
240
|
+
const pointer = document.stepIndex.getStep(workflowId, stepId);
|
|
241
|
+
return pointer === undefined ? undefined : this.#drillDocument(document, pointer);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Resolves `$sourceDescriptions.{name}.{reference}` with the resolution
|
|
246
|
+
* priority defined by the Arazzo Specification:
|
|
247
|
+
*
|
|
248
|
+
* 1. `{reference}` is matched as an operationId (OpenAPI source) or workflowId
|
|
249
|
+
* (Arazzo source) in the referenced document, resolving to that operation
|
|
250
|
+
* or workflow. A `{workflowId}.steps.{stepId}` reference resolves to that
|
|
251
|
+
* step of the referenced Arazzo document.
|
|
252
|
+
* 2. failing that, `{reference}` is matched as a field of the Source
|
|
253
|
+
* Description Object itself (e.g. `url`, `type`) — so
|
|
254
|
+
* `$sourceDescriptions.{name}.url` yields the source's URL. An operationId
|
|
255
|
+
* that collides with a field name takes precedence (tier 1 wins).
|
|
256
|
+
*
|
|
257
|
+
* Returns `undefined` when nothing matches.
|
|
258
|
+
*/
|
|
259
|
+
#sourceDescription({
|
|
260
|
+
sourceName,
|
|
261
|
+
reference,
|
|
262
|
+
stepsReference
|
|
263
|
+
}) {
|
|
264
|
+
const uri = this.#document?.resolveSourceDescriptionURI(sourceName);
|
|
265
|
+
|
|
266
|
+
// tier 1: operationId / workflowId / workflow step in the referenced document.
|
|
267
|
+
const apiDocument = uri === undefined ? undefined : this.#registry?.get(uri);
|
|
268
|
+
if (apiDocument !== undefined) {
|
|
269
|
+
if (stepsReference !== undefined) {
|
|
270
|
+
return this.#step(apiDocument, stepsReference.workflowId, stepsReference.stepId);
|
|
271
|
+
}
|
|
272
|
+
const pointer = OpenAPIDocument.is(apiDocument) ? apiDocument.operationIndex.get(reference) : ArazzoDocument.is(apiDocument) ? apiDocument.workflowIndex.get(reference) : undefined;
|
|
273
|
+
if (pointer !== undefined) return this.#drillDocument(apiDocument, pointer);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// tier 2: a field of the Source Description Object (url, type, ...).
|
|
277
|
+
return this.#document?.resolveSourceDescriptionField(sourceName, reference);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Reads a property from a context slot, or `undefined` when the slot is not
|
|
282
|
+
* an object or lacks the key. Own properties only, so prototype members
|
|
283
|
+
* (`constructor`, `toString`) never leak into a resolution.
|
|
284
|
+
*/
|
|
285
|
+
#get(slot, key) {
|
|
286
|
+
if (typeof slot !== 'object' || slot === null) return undefined;
|
|
287
|
+
if (!Object.hasOwn(slot, key)) return undefined;
|
|
288
|
+
return slot[key];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Reads a header case-insensitively. The parser already lowercases the header
|
|
293
|
+
* token, so only the context keys (populated from an HTTP response with
|
|
294
|
+
* arbitrary casing) need normalizing to match.
|
|
295
|
+
*/
|
|
296
|
+
#header(headers, token) {
|
|
297
|
+
if (headers === undefined) return undefined;
|
|
298
|
+
const key = Object.keys(headers).find(k => k.toLowerCase() === token);
|
|
299
|
+
return key === undefined ? undefined : headers[key];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Drills a JSON Pointer into a document's API element. Returns `undefined`
|
|
304
|
+
* when the document is absent or the pointer does not resolve.
|
|
305
|
+
*/
|
|
306
|
+
#drillDocument(document, pointer) {
|
|
307
|
+
return document === undefined ? undefined : this.#drill(document.parseResult.api, pointer);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Drills an optional JSON Pointer into a payload value, returning the plain
|
|
312
|
+
* runtime value. `toValue` is idempotent on plain values, so the leaf is plain
|
|
313
|
+
* whether the payload was JSON or an ApiDOM element (see `pointerRealm`).
|
|
314
|
+
*/
|
|
315
|
+
#drill(value, pointer) {
|
|
316
|
+
if (value === undefined) return undefined;
|
|
317
|
+
if (pointer === undefined) return toValue(value);
|
|
318
|
+
try {
|
|
319
|
+
return toValue(evaluateJSONPointer(value, pointer, {
|
|
320
|
+
realm: pointerRealm
|
|
321
|
+
}));
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (error instanceof JSONPointerEvaluateError) return undefined;
|
|
324
|
+
throw error;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
export default RuntimeExpressionEvaluator;
|
|
@@ -0,0 +1,48 @@
|
|
|
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 _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
9
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
10
|
+
var _apidomTraverse = require("@speclynx/apidom-traverse");
|
|
11
|
+
var _ExtractionError = _interopRequireDefault(require("../errors/ExtractionError.cjs"));
|
|
12
|
+
/**
|
|
13
|
+
* Extracts a step from an Arazzo workflow by stepId.
|
|
14
|
+
*
|
|
15
|
+
* Searches the workflow's steps array for the matching stepId.
|
|
16
|
+
* The workflow should be already extracted via ArazzoWorkflowExtractor.
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
class ArazzoStepExtractor {
|
|
20
|
+
/**
|
|
21
|
+
* Extracts a step element by stepId from a workflow.
|
|
22
|
+
*/
|
|
23
|
+
extract(workflow, stepId) {
|
|
24
|
+
const steps = workflow.steps;
|
|
25
|
+
let step;
|
|
26
|
+
if (!(0, _apidomDatamodel.isArrayElement)(steps)) {
|
|
27
|
+
throw new _ExtractionError.default(`Workflow "${(0, _apidomCore.toValue)(workflow.workflowId)}" has no steps`, {
|
|
28
|
+
workflowId: (0, _apidomCore.toValue)(workflow.workflowId)
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
(0, _apidomTraverse.traverse)(workflow, {
|
|
32
|
+
StepElement(path) {
|
|
33
|
+
if (!path.node.stepId?.equals(stepId)) return path.skip();
|
|
34
|
+
step = path.node;
|
|
35
|
+
step.meta.set('workflowId', (0, _apidomCore.toValue)(workflow.workflowId));
|
|
36
|
+
path.stop();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
if (!step) {
|
|
40
|
+
throw new _ExtractionError.default(`Step "${stepId}" not found in workflow "${(0, _apidomCore.toValue)(workflow.workflowId)}"`, {
|
|
41
|
+
workflowId: (0, _apidomCore.toValue)(workflow.workflowId),
|
|
42
|
+
stepId
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return step;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
var _default = exports.default = ArazzoStepExtractor;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { isArrayElement } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
3
|
+
import { traverse } from '@speclynx/apidom-traverse';
|
|
4
|
+
import ExtractionError from "../errors/ExtractionError.mjs";
|
|
5
|
+
/**
|
|
6
|
+
* Extracts a step from an Arazzo workflow by stepId.
|
|
7
|
+
*
|
|
8
|
+
* Searches the workflow's steps array for the matching stepId.
|
|
9
|
+
* The workflow should be already extracted via ArazzoWorkflowExtractor.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
class ArazzoStepExtractor {
|
|
13
|
+
/**
|
|
14
|
+
* Extracts a step element by stepId from a workflow.
|
|
15
|
+
*/
|
|
16
|
+
extract(workflow, stepId) {
|
|
17
|
+
const steps = workflow.steps;
|
|
18
|
+
let step;
|
|
19
|
+
if (!isArrayElement(steps)) {
|
|
20
|
+
throw new ExtractionError(`Workflow "${toValue(workflow.workflowId)}" has no steps`, {
|
|
21
|
+
workflowId: toValue(workflow.workflowId)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
traverse(workflow, {
|
|
25
|
+
StepElement(path) {
|
|
26
|
+
if (!path.node.stepId?.equals(stepId)) return path.skip();
|
|
27
|
+
step = path.node;
|
|
28
|
+
step.meta.set('workflowId', toValue(workflow.workflowId));
|
|
29
|
+
path.stop();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (!step) {
|
|
33
|
+
throw new ExtractionError(`Step "${stepId}" not found in workflow "${toValue(workflow.workflowId)}"`, {
|
|
34
|
+
workflowId: toValue(workflow.workflowId),
|
|
35
|
+
stepId
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return step;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export default ArazzoStepExtractor;
|
|
@@ -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 _apidomJsonPointer = require("@speclynx/apidom-json-pointer");
|
|
9
|
+
var _ExtractionError = _interopRequireDefault(require("../errors/ExtractionError.cjs"));
|
|
10
|
+
/**
|
|
11
|
+
* Extracts a workflow from an Arazzo document by workflowId.
|
|
12
|
+
*
|
|
13
|
+
* The workflow is already fully dereferenced in the document,
|
|
14
|
+
* so no additional processing is needed.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
class ArazzoWorkflowExtractor {
|
|
18
|
+
/**
|
|
19
|
+
* Extracts a workflow element by workflowId.
|
|
20
|
+
*/
|
|
21
|
+
extract(document, workflowId) {
|
|
22
|
+
const pointer = document.workflowIndex.get(workflowId);
|
|
23
|
+
let workflow;
|
|
24
|
+
if (pointer === undefined) {
|
|
25
|
+
throw new _ExtractionError.default(`Workflow "${workflowId}" not found in Arazzo document at "${document.uri}"`, {
|
|
26
|
+
workflowId,
|
|
27
|
+
uri: document.uri
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
workflow = (0, _apidomJsonPointer.evaluate)(document.parseResult.api, pointer);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw new _ExtractionError.default(`Failed to evaluate pointer "${pointer}" in Arazzo document at "${document.uri}"`, {
|
|
34
|
+
cause: error,
|
|
35
|
+
workflowId,
|
|
36
|
+
pointer,
|
|
37
|
+
uri: document.uri
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (workflow?.element !== 'workflow') {
|
|
41
|
+
throw new _ExtractionError.default(`Pointer "${pointer}" does not reference a workflow in Arazzo document at "${document.uri}"`, {
|
|
42
|
+
workflowId,
|
|
43
|
+
pointer,
|
|
44
|
+
uri: document.uri
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return workflow;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var _default = exports.default = ArazzoWorkflowExtractor;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { evaluate } from '@speclynx/apidom-json-pointer';
|
|
2
|
+
import ExtractionError from "../errors/ExtractionError.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Extracts a workflow from an Arazzo document by workflowId.
|
|
5
|
+
*
|
|
6
|
+
* The workflow is already fully dereferenced in the document,
|
|
7
|
+
* so no additional processing is needed.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
class ArazzoWorkflowExtractor {
|
|
11
|
+
/**
|
|
12
|
+
* Extracts a workflow element by workflowId.
|
|
13
|
+
*/
|
|
14
|
+
extract(document, workflowId) {
|
|
15
|
+
const pointer = document.workflowIndex.get(workflowId);
|
|
16
|
+
let workflow;
|
|
17
|
+
if (pointer === undefined) {
|
|
18
|
+
throw new ExtractionError(`Workflow "${workflowId}" not found in Arazzo document at "${document.uri}"`, {
|
|
19
|
+
workflowId,
|
|
20
|
+
uri: document.uri
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
workflow = evaluate(document.parseResult.api, pointer);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throw new ExtractionError(`Failed to evaluate pointer "${pointer}" in Arazzo document at "${document.uri}"`, {
|
|
27
|
+
cause: error,
|
|
28
|
+
workflowId,
|
|
29
|
+
pointer,
|
|
30
|
+
uri: document.uri
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (workflow?.element !== 'workflow') {
|
|
34
|
+
throw new ExtractionError(`Pointer "${pointer}" does not reference a workflow in Arazzo document at "${document.uri}"`, {
|
|
35
|
+
workflowId,
|
|
36
|
+
pointer,
|
|
37
|
+
uri: document.uri
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return workflow;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export default ArazzoWorkflowExtractor;
|
|
@@ -0,0 +1,84 @@
|
|
|
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 _apidomJsonPointer = require("@speclynx/apidom-json-pointer");
|
|
9
|
+
var _ExtractionError = _interopRequireDefault(require("../errors/ExtractionError.cjs"));
|
|
10
|
+
/**
|
|
11
|
+
* Extracts an operation from an OpenAPI document.
|
|
12
|
+
*
|
|
13
|
+
* Locates the operation by operationId or operationPath (JSON Pointer)
|
|
14
|
+
* and attaches metadata (pointer, method, path) to the element.
|
|
15
|
+
* The extracted operation is not dereferenced or normalized.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
class OpenAPIOperationExtractor {
|
|
19
|
+
/**
|
|
20
|
+
* Extracts an operation by operationId.
|
|
21
|
+
*/
|
|
22
|
+
extract(document, operationId) {
|
|
23
|
+
const pointer = document.operationIndex.get(operationId);
|
|
24
|
+
if (pointer === undefined) {
|
|
25
|
+
throw new _ExtractionError.default(`Operation "${operationId}" not found in OpenAPI document at "${document.uri}"`, {
|
|
26
|
+
operationId,
|
|
27
|
+
uri: document.uri
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return this.extractByPointer(document, pointer);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extracts an operation by JSON Pointer (operationPath).
|
|
35
|
+
*/
|
|
36
|
+
extractByPointer(document, pointer) {
|
|
37
|
+
let operation;
|
|
38
|
+
let tokens;
|
|
39
|
+
try {
|
|
40
|
+
tokens = (0, _apidomJsonPointer.parse)(pointer).tree;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw new _ExtractionError.default(`Failed to parse pointer "${pointer}"`, {
|
|
43
|
+
cause: error,
|
|
44
|
+
pointer,
|
|
45
|
+
uri: document.uri
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// an invalid pointer does not throw: the parse result just has no tree
|
|
49
|
+
if (tokens === undefined) {
|
|
50
|
+
throw new _ExtractionError.default(`Invalid JSON Pointer "${pointer}"`, {
|
|
51
|
+
pointer,
|
|
52
|
+
uri: document.uri
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (tokens.length !== 3 || tokens[0] !== 'paths') {
|
|
56
|
+
throw new _ExtractionError.default(`Invalid operation pointer "${pointer}": expected /paths/{path}/{method}`, {
|
|
57
|
+
pointer,
|
|
58
|
+
uri: document.uri
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
operation = (0, _apidomJsonPointer.evaluate)(document.parseResult.api, pointer);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
throw new _ExtractionError.default(`Failed to evaluate pointer "${pointer}" in OpenAPI document at "${document.uri}"`, {
|
|
65
|
+
cause: error,
|
|
66
|
+
pointer,
|
|
67
|
+
uri: document.uri
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (operation?.element !== 'operation') {
|
|
71
|
+
throw new _ExtractionError.default(`Pointer "${pointer}" does not reference an operation in OpenAPI document at "${document.uri}"`, {
|
|
72
|
+
pointer,
|
|
73
|
+
uri: document.uri
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// attach metadata for downstream consumers
|
|
78
|
+
operation.meta.set('pointer', pointer);
|
|
79
|
+
operation.meta.set('http-method', tokens[2]);
|
|
80
|
+
operation.meta.set('path', tokens[1]);
|
|
81
|
+
return operation;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
var _default = exports.default = OpenAPIOperationExtractor;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { evaluate, parse } from '@speclynx/apidom-json-pointer';
|
|
2
|
+
import ExtractionError from "../errors/ExtractionError.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Extracts an operation from an OpenAPI document.
|
|
5
|
+
*
|
|
6
|
+
* Locates the operation by operationId or operationPath (JSON Pointer)
|
|
7
|
+
* and attaches metadata (pointer, method, path) to the element.
|
|
8
|
+
* The extracted operation is not dereferenced or normalized.
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
class OpenAPIOperationExtractor {
|
|
12
|
+
/**
|
|
13
|
+
* Extracts an operation by operationId.
|
|
14
|
+
*/
|
|
15
|
+
extract(document, operationId) {
|
|
16
|
+
const pointer = document.operationIndex.get(operationId);
|
|
17
|
+
if (pointer === undefined) {
|
|
18
|
+
throw new ExtractionError(`Operation "${operationId}" not found in OpenAPI document at "${document.uri}"`, {
|
|
19
|
+
operationId,
|
|
20
|
+
uri: document.uri
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return this.extractByPointer(document, pointer);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Extracts an operation by JSON Pointer (operationPath).
|
|
28
|
+
*/
|
|
29
|
+
extractByPointer(document, pointer) {
|
|
30
|
+
let operation;
|
|
31
|
+
let tokens;
|
|
32
|
+
try {
|
|
33
|
+
tokens = parse(pointer).tree;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
throw new ExtractionError(`Failed to parse pointer "${pointer}"`, {
|
|
36
|
+
cause: error,
|
|
37
|
+
pointer,
|
|
38
|
+
uri: document.uri
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// an invalid pointer does not throw: the parse result just has no tree
|
|
42
|
+
if (tokens === undefined) {
|
|
43
|
+
throw new ExtractionError(`Invalid JSON Pointer "${pointer}"`, {
|
|
44
|
+
pointer,
|
|
45
|
+
uri: document.uri
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (tokens.length !== 3 || tokens[0] !== 'paths') {
|
|
49
|
+
throw new ExtractionError(`Invalid operation pointer "${pointer}": expected /paths/{path}/{method}`, {
|
|
50
|
+
pointer,
|
|
51
|
+
uri: document.uri
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
operation = evaluate(document.parseResult.api, pointer);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw new ExtractionError(`Failed to evaluate pointer "${pointer}" in OpenAPI document at "${document.uri}"`, {
|
|
58
|
+
cause: error,
|
|
59
|
+
pointer,
|
|
60
|
+
uri: document.uri
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (operation?.element !== 'operation') {
|
|
64
|
+
throw new ExtractionError(`Pointer "${pointer}" does not reference an operation in OpenAPI document at "${document.uri}"`, {
|
|
65
|
+
pointer,
|
|
66
|
+
uri: document.uri
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// attach metadata for downstream consumers
|
|
71
|
+
operation.meta.set('pointer', pointer);
|
|
72
|
+
operation.meta.set('http-method', tokens[2]);
|
|
73
|
+
operation.meta.set('path', tokens[1]);
|
|
74
|
+
return operation;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export default OpenAPIOperationExtractor;
|