@speclynx/apidom-reference 2.5.1 → 2.6.1
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 +14 -0
- package/README.md +109 -6
- package/dist/apidom-reference.browser.js +78639 -78397
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +25 -25
- package/src/bundle/index.cjs +1 -1
- package/src/bundle/index.mjs +1 -1
- package/src/configuration/saturated.cjs +4 -2
- package/src/configuration/saturated.mjs +5 -3
- package/src/dereference/index.cjs +1 -1
- package/src/dereference/index.mjs +1 -1
- package/src/dereference/strategies/openapi-3-0/visitor.cjs +1 -1
- package/src/dereference/strategies/openapi-3-0/visitor.mjs +1 -1
- package/src/dereference/strategies/openapi-3-1/visitor.cjs +1 -1
- package/src/dereference/strategies/openapi-3-1/visitor.mjs +1 -1
- package/src/errors/InvalidJsonSchema$anchorError.cjs +1 -1
- package/src/errors/InvalidJsonSchema$anchorError.mjs +1 -1
- package/src/errors/UnmatchedParserError.cjs +11 -0
- package/src/errors/UnmatchedParserError.mjs +6 -0
- package/src/index.cjs +3 -1
- package/src/index.mjs +1 -0
- package/src/parse/index.cjs +3 -3
- package/src/parse/index.mjs +3 -3
- package/src/parse/parsers/arazzo-json-1/index.cjs +12 -2
- package/src/parse/parsers/arazzo-json-1/index.mjs +14 -4
- package/src/parse/parsers/arazzo-json-1/source-description.cjs +177 -0
- package/src/parse/parsers/arazzo-json-1/source-description.mjs +171 -0
- package/src/parse/parsers/arazzo-yaml-1/index.cjs +12 -2
- package/src/parse/parsers/arazzo-yaml-1/index.mjs +12 -2
- package/src/resolve/index.cjs +2 -2
- package/src/resolve/index.mjs +2 -2
- package/src/resolve/strategies/apidom/index.cjs +1 -1
- package/src/resolve/strategies/apidom/index.mjs +1 -1
- package/src/resolve/strategies/asyncapi-2/index.cjs +1 -1
- package/src/resolve/strategies/asyncapi-2/index.mjs +1 -1
- package/src/resolve/strategies/openapi-2/index.cjs +1 -1
- package/src/resolve/strategies/openapi-2/index.mjs +1 -1
- package/src/resolve/strategies/openapi-3-0/index.cjs +1 -1
- package/src/resolve/strategies/openapi-3-0/index.mjs +1 -1
- package/src/resolve/strategies/openapi-3-1/index.cjs +1 -1
- package/src/resolve/strategies/openapi-3-1/index.mjs +1 -1
- package/src/resolve/util.cjs +2 -2
- package/src/resolve/util.mjs +2 -2
- package/types/apidom-reference.d.ts +10 -4
- package/types/errors/UnmatchedParserError.d.ts +7 -0
- package/types/index.d.ts +1 -0
- package/types/parse/parsers/Parser.d.ts +3 -2
- package/types/parse/parsers/arazzo-json-1/index.d.ts +5 -1
- package/types/parse/parsers/arazzo-json-1/source-description.d.ts +13 -0
- package/types/parse/parsers/arazzo-yaml-1/index.d.ts +5 -1
- package/types/resolve/resolvers/Resolver.d.ts +3 -2
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { ParseResultElement, AnnotationElement, isArrayElement, isStringElement, cloneDeep } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { isArazzoSpecification1Element, isSourceDescriptionElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
3
|
+
import { isSwaggerElement } from '@speclynx/apidom-ns-openapi-2';
|
|
4
|
+
import { isOpenApi3_0Element } from '@speclynx/apidom-ns-openapi-3-0';
|
|
5
|
+
import { isOpenApi3_1Element } from '@speclynx/apidom-ns-openapi-3-1';
|
|
6
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
7
|
+
import * as url from "../../../util/url.mjs";
|
|
8
|
+
import { merge as mergeOptions } from "../../../options/util.mjs"; // shared key for recursion state (works across JSON/YAML parsers)
|
|
9
|
+
const ARAZZO_RECURSION_KEY = 'arazzo-1';
|
|
10
|
+
/**
|
|
11
|
+
* Parses a single source description element.
|
|
12
|
+
* Returns ParseResultElement on success, or undefined if skipped.
|
|
13
|
+
*/
|
|
14
|
+
async function parseSourceDescription(sourceDescription, ctx) {
|
|
15
|
+
const parseResult = new ParseResultElement();
|
|
16
|
+
if (!isSourceDescriptionElement(sourceDescription)) {
|
|
17
|
+
const annotation = new AnnotationElement('Element is not a valid SourceDescriptionElement. Skipping.');
|
|
18
|
+
annotation.classes.push('warning');
|
|
19
|
+
parseResult.push(annotation);
|
|
20
|
+
return parseResult;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// set class and metadata from source description element
|
|
24
|
+
parseResult.classes.push('source-description');
|
|
25
|
+
if (isStringElement(sourceDescription.name)) parseResult.setMetaProperty('name', cloneDeep(sourceDescription.name));
|
|
26
|
+
if (isStringElement(sourceDescription.type)) parseResult.setMetaProperty('type', cloneDeep(sourceDescription.type));
|
|
27
|
+
const sourceDescriptionURI = toValue(sourceDescription.url);
|
|
28
|
+
if (typeof sourceDescriptionURI !== 'string') {
|
|
29
|
+
const annotation = new AnnotationElement('Source description URL is missing or not a string. Skipping.');
|
|
30
|
+
annotation.classes.push('warning');
|
|
31
|
+
parseResult.push(annotation);
|
|
32
|
+
return parseResult;
|
|
33
|
+
}
|
|
34
|
+
const retrievalURI = url.resolve(ctx.baseURI, sourceDescriptionURI);
|
|
35
|
+
|
|
36
|
+
// skip if already visited (cycle detection)
|
|
37
|
+
if (ctx.visitedUrls.has(retrievalURI)) {
|
|
38
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" has already been visited. Skipping to prevent cycle.`);
|
|
39
|
+
annotation.classes.push('warning');
|
|
40
|
+
parseResult.push(annotation);
|
|
41
|
+
return parseResult;
|
|
42
|
+
}
|
|
43
|
+
ctx.visitedUrls.add(retrievalURI);
|
|
44
|
+
try {
|
|
45
|
+
const sdParseResult = await ctx.parseFn(retrievalURI, mergeOptions(ctx.options, {
|
|
46
|
+
parse: {
|
|
47
|
+
mediaType: 'text/plain',
|
|
48
|
+
// allow parser plugin detection
|
|
49
|
+
parserOpts: {
|
|
50
|
+
[ARAZZO_RECURSION_KEY]: {
|
|
51
|
+
sourceDescriptionsDepth: ctx.currentDepth + 1,
|
|
52
|
+
sourceDescriptionsVisitedUrls: ctx.visitedUrls
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
// merge parsed result into our parse result
|
|
58
|
+
for (const item of sdParseResult) {
|
|
59
|
+
parseResult.push(item);
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
// create error annotation instead of failing entire parse
|
|
63
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
64
|
+
const annotation = new AnnotationElement(`Error parsing source description "${retrievalURI}": ${message}`);
|
|
65
|
+
annotation.classes.push('error');
|
|
66
|
+
parseResult.push(annotation);
|
|
67
|
+
return parseResult;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// only allow OpenAPI and Arazzo as source descriptions
|
|
71
|
+
const {
|
|
72
|
+
api: sourceDescriptionAPI
|
|
73
|
+
} = parseResult;
|
|
74
|
+
const isOpenApi = isSwaggerElement(sourceDescriptionAPI) || isOpenApi3_0Element(sourceDescriptionAPI) || isOpenApi3_1Element(sourceDescriptionAPI);
|
|
75
|
+
const isArazzo = isArazzoSpecification1Element(sourceDescriptionAPI);
|
|
76
|
+
if (!isOpenApi && !isArazzo) {
|
|
77
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" is not an OpenAPI or Arazzo document. Skipping.`);
|
|
78
|
+
annotation.classes.push('warning');
|
|
79
|
+
parseResult.push(annotation);
|
|
80
|
+
return parseResult;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// validate declared type matches actual parsed type
|
|
84
|
+
const declaredType = toValue(sourceDescription.type);
|
|
85
|
+
if (typeof declaredType === 'string') {
|
|
86
|
+
if (declaredType === 'openapi' && !isOpenApi) {
|
|
87
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" declared as "openapi" but parsed as Arazzo document.`);
|
|
88
|
+
annotation.classes.push('warning');
|
|
89
|
+
parseResult.push(annotation);
|
|
90
|
+
} else if (declaredType === 'arazzo' && !isArazzo) {
|
|
91
|
+
const annotation = new AnnotationElement(`Source description "${retrievalURI}" declared as "arazzo" but parsed as OpenAPI document.`);
|
|
92
|
+
annotation.classes.push('warning');
|
|
93
|
+
parseResult.push(annotation);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return parseResult;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Shared function for parsing source descriptions.
|
|
101
|
+
* Call with `.call(this, ...)` where `this` has `name` and `parseFn` properties.
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export async function parseSourceDescriptions(api, file, options) {
|
|
105
|
+
const results = [];
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Validate prerequisites for parsing source descriptions.
|
|
109
|
+
* Return warning annotations if validation fails.
|
|
110
|
+
*/
|
|
111
|
+
if (!isArazzoSpecification1Element(api)) {
|
|
112
|
+
const annotation = new AnnotationElement('Cannot parse source descriptions: API is not an Arazzo specification.');
|
|
113
|
+
annotation.classes.push('warning');
|
|
114
|
+
return [new ParseResultElement([annotation])];
|
|
115
|
+
}
|
|
116
|
+
if (!isArrayElement(api.sourceDescriptions)) {
|
|
117
|
+
const annotation = new AnnotationElement('Cannot parse source descriptions: sourceDescriptions field is missing or not an array.');
|
|
118
|
+
annotation.classes.push('warning');
|
|
119
|
+
return [new ParseResultElement([annotation])];
|
|
120
|
+
}
|
|
121
|
+
if (typeof this.parseFn !== 'function') {
|
|
122
|
+
const annotation = new AnnotationElement('Source descriptions found but parseFn is not configured. Skipping source description parsing.');
|
|
123
|
+
annotation.classes.push('error');
|
|
124
|
+
return [new ParseResultElement([annotation])];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// user config: parser-specific options take precedence over global parserOpts
|
|
128
|
+
const maxDepth = options?.parse?.parserOpts?.[this.name]?.sourceDescriptionsMaxDepth ?? options?.parse?.parserOpts?.sourceDescriptionsMaxDepth ?? +Infinity;
|
|
129
|
+
|
|
130
|
+
// recursion state comes from shared key (works across JSON/YAML)
|
|
131
|
+
const sharedOpts = options?.parse?.parserOpts?.[ARAZZO_RECURSION_KEY] ?? {};
|
|
132
|
+
const currentDepth = sharedOpts.sourceDescriptionsDepth ?? 0;
|
|
133
|
+
const visitedUrls = sharedOpts.sourceDescriptionsVisitedUrls ?? new Set();
|
|
134
|
+
|
|
135
|
+
// add current file to visited URLs to prevent cycles
|
|
136
|
+
visitedUrls.add(file.uri);
|
|
137
|
+
if (currentDepth >= maxDepth) {
|
|
138
|
+
const annotation = new AnnotationElement(`Maximum parse depth of ${maxDepth} has been exceeded by file "${file.uri}"`);
|
|
139
|
+
annotation.classes.push('error');
|
|
140
|
+
const parseResult = new ParseResultElement([annotation]);
|
|
141
|
+
parseResult.classes.push('source-description');
|
|
142
|
+
return [parseResult];
|
|
143
|
+
}
|
|
144
|
+
const ctx = {
|
|
145
|
+
parseFn: this.parseFn,
|
|
146
|
+
baseURI: file.uri,
|
|
147
|
+
options,
|
|
148
|
+
currentDepth,
|
|
149
|
+
visitedUrls
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// determine which source descriptions to parse
|
|
153
|
+
const sourceDescriptionsOption = options?.parse?.parserOpts?.[this.name]?.sourceDescriptions ?? options?.parse?.parserOpts?.sourceDescriptions;
|
|
154
|
+
|
|
155
|
+
// handle false or other falsy values - no source descriptions should be parsed
|
|
156
|
+
if (!sourceDescriptionsOption) {
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
159
|
+
const sourceDescriptions = Array.isArray(sourceDescriptionsOption) ? api.sourceDescriptions.filter(sd => {
|
|
160
|
+
if (!isSourceDescriptionElement(sd)) return false;
|
|
161
|
+
const name = toValue(sd.name);
|
|
162
|
+
return typeof name === 'string' && sourceDescriptionsOption.includes(name);
|
|
163
|
+
}) : api.sourceDescriptions;
|
|
164
|
+
|
|
165
|
+
// process sequentially to ensure proper cycle detection with shared visitedUrls
|
|
166
|
+
for (const sourceDescription of sourceDescriptions) {
|
|
167
|
+
const sourceDescriptionParseResult = await parseSourceDescription(sourceDescription, ctx);
|
|
168
|
+
results.push(sourceDescriptionParseResult);
|
|
169
|
+
}
|
|
170
|
+
return results;
|
|
171
|
+
}
|
|
@@ -7,6 +7,7 @@ var _ramda = require("ramda");
|
|
|
7
7
|
var _apidomParserAdapterArazzoYaml = require("@speclynx/apidom-parser-adapter-arazzo-yaml-1");
|
|
8
8
|
var _ParserError = _interopRequireDefault(require("../../../errors/ParserError.cjs"));
|
|
9
9
|
var _Parser = _interopRequireDefault(require("../Parser.cjs"));
|
|
10
|
+
var _sourceDescription = require("../arazzo-json-1/source-description.cjs");
|
|
10
11
|
/**
|
|
11
12
|
* @public
|
|
12
13
|
*/
|
|
@@ -16,8 +17,10 @@ var _Parser = _interopRequireDefault(require("../Parser.cjs"));
|
|
|
16
17
|
*/
|
|
17
18
|
class ArazzoYAML1Parser extends _Parser.default {
|
|
18
19
|
refractorOpts;
|
|
20
|
+
parseFn;
|
|
19
21
|
constructor(options) {
|
|
20
22
|
const {
|
|
23
|
+
parseFn,
|
|
21
24
|
fileExtensions = [],
|
|
22
25
|
mediaTypes = _apidomParserAdapterArazzoYaml.mediaTypes,
|
|
23
26
|
...rest
|
|
@@ -28,6 +31,7 @@ class ArazzoYAML1Parser extends _Parser.default {
|
|
|
28
31
|
fileExtensions,
|
|
29
32
|
mediaTypes
|
|
30
33
|
});
|
|
34
|
+
this.parseFn = parseFn;
|
|
31
35
|
}
|
|
32
36
|
async canParse(file) {
|
|
33
37
|
const hasSupportedFileExtension = this.fileExtensions.length === 0 ? true : this.fileExtensions.includes(file.extension);
|
|
@@ -39,11 +43,17 @@ class ArazzoYAML1Parser extends _Parser.default {
|
|
|
39
43
|
}
|
|
40
44
|
return false;
|
|
41
45
|
}
|
|
42
|
-
async parse(file) {
|
|
46
|
+
async parse(file, options) {
|
|
43
47
|
const source = file.toString();
|
|
44
48
|
try {
|
|
45
49
|
const parserOpts = (0, _ramda.pick)(['sourceMap', 'strict', 'refractorOpts'], this);
|
|
46
|
-
|
|
50
|
+
const parseResult = await (0, _apidomParserAdapterArazzoYaml.parse)(source, parserOpts);
|
|
51
|
+
const shouldParseSourceDescriptions = options?.parse?.parserOpts?.[this.name]?.sourceDescriptions ?? options?.parse?.parserOpts?.sourceDescriptions;
|
|
52
|
+
if (shouldParseSourceDescriptions) {
|
|
53
|
+
const sourceDescriptions = await _sourceDescription.parseSourceDescriptions.call(this, parseResult.api, file, options);
|
|
54
|
+
parseResult.push(...sourceDescriptions);
|
|
55
|
+
}
|
|
56
|
+
return parseResult;
|
|
47
57
|
} catch (error) {
|
|
48
58
|
throw new _ParserError.default(`Error parsing "${file.uri}"`, {
|
|
49
59
|
cause: error
|
|
@@ -2,6 +2,7 @@ import { pick } from 'ramda';
|
|
|
2
2
|
import { parse, mediaTypes as ArazzoYAML1MediaTypes, detect } from '@speclynx/apidom-parser-adapter-arazzo-yaml-1';
|
|
3
3
|
import ParserError from "../../../errors/ParserError.mjs";
|
|
4
4
|
import Parser from "../Parser.mjs";
|
|
5
|
+
import { parseSourceDescriptions } from "../arazzo-json-1/source-description.mjs";
|
|
5
6
|
/**
|
|
6
7
|
* @public
|
|
7
8
|
*/
|
|
@@ -10,8 +11,10 @@ import Parser from "../Parser.mjs";
|
|
|
10
11
|
*/
|
|
11
12
|
class ArazzoYAML1Parser extends Parser {
|
|
12
13
|
refractorOpts;
|
|
14
|
+
parseFn;
|
|
13
15
|
constructor(options) {
|
|
14
16
|
const {
|
|
17
|
+
parseFn,
|
|
15
18
|
fileExtensions = [],
|
|
16
19
|
mediaTypes = ArazzoYAML1MediaTypes,
|
|
17
20
|
...rest
|
|
@@ -22,6 +25,7 @@ class ArazzoYAML1Parser extends Parser {
|
|
|
22
25
|
fileExtensions,
|
|
23
26
|
mediaTypes
|
|
24
27
|
});
|
|
28
|
+
this.parseFn = parseFn;
|
|
25
29
|
}
|
|
26
30
|
async canParse(file) {
|
|
27
31
|
const hasSupportedFileExtension = this.fileExtensions.length === 0 ? true : this.fileExtensions.includes(file.extension);
|
|
@@ -33,11 +37,17 @@ class ArazzoYAML1Parser extends Parser {
|
|
|
33
37
|
}
|
|
34
38
|
return false;
|
|
35
39
|
}
|
|
36
|
-
async parse(file) {
|
|
40
|
+
async parse(file, options) {
|
|
37
41
|
const source = file.toString();
|
|
38
42
|
try {
|
|
39
43
|
const parserOpts = pick(['sourceMap', 'strict', 'refractorOpts'], this);
|
|
40
|
-
|
|
44
|
+
const parseResult = await parse(source, parserOpts);
|
|
45
|
+
const shouldParseSourceDescriptions = options?.parse?.parserOpts?.[this.name]?.sourceDescriptions ?? options?.parse?.parserOpts?.sourceDescriptions;
|
|
46
|
+
if (shouldParseSourceDescriptions) {
|
|
47
|
+
const sourceDescriptions = await parseSourceDescriptions.call(this, parseResult.api, file, options);
|
|
48
|
+
parseResult.push(...sourceDescriptions);
|
|
49
|
+
}
|
|
50
|
+
return parseResult;
|
|
41
51
|
} catch (error) {
|
|
42
52
|
throw new ParserError(`Error parsing "${file.uri}"`, {
|
|
43
53
|
cause: error
|
package/src/resolve/index.cjs
CHANGED
|
@@ -35,9 +35,9 @@ const resolveApiDOM = async (element, options) => {
|
|
|
35
35
|
});
|
|
36
36
|
const resolveStrategies = await plugins.filter('canResolve', [file, options], options.resolve.strategies);
|
|
37
37
|
|
|
38
|
-
// we couldn't find any
|
|
38
|
+
// we couldn't find any resolve strategy for this File
|
|
39
39
|
if ((0, _ramda.isEmpty)(resolveStrategies)) {
|
|
40
|
-
throw new _UnmatchedResolveStrategyError.default(file.uri);
|
|
40
|
+
throw new _UnmatchedResolveStrategyError.default(`Could not find a resolve strategy that can resolve the file "${file.uri}"`);
|
|
41
41
|
}
|
|
42
42
|
try {
|
|
43
43
|
const {
|
package/src/resolve/index.mjs
CHANGED
|
@@ -29,9 +29,9 @@ export const resolveApiDOM = async (element, options) => {
|
|
|
29
29
|
});
|
|
30
30
|
const resolveStrategies = await plugins.filter('canResolve', [file, options], options.resolve.strategies);
|
|
31
31
|
|
|
32
|
-
// we couldn't find any
|
|
32
|
+
// we couldn't find any resolve strategy for this File
|
|
33
33
|
if (isEmpty(resolveStrategies)) {
|
|
34
|
-
throw new UnmatchedResolveStrategyError(file.uri);
|
|
34
|
+
throw new UnmatchedResolveStrategyError(`Could not find a resolve strategy that can resolve the file "${file.uri}"`);
|
|
35
35
|
}
|
|
36
36
|
try {
|
|
37
37
|
const {
|
|
@@ -31,7 +31,7 @@ class ApiDOMResolveStrategy extends _ResolveStrategy.default {
|
|
|
31
31
|
async resolve(file, options) {
|
|
32
32
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'apidom');
|
|
33
33
|
if (dereferenceStrategy === undefined) {
|
|
34
|
-
throw new _UnmatchedDereferenceStrategyError.default(
|
|
34
|
+
throw new _UnmatchedDereferenceStrategyError.default(`"apidom" resolve strategy requires "apidom" dereference strategy to be configured for file "${file.uri}"`);
|
|
35
35
|
}
|
|
36
36
|
const refSet = new _ReferenceSet.default();
|
|
37
37
|
const mergedOptions = (0, _util.merge)(options, {
|
|
@@ -25,7 +25,7 @@ class ApiDOMResolveStrategy extends ResolveStrategy {
|
|
|
25
25
|
async resolve(file, options) {
|
|
26
26
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'apidom');
|
|
27
27
|
if (dereferenceStrategy === undefined) {
|
|
28
|
-
throw new UnmatchedDereferenceStrategyError(
|
|
28
|
+
throw new UnmatchedDereferenceStrategyError(`"apidom" resolve strategy requires "apidom" dereference strategy to be configured for file "${file.uri}"`);
|
|
29
29
|
}
|
|
30
30
|
const refSet = new ReferenceSet();
|
|
31
31
|
const mergedOptions = mergeOptions(options, {
|
|
@@ -31,7 +31,7 @@ class AsyncAPI2ResolveStrategy extends _ResolveStrategy.default {
|
|
|
31
31
|
async resolve(file, options) {
|
|
32
32
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'asyncapi-2');
|
|
33
33
|
if (dereferenceStrategy === undefined) {
|
|
34
|
-
throw new _UnmatchedDereferenceStrategyError.default(
|
|
34
|
+
throw new _UnmatchedDereferenceStrategyError.default(`"asyncapi-2" resolve strategy requires "asyncapi-2" dereference strategy to be configured for file "${file.uri}"`);
|
|
35
35
|
}
|
|
36
36
|
const refSet = new _ReferenceSet.default();
|
|
37
37
|
const mergedOptions = (0, _util.merge)(options, {
|
|
@@ -25,7 +25,7 @@ class AsyncAPI2ResolveStrategy extends ResolveStrategy {
|
|
|
25
25
|
async resolve(file, options) {
|
|
26
26
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'asyncapi-2');
|
|
27
27
|
if (dereferenceStrategy === undefined) {
|
|
28
|
-
throw new UnmatchedDereferenceStrategyError(
|
|
28
|
+
throw new UnmatchedDereferenceStrategyError(`"asyncapi-2" resolve strategy requires "asyncapi-2" dereference strategy to be configured for file "${file.uri}"`);
|
|
29
29
|
}
|
|
30
30
|
const refSet = new ReferenceSet();
|
|
31
31
|
const mergedOptions = mergeOptions(options, {
|
|
@@ -31,7 +31,7 @@ class OpenAPI2ResolveStrategy extends _ResolveStrategy.default {
|
|
|
31
31
|
async resolve(file, options) {
|
|
32
32
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'openapi-2');
|
|
33
33
|
if (dereferenceStrategy === undefined) {
|
|
34
|
-
throw new _UnmatchedDereferenceStrategyError.default(
|
|
34
|
+
throw new _UnmatchedDereferenceStrategyError.default(`"openapi-2" resolve strategy requires "openapi-2" dereference strategy to be configured for file "${file.uri}"`);
|
|
35
35
|
}
|
|
36
36
|
const refSet = new _ReferenceSet.default();
|
|
37
37
|
const mergedOptions = (0, _util.merge)(options, {
|
|
@@ -25,7 +25,7 @@ class OpenAPI2ResolveStrategy extends ResolveStrategy {
|
|
|
25
25
|
async resolve(file, options) {
|
|
26
26
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'openapi-2');
|
|
27
27
|
if (dereferenceStrategy === undefined) {
|
|
28
|
-
throw new UnmatchedDereferenceStrategyError(
|
|
28
|
+
throw new UnmatchedDereferenceStrategyError(`"openapi-2" resolve strategy requires "openapi-2" dereference strategy to be configured for file "${file.uri}"`);
|
|
29
29
|
}
|
|
30
30
|
const refSet = new ReferenceSet();
|
|
31
31
|
const mergedOptions = mergeOptions(options, {
|
|
@@ -31,7 +31,7 @@ class OpenAPI3_0ResolveStrategy extends _ResolveStrategy.default {
|
|
|
31
31
|
async resolve(file, options) {
|
|
32
32
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'openapi-3-0');
|
|
33
33
|
if (dereferenceStrategy === undefined) {
|
|
34
|
-
throw new _UnmatchedDereferenceStrategyError.default(
|
|
34
|
+
throw new _UnmatchedDereferenceStrategyError.default(`"openapi-3-0" resolve strategy requires "openapi-3-0" dereference strategy to be configured for file "${file.uri}"`);
|
|
35
35
|
}
|
|
36
36
|
const refSet = new _ReferenceSet.default();
|
|
37
37
|
const mergedOptions = (0, _util.merge)(options, {
|
|
@@ -25,7 +25,7 @@ class OpenAPI3_0ResolveStrategy extends ResolveStrategy {
|
|
|
25
25
|
async resolve(file, options) {
|
|
26
26
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'openapi-3-0');
|
|
27
27
|
if (dereferenceStrategy === undefined) {
|
|
28
|
-
throw new UnmatchedDereferenceStrategyError(
|
|
28
|
+
throw new UnmatchedDereferenceStrategyError(`"openapi-3-0" resolve strategy requires "openapi-3-0" dereference strategy to be configured for file "${file.uri}"`);
|
|
29
29
|
}
|
|
30
30
|
const refSet = new ReferenceSet();
|
|
31
31
|
const mergedOptions = mergeOptions(options, {
|
|
@@ -31,7 +31,7 @@ class OpenAPI3_1ResolveStrategy extends _ResolveStrategy.default {
|
|
|
31
31
|
async resolve(file, options) {
|
|
32
32
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'openapi-3-1');
|
|
33
33
|
if (dereferenceStrategy === undefined) {
|
|
34
|
-
throw new _UnmatchedDereferenceStrategyError.default(
|
|
34
|
+
throw new _UnmatchedDereferenceStrategyError.default(`"openapi-3-1" resolve strategy requires "openapi-3-1" dereference strategy to be configured for file "${file.uri}"`);
|
|
35
35
|
}
|
|
36
36
|
const refSet = new _ReferenceSet.default();
|
|
37
37
|
const mergedOptions = (0, _util.merge)(options, {
|
|
@@ -25,7 +25,7 @@ class OpenAPI3_1ResolveStrategy extends ResolveStrategy {
|
|
|
25
25
|
async resolve(file, options) {
|
|
26
26
|
const dereferenceStrategy = options.dereference.strategies.find(strategy => strategy.name === 'openapi-3-1');
|
|
27
27
|
if (dereferenceStrategy === undefined) {
|
|
28
|
-
throw new UnmatchedDereferenceStrategyError(
|
|
28
|
+
throw new UnmatchedDereferenceStrategyError(`"openapi-3-1" resolve strategy requires "openapi-3-1" dereference strategy to be configured for file "${file.uri}"`);
|
|
29
29
|
}
|
|
30
30
|
const refSet = new ReferenceSet();
|
|
31
31
|
const mergedOptions = mergeOptions(options, {
|
package/src/resolve/util.cjs
CHANGED
|
@@ -21,12 +21,12 @@ const readFile = async (file, options) => {
|
|
|
21
21
|
|
|
22
22
|
// we couldn't find any resolver for this File
|
|
23
23
|
if ((0, _ramda.isEmpty)(resolvers)) {
|
|
24
|
-
throw new _UnmatchedResolverError.default(file.uri);
|
|
24
|
+
throw new _UnmatchedResolverError.default(`Could not find a resolver that can read the file "${file.uri}"`);
|
|
25
25
|
}
|
|
26
26
|
try {
|
|
27
27
|
const {
|
|
28
28
|
result
|
|
29
|
-
} = await plugins.run('read', [file], resolvers);
|
|
29
|
+
} = await plugins.run('read', [file, options], resolvers);
|
|
30
30
|
return result;
|
|
31
31
|
} catch (error) {
|
|
32
32
|
throw new _ResolveError.default(`Error while reading file "${file.uri}"`, {
|
package/src/resolve/util.mjs
CHANGED
|
@@ -15,12 +15,12 @@ export const readFile = async (file, options) => {
|
|
|
15
15
|
|
|
16
16
|
// we couldn't find any resolver for this File
|
|
17
17
|
if (isEmpty(resolvers)) {
|
|
18
|
-
throw new UnmatchedResolverError(file.uri);
|
|
18
|
+
throw new UnmatchedResolverError(`Could not find a resolver that can read the file "${file.uri}"`);
|
|
19
19
|
}
|
|
20
20
|
try {
|
|
21
21
|
const {
|
|
22
22
|
result
|
|
23
|
-
} = await plugins.run('read', [file], resolvers);
|
|
23
|
+
} = await plugins.run('read', [file, options], resolvers);
|
|
24
24
|
return result;
|
|
25
25
|
} catch (error) {
|
|
26
26
|
throw new ResolveError(`Error while reading file "${file.uri}"`, {
|
|
@@ -344,8 +344,8 @@ export declare abstract class Parser {
|
|
|
344
344
|
*/
|
|
345
345
|
mediaTypes: string[];
|
|
346
346
|
constructor({ name, allowEmpty, sourceMap, strict, fileExtensions, mediaTypes, }: ParserOptions);
|
|
347
|
-
abstract canParse(file: File_2): boolean | Promise<boolean>;
|
|
348
|
-
abstract parse(file: File_2): ParseResultElement | Promise<ParseResultElement>;
|
|
347
|
+
abstract canParse(file: File_2, options?: ApiDOMReferenceOptions): boolean | Promise<boolean>;
|
|
348
|
+
abstract parse(file: File_2, options?: ApiDOMReferenceOptions): ParseResultElement | Promise<ParseResultElement>;
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
/**
|
|
@@ -457,8 +457,8 @@ export declare class ResolveError extends ApiDOMError {
|
|
|
457
457
|
export declare abstract class Resolver {
|
|
458
458
|
readonly name: string;
|
|
459
459
|
constructor({ name }: ResolverOptions);
|
|
460
|
-
abstract canRead(file: File_2): boolean;
|
|
461
|
-
abstract read(file: File_2): Promise<Buffer>;
|
|
460
|
+
abstract canRead(file: File_2, options?: ApiDOMReferenceOptions): boolean;
|
|
461
|
+
abstract read(file: File_2, options?: ApiDOMReferenceOptions): Promise<Buffer>;
|
|
462
462
|
}
|
|
463
463
|
|
|
464
464
|
/**
|
|
@@ -533,6 +533,12 @@ export declare class UnmatchedBundleStrategyError extends BundleError {
|
|
|
533
533
|
export declare class UnmatchedDereferenceStrategyError extends DereferenceError {
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
+
/**
|
|
537
|
+
* @public
|
|
538
|
+
*/
|
|
539
|
+
export declare class UnmatchedParserError extends ParserError {
|
|
540
|
+
}
|
|
541
|
+
|
|
536
542
|
/**
|
|
537
543
|
* @public
|
|
538
544
|
*/
|
package/types/index.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export { default as ResolverError } from './errors/ResolverError.ts';
|
|
|
45
45
|
export { default as UnmatchedDereferenceStrategyError } from './errors/UnmatchedDereferenceStrategyError.ts';
|
|
46
46
|
export { default as UnmatchedResolveStrategyError } from './errors/UnmatchedResolveStrategyError.ts';
|
|
47
47
|
export { default as UnmatchedResolverError } from './errors/UnmatchedResolverError.ts';
|
|
48
|
+
export { default as UnmatchedParserError } from './errors/UnmatchedParserError.ts';
|
|
48
49
|
/**
|
|
49
50
|
* @public
|
|
50
51
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ParseResultElement } from '@speclynx/apidom-datamodel';
|
|
2
2
|
import File from '../../File.ts';
|
|
3
|
+
import type { ReferenceOptions } from '../../options/index.ts';
|
|
3
4
|
/**
|
|
4
5
|
* @public
|
|
5
6
|
*/
|
|
@@ -37,7 +38,7 @@ declare abstract class Parser {
|
|
|
37
38
|
*/
|
|
38
39
|
mediaTypes: string[];
|
|
39
40
|
constructor({ name, allowEmpty, sourceMap, strict, fileExtensions, mediaTypes, }: ParserOptions);
|
|
40
|
-
abstract canParse(file: File): boolean | Promise<boolean>;
|
|
41
|
-
abstract parse(file: File): ParseResultElement | Promise<ParseResultElement>;
|
|
41
|
+
abstract canParse(file: File, options?: ReferenceOptions): boolean | Promise<boolean>;
|
|
42
|
+
abstract parse(file: File, options?: ReferenceOptions): ParseResultElement | Promise<ParseResultElement>;
|
|
42
43
|
}
|
|
43
44
|
export default Parser;
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { ParseResultElement } from '@speclynx/apidom-datamodel';
|
|
2
2
|
import Parser, { ParserOptions } from '../Parser.ts';
|
|
3
3
|
import File from '../../../File.ts';
|
|
4
|
+
import type { ReferenceOptions } from '../../../options/index.ts';
|
|
5
|
+
import type ParseFn from '../../index.ts';
|
|
4
6
|
export type { default as Parser, ParserOptions } from '../Parser.ts';
|
|
5
7
|
export type { default as File, FileOptions } from '../../../File.ts';
|
|
6
8
|
/**
|
|
7
9
|
* @public
|
|
8
10
|
*/
|
|
9
11
|
export interface ArazzoJSON1ParserOptions extends Omit<ParserOptions, 'name'> {
|
|
12
|
+
readonly parseFn?: typeof ParseFn;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
15
|
* @public
|
|
13
16
|
*/
|
|
14
17
|
declare class ArazzoJSON1Parser extends Parser {
|
|
15
18
|
refractorOpts: object;
|
|
19
|
+
parseFn?: typeof ParseFn;
|
|
16
20
|
constructor(options?: ArazzoJSON1ParserOptions);
|
|
17
21
|
canParse(file: File): Promise<boolean>;
|
|
18
|
-
parse(file: File): Promise<ParseResultElement>;
|
|
22
|
+
parse(file: File, options?: ReferenceOptions): Promise<ParseResultElement>;
|
|
19
23
|
}
|
|
20
24
|
export default ArazzoJSON1Parser;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Element, ParseResultElement } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import File from '../../../File.ts';
|
|
3
|
+
import type { ReferenceOptions } from '../../../options/index.ts';
|
|
4
|
+
import type ParseFn from '../../index.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Shared function for parsing source descriptions.
|
|
7
|
+
* Call with `.call(this, ...)` where `this` has `name` and `parseFn` properties.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseSourceDescriptions(this: {
|
|
11
|
+
name: string;
|
|
12
|
+
parseFn?: typeof ParseFn;
|
|
13
|
+
}, api: Element | undefined, file: File, options: ReferenceOptions): Promise<ParseResultElement[]>;
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { ParseResultElement } from '@speclynx/apidom-datamodel';
|
|
2
2
|
import Parser, { ParserOptions } from '../Parser.ts';
|
|
3
3
|
import File from '../../../File.ts';
|
|
4
|
+
import type { ReferenceOptions } from '../../../options/index.ts';
|
|
5
|
+
import type ParseFn from '../../index.ts';
|
|
4
6
|
export type { default as Parser, ParserOptions } from '../Parser.ts';
|
|
5
7
|
export type { default as File, FileOptions } from '../../../File.ts';
|
|
6
8
|
/**
|
|
7
9
|
* @public
|
|
8
10
|
*/
|
|
9
11
|
export interface ArazzoYAML1ParserOptions extends Omit<ParserOptions, 'name'> {
|
|
12
|
+
readonly parseFn?: typeof ParseFn;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
15
|
* @public
|
|
13
16
|
*/
|
|
14
17
|
declare class ArazzoYAML1Parser extends Parser {
|
|
15
18
|
refractorOpts: object;
|
|
19
|
+
parseFn?: typeof ParseFn;
|
|
16
20
|
constructor(options?: ArazzoYAML1ParserOptions);
|
|
17
21
|
canParse(file: File): Promise<boolean>;
|
|
18
|
-
parse(file: File): Promise<ParseResultElement>;
|
|
22
|
+
parse(file: File, options?: ReferenceOptions): Promise<ParseResultElement>;
|
|
19
23
|
}
|
|
20
24
|
export default ArazzoYAML1Parser;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import File from '../../File.ts';
|
|
2
|
+
import type { ReferenceOptions } from '../../options/index.ts';
|
|
2
3
|
/**
|
|
3
4
|
* @public
|
|
4
5
|
*/
|
|
@@ -11,7 +12,7 @@ export interface ResolverOptions {
|
|
|
11
12
|
declare abstract class Resolver {
|
|
12
13
|
readonly name: string;
|
|
13
14
|
constructor({ name }: ResolverOptions);
|
|
14
|
-
abstract canRead(file: File): boolean;
|
|
15
|
-
abstract read(file: File): Promise<Buffer>;
|
|
15
|
+
abstract canRead(file: File, options?: ReferenceOptions): boolean;
|
|
16
|
+
abstract read(file: File, options?: ReferenceOptions): Promise<Buffer>;
|
|
16
17
|
}
|
|
17
18
|
export default Resolver;
|