@jentic/arazzo-resolver 1.0.0-alpha.24 → 1.0.0-alpha.25
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 +6 -0
- package/package.json +4 -5
- package/src/dereference/arazzo.cjs +231 -0
- package/src/dereference/arazzo.mjs +223 -0
- package/src/dereference/openapi.cjs +224 -0
- package/src/dereference/openapi.mjs +216 -0
- package/src/errors/DereferenceError.cjs +15 -0
- package/src/errors/DereferenceError.mjs +12 -0
- package/src/index.cjs +15 -0
- package/src/index.mjs +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.0.0-alpha.25](https://github.com/jentic/jentic-arazzo-tools/compare/v1.0.0-alpha.24...v1.0.0-alpha.25) (2026-03-11)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **release:** fix issue in lerna not publishing _.cjs|_.mjs files ([8982184](https://github.com/jentic/jentic-arazzo-tools/commit/8982184ddae167b6f2a772114f9a9321f3b67d14))
|
|
11
|
+
|
|
6
12
|
# [1.0.0-alpha.24](https://github.com/jentic/jentic-arazzo-tools/compare/v1.0.0-alpha.23...v1.0.0-alpha.24) (2026-03-11)
|
|
7
13
|
|
|
8
14
|
**Note:** Version bump only for package @jentic/arazzo-resolver
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jentic/arazzo-resolver",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.25",
|
|
4
4
|
"description": "Resolver for Arazzo Documents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arazzo",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"license": "Apache-2.0",
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@babel/runtime-corejs3": "^7.28.4",
|
|
52
|
-
"@jentic/arazzo-parser": "1.0.0-alpha.
|
|
52
|
+
"@jentic/arazzo-parser": "1.0.0-alpha.25",
|
|
53
53
|
"@speclynx/apidom-datamodel": "^4.0.3",
|
|
54
54
|
"@speclynx/apidom-error": "^4.0.3",
|
|
55
55
|
"@speclynx/apidom-ns-arazzo-1": "^4.0.3",
|
|
@@ -63,8 +63,7 @@
|
|
|
63
63
|
"@speclynx/apidom-core": "^4.0.3"
|
|
64
64
|
},
|
|
65
65
|
"files": [
|
|
66
|
-
"src
|
|
67
|
-
"src/**/*.cjs",
|
|
66
|
+
"src/",
|
|
68
67
|
"dist/",
|
|
69
68
|
"types/arazzo-resolver.d.ts",
|
|
70
69
|
"LICENSE",
|
|
@@ -72,5 +71,5 @@
|
|
|
72
71
|
"README.md",
|
|
73
72
|
"CHANGELOG.md"
|
|
74
73
|
],
|
|
75
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "b9a3213b0561fc58e0491c7e638d6a96383befff"
|
|
76
75
|
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.defaultOptions = void 0;
|
|
6
|
+
exports.dereference = dereference;
|
|
7
|
+
exports.dereferenceElement = dereferenceElement;
|
|
8
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
9
|
+
var _empty = require("@speclynx/apidom-reference/configuration/empty");
|
|
10
|
+
var _arazzo = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/arazzo-1"));
|
|
11
|
+
var _openapi = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/openapi-2"));
|
|
12
|
+
var _openapi2 = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/openapi-3-0"));
|
|
13
|
+
var _openapi3 = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/openapi-3-1"));
|
|
14
|
+
var _json = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/json"));
|
|
15
|
+
var _yaml = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/yaml-1-2"));
|
|
16
|
+
var _binary = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/binary"));
|
|
17
|
+
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
18
|
+
var _arazzoParser = require("@jentic/arazzo-parser");
|
|
19
|
+
var _DereferenceError = _interopRequireDefault(require("../errors/DereferenceError.cjs"));
|
|
20
|
+
/**
|
|
21
|
+
* Options for dereferencing Arazzo Documents.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Default reference options for dereferencing Arazzo Documents.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
const defaultOptions = exports.defaultOptions = {
|
|
30
|
+
resolve: {
|
|
31
|
+
resolvers: [..._arazzoParser.defaultArazzoOptions.resolve.resolvers]
|
|
32
|
+
},
|
|
33
|
+
parse: {
|
|
34
|
+
parsers: [..._arazzoParser.defaultArazzoOptions.parse.parsers, new _json.default({
|
|
35
|
+
allowEmpty: false
|
|
36
|
+
}), new _yaml.default({
|
|
37
|
+
allowEmpty: false
|
|
38
|
+
}), new _binary.default({
|
|
39
|
+
allowEmpty: false
|
|
40
|
+
})],
|
|
41
|
+
parserOpts: {
|
|
42
|
+
..._arazzoParser.defaultArazzoOptions.parse.parserOpts
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
dereference: {
|
|
46
|
+
strategies: [new _arazzo.default(), new _openapi.default(), new _openapi2.default(), new _openapi3.default()],
|
|
47
|
+
strategyOpts: {
|
|
48
|
+
sourceDescriptions: false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Dereferences an Arazzo Document from a file system path or HTTP(S) URL.
|
|
55
|
+
*
|
|
56
|
+
* This function resolves all JSON References ($ref) and Reusable Object references
|
|
57
|
+
* ($components.*) in the Arazzo Document.
|
|
58
|
+
*
|
|
59
|
+
* Source descriptions can optionally be dereferenced using strategy options:
|
|
60
|
+
* - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
|
|
61
|
+
* - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
|
|
62
|
+
*
|
|
63
|
+
* Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
|
|
64
|
+
*
|
|
65
|
+
* @param uri - A file system path or HTTP(S) URL to the Arazzo Document
|
|
66
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
67
|
+
* @returns A promise that resolves to the dereferenced Arazzo Document as ApiDOM element
|
|
68
|
+
* @throws DereferenceError - When dereferencing fails or document is not an Arazzo specification. The original error is available via the `cause` property.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // Dereference from file
|
|
72
|
+
* const result = await dereferenceArazzo('/path/to/arazzo.json');
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Dereference from URL
|
|
76
|
+
* const result = await dereferenceArazzo('https://example.com/arazzo.yaml');
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* Dereference with source descriptions
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const result = await dereferenceArazzo('/path/to/arazzo.json', {
|
|
82
|
+
* dereference: { strategyOpts: { sourceDescriptions: true } },
|
|
83
|
+
* });
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* // Dereference with custom options
|
|
88
|
+
* const result = await dereferenceArazzo('/path/to/arazzo.json', customReferenceOptions);
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
async function dereference(uri, options = {}) {
|
|
92
|
+
const mergedOptions = (0, _empty.mergeOptions)(defaultOptions, options);
|
|
93
|
+
try {
|
|
94
|
+
const parseResult = await (0, _empty.dereference)(uri, mergedOptions);
|
|
95
|
+
|
|
96
|
+
// validate that the dereferenced document is an Arazzo specification
|
|
97
|
+
if (!(0, _apidomNsArazzo.isArazzoSpecification1Element)(parseResult.api)) {
|
|
98
|
+
throw new _empty.UnmatchedDereferenceStrategyError(`Could not find a dereference strategy that can dereference "${uri}" as an Arazzo specification`);
|
|
99
|
+
}
|
|
100
|
+
parseResult.meta.set('retrievalURI', uri);
|
|
101
|
+
return parseResult;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
throw new _DereferenceError.default(`Failed to dereference Arazzo Document at "${uri}"`, {
|
|
104
|
+
cause: error
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Dereferences an ApiDOM element representing an Arazzo Document.
|
|
111
|
+
*
|
|
112
|
+
* This function resolves all JSON References ($ref) and Reusable Object references
|
|
113
|
+
* ($components.*) in the Arazzo Document element.
|
|
114
|
+
*
|
|
115
|
+
* Supported scenarios:
|
|
116
|
+
* - ParseResultElement with retrievalURI metadata: baseURI derived automatically
|
|
117
|
+
* - ParseResultElement without retrievalURI: requires `options.resolve.baseURI`
|
|
118
|
+
* - Child element (e.g., WorkflowElement) with parseResult in strategyOpts:
|
|
119
|
+
* requires `options.dereference.strategyOpts.parseResult` for component resolution,
|
|
120
|
+
* and `options.resolve.baseURI` if parseResult lacks retrievalURI metadata
|
|
121
|
+
*
|
|
122
|
+
* Source descriptions can optionally be dereferenced using strategy options:
|
|
123
|
+
* - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
|
|
124
|
+
* - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
|
|
125
|
+
*
|
|
126
|
+
* Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
|
|
127
|
+
*
|
|
128
|
+
* @param element - An ApiDOM element (ParseResultElement or child element like WorkflowElement)
|
|
129
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
130
|
+
* @returns A promise that resolves to the dereferenced element
|
|
131
|
+
* @throws DereferenceError - When baseURI is required but not provided, or when dereferencing fails
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* Dereference ParseResultElement with retrievalURI (from file parsing)
|
|
135
|
+
* ```typescript
|
|
136
|
+
* import { parseArazzo } from '@jentic/arazzo-parser';
|
|
137
|
+
*
|
|
138
|
+
* const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
139
|
+
* const dereferenced = await dereferenceArazzoElement(parseResult);
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* Dereference ParseResultElement without retrievalURI (from inline parsing)
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const parseResult = await parseArazzo({ arazzo: '1.0.1', ... });
|
|
146
|
+
* const dereferenced = await dereferenceArazzoElement(parseResult, {
|
|
147
|
+
* resolve: { baseURI: 'https://example.com/arazzo.json' },
|
|
148
|
+
* });
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* Dereference child element (e.g., WorkflowElement)
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
155
|
+
* const workflow = parseResult.api.workflows.get(0);
|
|
156
|
+
* const dereferenced = await dereferenceArazzoElement(workflow, {
|
|
157
|
+
* dereference: { strategyOpts: { parseResult } },
|
|
158
|
+
* });
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* Dereference with source descriptions
|
|
163
|
+
* ```typescript
|
|
164
|
+
* const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
165
|
+
* const dereferenced = await dereferenceArazzoElement(parseResult, {
|
|
166
|
+
* dereference: { strategyOpts: { sourceDescriptions: true } },
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
169
|
+
* @public
|
|
170
|
+
*/
|
|
171
|
+
async function dereferenceElement(element, options = {}) {
|
|
172
|
+
const mergedOptions = (0, _empty.mergeOptions)(defaultOptions, options);
|
|
173
|
+
const refSet = mergedOptions.dereference?.refSet ?? new _empty.ReferenceSet();
|
|
174
|
+
let baseURI = mergedOptions.resolve?.baseURI;
|
|
175
|
+
let mediaType = 'text/plain';
|
|
176
|
+
if (refSet.size === 0) {
|
|
177
|
+
if ((0, _apidomDatamodel.isParseResultElement)(element)) {
|
|
178
|
+
if ((0, _apidomNsArazzo.isArazzoSpecification1Element)(element.api)) {
|
|
179
|
+
mediaType = _apidomNsArazzo.mediaTypes.latest();
|
|
180
|
+
}
|
|
181
|
+
if (element.hasMetaProperty('retrievalURI')) {
|
|
182
|
+
baseURI = element.meta.get('retrievalURI');
|
|
183
|
+
} else if (!baseURI) {
|
|
184
|
+
throw new _DereferenceError.default('baseURI option is required when dereferencing a ParseResultElement without retrievalURI metadata');
|
|
185
|
+
}
|
|
186
|
+
} else if ((0, _apidomDatamodel.isParseResultElement)(mergedOptions.dereference?.strategyOpts?.parseResult)) {
|
|
187
|
+
// dereferencing child element requires refSet for component resolution
|
|
188
|
+
const {
|
|
189
|
+
parseResult
|
|
190
|
+
} = mergedOptions.dereference.strategyOpts;
|
|
191
|
+
let rootURI;
|
|
192
|
+
if ((0, _apidomNsArazzo.isArazzoSpecification1Element)(parseResult.api)) {
|
|
193
|
+
mediaType = _apidomNsArazzo.mediaTypes.latest();
|
|
194
|
+
}
|
|
195
|
+
if (parseResult.hasMetaProperty('retrievalURI')) {
|
|
196
|
+
rootURI = parseResult.meta.get('retrievalURI');
|
|
197
|
+
} else if (baseURI) {
|
|
198
|
+
rootURI = baseURI;
|
|
199
|
+
} else {
|
|
200
|
+
throw new _DereferenceError.default('baseURI option is required when dereferencing a child element without retrievalURI metadata');
|
|
201
|
+
}
|
|
202
|
+
const elementReference = new _empty.Reference({
|
|
203
|
+
uri: `${rootURI}#fragment`,
|
|
204
|
+
value: new _apidomDatamodel.ParseResultElement([element])
|
|
205
|
+
});
|
|
206
|
+
const rootReference = new _empty.Reference({
|
|
207
|
+
uri: rootURI,
|
|
208
|
+
value: parseResult
|
|
209
|
+
});
|
|
210
|
+
refSet.add(elementReference).add(rootReference);
|
|
211
|
+
baseURI = rootURI;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
return await (0, _empty.dereferenceApiDOM)(element, (0, _empty.mergeOptions)(mergedOptions, {
|
|
216
|
+
resolve: {
|
|
217
|
+
baseURI
|
|
218
|
+
},
|
|
219
|
+
parse: {
|
|
220
|
+
mediaType
|
|
221
|
+
},
|
|
222
|
+
dereference: {
|
|
223
|
+
refSet
|
|
224
|
+
}
|
|
225
|
+
}));
|
|
226
|
+
} catch (error) {
|
|
227
|
+
throw new _DereferenceError.default('Failed to dereference Arazzo Document', {
|
|
228
|
+
cause: error
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { isParseResultElement, ParseResultElement } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { dereference as dereferenceURI, dereferenceApiDOM as dereferenceApiDOMElement, mergeOptions, ReferenceSet, Reference, UnmatchedDereferenceStrategyError } from '@speclynx/apidom-reference/configuration/empty';
|
|
3
|
+
import Arazzo1DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/arazzo-1';
|
|
4
|
+
import OpenAPI2DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/openapi-2';
|
|
5
|
+
import OpenAPI30DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/openapi-3-0';
|
|
6
|
+
import OpenAPI31DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/openapi-3-1';
|
|
7
|
+
import JSONParser from '@speclynx/apidom-reference/parse/parsers/json';
|
|
8
|
+
import YAMLParser from '@speclynx/apidom-reference/parse/parsers/yaml-1-2';
|
|
9
|
+
import BinaryParser from '@speclynx/apidom-reference/parse/parsers/binary';
|
|
10
|
+
import { isArazzoSpecification1Element, mediaTypes } from '@speclynx/apidom-ns-arazzo-1';
|
|
11
|
+
import { defaultArazzoOptions as parserDefaultOptions } from '@jentic/arazzo-parser';
|
|
12
|
+
import DereferenceError from "../errors/DereferenceError.mjs";
|
|
13
|
+
/**
|
|
14
|
+
* Options for dereferencing Arazzo Documents.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Default reference options for dereferencing Arazzo Documents.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export const defaultOptions = {
|
|
22
|
+
resolve: {
|
|
23
|
+
resolvers: [...parserDefaultOptions.resolve.resolvers]
|
|
24
|
+
},
|
|
25
|
+
parse: {
|
|
26
|
+
parsers: [...parserDefaultOptions.parse.parsers, new JSONParser({
|
|
27
|
+
allowEmpty: false
|
|
28
|
+
}), new YAMLParser({
|
|
29
|
+
allowEmpty: false
|
|
30
|
+
}), new BinaryParser({
|
|
31
|
+
allowEmpty: false
|
|
32
|
+
})],
|
|
33
|
+
parserOpts: {
|
|
34
|
+
...parserDefaultOptions.parse.parserOpts
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
dereference: {
|
|
38
|
+
strategies: [new Arazzo1DereferenceStrategy(), new OpenAPI2DereferenceStrategy(), new OpenAPI30DereferenceStrategy(), new OpenAPI31DereferenceStrategy()],
|
|
39
|
+
strategyOpts: {
|
|
40
|
+
sourceDescriptions: false
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Dereferences an Arazzo Document from a file system path or HTTP(S) URL.
|
|
47
|
+
*
|
|
48
|
+
* This function resolves all JSON References ($ref) and Reusable Object references
|
|
49
|
+
* ($components.*) in the Arazzo Document.
|
|
50
|
+
*
|
|
51
|
+
* Source descriptions can optionally be dereferenced using strategy options:
|
|
52
|
+
* - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
|
|
53
|
+
* - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
|
|
54
|
+
*
|
|
55
|
+
* Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
|
|
56
|
+
*
|
|
57
|
+
* @param uri - A file system path or HTTP(S) URL to the Arazzo Document
|
|
58
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
59
|
+
* @returns A promise that resolves to the dereferenced Arazzo Document as ApiDOM element
|
|
60
|
+
* @throws DereferenceError - When dereferencing fails or document is not an Arazzo specification. The original error is available via the `cause` property.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* // Dereference from file
|
|
64
|
+
* const result = await dereferenceArazzo('/path/to/arazzo.json');
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Dereference from URL
|
|
68
|
+
* const result = await dereferenceArazzo('https://example.com/arazzo.yaml');
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* Dereference with source descriptions
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const result = await dereferenceArazzo('/path/to/arazzo.json', {
|
|
74
|
+
* dereference: { strategyOpts: { sourceDescriptions: true } },
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Dereference with custom options
|
|
80
|
+
* const result = await dereferenceArazzo('/path/to/arazzo.json', customReferenceOptions);
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
export async function dereference(uri, options = {}) {
|
|
84
|
+
const mergedOptions = mergeOptions(defaultOptions, options);
|
|
85
|
+
try {
|
|
86
|
+
const parseResult = await dereferenceURI(uri, mergedOptions);
|
|
87
|
+
|
|
88
|
+
// validate that the dereferenced document is an Arazzo specification
|
|
89
|
+
if (!isArazzoSpecification1Element(parseResult.api)) {
|
|
90
|
+
throw new UnmatchedDereferenceStrategyError(`Could not find a dereference strategy that can dereference "${uri}" as an Arazzo specification`);
|
|
91
|
+
}
|
|
92
|
+
parseResult.meta.set('retrievalURI', uri);
|
|
93
|
+
return parseResult;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
throw new DereferenceError(`Failed to dereference Arazzo Document at "${uri}"`, {
|
|
96
|
+
cause: error
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Dereferences an ApiDOM element representing an Arazzo Document.
|
|
103
|
+
*
|
|
104
|
+
* This function resolves all JSON References ($ref) and Reusable Object references
|
|
105
|
+
* ($components.*) in the Arazzo Document element.
|
|
106
|
+
*
|
|
107
|
+
* Supported scenarios:
|
|
108
|
+
* - ParseResultElement with retrievalURI metadata: baseURI derived automatically
|
|
109
|
+
* - ParseResultElement without retrievalURI: requires `options.resolve.baseURI`
|
|
110
|
+
* - Child element (e.g., WorkflowElement) with parseResult in strategyOpts:
|
|
111
|
+
* requires `options.dereference.strategyOpts.parseResult` for component resolution,
|
|
112
|
+
* and `options.resolve.baseURI` if parseResult lacks retrievalURI metadata
|
|
113
|
+
*
|
|
114
|
+
* Source descriptions can optionally be dereferenced using strategy options:
|
|
115
|
+
* - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
|
|
116
|
+
* - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
|
|
117
|
+
*
|
|
118
|
+
* Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
|
|
119
|
+
*
|
|
120
|
+
* @param element - An ApiDOM element (ParseResultElement or child element like WorkflowElement)
|
|
121
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
122
|
+
* @returns A promise that resolves to the dereferenced element
|
|
123
|
+
* @throws DereferenceError - When baseURI is required but not provided, or when dereferencing fails
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* Dereference ParseResultElement with retrievalURI (from file parsing)
|
|
127
|
+
* ```typescript
|
|
128
|
+
* import { parseArazzo } from '@jentic/arazzo-parser';
|
|
129
|
+
*
|
|
130
|
+
* const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
131
|
+
* const dereferenced = await dereferenceArazzoElement(parseResult);
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* Dereference ParseResultElement without retrievalURI (from inline parsing)
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const parseResult = await parseArazzo({ arazzo: '1.0.1', ... });
|
|
138
|
+
* const dereferenced = await dereferenceArazzoElement(parseResult, {
|
|
139
|
+
* resolve: { baseURI: 'https://example.com/arazzo.json' },
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* Dereference child element (e.g., WorkflowElement)
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
147
|
+
* const workflow = parseResult.api.workflows.get(0);
|
|
148
|
+
* const dereferenced = await dereferenceArazzoElement(workflow, {
|
|
149
|
+
* dereference: { strategyOpts: { parseResult } },
|
|
150
|
+
* });
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* Dereference with source descriptions
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
157
|
+
* const dereferenced = await dereferenceArazzoElement(parseResult, {
|
|
158
|
+
* dereference: { strategyOpts: { sourceDescriptions: true } },
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
161
|
+
* @public
|
|
162
|
+
*/
|
|
163
|
+
export async function dereferenceElement(element, options = {}) {
|
|
164
|
+
const mergedOptions = mergeOptions(defaultOptions, options);
|
|
165
|
+
const refSet = mergedOptions.dereference?.refSet ?? new ReferenceSet();
|
|
166
|
+
let baseURI = mergedOptions.resolve?.baseURI;
|
|
167
|
+
let mediaType = 'text/plain';
|
|
168
|
+
if (refSet.size === 0) {
|
|
169
|
+
if (isParseResultElement(element)) {
|
|
170
|
+
if (isArazzoSpecification1Element(element.api)) {
|
|
171
|
+
mediaType = mediaTypes.latest();
|
|
172
|
+
}
|
|
173
|
+
if (element.hasMetaProperty('retrievalURI')) {
|
|
174
|
+
baseURI = element.meta.get('retrievalURI');
|
|
175
|
+
} else if (!baseURI) {
|
|
176
|
+
throw new DereferenceError('baseURI option is required when dereferencing a ParseResultElement without retrievalURI metadata');
|
|
177
|
+
}
|
|
178
|
+
} else if (isParseResultElement(mergedOptions.dereference?.strategyOpts?.parseResult)) {
|
|
179
|
+
// dereferencing child element requires refSet for component resolution
|
|
180
|
+
const {
|
|
181
|
+
parseResult
|
|
182
|
+
} = mergedOptions.dereference.strategyOpts;
|
|
183
|
+
let rootURI;
|
|
184
|
+
if (isArazzoSpecification1Element(parseResult.api)) {
|
|
185
|
+
mediaType = mediaTypes.latest();
|
|
186
|
+
}
|
|
187
|
+
if (parseResult.hasMetaProperty('retrievalURI')) {
|
|
188
|
+
rootURI = parseResult.meta.get('retrievalURI');
|
|
189
|
+
} else if (baseURI) {
|
|
190
|
+
rootURI = baseURI;
|
|
191
|
+
} else {
|
|
192
|
+
throw new DereferenceError('baseURI option is required when dereferencing a child element without retrievalURI metadata');
|
|
193
|
+
}
|
|
194
|
+
const elementReference = new Reference({
|
|
195
|
+
uri: `${rootURI}#fragment`,
|
|
196
|
+
value: new ParseResultElement([element])
|
|
197
|
+
});
|
|
198
|
+
const rootReference = new Reference({
|
|
199
|
+
uri: rootURI,
|
|
200
|
+
value: parseResult
|
|
201
|
+
});
|
|
202
|
+
refSet.add(elementReference).add(rootReference);
|
|
203
|
+
baseURI = rootURI;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
return await dereferenceApiDOMElement(element, mergeOptions(mergedOptions, {
|
|
208
|
+
resolve: {
|
|
209
|
+
baseURI
|
|
210
|
+
},
|
|
211
|
+
parse: {
|
|
212
|
+
mediaType
|
|
213
|
+
},
|
|
214
|
+
dereference: {
|
|
215
|
+
refSet
|
|
216
|
+
}
|
|
217
|
+
}));
|
|
218
|
+
} catch (error) {
|
|
219
|
+
throw new DereferenceError('Failed to dereference Arazzo Document', {
|
|
220
|
+
cause: error
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.defaultOptions = void 0;
|
|
6
|
+
exports.dereference = dereference;
|
|
7
|
+
exports.dereferenceElement = dereferenceElement;
|
|
8
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
9
|
+
var _empty = require("@speclynx/apidom-reference/configuration/empty");
|
|
10
|
+
var _openapi = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/openapi-2"));
|
|
11
|
+
var _openapi2 = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/openapi-3-0"));
|
|
12
|
+
var _openapi3 = _interopRequireDefault(require("@speclynx/apidom-reference/dereference/strategies/openapi-3-1"));
|
|
13
|
+
var _json = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/json"));
|
|
14
|
+
var _yaml = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/yaml-1-2"));
|
|
15
|
+
var _binary = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/binary"));
|
|
16
|
+
var _apidomNsOpenapi = require("@speclynx/apidom-ns-openapi-2");
|
|
17
|
+
var _apidomNsOpenapi2 = require("@speclynx/apidom-ns-openapi-3-0");
|
|
18
|
+
var _apidomNsOpenapi3 = require("@speclynx/apidom-ns-openapi-3-1");
|
|
19
|
+
var _arazzoParser = require("@jentic/arazzo-parser");
|
|
20
|
+
var _DereferenceError = _interopRequireDefault(require("../errors/DereferenceError.cjs"));
|
|
21
|
+
/**
|
|
22
|
+
* Options for dereferencing OpenAPI Documents.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Default reference options for dereferencing OpenAPI Documents.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
const defaultOptions = exports.defaultOptions = {
|
|
31
|
+
resolve: {
|
|
32
|
+
resolvers: [..._arazzoParser.defaultOpenAPIOptions.resolve.resolvers]
|
|
33
|
+
},
|
|
34
|
+
parse: {
|
|
35
|
+
parsers: [..._arazzoParser.defaultOpenAPIOptions.parse.parsers, new _json.default({
|
|
36
|
+
allowEmpty: false
|
|
37
|
+
}), new _yaml.default({
|
|
38
|
+
allowEmpty: false
|
|
39
|
+
}), new _binary.default({
|
|
40
|
+
allowEmpty: false
|
|
41
|
+
})],
|
|
42
|
+
parserOpts: {
|
|
43
|
+
..._arazzoParser.defaultOpenAPIOptions.parse.parserOpts
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
dereference: {
|
|
47
|
+
strategies: [new _openapi.default(), new _openapi2.default(), new _openapi3.default()],
|
|
48
|
+
strategyOpts: {}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Dereferences an OpenAPI Document from a file system path or HTTP(S) URL.
|
|
54
|
+
*
|
|
55
|
+
* This function resolves all JSON References ($ref) in the OpenAPI Document.
|
|
56
|
+
*
|
|
57
|
+
* Supports OpenAPI 2.0 (Swagger), OpenAPI 3.0.x, and OpenAPI 3.1.x.
|
|
58
|
+
*
|
|
59
|
+
* @param uri - A file system path or HTTP(S) URL to the OpenAPI Document
|
|
60
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
61
|
+
* @returns A promise that resolves to the dereferenced OpenAPI Document as ApiDOM element
|
|
62
|
+
* @throws DereferenceError - When dereferencing fails or document is not an OpenAPI specification. The original error is available via the `cause` property.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* // Dereference from file
|
|
66
|
+
* const result = await dereferenceOpenAPI('/path/to/openapi.json');
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // Dereference from URL
|
|
70
|
+
* const result = await dereferenceOpenAPI('https://example.com/openapi.yaml');
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // Dereference with custom options
|
|
74
|
+
* const result = await dereferenceOpenAPI('/path/to/openapi.json', customReferenceOptions);
|
|
75
|
+
* @public
|
|
76
|
+
*/
|
|
77
|
+
async function dereference(uri, options = {}) {
|
|
78
|
+
const mergedOptions = (0, _empty.mergeOptions)(defaultOptions, options);
|
|
79
|
+
try {
|
|
80
|
+
const parseResult = await (0, _empty.dereference)(uri, mergedOptions);
|
|
81
|
+
|
|
82
|
+
// validate that the dereferenced document is an OpenAPI specification
|
|
83
|
+
if (!isOpenApiElement(parseResult.api)) {
|
|
84
|
+
throw new _empty.UnmatchedDereferenceStrategyError(`Could not find a dereference strategy that can dereference "${uri}" as an OpenAPI specification`);
|
|
85
|
+
}
|
|
86
|
+
parseResult.meta.set('retrievalURI', uri);
|
|
87
|
+
return parseResult;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
throw new _DereferenceError.default(`Failed to dereference OpenAPI Document at "${uri}"`, {
|
|
90
|
+
cause: error
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Dereferences an ApiDOM element representing an OpenAPI Document.
|
|
97
|
+
*
|
|
98
|
+
* This function resolves all JSON References ($ref) in the OpenAPI Document element.
|
|
99
|
+
*
|
|
100
|
+
* Supported scenarios:
|
|
101
|
+
* - ParseResultElement with retrievalURI metadata: baseURI derived automatically
|
|
102
|
+
* - ParseResultElement without retrievalURI: requires `options.resolve.baseURI`
|
|
103
|
+
* - Child element (e.g., PathItemElement) with parseResult in strategyOpts:
|
|
104
|
+
* requires `options.dereference.strategyOpts.parseResult` for component resolution,
|
|
105
|
+
* and `options.resolve.baseURI` if parseResult lacks retrievalURI metadata
|
|
106
|
+
*
|
|
107
|
+
* @param element - An ApiDOM element (ParseResultElement or child element like PathItemElement)
|
|
108
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
109
|
+
* @returns A promise that resolves to the dereferenced element
|
|
110
|
+
* @throws DereferenceError - When baseURI is required but not provided, or when dereferencing fails
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* Dereference ParseResultElement with retrievalURI (from file parsing)
|
|
114
|
+
* ```typescript
|
|
115
|
+
* import { parseOpenAPI } from '@jentic/arazzo-parser';
|
|
116
|
+
*
|
|
117
|
+
* const parseResult = await parseOpenAPI('/path/to/openapi.json');
|
|
118
|
+
* const dereferenced = await dereferenceOpenAPIElement(parseResult);
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* Dereference ParseResultElement without retrievalURI (from inline parsing)
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const parseResult = await parseOpenAPI({ openapi: '3.1.0', ... });
|
|
125
|
+
* const dereferenced = await dereferenceOpenAPIElement(parseResult, {
|
|
126
|
+
* resolve: { baseURI: 'https://example.com/openapi.json' },
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* Dereference child element (e.g., PathItemElement)
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const parseResult = await parseOpenAPI('/path/to/openapi.json');
|
|
134
|
+
* const pathItem = parseResult.api.paths.get('/users');
|
|
135
|
+
* const dereferenced = await dereferenceOpenAPIElement(pathItem, {
|
|
136
|
+
* dereference: { strategyOpts: { parseResult } },
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
* @public
|
|
140
|
+
*/
|
|
141
|
+
async function dereferenceElement(element, options = {}) {
|
|
142
|
+
const mergedOptions = (0, _empty.mergeOptions)(defaultOptions, options);
|
|
143
|
+
const refSet = mergedOptions.dereference?.refSet ?? new _empty.ReferenceSet();
|
|
144
|
+
let baseURI = mergedOptions.resolve?.baseURI;
|
|
145
|
+
let mediaType = 'text/plain';
|
|
146
|
+
if (refSet.size === 0) {
|
|
147
|
+
if ((0, _apidomDatamodel.isParseResultElement)(element)) {
|
|
148
|
+
if (isOpenApiElement(element.api)) {
|
|
149
|
+
mediaType = inferOpenApiMediaType(element.api);
|
|
150
|
+
}
|
|
151
|
+
if (element.hasMetaProperty('retrievalURI')) {
|
|
152
|
+
baseURI = element.meta.get('retrievalURI');
|
|
153
|
+
} else if (!baseURI) {
|
|
154
|
+
throw new _DereferenceError.default('baseURI option is required when dereferencing a ParseResultElement without retrievalURI metadata');
|
|
155
|
+
}
|
|
156
|
+
} else if ((0, _apidomDatamodel.isParseResultElement)(mergedOptions.dereference?.strategyOpts?.parseResult)) {
|
|
157
|
+
// dereferencing child element requires refSet for component resolution
|
|
158
|
+
const {
|
|
159
|
+
parseResult
|
|
160
|
+
} = mergedOptions.dereference.strategyOpts;
|
|
161
|
+
let rootURI;
|
|
162
|
+
if (isOpenApiElement(parseResult.api)) {
|
|
163
|
+
mediaType = inferOpenApiMediaType(parseResult.api);
|
|
164
|
+
}
|
|
165
|
+
if (parseResult.hasMetaProperty('retrievalURI')) {
|
|
166
|
+
rootURI = parseResult.meta.get('retrievalURI');
|
|
167
|
+
} else if (baseURI) {
|
|
168
|
+
rootURI = baseURI;
|
|
169
|
+
} else {
|
|
170
|
+
throw new _DereferenceError.default('baseURI option is required when dereferencing a child element without retrievalURI metadata');
|
|
171
|
+
}
|
|
172
|
+
const elementReference = new _empty.Reference({
|
|
173
|
+
uri: `${rootURI}#fragment`,
|
|
174
|
+
value: new _apidomDatamodel.ParseResultElement([element])
|
|
175
|
+
});
|
|
176
|
+
const rootReference = new _empty.Reference({
|
|
177
|
+
uri: rootURI,
|
|
178
|
+
value: parseResult
|
|
179
|
+
});
|
|
180
|
+
refSet.add(elementReference).add(rootReference);
|
|
181
|
+
baseURI = rootURI;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
return await (0, _empty.dereferenceApiDOM)(element, (0, _empty.mergeOptions)(mergedOptions, {
|
|
186
|
+
resolve: {
|
|
187
|
+
baseURI
|
|
188
|
+
},
|
|
189
|
+
parse: {
|
|
190
|
+
mediaType
|
|
191
|
+
},
|
|
192
|
+
dereference: {
|
|
193
|
+
refSet
|
|
194
|
+
}
|
|
195
|
+
}));
|
|
196
|
+
} catch (error) {
|
|
197
|
+
throw new _DereferenceError.default('Failed to dereference OpenAPI Document', {
|
|
198
|
+
cause: error
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Checks if the element is a valid OpenAPI specification element.
|
|
205
|
+
*/
|
|
206
|
+
function isOpenApiElement(element) {
|
|
207
|
+
return (0, _apidomNsOpenapi.isSwaggerElement)(element) || (0, _apidomNsOpenapi2.isOpenApi3_0Element)(element) || (0, _apidomNsOpenapi3.isOpenApi3_1Element)(element);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Gets the appropriate mediaType for an OpenAPI element.
|
|
212
|
+
*/
|
|
213
|
+
function inferOpenApiMediaType(element) {
|
|
214
|
+
if ((0, _apidomNsOpenapi.isSwaggerElement)(element)) {
|
|
215
|
+
return _apidomNsOpenapi.mediaTypes.latest();
|
|
216
|
+
}
|
|
217
|
+
if ((0, _apidomNsOpenapi2.isOpenApi3_0Element)(element)) {
|
|
218
|
+
return _apidomNsOpenapi2.mediaTypes.latest();
|
|
219
|
+
}
|
|
220
|
+
if ((0, _apidomNsOpenapi3.isOpenApi3_1Element)(element)) {
|
|
221
|
+
return _apidomNsOpenapi3.mediaTypes.latest();
|
|
222
|
+
}
|
|
223
|
+
return 'text/plain';
|
|
224
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { isParseResultElement, ParseResultElement } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { dereference as dereferenceURI, dereferenceApiDOM as dereferenceApiDOMElement, mergeOptions, ReferenceSet, Reference, UnmatchedDereferenceStrategyError } from '@speclynx/apidom-reference/configuration/empty';
|
|
3
|
+
import OpenAPI2DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/openapi-2';
|
|
4
|
+
import OpenAPI3_0DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/openapi-3-0';
|
|
5
|
+
import OpenAPI3_1DereferenceStrategy from '@speclynx/apidom-reference/dereference/strategies/openapi-3-1';
|
|
6
|
+
import JSONParser from '@speclynx/apidom-reference/parse/parsers/json';
|
|
7
|
+
import YAMLParser from '@speclynx/apidom-reference/parse/parsers/yaml-1-2';
|
|
8
|
+
import BinaryParser from '@speclynx/apidom-reference/parse/parsers/binary';
|
|
9
|
+
import { isSwaggerElement, mediaTypes as openApi2MediaTypes } from '@speclynx/apidom-ns-openapi-2';
|
|
10
|
+
import { isOpenApi3_0Element, mediaTypes as openApi3_0MediaTypes } from '@speclynx/apidom-ns-openapi-3-0';
|
|
11
|
+
import { isOpenApi3_1Element, mediaTypes as openApi3_1MediaTypes } from '@speclynx/apidom-ns-openapi-3-1';
|
|
12
|
+
import { defaultOpenAPIOptions as parserDefaultOptions } from '@jentic/arazzo-parser';
|
|
13
|
+
import DereferenceError from "../errors/DereferenceError.mjs";
|
|
14
|
+
/**
|
|
15
|
+
* Options for dereferencing OpenAPI Documents.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Default reference options for dereferencing OpenAPI Documents.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export const defaultOptions = {
|
|
23
|
+
resolve: {
|
|
24
|
+
resolvers: [...parserDefaultOptions.resolve.resolvers]
|
|
25
|
+
},
|
|
26
|
+
parse: {
|
|
27
|
+
parsers: [...parserDefaultOptions.parse.parsers, new JSONParser({
|
|
28
|
+
allowEmpty: false
|
|
29
|
+
}), new YAMLParser({
|
|
30
|
+
allowEmpty: false
|
|
31
|
+
}), new BinaryParser({
|
|
32
|
+
allowEmpty: false
|
|
33
|
+
})],
|
|
34
|
+
parserOpts: {
|
|
35
|
+
...parserDefaultOptions.parse.parserOpts
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
dereference: {
|
|
39
|
+
strategies: [new OpenAPI2DereferenceStrategy(), new OpenAPI3_0DereferenceStrategy(), new OpenAPI3_1DereferenceStrategy()],
|
|
40
|
+
strategyOpts: {}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Dereferences an OpenAPI Document from a file system path or HTTP(S) URL.
|
|
46
|
+
*
|
|
47
|
+
* This function resolves all JSON References ($ref) in the OpenAPI Document.
|
|
48
|
+
*
|
|
49
|
+
* Supports OpenAPI 2.0 (Swagger), OpenAPI 3.0.x, and OpenAPI 3.1.x.
|
|
50
|
+
*
|
|
51
|
+
* @param uri - A file system path or HTTP(S) URL to the OpenAPI Document
|
|
52
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
53
|
+
* @returns A promise that resolves to the dereferenced OpenAPI Document as ApiDOM element
|
|
54
|
+
* @throws DereferenceError - When dereferencing fails or document is not an OpenAPI specification. The original error is available via the `cause` property.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // Dereference from file
|
|
58
|
+
* const result = await dereferenceOpenAPI('/path/to/openapi.json');
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* // Dereference from URL
|
|
62
|
+
* const result = await dereferenceOpenAPI('https://example.com/openapi.yaml');
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* // Dereference with custom options
|
|
66
|
+
* const result = await dereferenceOpenAPI('/path/to/openapi.json', customReferenceOptions);
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
export async function dereference(uri, options = {}) {
|
|
70
|
+
const mergedOptions = mergeOptions(defaultOptions, options);
|
|
71
|
+
try {
|
|
72
|
+
const parseResult = await dereferenceURI(uri, mergedOptions);
|
|
73
|
+
|
|
74
|
+
// validate that the dereferenced document is an OpenAPI specification
|
|
75
|
+
if (!isOpenApiElement(parseResult.api)) {
|
|
76
|
+
throw new UnmatchedDereferenceStrategyError(`Could not find a dereference strategy that can dereference "${uri}" as an OpenAPI specification`);
|
|
77
|
+
}
|
|
78
|
+
parseResult.meta.set('retrievalURI', uri);
|
|
79
|
+
return parseResult;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
throw new DereferenceError(`Failed to dereference OpenAPI Document at "${uri}"`, {
|
|
82
|
+
cause: error
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Dereferences an ApiDOM element representing an OpenAPI Document.
|
|
89
|
+
*
|
|
90
|
+
* This function resolves all JSON References ($ref) in the OpenAPI Document element.
|
|
91
|
+
*
|
|
92
|
+
* Supported scenarios:
|
|
93
|
+
* - ParseResultElement with retrievalURI metadata: baseURI derived automatically
|
|
94
|
+
* - ParseResultElement without retrievalURI: requires `options.resolve.baseURI`
|
|
95
|
+
* - Child element (e.g., PathItemElement) with parseResult in strategyOpts:
|
|
96
|
+
* requires `options.dereference.strategyOpts.parseResult` for component resolution,
|
|
97
|
+
* and `options.resolve.baseURI` if parseResult lacks retrievalURI metadata
|
|
98
|
+
*
|
|
99
|
+
* @param element - An ApiDOM element (ParseResultElement or child element like PathItemElement)
|
|
100
|
+
* @param options - Reference options (uses defaultOptions when not provided)
|
|
101
|
+
* @returns A promise that resolves to the dereferenced element
|
|
102
|
+
* @throws DereferenceError - When baseURI is required but not provided, or when dereferencing fails
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* Dereference ParseResultElement with retrievalURI (from file parsing)
|
|
106
|
+
* ```typescript
|
|
107
|
+
* import { parseOpenAPI } from '@jentic/arazzo-parser';
|
|
108
|
+
*
|
|
109
|
+
* const parseResult = await parseOpenAPI('/path/to/openapi.json');
|
|
110
|
+
* const dereferenced = await dereferenceOpenAPIElement(parseResult);
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* Dereference ParseResultElement without retrievalURI (from inline parsing)
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const parseResult = await parseOpenAPI({ openapi: '3.1.0', ... });
|
|
117
|
+
* const dereferenced = await dereferenceOpenAPIElement(parseResult, {
|
|
118
|
+
* resolve: { baseURI: 'https://example.com/openapi.json' },
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* Dereference child element (e.g., PathItemElement)
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const parseResult = await parseOpenAPI('/path/to/openapi.json');
|
|
126
|
+
* const pathItem = parseResult.api.paths.get('/users');
|
|
127
|
+
* const dereferenced = await dereferenceOpenAPIElement(pathItem, {
|
|
128
|
+
* dereference: { strategyOpts: { parseResult } },
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
* @public
|
|
132
|
+
*/
|
|
133
|
+
export async function dereferenceElement(element, options = {}) {
|
|
134
|
+
const mergedOptions = mergeOptions(defaultOptions, options);
|
|
135
|
+
const refSet = mergedOptions.dereference?.refSet ?? new ReferenceSet();
|
|
136
|
+
let baseURI = mergedOptions.resolve?.baseURI;
|
|
137
|
+
let mediaType = 'text/plain';
|
|
138
|
+
if (refSet.size === 0) {
|
|
139
|
+
if (isParseResultElement(element)) {
|
|
140
|
+
if (isOpenApiElement(element.api)) {
|
|
141
|
+
mediaType = inferOpenApiMediaType(element.api);
|
|
142
|
+
}
|
|
143
|
+
if (element.hasMetaProperty('retrievalURI')) {
|
|
144
|
+
baseURI = element.meta.get('retrievalURI');
|
|
145
|
+
} else if (!baseURI) {
|
|
146
|
+
throw new DereferenceError('baseURI option is required when dereferencing a ParseResultElement without retrievalURI metadata');
|
|
147
|
+
}
|
|
148
|
+
} else if (isParseResultElement(mergedOptions.dereference?.strategyOpts?.parseResult)) {
|
|
149
|
+
// dereferencing child element requires refSet for component resolution
|
|
150
|
+
const {
|
|
151
|
+
parseResult
|
|
152
|
+
} = mergedOptions.dereference.strategyOpts;
|
|
153
|
+
let rootURI;
|
|
154
|
+
if (isOpenApiElement(parseResult.api)) {
|
|
155
|
+
mediaType = inferOpenApiMediaType(parseResult.api);
|
|
156
|
+
}
|
|
157
|
+
if (parseResult.hasMetaProperty('retrievalURI')) {
|
|
158
|
+
rootURI = parseResult.meta.get('retrievalURI');
|
|
159
|
+
} else if (baseURI) {
|
|
160
|
+
rootURI = baseURI;
|
|
161
|
+
} else {
|
|
162
|
+
throw new DereferenceError('baseURI option is required when dereferencing a child element without retrievalURI metadata');
|
|
163
|
+
}
|
|
164
|
+
const elementReference = new Reference({
|
|
165
|
+
uri: `${rootURI}#fragment`,
|
|
166
|
+
value: new ParseResultElement([element])
|
|
167
|
+
});
|
|
168
|
+
const rootReference = new Reference({
|
|
169
|
+
uri: rootURI,
|
|
170
|
+
value: parseResult
|
|
171
|
+
});
|
|
172
|
+
refSet.add(elementReference).add(rootReference);
|
|
173
|
+
baseURI = rootURI;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
return await dereferenceApiDOMElement(element, mergeOptions(mergedOptions, {
|
|
178
|
+
resolve: {
|
|
179
|
+
baseURI
|
|
180
|
+
},
|
|
181
|
+
parse: {
|
|
182
|
+
mediaType
|
|
183
|
+
},
|
|
184
|
+
dereference: {
|
|
185
|
+
refSet
|
|
186
|
+
}
|
|
187
|
+
}));
|
|
188
|
+
} catch (error) {
|
|
189
|
+
throw new DereferenceError('Failed to dereference OpenAPI Document', {
|
|
190
|
+
cause: error
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Checks if the element is a valid OpenAPI specification element.
|
|
197
|
+
*/
|
|
198
|
+
function isOpenApiElement(element) {
|
|
199
|
+
return isSwaggerElement(element) || isOpenApi3_0Element(element) || isOpenApi3_1Element(element);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Gets the appropriate mediaType for an OpenAPI element.
|
|
204
|
+
*/
|
|
205
|
+
function inferOpenApiMediaType(element) {
|
|
206
|
+
if (isSwaggerElement(element)) {
|
|
207
|
+
return openApi2MediaTypes.latest();
|
|
208
|
+
}
|
|
209
|
+
if (isOpenApi3_0Element(element)) {
|
|
210
|
+
return openApi3_0MediaTypes.latest();
|
|
211
|
+
}
|
|
212
|
+
if (isOpenApi3_1Element(element)) {
|
|
213
|
+
return openApi3_1MediaTypes.latest();
|
|
214
|
+
}
|
|
215
|
+
return 'text/plain';
|
|
216
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _apidomError = require("@speclynx/apidom-error");
|
|
6
|
+
/**
|
|
7
|
+
* Error thrown when dereferencing an Arazzo document or element fails.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
class DereferenceError extends _apidomError.ApiDOMError {
|
|
11
|
+
constructor(message, options) {
|
|
12
|
+
super(message, options);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
var _default = exports.default = DereferenceError;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ApiDOMError } from '@speclynx/apidom-error';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error thrown when dereferencing an Arazzo document or element fails.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
class DereferenceError extends ApiDOMError {
|
|
8
|
+
constructor(message, options) {
|
|
9
|
+
super(message, options);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export default DereferenceError;
|
package/src/index.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.dereferenceOpenAPIElement = exports.dereferenceOpenAPI = exports.dereferenceArazzoElement = exports.dereferenceArazzo = exports.defaultDereferenceOpenAPIOptions = exports.defaultDereferenceArazzoOptions = exports.DereferenceError = void 0;
|
|
6
|
+
var _arazzo = require("./dereference/arazzo.cjs");
|
|
7
|
+
exports.defaultDereferenceArazzoOptions = _arazzo.defaultOptions;
|
|
8
|
+
exports.dereferenceArazzo = _arazzo.dereference;
|
|
9
|
+
exports.dereferenceArazzoElement = _arazzo.dereferenceElement;
|
|
10
|
+
var _openapi = require("./dereference/openapi.cjs");
|
|
11
|
+
exports.defaultDereferenceOpenAPIOptions = _openapi.defaultOptions;
|
|
12
|
+
exports.dereferenceOpenAPI = _openapi.dereference;
|
|
13
|
+
exports.dereferenceOpenAPIElement = _openapi.dereferenceElement;
|
|
14
|
+
var _DereferenceError = _interopRequireDefault(require("./errors/DereferenceError.cjs"));
|
|
15
|
+
exports.DereferenceError = _DereferenceError.default;
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { defaultOptions as defaultDereferenceArazzoOptions, dereference as dereferenceArazzo, dereferenceElement as dereferenceArazzoElement } from "./dereference/arazzo.mjs";
|
|
2
|
+
export { defaultOptions as defaultDereferenceOpenAPIOptions, dereference as dereferenceOpenAPI, dereferenceElement as dereferenceOpenAPIElement } from "./dereference/openapi.mjs";
|
|
3
|
+
export { default as DereferenceError } from "./errors/DereferenceError.mjs";
|