@jentic/arazzo-resolver 1.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@jentic/arazzo-resolver",
3
+ "version": "1.0.0-alpha.10",
4
+ "description": "Resolver for Arazzo Documents.",
5
+ "keywords": [
6
+ "arazzo",
7
+ "arazzo-specification",
8
+ "resolver",
9
+ "resolve",
10
+ "dereference",
11
+ "workflow",
12
+ "workflows"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "registry": "https://registry.npmjs.org",
17
+ "provenance": true,
18
+ "tag": "latest"
19
+ },
20
+ "type": "module",
21
+ "sideEffects": false,
22
+ "unpkg": "./dist/jentic-arazzo-resolver.browser.min.js",
23
+ "main": "./src/index.cjs",
24
+ "exports": {
25
+ "types": "./types/arazzo-resolver.d.ts",
26
+ "import": "./src/index.mjs",
27
+ "require": "./src/index.cjs"
28
+ },
29
+ "types": "./types/arazzo-resolver.d.ts",
30
+ "scripts": {
31
+ "build": "npm run clean && run-p --max-parallel ${CPU_CORES:-2} typescript:declaration build:es build:cjs build:umd:browser",
32
+ "build:es": "cross-env BABEL_ENV=es babel src --out-dir src --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward'",
33
+ "build:cjs": "cross-env BABEL_ENV=cjs babel src --out-dir src --extensions '.ts' --out-file-extension '.cjs' --root-mode 'upward'",
34
+ "build:umd:browser": "cross-env BABEL_ENV=browser webpack --config config/webpack/browser.config.js --progress",
35
+ "lint": "eslint ./",
36
+ "lint:fix": "eslint ./ --fix",
37
+ "clean": "rimraf --glob 'src/**/*.mjs' 'src/**/*.cjs' 'test/**/*.mjs' ./dist ./types",
38
+ "typescript:check-types": "tsc --noEmit",
39
+ "typescript:declaration": "tsc -p tsconfig.declaration.json && api-extractor run -l -c ./config/api-extractor/api-extractor.json",
40
+ "test": "npm run build:es && cross-env BABEL_ENV=es babel test --out-dir test --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward' && cross-env NODE_ENV=test mocha",
41
+ "prepack": "copyfiles -u 2 ../../LICENSE . && copyfiles -u 2 ../../NOTICE .",
42
+ "postpack": "rimraf NOTICE LICENSE"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/jentic/jentic-arazzo-tools.git"
47
+ },
48
+ "author": "Jentic <hello@jentic.com>",
49
+ "license": "Apache-2.0",
50
+ "dependencies": {
51
+ "@babel/runtime-corejs3": "^7.28.4",
52
+ "@speclynx/apidom-core": "2.10.0",
53
+ "@speclynx/apidom-datamodel": "2.10.0",
54
+ "@speclynx/apidom-error": "2.10.0",
55
+ "@speclynx/apidom-ns-arazzo-1": "2.10.0",
56
+ "@speclynx/apidom-ns-openapi-2": "2.10.0",
57
+ "@speclynx/apidom-ns-openapi-3-0": "2.10.0",
58
+ "@speclynx/apidom-ns-openapi-3-1": "2.10.0",
59
+ "@speclynx/apidom-reference": "2.10.0",
60
+ "type-fest": "^5.4.3"
61
+ },
62
+ "files": [
63
+ "src/**/*.mjs",
64
+ "src/**/*.cjs",
65
+ "dist/",
66
+ "types/arazzo-resolver.d.ts",
67
+ "LICENSE",
68
+ "NOTICE",
69
+ "README.md",
70
+ "CHANGELOG.md"
71
+ ],
72
+ "gitHead": "13363a00a365e8f5d30ddedfdde8e93216e60df8"
73
+ }
@@ -0,0 +1,272 @@
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 _arazzoJson = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/arazzo-json-1"));
15
+ var _arazzoYaml = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/arazzo-yaml-1"));
16
+ var _openapiJson = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-json-2"));
17
+ var _openapiYaml = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-yaml-2"));
18
+ var _openapiJson2 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-json-3-0"));
19
+ var _openapiYaml2 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-0"));
20
+ var _openapiJson3 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-json-3-1"));
21
+ var _openapiYaml3 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-1"));
22
+ var _json = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/json"));
23
+ var _yaml = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/yaml-1-2"));
24
+ var _binary = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/binary"));
25
+ var _file = _interopRequireDefault(require("@speclynx/apidom-reference/resolve/resolvers/file"));
26
+ var _httpAxios = _interopRequireDefault(require("@speclynx/apidom-reference/resolve/resolvers/http-axios"));
27
+ var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
28
+ var _apidomCore = require("@speclynx/apidom-core");
29
+ var _DereferenceError = _interopRequireDefault(require("../errors/DereferenceError.cjs"));
30
+ /**
31
+ * Options for dereferencing Arazzo Documents.
32
+ * @public
33
+ */
34
+
35
+ /**
36
+ * Default reference options for dereferencing Arazzo Documents.
37
+ * @public
38
+ */
39
+ const defaultOptions = exports.defaultOptions = {
40
+ resolve: {
41
+ resolvers: [new _file.default({
42
+ fileAllowList: ['*.json', '*.yaml', '*.yml']
43
+ }), new _httpAxios.default({
44
+ timeout: 5000,
45
+ redirects: 5,
46
+ withCredentials: false
47
+ })]
48
+ },
49
+ parse: {
50
+ parsers: [new _arazzoJson.default({
51
+ allowEmpty: false,
52
+ fileExtensions: ['.json']
53
+ }), new _arazzoYaml.default({
54
+ allowEmpty: false,
55
+ fileExtensions: ['.yaml', '.yml']
56
+ }), new _openapiJson.default({
57
+ allowEmpty: false,
58
+ fileExtensions: ['.json']
59
+ }), new _openapiYaml.default({
60
+ allowEmpty: false,
61
+ fileExtensions: ['.yaml', '.yml']
62
+ }), new _openapiJson2.default({
63
+ allowEmpty: false,
64
+ fileExtensions: ['.json']
65
+ }), new _openapiYaml2.default({
66
+ allowEmpty: false,
67
+ fileExtensions: ['.yaml', '.yml']
68
+ }), new _openapiJson3.default({
69
+ allowEmpty: false,
70
+ fileExtensions: ['.json']
71
+ }), new _openapiYaml3.default({
72
+ allowEmpty: false,
73
+ fileExtensions: ['.yaml', '.yml']
74
+ }), new _json.default({
75
+ allowEmpty: false,
76
+ fileExtensions: ['.json']
77
+ }), new _yaml.default({
78
+ allowEmpty: false,
79
+ fileExtensions: ['.yaml', '.yml']
80
+ }), new _binary.default({
81
+ allowEmpty: false
82
+ })],
83
+ parserOpts: {
84
+ sourceMap: false,
85
+ strict: true
86
+ }
87
+ },
88
+ dereference: {
89
+ strategies: [new _arazzo.default(), new _openapi.default(), new _openapi2.default(), new _openapi3.default()],
90
+ strategyOpts: {
91
+ sourceDescriptions: false
92
+ }
93
+ }
94
+ };
95
+
96
+ /**
97
+ * Dereferences an Arazzo Document from a file system path or HTTP(S) URL.
98
+ *
99
+ * This function resolves all JSON References ($ref) and Reusable Object references
100
+ * ($components.*) in the Arazzo Document.
101
+ *
102
+ * Source descriptions can optionally be dereferenced using strategy options:
103
+ * - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
104
+ * - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
105
+ *
106
+ * Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
107
+ *
108
+ * @param uri - A file system path or HTTP(S) URL to the Arazzo Document
109
+ * @param options - Reference options (uses defaultOptions when not provided)
110
+ * @returns A promise that resolves to the dereferenced Arazzo Document as ApiDOM element
111
+ * @throws DereferenceError - When dereferencing fails or document is not an Arazzo specification. The original error is available via the `cause` property.
112
+ *
113
+ * @example
114
+ * // Dereference from file
115
+ * const result = await dereferenceArazzo('/path/to/arazzo.json');
116
+ *
117
+ * @example
118
+ * // Dereference from URL
119
+ * const result = await dereferenceArazzo('https://example.com/arazzo.yaml');
120
+ *
121
+ * @example
122
+ * // Dereference with source descriptions
123
+ * const result = await dereferenceArazzo('/path/to/arazzo.json', {
124
+ * dereference: { strategyOpts: { sourceDescriptions: true } },
125
+ * });
126
+ *
127
+ * @example
128
+ * // Dereference with custom options
129
+ * const result = await dereferenceArazzo('/path/to/arazzo.json', customReferenceOptions);
130
+ * @public
131
+ */
132
+ async function dereference(uri, options = {}) {
133
+ const mergedOptions = (0, _empty.mergeOptions)(defaultOptions, options);
134
+ try {
135
+ const parseResult = await (0, _empty.dereference)(uri, mergedOptions);
136
+
137
+ // validate that the dereferenced document is an Arazzo specification
138
+ if (!(0, _apidomNsArazzo.isArazzoSpecification1Element)(parseResult.api)) {
139
+ throw new _empty.UnmatchedDereferenceStrategyError(`Could not find a dereference strategy that can dereference "${uri}" as an Arazzo specification`);
140
+ }
141
+ parseResult.meta.set('retrievalURI', uri);
142
+ return parseResult;
143
+ } catch (error) {
144
+ throw new _DereferenceError.default(`Failed to dereference Arazzo Document at "${uri}"`, {
145
+ cause: error
146
+ });
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Dereferences an ApiDOM element representing an Arazzo Document.
152
+ *
153
+ * This function resolves all JSON References ($ref) and Reusable Object references
154
+ * ($components.*) in the Arazzo Document element.
155
+ *
156
+ * Supported scenarios:
157
+ * - ParseResultElement with retrievalURI metadata: baseURI derived automatically
158
+ * - ParseResultElement without retrievalURI: requires `options.resolve.baseURI`
159
+ * - Child element (e.g., WorkflowElement) with parseResult in strategyOpts:
160
+ * requires `options.dereference.strategyOpts.parseResult` for component resolution,
161
+ * and `options.resolve.baseURI` if parseResult lacks retrievalURI metadata
162
+ *
163
+ * Source descriptions can optionally be dereferenced using strategy options:
164
+ * - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
165
+ * - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
166
+ *
167
+ * Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
168
+ *
169
+ * @param element - An ApiDOM element (ParseResultElement or child element like WorkflowElement)
170
+ * @param options - Reference options (uses defaultOptions when not provided)
171
+ * @returns A promise that resolves to the dereferenced element
172
+ * @throws DereferenceError - When baseURI is required but not provided, or when dereferencing fails
173
+ *
174
+ * @example
175
+ * Dereference ParseResultElement with retrievalURI (from file parsing)
176
+ * ```typescript
177
+ * import { parseArazzo } from '@jentic/arazzo-parser';
178
+ *
179
+ * const parseResult = await parseArazzo('/path/to/arazzo.json');
180
+ * const dereferenced = await dereferenceArazzoElement(parseResult);
181
+ * ```
182
+ *
183
+ * @example
184
+ * Dereference ParseResultElement without retrievalURI (from inline parsing)
185
+ * ```typescript
186
+ * const parseResult = await parseArazzo({ arazzo: '1.0.1', ... });
187
+ * const dereferenced = await dereferenceArazzoElement(parseResult, {
188
+ * resolve: { baseURI: 'https://example.com/arazzo.json' },
189
+ * });
190
+ * ```
191
+ *
192
+ * @example
193
+ * Dereference child element (e.g., WorkflowElement)
194
+ * ```typescript
195
+ * const parseResult = await parseArazzo('/path/to/arazzo.json');
196
+ * const workflow = parseResult.api.workflows.get(0);
197
+ * const dereferenced = await dereferenceArazzoElement(workflow, {
198
+ * dereference: { strategyOpts: { parseResult } },
199
+ * });
200
+ * ```
201
+ *
202
+ * @example
203
+ * Dereference with source descriptions
204
+ * ```typescript
205
+ * const parseResult = await parseArazzo('/path/to/arazzo.json');
206
+ * const dereferenced = await dereferenceArazzoElement(parseResult, {
207
+ * dereference: { strategyOpts: { sourceDescriptions: true } },
208
+ * });
209
+ * ```
210
+ * @public
211
+ */
212
+ async function dereferenceElement(element, options = {}) {
213
+ const mergedOptions = (0, _empty.mergeOptions)(defaultOptions, options);
214
+ const refSet = mergedOptions.dereference?.refSet ?? new _empty.ReferenceSet();
215
+ let baseURI = mergedOptions.resolve?.baseURI;
216
+ let mediaType = 'text/plain';
217
+ if (refSet.size === 0) {
218
+ if ((0, _apidomDatamodel.isParseResultElement)(element)) {
219
+ if ((0, _apidomNsArazzo.isArazzoSpecification1Element)(element.api)) {
220
+ mediaType = _apidomNsArazzo.mediaTypes.latest();
221
+ }
222
+ if (element.hasMetaProperty('retrievalURI')) {
223
+ baseURI = (0, _apidomCore.toValue)(element.meta.get('retrievalURI'));
224
+ } else if (!baseURI) {
225
+ throw new _DereferenceError.default('baseURI option is required when dereferencing a ParseResultElement without retrievalURI metadata');
226
+ }
227
+ } else if ((0, _apidomDatamodel.isParseResultElement)(mergedOptions.dereference?.strategyOpts?.parseResult)) {
228
+ // dereferencing child element requires refSet for component resolution
229
+ const {
230
+ parseResult
231
+ } = mergedOptions.dereference.strategyOpts;
232
+ let rootURI;
233
+ if ((0, _apidomNsArazzo.isArazzoSpecification1Element)(parseResult.api)) {
234
+ mediaType = _apidomNsArazzo.mediaTypes.latest();
235
+ }
236
+ if (parseResult.hasMetaProperty('retrievalURI')) {
237
+ rootURI = (0, _apidomCore.toValue)(parseResult.meta.get('retrievalURI'));
238
+ } else if (baseURI) {
239
+ rootURI = baseURI;
240
+ } else {
241
+ throw new _DereferenceError.default('baseURI option is required when dereferencing a child element without retrievalURI metadata');
242
+ }
243
+ const elementReference = new _empty.Reference({
244
+ uri: `${rootURI}#fragment`,
245
+ value: new _apidomDatamodel.ParseResultElement([element])
246
+ });
247
+ const rootReference = new _empty.Reference({
248
+ uri: rootURI,
249
+ value: parseResult
250
+ });
251
+ refSet.add(elementReference).add(rootReference);
252
+ baseURI = rootURI;
253
+ }
254
+ }
255
+ try {
256
+ return await (0, _empty.dereferenceApiDOM)(element, (0, _empty.mergeOptions)(mergedOptions, {
257
+ resolve: {
258
+ baseURI
259
+ },
260
+ parse: {
261
+ mediaType
262
+ },
263
+ dereference: {
264
+ refSet
265
+ }
266
+ }));
267
+ } catch (error) {
268
+ throw new _DereferenceError.default('Failed to dereference Arazzo Document', {
269
+ cause: error
270
+ });
271
+ }
272
+ }
@@ -0,0 +1,264 @@
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 ArazzoJSON1Parser from '@speclynx/apidom-reference/parse/parsers/arazzo-json-1';
8
+ import ArazzoYAML1Parser from '@speclynx/apidom-reference/parse/parsers/arazzo-yaml-1';
9
+ import OpenAPIJSON20Parser from '@speclynx/apidom-reference/parse/parsers/openapi-json-2';
10
+ import OpenAPIYAML20Parser from '@speclynx/apidom-reference/parse/parsers/openapi-yaml-2';
11
+ import OpenAPIJSON30Parser from '@speclynx/apidom-reference/parse/parsers/openapi-json-3-0';
12
+ import OpenAPIYAML30Parser from '@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-0';
13
+ import OpenAPIJSON31Parser from '@speclynx/apidom-reference/parse/parsers/openapi-json-3-1';
14
+ import OpenAPIYAML31Parser from '@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-1';
15
+ import JSONParser from '@speclynx/apidom-reference/parse/parsers/json';
16
+ import YAMLParser from '@speclynx/apidom-reference/parse/parsers/yaml-1-2';
17
+ import BinaryParser from '@speclynx/apidom-reference/parse/parsers/binary';
18
+ import FileResolver from '@speclynx/apidom-reference/resolve/resolvers/file';
19
+ import HTTPResolverAxios from '@speclynx/apidom-reference/resolve/resolvers/http-axios';
20
+ import { isArazzoSpecification1Element, mediaTypes } from '@speclynx/apidom-ns-arazzo-1';
21
+ import { toValue } from '@speclynx/apidom-core';
22
+ import DereferenceError from "../errors/DereferenceError.mjs";
23
+ /**
24
+ * Options for dereferencing Arazzo Documents.
25
+ * @public
26
+ */
27
+ /**
28
+ * Default reference options for dereferencing Arazzo Documents.
29
+ * @public
30
+ */
31
+ export const defaultOptions = {
32
+ resolve: {
33
+ resolvers: [new FileResolver({
34
+ fileAllowList: ['*.json', '*.yaml', '*.yml']
35
+ }), new HTTPResolverAxios({
36
+ timeout: 5000,
37
+ redirects: 5,
38
+ withCredentials: false
39
+ })]
40
+ },
41
+ parse: {
42
+ parsers: [new ArazzoJSON1Parser({
43
+ allowEmpty: false,
44
+ fileExtensions: ['.json']
45
+ }), new ArazzoYAML1Parser({
46
+ allowEmpty: false,
47
+ fileExtensions: ['.yaml', '.yml']
48
+ }), new OpenAPIJSON20Parser({
49
+ allowEmpty: false,
50
+ fileExtensions: ['.json']
51
+ }), new OpenAPIYAML20Parser({
52
+ allowEmpty: false,
53
+ fileExtensions: ['.yaml', '.yml']
54
+ }), new OpenAPIJSON30Parser({
55
+ allowEmpty: false,
56
+ fileExtensions: ['.json']
57
+ }), new OpenAPIYAML30Parser({
58
+ allowEmpty: false,
59
+ fileExtensions: ['.yaml', '.yml']
60
+ }), new OpenAPIJSON31Parser({
61
+ allowEmpty: false,
62
+ fileExtensions: ['.json']
63
+ }), new OpenAPIYAML31Parser({
64
+ allowEmpty: false,
65
+ fileExtensions: ['.yaml', '.yml']
66
+ }), new JSONParser({
67
+ allowEmpty: false,
68
+ fileExtensions: ['.json']
69
+ }), new YAMLParser({
70
+ allowEmpty: false,
71
+ fileExtensions: ['.yaml', '.yml']
72
+ }), new BinaryParser({
73
+ allowEmpty: false
74
+ })],
75
+ parserOpts: {
76
+ sourceMap: false,
77
+ strict: true
78
+ }
79
+ },
80
+ dereference: {
81
+ strategies: [new Arazzo1DereferenceStrategy(), new OpenAPI2DereferenceStrategy(), new OpenAPI30DereferenceStrategy(), new OpenAPI31DereferenceStrategy()],
82
+ strategyOpts: {
83
+ sourceDescriptions: false
84
+ }
85
+ }
86
+ };
87
+
88
+ /**
89
+ * Dereferences an Arazzo Document from a file system path or HTTP(S) URL.
90
+ *
91
+ * This function resolves all JSON References ($ref) and Reusable Object references
92
+ * ($components.*) in the Arazzo Document.
93
+ *
94
+ * Source descriptions can optionally be dereferenced using strategy options:
95
+ * - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
96
+ * - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
97
+ *
98
+ * Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
99
+ *
100
+ * @param uri - A file system path or HTTP(S) URL to the Arazzo Document
101
+ * @param options - Reference options (uses defaultOptions when not provided)
102
+ * @returns A promise that resolves to the dereferenced Arazzo Document as ApiDOM element
103
+ * @throws DereferenceError - When dereferencing fails or document is not an Arazzo specification. The original error is available via the `cause` property.
104
+ *
105
+ * @example
106
+ * // Dereference from file
107
+ * const result = await dereferenceArazzo('/path/to/arazzo.json');
108
+ *
109
+ * @example
110
+ * // Dereference from URL
111
+ * const result = await dereferenceArazzo('https://example.com/arazzo.yaml');
112
+ *
113
+ * @example
114
+ * // Dereference with source descriptions
115
+ * const result = await dereferenceArazzo('/path/to/arazzo.json', {
116
+ * dereference: { strategyOpts: { sourceDescriptions: true } },
117
+ * });
118
+ *
119
+ * @example
120
+ * // Dereference with custom options
121
+ * const result = await dereferenceArazzo('/path/to/arazzo.json', customReferenceOptions);
122
+ * @public
123
+ */
124
+ export async function dereference(uri, options = {}) {
125
+ const mergedOptions = mergeOptions(defaultOptions, options);
126
+ try {
127
+ const parseResult = await dereferenceURI(uri, mergedOptions);
128
+
129
+ // validate that the dereferenced document is an Arazzo specification
130
+ if (!isArazzoSpecification1Element(parseResult.api)) {
131
+ throw new UnmatchedDereferenceStrategyError(`Could not find a dereference strategy that can dereference "${uri}" as an Arazzo specification`);
132
+ }
133
+ parseResult.meta.set('retrievalURI', uri);
134
+ return parseResult;
135
+ } catch (error) {
136
+ throw new DereferenceError(`Failed to dereference Arazzo Document at "${uri}"`, {
137
+ cause: error
138
+ });
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Dereferences an ApiDOM element representing an Arazzo Document.
144
+ *
145
+ * This function resolves all JSON References ($ref) and Reusable Object references
146
+ * ($components.*) in the Arazzo Document element.
147
+ *
148
+ * Supported scenarios:
149
+ * - ParseResultElement with retrievalURI metadata: baseURI derived automatically
150
+ * - ParseResultElement without retrievalURI: requires `options.resolve.baseURI`
151
+ * - Child element (e.g., WorkflowElement) with parseResult in strategyOpts:
152
+ * requires `options.dereference.strategyOpts.parseResult` for component resolution,
153
+ * and `options.resolve.baseURI` if parseResult lacks retrievalURI metadata
154
+ *
155
+ * Source descriptions can optionally be dereferenced using strategy options:
156
+ * - `sourceDescriptions`: `true` (all) or `['name1', 'name2']` (specific names only)
157
+ * - `sourceDescriptionsMaxDepth`: Maximum recursion depth for nested Arazzo source descriptions (default: `+Infinity`)
158
+ *
159
+ * Options can be passed globally via `strategyOpts` or strategy-specific via `strategyOpts['arazzo-1']`.
160
+ *
161
+ * @param element - An ApiDOM element (ParseResultElement or child element like WorkflowElement)
162
+ * @param options - Reference options (uses defaultOptions when not provided)
163
+ * @returns A promise that resolves to the dereferenced element
164
+ * @throws DereferenceError - When baseURI is required but not provided, or when dereferencing fails
165
+ *
166
+ * @example
167
+ * Dereference ParseResultElement with retrievalURI (from file parsing)
168
+ * ```typescript
169
+ * import { parseArazzo } from '@jentic/arazzo-parser';
170
+ *
171
+ * const parseResult = await parseArazzo('/path/to/arazzo.json');
172
+ * const dereferenced = await dereferenceArazzoElement(parseResult);
173
+ * ```
174
+ *
175
+ * @example
176
+ * Dereference ParseResultElement without retrievalURI (from inline parsing)
177
+ * ```typescript
178
+ * const parseResult = await parseArazzo({ arazzo: '1.0.1', ... });
179
+ * const dereferenced = await dereferenceArazzoElement(parseResult, {
180
+ * resolve: { baseURI: 'https://example.com/arazzo.json' },
181
+ * });
182
+ * ```
183
+ *
184
+ * @example
185
+ * Dereference child element (e.g., WorkflowElement)
186
+ * ```typescript
187
+ * const parseResult = await parseArazzo('/path/to/arazzo.json');
188
+ * const workflow = parseResult.api.workflows.get(0);
189
+ * const dereferenced = await dereferenceArazzoElement(workflow, {
190
+ * dereference: { strategyOpts: { parseResult } },
191
+ * });
192
+ * ```
193
+ *
194
+ * @example
195
+ * Dereference with source descriptions
196
+ * ```typescript
197
+ * const parseResult = await parseArazzo('/path/to/arazzo.json');
198
+ * const dereferenced = await dereferenceArazzoElement(parseResult, {
199
+ * dereference: { strategyOpts: { sourceDescriptions: true } },
200
+ * });
201
+ * ```
202
+ * @public
203
+ */
204
+ export async function dereferenceElement(element, options = {}) {
205
+ const mergedOptions = mergeOptions(defaultOptions, options);
206
+ const refSet = mergedOptions.dereference?.refSet ?? new ReferenceSet();
207
+ let baseURI = mergedOptions.resolve?.baseURI;
208
+ let mediaType = 'text/plain';
209
+ if (refSet.size === 0) {
210
+ if (isParseResultElement(element)) {
211
+ if (isArazzoSpecification1Element(element.api)) {
212
+ mediaType = mediaTypes.latest();
213
+ }
214
+ if (element.hasMetaProperty('retrievalURI')) {
215
+ baseURI = toValue(element.meta.get('retrievalURI'));
216
+ } else if (!baseURI) {
217
+ throw new DereferenceError('baseURI option is required when dereferencing a ParseResultElement without retrievalURI metadata');
218
+ }
219
+ } else if (isParseResultElement(mergedOptions.dereference?.strategyOpts?.parseResult)) {
220
+ // dereferencing child element requires refSet for component resolution
221
+ const {
222
+ parseResult
223
+ } = mergedOptions.dereference.strategyOpts;
224
+ let rootURI;
225
+ if (isArazzoSpecification1Element(parseResult.api)) {
226
+ mediaType = mediaTypes.latest();
227
+ }
228
+ if (parseResult.hasMetaProperty('retrievalURI')) {
229
+ rootURI = toValue(parseResult.meta.get('retrievalURI'));
230
+ } else if (baseURI) {
231
+ rootURI = baseURI;
232
+ } else {
233
+ throw new DereferenceError('baseURI option is required when dereferencing a child element without retrievalURI metadata');
234
+ }
235
+ const elementReference = new Reference({
236
+ uri: `${rootURI}#fragment`,
237
+ value: new ParseResultElement([element])
238
+ });
239
+ const rootReference = new Reference({
240
+ uri: rootURI,
241
+ value: parseResult
242
+ });
243
+ refSet.add(elementReference).add(rootReference);
244
+ baseURI = rootURI;
245
+ }
246
+ }
247
+ try {
248
+ return await dereferenceApiDOMElement(element, mergeOptions(mergedOptions, {
249
+ resolve: {
250
+ baseURI
251
+ },
252
+ parse: {
253
+ mediaType
254
+ },
255
+ dereference: {
256
+ refSet
257
+ }
258
+ }));
259
+ } catch (error) {
260
+ throw new DereferenceError('Failed to dereference Arazzo Document', {
261
+ cause: error
262
+ });
263
+ }
264
+ }