@usearazzo/runner 1.0.1-alpha.22 → 1.0.1-alpha.24

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 (56) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -1
  3. package/dist/arazzo-runner.browser.js +473 -293
  4. package/dist/arazzo-runner.browser.min.js +1 -1
  5. package/package.json +4 -4
  6. package/src/action/ActionResolver.cjs +4 -4
  7. package/src/action/ActionResolver.mjs +4 -4
  8. package/src/criterion/CriterionEvaluator.cjs +8 -9
  9. package/src/criterion/CriterionEvaluator.mjs +8 -9
  10. package/src/criterion/JSONPathCriterionEvaluator.cjs +1 -2
  11. package/src/criterion/JSONPathCriterionEvaluator.mjs +1 -2
  12. package/src/criterion/RegexCriterionEvaluator.cjs +1 -2
  13. package/src/criterion/RegexCriterionEvaluator.mjs +1 -2
  14. package/src/criterion/SimpleCriterionEvaluator.cjs +1 -2
  15. package/src/criterion/SimpleCriterionEvaluator.mjs +1 -2
  16. package/src/criterion/XPathCriterionEvaluator.cjs +4 -5
  17. package/src/criterion/XPathCriterionEvaluator.mjs +4 -5
  18. package/src/errors/CriterionError.cjs +52 -2
  19. package/src/errors/CriterionError.mjs +53 -2
  20. package/src/errors/ExecutionError.cjs +73 -2
  21. package/src/errors/ExecutionError.mjs +74 -2
  22. package/src/errors/ResolverError.cjs +53 -2
  23. package/src/errors/ResolverError.mjs +54 -2
  24. package/src/errors/RuntimeExpressionError.cjs +32 -2
  25. package/src/errors/RuntimeExpressionError.mjs +33 -2
  26. package/src/executor/ArazzoWorkflowLocatorNormalizer.cjs +4 -4
  27. package/src/executor/ArazzoWorkflowLocatorNormalizer.mjs +4 -4
  28. package/src/executor/OpenAPIOperationLocatorNormalizer.cjs +79 -47
  29. package/src/executor/OpenAPIOperationLocatorNormalizer.mjs +80 -48
  30. package/src/executor/StepExecutor.cjs +42 -32
  31. package/src/executor/StepExecutor.mjs +42 -32
  32. package/src/executor/StepRetryRunner.cjs +1 -1
  33. package/src/executor/StepRetryRunner.mjs +1 -1
  34. package/src/executor/StepTransitionInterpreter.cjs +3 -3
  35. package/src/executor/StepTransitionInterpreter.mjs +3 -3
  36. package/src/executor/WorkflowCallStack.cjs +2 -2
  37. package/src/executor/WorkflowCallStack.mjs +2 -2
  38. package/src/executor/WorkflowExecutor.cjs +17 -16
  39. package/src/executor/WorkflowExecutor.mjs +17 -16
  40. package/src/executor/abort.cjs +3 -3
  41. package/src/executor/abort.mjs +3 -3
  42. package/src/expression/RuntimeExpressionEvaluator.cjs +5 -5
  43. package/src/expression/RuntimeExpressionEvaluator.mjs +5 -5
  44. package/src/index.cjs +0 -7
  45. package/src/index.mjs +0 -1
  46. package/src/resolver/OpenAPIOperationParameterResolver.cjs +6 -6
  47. package/src/resolver/OpenAPIOperationParameterResolver.mjs +6 -6
  48. package/src/resolver/OutputResolver.cjs +3 -3
  49. package/src/resolver/OutputResolver.mjs +3 -3
  50. package/src/resolver/RequestBodyResolver.cjs +6 -6
  51. package/src/resolver/RequestBodyResolver.mjs +6 -6
  52. package/src/resolver/WorkflowParameterResolver.cjs +1 -1
  53. package/src/resolver/WorkflowParameterResolver.mjs +1 -1
  54. package/types/runner.d.ts +236 -60
  55. package/src/criterion/CriterionErrorReason.cjs +0 -51
  56. package/src/criterion/CriterionErrorReason.mjs +0 -46
@@ -1,4 +1,76 @@
1
1
  import ArazzoRunnerError from "./ArazzoRunnerError.mjs";
2
- /** @public */
3
- class ExecutionError extends ArazzoRunnerError {}
2
+ /**
3
+ * Carries a `reason`, one of the class's static reason fields.
4
+ *
5
+ * Every static on this class is a reason: {@link ExecutionErrorReason} is
6
+ * derived from the class's own statics, so a non-reason static would join the
7
+ * union.
8
+ * @public
9
+ */
10
+ class ExecutionError extends ArazzoRunnerError {
11
+ /** The run was cancelled through its `AbortSignal`; the signal's reason is the `cause`. */
12
+ static Aborted = 'aborted';
13
+ /** A step or a `goto`/`retry` action declares more than one mutually exclusive target. */
14
+ static AmbiguousTarget = 'ambiguous-target';
15
+ /** The `dependsOn` edges alone form a cycle between workflows. */
16
+ static DependsOnCycle = 'dependsOn-cycle';
17
+ /** A `goto` action declares neither a `stepId` nor a `workflowId`. */
18
+ static GotoTargetMissing = 'goto-target-missing';
19
+ /** A `goto` action's `stepId` names no step in the workflow. */
20
+ static GotoTargetNotFound = 'goto-target-not-found';
21
+ /** An `operationId` or `operationPath` is not a valid operation reference. */
22
+ static InvalidOperationReference = 'invalid-operation-reference';
23
+ /** A `workflowId` is not a valid `$sourceDescriptions.{name}.{workflowId}` expression. */
24
+ static InvalidWorkflowReference = 'invalid-workflow-reference';
25
+ /** A workflow's `dependsOn` is not a list or holds a non-string entry. */
26
+ static MalformedDependsOn = 'malformed-dependsOn';
27
+ /** A workflow's `steps` is not a list or holds an entry that is not a Step Object. */
28
+ static MalformedSteps = 'malformed-steps';
29
+ /** A step run as an operation declares neither an `operationId` nor an `operationPath`. */
30
+ static MissingOperation = 'missing-operation';
31
+ /** An operation reference locates no operation in its OpenAPI source description. */
32
+ static OperationNotFound = 'operation-not-found';
33
+ /** A `retry` action references a step or workflow, but no run reference was given to run it. */
34
+ static RetryReferenceUnsupported = 'retry-reference-unsupported';
35
+ /** A `retry` action's `stepId` names no step in the workflow. */
36
+ static RetryTargetNotFound = 'retry-target-not-found';
37
+ /** A workflow reference names a source description that is not an Arazzo document. */
38
+ static SourceDescriptionNotArazzo = 'source-description-not-arazzo';
39
+ /** A reference names a source description the Arazzo document does not define. */
40
+ static SourceDescriptionNotFound = 'source-description-not-found';
41
+ /** An operation reference names a source description that is not an OpenAPI document. */
42
+ static SourceDescriptionNotOpenAPI = 'source-description-not-openapi';
43
+ /** A workflow exceeded its budget of step attempts. */
44
+ static StepBudget = 'step-budget';
45
+ /** An action declares a `type` other than `end`, `goto` or `retry`. */
46
+ static UnknownActionType = 'unknown-action-type';
47
+ /** `execute` received an option it does not know. */
48
+ static UnknownExecuteOption = 'unknown-execute-option';
49
+ /** A step produced a transition the workflow executor does not recognize. */
50
+ static UnknownTransitionKind = 'unknown-transition-kind';
51
+ /** A sub-workflow call (alone or together with `dependsOn`) forms a cycle between workflows. */
52
+ static WorkflowCycle = 'workflow-cycle';
53
+ /** Workflows nest deeper than the configured limit. */
54
+ static WorkflowDepth = 'workflow-depth';
55
+ /** A workflow reference names a workflow the Arazzo document does not define. */
56
+ static WorkflowNotFound = 'workflow-not-found';
57
+ /** A step that targets a workflow was handed to the step executor, which runs operations only. */
58
+ static WorkflowStep = 'workflow-step';
59
+
60
+ /**
61
+ * The chain of workflowIds the error concerns — the loop A → B → A for a
62
+ * cycle, or the call chain in progress when a budget ran out.
63
+ */
64
+
65
+ constructor(message, options) {
66
+ super(message, options);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * One of the reasons an {@link ExecutionError} carries: an `ExecutionError`
72
+ * static such as `ExecutionError.OperationNotFound`.
73
+ * @public
74
+ */
75
+
4
76
  export default ExecutionError;
@@ -6,6 +6,57 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.default = void 0;
8
8
  var _ArazzoRunnerError = _interopRequireDefault(require("./ArazzoRunnerError.cjs"));
9
- /** @public */
10
- class ResolverError extends _ArazzoRunnerError.default {}
9
+ /**
10
+ * Carries a `reason`, one of the class's static reason fields.
11
+ *
12
+ * Every static on this class is a reason: {@link ResolverErrorReason} is
13
+ * derived from the class's own statics, so a non-reason static would join the
14
+ * union.
15
+ * @public
16
+ */
17
+ class ResolverError extends _ArazzoRunnerError.default {
18
+ /** A parameter cannot be delivered unambiguously at its location. */
19
+ static AmbiguousDelivery = 'ambiguous-delivery';
20
+ /** An output or a request body payload holds a value that is not a valid runtime expression. */
21
+ static InvalidExpression = 'invalid-expression';
22
+ /** A parameter's location (`in`) is not one of the known locations. */
23
+ static InvalidLocation = 'invalid-location';
24
+ /** An `onSuccess`/`onFailure` list holds an entry that is not a Success/Failure Action Object. */
25
+ static MalformedActionEntry = 'malformed-action-entry';
26
+ /** A step's `onSuccess` or `onFailure` is present but is not a list. */
27
+ static MalformedActions = 'malformed-actions';
28
+ /** A step's `successCriteria` or an action's `criteria` is present but is not a list. */
29
+ static MalformedCriteria = 'malformed-criteria';
30
+ /** A criteria list holds an entry that is not a Criterion Object. */
31
+ static MalformedCriterion = 'malformed-criterion';
32
+ /** A parameter's location (`in`) is not a string. */
33
+ static MalformedLocation = 'malformed-location';
34
+ /** A step's or workflow's `outputs` is present but is not a map. */
35
+ static MalformedOutputs = 'malformed-outputs';
36
+ /** `parameters` is present but is not a list. */
37
+ static MalformedParameters = 'malformed-parameters';
38
+ /** `requestBody.replacements` is present but is not a list. */
39
+ static MalformedReplacements = 'malformed-replacements';
40
+ /** `requestBody` is present but is not a map. */
41
+ static MalformedRequestBody = 'malformed-request-body';
42
+ /** A parameter of a step that targets an operation declares no location (`in`). */
43
+ static MissingLocation = 'missing-location';
44
+ /** A parameter has a missing or non-string `name`. */
45
+ static MissingName = 'missing-name';
46
+ /** A runtime expression in the request body did not resolve. */
47
+ static UnresolvedExpression = 'unresolved-expression';
48
+ /** A `requestBody` replacement target does not resolve in the payload. */
49
+ static UnresolvedTarget = 'unresolved-target';
50
+ /** A `requestBody` replacement target is not a JSON Pointer. */
51
+ static UnsupportedTarget = 'unsupported-target';
52
+ constructor(message, options) {
53
+ super(message, options);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * One of the reasons a {@link ResolverError} carries: a `ResolverError`
59
+ * static such as `ResolverError.MalformedParameters`.
60
+ * @public
61
+ */
11
62
  var _default = exports.default = ResolverError;
@@ -1,4 +1,56 @@
1
1
  import ArazzoRunnerError from "./ArazzoRunnerError.mjs";
2
- /** @public */
3
- class ResolverError extends ArazzoRunnerError {}
2
+ /**
3
+ * Carries a `reason`, one of the class's static reason fields.
4
+ *
5
+ * Every static on this class is a reason: {@link ResolverErrorReason} is
6
+ * derived from the class's own statics, so a non-reason static would join the
7
+ * union.
8
+ * @public
9
+ */
10
+ class ResolverError extends ArazzoRunnerError {
11
+ /** A parameter cannot be delivered unambiguously at its location. */
12
+ static AmbiguousDelivery = 'ambiguous-delivery';
13
+ /** An output or a request body payload holds a value that is not a valid runtime expression. */
14
+ static InvalidExpression = 'invalid-expression';
15
+ /** A parameter's location (`in`) is not one of the known locations. */
16
+ static InvalidLocation = 'invalid-location';
17
+ /** An `onSuccess`/`onFailure` list holds an entry that is not a Success/Failure Action Object. */
18
+ static MalformedActionEntry = 'malformed-action-entry';
19
+ /** A step's `onSuccess` or `onFailure` is present but is not a list. */
20
+ static MalformedActions = 'malformed-actions';
21
+ /** A step's `successCriteria` or an action's `criteria` is present but is not a list. */
22
+ static MalformedCriteria = 'malformed-criteria';
23
+ /** A criteria list holds an entry that is not a Criterion Object. */
24
+ static MalformedCriterion = 'malformed-criterion';
25
+ /** A parameter's location (`in`) is not a string. */
26
+ static MalformedLocation = 'malformed-location';
27
+ /** A step's or workflow's `outputs` is present but is not a map. */
28
+ static MalformedOutputs = 'malformed-outputs';
29
+ /** `parameters` is present but is not a list. */
30
+ static MalformedParameters = 'malformed-parameters';
31
+ /** `requestBody.replacements` is present but is not a list. */
32
+ static MalformedReplacements = 'malformed-replacements';
33
+ /** `requestBody` is present but is not a map. */
34
+ static MalformedRequestBody = 'malformed-request-body';
35
+ /** A parameter of a step that targets an operation declares no location (`in`). */
36
+ static MissingLocation = 'missing-location';
37
+ /** A parameter has a missing or non-string `name`. */
38
+ static MissingName = 'missing-name';
39
+ /** A runtime expression in the request body did not resolve. */
40
+ static UnresolvedExpression = 'unresolved-expression';
41
+ /** A `requestBody` replacement target does not resolve in the payload. */
42
+ static UnresolvedTarget = 'unresolved-target';
43
+ /** A `requestBody` replacement target is not a JSON Pointer. */
44
+ static UnsupportedTarget = 'unsupported-target';
45
+ constructor(message, options) {
46
+ super(message, options);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * One of the reasons a {@link ResolverError} carries: a `ResolverError`
52
+ * static such as `ResolverError.MalformedParameters`.
53
+ * @public
54
+ */
55
+
4
56
  export default ResolverError;
@@ -6,6 +6,36 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.default = void 0;
8
8
  var _ArazzoRunnerError = _interopRequireDefault(require("./ArazzoRunnerError.cjs"));
9
- /** @public */
10
- class RuntimeExpressionError extends _ArazzoRunnerError.default {}
9
+ /**
10
+ * Carries a `reason`, one of the class's static reason fields.
11
+ *
12
+ * Every static on this class is a reason: {@link RuntimeExpressionErrorReason}
13
+ * is derived from the class's own statics, so a non-reason static would join
14
+ * the union.
15
+ * @public
16
+ */
17
+ class RuntimeExpressionError extends _ArazzoRunnerError.default {
18
+ /** The expression is not a valid runtime expression. */
19
+ static InvalidExpression = 'invalid-expression';
20
+ /** The runtime expression parser failed on the expression. */
21
+ static ParseError = 'parse-error';
22
+ /**
23
+ * The expression reads HTTP data (`$statusCode`, `$url`, `$method`, `$request`,
24
+ * `$response`) in a step that calls a workflow and so made no HTTP call.
25
+ */
26
+ static UnavailableExpression = 'unavailable-expression';
27
+ /** The expression could not be resolved against the evaluation context. */
28
+ static UnresolvedReference = 'unresolved-reference';
29
+ /** The parsed expression contains a node the evaluator does not support. */
30
+ static UnsupportedNode = 'unsupported-node';
31
+ constructor(message, options) {
32
+ super(message, options);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * One of the reasons a {@link RuntimeExpressionError} carries: a
38
+ * `RuntimeExpressionError` static such as `RuntimeExpressionError.ParseError`.
39
+ * @public
40
+ */
11
41
  var _default = exports.default = RuntimeExpressionError;
@@ -1,4 +1,35 @@
1
1
  import ArazzoRunnerError from "./ArazzoRunnerError.mjs";
2
- /** @public */
3
- class RuntimeExpressionError extends ArazzoRunnerError {}
2
+ /**
3
+ * Carries a `reason`, one of the class's static reason fields.
4
+ *
5
+ * Every static on this class is a reason: {@link RuntimeExpressionErrorReason}
6
+ * is derived from the class's own statics, so a non-reason static would join
7
+ * the union.
8
+ * @public
9
+ */
10
+ class RuntimeExpressionError extends ArazzoRunnerError {
11
+ /** The expression is not a valid runtime expression. */
12
+ static InvalidExpression = 'invalid-expression';
13
+ /** The runtime expression parser failed on the expression. */
14
+ static ParseError = 'parse-error';
15
+ /**
16
+ * The expression reads HTTP data (`$statusCode`, `$url`, `$method`, `$request`,
17
+ * `$response`) in a step that calls a workflow and so made no HTTP call.
18
+ */
19
+ static UnavailableExpression = 'unavailable-expression';
20
+ /** The expression could not be resolved against the evaluation context. */
21
+ static UnresolvedReference = 'unresolved-reference';
22
+ /** The parsed expression contains a node the evaluator does not support. */
23
+ static UnsupportedNode = 'unsupported-node';
24
+ constructor(message, options) {
25
+ super(message, options);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * One of the reasons a {@link RuntimeExpressionError} carries: a
31
+ * `RuntimeExpressionError` static such as `RuntimeExpressionError.ParseError`.
32
+ * @public
33
+ */
34
+
4
35
  export default RuntimeExpressionError;
@@ -75,7 +75,7 @@ class ArazzoWorkflowLocatorNormalizer extends _SourceDescriptionsLocatorNormaliz
75
75
  throw new _ExecutionError.default(`workflow reference "${reference}" in workflow "${context.workflowId}" names workflow "${locator.workflowId}", which the Arazzo document at "${locator.document.uri}" does not define`, {
76
76
  workflowId: context.workflowId,
77
77
  stepId: context.stepId,
78
- reason: 'workflow-not-found'
78
+ reason: _ExecutionError.default.WorkflowNotFound
79
79
  });
80
80
  }
81
81
  return locator;
@@ -104,7 +104,7 @@ class ArazzoWorkflowLocatorNormalizer extends _SourceDescriptionsLocatorNormaliz
104
104
  throw new _ExecutionError.default(`workflow reference "${reference}" in workflow "${workflowId}" is not a $sourceDescriptions.{name}.{workflowId} expression`, {
105
105
  workflowId,
106
106
  stepId,
107
- reason: 'invalid-workflow-reference'
107
+ reason: _ExecutionError.default.InvalidWorkflowReference
108
108
  });
109
109
  }
110
110
  return {
@@ -138,7 +138,7 @@ class ArazzoWorkflowLocatorNormalizer extends _SourceDescriptionsLocatorNormaliz
138
138
  throw new _ExecutionError.default(`workflow reference "${parsed.reference}" in workflow "${workflowId}" names source description "${parsed.sourceName}", which the Arazzo document at "${document.uri}" does not define`, {
139
139
  workflowId,
140
140
  stepId,
141
- reason: 'source-description-not-found'
141
+ reason: _ExecutionError.default.SourceDescriptionNotFound
142
142
  });
143
143
  }
144
144
  const source = await this.registry.acquire(uri);
@@ -146,7 +146,7 @@ class ArazzoWorkflowLocatorNormalizer extends _SourceDescriptionsLocatorNormaliz
146
146
  throw new _ExecutionError.default(`workflow reference "${parsed.reference}" in workflow "${workflowId}" names source description "${parsed.sourceName}" at "${uri}", which is not an Arazzo document`, {
147
147
  workflowId,
148
148
  stepId,
149
- reason: 'source-description-not-arazzo'
149
+ reason: _ExecutionError.default.SourceDescriptionNotArazzo
150
150
  });
151
151
  }
152
152
  return {
@@ -65,7 +65,7 @@ class ArazzoWorkflowLocatorNormalizer extends SourceDescriptionsLocatorNormalize
65
65
  throw new ExecutionError(`workflow reference "${reference}" in workflow "${context.workflowId}" names workflow "${locator.workflowId}", which the Arazzo document at "${locator.document.uri}" does not define`, {
66
66
  workflowId: context.workflowId,
67
67
  stepId: context.stepId,
68
- reason: 'workflow-not-found'
68
+ reason: ExecutionError.WorkflowNotFound
69
69
  });
70
70
  }
71
71
  return locator;
@@ -94,7 +94,7 @@ class ArazzoWorkflowLocatorNormalizer extends SourceDescriptionsLocatorNormalize
94
94
  throw new ExecutionError(`workflow reference "${reference}" in workflow "${workflowId}" is not a $sourceDescriptions.{name}.{workflowId} expression`, {
95
95
  workflowId,
96
96
  stepId,
97
- reason: 'invalid-workflow-reference'
97
+ reason: ExecutionError.InvalidWorkflowReference
98
98
  });
99
99
  }
100
100
  return {
@@ -128,7 +128,7 @@ class ArazzoWorkflowLocatorNormalizer extends SourceDescriptionsLocatorNormalize
128
128
  throw new ExecutionError(`workflow reference "${parsed.reference}" in workflow "${workflowId}" names source description "${parsed.sourceName}", which the Arazzo document at "${document.uri}" does not define`, {
129
129
  workflowId,
130
130
  stepId,
131
- reason: 'source-description-not-found'
131
+ reason: ExecutionError.SourceDescriptionNotFound
132
132
  });
133
133
  }
134
134
  const source = await this.registry.acquire(uri);
@@ -136,7 +136,7 @@ class ArazzoWorkflowLocatorNormalizer extends SourceDescriptionsLocatorNormalize
136
136
  throw new ExecutionError(`workflow reference "${parsed.reference}" in workflow "${workflowId}" names source description "${parsed.sourceName}" at "${uri}", which is not an Arazzo document`, {
137
137
  workflowId,
138
138
  stepId,
139
- reason: 'source-description-not-arazzo'
139
+ reason: ExecutionError.SourceDescriptionNotArazzo
140
140
  });
141
141
  }
142
142
  return {
@@ -10,7 +10,8 @@ var _jsonPointer = require("@swaggerexpert/json-pointer");
10
10
  var _empty = require("@speclynx/apidom-reference/configuration/empty");
11
11
  var _OpenAPIDocument = _interopRequireDefault(require("../document/OpenAPIDocument.cjs"));
12
12
  var _RuntimeExpressionEvaluator = _interopRequireDefault(require("../expression/RuntimeExpressionEvaluator.cjs"));
13
- var _ExtractionError = _interopRequireDefault(require("../errors/ExtractionError.cjs"));
13
+ var _OpenAPIOperationExtractor = _interopRequireDefault(require("../extractor/OpenAPIOperationExtractor.cjs"));
14
+ var _ExecutionError = _interopRequireDefault(require("../errors/ExecutionError.cjs"));
14
15
  var _SourceDescriptionsLocatorNormalizer = _interopRequireDefault(require("./SourceDescriptionsLocatorNormalizer.cjs"));
15
16
  /**
16
17
  * A canonical OpenAPI operation locator: the OpenAPI document that owns the
@@ -34,7 +35,7 @@ var _SourceDescriptionsLocatorNormalizer = _interopRequireDefault(require("./Sou
34
35
  * `$sourceDescriptions.{name}.{operationId}`. Per the Arazzo Specification, a
35
36
  * plain name is only valid when a single (non-arazzo) source description is
36
37
  * defined; multiple sources require the expression form. A plain name is
37
- * therefore resolved against the first source description that has it.
38
+ * therefore looked up in the first OpenAPI source description only.
38
39
  * - `operationPath` embeds a `{$sourceDescriptions.{name}.url}` runtime
39
40
  * expression followed by a JSON Pointer to the operation.
40
41
  *
@@ -42,21 +43,31 @@ var _SourceDescriptionsLocatorNormalizer = _interopRequireDefault(require("./Sou
42
43
  * or wrong); a source is classified by what it actually parses to. The
43
44
  * normalizer acquires the referenced source documents from the registry on
44
45
  * demand.
46
+ *
47
+ * A reference that cannot be resolved throws {@link ExecutionError}, attributed
48
+ * to the referencing step when a {@link StepScope} is given:
49
+ * `operation-not-found` when no operation answers it,
50
+ * `source-description-not-found` for a source name the document does not
51
+ * define, `source-description-not-openapi` for a source that is not an OpenAPI
52
+ * document, and `invalid-operation-reference` for a reference malformed as
53
+ * written. Every returned locator names an existing operation.
45
54
  * @public
46
55
  */
47
56
  class OpenAPIOperationLocatorNormalizer extends _SourceDescriptionsLocatorNormalizer.default {
57
+ #extractor = new _OpenAPIOperationExtractor.default();
58
+
48
59
  /**
49
60
  * Normalizes a plain or expression `operationId` to a canonical locator.
50
61
  *
51
62
  * A whole runtime expression (`$sourceDescriptions.{name}.{operationId}`) is
52
- * resolved against its named source; a plain name is resolved against the
53
- * first source description that has it.
63
+ * resolved against its named source; a plain name is looked up in the first
64
+ * OpenAPI source description only.
54
65
  */
55
- async normalizeOperationId(operationId, document) {
66
+ async normalizeOperationId(operationId, document, scope) {
56
67
  if ((0, _arazzoRuntimeExpression.test)(operationId)) {
57
- return this.#resolveSourced(operationId, document);
68
+ return this.#resolveSourced(operationId, document, scope);
58
69
  }
59
- return this.#resolvePlainOperationId(operationId, document);
70
+ return this.#resolvePlainOperationId(operationId, document, scope);
60
71
  }
61
72
 
62
73
  /**
@@ -72,10 +83,21 @@ class OpenAPIOperationLocatorNormalizer extends _SourceDescriptionsLocatorNormal
72
83
  * The runner only needs a URL and a JSON Pointer, so it does not enforce that
73
84
  * the source description is identified by a runtime expression rather than a
74
85
  * literal URL (a literal URL interpolates to itself and still resolves) — that
75
- * is a conformance concern for the validator. It fails only when the URL does
76
- * not resolve to an OpenAPI source or the JSON Pointer is invalid.
86
+ * is a conformance concern for the validator. A source name the document does
87
+ * not define is detected before interpolation, so it is reported as such
88
+ * rather than as the empty URL it would interpolate to; the JSON Pointer must
89
+ * locate an operation in the acquired OpenAPI document.
77
90
  */
78
- async normalizeOperationPath(operationPath, document) {
91
+ async normalizeOperationPath(operationPath, document, scope) {
92
+ for (const expression of (0, _arazzoRuntimeExpression.extract)(operationPath) ?? []) {
93
+ const parsed = this.parseSourceDescriptionsExpression(expression);
94
+ if (parsed !== undefined && document.resolveSourceDescriptionURI(parsed.sourceName) === undefined) {
95
+ throw new _ExecutionError.default(`operationPath "${operationPath}" names source description "${parsed.sourceName}", which the Arazzo document at "${document.uri}" does not define`, {
96
+ ...scope,
97
+ reason: _ExecutionError.default.SourceDescriptionNotFound
98
+ });
99
+ }
100
+ }
79
101
  const evaluator = new _RuntimeExpressionEvaluator.default({}, {
80
102
  strict: false,
81
103
  document,
@@ -84,23 +106,35 @@ class OpenAPIOperationLocatorNormalizer extends _SourceDescriptionsLocatorNormal
84
106
  const uriReference = evaluator.interpolate(operationPath);
85
107
  const documentURI = _empty.url.sanitize(_empty.url.stripHash(uriReference));
86
108
  if (documentURI === '') {
87
- throw new _ExtractionError.default(`operationPath "${operationPath}" does not resolve to a source description URL`, {
88
- pointer: operationPath,
89
- uri: document.uri
109
+ throw new _ExecutionError.default(`operationPath "${operationPath}" does not resolve to a source description URL`, {
110
+ ...scope,
111
+ reason: _ExecutionError.default.InvalidOperationReference
90
112
  });
91
113
  }
92
114
  const jsonPointer = _jsonPointer.URIFragmentIdentifier.fromURIReference(uriReference);
93
115
  if (!(0, _jsonPointer.testJSONPointer)(jsonPointer)) {
94
- throw new _ExtractionError.default(`operationPath "${operationPath}" has an invalid JSON Pointer`, {
95
- pointer: operationPath,
96
- uri: document.uri
116
+ throw new _ExecutionError.default(`operationPath "${operationPath}" has an invalid JSON Pointer`, {
117
+ ...scope,
118
+ reason: _ExecutionError.default.InvalidOperationReference
97
119
  });
98
120
  }
99
121
  const source = await this.registry.acquire(documentURI);
100
122
  if (!_OpenAPIDocument.default.is(source)) {
101
- throw new _ExtractionError.default(`operationPath "${operationPath}" does not reference an OpenAPI document`, {
102
- pointer: operationPath,
103
- uri: documentURI
123
+ throw new _ExecutionError.default(`operationPath "${operationPath}" references "${documentURI}", which is not an OpenAPI document`, {
124
+ ...scope,
125
+ reason: _ExecutionError.default.SourceDescriptionNotOpenAPI
126
+ });
127
+ }
128
+
129
+ // the extractor owns locating an operation by pointer; its failure here
130
+ // means the pointer names no operation in this document.
131
+ try {
132
+ this.#extractor.extractByPointer(source, jsonPointer);
133
+ } catch (error) {
134
+ throw new _ExecutionError.default(`operationPath "${operationPath}" does not locate an operation in the OpenAPI document at "${source.uri}"`, {
135
+ cause: error,
136
+ ...scope,
137
+ reason: _ExecutionError.default.OperationNotFound
104
138
  });
105
139
  }
106
140
  return {
@@ -108,31 +142,24 @@ class OpenAPIOperationLocatorNormalizer extends _SourceDescriptionsLocatorNormal
108
142
  jsonPointer
109
143
  };
110
144
  }
111
-
112
- /**
113
- * Parses a `$sourceDescriptions.{name}.{reference}` expression, asserting
114
- * it is a source-descriptions expression.
115
- */
116
- #parseSourceDescriptionsExpression(expression) {
145
+ async #resolveSourced(expression, document, scope) {
117
146
  const parsed = this.parseSourceDescriptionsExpression(expression);
118
147
  if (parsed === undefined) {
119
- throw new _ExtractionError.default(`Unsupported operationId expression "${expression}"`, {
120
- operationId: expression
148
+ throw new _ExecutionError.default(`operationId "${expression}" is not a $sourceDescriptions.{name}.{operationId} expression`, {
149
+ ...scope,
150
+ reason: _ExecutionError.default.InvalidOperationReference
121
151
  });
122
152
  }
123
- return parsed;
124
- }
125
- async #resolveSourced(expression, document) {
126
153
  const {
127
154
  sourceName,
128
155
  reference: operationId
129
- } = this.#parseSourceDescriptionsExpression(expression);
130
- const openapiDocument = await this.#sourceDocument(sourceName, document);
156
+ } = parsed;
157
+ const openapiDocument = await this.#sourceDocument(sourceName, document, scope);
131
158
  const jsonPointer = openapiDocument.operationIndex.get(operationId);
132
159
  if (jsonPointer === undefined) {
133
- throw new _ExtractionError.default(`Operation "${operationId}" not found in source description "${sourceName}"`, {
134
- operationId,
135
- uri: openapiDocument.uri
160
+ throw new _ExecutionError.default(`Operation "${operationId}" not found in source description "${sourceName}" at "${openapiDocument.uri}"`, {
161
+ ...scope,
162
+ reason: _ExecutionError.default.OperationNotFound
136
163
  });
137
164
  }
138
165
  return {
@@ -153,15 +180,15 @@ class OpenAPIOperationLocatorNormalizer extends _SourceDescriptionsLocatorNormal
153
180
  * Non-OpenAPI (arazzo) sources are skipped. Sources are acquired one at a time
154
181
  * until the first OpenAPI source is reached.
155
182
  */
156
- async #resolvePlainOperationId(operationId, document) {
183
+ async #resolvePlainOperationId(operationId, document, scope) {
157
184
  for (const uri of document.sourceDescriptionURIs()) {
158
185
  const source = await this.registry.acquire(uri);
159
186
  if (!_OpenAPIDocument.default.is(source)) continue;
160
187
  const jsonPointer = source.operationIndex.get(operationId);
161
188
  if (jsonPointer === undefined) {
162
- throw new _ExtractionError.default(`Operation "${operationId}" not found in source description at "${source.uri}"`, {
163
- operationId,
164
- uri: source.uri
189
+ throw new _ExecutionError.default(`Operation "${operationId}" not found in source description at "${source.uri}"`, {
190
+ ...scope,
191
+ reason: _ExecutionError.default.OperationNotFound
165
192
  });
166
193
  }
167
194
  return {
@@ -169,26 +196,31 @@ class OpenAPIOperationLocatorNormalizer extends _SourceDescriptionsLocatorNormal
169
196
  jsonPointer
170
197
  };
171
198
  }
172
- throw new _ExtractionError.default(`Operation "${operationId}" has no OpenAPI source description`, {
173
- operationId,
174
- uri: document.uri
199
+
200
+ // no source was named, so this is not a missing source description: there
201
+ // is simply no OpenAPI document for the operation to be in.
202
+ throw new _ExecutionError.default(`Operation "${operationId}" not found: the Arazzo document at "${document.uri}" has no OpenAPI source description`, {
203
+ ...scope,
204
+ reason: _ExecutionError.default.OperationNotFound
175
205
  });
176
206
  }
177
207
 
178
208
  /**
179
209
  * Acquires a source description by name and asserts it is an OpenAPI document.
180
210
  */
181
- async #sourceDocument(sourceName, document) {
211
+ async #sourceDocument(sourceName, document, scope) {
182
212
  const uri = document.resolveSourceDescriptionURI(sourceName);
183
213
  if (uri === undefined) {
184
- throw new _ExtractionError.default(`Source description "${sourceName}" not found`, {
185
- uri: document.uri
214
+ throw new _ExecutionError.default(`Source description "${sourceName}" not found in the Arazzo document at "${document.uri}"`, {
215
+ ...scope,
216
+ reason: _ExecutionError.default.SourceDescriptionNotFound
186
217
  });
187
218
  }
188
219
  const source = await this.registry.acquire(uri);
189
220
  if (!_OpenAPIDocument.default.is(source)) {
190
- throw new _ExtractionError.default(`Source description "${sourceName}" is not an OpenAPI document`, {
191
- uri
221
+ throw new _ExecutionError.default(`Source description "${sourceName}" at "${uri}" is not an OpenAPI document`, {
222
+ ...scope,
223
+ reason: _ExecutionError.default.SourceDescriptionNotOpenAPI
192
224
  });
193
225
  }
194
226
  return source;