@gitbook/react-openapi 0.7.0 → 1.0.0
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 +51 -0
- package/dist/InteractiveSection.d.ts +4 -6
- package/dist/InteractiveSection.jsx +96 -0
- package/dist/Markdown.d.ts +1 -2
- package/dist/Markdown.jsx +5 -0
- package/dist/OpenAPICodeSample.d.ts +2 -4
- package/dist/OpenAPICodeSample.jsx +143 -0
- package/dist/OpenAPIDisclosure.d.ts +12 -0
- package/dist/OpenAPIDisclosure.jsx +32 -0
- package/dist/OpenAPIDisclosureGroup.d.ts +19 -0
- package/dist/OpenAPIDisclosureGroup.jsx +81 -0
- package/dist/OpenAPIOperation.d.ts +2 -4
- package/dist/OpenAPIOperation.jsx +51 -0
- package/dist/OpenAPIOperationContext.d.ts +16 -0
- package/dist/OpenAPIOperationContext.jsx +26 -0
- package/dist/OpenAPIPath.d.ts +8 -0
- package/dist/OpenAPIPath.jsx +54 -0
- package/dist/OpenAPIRequestBody.d.ts +3 -4
- package/dist/OpenAPIRequestBody.jsx +19 -0
- package/dist/OpenAPIResponse.d.ts +4 -4
- package/dist/OpenAPIResponse.jsx +49 -0
- package/dist/OpenAPIResponseExample.d.ts +2 -4
- package/dist/OpenAPIResponseExample.jsx +108 -0
- package/dist/OpenAPIResponses.d.ts +3 -4
- package/dist/OpenAPIResponses.jsx +36 -0
- package/dist/OpenAPISchema.d.ts +11 -8
- package/dist/OpenAPISchema.jsx +295 -0
- package/dist/OpenAPISchemaName.d.ts +12 -0
- package/dist/OpenAPISchemaName.jsx +15 -0
- package/dist/OpenAPISecurities.d.ts +2 -4
- package/dist/OpenAPISecurities.jsx +55 -0
- package/dist/OpenAPIServerURL.d.ts +2 -3
- package/dist/OpenAPIServerURL.jsx +67 -0
- package/dist/OpenAPIServerURLVariable.d.ts +2 -3
- package/dist/OpenAPIServerURLVariable.jsx +8 -0
- package/dist/OpenAPISpec.d.ts +3 -4
- package/dist/OpenAPISpec.jsx +91 -0
- package/dist/OpenAPITabs.d.ts +25 -0
- package/dist/OpenAPITabs.jsx +67 -0
- package/dist/ScalarApiButton.d.ts +5 -2
- package/dist/ScalarApiButton.jsx +51 -0
- package/dist/code-samples.d.ts +4 -0
- package/dist/code-samples.js +103 -38
- package/dist/fetchOpenAPIOperation.d.ts +9 -54
- package/dist/fetchOpenAPIOperation.js +178 -107
- package/dist/generateSchemaExample.d.ts +2 -2
- package/dist/generateSchemaExample.js +28 -100
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/resolveOpenAPIOperation.d.ts +11 -0
- package/dist/resolveOpenAPIOperation.js +194 -0
- package/dist/stringifyOpenAPI.d.ts +4 -0
- package/dist/stringifyOpenAPI.js +6 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +11 -12
- package/dist/utils.d.ts +6 -1
- package/dist/utils.js +15 -2
- package/package.json +12 -11
- package/src/InteractiveSection.tsx +119 -78
- package/src/Markdown.tsx +2 -3
- package/src/OpenAPICodeSample.tsx +35 -21
- package/src/OpenAPIDisclosure.tsx +50 -0
- package/src/OpenAPIDisclosureGroup.tsx +136 -0
- package/src/OpenAPIOperation.tsx +36 -42
- package/src/OpenAPIOperationContext.tsx +45 -0
- package/src/OpenAPIPath.tsx +65 -0
- package/src/OpenAPIRequestBody.tsx +3 -14
- package/src/OpenAPIResponse.tsx +39 -43
- package/src/OpenAPIResponseExample.tsx +89 -31
- package/src/OpenAPIResponses.tsx +51 -15
- package/src/OpenAPISchema.test.ts +1 -1
- package/src/OpenAPISchema.tsx +124 -92
- package/src/OpenAPISchemaName.tsx +27 -0
- package/src/OpenAPISecurities.tsx +45 -24
- package/src/OpenAPIServerURL.tsx +17 -10
- package/src/OpenAPIServerURLVariable.tsx +2 -4
- package/src/OpenAPISpec.tsx +56 -53
- package/src/OpenAPITabs.tsx +113 -0
- package/src/ScalarApiButton.tsx +86 -6
- package/src/code-samples.test.ts +51 -0
- package/src/code-samples.ts +95 -31
- package/src/generateSchemaExample.ts +25 -151
- package/src/index.ts +3 -2
- package/src/resolveOpenAPIOperation.test.ts +177 -0
- package/src/resolveOpenAPIOperation.ts +163 -0
- package/src/stringifyOpenAPI.ts +6 -0
- package/src/types.ts +17 -10
- package/src/utils.ts +17 -2
- package/dist/InteractiveSection.js +0 -47
- package/dist/Markdown.js +0 -6
- package/dist/OpenAPICodeSample.js +0 -110
- package/dist/OpenAPIOperation.js +0 -38
- package/dist/OpenAPIRequestBody.js +0 -18
- package/dist/OpenAPIResponse.js +0 -32
- package/dist/OpenAPIResponseExample.js +0 -54
- package/dist/OpenAPIResponses.js +0 -18
- package/dist/OpenAPISchema.js +0 -235
- package/dist/OpenAPISchema.test.d.ts +0 -1
- package/dist/OpenAPISchema.test.js +0 -91
- package/dist/OpenAPISecurities.js +0 -42
- package/dist/OpenAPIServerURL.js +0 -51
- package/dist/OpenAPIServerURLVariable.js +0 -10
- package/dist/OpenAPISpec.js +0 -70
- package/dist/ScalarApiButton.js +0 -14
- package/dist/fetchOpenAPIOperation.test.d.ts +0 -1
- package/dist/fetchOpenAPIOperation.test.js +0 -152
- package/dist/resolveOpenAPIPath.d.ts +0 -7
- package/dist/resolveOpenAPIPath.js +0 -112
- package/dist/resolveOpenAPIPath.test.d.ts +0 -1
- package/dist/resolveOpenAPIPath.test.js +0 -39
- package/src/fetchOpenAPIOperation.test.ts +0 -185
- package/src/fetchOpenAPIOperation.ts +0 -230
- package/src/resolveOpenAPIPath.test.ts +0 -60
- package/src/resolveOpenAPIPath.ts +0 -145
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { toJSON, fromJSON } from 'flatted';
|
|
2
|
-
import { OpenAPIV3 } from 'openapi-types';
|
|
3
|
-
import YAML from 'yaml';
|
|
4
|
-
import swagger2openapi, { ConvertOutputOptions } from 'swagger2openapi';
|
|
5
|
-
|
|
6
|
-
import { resolveOpenAPIPath } from './resolveOpenAPIPath';
|
|
7
|
-
import { OpenAPIFetcher } from './types';
|
|
8
|
-
|
|
9
|
-
export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
|
|
10
|
-
path: string;
|
|
11
|
-
method: string;
|
|
12
|
-
|
|
13
|
-
/** Servers to be used for this operation */
|
|
14
|
-
servers: OpenAPIV3.ServerObject[];
|
|
15
|
-
|
|
16
|
-
/** Spec of the operation */
|
|
17
|
-
operation: OpenAPIV3.OperationObject & OpenAPICustomOperationProperties;
|
|
18
|
-
|
|
19
|
-
/** Securities that should be used for this operation */
|
|
20
|
-
securities: [string, OpenAPIV3.SecuritySchemeObject][];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Custom properties that can be defined at the entire spec level.
|
|
25
|
-
*/
|
|
26
|
-
export interface OpenAPICustomSpecProperties {
|
|
27
|
-
/**
|
|
28
|
-
* If `true`, code samples will not be displayed.
|
|
29
|
-
* This option can be used to hide code samples for the entire spec.
|
|
30
|
-
*/
|
|
31
|
-
'x-codeSamples'?: boolean;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* If `true`, the "Try it" button will not be displayed.
|
|
35
|
-
* This option can be used to hide code samples for the entire spec.
|
|
36
|
-
*/
|
|
37
|
-
'x-hideTryItPanel'?: boolean;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Custom properties that can be defined at the operation level.
|
|
42
|
-
* These properties are not part of the OpenAPI spec.
|
|
43
|
-
*/
|
|
44
|
-
export interface OpenAPICustomOperationProperties {
|
|
45
|
-
'x-code-samples'?: OpenAPICustomCodeSample[];
|
|
46
|
-
'x-codeSamples'?: OpenAPICustomCodeSample[] | false;
|
|
47
|
-
'x-custom-examples'?: OpenAPICustomCodeSample[];
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* If `true`, the "Try it" button will not be displayed.
|
|
51
|
-
* https://redocly.com/docs/api-reference-docs/specification-extensions/x-hidetryitpanel/
|
|
52
|
-
*/
|
|
53
|
-
'x-hideTryItPanel'?: boolean;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Custom code samples that can be defined at the operation level.
|
|
58
|
-
* It follows the spec defined by Redocly.
|
|
59
|
-
* https://redocly.com/docs/api-reference-docs/specification-extensions/x-code-samples/
|
|
60
|
-
*/
|
|
61
|
-
export interface OpenAPICustomCodeSample {
|
|
62
|
-
lang: string;
|
|
63
|
-
label: string;
|
|
64
|
-
source: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export { toJSON, fromJSON };
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Resolve an OpenAPI operation in a file and compile it to a more usable format.
|
|
71
|
-
*/
|
|
72
|
-
export async function fetchOpenAPIOperation(
|
|
73
|
-
input: {
|
|
74
|
-
url: string;
|
|
75
|
-
path: string;
|
|
76
|
-
method: string;
|
|
77
|
-
},
|
|
78
|
-
rawFetcher: OpenAPIFetcher,
|
|
79
|
-
): Promise<OpenAPIOperationData | null> {
|
|
80
|
-
const fetcher = cacheFetcher(rawFetcher);
|
|
81
|
-
|
|
82
|
-
let operation = await resolveOpenAPIPath<OpenAPIV3.OperationObject>(
|
|
83
|
-
input.url,
|
|
84
|
-
['paths', input.path, input.method],
|
|
85
|
-
fetcher,
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
if (!operation) {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const specData = await fetcher.fetch(input.url);
|
|
93
|
-
|
|
94
|
-
// Resolve common parameters
|
|
95
|
-
const commonParameters = await resolveOpenAPIPath<OpenAPIV3.ParameterObject[]>(
|
|
96
|
-
input.url,
|
|
97
|
-
['paths', input.path, 'parameters'],
|
|
98
|
-
fetcher,
|
|
99
|
-
);
|
|
100
|
-
if (commonParameters) {
|
|
101
|
-
operation = {
|
|
102
|
-
...operation,
|
|
103
|
-
parameters: [...commonParameters, ...(operation.parameters ?? [])],
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Resolve servers
|
|
108
|
-
const servers = await resolveOpenAPIPath<OpenAPIV3.ServerObject[]>(
|
|
109
|
-
input.url,
|
|
110
|
-
['servers'],
|
|
111
|
-
fetcher,
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
// Resolve securities
|
|
115
|
-
const securities: OpenAPIOperationData['securities'] = [];
|
|
116
|
-
for (const security of operation.security ?? []) {
|
|
117
|
-
const securityKey = Object.keys(security)[0];
|
|
118
|
-
|
|
119
|
-
const securityScheme = await resolveOpenAPIPath<OpenAPIV3.SecuritySchemeObject>(
|
|
120
|
-
input.url,
|
|
121
|
-
['components', 'securitySchemes', securityKey],
|
|
122
|
-
fetcher,
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
if (securityScheme) {
|
|
126
|
-
securities.push([securityKey, securityScheme]);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
servers: servers ?? [],
|
|
132
|
-
operation,
|
|
133
|
-
method: input.method,
|
|
134
|
-
path: input.path,
|
|
135
|
-
securities,
|
|
136
|
-
'x-codeSamples':
|
|
137
|
-
typeof specData['x-codeSamples'] === 'boolean' ? specData['x-codeSamples'] : undefined,
|
|
138
|
-
'x-hideTryItPanel':
|
|
139
|
-
typeof specData['x-hideTryItPanel'] === 'boolean'
|
|
140
|
-
? specData['x-hideTryItPanel']
|
|
141
|
-
: undefined,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function cacheFetcher(fetcher: OpenAPIFetcher): OpenAPIFetcher {
|
|
146
|
-
const cache = new Map<string, Promise<any>>();
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
async fetch(url) {
|
|
150
|
-
if (cache.has(url)) {
|
|
151
|
-
return cache.get(url);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const promise = fetcher.fetch(url);
|
|
155
|
-
cache.set(url, promise);
|
|
156
|
-
return promise;
|
|
157
|
-
},
|
|
158
|
-
parseMarkdown: fetcher.parseMarkdown,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Parse a raw string into an OpenAPI document.
|
|
164
|
-
* It will also convert Swagger 2.0 to OpenAPI 3.0.
|
|
165
|
-
* It can throw an `OpenAPIFetchError` if the document is invalid.
|
|
166
|
-
*/
|
|
167
|
-
export async function parseOpenAPIV3(url: string, text: string): Promise<OpenAPIV3.Document> {
|
|
168
|
-
// Parse the JSON or YAML
|
|
169
|
-
let data: unknown;
|
|
170
|
-
|
|
171
|
-
// Try with JSON
|
|
172
|
-
try {
|
|
173
|
-
data = JSON.parse(text);
|
|
174
|
-
} catch (jsonError) {
|
|
175
|
-
try {
|
|
176
|
-
// Try with YAML
|
|
177
|
-
data = YAML.parse(text);
|
|
178
|
-
} catch (yamlError) {
|
|
179
|
-
if (yamlError instanceof Error && yamlError.name.startsWith('YAML')) {
|
|
180
|
-
throw new OpenAPIFetchError('Failed to parse YAML: ' + yamlError.message, url);
|
|
181
|
-
} else {
|
|
182
|
-
throw yamlError;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Convert Swagger 2.0 to OpenAPI 3.0
|
|
188
|
-
// @ts-ignore
|
|
189
|
-
if (data && data.swagger) {
|
|
190
|
-
try {
|
|
191
|
-
// Convert Swagger 2.0 to OpenAPI 3.0
|
|
192
|
-
// @ts-ignore
|
|
193
|
-
const result = (await swagger2openapi.convertObj(data, {
|
|
194
|
-
resolve: false,
|
|
195
|
-
resolveInternal: false,
|
|
196
|
-
laxDefaults: true,
|
|
197
|
-
laxurls: true,
|
|
198
|
-
lint: false,
|
|
199
|
-
prevalidate: false,
|
|
200
|
-
anchors: true,
|
|
201
|
-
patch: true,
|
|
202
|
-
})) as ConvertOutputOptions;
|
|
203
|
-
|
|
204
|
-
data = result.openapi;
|
|
205
|
-
} catch (error) {
|
|
206
|
-
if ((error as Error).name === 'S2OError') {
|
|
207
|
-
throw new OpenAPIFetchError(
|
|
208
|
-
'Failed to convert Swagger 2.0 to OpenAPI 3.0: ' + (error as Error).message,
|
|
209
|
-
url,
|
|
210
|
-
);
|
|
211
|
-
} else {
|
|
212
|
-
throw error;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// @ts-ignore
|
|
218
|
-
return data;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export class OpenAPIFetchError extends Error {
|
|
222
|
-
public name = 'OpenAPIFetchError';
|
|
223
|
-
|
|
224
|
-
constructor(
|
|
225
|
-
message: string,
|
|
226
|
-
public readonly url: string,
|
|
227
|
-
) {
|
|
228
|
-
super(message);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { it, expect } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
import { resolveOpenAPIPath } from './resolveOpenAPIPath';
|
|
4
|
-
import { OpenAPIFetcher } from './types';
|
|
5
|
-
|
|
6
|
-
const createFetcherForSchema = (schema: any): OpenAPIFetcher => {
|
|
7
|
-
return {
|
|
8
|
-
fetch: async (url) => {
|
|
9
|
-
return schema;
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
it('should resolve a simple path through objects', async () => {
|
|
15
|
-
const resolved = await resolveOpenAPIPath(
|
|
16
|
-
'https://test.com',
|
|
17
|
-
['a', 'b', 'c'],
|
|
18
|
-
createFetcherForSchema({
|
|
19
|
-
a: {
|
|
20
|
-
b: {
|
|
21
|
-
c: 'hello',
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
}),
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
expect(resolved).toBe('hello');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should return undefined if the last part of the path does not exists', async () => {
|
|
31
|
-
const resolved = await resolveOpenAPIPath(
|
|
32
|
-
'https://test.com',
|
|
33
|
-
['a', 'b', 'c'],
|
|
34
|
-
createFetcherForSchema({
|
|
35
|
-
a: {
|
|
36
|
-
b: {
|
|
37
|
-
d: 'hello',
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
}),
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
expect(resolved).toBe(undefined);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should return undefined if a middle part of the path does not exists', async () => {
|
|
47
|
-
const resolved = await resolveOpenAPIPath(
|
|
48
|
-
'https://test.com',
|
|
49
|
-
['a', 'x', 'c'],
|
|
50
|
-
createFetcherForSchema({
|
|
51
|
-
a: {
|
|
52
|
-
b: {
|
|
53
|
-
c: 'hello',
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
}),
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
expect(resolved).toBe(undefined);
|
|
60
|
-
});
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { OpenAPIFetcher } from './types';
|
|
2
|
-
|
|
3
|
-
const SYMBOL_MARKDOWN_PARSED = '__$markdownParsed';
|
|
4
|
-
export const SYMBOL_REF_RESOLVED = '__$refResolved';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Resolve a path in a OpenAPI file.
|
|
8
|
-
* It resolves any reference needed to resolve the path, ignoring other references outside the path.
|
|
9
|
-
*/
|
|
10
|
-
export async function resolveOpenAPIPath<T>(
|
|
11
|
-
url: string,
|
|
12
|
-
dataPath: string[],
|
|
13
|
-
fetcher: OpenAPIFetcher,
|
|
14
|
-
): Promise<T | undefined> {
|
|
15
|
-
const data = await fetcher.fetch(url);
|
|
16
|
-
let value: unknown = data;
|
|
17
|
-
|
|
18
|
-
if (!value) {
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const lastKey = dataPath[dataPath.length - 1];
|
|
23
|
-
dataPath = dataPath.slice(0, -1);
|
|
24
|
-
|
|
25
|
-
for (const part of dataPath) {
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
if (isRef(value[part])) {
|
|
28
|
-
await transformAll(url, value, part, fetcher);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// @ts-ignore
|
|
32
|
-
value = value[part];
|
|
33
|
-
|
|
34
|
-
// If any part along the path is undefined, return undefined.
|
|
35
|
-
if (typeof value !== 'object' || value === null) {
|
|
36
|
-
return undefined;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
await transformAll(url, value, lastKey, fetcher);
|
|
41
|
-
|
|
42
|
-
// @ts-expect-error
|
|
43
|
-
return value[lastKey] as T;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Recursively process a part of the OpenAPI spec to resolve all references.
|
|
48
|
-
*/
|
|
49
|
-
async function transformAll(
|
|
50
|
-
url: string,
|
|
51
|
-
data: any,
|
|
52
|
-
key: string | number,
|
|
53
|
-
fetcher: OpenAPIFetcher,
|
|
54
|
-
): Promise<void> {
|
|
55
|
-
const value = data[key];
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
typeof value === 'string' &&
|
|
59
|
-
key === 'description' &&
|
|
60
|
-
fetcher.parseMarkdown &&
|
|
61
|
-
!data[SYMBOL_MARKDOWN_PARSED]
|
|
62
|
-
) {
|
|
63
|
-
// Parse markdown
|
|
64
|
-
data[SYMBOL_MARKDOWN_PARSED] = true;
|
|
65
|
-
data[key] = await fetcher.parseMarkdown(value);
|
|
66
|
-
} else if (
|
|
67
|
-
typeof value === 'string' ||
|
|
68
|
-
typeof value === 'number' ||
|
|
69
|
-
typeof value === 'boolean' ||
|
|
70
|
-
value === null
|
|
71
|
-
) {
|
|
72
|
-
// Primitives
|
|
73
|
-
} else if (typeof value === 'object' && value !== null && SYMBOL_REF_RESOLVED in value) {
|
|
74
|
-
// Ref was already resolved
|
|
75
|
-
} else if (isRef(value)) {
|
|
76
|
-
const ref = value.$ref;
|
|
77
|
-
|
|
78
|
-
// Delete the ref to avoid infinite loop with circular references
|
|
79
|
-
// @ts-ignore
|
|
80
|
-
delete value.$ref;
|
|
81
|
-
|
|
82
|
-
data[key] = await resolveReference(url, ref, fetcher);
|
|
83
|
-
if (data[key]) {
|
|
84
|
-
data[key][SYMBOL_REF_RESOLVED] = extractRefName(ref);
|
|
85
|
-
}
|
|
86
|
-
} else if (Array.isArray(value)) {
|
|
87
|
-
// Recursively resolve all references in the array
|
|
88
|
-
await Promise.all(value.map((item, index) => transformAll(url, value, index, fetcher)));
|
|
89
|
-
} else if (typeof value === 'object' && value !== null) {
|
|
90
|
-
// Recursively resolve all references in the object
|
|
91
|
-
const keys = Object.keys(value);
|
|
92
|
-
for (const key of keys) {
|
|
93
|
-
await transformAll(url, value, key, fetcher);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async function resolveReference(
|
|
99
|
-
origin: string,
|
|
100
|
-
ref: string,
|
|
101
|
-
fetcher: OpenAPIFetcher,
|
|
102
|
-
): Promise<any> {
|
|
103
|
-
const parsed = parseReference(origin, ref);
|
|
104
|
-
return resolveOpenAPIPath(parsed.url, parsed.dataPath, fetcher);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function parseReference(origin: string, ref: string): { url: string; dataPath: string[] } {
|
|
108
|
-
if (!ref) {
|
|
109
|
-
return {
|
|
110
|
-
url: origin,
|
|
111
|
-
dataPath: [],
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (ref.startsWith('#')) {
|
|
116
|
-
// Local references
|
|
117
|
-
const dataPath = ref.split('/').filter(Boolean).slice(1);
|
|
118
|
-
return {
|
|
119
|
-
url: origin,
|
|
120
|
-
dataPath,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Absolute references
|
|
125
|
-
const url = new URL(ref, origin);
|
|
126
|
-
if (url.hash) {
|
|
127
|
-
const hash = url.hash;
|
|
128
|
-
url.hash = '';
|
|
129
|
-
return parseReference(url.toString(), hash);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
url: url.toString(),
|
|
134
|
-
dataPath: [],
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function extractRefName(ref: string): string {
|
|
139
|
-
const parts = ref.split('/');
|
|
140
|
-
return parts[parts.length - 1];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function isRef(ref: any): ref is { $ref: string } {
|
|
144
|
-
return typeof ref === 'object' && ref !== null && '$ref' in ref && ref.$ref;
|
|
145
|
-
}
|