@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.
Files changed (152) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +20 -0
  4. package/README.md +777 -2
  5. package/dist/arazzo-runner.browser.js +113254 -0
  6. package/dist/arazzo-runner.browser.min.js +1 -0
  7. package/package.json +91 -4
  8. package/src/action/ActionResolver.cjs +160 -0
  9. package/src/action/ActionResolver.mjs +150 -0
  10. package/src/assembler/OpenAPI2DocumentAssembler.cjs +111 -0
  11. package/src/assembler/OpenAPI2DocumentAssembler.mjs +104 -0
  12. package/src/assembler/OpenAPI30DocumentAssembler.cjs +110 -0
  13. package/src/assembler/OpenAPI30DocumentAssembler.mjs +103 -0
  14. package/src/assembler/OpenAPI31DocumentAssembler.cjs +111 -0
  15. package/src/assembler/OpenAPI31DocumentAssembler.mjs +104 -0
  16. package/src/assembler/OpenAPIDocumentAssembler.cjs +58 -0
  17. package/src/assembler/OpenAPIDocumentAssembler.mjs +50 -0
  18. package/src/client/HTTPClient.cjs +5 -0
  19. package/src/client/HTTPClient.mjs +1 -0
  20. package/src/client/HTTPClientFetch.cjs +16 -0
  21. package/src/client/HTTPClientFetch.mjs +10 -0
  22. package/src/client/OpenAPIOperationRequest.cjs +5 -0
  23. package/src/client/OpenAPIOperationRequest.mjs +1 -0
  24. package/src/client/OpenAPIOperationResponse.cjs +42 -0
  25. package/src/client/OpenAPIOperationResponse.mjs +36 -0
  26. package/src/client/OpenAPIOperationResponseNormalizer.cjs +48 -0
  27. package/src/client/OpenAPIOperationResponseNormalizer.mjs +40 -0
  28. package/src/client/ParameterDelivery.cjs +119 -0
  29. package/src/client/ParameterDelivery.mjs +113 -0
  30. package/src/constants.cjs +9 -0
  31. package/src/constants.mjs +3 -0
  32. package/src/criterion/CriterionEvaluator.cjs +205 -0
  33. package/src/criterion/CriterionEvaluator.mjs +196 -0
  34. package/src/criterion/JSONPathCriterionEvaluator.cjs +47 -0
  35. package/src/criterion/JSONPathCriterionEvaluator.mjs +40 -0
  36. package/src/criterion/RegexCriterionEvaluator.cjs +67 -0
  37. package/src/criterion/RegexCriterionEvaluator.mjs +60 -0
  38. package/src/criterion/SimpleCriterionEvaluator.cjs +50 -0
  39. package/src/criterion/SimpleCriterionEvaluator.mjs +43 -0
  40. package/src/criterion/XPathCriterionEvaluator.cjs +117 -0
  41. package/src/criterion/XPathCriterionEvaluator.mjs +109 -0
  42. package/src/document/APIDocument.cjs +35 -0
  43. package/src/document/APIDocument.mjs +30 -0
  44. package/src/document/ArazzoDocument.cjs +81 -0
  45. package/src/document/ArazzoDocument.mjs +74 -0
  46. package/src/document/ArazzoSourceDescriptionIndex.cjs +26 -0
  47. package/src/document/ArazzoSourceDescriptionIndex.mjs +20 -0
  48. package/src/document/ArazzoStepIndex.cjs +25 -0
  49. package/src/document/ArazzoStepIndex.mjs +19 -0
  50. package/src/document/ArazzoWorkflowIndex.cjs +17 -0
  51. package/src/document/ArazzoWorkflowIndex.mjs +11 -0
  52. package/src/document/OpenAPIDocument.cjs +28 -0
  53. package/src/document/OpenAPIDocument.mjs +21 -0
  54. package/src/document/OpenAPIOperationIndex.cjs +24 -0
  55. package/src/document/OpenAPIOperationIndex.mjs +18 -0
  56. package/src/document/ParameterIdentity.cjs +93 -0
  57. package/src/document/ParameterIdentity.mjs +88 -0
  58. package/src/document/openapi-types.cjs +5 -0
  59. package/src/document/openapi-types.mjs +1 -0
  60. package/src/errors/ArazzoRunnerError.cjs +10 -0
  61. package/src/errors/ArazzoRunnerError.mjs +5 -0
  62. package/src/errors/AssemblerError.cjs +11 -0
  63. package/src/errors/AssemblerError.mjs +4 -0
  64. package/src/errors/ClientError.cjs +11 -0
  65. package/src/errors/ClientError.mjs +4 -0
  66. package/src/errors/CriterionError.cjs +11 -0
  67. package/src/errors/CriterionError.mjs +4 -0
  68. package/src/errors/ExecutionError.cjs +11 -0
  69. package/src/errors/ExecutionError.mjs +4 -0
  70. package/src/errors/ExtractionError.cjs +11 -0
  71. package/src/errors/ExtractionError.mjs +4 -0
  72. package/src/errors/InvalidEntryDocumentError.cjs +11 -0
  73. package/src/errors/InvalidEntryDocumentError.mjs +4 -0
  74. package/src/errors/NormalizationError.cjs +11 -0
  75. package/src/errors/NormalizationError.mjs +4 -0
  76. package/src/errors/ResolverError.cjs +11 -0
  77. package/src/errors/ResolverError.mjs +4 -0
  78. package/src/errors/RuntimeExpressionError.cjs +11 -0
  79. package/src/errors/RuntimeExpressionError.mjs +4 -0
  80. package/src/errors/UnmatchedProviderError.cjs +11 -0
  81. package/src/errors/UnmatchedProviderError.mjs +4 -0
  82. package/src/executor/ArazzoWorkflowLocatorNormalizer.cjs +147 -0
  83. package/src/executor/ArazzoWorkflowLocatorNormalizer.mjs +137 -0
  84. package/src/executor/OpenAPIOperationExecutor.cjs +458 -0
  85. package/src/executor/OpenAPIOperationExecutor.mjs +447 -0
  86. package/src/executor/OpenAPIOperationLocatorNormalizer.cjs +197 -0
  87. package/src/executor/OpenAPIOperationLocatorNormalizer.mjs +189 -0
  88. package/src/executor/SourceDescriptionsLocatorNormalizer.cjs +44 -0
  89. package/src/executor/SourceDescriptionsLocatorNormalizer.mjs +38 -0
  90. package/src/executor/StepExecutor.cjs +333 -0
  91. package/src/executor/StepExecutor.mjs +326 -0
  92. package/src/executor/StepRetryRunner.cjs +226 -0
  93. package/src/executor/StepRetryRunner.mjs +215 -0
  94. package/src/executor/StepTransitionInterpreter.cjs +159 -0
  95. package/src/executor/StepTransitionInterpreter.mjs +151 -0
  96. package/src/executor/WorkflowCallStack.cjs +116 -0
  97. package/src/executor/WorkflowCallStack.mjs +106 -0
  98. package/src/executor/WorkflowExecutor.cjs +1091 -0
  99. package/src/executor/WorkflowExecutor.mjs +1077 -0
  100. package/src/executor/abort.cjs +70 -0
  101. package/src/executor/abort.mjs +60 -0
  102. package/src/expression/RuntimeExpressionContext.cjs +5 -0
  103. package/src/expression/RuntimeExpressionContext.mjs +1 -0
  104. package/src/expression/RuntimeExpressionEvaluator.cjs +337 -0
  105. package/src/expression/RuntimeExpressionEvaluator.mjs +328 -0
  106. package/src/extractor/ArazzoStepExtractor.cjs +48 -0
  107. package/src/extractor/ArazzoStepExtractor.mjs +41 -0
  108. package/src/extractor/ArazzoWorkflowExtractor.cjs +50 -0
  109. package/src/extractor/ArazzoWorkflowExtractor.mjs +43 -0
  110. package/src/extractor/OpenAPIOperationExtractor.cjs +84 -0
  111. package/src/extractor/OpenAPIOperationExtractor.mjs +77 -0
  112. package/src/index.cjs +419 -0
  113. package/src/index.mjs +73 -0
  114. package/src/normalizer/ArazzoStepNormalizer.cjs +23 -0
  115. package/src/normalizer/ArazzoStepNormalizer.mjs +17 -0
  116. package/src/normalizer/ArazzoWorkflowNormalizer.cjs +214 -0
  117. package/src/normalizer/ArazzoWorkflowNormalizer.mjs +206 -0
  118. package/src/normalizer/OpenAPI2OperationNormalizer.cjs +128 -0
  119. package/src/normalizer/OpenAPI2OperationNormalizer.mjs +120 -0
  120. package/src/normalizer/OpenAPI30OperationNormalizer.cjs +129 -0
  121. package/src/normalizer/OpenAPI30OperationNormalizer.mjs +121 -0
  122. package/src/normalizer/OpenAPI31OperationNormalizer.cjs +131 -0
  123. package/src/normalizer/OpenAPI31OperationNormalizer.mjs +123 -0
  124. package/src/normalizer/OpenAPIOperationNormalizer.cjs +58 -0
  125. package/src/normalizer/OpenAPIOperationNormalizer.mjs +50 -0
  126. package/src/registry/DocumentRegistry.cjs +160 -0
  127. package/src/registry/DocumentRegistry.mjs +151 -0
  128. package/src/registry/providers/ArazzoDocumentRegistryProvider.cjs +154 -0
  129. package/src/registry/providers/ArazzoDocumentRegistryProvider.mjs +146 -0
  130. package/src/registry/providers/DocumentRegistryProvider.cjs +31 -0
  131. package/src/registry/providers/DocumentRegistryProvider.mjs +25 -0
  132. package/src/registry/providers/OpenAPIDocumentRegistryProvider.cjs +122 -0
  133. package/src/registry/providers/OpenAPIDocumentRegistryProvider.mjs +114 -0
  134. package/src/resolver/ArazzoValueResolver.cjs +42 -0
  135. package/src/resolver/ArazzoValueResolver.mjs +37 -0
  136. package/src/resolver/OpenAPIOperationParameterResolver.cjs +117 -0
  137. package/src/resolver/OpenAPIOperationParameterResolver.mjs +110 -0
  138. package/src/resolver/OutputResolver.cjs +71 -0
  139. package/src/resolver/OutputResolver.mjs +64 -0
  140. package/src/resolver/RequestBodyResolver.cjs +227 -0
  141. package/src/resolver/RequestBodyResolver.mjs +220 -0
  142. package/src/resolver/ResolverScope.cjs +5 -0
  143. package/src/resolver/ResolverScope.mjs +1 -0
  144. package/src/resolver/StepParameterResolver.cjs +22 -0
  145. package/src/resolver/StepParameterResolver.mjs +15 -0
  146. package/src/resolver/WorkflowParameterResolver.cjs +73 -0
  147. package/src/resolver/WorkflowParameterResolver.mjs +66 -0
  148. package/src/state/WorkflowExecutionState.cjs +99 -0
  149. package/src/state/WorkflowExecutionState.mjs +93 -0
  150. package/src/vendor/swagger-client.cjs +1 -0
  151. package/src/vendor/swagger-client.mjs +1 -0
  152. package/types/runner.d.ts +2341 -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;