@redocly/cli 1.22.1 → 1.23.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 +19 -0
- package/lib/__tests__/commands/bundle.test.js +146 -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 +15 -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 +10 -1
- package/lib/utils/miscellaneous.js +24 -20
- package/lib/utils/update-version-notifier.js +8 -4
- package/package.json +2 -2
- package/src/__tests__/commands/bundle.test.ts +172 -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 +20 -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 +45 -30
- 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,29 +363,36 @@ export function printConfigLintTotals(totals: Totals, command?: string | number)
|
|
|
356
363
|
}
|
|
357
364
|
}
|
|
358
365
|
|
|
359
|
-
export function getOutputFileName(
|
|
360
|
-
entrypoint
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
ext
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
366
|
+
export function getOutputFileName({
|
|
367
|
+
entrypoint,
|
|
368
|
+
output,
|
|
369
|
+
argvOutput,
|
|
370
|
+
ext,
|
|
371
|
+
entries,
|
|
372
|
+
}: {
|
|
373
|
+
entrypoint: string;
|
|
374
|
+
output?: string;
|
|
375
|
+
argvOutput?: string;
|
|
376
|
+
ext?: BundleOutputFormat;
|
|
377
|
+
entries: number;
|
|
378
|
+
}) {
|
|
379
|
+
let outputFile = output || argvOutput;
|
|
380
|
+
if (!outputFile) {
|
|
381
|
+
return { ext: ext || 'yaml' };
|
|
367
382
|
}
|
|
368
383
|
|
|
369
|
-
|
|
370
|
-
if (entries > 1) {
|
|
384
|
+
if (entries > 1 && argvOutput) {
|
|
371
385
|
ext = ext || (extname(entrypoint).substring(1) as BundleOutputFormat);
|
|
372
|
-
if (!outputExtensions.includes(ext
|
|
386
|
+
if (!outputExtensions.includes(ext)) {
|
|
373
387
|
throw new Error(`Invalid file extension: ${ext}.`);
|
|
374
388
|
}
|
|
375
|
-
outputFile = join(
|
|
389
|
+
outputFile = join(argvOutput, basename(entrypoint, extname(entrypoint))) + '.' + ext;
|
|
376
390
|
} else {
|
|
377
|
-
|
|
378
|
-
ext
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if (!outputExtensions.includes(ext
|
|
391
|
+
ext =
|
|
392
|
+
ext ||
|
|
393
|
+
(extname(outputFile).substring(1) as BundleOutputFormat) ||
|
|
394
|
+
(extname(entrypoint).substring(1) as BundleOutputFormat);
|
|
395
|
+
if (!outputExtensions.includes(ext)) {
|
|
382
396
|
throw new Error(`Invalid file extension: ${ext}.`);
|
|
383
397
|
}
|
|
384
398
|
outputFile = join(dirname(outputFile), basename(outputFile, extname(outputFile))) + '.' + ext;
|
|
@@ -569,6 +583,7 @@ export async function sendTelemetry(
|
|
|
569
583
|
spec_full_version,
|
|
570
584
|
};
|
|
571
585
|
await fetch(`https://api.redocly.com/registry/telemetry/cli`, {
|
|
586
|
+
timeout: DEFAULT_FETCH_TIMEOUT,
|
|
572
587
|
method: 'POST',
|
|
573
588
|
headers: {
|
|
574
589
|
'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 = () => {
|