@redocly/cli 1.22.1 → 1.23.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 +12 -0
- package/lib/__tests__/commands/bundle.test.js +110 -1
- package/lib/__tests__/fetch-with-timeout.test.js +29 -5
- package/lib/__tests__/utils.test.js +54 -32
- package/lib/cms/api/__tests__/api.client.test.js +17 -9
- package/lib/cms/api/api-client.d.ts +26 -7
- package/lib/cms/api/api-client.js +103 -72
- package/lib/cms/commands/__tests__/push-status.test.js +1 -1
- package/lib/cms/commands/__tests__/push.test.js +41 -1
- package/lib/cms/commands/__tests__/utils.test.js +1 -1
- package/lib/cms/commands/push-status.d.ts +1 -1
- package/lib/cms/commands/push-status.js +3 -7
- package/lib/cms/commands/push.js +4 -4
- package/lib/cms/commands/utils.d.ts +3 -0
- package/lib/cms/commands/utils.js +8 -1
- package/lib/commands/bundle.d.ts +1 -1
- package/lib/commands/bundle.js +9 -9
- package/lib/commands/eject.d.ts +1 -1
- package/lib/commands/eject.js +1 -1
- package/lib/commands/preview-project/index.js +1 -1
- package/lib/index.js +1 -2
- package/lib/types.d.ts +1 -0
- package/lib/utils/__mocks__/miscellaneous.d.ts +1 -0
- package/lib/utils/__mocks__/miscellaneous.js +2 -1
- package/lib/utils/fetch-with-timeout.d.ts +6 -1
- package/lib/utils/fetch-with-timeout.js +16 -14
- package/lib/utils/miscellaneous.d.ts +4 -1
- package/lib/utils/miscellaneous.js +24 -29
- package/lib/utils/update-version-notifier.js +8 -4
- package/package.json +2 -2
- package/src/__tests__/commands/bundle.test.ts +131 -4
- package/src/__tests__/fetch-with-timeout.test.ts +36 -6
- package/src/__tests__/utils.test.ts +58 -33
- package/src/cms/api/__tests__/api.client.test.ts +20 -11
- package/src/cms/api/api-client.ts +158 -91
- package/src/cms/commands/__tests__/push-status.test.ts +1 -1
- package/src/cms/commands/__tests__/push.test.ts +49 -2
- package/src/cms/commands/__tests__/utils.test.ts +1 -1
- package/src/cms/commands/push-status.ts +5 -9
- package/src/cms/commands/push.ts +5 -6
- package/src/cms/commands/utils.ts +15 -1
- package/src/commands/bundle.ts +14 -12
- package/src/commands/eject.ts +2 -2
- package/src/commands/preview-project/index.ts +1 -1
- package/src/index.ts +1 -2
- package/src/types.ts +1 -0
- package/src/utils/__mocks__/miscellaneous.ts +1 -0
- package/src/utils/fetch-with-timeout.ts +23 -14
- package/src/utils/miscellaneous.ts +32 -37
- package/src/utils/update-version-notifier.ts +11 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
import nodeFetch from 'node-fetch';
|
|
1
|
+
import nodeFetch, { type RequestInit } from 'node-fetch';
|
|
2
2
|
import AbortController from 'abort-controller';
|
|
3
3
|
import { getProxyAgent } from '@redocly/openapi-core';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
export const DEFAULT_FETCH_TIMEOUT = 3000;
|
|
6
6
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const timeout = setTimeout(() => {
|
|
11
|
-
controller.abort();
|
|
12
|
-
}, TIMEOUT);
|
|
7
|
+
export type FetchWithTimeoutOptions = RequestInit & {
|
|
8
|
+
timeout?: number;
|
|
9
|
+
};
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
export default async (url: string, { timeout, ...options }: FetchWithTimeoutOptions = {}) => {
|
|
12
|
+
if (!timeout) {
|
|
13
|
+
return nodeFetch(url, {
|
|
16
14
|
...options,
|
|
17
15
|
agent: getProxyAgent(),
|
|
18
16
|
});
|
|
19
|
-
clearTimeout(timeout);
|
|
20
|
-
return res;
|
|
21
|
-
} catch (e) {
|
|
22
|
-
return;
|
|
23
17
|
}
|
|
18
|
+
|
|
19
|
+
const controller = new AbortController();
|
|
20
|
+
const timeoutId = setTimeout(() => {
|
|
21
|
+
controller.abort();
|
|
22
|
+
}, timeout);
|
|
23
|
+
|
|
24
|
+
const res = await nodeFetch(url, {
|
|
25
|
+
signal: controller.signal,
|
|
26
|
+
...options,
|
|
27
|
+
agent: getProxyAgent(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
clearTimeout(timeoutId);
|
|
31
|
+
|
|
32
|
+
return res;
|
|
24
33
|
};
|
|
@@ -16,13 +16,19 @@ import {
|
|
|
16
16
|
loadConfig,
|
|
17
17
|
RedoclyClient,
|
|
18
18
|
} from '@redocly/openapi-core';
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
isEmptyObject,
|
|
21
|
+
isNotEmptyArray,
|
|
22
|
+
isNotEmptyObject,
|
|
23
|
+
isPlainObject,
|
|
24
|
+
pluralize,
|
|
25
|
+
} from '@redocly/openapi-core/lib/utils';
|
|
20
26
|
import { ConfigValidationError } from '@redocly/openapi-core/lib/config';
|
|
21
27
|
import { deprecatedRefDocsSchema } from '@redocly/config/lib/reference-docs-config-schema';
|
|
22
28
|
import { outputExtensions } from '../types';
|
|
23
29
|
import { version } from './update-version-notifier';
|
|
24
30
|
import { DESTINATION_REGEX } from '../commands/push';
|
|
25
|
-
import fetch from './fetch-with-timeout';
|
|
31
|
+
import fetch, { DEFAULT_FETCH_TIMEOUT } from './fetch-with-timeout';
|
|
26
32
|
|
|
27
33
|
import type { Arguments } from 'yargs';
|
|
28
34
|
import type {
|
|
@@ -42,8 +48,7 @@ export async function getFallbackApisOrExit(
|
|
|
42
48
|
config: ConfigApis
|
|
43
49
|
): Promise<Entrypoint[]> {
|
|
44
50
|
const { apis } = config;
|
|
45
|
-
const shouldFallbackToAllDefinitions =
|
|
46
|
-
!isNotEmptyArray(argsApis) && apis && Object.keys(apis).length > 0;
|
|
51
|
+
const shouldFallbackToAllDefinitions = !isNotEmptyArray(argsApis) && isNotEmptyObject(apis);
|
|
47
52
|
const res = shouldFallbackToAllDefinitions
|
|
48
53
|
? fallbackToAllDefinitions(apis, config)
|
|
49
54
|
: await expandGlobsInEntrypoints(argsApis!, config);
|
|
@@ -64,10 +69,6 @@ function getConfigDirectory(config: ConfigApis) {
|
|
|
64
69
|
return config.configFile ? dirname(config.configFile) : process.cwd();
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
function isNotEmptyArray<T>(args?: T[]): boolean {
|
|
68
|
-
return Array.isArray(args) && !!args.length;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
72
|
function isApiPathValid(apiPath: string): string | void {
|
|
72
73
|
if (!apiPath.trim()) {
|
|
73
74
|
exitWithError('Path cannot be empty.');
|
|
@@ -80,15 +81,21 @@ function fallbackToAllDefinitions(
|
|
|
80
81
|
apis: Record<string, ResolvedApi>,
|
|
81
82
|
config: ConfigApis
|
|
82
83
|
): Entrypoint[] {
|
|
83
|
-
return Object.entries(apis).map(([alias, { root }]) => ({
|
|
84
|
+
return Object.entries(apis).map(([alias, { root, output }]) => ({
|
|
84
85
|
path: isAbsoluteUrl(root) ? root : resolve(getConfigDirectory(config), root),
|
|
85
86
|
alias,
|
|
87
|
+
output: output && resolve(getConfigDirectory(config), output),
|
|
86
88
|
}));
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
function getAliasOrPath(config: ConfigApis, aliasOrPath: string): Entrypoint {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
const aliasApi = config.apis[aliasOrPath];
|
|
93
|
+
return aliasApi
|
|
94
|
+
? {
|
|
95
|
+
path: aliasApi.root,
|
|
96
|
+
alias: aliasOrPath,
|
|
97
|
+
output: aliasApi.output,
|
|
98
|
+
}
|
|
92
99
|
: {
|
|
93
100
|
path: aliasOrPath,
|
|
94
101
|
// find alias by path, take the first match
|
|
@@ -99,10 +106,10 @@ function getAliasOrPath(config: ConfigApis, aliasOrPath: string): Entrypoint {
|
|
|
99
106
|
};
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
async function expandGlobsInEntrypoints(
|
|
109
|
+
async function expandGlobsInEntrypoints(argApis: string[], config: ConfigApis) {
|
|
103
110
|
return (
|
|
104
111
|
await Promise.all(
|
|
105
|
-
|
|
112
|
+
argApis.map(async (aliasOrPath) => {
|
|
106
113
|
return glob.hasMagic(aliasOrPath) && !isAbsoluteUrl(aliasOrPath)
|
|
107
114
|
? (await promisify(glob)(aliasOrPath)).map((g: string) => getAliasOrPath(config, g))
|
|
108
115
|
: getAliasOrPath(config, aliasOrPath);
|
|
@@ -356,33 +363,20 @@ export function printConfigLintTotals(totals: Totals, command?: string | number)
|
|
|
356
363
|
}
|
|
357
364
|
}
|
|
358
365
|
|
|
359
|
-
export function getOutputFileName(
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
ext?: BundleOutputFormat
|
|
364
|
-
) {
|
|
365
|
-
if (!output) {
|
|
366
|
-
return { outputFile: 'stdout', ext: ext || 'yaml' };
|
|
366
|
+
export function getOutputFileName(entrypoint: string, output?: string, ext?: BundleOutputFormat) {
|
|
367
|
+
let outputFile = output;
|
|
368
|
+
if (!outputFile) {
|
|
369
|
+
return { ext: ext || 'yaml' };
|
|
367
370
|
}
|
|
368
371
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
outputFile = join(output, basename(entrypoint, extname(entrypoint))) + '.' + ext;
|
|
376
|
-
} else {
|
|
377
|
-
if (output) {
|
|
378
|
-
ext = ext || (extname(output).substring(1) as BundleOutputFormat);
|
|
379
|
-
}
|
|
380
|
-
ext = ext || (extname(entrypoint).substring(1) as BundleOutputFormat);
|
|
381
|
-
if (!outputExtensions.includes(ext as any)) {
|
|
382
|
-
throw new Error(`Invalid file extension: ${ext}.`);
|
|
383
|
-
}
|
|
384
|
-
outputFile = join(dirname(outputFile), basename(outputFile, extname(outputFile))) + '.' + ext;
|
|
372
|
+
if (outputFile) {
|
|
373
|
+
ext = ext || (extname(outputFile).substring(1) as BundleOutputFormat);
|
|
374
|
+
}
|
|
375
|
+
ext = ext || (extname(entrypoint).substring(1) as BundleOutputFormat);
|
|
376
|
+
if (!outputExtensions.includes(ext)) {
|
|
377
|
+
throw new Error(`Invalid file extension: ${ext}.`);
|
|
385
378
|
}
|
|
379
|
+
outputFile = join(dirname(outputFile), basename(outputFile, extname(outputFile))) + '.' + ext;
|
|
386
380
|
return { outputFile, ext };
|
|
387
381
|
}
|
|
388
382
|
|
|
@@ -569,6 +563,7 @@ export async function sendTelemetry(
|
|
|
569
563
|
spec_full_version,
|
|
570
564
|
};
|
|
571
565
|
await fetch(`https://api.redocly.com/registry/telemetry/cli`, {
|
|
566
|
+
timeout: DEFAULT_FETCH_TIMEOUT,
|
|
572
567
|
method: 'POST',
|
|
573
568
|
headers: {
|
|
574
569
|
'content-type': 'application/json',
|
|
@@ -2,7 +2,7 @@ import { tmpdir } from 'os';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { existsSync, writeFileSync, readFileSync, statSync } from 'fs';
|
|
4
4
|
import { compare } from 'semver';
|
|
5
|
-
import fetch from './fetch-with-timeout';
|
|
5
|
+
import fetch, { DEFAULT_FETCH_TIMEOUT } from './fetch-with-timeout';
|
|
6
6
|
import { cyan, green, yellow } from 'colorette';
|
|
7
7
|
import { cleanColors } from './miscellaneous';
|
|
8
8
|
|
|
@@ -34,10 +34,16 @@ const isNewVersionAvailable = (current: string, latest: string) => compare(curre
|
|
|
34
34
|
|
|
35
35
|
const getLatestVersion = async (packageName: string): Promise<string | undefined> => {
|
|
36
36
|
const latestUrl = `http://registry.npmjs.org/${packageName}/latest`;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch(latestUrl, { timeout: DEFAULT_FETCH_TIMEOUT });
|
|
40
|
+
const info = await response.json();
|
|
41
|
+
|
|
42
|
+
return info.version;
|
|
43
|
+
} catch {
|
|
44
|
+
// Do nothing
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
41
47
|
};
|
|
42
48
|
|
|
43
49
|
export const cacheLatestVersion = () => {
|