@usearazzo/runner 0.0.0-stage → 1.0.1-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +777 -2
- package/dist/arazzo-runner.browser.js +111247 -0
- package/dist/arazzo-runner.browser.min.js +1 -0
- package/package.json +90 -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 +457 -0
- package/src/executor/OpenAPIOperationExecutor.mjs +446 -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,214 @@
|
|
|
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 _ramda = require("ramda");
|
|
9
|
+
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
10
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
11
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
12
|
+
var _resolver = require("@usearazzo/resolver");
|
|
13
|
+
var _empty = require("@speclynx/apidom-reference/configuration/empty");
|
|
14
|
+
var _ParameterIdentity = _interopRequireDefault(require("../document/ParameterIdentity.cjs"));
|
|
15
|
+
var _NormalizationError = _interopRequireDefault(require("../errors/NormalizationError.cjs"));
|
|
16
|
+
var _ArazzoDocumentRegistryProvider = require("../registry/providers/ArazzoDocumentRegistryProvider.cjs");
|
|
17
|
+
/**
|
|
18
|
+
* Options for normalizing an Arazzo workflow.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default options for normalizing an Arazzo workflow.
|
|
24
|
+
*/
|
|
25
|
+
// shallow copy to avoid mutating the provider's shared options
|
|
26
|
+
const normalizerOptionsOverride = (0, _empty.mergeOptions)(_ArazzoDocumentRegistryProvider.providerOptionsOverride, {});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Normalizes an extracted Arazzo workflow.
|
|
30
|
+
*
|
|
31
|
+
* Dereferences the workflow subtree ($components.* references),
|
|
32
|
+
* producing a self-contained workflow element, then inherits the workflow's
|
|
33
|
+
* "applicable for all steps" defaults — its `parameters`, and its
|
|
34
|
+
* `successActions` / `failureActions` — into each of its steps.
|
|
35
|
+
*
|
|
36
|
+
* All passes mutate, and what they mutate is the document itself: the extractor
|
|
37
|
+
* hands over the live workflow node out of `document.parseResult`, and
|
|
38
|
+
* dereferencing runs `immutable: false`, returning that same instance. Writing
|
|
39
|
+
* through to the document is what lets the registry act as a natural cache —
|
|
40
|
+
* a workflow reached a second time is already dereferenced and already
|
|
41
|
+
* inherited into, so no pass repeats. The inheritance is idempotent for
|
|
42
|
+
* exactly that reason.
|
|
43
|
+
*
|
|
44
|
+
* The writes differ in kind, which is worth knowing before sharing a
|
|
45
|
+
* registry. Dereferencing only *resolves* what the document already says — a
|
|
46
|
+
* `$ref` replaced by its target means the same thing. Inheritance *synthesizes*:
|
|
47
|
+
* afterwards a step carries `parameters` or an `onSuccess` its source never
|
|
48
|
+
* declared, so a consumer that reads the document back (`APIDocument.toJSON()`)
|
|
49
|
+
* sees one that no longer matches the file it was parsed from. The OpenAPI
|
|
50
|
+
* normalizers write inherited servers, parameters and security requirements into
|
|
51
|
+
* their documents the same way, so this is the layer's established contract
|
|
52
|
+
* rather than a property of Arazzo.
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
class ArazzoWorkflowNormalizer {
|
|
56
|
+
#options;
|
|
57
|
+
constructor(options = {}) {
|
|
58
|
+
this.#options = (0, _empty.mergeOptions)(normalizerOptionsOverride, options);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Dereferences the workflow subtree against its parent document, then inherits
|
|
63
|
+
* the workflow's `parameters` and default actions into its steps.
|
|
64
|
+
*/
|
|
65
|
+
async normalize(workflow, document) {
|
|
66
|
+
let dereferenced;
|
|
67
|
+
try {
|
|
68
|
+
dereferenced = await (0, _resolver.dereferenceArazzoElement)(workflow, (0, _empty.mergeOptions)(_resolver.defaultDereferenceArazzoOptions, (0, _empty.mergeOptions)(this.#options, {
|
|
69
|
+
resolve: {
|
|
70
|
+
baseURI: document.uri
|
|
71
|
+
},
|
|
72
|
+
dereference: {
|
|
73
|
+
strategyOpts: {
|
|
74
|
+
parseResult: document.parseResult
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
})));
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new _NormalizationError.default(`Failed to normalize workflow "${(0, _apidomCore.toValue)(workflow.workflowId)}" in Arazzo document at "${document.uri}"`, {
|
|
80
|
+
cause: error,
|
|
81
|
+
workflowId: (0, _apidomCore.toValue)(workflow.workflowId),
|
|
82
|
+
uri: document.uri
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// normalization (mutable) — after dereferencing, so a `parameters` or
|
|
87
|
+
// action list reaching the steps through a $components reference is
|
|
88
|
+
// inherited as a resolved Parameter / Success Action Object rather than as
|
|
89
|
+
// the Reusable Object it was written as.
|
|
90
|
+
this.#inheritParametersToSteps(dereferenced);
|
|
91
|
+
this.#inheritActionsToSteps(dereferenced);
|
|
92
|
+
return dereferenced;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Inherits the workflow's `parameters` into each of its steps.
|
|
97
|
+
*
|
|
98
|
+
* Per Arazzo 1.0.1 a workflow's `parameters` are "applicable for all steps
|
|
99
|
+
* described under this workflow" and a step's own definition "will override it
|
|
100
|
+
* but can never remove it" — so each step ends up with the union, its own
|
|
101
|
+
* declaration winning wherever the two are the same parameter by
|
|
102
|
+
* {@link ParameterIdentity}. `uniqWith` keeps the first of each equal pair,
|
|
103
|
+
* so the step's own list leads, exactly as `inheritParametersToOperation`
|
|
104
|
+
* orders an Operation's ahead of the Path Item's it inherits.
|
|
105
|
+
*
|
|
106
|
+
* That leading position is what makes the override effective and not merely
|
|
107
|
+
* present: the parameter resolvers key resolved values first-wins — by the
|
|
108
|
+
* same `(name, in)` identity for an operation step
|
|
109
|
+
* ({@link OpenAPIOperationParameterResolver}), and by bare name for a
|
|
110
|
+
* `workflowId` step's inputs ({@link WorkflowParameterResolver}) — so
|
|
111
|
+
* wherever the two collapse to one key, the earlier survives, which must be
|
|
112
|
+
* the step's.
|
|
113
|
+
*
|
|
114
|
+
* Inheriting the elements here rather than the resolved values is what lets a
|
|
115
|
+
* workflow-level `value` that is a runtime expression still be evaluated once
|
|
116
|
+
* per step, against the state that step is entered with.
|
|
117
|
+
*
|
|
118
|
+
* Not every workflow parameter is applicable to every kind of step: one
|
|
119
|
+
* without a location is a workflow-input mapping (see
|
|
120
|
+
* {@link ParameterIdentity}), so it is inherited only into steps targeting a
|
|
121
|
+
* `workflowId` — on an operation step it names no place in a request, and
|
|
122
|
+
* the resolver reports a location-less parameter there as the step's *own*
|
|
123
|
+
* authoring error, which not synthesizing one is what keeps true. The
|
|
124
|
+
* workflow's own `parameters` list is left intact; only the synthesized
|
|
125
|
+
* per-step copies are filtered.
|
|
126
|
+
*
|
|
127
|
+
* A malformed `steps` or `parameters` is left for the executor to report as
|
|
128
|
+
* the authoring error it is; there is nothing to inherit through it here, and
|
|
129
|
+
* a step whose own `parameters` is present but not a list is skipped rather
|
|
130
|
+
* than handed a synthesized one — overwriting it would erase the very thing
|
|
131
|
+
* that makes the document invalid and leave nothing to report. An entry
|
|
132
|
+
* *within* either list that is not a Parameter Object is carried across
|
|
133
|
+
* untouched rather than filtered out, for the same reason: rebuilding a step's
|
|
134
|
+
* list is no licence to drop what its author wrote, and the parameter
|
|
135
|
+
* resolvers ignore it anyway. A parameter whose location is malformed (`in: 1`) is
|
|
136
|
+
* likewise carried, for the resolver to report loudly.
|
|
137
|
+
*/
|
|
138
|
+
#inheritParametersToSteps(workflow) {
|
|
139
|
+
const inherited = workflow.parameters;
|
|
140
|
+
if (!(0, _apidomDatamodel.isArrayElement)(inherited) || inherited.isEmpty) return;
|
|
141
|
+
if (!(0, _apidomDatamodel.isArrayElement)(workflow.steps)) return;
|
|
142
|
+
const inheritedParameters = [...inherited];
|
|
143
|
+
// what an operation step may inherit — the input-shaped entries filtered
|
|
144
|
+
// out once, ahead of the per-step loop
|
|
145
|
+
const requestShaped = inheritedParameters.filter(parameter => !(0, _apidomNsArazzo.isParameterElement)(parameter) || _ParameterIdentity.default.locationOf(parameter) !== undefined);
|
|
146
|
+
for (const step of workflow.steps) {
|
|
147
|
+
if (!(0, _apidomNsArazzo.isStepElement)(step)) continue;
|
|
148
|
+
if (step.parameters !== undefined && !(0, _apidomDatamodel.isArrayElement)(step.parameters)) continue;
|
|
149
|
+
|
|
150
|
+
// when nothing applicable remains AND the step declares no list of its
|
|
151
|
+
// own, there is nothing to synthesize. A step with its own list is still
|
|
152
|
+
// rebuilt, so its duplicates collapse the same way whichever kind of
|
|
153
|
+
// step it is — not depending on what the workflow happened to contribute
|
|
154
|
+
const applicable = (0, _apidomDatamodel.isStringElement)(step.workflowId) ? inheritedParameters : requestShaped;
|
|
155
|
+
if (applicable.length === 0 && step.parameters === undefined) continue;
|
|
156
|
+
const own = (0, _apidomDatamodel.isArrayElement)(step.parameters) ? [...step.parameters] : [];
|
|
157
|
+
step.parameters = new _apidomNsArazzo.StepParametersElement((0, _ramda.uniqWith)(_ParameterIdentity.default.equal, [...own, ...applicable]));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Inherits the workflow's `successActions` / `failureActions` into each step
|
|
163
|
+
* that declares no `onSuccess` / `onFailure` of its own.
|
|
164
|
+
*
|
|
165
|
+
* Per Arazzo 1.0.1 both lists are "applicable for all steps described under
|
|
166
|
+
* this workflow", and a step's own list **overrides** the corresponding
|
|
167
|
+
* workflow one — wholesale, with no per-action merge, which is where this
|
|
168
|
+
* differs from the parameters above. Success and failure fall back
|
|
169
|
+
* independently: a step may override only its `onFailure` and still inherit
|
|
170
|
+
* the workflow's `successActions`.
|
|
171
|
+
*
|
|
172
|
+
* Presence is tested with `hasKey`, not truthiness: a step declaring an empty
|
|
173
|
+
* list (`onSuccess: []`) has *overridden* the default with an empty set of
|
|
174
|
+
* actions, not asked for one — it is skipped, as is a step whose `onSuccess`
|
|
175
|
+
* is present but not a list, for the same reason the parameters pass leaves a
|
|
176
|
+
* malformed list alone. Testing the key is also what makes the pass
|
|
177
|
+
* idempotent: after the first run the step has it, so a workflow reached again
|
|
178
|
+
* through the registry cache is skipped.
|
|
179
|
+
*
|
|
180
|
+
* Unlike parameters there is no step-kind filter — an action names a
|
|
181
|
+
* transition within the workflow, which is as meaningful for a step targeting
|
|
182
|
+
* a `workflowId` as for one invoking an operation, so both kinds take the
|
|
183
|
+
* defaults.
|
|
184
|
+
*
|
|
185
|
+
* The workflow's own action *elements* are shared into the steps rather than
|
|
186
|
+
* copied, matching what falling back to one shared list did before: retry
|
|
187
|
+
* budgets are keyed by action element identity ({@link StepRetryRunner}) and
|
|
188
|
+
* held per `run()` call, so steps sharing an inherited `retry` share nothing
|
|
189
|
+
* that outlives the attempt loop.
|
|
190
|
+
*/
|
|
191
|
+
#inheritActionsToSteps(workflow) {
|
|
192
|
+
if (!(0, _apidomDatamodel.isArrayElement)(workflow.steps)) return;
|
|
193
|
+
const {
|
|
194
|
+
successActions,
|
|
195
|
+
failureActions
|
|
196
|
+
} = workflow;
|
|
197
|
+
// an empty list defaults to nothing, which is what declaring no list
|
|
198
|
+
// already means — synthesizing one would only move the document further
|
|
199
|
+
// from its source for no change in behavior.
|
|
200
|
+
const inheritSuccess = (0, _apidomDatamodel.isArrayElement)(successActions) && !successActions.isEmpty;
|
|
201
|
+
const inheritFailure = (0, _apidomDatamodel.isArrayElement)(failureActions) && !failureActions.isEmpty;
|
|
202
|
+
if (!inheritSuccess && !inheritFailure) return;
|
|
203
|
+
for (const step of workflow.steps) {
|
|
204
|
+
if (!(0, _apidomNsArazzo.isStepElement)(step)) continue;
|
|
205
|
+
if (inheritSuccess && !step.hasKey('onSuccess')) {
|
|
206
|
+
step.onSuccess = new _apidomNsArazzo.StepOnSuccessElement([...successActions]);
|
|
207
|
+
}
|
|
208
|
+
if (inheritFailure && !step.hasKey('onFailure')) {
|
|
209
|
+
step.onFailure = new _apidomNsArazzo.StepOnFailureElement([...failureActions]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
var _default = exports.default = ArazzoWorkflowNormalizer;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { uniqWith } from 'ramda';
|
|
2
|
+
import { isParameterElement, isStepElement, StepParametersElement, StepOnSuccessElement, StepOnFailureElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
3
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
4
|
+
import { isArrayElement, isStringElement } from '@speclynx/apidom-datamodel';
|
|
5
|
+
import { dereferenceArazzoElement, defaultDereferenceArazzoOptions } from '@usearazzo/resolver';
|
|
6
|
+
import { mergeOptions } from '@speclynx/apidom-reference/configuration/empty';
|
|
7
|
+
import ParameterIdentity from "../document/ParameterIdentity.mjs";
|
|
8
|
+
import NormalizationError from "../errors/NormalizationError.mjs";
|
|
9
|
+
import { providerOptionsOverride as arazzoProviderOptions } from "../registry/providers/ArazzoDocumentRegistryProvider.mjs";
|
|
10
|
+
/**
|
|
11
|
+
* Options for normalizing an Arazzo workflow.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Default options for normalizing an Arazzo workflow.
|
|
16
|
+
*/
|
|
17
|
+
// shallow copy to avoid mutating the provider's shared options
|
|
18
|
+
const normalizerOptionsOverride = mergeOptions(arazzoProviderOptions, {});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes an extracted Arazzo workflow.
|
|
22
|
+
*
|
|
23
|
+
* Dereferences the workflow subtree ($components.* references),
|
|
24
|
+
* producing a self-contained workflow element, then inherits the workflow's
|
|
25
|
+
* "applicable for all steps" defaults — its `parameters`, and its
|
|
26
|
+
* `successActions` / `failureActions` — into each of its steps.
|
|
27
|
+
*
|
|
28
|
+
* All passes mutate, and what they mutate is the document itself: the extractor
|
|
29
|
+
* hands over the live workflow node out of `document.parseResult`, and
|
|
30
|
+
* dereferencing runs `immutable: false`, returning that same instance. Writing
|
|
31
|
+
* through to the document is what lets the registry act as a natural cache —
|
|
32
|
+
* a workflow reached a second time is already dereferenced and already
|
|
33
|
+
* inherited into, so no pass repeats. The inheritance is idempotent for
|
|
34
|
+
* exactly that reason.
|
|
35
|
+
*
|
|
36
|
+
* The writes differ in kind, which is worth knowing before sharing a
|
|
37
|
+
* registry. Dereferencing only *resolves* what the document already says — a
|
|
38
|
+
* `$ref` replaced by its target means the same thing. Inheritance *synthesizes*:
|
|
39
|
+
* afterwards a step carries `parameters` or an `onSuccess` its source never
|
|
40
|
+
* declared, so a consumer that reads the document back (`APIDocument.toJSON()`)
|
|
41
|
+
* sees one that no longer matches the file it was parsed from. The OpenAPI
|
|
42
|
+
* normalizers write inherited servers, parameters and security requirements into
|
|
43
|
+
* their documents the same way, so this is the layer's established contract
|
|
44
|
+
* rather than a property of Arazzo.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
class ArazzoWorkflowNormalizer {
|
|
48
|
+
#options;
|
|
49
|
+
constructor(options = {}) {
|
|
50
|
+
this.#options = mergeOptions(normalizerOptionsOverride, options);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Dereferences the workflow subtree against its parent document, then inherits
|
|
55
|
+
* the workflow's `parameters` and default actions into its steps.
|
|
56
|
+
*/
|
|
57
|
+
async normalize(workflow, document) {
|
|
58
|
+
let dereferenced;
|
|
59
|
+
try {
|
|
60
|
+
dereferenced = await dereferenceArazzoElement(workflow, mergeOptions(defaultDereferenceArazzoOptions, mergeOptions(this.#options, {
|
|
61
|
+
resolve: {
|
|
62
|
+
baseURI: document.uri
|
|
63
|
+
},
|
|
64
|
+
dereference: {
|
|
65
|
+
strategyOpts: {
|
|
66
|
+
parseResult: document.parseResult
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
})));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw new NormalizationError(`Failed to normalize workflow "${toValue(workflow.workflowId)}" in Arazzo document at "${document.uri}"`, {
|
|
72
|
+
cause: error,
|
|
73
|
+
workflowId: toValue(workflow.workflowId),
|
|
74
|
+
uri: document.uri
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// normalization (mutable) — after dereferencing, so a `parameters` or
|
|
79
|
+
// action list reaching the steps through a $components reference is
|
|
80
|
+
// inherited as a resolved Parameter / Success Action Object rather than as
|
|
81
|
+
// the Reusable Object it was written as.
|
|
82
|
+
this.#inheritParametersToSteps(dereferenced);
|
|
83
|
+
this.#inheritActionsToSteps(dereferenced);
|
|
84
|
+
return dereferenced;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Inherits the workflow's `parameters` into each of its steps.
|
|
89
|
+
*
|
|
90
|
+
* Per Arazzo 1.0.1 a workflow's `parameters` are "applicable for all steps
|
|
91
|
+
* described under this workflow" and a step's own definition "will override it
|
|
92
|
+
* but can never remove it" — so each step ends up with the union, its own
|
|
93
|
+
* declaration winning wherever the two are the same parameter by
|
|
94
|
+
* {@link ParameterIdentity}. `uniqWith` keeps the first of each equal pair,
|
|
95
|
+
* so the step's own list leads, exactly as `inheritParametersToOperation`
|
|
96
|
+
* orders an Operation's ahead of the Path Item's it inherits.
|
|
97
|
+
*
|
|
98
|
+
* That leading position is what makes the override effective and not merely
|
|
99
|
+
* present: the parameter resolvers key resolved values first-wins — by the
|
|
100
|
+
* same `(name, in)` identity for an operation step
|
|
101
|
+
* ({@link OpenAPIOperationParameterResolver}), and by bare name for a
|
|
102
|
+
* `workflowId` step's inputs ({@link WorkflowParameterResolver}) — so
|
|
103
|
+
* wherever the two collapse to one key, the earlier survives, which must be
|
|
104
|
+
* the step's.
|
|
105
|
+
*
|
|
106
|
+
* Inheriting the elements here rather than the resolved values is what lets a
|
|
107
|
+
* workflow-level `value` that is a runtime expression still be evaluated once
|
|
108
|
+
* per step, against the state that step is entered with.
|
|
109
|
+
*
|
|
110
|
+
* Not every workflow parameter is applicable to every kind of step: one
|
|
111
|
+
* without a location is a workflow-input mapping (see
|
|
112
|
+
* {@link ParameterIdentity}), so it is inherited only into steps targeting a
|
|
113
|
+
* `workflowId` — on an operation step it names no place in a request, and
|
|
114
|
+
* the resolver reports a location-less parameter there as the step's *own*
|
|
115
|
+
* authoring error, which not synthesizing one is what keeps true. The
|
|
116
|
+
* workflow's own `parameters` list is left intact; only the synthesized
|
|
117
|
+
* per-step copies are filtered.
|
|
118
|
+
*
|
|
119
|
+
* A malformed `steps` or `parameters` is left for the executor to report as
|
|
120
|
+
* the authoring error it is; there is nothing to inherit through it here, and
|
|
121
|
+
* a step whose own `parameters` is present but not a list is skipped rather
|
|
122
|
+
* than handed a synthesized one — overwriting it would erase the very thing
|
|
123
|
+
* that makes the document invalid and leave nothing to report. An entry
|
|
124
|
+
* *within* either list that is not a Parameter Object is carried across
|
|
125
|
+
* untouched rather than filtered out, for the same reason: rebuilding a step's
|
|
126
|
+
* list is no licence to drop what its author wrote, and the parameter
|
|
127
|
+
* resolvers ignore it anyway. A parameter whose location is malformed (`in: 1`) is
|
|
128
|
+
* likewise carried, for the resolver to report loudly.
|
|
129
|
+
*/
|
|
130
|
+
#inheritParametersToSteps(workflow) {
|
|
131
|
+
const inherited = workflow.parameters;
|
|
132
|
+
if (!isArrayElement(inherited) || inherited.isEmpty) return;
|
|
133
|
+
if (!isArrayElement(workflow.steps)) return;
|
|
134
|
+
const inheritedParameters = [...inherited];
|
|
135
|
+
// what an operation step may inherit — the input-shaped entries filtered
|
|
136
|
+
// out once, ahead of the per-step loop
|
|
137
|
+
const requestShaped = inheritedParameters.filter(parameter => !isParameterElement(parameter) || ParameterIdentity.locationOf(parameter) !== undefined);
|
|
138
|
+
for (const step of workflow.steps) {
|
|
139
|
+
if (!isStepElement(step)) continue;
|
|
140
|
+
if (step.parameters !== undefined && !isArrayElement(step.parameters)) continue;
|
|
141
|
+
|
|
142
|
+
// when nothing applicable remains AND the step declares no list of its
|
|
143
|
+
// own, there is nothing to synthesize. A step with its own list is still
|
|
144
|
+
// rebuilt, so its duplicates collapse the same way whichever kind of
|
|
145
|
+
// step it is — not depending on what the workflow happened to contribute
|
|
146
|
+
const applicable = isStringElement(step.workflowId) ? inheritedParameters : requestShaped;
|
|
147
|
+
if (applicable.length === 0 && step.parameters === undefined) continue;
|
|
148
|
+
const own = isArrayElement(step.parameters) ? [...step.parameters] : [];
|
|
149
|
+
step.parameters = new StepParametersElement(uniqWith(ParameterIdentity.equal, [...own, ...applicable]));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Inherits the workflow's `successActions` / `failureActions` into each step
|
|
155
|
+
* that declares no `onSuccess` / `onFailure` of its own.
|
|
156
|
+
*
|
|
157
|
+
* Per Arazzo 1.0.1 both lists are "applicable for all steps described under
|
|
158
|
+
* this workflow", and a step's own list **overrides** the corresponding
|
|
159
|
+
* workflow one — wholesale, with no per-action merge, which is where this
|
|
160
|
+
* differs from the parameters above. Success and failure fall back
|
|
161
|
+
* independently: a step may override only its `onFailure` and still inherit
|
|
162
|
+
* the workflow's `successActions`.
|
|
163
|
+
*
|
|
164
|
+
* Presence is tested with `hasKey`, not truthiness: a step declaring an empty
|
|
165
|
+
* list (`onSuccess: []`) has *overridden* the default with an empty set of
|
|
166
|
+
* actions, not asked for one — it is skipped, as is a step whose `onSuccess`
|
|
167
|
+
* is present but not a list, for the same reason the parameters pass leaves a
|
|
168
|
+
* malformed list alone. Testing the key is also what makes the pass
|
|
169
|
+
* idempotent: after the first run the step has it, so a workflow reached again
|
|
170
|
+
* through the registry cache is skipped.
|
|
171
|
+
*
|
|
172
|
+
* Unlike parameters there is no step-kind filter — an action names a
|
|
173
|
+
* transition within the workflow, which is as meaningful for a step targeting
|
|
174
|
+
* a `workflowId` as for one invoking an operation, so both kinds take the
|
|
175
|
+
* defaults.
|
|
176
|
+
*
|
|
177
|
+
* The workflow's own action *elements* are shared into the steps rather than
|
|
178
|
+
* copied, matching what falling back to one shared list did before: retry
|
|
179
|
+
* budgets are keyed by action element identity ({@link StepRetryRunner}) and
|
|
180
|
+
* held per `run()` call, so steps sharing an inherited `retry` share nothing
|
|
181
|
+
* that outlives the attempt loop.
|
|
182
|
+
*/
|
|
183
|
+
#inheritActionsToSteps(workflow) {
|
|
184
|
+
if (!isArrayElement(workflow.steps)) return;
|
|
185
|
+
const {
|
|
186
|
+
successActions,
|
|
187
|
+
failureActions
|
|
188
|
+
} = workflow;
|
|
189
|
+
// an empty list defaults to nothing, which is what declaring no list
|
|
190
|
+
// already means — synthesizing one would only move the document further
|
|
191
|
+
// from its source for no change in behavior.
|
|
192
|
+
const inheritSuccess = isArrayElement(successActions) && !successActions.isEmpty;
|
|
193
|
+
const inheritFailure = isArrayElement(failureActions) && !failureActions.isEmpty;
|
|
194
|
+
if (!inheritSuccess && !inheritFailure) return;
|
|
195
|
+
for (const step of workflow.steps) {
|
|
196
|
+
if (!isStepElement(step)) continue;
|
|
197
|
+
if (inheritSuccess && !step.hasKey('onSuccess')) {
|
|
198
|
+
step.onSuccess = new StepOnSuccessElement([...successActions]);
|
|
199
|
+
}
|
|
200
|
+
if (inheritFailure && !step.hasKey('onFailure')) {
|
|
201
|
+
step.onFailure = new StepOnFailureElement([...failureActions]);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
export default ArazzoWorkflowNormalizer;
|
|
@@ -0,0 +1,128 @@
|
|
|
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 _apidomCore = require("@speclynx/apidom-core");
|
|
9
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
10
|
+
var _resolver = require("@usearazzo/resolver");
|
|
11
|
+
var _empty = require("@speclynx/apidom-reference/configuration/empty");
|
|
12
|
+
var _apidomJsonPointer = require("@speclynx/apidom-json-pointer");
|
|
13
|
+
var _openapi = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/openapi-2"));
|
|
14
|
+
var _apidomNsOpenapi = require("@speclynx/apidom-ns-openapi-2");
|
|
15
|
+
var _NormalizationError = _interopRequireDefault(require("../errors/NormalizationError.cjs"));
|
|
16
|
+
var _OpenAPIDocumentRegistryProvider = require("../registry/providers/OpenAPIDocumentRegistryProvider.cjs");
|
|
17
|
+
/**
|
|
18
|
+
* Options for normalizing an OpenAPI 2.0 operation.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const normalizerOptionsOverride = (0, _empty.mergeOptions)(_OpenAPIDocumentRegistryProvider.providerOptionsOverride, {
|
|
23
|
+
dereference: {
|
|
24
|
+
strategies: [new _openapi.default()]
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Version-specific normalization for OpenAPI 2.0 (Swagger) operations.
|
|
30
|
+
*
|
|
31
|
+
* Dereferences the operation subtree and handles merging of
|
|
32
|
+
* parameters and security from path item and root levels.
|
|
33
|
+
* OpenAPI 2.0 does not support servers at path item or operation level;
|
|
34
|
+
* host/basePath/schemes are root-level only and handled at execution time.
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
class OpenAPI2OperationNormalizer {
|
|
38
|
+
#options;
|
|
39
|
+
constructor(options = {}) {
|
|
40
|
+
this.#options = (0, _empty.mergeOptions)(normalizerOptionsOverride, options);
|
|
41
|
+
}
|
|
42
|
+
async normalize(operation, document) {
|
|
43
|
+
const operationPointer = (0, _apidomCore.toValue)(operation.meta.get('pointer'));
|
|
44
|
+
if (!(0, _apidomJsonPointer.testJSONPointer)(operationPointer)) {
|
|
45
|
+
throw new _NormalizationError.default(`Operation is missing valid "pointer" metadata. Was it produced by OpenAPIOperationExtractor?`, {
|
|
46
|
+
operationId: (0, _apidomCore.toValue)(operation.operationId),
|
|
47
|
+
uri: document.uri,
|
|
48
|
+
operationPointer
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const tokens = (0, _apidomJsonPointer.parse)(operationPointer).tree;
|
|
52
|
+
const pathItemPointer = (0, _apidomJsonPointer.compile)(tokens.slice(0, -1));
|
|
53
|
+
let pathItem;
|
|
54
|
+
try {
|
|
55
|
+
pathItem = (0, _apidomJsonPointer.evaluate)(document.parseResult.api, pathItemPointer);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw new _NormalizationError.default(`Failed to evaluate path item pointer "${pathItemPointer}" in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
58
|
+
cause: error,
|
|
59
|
+
operationId: (0, _apidomCore.toValue)(operation.operationId),
|
|
60
|
+
uri: document.uri,
|
|
61
|
+
operationPointer,
|
|
62
|
+
pathItemPointer
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (!(0, _apidomNsOpenapi.isPathItemElement)(pathItem)) {
|
|
66
|
+
throw new _NormalizationError.default(`Pointer "${pathItemPointer}" does not reference a path item in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
67
|
+
operationId: (0, _apidomCore.toValue)(operation.operationId),
|
|
68
|
+
uri: document.uri,
|
|
69
|
+
operationPointer,
|
|
70
|
+
pathItemPointer
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// preparing data for normalization by lazy dereferencing
|
|
75
|
+
const entry = document.parseResult.api;
|
|
76
|
+
const operationDeref = await this.#dereferenceOperation(operation, document);
|
|
77
|
+
|
|
78
|
+
// dereferencing Path Item Parameter Object references
|
|
79
|
+
if ((0, _apidomDatamodel.isArrayElement)(pathItem.parameters)) {
|
|
80
|
+
pathItem.parameters = await this.#dereferencePathItemParameters(pathItem, document);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// normalization (mutable) — no servers in OpenAPI 2.0
|
|
84
|
+
_apidomNsOpenapi.refractorPluginNormalizeParameters.inheritParametersToOperation(operationDeref, pathItem);
|
|
85
|
+
_apidomNsOpenapi.refractorPluginNormalizeSecurityRequirements.inheritSecurityToOperation(operationDeref, entry);
|
|
86
|
+
return operationDeref;
|
|
87
|
+
}
|
|
88
|
+
async #dereferenceOperation(operation, document) {
|
|
89
|
+
try {
|
|
90
|
+
return await (0, _resolver.dereferenceOpenAPIElement)(operation, (0, _empty.mergeOptions)(_resolver.defaultDereferenceOpenAPIOptions, (0, _empty.mergeOptions)(this.#options, {
|
|
91
|
+
resolve: {
|
|
92
|
+
baseURI: document.uri
|
|
93
|
+
},
|
|
94
|
+
dereference: {
|
|
95
|
+
strategyOpts: {
|
|
96
|
+
parseResult: document.parseResult
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
})));
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new _NormalizationError.default(`Failed to dereference Operation("${(0, _apidomCore.toValue)(operation.operationId)}") in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
102
|
+
cause: error,
|
|
103
|
+
operationId: (0, _apidomCore.toValue)(operation.operationId),
|
|
104
|
+
uri: document.uri
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async #dereferencePathItemParameters(pathItem, document) {
|
|
109
|
+
try {
|
|
110
|
+
return await (0, _resolver.dereferenceOpenAPIElement)(pathItem.parameters, (0, _empty.mergeOptions)(_resolver.defaultDereferenceOpenAPIOptions, (0, _empty.mergeOptions)(this.#options, {
|
|
111
|
+
resolve: {
|
|
112
|
+
baseURI: document.uri
|
|
113
|
+
},
|
|
114
|
+
dereference: {
|
|
115
|
+
strategyOpts: {
|
|
116
|
+
parseResult: document.parseResult
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
})));
|
|
120
|
+
} catch (error) {
|
|
121
|
+
throw new _NormalizationError.default(`Failed to dereference Path Item parameters in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
122
|
+
cause: error,
|
|
123
|
+
uri: document.uri
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
var _default = exports.default = OpenAPI2OperationNormalizer;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
2
|
+
import { isArrayElement } from '@speclynx/apidom-datamodel';
|
|
3
|
+
import { dereferenceOpenAPIElement, defaultDereferenceOpenAPIOptions } from '@usearazzo/resolver';
|
|
4
|
+
import { mergeOptions } from '@speclynx/apidom-reference/configuration/empty';
|
|
5
|
+
import { evaluate, parse, compile, testJSONPointer } from '@speclynx/apidom-json-pointer';
|
|
6
|
+
import OpenAPI2DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/openapi-2';
|
|
7
|
+
import { isPathItemElement, refractorPluginNormalizeParameters, refractorPluginNormalizeSecurityRequirements } from '@speclynx/apidom-ns-openapi-2';
|
|
8
|
+
import NormalizationError from "../errors/NormalizationError.mjs";
|
|
9
|
+
import { providerOptionsOverride as openAPIProviderOptions } from "../registry/providers/OpenAPIDocumentRegistryProvider.mjs";
|
|
10
|
+
/**
|
|
11
|
+
* Options for normalizing an OpenAPI 2.0 operation.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
const normalizerOptionsOverride = mergeOptions(openAPIProviderOptions, {
|
|
15
|
+
dereference: {
|
|
16
|
+
strategies: [new OpenAPI2DereferenceStrategy()]
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Version-specific normalization for OpenAPI 2.0 (Swagger) operations.
|
|
22
|
+
*
|
|
23
|
+
* Dereferences the operation subtree and handles merging of
|
|
24
|
+
* parameters and security from path item and root levels.
|
|
25
|
+
* OpenAPI 2.0 does not support servers at path item or operation level;
|
|
26
|
+
* host/basePath/schemes are root-level only and handled at execution time.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
class OpenAPI2OperationNormalizer {
|
|
30
|
+
#options;
|
|
31
|
+
constructor(options = {}) {
|
|
32
|
+
this.#options = mergeOptions(normalizerOptionsOverride, options);
|
|
33
|
+
}
|
|
34
|
+
async normalize(operation, document) {
|
|
35
|
+
const operationPointer = toValue(operation.meta.get('pointer'));
|
|
36
|
+
if (!testJSONPointer(operationPointer)) {
|
|
37
|
+
throw new NormalizationError(`Operation is missing valid "pointer" metadata. Was it produced by OpenAPIOperationExtractor?`, {
|
|
38
|
+
operationId: toValue(operation.operationId),
|
|
39
|
+
uri: document.uri,
|
|
40
|
+
operationPointer
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const tokens = parse(operationPointer).tree;
|
|
44
|
+
const pathItemPointer = compile(tokens.slice(0, -1));
|
|
45
|
+
let pathItem;
|
|
46
|
+
try {
|
|
47
|
+
pathItem = evaluate(document.parseResult.api, pathItemPointer);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw new NormalizationError(`Failed to evaluate path item pointer "${pathItemPointer}" in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
50
|
+
cause: error,
|
|
51
|
+
operationId: toValue(operation.operationId),
|
|
52
|
+
uri: document.uri,
|
|
53
|
+
operationPointer,
|
|
54
|
+
pathItemPointer
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (!isPathItemElement(pathItem)) {
|
|
58
|
+
throw new NormalizationError(`Pointer "${pathItemPointer}" does not reference a path item in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
59
|
+
operationId: toValue(operation.operationId),
|
|
60
|
+
uri: document.uri,
|
|
61
|
+
operationPointer,
|
|
62
|
+
pathItemPointer
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// preparing data for normalization by lazy dereferencing
|
|
67
|
+
const entry = document.parseResult.api;
|
|
68
|
+
const operationDeref = await this.#dereferenceOperation(operation, document);
|
|
69
|
+
|
|
70
|
+
// dereferencing Path Item Parameter Object references
|
|
71
|
+
if (isArrayElement(pathItem.parameters)) {
|
|
72
|
+
pathItem.parameters = await this.#dereferencePathItemParameters(pathItem, document);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// normalization (mutable) — no servers in OpenAPI 2.0
|
|
76
|
+
refractorPluginNormalizeParameters.inheritParametersToOperation(operationDeref, pathItem);
|
|
77
|
+
refractorPluginNormalizeSecurityRequirements.inheritSecurityToOperation(operationDeref, entry);
|
|
78
|
+
return operationDeref;
|
|
79
|
+
}
|
|
80
|
+
async #dereferenceOperation(operation, document) {
|
|
81
|
+
try {
|
|
82
|
+
return await dereferenceOpenAPIElement(operation, mergeOptions(defaultDereferenceOpenAPIOptions, mergeOptions(this.#options, {
|
|
83
|
+
resolve: {
|
|
84
|
+
baseURI: document.uri
|
|
85
|
+
},
|
|
86
|
+
dereference: {
|
|
87
|
+
strategyOpts: {
|
|
88
|
+
parseResult: document.parseResult
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
})));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
throw new NormalizationError(`Failed to dereference Operation("${toValue(operation.operationId)}") in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
94
|
+
cause: error,
|
|
95
|
+
operationId: toValue(operation.operationId),
|
|
96
|
+
uri: document.uri
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async #dereferencePathItemParameters(pathItem, document) {
|
|
101
|
+
try {
|
|
102
|
+
return await dereferenceOpenAPIElement(pathItem.parameters, mergeOptions(defaultDereferenceOpenAPIOptions, mergeOptions(this.#options, {
|
|
103
|
+
resolve: {
|
|
104
|
+
baseURI: document.uri
|
|
105
|
+
},
|
|
106
|
+
dereference: {
|
|
107
|
+
strategyOpts: {
|
|
108
|
+
parseResult: document.parseResult
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
})));
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new NormalizationError(`Failed to dereference Path Item parameters in OpenAPI 2.0 document at "${document.uri}"`, {
|
|
114
|
+
cause: error,
|
|
115
|
+
uri: document.uri
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export default OpenAPI2OperationNormalizer;
|