@redocly/cli 0.0.0-snapshot.1737554067
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/README.md +114 -0
- package/bin/cli.js +3 -0
- package/lib/__mocks__/@redocly/openapi-core.d.ts +99 -0
- package/lib/__mocks__/@redocly/openapi-core.js +84 -0
- package/lib/__mocks__/documents.d.ts +150 -0
- package/lib/__mocks__/documents.js +123 -0
- package/lib/__mocks__/fs.d.ts +8 -0
- package/lib/__mocks__/fs.js +9 -0
- package/lib/__mocks__/perf_hooks.d.ts +3 -0
- package/lib/__mocks__/perf_hooks.js +6 -0
- package/lib/__mocks__/redoc.d.ts +6 -0
- package/lib/__mocks__/redoc.js +5 -0
- package/lib/__tests__/commands/build-docs.test.d.ts +1 -0
- package/lib/__tests__/commands/build-docs.test.js +54 -0
- package/lib/__tests__/commands/bundle.test.d.ts +1 -0
- package/lib/__tests__/commands/bundle.test.js +235 -0
- package/lib/__tests__/commands/join.test.d.ts +1 -0
- package/lib/__tests__/commands/join.test.js +274 -0
- package/lib/__tests__/commands/lint.test.d.ts +1 -0
- package/lib/__tests__/commands/lint.test.js +149 -0
- package/lib/__tests__/commands/push-region.test.d.ts +1 -0
- package/lib/__tests__/commands/push-region.test.js +55 -0
- package/lib/__tests__/commands/push.test.d.ts +1 -0
- package/lib/__tests__/commands/push.test.js +463 -0
- package/lib/__tests__/fetch-with-timeout.test.d.ts +1 -0
- package/lib/__tests__/fetch-with-timeout.test.js +44 -0
- package/lib/__tests__/fixtures/config.d.ts +21 -0
- package/lib/__tests__/fixtures/config.js +24 -0
- package/lib/__tests__/spinner.test.d.ts +1 -0
- package/lib/__tests__/spinner.test.js +43 -0
- package/lib/__tests__/utils.test.d.ts +1 -0
- package/lib/__tests__/utils.test.js +593 -0
- package/lib/__tests__/wrapper.test.d.ts +1 -0
- package/lib/__tests__/wrapper.test.js +68 -0
- package/lib/cms/api/__tests__/api-keys.test.d.ts +1 -0
- package/lib/cms/api/__tests__/api-keys.test.js +26 -0
- package/lib/cms/api/__tests__/api.client.test.d.ts +1 -0
- package/lib/cms/api/__tests__/api.client.test.js +333 -0
- package/lib/cms/api/__tests__/domains.test.d.ts +1 -0
- package/lib/cms/api/__tests__/domains.test.js +13 -0
- package/lib/cms/api/api-client.d.ts +75 -0
- package/lib/cms/api/api-client.js +225 -0
- package/lib/cms/api/api-keys.d.ts +1 -0
- package/lib/cms/api/api-keys.js +23 -0
- package/lib/cms/api/domains.d.ts +1 -0
- package/lib/cms/api/domains.js +11 -0
- package/lib/cms/api/index.d.ts +3 -0
- package/lib/cms/api/index.js +19 -0
- package/lib/cms/api/types.d.ts +102 -0
- package/lib/cms/api/types.js +2 -0
- package/lib/cms/commands/__tests__/push-status.test.d.ts +1 -0
- package/lib/cms/commands/__tests__/push-status.test.js +563 -0
- package/lib/cms/commands/__tests__/push.test.d.ts +1 -0
- package/lib/cms/commands/__tests__/push.test.js +315 -0
- package/lib/cms/commands/__tests__/utils.test.d.ts +1 -0
- package/lib/cms/commands/__tests__/utils.test.js +51 -0
- package/lib/cms/commands/push-status.d.ts +23 -0
- package/lib/cms/commands/push-status.js +206 -0
- package/lib/cms/commands/push.d.ts +28 -0
- package/lib/cms/commands/push.js +142 -0
- package/lib/cms/commands/utils.d.ts +25 -0
- package/lib/cms/commands/utils.js +46 -0
- package/lib/cms/utils.d.ts +2 -0
- package/lib/cms/utils.js +6 -0
- package/lib/commands/build-docs/index.d.ts +3 -0
- package/lib/commands/build-docs/index.js +39 -0
- package/lib/commands/build-docs/template.hbs +23 -0
- package/lib/commands/build-docs/types.d.ts +23 -0
- package/lib/commands/build-docs/types.js +2 -0
- package/lib/commands/build-docs/utils.d.ts +7 -0
- package/lib/commands/build-docs/utils.js +87 -0
- package/lib/commands/bundle.d.ts +14 -0
- package/lib/commands/bundle.js +91 -0
- package/lib/commands/eject.d.ts +9 -0
- package/lib/commands/eject.js +28 -0
- package/lib/commands/join.d.ts +11 -0
- package/lib/commands/join.js +565 -0
- package/lib/commands/lint.d.ts +13 -0
- package/lib/commands/lint.js +108 -0
- package/lib/commands/login.d.ts +9 -0
- package/lib/commands/login.js +23 -0
- package/lib/commands/preview-docs/index.d.ts +12 -0
- package/lib/commands/preview-docs/index.js +127 -0
- package/lib/commands/preview-docs/preview-server/default.hbs +24 -0
- package/lib/commands/preview-docs/preview-server/hot.js +59 -0
- package/lib/commands/preview-docs/preview-server/oauth2-redirect.html +21 -0
- package/lib/commands/preview-docs/preview-server/preview-server.d.ts +5 -0
- package/lib/commands/preview-docs/preview-server/preview-server.js +113 -0
- package/lib/commands/preview-docs/preview-server/server.d.ts +22 -0
- package/lib/commands/preview-docs/preview-server/server.js +85 -0
- package/lib/commands/preview-project/constants.d.ts +14 -0
- package/lib/commands/preview-project/constants.js +22 -0
- package/lib/commands/preview-project/index.d.ts +3 -0
- package/lib/commands/preview-project/index.js +56 -0
- package/lib/commands/preview-project/types.d.ts +10 -0
- package/lib/commands/preview-project/types.js +2 -0
- package/lib/commands/push.d.ts +44 -0
- package/lib/commands/push.js +295 -0
- package/lib/commands/split/__tests__/index.test.d.ts +1 -0
- package/lib/commands/split/__tests__/index.test.js +91 -0
- package/lib/commands/split/index.d.ts +13 -0
- package/lib/commands/split/index.js +259 -0
- package/lib/commands/split/types.d.ts +36 -0
- package/lib/commands/split/types.js +51 -0
- package/lib/commands/stats.d.ts +8 -0
- package/lib/commands/stats.js +96 -0
- package/lib/commands/translations.d.ts +7 -0
- package/lib/commands/translations.js +20 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +733 -0
- package/lib/types.d.ts +43 -0
- package/lib/types.js +5 -0
- package/lib/utils/__mocks__/miscellaneous.d.ts +43 -0
- package/lib/utils/__mocks__/miscellaneous.js +24 -0
- package/lib/utils/assert-node-version.d.ts +1 -0
- package/lib/utils/assert-node-version.js +16 -0
- package/lib/utils/fetch-with-timeout.d.ts +7 -0
- package/lib/utils/fetch-with-timeout.js +26 -0
- package/lib/utils/getCommandNameFromArgs.d.ts +2 -0
- package/lib/utils/getCommandNameFromArgs.js +6 -0
- package/lib/utils/js-utils.d.ts +5 -0
- package/lib/utils/js-utils.js +28 -0
- package/lib/utils/miscellaneous.d.ts +81 -0
- package/lib/utils/miscellaneous.js +551 -0
- package/lib/utils/platform.d.ts +16 -0
- package/lib/utils/platform.js +34 -0
- package/lib/utils/spinner.d.ts +10 -0
- package/lib/utils/spinner.js +42 -0
- package/lib/utils/update-version-notifier.d.ts +3 -0
- package/lib/utils/update-version-notifier.js +102 -0
- package/lib/wrapper.d.ts +11 -0
- package/lib/wrapper.js +65 -0
- package/package.json +69 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handlePush = handlePush;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const openapi_core_1 = require("@redocly/openapi-core");
|
|
7
|
+
const utils_1 = require("@redocly/openapi-core/lib/utils");
|
|
8
|
+
const colorette_1 = require("colorette");
|
|
9
|
+
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
10
|
+
const push_status_1 = require("./push-status");
|
|
11
|
+
const api_1 = require("../api");
|
|
12
|
+
const utils_2 = require("./utils");
|
|
13
|
+
async function handlePush({ argv, config, version, }) {
|
|
14
|
+
const startedAt = performance.now(); // for printing execution time
|
|
15
|
+
const startTime = Date.now(); // for push-status command
|
|
16
|
+
const { organization, project: projectId, 'mount-path': mountPath, verbose } = argv;
|
|
17
|
+
const orgId = organization || config.organization;
|
|
18
|
+
if (!argv.message || !argv.author || !argv.branch) {
|
|
19
|
+
(0, miscellaneous_1.exitWithError)('Error: message, author and branch are required for push to the Reunite.');
|
|
20
|
+
}
|
|
21
|
+
if (!orgId) {
|
|
22
|
+
return (0, miscellaneous_1.exitWithError)(`No organization provided, please use --organization option or specify the 'organization' field in the config file.`);
|
|
23
|
+
}
|
|
24
|
+
const domain = argv.domain || (0, api_1.getDomain)();
|
|
25
|
+
if (!domain) {
|
|
26
|
+
return (0, miscellaneous_1.exitWithError)(`No domain provided, please use --domain option or environment variable REDOCLY_AUTHORIZATION.`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const { 'commit-sha': commitSha, 'commit-url': commitUrl, 'default-branch': defaultBranch, 'wait-for-deployment': waitForDeployment, 'max-execution-time': maxExecutionTime, } = argv;
|
|
30
|
+
const author = parseCommitAuthor(argv.author);
|
|
31
|
+
const apiKey = (0, api_1.getApiKeys)(domain);
|
|
32
|
+
const filesToUpload = collectFilesToPush(argv.files || argv.apis);
|
|
33
|
+
const commandName = 'push';
|
|
34
|
+
if (!filesToUpload.length) {
|
|
35
|
+
return (0, miscellaneous_1.printExecutionTime)(commandName, startedAt, `No files to upload`);
|
|
36
|
+
}
|
|
37
|
+
const client = new api_1.ReuniteApi({ domain, apiKey, version, command: commandName });
|
|
38
|
+
const projectDefaultBranch = await client.remotes.getDefaultBranch(orgId, projectId);
|
|
39
|
+
const remote = await client.remotes.upsert(orgId, projectId, {
|
|
40
|
+
mountBranchName: projectDefaultBranch,
|
|
41
|
+
mountPath,
|
|
42
|
+
});
|
|
43
|
+
process.stderr.write(`Uploading to ${remote.mountPath} ${filesToUpload.length} ${(0, utils_1.pluralize)('file', filesToUpload.length)}:\n`);
|
|
44
|
+
const { id } = await client.remotes.push(orgId, projectId, {
|
|
45
|
+
remoteId: remote.id,
|
|
46
|
+
commit: {
|
|
47
|
+
message: argv.message,
|
|
48
|
+
branchName: argv.branch,
|
|
49
|
+
sha: commitSha,
|
|
50
|
+
url: commitUrl,
|
|
51
|
+
createdAt: argv['created-at'],
|
|
52
|
+
namespace: argv.namespace,
|
|
53
|
+
repository: argv.repository,
|
|
54
|
+
author,
|
|
55
|
+
},
|
|
56
|
+
isMainBranch: defaultBranch === argv.branch,
|
|
57
|
+
}, filesToUpload.map((f) => ({ path: (0, openapi_core_1.slash)(f.name), stream: fs.createReadStream(f.path) })));
|
|
58
|
+
filesToUpload.forEach((f) => {
|
|
59
|
+
process.stderr.write((0, colorette_1.green)(`✓ ${f.name}\n`));
|
|
60
|
+
});
|
|
61
|
+
process.stdout.write('\n');
|
|
62
|
+
process.stdout.write(`Push ID: ${id}\n`);
|
|
63
|
+
if (waitForDeployment) {
|
|
64
|
+
process.stdout.write('\n');
|
|
65
|
+
await (0, push_status_1.handlePushStatus)({
|
|
66
|
+
argv: {
|
|
67
|
+
organization: orgId,
|
|
68
|
+
project: projectId,
|
|
69
|
+
pushId: id,
|
|
70
|
+
wait: true,
|
|
71
|
+
domain,
|
|
72
|
+
'max-execution-time': maxExecutionTime,
|
|
73
|
+
'start-time': startTime,
|
|
74
|
+
'continue-on-deploy-failures': argv['continue-on-deploy-failures'],
|
|
75
|
+
},
|
|
76
|
+
config,
|
|
77
|
+
version,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
verbose &&
|
|
81
|
+
(0, miscellaneous_1.printExecutionTime)(commandName, startedAt, `${(0, utils_1.pluralize)('file', filesToUpload.length)} uploaded to organization ${orgId}, project ${projectId}. Push ID: ${id}.`);
|
|
82
|
+
client.reportSunsetWarnings();
|
|
83
|
+
return {
|
|
84
|
+
pushId: id,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
(0, utils_2.handleReuniteError)('✗ File upload failed.', err);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function parseCommitAuthor(author) {
|
|
92
|
+
// Author Name <author@email.com>
|
|
93
|
+
const reg = /^.+\s<[^<>]+>$/;
|
|
94
|
+
if (!reg.test(author)) {
|
|
95
|
+
throw new Error('Invalid author format. Use "Author Name <author@email.com>"');
|
|
96
|
+
}
|
|
97
|
+
const [name, email] = author.split('<');
|
|
98
|
+
return {
|
|
99
|
+
name: name.trim(),
|
|
100
|
+
email: email.replace('>', '').trim(),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function collectFilesToPush(files) {
|
|
104
|
+
const collectedFiles = {};
|
|
105
|
+
for (const file of files) {
|
|
106
|
+
if (fs.statSync(file).isDirectory()) {
|
|
107
|
+
const dir = file;
|
|
108
|
+
const fileList = getFilesList(dir, []);
|
|
109
|
+
fileList.forEach((f) => addFile(f, dir));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
addFile(file, path.dirname(file));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function addFile(filePath, fileDir) {
|
|
116
|
+
const fileName = path.relative(fileDir, filePath);
|
|
117
|
+
if (collectedFiles[fileName]) {
|
|
118
|
+
process.stdout.write((0, colorette_1.yellow)(`File ${collectedFiles[fileName]} is overwritten by ${filePath}\n`));
|
|
119
|
+
}
|
|
120
|
+
collectedFiles[fileName] = filePath;
|
|
121
|
+
}
|
|
122
|
+
return Object.entries(collectedFiles).map(([name, filePath]) => getFileEntry(name, filePath));
|
|
123
|
+
}
|
|
124
|
+
function getFileEntry(name, filePath) {
|
|
125
|
+
return {
|
|
126
|
+
name,
|
|
127
|
+
path: path.resolve(filePath),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function getFilesList(dir, files) {
|
|
131
|
+
const filesAndDirs = fs.readdirSync(dir);
|
|
132
|
+
for (const name of filesAndDirs) {
|
|
133
|
+
const currentPath = path.join(dir, name);
|
|
134
|
+
if (fs.statSync(currentPath).isDirectory()) {
|
|
135
|
+
files = getFilesList(currentPath, files);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
files.push(currentPath);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return files;
|
|
142
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DeploymentError } from '../utils';
|
|
2
|
+
import type { ReuniteApiError } from '../api';
|
|
3
|
+
/**
|
|
4
|
+
* This function retries an operation until a condition is met or a timeout is exceeded.
|
|
5
|
+
* If the condition is not met within the timeout, an error is thrown.
|
|
6
|
+
* @operation The operation to retry.
|
|
7
|
+
* @condition The condition to check after each operation result. Return false to continue retrying. Return true to stop retrying.
|
|
8
|
+
* If not provided, the first result will be returned.
|
|
9
|
+
* @param onConditionNotMet Will be called with the last result right after checking condition and before timeout and retrying.
|
|
10
|
+
* @param onRetry Will be called right before retrying operation with the last result before retrying.
|
|
11
|
+
* @param startTime The start time of the operation. Default is the current time.
|
|
12
|
+
* @param retryTimeoutMs The maximum time to retry the operation. Default is 10 minutes.
|
|
13
|
+
* @param retryIntervalMs The interval between retries. Default is 5 seconds.
|
|
14
|
+
*/
|
|
15
|
+
export declare function retryUntilConditionMet<T>({ operation, condition, onConditionNotMet, onRetry, startTime, retryTimeoutMs, // 10 min
|
|
16
|
+
retryIntervalMs, }: {
|
|
17
|
+
operation: () => Promise<T>;
|
|
18
|
+
condition?: ((result: T) => boolean) | null;
|
|
19
|
+
onConditionNotMet?: (lastResult: T) => void;
|
|
20
|
+
onRetry?: (lastResult: T) => void | Promise<void>;
|
|
21
|
+
startTime?: number;
|
|
22
|
+
retryTimeoutMs?: number;
|
|
23
|
+
retryIntervalMs?: number;
|
|
24
|
+
}): Promise<T>;
|
|
25
|
+
export declare function handleReuniteError(message: string, error: ReuniteApiError | DeploymentError | Error): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.retryUntilConditionMet = retryUntilConditionMet;
|
|
4
|
+
exports.handleReuniteError = handleReuniteError;
|
|
5
|
+
const openapi_core_1 = require("@redocly/openapi-core");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
8
|
+
/**
|
|
9
|
+
* This function retries an operation until a condition is met or a timeout is exceeded.
|
|
10
|
+
* If the condition is not met within the timeout, an error is thrown.
|
|
11
|
+
* @operation The operation to retry.
|
|
12
|
+
* @condition The condition to check after each operation result. Return false to continue retrying. Return true to stop retrying.
|
|
13
|
+
* If not provided, the first result will be returned.
|
|
14
|
+
* @param onConditionNotMet Will be called with the last result right after checking condition and before timeout and retrying.
|
|
15
|
+
* @param onRetry Will be called right before retrying operation with the last result before retrying.
|
|
16
|
+
* @param startTime The start time of the operation. Default is the current time.
|
|
17
|
+
* @param retryTimeoutMs The maximum time to retry the operation. Default is 10 minutes.
|
|
18
|
+
* @param retryIntervalMs The interval between retries. Default is 5 seconds.
|
|
19
|
+
*/
|
|
20
|
+
async function retryUntilConditionMet({ operation, condition, onConditionNotMet, onRetry, startTime = Date.now(), retryTimeoutMs = 600000, // 10 min
|
|
21
|
+
retryIntervalMs = 5000, // 5 sec
|
|
22
|
+
}) {
|
|
23
|
+
async function attempt() {
|
|
24
|
+
const result = await operation();
|
|
25
|
+
if (!condition) {
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
if (condition(result)) {
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
else if (Date.now() - startTime > retryTimeoutMs) {
|
|
32
|
+
throw new Error('Timeout exceeded.');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
onConditionNotMet?.(result);
|
|
36
|
+
await (0, openapi_core_1.pause)(retryIntervalMs);
|
|
37
|
+
await onRetry?.(result);
|
|
38
|
+
return attempt();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return attempt();
|
|
42
|
+
}
|
|
43
|
+
function handleReuniteError(message, error) {
|
|
44
|
+
const errorMessage = error instanceof utils_1.DeploymentError ? error.message : `${message} Reason: ${error.message}\n`;
|
|
45
|
+
return (0, miscellaneous_1.exitWithError)(errorMessage);
|
|
46
|
+
}
|
package/lib/cms/utils.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handlerBuildCommand = void 0;
|
|
4
|
+
const redoc_1 = require("redoc");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
8
|
+
const openapi_core_1 = require("@redocly/openapi-core");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
11
|
+
const handlerBuildCommand = async ({ argv, config: configFromFile, collectSpecData, }) => {
|
|
12
|
+
const startedAt = perf_hooks_1.performance.now();
|
|
13
|
+
const config = (0, openapi_core_1.getMergedConfig)(configFromFile, argv.api);
|
|
14
|
+
const apis = await (0, miscellaneous_1.getFallbackApisOrExit)(argv.api ? [argv.api] : [], config);
|
|
15
|
+
const { path: pathToApi } = apis[0];
|
|
16
|
+
const options = {
|
|
17
|
+
output: argv.o,
|
|
18
|
+
title: argv.title,
|
|
19
|
+
disableGoogleFont: argv.disableGoogleFont,
|
|
20
|
+
templateFileName: argv.template,
|
|
21
|
+
templateOptions: argv.templateOptions || {},
|
|
22
|
+
redocOptions: (0, utils_1.getObjectOrJSON)(argv.theme?.openapi, config),
|
|
23
|
+
};
|
|
24
|
+
const redocCurrentVersion = require('../../../package.json').dependencies.redoc.substring(1); // remove ~
|
|
25
|
+
try {
|
|
26
|
+
const elapsed = (0, miscellaneous_1.getExecutionTime)(startedAt);
|
|
27
|
+
const api = await (0, redoc_1.loadAndBundleSpec)((0, openapi_core_1.isAbsoluteUrl)(pathToApi) ? pathToApi : (0, path_1.resolve)(pathToApi));
|
|
28
|
+
collectSpecData?.(api);
|
|
29
|
+
const pageHTML = await (0, utils_1.getPageHTML)(api, pathToApi, { ...options, redocCurrentVersion }, argv.config);
|
|
30
|
+
(0, fs_1.mkdirSync)((0, path_1.dirname)(options.output), { recursive: true });
|
|
31
|
+
(0, fs_1.writeFileSync)(options.output, pageHTML);
|
|
32
|
+
const sizeInKiB = Math.ceil(Buffer.byteLength(pageHTML) / 1024);
|
|
33
|
+
process.stdout.write(`\n🎉 bundled successfully in: ${options.output} (${sizeInKiB} KiB) [⏱ ${elapsed}].\n`);
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
(0, miscellaneous_1.exitWithError)(e);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
exports.handlerBuildCommand = handlerBuildCommand;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf8" />
|
|
6
|
+
<title>{{title}}</title>
|
|
7
|
+
<!-- needed for adaptive design -->
|
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
9
|
+
<style>
|
|
10
|
+
body {
|
|
11
|
+
padding: 0;
|
|
12
|
+
margin: 0;
|
|
13
|
+
}
|
|
14
|
+
</style>
|
|
15
|
+
{{{redocHead}}}
|
|
16
|
+
{{#unless disableGoogleFont}}<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">{{/unless}}
|
|
17
|
+
</head>
|
|
18
|
+
|
|
19
|
+
<body>
|
|
20
|
+
{{{redocHTML}}}
|
|
21
|
+
</body>
|
|
22
|
+
|
|
23
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { VerifyConfigOptions } from '../../types';
|
|
2
|
+
export type BuildDocsOptions = {
|
|
3
|
+
watch?: boolean;
|
|
4
|
+
output?: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
disableGoogleFont?: boolean;
|
|
7
|
+
port?: number;
|
|
8
|
+
templateFileName?: string;
|
|
9
|
+
templateOptions?: any;
|
|
10
|
+
redocOptions?: any;
|
|
11
|
+
redocCurrentVersion: string;
|
|
12
|
+
};
|
|
13
|
+
export type BuildDocsArgv = {
|
|
14
|
+
api: string;
|
|
15
|
+
o: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
disableGoogleFont?: boolean;
|
|
18
|
+
template?: string;
|
|
19
|
+
templateOptions: Record<string, any>;
|
|
20
|
+
theme: {
|
|
21
|
+
openapi: string | Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
} & VerifyConfigOptions;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Config } from '@redocly/openapi-core';
|
|
2
|
+
import type { BuildDocsOptions } from './types';
|
|
3
|
+
export declare function getObjectOrJSON(openapiOptions: string | Record<string, unknown>, config: Config): JSON | Record<string, unknown> | Config;
|
|
4
|
+
export declare function getPageHTML(api: any, pathToApi: string, { title, disableGoogleFont, templateFileName, templateOptions, redocOptions, redocCurrentVersion, }: BuildDocsOptions, configPath?: string): Promise<string>;
|
|
5
|
+
export declare function sanitizeJSONString(str: string): string;
|
|
6
|
+
export declare function escapeClosingScriptTag(str: string): string;
|
|
7
|
+
export declare function escapeUnicode(str: string): string;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getObjectOrJSON = getObjectOrJSON;
|
|
4
|
+
exports.getPageHTML = getPageHTML;
|
|
5
|
+
exports.sanitizeJSONString = sanitizeJSONString;
|
|
6
|
+
exports.escapeClosingScriptTag = escapeClosingScriptTag;
|
|
7
|
+
exports.escapeUnicode = escapeUnicode;
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const redoc_1 = require("redoc");
|
|
10
|
+
const server_1 = require("react-dom/server");
|
|
11
|
+
const styled_components_1 = require("styled-components");
|
|
12
|
+
const handlebars_1 = require("handlebars");
|
|
13
|
+
const path_1 = require("path");
|
|
14
|
+
const fs_1 = require("fs");
|
|
15
|
+
const colorette_1 = require("colorette");
|
|
16
|
+
const openapi_core_1 = require("@redocly/openapi-core");
|
|
17
|
+
const miscellaneous_1 = require("../../utils/miscellaneous");
|
|
18
|
+
function getObjectOrJSON(openapiOptions, config) {
|
|
19
|
+
switch (typeof openapiOptions) {
|
|
20
|
+
case 'object':
|
|
21
|
+
return openapiOptions;
|
|
22
|
+
case 'string':
|
|
23
|
+
try {
|
|
24
|
+
if ((0, fs_1.existsSync)(openapiOptions) && (0, fs_1.lstatSync)(openapiOptions).isFile()) {
|
|
25
|
+
return JSON.parse((0, fs_1.readFileSync)(openapiOptions, 'utf-8'));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return JSON.parse(openapiOptions);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
process.stderr.write((0, colorette_1.red)(`Encountered error:\n\n${openapiOptions}\n\nis neither a file with a valid JSON object neither a stringified JSON object.`));
|
|
33
|
+
(0, miscellaneous_1.exitWithError)(e);
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
default: {
|
|
37
|
+
if (config) {
|
|
38
|
+
process.stdout.write(`Found ${config.configFile} and using theme.openapi options\n`);
|
|
39
|
+
return config.theme.openapi ? config.theme.openapi : {};
|
|
40
|
+
}
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
async function getPageHTML(api, pathToApi, { title, disableGoogleFont, templateFileName, templateOptions, redocOptions = {}, redocCurrentVersion, }, configPath) {
|
|
47
|
+
process.stdout.write('Prerendering docs\n');
|
|
48
|
+
const apiUrl = redocOptions.specUrl || ((0, openapi_core_1.isAbsoluteUrl)(pathToApi) ? pathToApi : undefined);
|
|
49
|
+
const store = await (0, redoc_1.createStore)(api, apiUrl, redocOptions);
|
|
50
|
+
const sheet = new styled_components_1.ServerStyleSheet();
|
|
51
|
+
const html = (0, server_1.renderToString)(sheet.collectStyles((0, react_1.createElement)(redoc_1.Redoc, { store })));
|
|
52
|
+
const state = await store.toJS();
|
|
53
|
+
const css = sheet.getStyleTags();
|
|
54
|
+
templateFileName = templateFileName
|
|
55
|
+
? templateFileName
|
|
56
|
+
: redocOptions?.htmlTemplate
|
|
57
|
+
? (0, path_1.resolve)(configPath ? (0, path_1.dirname)(configPath) : '', redocOptions.htmlTemplate)
|
|
58
|
+
: (0, path_1.join)(__dirname, './template.hbs');
|
|
59
|
+
const template = (0, handlebars_1.compile)((0, fs_1.readFileSync)(templateFileName).toString());
|
|
60
|
+
return template({
|
|
61
|
+
redocHTML: `
|
|
62
|
+
<div id="redoc">${html || ''}</div>
|
|
63
|
+
<script>
|
|
64
|
+
${`const __redoc_state = ${sanitizeJSONString(JSON.stringify(state))};` || ''}
|
|
65
|
+
|
|
66
|
+
var container = document.getElementById('redoc');
|
|
67
|
+
Redoc.${'hydrate(__redoc_state, container)'};
|
|
68
|
+
|
|
69
|
+
</script>`,
|
|
70
|
+
redocHead: `<script src="https://cdn.redocly.com/redoc/v${redocCurrentVersion}/bundles/redoc.standalone.js"></script>` +
|
|
71
|
+
css,
|
|
72
|
+
title: title || api.info.title || 'ReDoc documentation',
|
|
73
|
+
disableGoogleFont,
|
|
74
|
+
templateOptions,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function sanitizeJSONString(str) {
|
|
78
|
+
return escapeClosingScriptTag(escapeUnicode(str));
|
|
79
|
+
}
|
|
80
|
+
// see http://www.thespanner.co.uk/2011/07/25/the-json-specification-is-now-wrong/
|
|
81
|
+
function escapeClosingScriptTag(str) {
|
|
82
|
+
return str.replace(/<\/script>/g, '<\\/script>');
|
|
83
|
+
}
|
|
84
|
+
// see http://www.thespanner.co.uk/2011/07/25/the-json-specification-is-now-wrong/
|
|
85
|
+
function escapeUnicode(str) {
|
|
86
|
+
return str.replace(/\u2028|\u2029/g, (m) => '\\u202' + (m === '\u2028' ? '8' : '9'));
|
|
87
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OutputExtensions, Skips, VerifyConfigOptions } from '../types';
|
|
2
|
+
import type { CommandArgs } from '../wrapper';
|
|
3
|
+
export type BundleOptions = {
|
|
4
|
+
apis?: string[];
|
|
5
|
+
extends?: string[];
|
|
6
|
+
output?: string;
|
|
7
|
+
ext?: OutputExtensions;
|
|
8
|
+
dereferenced?: boolean;
|
|
9
|
+
force?: boolean;
|
|
10
|
+
metafile?: string;
|
|
11
|
+
'remove-unused-components'?: boolean;
|
|
12
|
+
'keep-url-references'?: boolean;
|
|
13
|
+
} & Skips & VerifyConfigOptions;
|
|
14
|
+
export declare function handleBundle({ argv, config, version, collectSpecData, }: CommandArgs<BundleOptions>): Promise<void>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleBundle = handleBundle;
|
|
4
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
5
|
+
const colorette_1 = require("colorette");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const openapi_core_1 = require("@redocly/openapi-core");
|
|
8
|
+
const miscellaneous_1 = require("../utils/miscellaneous");
|
|
9
|
+
async function handleBundle({ argv, config, version, collectSpecData, }) {
|
|
10
|
+
const removeUnusedComponents = argv['remove-unused-components'] ||
|
|
11
|
+
config.rawConfig?.styleguide?.decorators?.hasOwnProperty('remove-unused-components');
|
|
12
|
+
const apis = await (0, miscellaneous_1.getFallbackApisOrExit)(argv.apis, config);
|
|
13
|
+
const totals = { errors: 0, warnings: 0, ignored: 0 };
|
|
14
|
+
const deprecatedOptions = [];
|
|
15
|
+
(0, miscellaneous_1.checkForDeprecatedOptions)(argv, deprecatedOptions);
|
|
16
|
+
for (const { path, alias, output } of apis) {
|
|
17
|
+
try {
|
|
18
|
+
const startedAt = perf_hooks_1.performance.now();
|
|
19
|
+
const resolvedConfig = (0, openapi_core_1.getMergedConfig)(config, alias);
|
|
20
|
+
const { styleguide } = resolvedConfig;
|
|
21
|
+
styleguide.skipPreprocessors(argv['skip-preprocessor']);
|
|
22
|
+
styleguide.skipDecorators(argv['skip-decorator']);
|
|
23
|
+
process.stderr.write((0, colorette_1.gray)(`bundling ${(0, miscellaneous_1.formatPath)(path)}...\n`));
|
|
24
|
+
const { bundle: result, problems, ...meta } = await (0, openapi_core_1.bundle)({
|
|
25
|
+
config: resolvedConfig,
|
|
26
|
+
ref: path,
|
|
27
|
+
dereference: argv.dereferenced,
|
|
28
|
+
removeUnusedComponents,
|
|
29
|
+
keepUrlRefs: argv['keep-url-references'],
|
|
30
|
+
collectSpecData,
|
|
31
|
+
});
|
|
32
|
+
const fileTotals = (0, openapi_core_1.getTotals)(problems);
|
|
33
|
+
const { outputFile, ext } = (0, miscellaneous_1.getOutputFileName)({
|
|
34
|
+
entrypoint: path,
|
|
35
|
+
output,
|
|
36
|
+
argvOutput: argv.output,
|
|
37
|
+
ext: argv.ext,
|
|
38
|
+
entries: argv?.apis?.length || 0,
|
|
39
|
+
});
|
|
40
|
+
if (fileTotals.errors === 0 || argv.force) {
|
|
41
|
+
if (!outputFile) {
|
|
42
|
+
const bundled = (0, miscellaneous_1.dumpBundle)((0, miscellaneous_1.sortTopLevelKeysForOas)(result.parsed), argv.ext || 'yaml', argv.dereferenced);
|
|
43
|
+
process.stdout.write(bundled);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const bundled = (0, miscellaneous_1.dumpBundle)((0, miscellaneous_1.sortTopLevelKeysForOas)(result.parsed), ext, argv.dereferenced);
|
|
47
|
+
(0, miscellaneous_1.saveBundle)(outputFile, bundled);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
totals.errors += fileTotals.errors;
|
|
51
|
+
totals.warnings += fileTotals.warnings;
|
|
52
|
+
totals.ignored += fileTotals.ignored;
|
|
53
|
+
(0, openapi_core_1.formatProblems)(problems, {
|
|
54
|
+
format: 'codeframe',
|
|
55
|
+
totals: fileTotals,
|
|
56
|
+
version,
|
|
57
|
+
});
|
|
58
|
+
if (argv.metafile) {
|
|
59
|
+
if (apis.length > 1) {
|
|
60
|
+
process.stderr.write((0, colorette_1.yellow)(`[WARNING] "--metafile" cannot be used with multiple apis. Skipping...`));
|
|
61
|
+
}
|
|
62
|
+
{
|
|
63
|
+
(0, fs_1.writeFileSync)(argv.metafile, JSON.stringify(meta), 'utf-8');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const elapsed = (0, miscellaneous_1.getExecutionTime)(startedAt);
|
|
67
|
+
if (fileTotals.errors > 0) {
|
|
68
|
+
if (argv.force) {
|
|
69
|
+
process.stderr.write(`❓ Created a bundle for ${(0, colorette_1.blue)((0, miscellaneous_1.formatPath)(path))} at ${(0, colorette_1.blue)(outputFile || 'stdout')} with errors ${(0, colorette_1.green)(elapsed)}.\n${(0, colorette_1.yellow)('Errors ignored because of --force')}.\n`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
process.stderr.write(`❌ Errors encountered while bundling ${(0, colorette_1.blue)((0, miscellaneous_1.formatPath)(path))}: bundle not created (use --force to ignore errors).\n`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
process.stderr.write(`📦 Created a bundle for ${(0, colorette_1.blue)((0, miscellaneous_1.formatPath)(path))} at ${(0, colorette_1.blue)(outputFile || 'stdout')} ${(0, colorette_1.green)(elapsed)}.\n`);
|
|
77
|
+
}
|
|
78
|
+
const removedCount = meta.visitorsData?.['remove-unused-components']?.removedCount;
|
|
79
|
+
if (removedCount) {
|
|
80
|
+
process.stderr.write((0, colorette_1.gray)(`🧹 Removed ${removedCount} unused components.\n`));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
(0, miscellaneous_1.handleError)(e, path);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
(0, miscellaneous_1.printUnusedWarnings)(config.styleguide);
|
|
88
|
+
if (!(totals.errors === 0 || argv.force)) {
|
|
89
|
+
throw new Error('Bundle failed.');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CommandArgs } from '../wrapper';
|
|
2
|
+
import type { VerifyConfigOptions } from '../types';
|
|
3
|
+
export type EjectOptions = {
|
|
4
|
+
type: 'component';
|
|
5
|
+
path?: string;
|
|
6
|
+
'project-dir'?: string;
|
|
7
|
+
force: boolean;
|
|
8
|
+
} & VerifyConfigOptions;
|
|
9
|
+
export declare const handleEject: ({ argv }: CommandArgs<EjectOptions>) => Promise<void>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleEject = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const platform_1 = require("../utils/platform");
|
|
6
|
+
const handleEject = async ({ argv }) => {
|
|
7
|
+
process.stdout.write(`\nLaunching eject using NPX.\n\n`);
|
|
8
|
+
const { npxExecutableName, sanitize, shell } = (0, platform_1.getPlatformSpawnArgs)();
|
|
9
|
+
const path = sanitize(argv.path, platform_1.sanitizePath);
|
|
10
|
+
const projectDir = sanitize(argv['project-dir'], platform_1.sanitizePath);
|
|
11
|
+
const child = (0, child_process_1.spawn)(npxExecutableName, [
|
|
12
|
+
'-y',
|
|
13
|
+
'@redocly/realm',
|
|
14
|
+
'eject',
|
|
15
|
+
`${argv.type}`,
|
|
16
|
+
path,
|
|
17
|
+
`-d=${projectDir}`,
|
|
18
|
+
argv.force ? `--force=${argv.force}` : '',
|
|
19
|
+
], {
|
|
20
|
+
stdio: 'inherit',
|
|
21
|
+
shell,
|
|
22
|
+
});
|
|
23
|
+
child.on('error', (error) => {
|
|
24
|
+
process.stderr.write(`Eject launch failed: ${error.message}`);
|
|
25
|
+
throw new Error('Eject launch failed.');
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
exports.handleEject = handleEject;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CommandArgs } from '../wrapper';
|
|
2
|
+
import type { VerifyConfigOptions } from '../types';
|
|
3
|
+
export type JoinOptions = {
|
|
4
|
+
apis: string[];
|
|
5
|
+
'prefix-tags-with-info-prop'?: string;
|
|
6
|
+
'prefix-tags-with-filename'?: boolean;
|
|
7
|
+
'prefix-components-with-info-prop'?: string;
|
|
8
|
+
'without-x-tag-groups'?: boolean;
|
|
9
|
+
output?: string;
|
|
10
|
+
} & VerifyConfigOptions;
|
|
11
|
+
export declare function handleJoin({ argv, config, version: packageVersion, }: CommandArgs<JoinOptions>): Promise<void>;
|