@redocly/cli 1.25.15 → 1.26.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 +21 -0
- package/lib/__tests__/commands/join.test.js +24 -1
- package/lib/__tests__/utils.test.js +62 -1
- package/lib/commands/bundle.js +5 -4
- package/lib/commands/eject.js +15 -5
- package/lib/commands/join.js +6 -5
- package/lib/commands/lint.js +3 -2
- package/lib/commands/login.js +11 -6
- package/lib/commands/preview-project/index.js +8 -2
- package/lib/commands/translations.js +12 -2
- package/lib/utils/miscellaneous.js +5 -3
- package/lib/utils/platform.d.ts +16 -0
- package/lib/utils/platform.js +34 -0
- package/package.json +2 -2
- package/src/__tests__/commands/join.test.ts +35 -2
- package/src/__tests__/utils.test.ts +72 -1
- package/src/commands/bundle.ts +7 -6
- package/src/commands/eject.ts +18 -5
- package/src/commands/join.ts +8 -7
- package/src/commands/lint.ts +3 -2
- package/src/commands/login.ts +11 -7
- package/src/commands/preview-project/index.ts +9 -3
- package/src/commands/translations.ts +17 -4
- package/src/utils/miscellaneous.ts +5 -3
- package/src/utils/platform.ts +31 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/commands/eject.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
+
import { getPlatformSpawnArgs, sanitizePath } from '../utils/platform';
|
|
2
3
|
|
|
3
4
|
import type { CommandArgs } from '../wrapper';
|
|
4
5
|
import type { VerifyConfigOptions } from '../types';
|
|
@@ -12,18 +13,30 @@ export type EjectOptions = {
|
|
|
12
13
|
|
|
13
14
|
export const handleEject = async ({ argv }: CommandArgs<EjectOptions>) => {
|
|
14
15
|
process.stdout.write(`\nLaunching eject using NPX.\n\n`);
|
|
15
|
-
const npxExecutableName
|
|
16
|
-
|
|
16
|
+
const { npxExecutableName, sanitize, shell } = getPlatformSpawnArgs();
|
|
17
|
+
|
|
18
|
+
const path = sanitize(argv.path, sanitizePath);
|
|
19
|
+
const projectDir = sanitize(argv['project-dir'], sanitizePath);
|
|
20
|
+
|
|
21
|
+
const child = spawn(
|
|
17
22
|
npxExecutableName,
|
|
18
23
|
[
|
|
19
24
|
'-y',
|
|
20
25
|
'@redocly/realm',
|
|
21
26
|
'eject',
|
|
22
27
|
`${argv.type}`,
|
|
23
|
-
|
|
24
|
-
`-d=${
|
|
28
|
+
path,
|
|
29
|
+
`-d=${projectDir}`,
|
|
25
30
|
argv.force ? `--force=${argv.force}` : '',
|
|
26
31
|
],
|
|
27
|
-
{
|
|
32
|
+
{
|
|
33
|
+
stdio: 'inherit',
|
|
34
|
+
shell,
|
|
35
|
+
}
|
|
28
36
|
);
|
|
37
|
+
|
|
38
|
+
child.on('error', (error) => {
|
|
39
|
+
process.stderr.write(`Eject launch failed: ${error.message}`);
|
|
40
|
+
throw new Error('Eject launch failed.');
|
|
41
|
+
});
|
|
29
42
|
};
|
package/src/commands/join.ts
CHANGED
|
@@ -64,18 +64,12 @@ export async function handleJoin({
|
|
|
64
64
|
}: CommandArgs<JoinOptions>) {
|
|
65
65
|
const startedAt = performance.now();
|
|
66
66
|
|
|
67
|
-
if (argv.apis.length < 2) {
|
|
68
|
-
return exitWithError(`At least 2 apis should be provided.`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const fileExtension = getAndValidateFileExtension(argv.output || argv.apis[0]);
|
|
72
|
-
|
|
73
67
|
const {
|
|
74
68
|
'prefix-components-with-info-prop': prefixComponentsWithInfoProp,
|
|
75
69
|
'prefix-tags-with-filename': prefixTagsWithFilename,
|
|
76
70
|
'prefix-tags-with-info-prop': prefixTagsWithInfoProp,
|
|
77
71
|
'without-x-tag-groups': withoutXTagGroups,
|
|
78
|
-
output
|
|
72
|
+
output,
|
|
79
73
|
} = argv;
|
|
80
74
|
|
|
81
75
|
const usedTagsOptions = [
|
|
@@ -91,6 +85,13 @@ export async function handleJoin({
|
|
|
91
85
|
}
|
|
92
86
|
|
|
93
87
|
const apis = await getFallbackApisOrExit(argv.apis, config);
|
|
88
|
+
if (apis.length < 2) {
|
|
89
|
+
return exitWithError(`At least 2 APIs should be provided.`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const fileExtension = getAndValidateFileExtension(output || apis[0].path);
|
|
93
|
+
const specFilename = output || `openapi.${fileExtension}`;
|
|
94
|
+
|
|
94
95
|
const externalRefResolver = new BaseResolver(config.resolve);
|
|
95
96
|
const documents = await Promise.all(
|
|
96
97
|
apis.map(
|
package/src/commands/lint.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { relative } from 'path';
|
|
1
2
|
import { blue, gray } from 'colorette';
|
|
2
3
|
import { performance } from 'perf_hooks';
|
|
3
4
|
import {
|
|
@@ -74,7 +75,7 @@ export async function handleLint({
|
|
|
74
75
|
)} configuration by default.\n\n`
|
|
75
76
|
);
|
|
76
77
|
}
|
|
77
|
-
process.stderr.write(gray(`validating ${
|
|
78
|
+
process.stderr.write(gray(`validating ${relative(process.cwd(), path)}...\n`));
|
|
78
79
|
const results = await lint({
|
|
79
80
|
ref: path,
|
|
80
81
|
config: resolvedConfig,
|
|
@@ -101,7 +102,7 @@ export async function handleLint({
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
const elapsed = getExecutionTime(startedAt);
|
|
104
|
-
process.stderr.write(gray(`${
|
|
105
|
+
process.stderr.write(gray(`${relative(process.cwd(), path)}: validated in ${elapsed}\n\n`));
|
|
105
106
|
} catch (e) {
|
|
106
107
|
handleError(e, path);
|
|
107
108
|
}
|
package/src/commands/login.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { blue, green, gray } from 'colorette';
|
|
2
2
|
import { RedoclyClient } from '@redocly/openapi-core';
|
|
3
|
-
import { promptUser } from '../utils/miscellaneous';
|
|
3
|
+
import { exitWithError, promptUser } from '../utils/miscellaneous';
|
|
4
4
|
|
|
5
5
|
import type { CommandArgs } from '../wrapper';
|
|
6
6
|
import type { Region } from '@redocly/openapi-core';
|
|
@@ -21,10 +21,14 @@ export type LoginOptions = {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
export async function handleLogin({ argv, config }: CommandArgs<LoginOptions>) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
try {
|
|
25
|
+
const region = argv.region || config.region;
|
|
26
|
+
const client = new RedoclyClient(region);
|
|
27
|
+
const clientToken = await promptClientToken(client.domain);
|
|
28
|
+
process.stdout.write(gray('\n Logging in...\n'));
|
|
29
|
+
await client.login(clientToken, argv.verbose);
|
|
30
|
+
process.stdout.write(green(' Authorization confirmed. ✅\n\n'));
|
|
31
|
+
} catch (err) {
|
|
32
|
+
exitWithError(' ' + err?.message);
|
|
33
|
+
}
|
|
30
34
|
}
|
|
@@ -2,6 +2,7 @@ import path = require('path');
|
|
|
2
2
|
import { existsSync, readFileSync } from 'fs';
|
|
3
3
|
import { spawn } from 'child_process';
|
|
4
4
|
import { PRODUCT_NAMES, PRODUCT_PACKAGES } from './constants';
|
|
5
|
+
import { getPlatformSpawnArgs } from '../../utils/platform';
|
|
5
6
|
|
|
6
7
|
import type { PreviewProjectOptions, Product } from './types';
|
|
7
8
|
import type { CommandArgs } from '../../wrapper';
|
|
@@ -21,17 +22,22 @@ export const previewProject = async ({ argv }: CommandArgs<PreviewProjectOptions
|
|
|
21
22
|
const packageName = PRODUCT_PACKAGES[product];
|
|
22
23
|
|
|
23
24
|
process.stdout.write(`\nLaunching preview of ${productName} ${plan} using NPX.\n\n`);
|
|
25
|
+
const { npxExecutableName, shell } = getPlatformSpawnArgs();
|
|
24
26
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
spawn(
|
|
27
|
+
const child = spawn(
|
|
28
28
|
npxExecutableName,
|
|
29
29
|
['-y', packageName, 'preview', `--plan=${plan}`, `--port=${port || 4000}`],
|
|
30
30
|
{
|
|
31
31
|
stdio: 'inherit',
|
|
32
32
|
cwd: projectDir,
|
|
33
|
+
shell,
|
|
33
34
|
}
|
|
34
35
|
);
|
|
36
|
+
|
|
37
|
+
child.on('error', (error) => {
|
|
38
|
+
process.stderr.write(`Project preview launch failed: ${error.message}`);
|
|
39
|
+
throw new Error(`Project preview launch failed.`);
|
|
40
|
+
});
|
|
35
41
|
};
|
|
36
42
|
|
|
37
43
|
const isValidProduct = (product: string | undefined): product is Product => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
+
import { getPlatformSpawnArgs, sanitizeLocale, sanitizePath } from '../utils/platform';
|
|
2
3
|
|
|
3
4
|
import type { CommandArgs } from '../wrapper';
|
|
4
5
|
import type { VerifyConfigOptions } from '../types';
|
|
@@ -10,10 +11,22 @@ export type TranslationsOptions = {
|
|
|
10
11
|
|
|
11
12
|
export const handleTranslations = async ({ argv }: CommandArgs<TranslationsOptions>) => {
|
|
12
13
|
process.stdout.write(`\nLaunching translate using NPX.\n\n`);
|
|
13
|
-
const npxExecutableName
|
|
14
|
-
|
|
14
|
+
const { npxExecutableName, sanitize, shell } = getPlatformSpawnArgs();
|
|
15
|
+
|
|
16
|
+
const projectDir = sanitize(argv['project-dir'], sanitizePath);
|
|
17
|
+
const locale = sanitize(argv.locale, sanitizeLocale);
|
|
18
|
+
|
|
19
|
+
const child = spawn(
|
|
15
20
|
npxExecutableName,
|
|
16
|
-
['-y', '@redocly/realm', 'translate',
|
|
17
|
-
{
|
|
21
|
+
['-y', '@redocly/realm', 'translate', locale, `-d=${projectDir}`],
|
|
22
|
+
{
|
|
23
|
+
stdio: 'inherit',
|
|
24
|
+
shell,
|
|
25
|
+
}
|
|
18
26
|
);
|
|
27
|
+
|
|
28
|
+
child.on('error', (error) => {
|
|
29
|
+
process.stderr.write(`Translate launch failed: ${error.message}`);
|
|
30
|
+
throw new Error(`Translate launch failed.`);
|
|
31
|
+
});
|
|
19
32
|
};
|
|
@@ -92,9 +92,11 @@ function getAliasOrPath(config: ConfigApis, aliasOrPath: string): Entrypoint {
|
|
|
92
92
|
const aliasApi = config.apis[aliasOrPath];
|
|
93
93
|
return aliasApi
|
|
94
94
|
? {
|
|
95
|
-
path: aliasApi.root
|
|
95
|
+
path: isAbsolute(aliasApi.root)
|
|
96
|
+
? aliasApi.root
|
|
97
|
+
: resolve(getConfigDirectory(config), aliasApi.root),
|
|
96
98
|
alias: aliasOrPath,
|
|
97
|
-
output: aliasApi.output,
|
|
99
|
+
output: aliasApi.output && resolve(getConfigDirectory(config), aliasApi.output),
|
|
98
100
|
}
|
|
99
101
|
: {
|
|
100
102
|
path: aliasOrPath,
|
|
@@ -529,7 +531,7 @@ export function checkIfRulesetExist(rules: typeof StyleguideConfig.prototype.rul
|
|
|
529
531
|
...rules.oas3_1,
|
|
530
532
|
...rules.async2,
|
|
531
533
|
...rules.async3,
|
|
532
|
-
...rules.
|
|
534
|
+
...rules.arazzo1,
|
|
533
535
|
};
|
|
534
536
|
|
|
535
537
|
if (isEmptyObject(ruleset)) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitizes the input path by removing invalid characters.
|
|
3
|
+
*/
|
|
4
|
+
export const sanitizePath = (input: string): string => {
|
|
5
|
+
return input.replace(/[^a-zA-Z0-9 ._\-:\\/@]/g, '');
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sanitizes the input locale (ex. en-US) by removing invalid characters.
|
|
10
|
+
*/
|
|
11
|
+
export const sanitizeLocale = (input: string): string => {
|
|
12
|
+
return input.replace(/[^a-zA-Z0-9@._-]/g, '');
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Retrieves platform-specific arguments and utilities.
|
|
17
|
+
*/
|
|
18
|
+
export function getPlatformSpawnArgs() {
|
|
19
|
+
const isWindowsPlatform = process.platform === 'win32';
|
|
20
|
+
const npxExecutableName = isWindowsPlatform ? 'npx.cmd' : 'npx';
|
|
21
|
+
|
|
22
|
+
const sanitizeIfWindows = (input: string | undefined, sanitizer: (input: string) => string) => {
|
|
23
|
+
if (isWindowsPlatform && input) {
|
|
24
|
+
return sanitizer(input);
|
|
25
|
+
} else {
|
|
26
|
+
return input || '';
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return { npxExecutableName, sanitize: sanitizeIfWindows, shell: isWindowsPlatform };
|
|
31
|
+
}
|