@speclynx/apidom-reference 4.0.3 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/apidom-reference.browser.js +43 -19
  3. package/dist/apidom-reference.browser.min.js +1 -1
  4. package/package.json +27 -26
  5. package/src/File.ts +0 -63
  6. package/src/Reference.ts +0 -38
  7. package/src/ReferenceSet.ts +0 -73
  8. package/src/bundle/index.ts +0 -57
  9. package/src/bundle/strategies/BundleStrategy.ts +0 -27
  10. package/src/bundle/strategies/openapi-3-1/index.ts +0 -57
  11. package/src/configuration/empty.ts +0 -1
  12. package/src/configuration/saturated.ts +0 -72
  13. package/src/dereference/index.ts +0 -96
  14. package/src/dereference/strategies/DereferenceStrategy.ts +0 -27
  15. package/src/dereference/strategies/apidom/index.ts +0 -128
  16. package/src/dereference/strategies/apidom/selectors/element-id.ts +0 -48
  17. package/src/dereference/strategies/apidom/visitor.ts +0 -316
  18. package/src/dereference/strategies/arazzo-1/index.ts +0 -158
  19. package/src/dereference/strategies/arazzo-1/selectors/$anchor.ts +0 -9
  20. package/src/dereference/strategies/arazzo-1/selectors/uri.ts +0 -5
  21. package/src/dereference/strategies/arazzo-1/source-descriptions.ts +0 -317
  22. package/src/dereference/strategies/arazzo-1/util.ts +0 -33
  23. package/src/dereference/strategies/arazzo-1/visitor.ts +0 -574
  24. package/src/dereference/strategies/asyncapi-2/index.ts +0 -133
  25. package/src/dereference/strategies/asyncapi-2/visitor.ts +0 -589
  26. package/src/dereference/strategies/openapi-2/index.ts +0 -136
  27. package/src/dereference/strategies/openapi-2/visitor.ts +0 -745
  28. package/src/dereference/strategies/openapi-3-0/index.ts +0 -134
  29. package/src/dereference/strategies/openapi-3-0/visitor.ts +0 -760
  30. package/src/dereference/strategies/openapi-3-1/index.ts +0 -141
  31. package/src/dereference/strategies/openapi-3-1/selectors/$anchor.ts +0 -64
  32. package/src/dereference/strategies/openapi-3-1/selectors/uri.ts +0 -54
  33. package/src/dereference/strategies/openapi-3-1/util.ts +0 -83
  34. package/src/dereference/strategies/openapi-3-1/visitor.ts +0 -1053
  35. package/src/dereference/util.ts +0 -29
  36. package/src/errors/BundleError.ts +0 -8
  37. package/src/errors/DereferenceError.ts +0 -8
  38. package/src/errors/EvaluationElementIdError.ts +0 -8
  39. package/src/errors/EvaluationJsonSchema$anchorError.ts +0 -8
  40. package/src/errors/EvaluationJsonSchemaUriError.ts +0 -8
  41. package/src/errors/InvalidJsonSchema$anchorError.ts +0 -12
  42. package/src/errors/JsonSchema$anchorError.ts +0 -8
  43. package/src/errors/JsonSchemaUriError.ts +0 -8
  44. package/src/errors/MaximumBundleDepthError.ts +0 -8
  45. package/src/errors/MaximumDereferenceDepthError.ts +0 -8
  46. package/src/errors/MaximumResolveDepthError.ts +0 -8
  47. package/src/errors/ParseError.ts +0 -8
  48. package/src/errors/ParserError.ts +0 -8
  49. package/src/errors/PluginError.ts +0 -15
  50. package/src/errors/ResolveError.ts +0 -8
  51. package/src/errors/ResolverError.ts +0 -8
  52. package/src/errors/UnmatchedBundleStrategyError.ts +0 -8
  53. package/src/errors/UnmatchedDereferenceStrategyError.ts +0 -8
  54. package/src/errors/UnmatchedParserError.ts +0 -8
  55. package/src/errors/UnmatchedResolveStrategyError.ts +0 -8
  56. package/src/errors/UnmatchedResolverError.ts +0 -8
  57. package/src/errors/UnresolvableReferenceError.ts +0 -8
  58. package/src/index.ts +0 -135
  59. package/src/options/index.ts +0 -239
  60. package/src/options/util.ts +0 -22
  61. package/src/parse/index.ts +0 -67
  62. package/src/parse/parsers/Parser.ts +0 -80
  63. package/src/parse/parsers/apidom-json/index.ts +0 -78
  64. package/src/parse/parsers/arazzo-json-1/index.ts +0 -76
  65. package/src/parse/parsers/arazzo-json-1/source-descriptions.ts +0 -280
  66. package/src/parse/parsers/arazzo-yaml-1/index.ts +0 -77
  67. package/src/parse/parsers/arazzo-yaml-1/source-descriptions.ts +0 -16
  68. package/src/parse/parsers/asyncapi-json-2/index.ts +0 -58
  69. package/src/parse/parsers/asyncapi-yaml-2/index.ts +0 -58
  70. package/src/parse/parsers/binary/index-browser.ts +0 -60
  71. package/src/parse/parsers/binary/index-node.ts +0 -57
  72. package/src/parse/parsers/json/index.ts +0 -52
  73. package/src/parse/parsers/openapi-json-2/index.ts +0 -58
  74. package/src/parse/parsers/openapi-json-3-0/index.ts +0 -59
  75. package/src/parse/parsers/openapi-json-3-1/index.ts +0 -59
  76. package/src/parse/parsers/openapi-yaml-2/index.ts +0 -58
  77. package/src/parse/parsers/openapi-yaml-3-0/index.ts +0 -59
  78. package/src/parse/parsers/openapi-yaml-3-1/index.ts +0 -59
  79. package/src/parse/parsers/yaml-1-2/index.ts +0 -60
  80. package/src/resolve/index.ts +0 -75
  81. package/src/resolve/resolvers/HTTPResolver.ts +0 -58
  82. package/src/resolve/resolvers/Resolver.ts +0 -25
  83. package/src/resolve/resolvers/file/index-browser.ts +0 -24
  84. package/src/resolve/resolvers/file/index-node.ts +0 -55
  85. package/src/resolve/resolvers/http-axios/cache/MemoryCache.ts +0 -46
  86. package/src/resolve/resolvers/http-axios/index.ts +0 -130
  87. package/src/resolve/strategies/ResolveStrategy.ts +0 -26
  88. package/src/resolve/strategies/apidom/index.ts +0 -78
  89. package/src/resolve/strategies/asyncapi-2/index.ts +0 -78
  90. package/src/resolve/strategies/openapi-2/index.ts +0 -78
  91. package/src/resolve/strategies/openapi-3-0/index.ts +0 -78
  92. package/src/resolve/strategies/openapi-3-1/index.ts +0 -78
  93. package/src/resolve/util.ts +0 -39
  94. package/src/util/plugins.ts +0 -37
  95. package/src/util/url.ts +0 -285
@@ -1,317 +0,0 @@
1
- import {
2
- Element,
3
- ParseResultElement,
4
- AnnotationElement,
5
- isArrayElement,
6
- isStringElement,
7
- isParseResultElement,
8
- } from '@speclynx/apidom-datamodel';
9
- import {
10
- isArazzoSpecification1Element,
11
- isSourceDescriptionElement,
12
- } from '@speclynx/apidom-ns-arazzo-1';
13
- import { isSwaggerElement } from '@speclynx/apidom-ns-openapi-2';
14
- import { isOpenApi3_0Element } from '@speclynx/apidom-ns-openapi-3-0';
15
- import { isOpenApi3_1Element } from '@speclynx/apidom-ns-openapi-3-1';
16
- import { toValue } from '@speclynx/apidom-core';
17
-
18
- import * as url from '../../../util/url.ts';
19
- import type { ReferenceOptions } from '../../../options/index.ts';
20
- import { merge as mergeOptions } from '../../../options/util.ts';
21
- import dereference, { dereferenceApiDOM } from '../../index.ts';
22
-
23
- interface DereferenceSourceDescriptionContext {
24
- baseURI: string;
25
- options: ReferenceOptions;
26
- strategyName: string;
27
- currentDepth: number;
28
- visitedUrls: Set<string>;
29
- }
30
-
31
- /**
32
- * Dereferences a single source description element.
33
- * Returns ParseResultElement on success, or with annotation if skipped.
34
- */
35
- async function dereferenceSourceDescription(
36
- sourceDescription: Element,
37
- ctx: DereferenceSourceDescriptionContext,
38
- ): Promise<ParseResultElement> {
39
- const parseResult = new ParseResultElement();
40
-
41
- if (!isSourceDescriptionElement(sourceDescription)) {
42
- const annotation = new AnnotationElement(
43
- 'Element is not a valid SourceDescriptionElement. Skipping',
44
- );
45
- annotation.classes.push('warning');
46
- parseResult.push(annotation);
47
- return parseResult;
48
- }
49
-
50
- // set class and metadata from source description element
51
- parseResult.classes.push('source-description');
52
- if (isStringElement(sourceDescription.name))
53
- parseResult.setMetaProperty('name', toValue(sourceDescription.name) as string);
54
- if (isStringElement(sourceDescription.type))
55
- parseResult.setMetaProperty('type', toValue(sourceDescription.type) as string);
56
-
57
- const sourceDescriptionURI = toValue(sourceDescription.url);
58
- if (typeof sourceDescriptionURI !== 'string') {
59
- const annotation = new AnnotationElement(
60
- 'Source description URL is missing or not a string. Skipping',
61
- );
62
- annotation.classes.push('warning');
63
- parseResult.push(annotation);
64
- return parseResult;
65
- }
66
-
67
- // normalize URI for consistent cycle detection and refSet cache key matching
68
- const retrievalURI = url.sanitize(url.stripHash(url.resolve(ctx.baseURI, sourceDescriptionURI)));
69
- parseResult.setMetaProperty('retrievalURI', retrievalURI);
70
-
71
- // skip if already visited (cycle detection)
72
- if (ctx.visitedUrls.has(retrievalURI)) {
73
- const annotation = new AnnotationElement(
74
- `Source description "${retrievalURI}" has already been visited. Skipping to prevent cycle`,
75
- );
76
- annotation.classes.push('warning');
77
- parseResult.push(annotation);
78
- return parseResult;
79
- }
80
- ctx.visitedUrls.add(retrievalURI);
81
-
82
- // check if source description was already parsed (e.g., during parse phase with sourceDescriptions: true)
83
- const existingParseResult = sourceDescription.meta.get('parseResult');
84
-
85
- try {
86
- let sourceDescriptionDereferenced: ParseResultElement;
87
-
88
- if (isParseResultElement(existingParseResult)) {
89
- // use existing parsed result - just dereference it (no re-fetch/re-parse)
90
- sourceDescriptionDereferenced = await dereferenceApiDOM(
91
- existingParseResult,
92
- mergeOptions(ctx.options, {
93
- parse: {
94
- mediaType: 'text/plain', // allow dereference strategy detection via ApiDOM inspection
95
- },
96
- resolve: { baseURI: retrievalURI },
97
- dereference: {
98
- strategyOpts: {
99
- // nested documents should dereference all their source descriptions
100
- // (parent's name filter doesn't apply to nested documents)
101
- // set at strategy-specific level to override any inherited filters
102
- [ctx.strategyName]: {
103
- sourceDescriptions: true,
104
- sourceDescriptionsDepth: ctx.currentDepth + 1,
105
- sourceDescriptionsVisitedUrls: ctx.visitedUrls,
106
- },
107
- },
108
- },
109
- }),
110
- );
111
- } else {
112
- // no existing parse result - fetch, parse, and dereference
113
- sourceDescriptionDereferenced = await dereference(
114
- retrievalURI,
115
- mergeOptions(ctx.options, {
116
- parse: {
117
- mediaType: 'text/plain', // allow parser plugin detection
118
- },
119
- dereference: {
120
- strategyOpts: {
121
- // nested documents should dereference all their source descriptions
122
- // (parent's name filter doesn't apply to nested documents)
123
- // set at strategy-specific level to override any inherited filters
124
- [ctx.strategyName]: {
125
- sourceDescriptions: true,
126
- sourceDescriptionsDepth: ctx.currentDepth + 1,
127
- sourceDescriptionsVisitedUrls: ctx.visitedUrls,
128
- },
129
- },
130
- },
131
- }),
132
- );
133
- }
134
-
135
- // merge dereferenced result into our parse result
136
- for (const item of sourceDescriptionDereferenced) {
137
- parseResult.push(item);
138
- }
139
- } catch (error: unknown) {
140
- // create error annotation instead of failing entire dereference
141
- const message = error instanceof Error ? error.message : String(error);
142
- const annotation = new AnnotationElement(
143
- `Error dereferencing source description "${retrievalURI}": ${message}`,
144
- );
145
- annotation.classes.push('error');
146
- parseResult.push(annotation);
147
- return parseResult;
148
- }
149
-
150
- // only allow OpenAPI and Arazzo as source descriptions
151
- const { api: sourceDescriptionAPI } = parseResult;
152
- const isOpenApi =
153
- isSwaggerElement(sourceDescriptionAPI) ||
154
- isOpenApi3_0Element(sourceDescriptionAPI) ||
155
- isOpenApi3_1Element(sourceDescriptionAPI);
156
- const isArazzo = isArazzoSpecification1Element(sourceDescriptionAPI);
157
-
158
- if (!isOpenApi && !isArazzo) {
159
- const annotation = new AnnotationElement(
160
- `Source description "${retrievalURI}" is not an OpenAPI or Arazzo document`,
161
- );
162
- annotation.classes.push('warning');
163
- parseResult.push(annotation);
164
- return parseResult;
165
- }
166
-
167
- // validate declared type matches actual dereferenced type
168
- const declaredType = toValue(sourceDescription.type);
169
- if (typeof declaredType === 'string') {
170
- if (declaredType === 'openapi' && !isOpenApi) {
171
- const annotation = new AnnotationElement(
172
- `Source description "${retrievalURI}" declared as "openapi" but dereferenced as Arazzo document`,
173
- );
174
- annotation.classes.push('warning');
175
- parseResult.push(annotation);
176
- } else if (declaredType === 'arazzo' && !isArazzo) {
177
- const annotation = new AnnotationElement(
178
- `Source description "${retrievalURI}" declared as "arazzo" but dereferenced as OpenAPI document`,
179
- );
180
- annotation.classes.push('warning');
181
- parseResult.push(annotation);
182
- }
183
- }
184
-
185
- return parseResult;
186
- }
187
-
188
- /**
189
- * Dereferences source descriptions from an Arazzo document.
190
- *
191
- * Each source description result is attached to its corresponding
192
- * SourceDescriptionElement's meta as 'parseResult' for easy access,
193
- * regardless of success or failure. On failure, the ParseResultElement
194
- * contains annotations explaining what went wrong.
195
- *
196
- * @param parseResult - ParseResult containing a parsed (optionally dereferenced) Arazzo specification
197
- * @param parseResultRetrievalURI - URI from which the parseResult was retrieved
198
- * @param options - Full ReferenceOptions. Pass `sourceDescriptions` as an array of names
199
- * in `dereference.strategyOpts` to filter which source descriptions to process.
200
- * @param strategyName - Strategy name for options lookup (defaults to 'arazzo-1')
201
- * @returns Array of ParseResultElements. Returns one ParseResultElement per source description
202
- * (each with class 'source-description' and metadata: name, type, retrievalURI).
203
- * May return early with a single-element array containing a warning annotation when:
204
- * - The API is not an Arazzo specification
205
- * - The sourceDescriptions field is missing or not an array
206
- * - Maximum dereference depth is exceeded (error annotation)
207
- * Returns an empty array when no source description names match the filter.
208
- *
209
- * @example
210
- * ```typescript
211
- * import { toValue } from '@speclynx/apidom-core';
212
- *
213
- * // Dereference all source descriptions
214
- * await dereferenceSourceDescriptions(parseResult, uri, options);
215
- *
216
- * // Filter by name
217
- * await dereferenceSourceDescriptions(parseResult, uri, mergeOptions(options, {
218
- * dereference: { strategyOpts: { sourceDescriptions: ['petStore'] } },
219
- * }));
220
- *
221
- * // Access dereferenced document from source description element
222
- * const sourceDesc = parseResult.api.sourceDescriptions.get(0);
223
- * const dereferencedDoc = sourceDesc.meta.get('parseResult');
224
- * const retrievalURI = toValue(dereferencedDoc.meta.get('retrievalURI'));
225
- * ```
226
- *
227
- * @public
228
- */
229
- export async function dereferenceSourceDescriptions(
230
- parseResult: ParseResultElement,
231
- parseResultRetrievalURI: string,
232
- options: ReferenceOptions,
233
- strategyName: string = 'arazzo-1',
234
- ): Promise<ParseResultElement[]> {
235
- const baseURI = url.sanitize(url.stripHash(parseResultRetrievalURI));
236
- const results: ParseResultElement[] = [];
237
-
238
- // get API from dereferenced parse result
239
- const { api } = parseResult;
240
-
241
- /**
242
- * Validate prerequisites for dereferencing source descriptions.
243
- * Return warning annotations if validation fails.
244
- */
245
- if (!isArazzoSpecification1Element(api)) {
246
- const annotation = new AnnotationElement(
247
- 'Cannot dereference source descriptions: API is not an Arazzo specification',
248
- );
249
- annotation.classes.push('warning');
250
- return [new ParseResultElement([annotation])];
251
- }
252
- if (!isArrayElement(api.sourceDescriptions)) {
253
- const annotation = new AnnotationElement(
254
- 'Cannot dereference source descriptions: sourceDescriptions field is missing or not an array',
255
- );
256
- annotation.classes.push('warning');
257
- return [new ParseResultElement([annotation])];
258
- }
259
-
260
- // user config: strategy-specific options take precedence over global strategyOpts
261
- const maxDepth =
262
- options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptionsMaxDepth ??
263
- options?.dereference?.strategyOpts?.sourceDescriptionsMaxDepth ??
264
- +Infinity;
265
-
266
- // recursion state comes from strategy-specific options
267
- const sharedOpts = options?.dereference?.strategyOpts?.[strategyName] ?? {};
268
- const currentDepth = sharedOpts.sourceDescriptionsDepth ?? 0;
269
- const visitedUrls: Set<string> = sharedOpts.sourceDescriptionsVisitedUrls ?? new Set();
270
-
271
- // add current file to visited URLs to prevent cycles
272
- visitedUrls.add(baseURI);
273
-
274
- if (currentDepth >= maxDepth) {
275
- const annotation = new AnnotationElement(
276
- `Maximum dereference depth of ${maxDepth} has been exceeded by file "${baseURI}"`,
277
- );
278
- annotation.classes.push('error');
279
- const parseResult = new ParseResultElement([annotation]);
280
- parseResult.classes.push('source-description');
281
- return [parseResult];
282
- }
283
-
284
- const ctx: DereferenceSourceDescriptionContext = {
285
- baseURI,
286
- options,
287
- strategyName,
288
- currentDepth,
289
- visitedUrls,
290
- };
291
-
292
- // determine which source descriptions to dereference (array filters by name)
293
- const sourceDescriptionsOption =
294
- options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptions ??
295
- options?.dereference?.strategyOpts?.sourceDescriptions;
296
-
297
- const sourceDescriptions = Array.isArray(sourceDescriptionsOption)
298
- ? api.sourceDescriptions.filter((sd) => {
299
- if (!isSourceDescriptionElement(sd)) return false;
300
- const name = toValue(sd.name);
301
- return typeof name === 'string' && sourceDescriptionsOption.includes(name);
302
- })
303
- : api.sourceDescriptions;
304
-
305
- // process sequentially to ensure proper cycle detection with shared visitedUrls
306
- for (const sourceDescription of sourceDescriptions) {
307
- const sourceDescriptionDereferenceResult = await dereferenceSourceDescription(
308
- sourceDescription,
309
- ctx,
310
- );
311
- // always attach result (even on failure - contains annotations)
312
- sourceDescription.meta.set('parseResult', sourceDescriptionDereferenceResult);
313
- results.push(sourceDescriptionDereferenceResult);
314
- }
315
-
316
- return results;
317
- }
@@ -1,33 +0,0 @@
1
- import { Element, isPrimitiveElement } from '@speclynx/apidom-datamodel';
2
- import { refractJSONSchema } from '@speclynx/apidom-ns-arazzo-1';
3
-
4
- export { resolveSchema$refField, resolveSchema$idField } from '../openapi-3-1/util.ts';
5
-
6
- /**
7
- * Cached version of JSONSchemaElement.refract.
8
- */
9
- export const refractToJSONSchemaElement = <T extends Element>(element: T) => {
10
- if (refractToJSONSchemaElement.cache.has(element)) {
11
- return refractToJSONSchemaElement.cache.get(element);
12
- }
13
-
14
- const refracted = refractJSONSchema(element);
15
- refractToJSONSchemaElement.cache.set(element, refracted);
16
- return refracted;
17
- };
18
- refractToJSONSchemaElement.cache = new WeakMap();
19
-
20
- /**
21
- * @public
22
- */
23
- export const maybeRefractToJSONSchemaElement = <T extends Element>(element: T) => {
24
- /**
25
- * Conditional version of refractToJSONSchemaElement, that acts as an identity
26
- * function for all non-primitive Element instances.
27
- */
28
- if (isPrimitiveElement(element)) {
29
- return refractToJSONSchemaElement(element);
30
- }
31
-
32
- return element;
33
- };