@usearazzo/runner 0.0.0-stage → 1.0.1-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +163 -2
- package/dist/arazzo-runner.browser.js +113245 -0
- package/dist/arazzo-runner.browser.min.js +1 -0
- package/package.json +95 -4
- package/src/ArazzoRunner.cjs +122 -0
- package/src/ArazzoRunner.mjs +113 -0
- package/src/action/ActionResolver.cjs +160 -0
- package/src/action/ActionResolver.mjs +150 -0
- package/src/assembler/OpenAPI2DocumentAssembler.cjs +111 -0
- package/src/assembler/OpenAPI2DocumentAssembler.mjs +104 -0
- package/src/assembler/OpenAPI30DocumentAssembler.cjs +110 -0
- package/src/assembler/OpenAPI30DocumentAssembler.mjs +103 -0
- package/src/assembler/OpenAPI31DocumentAssembler.cjs +111 -0
- package/src/assembler/OpenAPI31DocumentAssembler.mjs +104 -0
- package/src/assembler/OpenAPIDocumentAssembler.cjs +58 -0
- package/src/assembler/OpenAPIDocumentAssembler.mjs +50 -0
- package/src/client/HTTPClient.cjs +5 -0
- package/src/client/HTTPClient.mjs +1 -0
- package/src/client/HTTPClientFetch.cjs +16 -0
- package/src/client/HTTPClientFetch.mjs +10 -0
- package/src/client/OpenAPIOperationRequest.cjs +5 -0
- package/src/client/OpenAPIOperationRequest.mjs +1 -0
- package/src/client/OpenAPIOperationResponse.cjs +42 -0
- package/src/client/OpenAPIOperationResponse.mjs +36 -0
- package/src/client/OpenAPIOperationResponseNormalizer.cjs +48 -0
- package/src/client/OpenAPIOperationResponseNormalizer.mjs +40 -0
- package/src/client/ParameterDelivery.cjs +119 -0
- package/src/client/ParameterDelivery.mjs +113 -0
- package/src/constants.cjs +9 -0
- package/src/constants.mjs +3 -0
- package/src/criterion/CriterionEvaluator.cjs +205 -0
- package/src/criterion/CriterionEvaluator.mjs +196 -0
- package/src/criterion/JSONPathCriterionEvaluator.cjs +47 -0
- package/src/criterion/JSONPathCriterionEvaluator.mjs +40 -0
- package/src/criterion/RegexCriterionEvaluator.cjs +67 -0
- package/src/criterion/RegexCriterionEvaluator.mjs +60 -0
- package/src/criterion/SimpleCriterionEvaluator.cjs +50 -0
- package/src/criterion/SimpleCriterionEvaluator.mjs +43 -0
- package/src/criterion/XPathCriterionEvaluator.cjs +117 -0
- package/src/criterion/XPathCriterionEvaluator.mjs +109 -0
- package/src/document/APIDocument.cjs +35 -0
- package/src/document/APIDocument.mjs +30 -0
- package/src/document/ArazzoDocument.cjs +81 -0
- package/src/document/ArazzoDocument.mjs +74 -0
- package/src/document/ArazzoSourceDescriptionIndex.cjs +26 -0
- package/src/document/ArazzoSourceDescriptionIndex.mjs +20 -0
- package/src/document/ArazzoStepIndex.cjs +25 -0
- package/src/document/ArazzoStepIndex.mjs +19 -0
- package/src/document/ArazzoWorkflowIndex.cjs +17 -0
- package/src/document/ArazzoWorkflowIndex.mjs +11 -0
- package/src/document/OpenAPIDocument.cjs +28 -0
- package/src/document/OpenAPIDocument.mjs +21 -0
- package/src/document/OpenAPIOperationIndex.cjs +24 -0
- package/src/document/OpenAPIOperationIndex.mjs +18 -0
- package/src/document/ParameterIdentity.cjs +93 -0
- package/src/document/ParameterIdentity.mjs +88 -0
- package/src/document/openapi-types.cjs +5 -0
- package/src/document/openapi-types.mjs +1 -0
- package/src/errors/ArazzoRunnerError.cjs +10 -0
- package/src/errors/ArazzoRunnerError.mjs +5 -0
- package/src/errors/AssemblerError.cjs +11 -0
- package/src/errors/AssemblerError.mjs +4 -0
- package/src/errors/ClientError.cjs +11 -0
- package/src/errors/ClientError.mjs +4 -0
- package/src/errors/CriterionError.cjs +11 -0
- package/src/errors/CriterionError.mjs +4 -0
- package/src/errors/ExecutionError.cjs +11 -0
- package/src/errors/ExecutionError.mjs +4 -0
- package/src/errors/ExtractionError.cjs +11 -0
- package/src/errors/ExtractionError.mjs +4 -0
- package/src/errors/InvalidEntryDocumentError.cjs +11 -0
- package/src/errors/InvalidEntryDocumentError.mjs +4 -0
- package/src/errors/NormalizationError.cjs +11 -0
- package/src/errors/NormalizationError.mjs +4 -0
- package/src/errors/ResolverError.cjs +11 -0
- package/src/errors/ResolverError.mjs +4 -0
- package/src/errors/RuntimeExpressionError.cjs +11 -0
- package/src/errors/RuntimeExpressionError.mjs +4 -0
- package/src/errors/UnmatchedProviderError.cjs +11 -0
- package/src/errors/UnmatchedProviderError.mjs +4 -0
- package/src/executor/ArazzoWorkflowLocatorNormalizer.cjs +147 -0
- package/src/executor/ArazzoWorkflowLocatorNormalizer.mjs +137 -0
- package/src/executor/OpenAPIOperationExecutor.cjs +458 -0
- package/src/executor/OpenAPIOperationExecutor.mjs +447 -0
- package/src/executor/OpenAPIOperationLocatorNormalizer.cjs +197 -0
- package/src/executor/OpenAPIOperationLocatorNormalizer.mjs +189 -0
- package/src/executor/SourceDescriptionsLocatorNormalizer.cjs +44 -0
- package/src/executor/SourceDescriptionsLocatorNormalizer.mjs +38 -0
- package/src/executor/StepExecutor.cjs +333 -0
- package/src/executor/StepExecutor.mjs +326 -0
- package/src/executor/StepRetryRunner.cjs +226 -0
- package/src/executor/StepRetryRunner.mjs +215 -0
- package/src/executor/StepTransitionInterpreter.cjs +159 -0
- package/src/executor/StepTransitionInterpreter.mjs +151 -0
- package/src/executor/WorkflowCallStack.cjs +116 -0
- package/src/executor/WorkflowCallStack.mjs +106 -0
- package/src/executor/WorkflowExecutor.cjs +1091 -0
- package/src/executor/WorkflowExecutor.mjs +1077 -0
- package/src/executor/abort.cjs +70 -0
- package/src/executor/abort.mjs +60 -0
- package/src/expression/RuntimeExpressionContext.cjs +5 -0
- package/src/expression/RuntimeExpressionContext.mjs +1 -0
- package/src/expression/RuntimeExpressionEvaluator.cjs +337 -0
- package/src/expression/RuntimeExpressionEvaluator.mjs +328 -0
- package/src/extractor/ArazzoStepExtractor.cjs +48 -0
- package/src/extractor/ArazzoStepExtractor.mjs +41 -0
- package/src/extractor/ArazzoWorkflowExtractor.cjs +50 -0
- package/src/extractor/ArazzoWorkflowExtractor.mjs +43 -0
- package/src/extractor/OpenAPIOperationExtractor.cjs +84 -0
- package/src/extractor/OpenAPIOperationExtractor.mjs +77 -0
- package/src/index.cjs +426 -0
- package/src/index.mjs +75 -0
- package/src/normalizer/ArazzoStepNormalizer.cjs +23 -0
- package/src/normalizer/ArazzoStepNormalizer.mjs +17 -0
- package/src/normalizer/ArazzoWorkflowNormalizer.cjs +214 -0
- package/src/normalizer/ArazzoWorkflowNormalizer.mjs +206 -0
- package/src/normalizer/OpenAPI2OperationNormalizer.cjs +128 -0
- package/src/normalizer/OpenAPI2OperationNormalizer.mjs +120 -0
- package/src/normalizer/OpenAPI30OperationNormalizer.cjs +129 -0
- package/src/normalizer/OpenAPI30OperationNormalizer.mjs +121 -0
- package/src/normalizer/OpenAPI31OperationNormalizer.cjs +131 -0
- package/src/normalizer/OpenAPI31OperationNormalizer.mjs +123 -0
- package/src/normalizer/OpenAPIOperationNormalizer.cjs +58 -0
- package/src/normalizer/OpenAPIOperationNormalizer.mjs +50 -0
- package/src/registry/DocumentRegistry.cjs +160 -0
- package/src/registry/DocumentRegistry.mjs +151 -0
- package/src/registry/providers/ArazzoDocumentRegistryProvider.cjs +154 -0
- package/src/registry/providers/ArazzoDocumentRegistryProvider.mjs +146 -0
- package/src/registry/providers/DocumentRegistryProvider.cjs +31 -0
- package/src/registry/providers/DocumentRegistryProvider.mjs +25 -0
- package/src/registry/providers/OpenAPIDocumentRegistryProvider.cjs +122 -0
- package/src/registry/providers/OpenAPIDocumentRegistryProvider.mjs +114 -0
- package/src/resolver/ArazzoValueResolver.cjs +42 -0
- package/src/resolver/ArazzoValueResolver.mjs +37 -0
- package/src/resolver/OpenAPIOperationParameterResolver.cjs +117 -0
- package/src/resolver/OpenAPIOperationParameterResolver.mjs +110 -0
- package/src/resolver/OutputResolver.cjs +71 -0
- package/src/resolver/OutputResolver.mjs +64 -0
- package/src/resolver/RequestBodyResolver.cjs +227 -0
- package/src/resolver/RequestBodyResolver.mjs +220 -0
- package/src/resolver/ResolverScope.cjs +5 -0
- package/src/resolver/ResolverScope.mjs +1 -0
- package/src/resolver/StepParameterResolver.cjs +22 -0
- package/src/resolver/StepParameterResolver.mjs +15 -0
- package/src/resolver/WorkflowParameterResolver.cjs +73 -0
- package/src/resolver/WorkflowParameterResolver.mjs +66 -0
- package/src/state/WorkflowExecutionState.cjs +99 -0
- package/src/state/WorkflowExecutionState.mjs +93 -0
- package/src/vendor/swagger-client.cjs +1 -0
- package/src/vendor/swagger-client.mjs +1 -0
- package/types/runner.d.ts +2410 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
var _empty = require("@speclynx/apidom-reference/configuration/empty");
|
|
10
|
+
var _ArazzoDocument = _interopRequireDefault(require("../document/ArazzoDocument.cjs"));
|
|
11
|
+
var _ArazzoDocumentRegistryProvider = _interopRequireDefault(require("./providers/ArazzoDocumentRegistryProvider.cjs"));
|
|
12
|
+
var _OpenAPIDocumentRegistryProvider = _interopRequireDefault(require("./providers/OpenAPIDocumentRegistryProvider.cjs"));
|
|
13
|
+
var _InvalidEntryDocumentError = _interopRequireDefault(require("../errors/InvalidEntryDocumentError.cjs"));
|
|
14
|
+
var _UnmatchedProviderError = _interopRequireDefault(require("../errors/UnmatchedProviderError.cjs"));
|
|
15
|
+
var constants = _interopRequireWildcard(require("../constants.cjs"));
|
|
16
|
+
/**
|
|
17
|
+
* Options for the DocumentRegistry.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Registry for API documents keyed by canonical URI.
|
|
23
|
+
*
|
|
24
|
+
* Acts as an LRU cache for parsed documents. The entry Arazzo document
|
|
25
|
+
* is pinned and never evicted. Providers are tried in order to detect
|
|
26
|
+
* and load documents.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
class DocumentRegistry {
|
|
30
|
+
#documents = new Map();
|
|
31
|
+
#providers;
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
this.#providers = options.providers ?? [new _ArazzoDocumentRegistryProvider.default(), new _OpenAPIDocumentRegistryProvider.default()];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns the entry Arazzo document, or undefined if not yet registered.
|
|
38
|
+
*/
|
|
39
|
+
get entryDocument() {
|
|
40
|
+
for (const doc of this.#documents.values()) {
|
|
41
|
+
if (_ArazzoDocument.default.is(doc) && doc.isEntry) {
|
|
42
|
+
return doc;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Acquires a document by URI. Returns cached document if available,
|
|
50
|
+
* otherwise detects the format, loads via the matching provider,
|
|
51
|
+
* caches, and returns it.
|
|
52
|
+
*/
|
|
53
|
+
async acquire(uri) {
|
|
54
|
+
const canonicalURI = this.#canonicalize(uri);
|
|
55
|
+
const cachedDocument = this.#get(canonicalURI);
|
|
56
|
+
if (cachedDocument) return cachedDocument;
|
|
57
|
+
for (const provider of this.#providers) {
|
|
58
|
+
if (await provider.canProvide(canonicalURI)) {
|
|
59
|
+
const document = await provider.provide(canonicalURI);
|
|
60
|
+
this.#set(canonicalURI, document);
|
|
61
|
+
return document;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw new _UnmatchedProviderError.default(`No provider can handle the document at "${canonicalURI}"`, {
|
|
65
|
+
uri: canonicalURI
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns an already-loaded document by URI, or undefined if not cached.
|
|
71
|
+
*
|
|
72
|
+
* Synchronous counterpart to `acquire`: it never loads a document, only
|
|
73
|
+
* returns one the registry already holds, marking it most recently used like
|
|
74
|
+
* any other access. Consumers that must resolve a reference without awaiting
|
|
75
|
+
* (e.g. runtime expression evaluation) use this; the executor is responsible
|
|
76
|
+
* for having acquired the document beforehand.
|
|
77
|
+
*/
|
|
78
|
+
get(uri) {
|
|
79
|
+
return this.#get(this.#canonicalize(uri));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Canonical form of a URI, used as the cache key and handed to providers.
|
|
84
|
+
*
|
|
85
|
+
* A relative file system path resolves against the current working directory
|
|
86
|
+
* first: the canonical URI doubles as the base URI for source description
|
|
87
|
+
* URLs, where a relative base resolves against the filesystem root instead of
|
|
88
|
+
* the document. A leading slash or backslash (UNC, drive-rooted) is already
|
|
89
|
+
* rooted and passes through untouched. The working directory is encoded so a
|
|
90
|
+
* directory name containing `#`, `?` or `%` survives URL parsing.
|
|
91
|
+
*/
|
|
92
|
+
#canonicalize(uri) {
|
|
93
|
+
const absoluteURI = !_empty.url.isHttpUrl(uri) && _empty.url.getProtocol(uri) !== 'file' && !/^[\\/]/.test(uri) ? _empty.url.resolve(_empty.url.fromFileSystemPath(_empty.url.cwd()), uri) : uri;
|
|
94
|
+
return _empty.url.sanitize(_empty.url.stripHash(absoluteURI));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Acquires the entry Arazzo document and marks it with `isEntry: true`.
|
|
99
|
+
* Validates that the document is an Arazzo specification.
|
|
100
|
+
*/
|
|
101
|
+
async acquireEntryDocument(uri) {
|
|
102
|
+
const document = await this.acquire(uri);
|
|
103
|
+
if (!_ArazzoDocument.default.is(document)) {
|
|
104
|
+
throw new _InvalidEntryDocumentError.default(`Entry document at "${uri}" is not an Arazzo Document`, {
|
|
105
|
+
uri
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
document.isEntry = true;
|
|
109
|
+
return document;
|
|
110
|
+
}
|
|
111
|
+
clear() {
|
|
112
|
+
this.#documents.clear();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Retrieves a document and marks it as recently used.
|
|
117
|
+
*/
|
|
118
|
+
#get(uri) {
|
|
119
|
+
const doc = this.#documents.get(uri);
|
|
120
|
+
if (doc === undefined) return undefined;
|
|
121
|
+
|
|
122
|
+
// move to end (most recently used)
|
|
123
|
+
this.#documents.delete(uri);
|
|
124
|
+
this.#documents.set(uri, doc);
|
|
125
|
+
return doc;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Registers a document in the registry.
|
|
130
|
+
*
|
|
131
|
+
* If the registry is at capacity, the least recently used document
|
|
132
|
+
* is evicted. The entry Arazzo document is never evicted.
|
|
133
|
+
*/
|
|
134
|
+
#set(uri, document) {
|
|
135
|
+
if (this.#documents.has(uri)) {
|
|
136
|
+
this.#documents.delete(uri);
|
|
137
|
+
} else if (this.#documents.size >= constants.MAX_DOCUMENT_REGISTRY_SIZE) {
|
|
138
|
+
this.#evictOldest();
|
|
139
|
+
}
|
|
140
|
+
this.#documents.set(uri, document);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Removes a document from the registry.
|
|
145
|
+
* The entry document cannot be removed.
|
|
146
|
+
*/
|
|
147
|
+
#delete(uri) {
|
|
148
|
+
const doc = this.#documents.get(uri);
|
|
149
|
+
if (doc && _ArazzoDocument.default.is(doc) && doc.isEntry) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return this.#documents.delete(uri);
|
|
153
|
+
}
|
|
154
|
+
#evictOldest() {
|
|
155
|
+
for (const [uri] of this.#documents) {
|
|
156
|
+
if (this.#delete(uri)) return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
var _default = exports.default = DocumentRegistry;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { url } from '@speclynx/apidom-reference/configuration/empty';
|
|
2
|
+
import ArazzoDocument from "../document/ArazzoDocument.mjs";
|
|
3
|
+
import ArazzoDocumentRegistryProvider from "./providers/ArazzoDocumentRegistryProvider.mjs";
|
|
4
|
+
import OpenAPIDocumentRegistryProvider from "./providers/OpenAPIDocumentRegistryProvider.mjs";
|
|
5
|
+
import InvalidEntryDocumentError from "../errors/InvalidEntryDocumentError.mjs";
|
|
6
|
+
import UnmatchedProviderError from "../errors/UnmatchedProviderError.mjs";
|
|
7
|
+
import * as constants from "../constants.mjs";
|
|
8
|
+
/**
|
|
9
|
+
* Options for the DocumentRegistry.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Registry for API documents keyed by canonical URI.
|
|
14
|
+
*
|
|
15
|
+
* Acts as an LRU cache for parsed documents. The entry Arazzo document
|
|
16
|
+
* is pinned and never evicted. Providers are tried in order to detect
|
|
17
|
+
* and load documents.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
class DocumentRegistry {
|
|
21
|
+
#documents = new Map();
|
|
22
|
+
#providers;
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.#providers = options.providers ?? [new ArazzoDocumentRegistryProvider(), new OpenAPIDocumentRegistryProvider()];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns the entry Arazzo document, or undefined if not yet registered.
|
|
29
|
+
*/
|
|
30
|
+
get entryDocument() {
|
|
31
|
+
for (const doc of this.#documents.values()) {
|
|
32
|
+
if (ArazzoDocument.is(doc) && doc.isEntry) {
|
|
33
|
+
return doc;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Acquires a document by URI. Returns cached document if available,
|
|
41
|
+
* otherwise detects the format, loads via the matching provider,
|
|
42
|
+
* caches, and returns it.
|
|
43
|
+
*/
|
|
44
|
+
async acquire(uri) {
|
|
45
|
+
const canonicalURI = this.#canonicalize(uri);
|
|
46
|
+
const cachedDocument = this.#get(canonicalURI);
|
|
47
|
+
if (cachedDocument) return cachedDocument;
|
|
48
|
+
for (const provider of this.#providers) {
|
|
49
|
+
if (await provider.canProvide(canonicalURI)) {
|
|
50
|
+
const document = await provider.provide(canonicalURI);
|
|
51
|
+
this.#set(canonicalURI, document);
|
|
52
|
+
return document;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
throw new UnmatchedProviderError(`No provider can handle the document at "${canonicalURI}"`, {
|
|
56
|
+
uri: canonicalURI
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns an already-loaded document by URI, or undefined if not cached.
|
|
62
|
+
*
|
|
63
|
+
* Synchronous counterpart to `acquire`: it never loads a document, only
|
|
64
|
+
* returns one the registry already holds, marking it most recently used like
|
|
65
|
+
* any other access. Consumers that must resolve a reference without awaiting
|
|
66
|
+
* (e.g. runtime expression evaluation) use this; the executor is responsible
|
|
67
|
+
* for having acquired the document beforehand.
|
|
68
|
+
*/
|
|
69
|
+
get(uri) {
|
|
70
|
+
return this.#get(this.#canonicalize(uri));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Canonical form of a URI, used as the cache key and handed to providers.
|
|
75
|
+
*
|
|
76
|
+
* A relative file system path resolves against the current working directory
|
|
77
|
+
* first: the canonical URI doubles as the base URI for source description
|
|
78
|
+
* URLs, where a relative base resolves against the filesystem root instead of
|
|
79
|
+
* the document. A leading slash or backslash (UNC, drive-rooted) is already
|
|
80
|
+
* rooted and passes through untouched. The working directory is encoded so a
|
|
81
|
+
* directory name containing `#`, `?` or `%` survives URL parsing.
|
|
82
|
+
*/
|
|
83
|
+
#canonicalize(uri) {
|
|
84
|
+
const absoluteURI = !url.isHttpUrl(uri) && url.getProtocol(uri) !== 'file' && !/^[\\/]/.test(uri) ? url.resolve(url.fromFileSystemPath(url.cwd()), uri) : uri;
|
|
85
|
+
return url.sanitize(url.stripHash(absoluteURI));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Acquires the entry Arazzo document and marks it with `isEntry: true`.
|
|
90
|
+
* Validates that the document is an Arazzo specification.
|
|
91
|
+
*/
|
|
92
|
+
async acquireEntryDocument(uri) {
|
|
93
|
+
const document = await this.acquire(uri);
|
|
94
|
+
if (!ArazzoDocument.is(document)) {
|
|
95
|
+
throw new InvalidEntryDocumentError(`Entry document at "${uri}" is not an Arazzo Document`, {
|
|
96
|
+
uri
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
document.isEntry = true;
|
|
100
|
+
return document;
|
|
101
|
+
}
|
|
102
|
+
clear() {
|
|
103
|
+
this.#documents.clear();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Retrieves a document and marks it as recently used.
|
|
108
|
+
*/
|
|
109
|
+
#get(uri) {
|
|
110
|
+
const doc = this.#documents.get(uri);
|
|
111
|
+
if (doc === undefined) return undefined;
|
|
112
|
+
|
|
113
|
+
// move to end (most recently used)
|
|
114
|
+
this.#documents.delete(uri);
|
|
115
|
+
this.#documents.set(uri, doc);
|
|
116
|
+
return doc;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Registers a document in the registry.
|
|
121
|
+
*
|
|
122
|
+
* If the registry is at capacity, the least recently used document
|
|
123
|
+
* is evicted. The entry Arazzo document is never evicted.
|
|
124
|
+
*/
|
|
125
|
+
#set(uri, document) {
|
|
126
|
+
if (this.#documents.has(uri)) {
|
|
127
|
+
this.#documents.delete(uri);
|
|
128
|
+
} else if (this.#documents.size >= constants.MAX_DOCUMENT_REGISTRY_SIZE) {
|
|
129
|
+
this.#evictOldest();
|
|
130
|
+
}
|
|
131
|
+
this.#documents.set(uri, document);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Removes a document from the registry.
|
|
136
|
+
* The entry document cannot be removed.
|
|
137
|
+
*/
|
|
138
|
+
#delete(uri) {
|
|
139
|
+
const doc = this.#documents.get(uri);
|
|
140
|
+
if (doc && ArazzoDocument.is(doc) && doc.isEntry) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return this.#documents.delete(uri);
|
|
144
|
+
}
|
|
145
|
+
#evictOldest() {
|
|
146
|
+
for (const [uri] of this.#documents) {
|
|
147
|
+
if (this.#delete(uri)) return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export default DocumentRegistry;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.providerOptionsOverride = exports.default = void 0;
|
|
9
|
+
var _parser = require("@usearazzo/parser");
|
|
10
|
+
var _empty = require("@speclynx/apidom-reference/configuration/empty");
|
|
11
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
12
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
13
|
+
var _apidomTraverse = require("@speclynx/apidom-traverse");
|
|
14
|
+
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
15
|
+
var constants = _interopRequireWildcard(require("../../constants.cjs"));
|
|
16
|
+
var _ArazzoDocument = _interopRequireDefault(require("../../document/ArazzoDocument.cjs"));
|
|
17
|
+
var _DocumentRegistryProvider = _interopRequireWildcard(require("./DocumentRegistryProvider.cjs"));
|
|
18
|
+
var _ArazzoWorkflowIndex = _interopRequireDefault(require("../../document/ArazzoWorkflowIndex.cjs"));
|
|
19
|
+
var _ArazzoStepIndex = _interopRequireDefault(require("../../document/ArazzoStepIndex.cjs"));
|
|
20
|
+
var _ArazzoSourceDescriptionIndex = _interopRequireDefault(require("../../document/ArazzoSourceDescriptionIndex.cjs"));
|
|
21
|
+
/**
|
|
22
|
+
* Options for loading an Arazzo document.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Default options for loading an Arazzo document.
|
|
28
|
+
*
|
|
29
|
+
* The provider only parses the Arazzo document; dereferencing is deferred
|
|
30
|
+
* to the normalizer when a specific workflow is accessed.
|
|
31
|
+
*/
|
|
32
|
+
const providerOptionsOverride = exports.providerOptionsOverride = {
|
|
33
|
+
resolve: {
|
|
34
|
+
resolverOpts: {
|
|
35
|
+
cache: {
|
|
36
|
+
maxEntries: constants.MAX_HTTP_CACHE_ENTRIES,
|
|
37
|
+
maxStaleAge: constants.MAX_HTTP_CACHE_STALE_AGE
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
dereference: {
|
|
42
|
+
immutable: false,
|
|
43
|
+
circular: 'replace',
|
|
44
|
+
circularReplacer: _DocumentRegistryProvider.circularReplacer,
|
|
45
|
+
strategyOpts: {
|
|
46
|
+
sourceDescriptions: false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Provides ArazzoDocument instances for the DocumentRegistry.
|
|
53
|
+
*
|
|
54
|
+
* Parses the Arazzo document and builds its workflow and source description
|
|
55
|
+
* indexes — the document itself is a container.
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
class ArazzoDocumentRegistryProvider extends _DocumentRegistryProvider.default {
|
|
59
|
+
#options;
|
|
60
|
+
constructor(options = {}) {
|
|
61
|
+
super();
|
|
62
|
+
this.#options = (0, _empty.mergeOptions)(providerOptionsOverride, options);
|
|
63
|
+
}
|
|
64
|
+
async canProvide(uri) {
|
|
65
|
+
try {
|
|
66
|
+
const options = this.#buildParseOptions();
|
|
67
|
+
const data = await (0, _empty.readFile)(uri, options);
|
|
68
|
+
const file = new _empty.File({
|
|
69
|
+
uri,
|
|
70
|
+
data
|
|
71
|
+
});
|
|
72
|
+
const parsers = options.parse.parsers.filter(p => p.name.startsWith('arazzo'));
|
|
73
|
+
for (const parser of parsers) {
|
|
74
|
+
if (await parser.canParse(file)) return true;
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (error instanceof _empty.UnmatchedResolverError) return false;
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Loads an Arazzo document from a URI and produces an ArazzoDocument.
|
|
85
|
+
*/
|
|
86
|
+
async provide(uri) {
|
|
87
|
+
const parseResult = await (0, _parser.parseArazzo)(uri, this.#buildParseOptions());
|
|
88
|
+
const {
|
|
89
|
+
workflowIndex,
|
|
90
|
+
stepIndex,
|
|
91
|
+
sourceDescriptionIndex
|
|
92
|
+
} = this.#buildIndexes(uri, parseResult);
|
|
93
|
+
return new _ArazzoDocument.default(uri, parseResult, workflowIndex, stepIndex, sourceDescriptionIndex);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Builds all indexes in one traversal of the parse result.
|
|
98
|
+
*
|
|
99
|
+
* A source description's canonical URI is resolved here too — against the
|
|
100
|
+
* document's base URI, into the exact form the document registry keys on —
|
|
101
|
+
* so every consumer works with a ready-to-use, non-relative URI. The first
|
|
102
|
+
* element of a duplicated source description name wins.
|
|
103
|
+
*/
|
|
104
|
+
#buildIndexes(uri, parseResult) {
|
|
105
|
+
const workflowIndex = new _ArazzoWorkflowIndex.default();
|
|
106
|
+
const stepIndex = new _ArazzoStepIndex.default();
|
|
107
|
+
const sourceDescriptionIndex = new _ArazzoSourceDescriptionIndex.default();
|
|
108
|
+
(0, _apidomTraverse.traverse)(parseResult.api, {
|
|
109
|
+
WorkflowElement(path) {
|
|
110
|
+
const workflow = path.node;
|
|
111
|
+
const workflowId = (0, _apidomCore.toValue)(workflow.workflowId);
|
|
112
|
+
if (typeof workflowId !== 'string') return path.skip();
|
|
113
|
+
if (workflowId === '') return path.skip();
|
|
114
|
+
const workflowPointer = path.formatPath('jsonpointer');
|
|
115
|
+
workflowIndex.set(workflowId, workflowPointer);
|
|
116
|
+
|
|
117
|
+
// steps are indexed by list position; malformed entries are left to the
|
|
118
|
+
// executor to report, the index simply omits them.
|
|
119
|
+
const steps = new Map();
|
|
120
|
+
if ((0, _apidomDatamodel.isArrayElement)(workflow.steps)) {
|
|
121
|
+
[...workflow.steps].forEach((step, index) => {
|
|
122
|
+
if (!(0, _apidomNsArazzo.isStepElement)(step)) return;
|
|
123
|
+
const stepId = (0, _apidomCore.toValue)(step.stepId);
|
|
124
|
+
if (typeof stepId !== 'string' || stepId === '') return;
|
|
125
|
+
if (!steps.has(stepId)) steps.set(stepId, `${workflowPointer}/steps/${index}`);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
stepIndex.set(workflowId, steps);
|
|
129
|
+
return path.skip();
|
|
130
|
+
},
|
|
131
|
+
SourceDescriptionElement(path) {
|
|
132
|
+
const element = path.node;
|
|
133
|
+
if (!(0, _apidomDatamodel.isStringElement)(element.name)) return path.skip();
|
|
134
|
+
const name = (0, _apidomCore.toValue)(element.name);
|
|
135
|
+
if (!sourceDescriptionIndex.has(name)) {
|
|
136
|
+
sourceDescriptionIndex.set(name, {
|
|
137
|
+
element,
|
|
138
|
+
uri: (0, _apidomDatamodel.isStringElement)(element.url) ? _empty.url.sanitize(_empty.url.stripHash(_empty.url.resolve(uri, (0, _apidomCore.toValue)(element.url)))) : undefined
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return path.skip();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
workflowIndex,
|
|
146
|
+
stepIndex,
|
|
147
|
+
sourceDescriptionIndex
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
#buildParseOptions() {
|
|
151
|
+
return (0, _empty.mergeOptions)(_parser.defaultParseArazzoOptions, this.#options);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
var _default = exports.default = ArazzoDocumentRegistryProvider;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { parseArazzo, defaultParseArazzoOptions } from '@usearazzo/parser';
|
|
2
|
+
import { readFile, File, mergeOptions, url } from '@speclynx/apidom-reference/configuration/empty';
|
|
3
|
+
import { UnmatchedResolverError } from '@speclynx/apidom-reference/configuration/empty';
|
|
4
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
5
|
+
import { isArrayElement, isStringElement } from '@speclynx/apidom-datamodel';
|
|
6
|
+
import { traverse } from '@speclynx/apidom-traverse';
|
|
7
|
+
import { isStepElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
8
|
+
import * as constants from "../../constants.mjs";
|
|
9
|
+
import ArazzoDocument from "../../document/ArazzoDocument.mjs";
|
|
10
|
+
import DocumentRegistryProvider, { circularReplacer } from "./DocumentRegistryProvider.mjs";
|
|
11
|
+
import ArazzoWorkflowIndex from "../../document/ArazzoWorkflowIndex.mjs";
|
|
12
|
+
import ArazzoStepIndex from "../../document/ArazzoStepIndex.mjs";
|
|
13
|
+
import ArazzoSourceDescriptionIndex from "../../document/ArazzoSourceDescriptionIndex.mjs";
|
|
14
|
+
/**
|
|
15
|
+
* Options for loading an Arazzo document.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Default options for loading an Arazzo document.
|
|
20
|
+
*
|
|
21
|
+
* The provider only parses the Arazzo document; dereferencing is deferred
|
|
22
|
+
* to the normalizer when a specific workflow is accessed.
|
|
23
|
+
*/
|
|
24
|
+
export const providerOptionsOverride = {
|
|
25
|
+
resolve: {
|
|
26
|
+
resolverOpts: {
|
|
27
|
+
cache: {
|
|
28
|
+
maxEntries: constants.MAX_HTTP_CACHE_ENTRIES,
|
|
29
|
+
maxStaleAge: constants.MAX_HTTP_CACHE_STALE_AGE
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
dereference: {
|
|
34
|
+
immutable: false,
|
|
35
|
+
circular: 'replace',
|
|
36
|
+
circularReplacer,
|
|
37
|
+
strategyOpts: {
|
|
38
|
+
sourceDescriptions: false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Provides ArazzoDocument instances for the DocumentRegistry.
|
|
45
|
+
*
|
|
46
|
+
* Parses the Arazzo document and builds its workflow and source description
|
|
47
|
+
* indexes — the document itself is a container.
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
class ArazzoDocumentRegistryProvider extends DocumentRegistryProvider {
|
|
51
|
+
#options;
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
super();
|
|
54
|
+
this.#options = mergeOptions(providerOptionsOverride, options);
|
|
55
|
+
}
|
|
56
|
+
async canProvide(uri) {
|
|
57
|
+
try {
|
|
58
|
+
const options = this.#buildParseOptions();
|
|
59
|
+
const data = await readFile(uri, options);
|
|
60
|
+
const file = new File({
|
|
61
|
+
uri,
|
|
62
|
+
data
|
|
63
|
+
});
|
|
64
|
+
const parsers = options.parse.parsers.filter(p => p.name.startsWith('arazzo'));
|
|
65
|
+
for (const parser of parsers) {
|
|
66
|
+
if (await parser.canParse(file)) return true;
|
|
67
|
+
}
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error instanceof UnmatchedResolverError) return false;
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Loads an Arazzo document from a URI and produces an ArazzoDocument.
|
|
77
|
+
*/
|
|
78
|
+
async provide(uri) {
|
|
79
|
+
const parseResult = await parseArazzo(uri, this.#buildParseOptions());
|
|
80
|
+
const {
|
|
81
|
+
workflowIndex,
|
|
82
|
+
stepIndex,
|
|
83
|
+
sourceDescriptionIndex
|
|
84
|
+
} = this.#buildIndexes(uri, parseResult);
|
|
85
|
+
return new ArazzoDocument(uri, parseResult, workflowIndex, stepIndex, sourceDescriptionIndex);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Builds all indexes in one traversal of the parse result.
|
|
90
|
+
*
|
|
91
|
+
* A source description's canonical URI is resolved here too — against the
|
|
92
|
+
* document's base URI, into the exact form the document registry keys on —
|
|
93
|
+
* so every consumer works with a ready-to-use, non-relative URI. The first
|
|
94
|
+
* element of a duplicated source description name wins.
|
|
95
|
+
*/
|
|
96
|
+
#buildIndexes(uri, parseResult) {
|
|
97
|
+
const workflowIndex = new ArazzoWorkflowIndex();
|
|
98
|
+
const stepIndex = new ArazzoStepIndex();
|
|
99
|
+
const sourceDescriptionIndex = new ArazzoSourceDescriptionIndex();
|
|
100
|
+
traverse(parseResult.api, {
|
|
101
|
+
WorkflowElement(path) {
|
|
102
|
+
const workflow = path.node;
|
|
103
|
+
const workflowId = toValue(workflow.workflowId);
|
|
104
|
+
if (typeof workflowId !== 'string') return path.skip();
|
|
105
|
+
if (workflowId === '') return path.skip();
|
|
106
|
+
const workflowPointer = path.formatPath('jsonpointer');
|
|
107
|
+
workflowIndex.set(workflowId, workflowPointer);
|
|
108
|
+
|
|
109
|
+
// steps are indexed by list position; malformed entries are left to the
|
|
110
|
+
// executor to report, the index simply omits them.
|
|
111
|
+
const steps = new Map();
|
|
112
|
+
if (isArrayElement(workflow.steps)) {
|
|
113
|
+
[...workflow.steps].forEach((step, index) => {
|
|
114
|
+
if (!isStepElement(step)) return;
|
|
115
|
+
const stepId = toValue(step.stepId);
|
|
116
|
+
if (typeof stepId !== 'string' || stepId === '') return;
|
|
117
|
+
if (!steps.has(stepId)) steps.set(stepId, `${workflowPointer}/steps/${index}`);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
stepIndex.set(workflowId, steps);
|
|
121
|
+
return path.skip();
|
|
122
|
+
},
|
|
123
|
+
SourceDescriptionElement(path) {
|
|
124
|
+
const element = path.node;
|
|
125
|
+
if (!isStringElement(element.name)) return path.skip();
|
|
126
|
+
const name = toValue(element.name);
|
|
127
|
+
if (!sourceDescriptionIndex.has(name)) {
|
|
128
|
+
sourceDescriptionIndex.set(name, {
|
|
129
|
+
element,
|
|
130
|
+
uri: isStringElement(element.url) ? url.sanitize(url.stripHash(url.resolve(uri, toValue(element.url)))) : undefined
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return path.skip();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
workflowIndex,
|
|
138
|
+
stepIndex,
|
|
139
|
+
sourceDescriptionIndex
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
#buildParseOptions() {
|
|
143
|
+
return mergeOptions(defaultParseArazzoOptions, this.#options);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
export default ArazzoDocumentRegistryProvider;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.circularReplacer = void 0;
|
|
7
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
8
|
+
/**
|
|
9
|
+
* Replaces circular $ref references with an empty ObjectElement
|
|
10
|
+
* annotated with the original $ref value. This ensures the dereferenced
|
|
11
|
+
* output is a finite tree safe for downstream tools.
|
|
12
|
+
* @param ref - The RefElement being replaced at the cycle boundary.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
const circularReplacer = ref => new _apidomDatamodel.ObjectElement({
|
|
16
|
+
'x-circular': ref.meta.get('$ref')
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Options for a document registry provider.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
exports.circularReplacer = circularReplacer;
|
|
24
|
+
/**
|
|
25
|
+
* Base class for document registry providers.
|
|
26
|
+
*
|
|
27
|
+
* Subclasses implement `canProvide()` for format detection and `provide()` for loading.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
class DocumentRegistryProvider {}
|
|
31
|
+
var _default = exports.default = DocumentRegistryProvider;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ObjectElement } from '@speclynx/apidom-datamodel';
|
|
2
|
+
/**
|
|
3
|
+
* Replaces circular $ref references with an empty ObjectElement
|
|
4
|
+
* annotated with the original $ref value. This ensures the dereferenced
|
|
5
|
+
* output is a finite tree safe for downstream tools.
|
|
6
|
+
* @param ref - The RefElement being replaced at the cycle boundary.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export const circularReplacer = ref => new ObjectElement({
|
|
10
|
+
'x-circular': ref.meta.get('$ref')
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Options for a document registry provider.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Base class for document registry providers.
|
|
20
|
+
*
|
|
21
|
+
* Subclasses implement `canProvide()` for format detection and `provide()` for loading.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
class DocumentRegistryProvider {}
|
|
25
|
+
export default DocumentRegistryProvider;
|