@redocly/cli 1.27.1 → 1.28.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 +17 -0
- package/README.md +1 -1
- package/lib/__tests__/commands/push-region.test.js +44 -9
- package/lib/__tests__/commands/push.test.js +39 -6
- package/lib/__tests__/fetch-with-timeout.test.js +33 -13
- package/lib/__tests__/wrapper.test.js +9 -1
- package/lib/cms/api/__tests__/api.client.test.js +17 -13
- package/lib/cms/api/api-client.d.ts +2 -1
- package/lib/cms/api/api-client.js +13 -3
- package/lib/commands/push.js +12 -6
- package/lib/commands/split/index.d.ts +1 -1
- package/lib/commands/split/types.d.ts +2 -2
- package/lib/utils/fetch-with-timeout.d.ts +1 -2
- package/lib/utils/fetch-with-timeout.js +5 -7
- package/package.json +4 -5
- package/src/__tests__/commands/push-region.test.ts +54 -10
- package/src/__tests__/commands/push.test.ts +47 -7
- package/src/__tests__/fetch-with-timeout.test.ts +41 -13
- package/src/__tests__/wrapper.test.ts +13 -1
- package/src/cms/api/__tests__/api.client.test.ts +18 -16
- package/src/cms/api/api-client.ts +14 -4
- package/src/commands/join.ts +12 -6
- package/src/commands/push.ts +20 -6
- package/src/commands/split/index.ts +16 -14
- package/src/commands/split/types.ts +3 -26
- package/src/utils/fetch-with-timeout.ts +7 -10
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -4,26 +4,66 @@ import { exitWithError } from '../../utils/miscellaneous';
|
|
|
4
4
|
import { getApiRoot, getDestinationProps, handlePush, transformPush } from '../../commands/push';
|
|
5
5
|
import { ConfigFixture } from '../fixtures/config';
|
|
6
6
|
import { yellow } from 'colorette';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
import { Readable } from 'node:stream';
|
|
8
|
+
|
|
9
|
+
// Mock fs operations
|
|
10
|
+
jest.mock('fs', () => ({
|
|
11
|
+
...jest.requireActual('fs'),
|
|
12
|
+
createReadStream: jest.fn(() => {
|
|
13
|
+
const readable = new Readable();
|
|
14
|
+
readable.push('test data');
|
|
15
|
+
readable.push(null);
|
|
16
|
+
return readable;
|
|
17
|
+
}),
|
|
18
|
+
statSync: jest.fn(() => ({ isDirectory: () => false, size: 10 })),
|
|
19
|
+
readFileSync: jest.fn(() => Buffer.from('test data')),
|
|
20
|
+
existsSync: jest.fn(() => false),
|
|
21
|
+
readdirSync: jest.fn(() => []),
|
|
14
22
|
}));
|
|
23
|
+
|
|
15
24
|
jest.mock('@redocly/openapi-core');
|
|
16
25
|
jest.mock('../../utils/miscellaneous');
|
|
17
26
|
|
|
27
|
+
// Mock fetch
|
|
28
|
+
const mockFetch = jest.fn(() =>
|
|
29
|
+
Promise.resolve({
|
|
30
|
+
ok: true,
|
|
31
|
+
status: 200,
|
|
32
|
+
json: () => Promise.resolve({}),
|
|
33
|
+
headers: new Headers(),
|
|
34
|
+
statusText: 'OK',
|
|
35
|
+
redirected: false,
|
|
36
|
+
type: 'default',
|
|
37
|
+
url: '',
|
|
38
|
+
clone: () => ({} as Response),
|
|
39
|
+
body: null,
|
|
40
|
+
bodyUsed: false,
|
|
41
|
+
arrayBuffer: async () => new ArrayBuffer(0),
|
|
42
|
+
blob: async () => new Blob(),
|
|
43
|
+
formData: async () => new FormData(),
|
|
44
|
+
text: async () => '',
|
|
45
|
+
} as Response)
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const originalFetch = global.fetch;
|
|
49
|
+
|
|
18
50
|
(getMergedConfig as jest.Mock).mockImplementation((config) => config);
|
|
19
51
|
|
|
20
52
|
describe('push', () => {
|
|
21
53
|
const redoclyClient = require('@redocly/openapi-core').__redoclyClient;
|
|
22
54
|
|
|
55
|
+
beforeAll(() => {
|
|
56
|
+
global.fetch = mockFetch;
|
|
57
|
+
});
|
|
58
|
+
|
|
23
59
|
beforeEach(() => {
|
|
24
60
|
jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
25
61
|
});
|
|
26
62
|
|
|
63
|
+
afterAll(() => {
|
|
64
|
+
global.fetch = originalFetch;
|
|
65
|
+
});
|
|
66
|
+
|
|
27
67
|
it('pushes definition', async () => {
|
|
28
68
|
await handlePush({
|
|
29
69
|
argv: {
|
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
import AbortController from 'abort-controller';
|
|
2
2
|
import fetchWithTimeout from '../utils/fetch-with-timeout';
|
|
3
|
-
import nodeFetch from 'node-fetch';
|
|
4
3
|
import { getProxyAgent } from '@redocly/openapi-core';
|
|
5
4
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
6
5
|
|
|
7
|
-
jest.mock('node-fetch');
|
|
8
6
|
jest.mock('@redocly/openapi-core');
|
|
9
7
|
|
|
8
|
+
const signalInstance = new AbortController().signal;
|
|
9
|
+
|
|
10
|
+
const mockFetch = jest.fn(() =>
|
|
11
|
+
Promise.resolve({
|
|
12
|
+
ok: true,
|
|
13
|
+
status: 200,
|
|
14
|
+
json: () => Promise.resolve({}),
|
|
15
|
+
headers: new Headers(),
|
|
16
|
+
statusText: 'OK',
|
|
17
|
+
redirected: false,
|
|
18
|
+
type: 'default',
|
|
19
|
+
url: '',
|
|
20
|
+
clone: () => ({} as Response),
|
|
21
|
+
body: null,
|
|
22
|
+
bodyUsed: false,
|
|
23
|
+
arrayBuffer: async () => new ArrayBuffer(0),
|
|
24
|
+
blob: async () => new Blob(),
|
|
25
|
+
formData: async () => new FormData(),
|
|
26
|
+
text: async () => '',
|
|
27
|
+
signal: signalInstance,
|
|
28
|
+
dispatcher: undefined,
|
|
29
|
+
} as Response)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const originalFetch = global.fetch;
|
|
33
|
+
global.fetch = mockFetch;
|
|
34
|
+
|
|
10
35
|
describe('fetchWithTimeout', () => {
|
|
11
36
|
beforeAll(() => {
|
|
12
37
|
// @ts-ignore
|
|
@@ -18,36 +43,39 @@ describe('fetchWithTimeout', () => {
|
|
|
18
43
|
(getProxyAgent as jest.Mock).mockReturnValueOnce(undefined);
|
|
19
44
|
});
|
|
20
45
|
|
|
21
|
-
|
|
22
|
-
|
|
46
|
+
afterAll(() => {
|
|
47
|
+
global.fetch = originalFetch;
|
|
23
48
|
});
|
|
24
49
|
|
|
25
|
-
it('should call
|
|
50
|
+
it('should call fetch with signal', async () => {
|
|
26
51
|
await fetchWithTimeout('url', { timeout: 1000 });
|
|
27
52
|
|
|
28
53
|
expect(global.setTimeout).toHaveBeenCalledTimes(1);
|
|
29
|
-
expect(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
54
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
55
|
+
'url',
|
|
56
|
+
expect.objectContaining({
|
|
57
|
+
signal: expect.any(AbortSignal),
|
|
58
|
+
dispatcher: undefined,
|
|
59
|
+
})
|
|
60
|
+
);
|
|
33
61
|
expect(global.clearTimeout).toHaveBeenCalledTimes(1);
|
|
34
62
|
});
|
|
35
63
|
|
|
36
|
-
it('should call
|
|
64
|
+
it('should call fetch with proxy agent', async () => {
|
|
37
65
|
(getProxyAgent as jest.Mock).mockRestore();
|
|
38
66
|
const proxyAgent = new HttpsProxyAgent('http://localhost');
|
|
39
67
|
(getProxyAgent as jest.Mock).mockReturnValueOnce(proxyAgent);
|
|
40
68
|
|
|
41
69
|
await fetchWithTimeout('url');
|
|
42
70
|
|
|
43
|
-
expect(
|
|
71
|
+
expect(global.fetch).toHaveBeenCalledWith('url', { dispatcher: proxyAgent });
|
|
44
72
|
});
|
|
45
73
|
|
|
46
|
-
it('should call
|
|
74
|
+
it('should call fetch without signal when timeout is not passed', async () => {
|
|
47
75
|
await fetchWithTimeout('url');
|
|
48
76
|
|
|
49
77
|
expect(global.setTimeout).not.toHaveBeenCalled();
|
|
50
|
-
expect(
|
|
78
|
+
expect(global.fetch).toHaveBeenCalledWith('url', { agent: undefined });
|
|
51
79
|
expect(global.clearTimeout).not.toHaveBeenCalled();
|
|
52
80
|
});
|
|
53
81
|
});
|
|
@@ -6,11 +6,23 @@ import { Arguments } from 'yargs';
|
|
|
6
6
|
import { handlePush, PushOptions } from '../commands/push';
|
|
7
7
|
import { detectSpec } from '@redocly/openapi-core';
|
|
8
8
|
|
|
9
|
-
jest.
|
|
9
|
+
const mockFetch = jest.fn();
|
|
10
|
+
const originalFetch = global.fetch;
|
|
11
|
+
|
|
10
12
|
jest.mock('../utils/miscellaneous', () => ({
|
|
11
13
|
sendTelemetry: jest.fn(),
|
|
12
14
|
loadConfigAndHandleErrors: jest.fn(),
|
|
13
15
|
}));
|
|
16
|
+
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
global.fetch = mockFetch;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterAll(() => {
|
|
22
|
+
jest.resetAllMocks();
|
|
23
|
+
global.fetch = originalFetch;
|
|
24
|
+
});
|
|
25
|
+
|
|
14
26
|
jest.mock('../commands/lint', () => ({
|
|
15
27
|
handleLint: jest.fn().mockImplementation(({ collectSpecData }) => {
|
|
16
28
|
collectSpecData({ openapi: '3.1.0' });
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
import fetch, { Response } from 'node-fetch';
|
|
2
|
-
import * as FormData from 'form-data';
|
|
3
1
|
import { red, yellow } from 'colorette';
|
|
4
2
|
|
|
5
3
|
import { ReuniteApi, PushPayload, ReuniteApiError } from '../api-client';
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
const originalFetch = global.fetch;
|
|
6
|
+
|
|
7
|
+
beforeAll(() => {
|
|
8
|
+
// Reset fetch mock before each test
|
|
9
|
+
global.fetch = jest.fn();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
afterAll(() => {
|
|
13
|
+
// Restore original fetch after each test
|
|
14
|
+
global.fetch = originalFetch;
|
|
15
|
+
});
|
|
10
16
|
|
|
11
17
|
function mockFetchResponse(response: any) {
|
|
12
|
-
(fetch as jest.
|
|
18
|
+
(global.fetch as jest.Mock).mockResolvedValue(response);
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
describe('ApiClient', () => {
|
|
@@ -38,7 +44,7 @@ describe('ApiClient', () => {
|
|
|
38
44
|
|
|
39
45
|
const result = await apiClient.remotes.getDefaultBranch(testOrg, testProject);
|
|
40
46
|
|
|
41
|
-
expect(fetch).toHaveBeenCalledWith(
|
|
47
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
42
48
|
`${testDomain}/api/orgs/${testOrg}/projects/${testProject}/source`,
|
|
43
49
|
{
|
|
44
50
|
method: 'GET',
|
|
@@ -115,7 +121,7 @@ describe('ApiClient', () => {
|
|
|
115
121
|
|
|
116
122
|
const result = await apiClient.remotes.upsert(testOrg, testProject, remotePayload);
|
|
117
123
|
|
|
118
|
-
expect(fetch).toHaveBeenCalledWith(
|
|
124
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
119
125
|
`${testDomain}/api/orgs/${testOrg}/projects/${testProject}/remotes`,
|
|
120
126
|
{
|
|
121
127
|
method: 'POST',
|
|
@@ -213,12 +219,11 @@ describe('ApiClient', () => {
|
|
|
213
219
|
});
|
|
214
220
|
|
|
215
221
|
it('should push to remote', async () => {
|
|
216
|
-
let passedFormData = new FormData();
|
|
222
|
+
let passedFormData: FormData = new FormData();
|
|
217
223
|
|
|
218
224
|
(fetch as jest.MockedFunction<typeof fetch>).mockImplementationOnce(
|
|
219
225
|
async (_: any, options: any): Promise<Response> => {
|
|
220
226
|
passedFormData = options.body as FormData;
|
|
221
|
-
|
|
222
227
|
return {
|
|
223
228
|
ok: true,
|
|
224
229
|
json: jest.fn().mockResolvedValue(responseMock),
|
|
@@ -226,14 +231,14 @@ describe('ApiClient', () => {
|
|
|
226
231
|
}
|
|
227
232
|
);
|
|
228
233
|
|
|
229
|
-
const formData = new FormData();
|
|
234
|
+
const formData = new globalThis.FormData();
|
|
230
235
|
|
|
231
236
|
formData.append('remoteId', testRemoteId);
|
|
232
237
|
formData.append('commit[message]', pushPayload.commit.message);
|
|
233
238
|
formData.append('commit[author][name]', pushPayload.commit.author.name);
|
|
234
239
|
formData.append('commit[author][email]', pushPayload.commit.author.email);
|
|
235
240
|
formData.append('commit[branchName]', pushPayload.commit.branchName);
|
|
236
|
-
formData.append('files[some-file.yaml]', filesMock[0].stream);
|
|
241
|
+
formData.append('files[some-file.yaml]', new Blob([filesMock[0].stream]));
|
|
237
242
|
|
|
238
243
|
const result = await apiClient.remotes.push(testOrg, testProject, pushPayload, filesMock);
|
|
239
244
|
|
|
@@ -247,10 +252,7 @@ describe('ApiClient', () => {
|
|
|
247
252
|
},
|
|
248
253
|
})
|
|
249
254
|
);
|
|
250
|
-
|
|
251
|
-
expect(
|
|
252
|
-
JSON.stringify(passedFormData).replace(new RegExp(passedFormData.getBoundary(), 'g'), '')
|
|
253
|
-
).toEqual(JSON.stringify(formData).replace(new RegExp(formData.getBoundary(), 'g'), ''));
|
|
255
|
+
expect(passedFormData).toEqual(formData);
|
|
254
256
|
expect(result).toEqual(responseMock);
|
|
255
257
|
});
|
|
256
258
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { yellow, red } from 'colorette';
|
|
2
|
-
import * as FormData from 'form-data';
|
|
3
2
|
import fetchWithTimeout, {
|
|
4
3
|
type FetchWithTimeoutOptions,
|
|
5
4
|
DEFAULT_FETCH_TIMEOUT,
|
|
6
5
|
} from '../../utils/fetch-with-timeout';
|
|
7
6
|
|
|
8
|
-
import type { Response } from 'node-fetch';
|
|
9
7
|
import type { ReadStream } from 'fs';
|
|
8
|
+
import type { Readable } from 'node:stream';
|
|
10
9
|
import type {
|
|
11
10
|
ListRemotesResponse,
|
|
12
11
|
ProjectSourceResponse,
|
|
@@ -178,7 +177,7 @@ class RemotesApi {
|
|
|
178
177
|
payload: PushPayload,
|
|
179
178
|
files: { path: string; stream: ReadStream | Buffer }[]
|
|
180
179
|
): Promise<PushResponse> {
|
|
181
|
-
const formData = new FormData();
|
|
180
|
+
const formData = new globalThis.FormData();
|
|
182
181
|
|
|
183
182
|
formData.append('remoteId', payload.remoteId);
|
|
184
183
|
formData.append('commit[message]', payload.commit.message);
|
|
@@ -192,7 +191,10 @@ class RemotesApi {
|
|
|
192
191
|
payload.commit.createdAt && formData.append('commit[createdAt]', payload.commit.createdAt);
|
|
193
192
|
|
|
194
193
|
for (const file of files) {
|
|
195
|
-
|
|
194
|
+
const blob = Buffer.isBuffer(file.stream)
|
|
195
|
+
? new Blob([file.stream])
|
|
196
|
+
: new Blob([await streamToBuffer(file.stream)]);
|
|
197
|
+
formData.append(`files[${file.path}]`, blob, file.path);
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
payload.isMainBranch && formData.append('isMainBranch', 'true');
|
|
@@ -369,3 +371,11 @@ export type PushPayload = {
|
|
|
369
371
|
};
|
|
370
372
|
isMainBranch?: boolean;
|
|
371
373
|
};
|
|
374
|
+
|
|
375
|
+
export async function streamToBuffer(stream: ReadStream | Readable): Promise<Buffer> {
|
|
376
|
+
const chunks: Buffer[] = [];
|
|
377
|
+
for await (const chunk of stream) {
|
|
378
|
+
chunks.push(chunk);
|
|
379
|
+
}
|
|
380
|
+
return Buffer.concat(chunks);
|
|
381
|
+
}
|
package/src/commands/join.ts
CHANGED
|
@@ -23,14 +23,17 @@ import { isObject, isString, keysOf } from '../utils/js-utils';
|
|
|
23
23
|
import { COMPONENTS, OPENAPI3_METHOD } from './split/types';
|
|
24
24
|
import { crawl, startsWithComponents } from './split';
|
|
25
25
|
|
|
26
|
-
import type {
|
|
26
|
+
import type { Document, Referenced } from '@redocly/openapi-core';
|
|
27
27
|
import type { BundleResult } from '@redocly/openapi-core/lib/bundle';
|
|
28
28
|
import type {
|
|
29
|
+
Oas3Definition,
|
|
30
|
+
Oas3_1Definition,
|
|
29
31
|
Oas3Parameter,
|
|
30
32
|
Oas3PathItem,
|
|
31
33
|
Oas3Server,
|
|
32
|
-
|
|
34
|
+
Oas3Tag,
|
|
33
35
|
} from '@redocly/openapi-core/lib/typings/openapi';
|
|
36
|
+
import type { StrictObject } from '@redocly/openapi-core/lib/utils';
|
|
34
37
|
import type { CommandArgs } from '../wrapper';
|
|
35
38
|
import type { VerifyConfigOptions } from '../types';
|
|
36
39
|
|
|
@@ -311,7 +314,7 @@ export async function handleJoin({
|
|
|
311
314
|
}
|
|
312
315
|
}
|
|
313
316
|
|
|
314
|
-
function collectServers(openapi: Oas3Definition) {
|
|
317
|
+
function collectServers(openapi: Oas3Definition | Oas3_1Definition) {
|
|
315
318
|
const { servers } = openapi;
|
|
316
319
|
if (servers) {
|
|
317
320
|
if (!joinedDef.hasOwnProperty('servers')) {
|
|
@@ -325,7 +328,10 @@ export async function handleJoin({
|
|
|
325
328
|
}
|
|
326
329
|
}
|
|
327
330
|
|
|
328
|
-
function collectExternalDocs(
|
|
331
|
+
function collectExternalDocs(
|
|
332
|
+
openapi: Oas3Definition | Oas3_1Definition,
|
|
333
|
+
{ api }: JoinDocumentContext
|
|
334
|
+
) {
|
|
329
335
|
const { externalDocs } = openapi;
|
|
330
336
|
if (externalDocs) {
|
|
331
337
|
if (joinedDef.hasOwnProperty('externalDocs')) {
|
|
@@ -339,7 +345,7 @@ export async function handleJoin({
|
|
|
339
345
|
}
|
|
340
346
|
|
|
341
347
|
function collectPaths(
|
|
342
|
-
openapi: Oas3Definition,
|
|
348
|
+
openapi: Oas3Definition | Oas3_1Definition,
|
|
343
349
|
{
|
|
344
350
|
apiFilename,
|
|
345
351
|
apiTitle,
|
|
@@ -567,7 +573,7 @@ export async function handleJoin({
|
|
|
567
573
|
|
|
568
574
|
function collectWebhooks(
|
|
569
575
|
oasVersion: SpecVersion,
|
|
570
|
-
openapi: Oas3_1Definition
|
|
576
|
+
openapi: StrictObject<Oas3Definition | Oas3_1Definition>,
|
|
571
577
|
{
|
|
572
578
|
apiFilename,
|
|
573
579
|
apiTitle,
|
package/src/commands/push.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import fetch from 'node-fetch';
|
|
4
3
|
import { performance } from 'perf_hooks';
|
|
5
4
|
import { yellow, green, blue, red } from 'colorette';
|
|
6
5
|
import { createHash } from 'crypto';
|
|
@@ -22,7 +21,10 @@ import {
|
|
|
22
21
|
} from '../utils/miscellaneous';
|
|
23
22
|
import { promptClientToken } from './login';
|
|
24
23
|
import { handlePush as handleCMSPush } from '../cms/commands/push';
|
|
24
|
+
import { streamToBuffer } from '../cms/api/api-client';
|
|
25
25
|
|
|
26
|
+
import type { Readable } from 'node:stream';
|
|
27
|
+
import type { Agent } from 'node:http';
|
|
26
28
|
import type { Config, BundleOutputFormat, Region } from '@redocly/openapi-core';
|
|
27
29
|
import type { CommandArgs } from '../wrapper';
|
|
28
30
|
import type { VerifyConfigOptions } from '../types';
|
|
@@ -436,7 +438,7 @@ export function getApiRoot({
|
|
|
436
438
|
return api?.root;
|
|
437
439
|
}
|
|
438
440
|
|
|
439
|
-
function uploadFileToS3(url: string, filePathOrBuffer: string | Buffer) {
|
|
441
|
+
async function uploadFileToS3(url: string, filePathOrBuffer: string | Buffer) {
|
|
440
442
|
const fileSizeInBytes =
|
|
441
443
|
typeof filePathOrBuffer === 'string'
|
|
442
444
|
? fs.statSync(filePathOrBuffer).size
|
|
@@ -445,12 +447,24 @@ function uploadFileToS3(url: string, filePathOrBuffer: string | Buffer) {
|
|
|
445
447
|
const readStream =
|
|
446
448
|
typeof filePathOrBuffer === 'string' ? fs.createReadStream(filePathOrBuffer) : filePathOrBuffer;
|
|
447
449
|
|
|
448
|
-
|
|
450
|
+
type NodeFetchRequestInit = RequestInit & {
|
|
451
|
+
dispatcher?: Agent;
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const requestOptions: NodeFetchRequestInit = {
|
|
449
455
|
method: 'PUT',
|
|
450
456
|
headers: {
|
|
451
457
|
'Content-Length': fileSizeInBytes.toString(),
|
|
452
458
|
},
|
|
453
|
-
body: readStream
|
|
454
|
-
|
|
455
|
-
|
|
459
|
+
body: Buffer.isBuffer(readStream)
|
|
460
|
+
? new Blob([readStream])
|
|
461
|
+
: new Blob([await streamToBuffer(readStream as Readable)]),
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
const proxyAgent = getProxyAgent();
|
|
465
|
+
if (proxyAgent) {
|
|
466
|
+
requestOptions.dispatcher = proxyAgent;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return fetch(url, requestOptions);
|
|
456
470
|
}
|
|
@@ -22,20 +22,18 @@ import {
|
|
|
22
22
|
OPENAPI3_COMPONENT_NAMES,
|
|
23
23
|
} from './types';
|
|
24
24
|
|
|
25
|
-
import type {
|
|
25
|
+
import type { Oas3Definition, Oas3_1Definition, Oas2Definition } from '@redocly/openapi-core';
|
|
26
26
|
import type {
|
|
27
|
-
Definition,
|
|
28
|
-
Oas2Definition,
|
|
29
27
|
Oas3Schema,
|
|
30
|
-
|
|
31
|
-
Oas3_1Definition,
|
|
28
|
+
Oas3_1Schema,
|
|
32
29
|
Oas3Components,
|
|
30
|
+
Oas3_1Components,
|
|
33
31
|
Oas3ComponentName,
|
|
34
|
-
ComponentsFiles,
|
|
35
|
-
RefObject,
|
|
36
32
|
Oas3PathItem,
|
|
33
|
+
OasRef,
|
|
37
34
|
Referenced,
|
|
38
|
-
} from '
|
|
35
|
+
} from '@redocly/openapi-core/lib/typings/openapi';
|
|
36
|
+
import type { ComponentsFiles, Definition, RefObject } from './types';
|
|
39
37
|
import type { CommandArgs } from '../../wrapper';
|
|
40
38
|
import type { VerifyConfigOptions } from '../../types';
|
|
41
39
|
|
|
@@ -239,7 +237,7 @@ function doesFileDiffer(filename: string, componentData: any) {
|
|
|
239
237
|
|
|
240
238
|
function removeEmptyComponents(
|
|
241
239
|
openapi: Oas3Definition | Oas3_1Definition,
|
|
242
|
-
componentType: Oas3ComponentName
|
|
240
|
+
componentType: Oas3ComponentName<Oas3Schema | Oas3_1Schema>
|
|
243
241
|
) {
|
|
244
242
|
if (openapi.components && isEmptyObject(openapi.components[componentType])) {
|
|
245
243
|
delete openapi.components[componentType];
|
|
@@ -264,15 +262,17 @@ function getFileNamePath(componentDirPath: string, componentName: string, ext: s
|
|
|
264
262
|
}
|
|
265
263
|
|
|
266
264
|
function gatherComponentsFiles(
|
|
267
|
-
components: Oas3Components,
|
|
265
|
+
components: Oas3Components | Oas3_1Components,
|
|
268
266
|
componentsFiles: ComponentsFiles,
|
|
269
|
-
componentType: Oas3ComponentName
|
|
267
|
+
componentType: Oas3ComponentName<Oas3Schema | Oas3_1Schema>,
|
|
270
268
|
componentName: string,
|
|
271
269
|
filename: string
|
|
272
270
|
) {
|
|
273
271
|
let inherits: string[] = [];
|
|
274
272
|
if (componentType === OPENAPI3_COMPONENT.Schemas) {
|
|
275
|
-
inherits = (
|
|
273
|
+
inherits = (
|
|
274
|
+
(components?.[componentType]?.[componentName] as Oas3Schema | Oas3_1Schema)?.allOf || []
|
|
275
|
+
)
|
|
276
276
|
.map(({ $ref }) => $ref)
|
|
277
277
|
.filter(isTruthy);
|
|
278
278
|
}
|
|
@@ -347,7 +347,9 @@ function iterateComponents(
|
|
|
347
347
|
componentTypes.forEach(iterateComponentTypes);
|
|
348
348
|
|
|
349
349
|
// eslint-disable-next-line no-inner-declarations
|
|
350
|
-
function iterateAndGatherComponentsFiles(
|
|
350
|
+
function iterateAndGatherComponentsFiles(
|
|
351
|
+
componentType: Oas3ComponentName<Oas3Schema | Oas3_1Schema>
|
|
352
|
+
) {
|
|
351
353
|
const componentDirPath = path.join(componentsDir, componentType);
|
|
352
354
|
for (const componentName of Object.keys(components?.[componentType] || {})) {
|
|
353
355
|
const filename = getFileNamePath(componentDirPath, componentName, ext);
|
|
@@ -356,7 +358,7 @@ function iterateComponents(
|
|
|
356
358
|
}
|
|
357
359
|
|
|
358
360
|
// eslint-disable-next-line no-inner-declarations
|
|
359
|
-
function iterateComponentTypes(componentType: Oas3ComponentName) {
|
|
361
|
+
function iterateComponentTypes(componentType: Oas3ComponentName<Oas3Schema | Oas3_1Schema>) {
|
|
360
362
|
const componentDirPath = path.join(componentsDir, componentType);
|
|
361
363
|
createComponentDir(componentDirPath, componentType);
|
|
362
364
|
for (const componentName of Object.keys(components?.[componentType] || {})) {
|
|
@@ -1,29 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Oas3Definition,
|
|
5
|
-
Oas3_1Definition,
|
|
6
|
-
Oas3Components,
|
|
7
|
-
Oas3PathItem,
|
|
8
|
-
Oas3Paths,
|
|
9
|
-
Oas3ComponentName,
|
|
10
|
-
Oas3_1Webhooks,
|
|
11
|
-
Oas2Definition,
|
|
12
|
-
Referenced,
|
|
13
|
-
} from '@redocly/openapi-core';
|
|
14
|
-
export {
|
|
15
|
-
Oas3_1Definition,
|
|
16
|
-
Oas3Definition,
|
|
17
|
-
Oas2Definition,
|
|
18
|
-
Oas3Components,
|
|
19
|
-
Oas3Paths,
|
|
20
|
-
Oas3PathItem,
|
|
21
|
-
Oas3ComponentName,
|
|
22
|
-
Oas3_1Schema,
|
|
23
|
-
Oas3Schema,
|
|
24
|
-
Oas3_1Webhooks,
|
|
25
|
-
Referenced,
|
|
26
|
-
};
|
|
1
|
+
import type { Oas2Definition } from '@redocly/openapi-core';
|
|
2
|
+
import type { Oas3_1Definition, Oas3Definition } from '@redocly/openapi-core/lib/typings/openapi';
|
|
3
|
+
|
|
27
4
|
export type Definition = Oas3_1Definition | Oas3Definition | Oas2Definition;
|
|
28
5
|
export interface ComponentsFiles {
|
|
29
6
|
[schemas: string]: any;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import nodeFetch, { type RequestInit } from 'node-fetch';
|
|
2
|
-
import AbortController from 'abort-controller';
|
|
3
1
|
import { getProxyAgent } from '@redocly/openapi-core';
|
|
4
2
|
|
|
5
3
|
export const DEFAULT_FETCH_TIMEOUT = 3000;
|
|
@@ -10,24 +8,23 @@ export type FetchWithTimeoutOptions = RequestInit & {
|
|
|
10
8
|
|
|
11
9
|
export default async (url: string, { timeout, ...options }: FetchWithTimeoutOptions = {}) => {
|
|
12
10
|
if (!timeout) {
|
|
13
|
-
return
|
|
11
|
+
return fetch(url, {
|
|
14
12
|
...options,
|
|
15
|
-
|
|
16
|
-
});
|
|
13
|
+
dispatcher: getProxyAgent(),
|
|
14
|
+
} as RequestInit);
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
const controller = new AbortController();
|
|
17
|
+
const controller = new globalThis.AbortController();
|
|
20
18
|
const timeoutId = setTimeout(() => {
|
|
21
19
|
controller.abort();
|
|
22
20
|
}, timeout);
|
|
23
21
|
|
|
24
|
-
const res = await
|
|
22
|
+
const res = await fetch(url, {
|
|
25
23
|
signal: controller.signal,
|
|
26
24
|
...options,
|
|
27
|
-
|
|
28
|
-
});
|
|
25
|
+
dispatcher: getProxyAgent(),
|
|
26
|
+
} as RequestInit);
|
|
29
27
|
|
|
30
28
|
clearTimeout(timeoutId);
|
|
31
|
-
|
|
32
29
|
return res;
|
|
33
30
|
};
|