@redocly/cli 1.0.0 → 1.0.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 +8 -0
- package/lib/commands/build-docs/index.js +2 -4
- package/lib/commands/build-docs/utils.d.ts +1 -1
- package/lib/commands/build-docs/utils.js +3 -3
- package/package.json +2 -2
- package/src/__mocks__/@redocly/openapi-core.ts +80 -0
- package/src/__mocks__/documents.ts +63 -0
- package/src/__mocks__/fs.ts +6 -0
- package/src/__mocks__/perf_hooks.ts +3 -0
- package/src/__mocks__/redoc.ts +2 -0
- package/src/__mocks__/utils.ts +19 -0
- package/src/__tests__/commands/build-docs.test.ts +62 -0
- package/src/__tests__/commands/bundle.test.ts +150 -0
- package/src/__tests__/commands/join.test.ts +122 -0
- package/src/__tests__/commands/lint.test.ts +190 -0
- package/src/__tests__/commands/push-region.test.ts +58 -0
- package/src/__tests__/commands/push.test.ts +492 -0
- package/src/__tests__/fetch-with-timeout.test.ts +35 -0
- package/src/__tests__/fixtures/config.ts +21 -0
- package/src/__tests__/fixtures/openapi.json +0 -0
- package/src/__tests__/fixtures/openapi.yaml +0 -0
- package/src/__tests__/fixtures/redocly.yaml +0 -0
- package/src/__tests__/utils.test.ts +564 -0
- package/src/__tests__/wrapper.test.ts +57 -0
- package/src/assert-node-version.ts +8 -0
- package/src/commands/build-docs/index.ts +50 -0
- package/src/commands/build-docs/template.hbs +23 -0
- package/src/commands/build-docs/types.ts +24 -0
- package/src/commands/build-docs/utils.ts +110 -0
- package/src/commands/bundle.ts +177 -0
- package/src/commands/join.ts +811 -0
- package/src/commands/lint.ts +151 -0
- package/src/commands/login.ts +27 -0
- package/src/commands/preview-docs/index.ts +190 -0
- package/src/commands/preview-docs/preview-server/default.hbs +24 -0
- package/src/commands/preview-docs/preview-server/hot.js +42 -0
- package/src/commands/preview-docs/preview-server/oauth2-redirect.html +21 -0
- package/src/commands/preview-docs/preview-server/preview-server.ts +156 -0
- package/src/commands/preview-docs/preview-server/server.ts +91 -0
- package/src/commands/push.ts +441 -0
- package/src/commands/split/__tests__/fixtures/samples.json +61 -0
- package/src/commands/split/__tests__/fixtures/spec.json +70 -0
- package/src/commands/split/__tests__/fixtures/webhooks.json +85 -0
- package/src/commands/split/__tests__/index.test.ts +137 -0
- package/src/commands/split/index.ts +385 -0
- package/src/commands/split/types.ts +85 -0
- package/src/commands/stats.ts +119 -0
- package/src/custom.d.ts +1 -0
- package/src/fetch-with-timeout.ts +21 -0
- package/src/index.ts +484 -0
- package/src/js-utils.ts +17 -0
- package/src/types.ts +40 -0
- package/src/update-version-notifier.ts +106 -0
- package/src/utils.ts +590 -0
- package/src/wrapper.ts +42 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { performance } from 'perf_hooks';
|
|
2
|
+
import * as colors from 'colorette';
|
|
3
|
+
import {
|
|
4
|
+
Config,
|
|
5
|
+
StyleguideConfig,
|
|
6
|
+
normalizeTypes,
|
|
7
|
+
Oas3Types,
|
|
8
|
+
Oas2Types,
|
|
9
|
+
BaseResolver,
|
|
10
|
+
resolveDocument,
|
|
11
|
+
detectOpenAPI,
|
|
12
|
+
OasMajorVersion,
|
|
13
|
+
openAPIMajor,
|
|
14
|
+
normalizeVisitors,
|
|
15
|
+
walkDocument,
|
|
16
|
+
Stats,
|
|
17
|
+
bundle,
|
|
18
|
+
} from '@redocly/openapi-core';
|
|
19
|
+
import { getFallbackApisOrExit } from '../utils';
|
|
20
|
+
import { printExecutionTime } from '../utils';
|
|
21
|
+
import type { StatsAccumulator, StatsName, WalkContext, OutputFormat } from '@redocly/openapi-core';
|
|
22
|
+
|
|
23
|
+
const statsAccumulator: StatsAccumulator = {
|
|
24
|
+
refs: { metric: '🚗 References', total: 0, color: 'red', items: new Set() },
|
|
25
|
+
externalDocs: { metric: '📦 External Documents', total: 0, color: 'magenta' },
|
|
26
|
+
schemas: { metric: '📈 Schemas', total: 0, color: 'white' },
|
|
27
|
+
parameters: { metric: '👉 Parameters', total: 0, color: 'yellow', items: new Set() },
|
|
28
|
+
links: { metric: '🔗 Links', total: 0, color: 'cyan', items: new Set() },
|
|
29
|
+
pathItems: { metric: '➡️ Path Items', total: 0, color: 'green' },
|
|
30
|
+
operations: { metric: '👷 Operations', total: 0, color: 'yellow' },
|
|
31
|
+
tags: { metric: '🔖 Tags', total: 0, color: 'white', items: new Set() },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function printStatsStylish(statsAccumulator: StatsAccumulator) {
|
|
35
|
+
for (const node in statsAccumulator) {
|
|
36
|
+
const { metric, total, color } = statsAccumulator[node as StatsName];
|
|
37
|
+
process.stderr.write(colors[color](`${metric}: ${total} \n`));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function printStatsJson(statsAccumulator: StatsAccumulator) {
|
|
42
|
+
const json: any = {};
|
|
43
|
+
for (const key of Object.keys(statsAccumulator)) {
|
|
44
|
+
json[key] = {
|
|
45
|
+
metric: statsAccumulator[key as StatsName].metric,
|
|
46
|
+
total: statsAccumulator[key as StatsName].total,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
process.stdout.write(JSON.stringify(json, null, 2));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function printStats(statsAccumulator: StatsAccumulator, api: string, format: string) {
|
|
53
|
+
process.stderr.write(`Document: ${colors.magenta(api)} stats:\n\n`);
|
|
54
|
+
switch (format) {
|
|
55
|
+
case 'stylish':
|
|
56
|
+
printStatsStylish(statsAccumulator);
|
|
57
|
+
break;
|
|
58
|
+
case 'json':
|
|
59
|
+
printStatsJson(statsAccumulator);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type StatsOptions = {
|
|
65
|
+
api?: string;
|
|
66
|
+
format: OutputFormat;
|
|
67
|
+
config?: string;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export async function handleStats(argv: StatsOptions, config: Config) {
|
|
71
|
+
const [{ path }] = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
|
|
72
|
+
const externalRefResolver = new BaseResolver(config.resolve);
|
|
73
|
+
const { bundle: document } = await bundle({ config, ref: path });
|
|
74
|
+
const lintConfig: StyleguideConfig = config.styleguide;
|
|
75
|
+
const oasVersion = detectOpenAPI(document.parsed);
|
|
76
|
+
const oasMajorVersion = openAPIMajor(oasVersion);
|
|
77
|
+
const types = normalizeTypes(
|
|
78
|
+
lintConfig.extendTypes(
|
|
79
|
+
oasMajorVersion === OasMajorVersion.Version3 ? Oas3Types : Oas2Types,
|
|
80
|
+
oasVersion
|
|
81
|
+
),
|
|
82
|
+
lintConfig
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const startedAt = performance.now();
|
|
86
|
+
const ctx: WalkContext = {
|
|
87
|
+
problems: [],
|
|
88
|
+
oasVersion: oasVersion,
|
|
89
|
+
visitorsData: {},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const resolvedRefMap = await resolveDocument({
|
|
93
|
+
rootDocument: document,
|
|
94
|
+
rootType: types.Root,
|
|
95
|
+
externalRefResolver,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const statsVisitor = normalizeVisitors(
|
|
99
|
+
[
|
|
100
|
+
{
|
|
101
|
+
severity: 'warn',
|
|
102
|
+
ruleId: 'stats',
|
|
103
|
+
visitor: Stats(statsAccumulator),
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
types
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
walkDocument({
|
|
110
|
+
document,
|
|
111
|
+
rootType: types.Root,
|
|
112
|
+
normalizedVisitors: statsVisitor,
|
|
113
|
+
resolvedRefMap,
|
|
114
|
+
ctx,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
printStats(statsAccumulator, path, argv.format);
|
|
118
|
+
printExecutionTime('stats', startedAt, path);
|
|
119
|
+
}
|
package/src/custom.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
type GenericObject = Record<string, any>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import nodeFetch from 'node-fetch';
|
|
2
|
+
|
|
3
|
+
const TIMEOUT = 3000;
|
|
4
|
+
|
|
5
|
+
export default async (url: string, options = {}) => {
|
|
6
|
+
try {
|
|
7
|
+
if (!global.AbortController) {
|
|
8
|
+
return nodeFetch(url, options);
|
|
9
|
+
}
|
|
10
|
+
const controller = new AbortController();
|
|
11
|
+
const timeout = setTimeout(() => {
|
|
12
|
+
controller.abort();
|
|
13
|
+
}, TIMEOUT);
|
|
14
|
+
|
|
15
|
+
const res = await nodeFetch(url, { signal: controller.signal, ...options });
|
|
16
|
+
clearTimeout(timeout);
|
|
17
|
+
return res;
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import './assert-node-version';
|
|
4
|
+
import * as yargs from 'yargs';
|
|
5
|
+
import { outputExtensions, regionChoices } from './types';
|
|
6
|
+
import { RedoclyClient } from '@redocly/openapi-core';
|
|
7
|
+
import { previewDocs } from './commands/preview-docs';
|
|
8
|
+
import { handleStats } from './commands/stats';
|
|
9
|
+
import { handleSplit } from './commands/split';
|
|
10
|
+
import { handleJoin } from './commands/join';
|
|
11
|
+
import { handlePush, transformPush } from './commands/push';
|
|
12
|
+
import { handleLint } from './commands/lint';
|
|
13
|
+
import { handleBundle } from './commands/bundle';
|
|
14
|
+
import { handleLogin } from './commands/login';
|
|
15
|
+
import { handlerBuildCommand } from './commands/build-docs';
|
|
16
|
+
import { cacheLatestVersion, notifyUpdateCliVersion } from './update-version-notifier';
|
|
17
|
+
import { commandWrapper } from './wrapper';
|
|
18
|
+
import { version } from './update-version-notifier';
|
|
19
|
+
import type { Arguments } from 'yargs';
|
|
20
|
+
import type { OutputFormat, RuleSeverity } from '@redocly/openapi-core';
|
|
21
|
+
import type { BuildDocsArgv } from './commands/build-docs/types';
|
|
22
|
+
|
|
23
|
+
cacheLatestVersion();
|
|
24
|
+
|
|
25
|
+
yargs
|
|
26
|
+
.version('version', 'Show version number.', version)
|
|
27
|
+
.help('help', 'Show help.')
|
|
28
|
+
.parserConfiguration({ 'greedy-arrays': false, 'camel-case-expansion': false })
|
|
29
|
+
.command(
|
|
30
|
+
'stats [api]',
|
|
31
|
+
'Show statistics for an API description.',
|
|
32
|
+
(yargs) =>
|
|
33
|
+
yargs.positional('api', { type: 'string' }).option({
|
|
34
|
+
config: { description: 'Path to the config file.', type: 'string' },
|
|
35
|
+
format: {
|
|
36
|
+
description: 'Use a specific output format.',
|
|
37
|
+
choices: ['stylish', 'json'] as ReadonlyArray<OutputFormat>,
|
|
38
|
+
default: 'stylish' as OutputFormat,
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
(argv) => {
|
|
42
|
+
process.env.REDOCLY_CLI_COMMAND = 'stats';
|
|
43
|
+
commandWrapper(handleStats)(argv);
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
.command(
|
|
47
|
+
'split [api]',
|
|
48
|
+
'Split an API definition into a multi-file structure.',
|
|
49
|
+
(yargs) =>
|
|
50
|
+
yargs
|
|
51
|
+
.positional('api', {
|
|
52
|
+
description: 'API definition file that you want to split',
|
|
53
|
+
type: 'string',
|
|
54
|
+
})
|
|
55
|
+
.option({
|
|
56
|
+
outDir: {
|
|
57
|
+
description: 'Output directory where files will be saved.',
|
|
58
|
+
required: true,
|
|
59
|
+
type: 'string',
|
|
60
|
+
},
|
|
61
|
+
separator: {
|
|
62
|
+
description: 'File path separator used while splitting.',
|
|
63
|
+
required: false,
|
|
64
|
+
type: 'string',
|
|
65
|
+
default: '_',
|
|
66
|
+
},
|
|
67
|
+
config: {
|
|
68
|
+
description: 'Path to the config file.',
|
|
69
|
+
requiresArg: true,
|
|
70
|
+
type: 'string',
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
.demandOption('api'),
|
|
74
|
+
(argv) => {
|
|
75
|
+
process.env.REDOCLY_CLI_COMMAND = 'split';
|
|
76
|
+
commandWrapper(handleSplit)(argv);
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
.command(
|
|
80
|
+
'join [apis...]',
|
|
81
|
+
'Join definitions [experimental].',
|
|
82
|
+
(yargs) =>
|
|
83
|
+
yargs
|
|
84
|
+
.positional('apis', {
|
|
85
|
+
array: true,
|
|
86
|
+
type: 'string',
|
|
87
|
+
demandOption: true,
|
|
88
|
+
})
|
|
89
|
+
.option({
|
|
90
|
+
lint: { description: 'Lint definitions', type: 'boolean', default: false },
|
|
91
|
+
decorate: { description: 'Run decorators', type: 'boolean', default: false },
|
|
92
|
+
preprocess: { description: 'Run preprocessors', type: 'boolean', default: false },
|
|
93
|
+
'prefix-tags-with-info-prop': {
|
|
94
|
+
description: 'Prefix tags with property value from info object.',
|
|
95
|
+
requiresArg: true,
|
|
96
|
+
type: 'string',
|
|
97
|
+
},
|
|
98
|
+
'prefix-tags-with-filename': {
|
|
99
|
+
description: 'Prefix tags with property value from file name.',
|
|
100
|
+
type: 'boolean',
|
|
101
|
+
default: false,
|
|
102
|
+
},
|
|
103
|
+
'prefix-components-with-info-prop': {
|
|
104
|
+
description: 'Prefix components with property value from info object.',
|
|
105
|
+
requiresArg: true,
|
|
106
|
+
type: 'string',
|
|
107
|
+
},
|
|
108
|
+
'without-x-tag-groups': {
|
|
109
|
+
description: 'Skip automated x-tagGroups creation',
|
|
110
|
+
type: 'boolean',
|
|
111
|
+
},
|
|
112
|
+
output: {
|
|
113
|
+
describe: 'Output file',
|
|
114
|
+
alias: 'o',
|
|
115
|
+
type: 'string',
|
|
116
|
+
default: 'openapi.yaml',
|
|
117
|
+
},
|
|
118
|
+
config: {
|
|
119
|
+
description: 'Path to the config file.',
|
|
120
|
+
requiresArg: true,
|
|
121
|
+
type: 'string',
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
(argv) => {
|
|
125
|
+
process.env.REDOCLY_CLI_COMMAND = 'join';
|
|
126
|
+
commandWrapper(handleJoin)(argv);
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
.command(
|
|
131
|
+
'push [api] [maybeDestination] [maybeBranchName]',
|
|
132
|
+
'Push an API definition to the Redocly API registry.',
|
|
133
|
+
(yargs) =>
|
|
134
|
+
yargs
|
|
135
|
+
.usage('push [api]')
|
|
136
|
+
.positional('api', { type: 'string' })
|
|
137
|
+
.positional('maybeDestination', { type: 'string' })
|
|
138
|
+
.hide('maybeDestination')
|
|
139
|
+
.hide('maybeBranchName')
|
|
140
|
+
.option({
|
|
141
|
+
organization: {
|
|
142
|
+
description: 'Name of the organization to push to.',
|
|
143
|
+
type: 'string',
|
|
144
|
+
alias: 'o',
|
|
145
|
+
},
|
|
146
|
+
destination: {
|
|
147
|
+
description: 'API name and version in the format `name@version`.',
|
|
148
|
+
type: 'string',
|
|
149
|
+
alias: 'd',
|
|
150
|
+
},
|
|
151
|
+
branch: {
|
|
152
|
+
description: 'Branch name to push to.',
|
|
153
|
+
type: 'string',
|
|
154
|
+
alias: 'b',
|
|
155
|
+
},
|
|
156
|
+
upsert: {
|
|
157
|
+
description:
|
|
158
|
+
"Create the specified API version if it doesn't exist, update if it does exist.",
|
|
159
|
+
type: 'boolean',
|
|
160
|
+
alias: 'u',
|
|
161
|
+
},
|
|
162
|
+
'batch-id': {
|
|
163
|
+
description:
|
|
164
|
+
'Specifies the ID of the CI job that the current push will be associated with.',
|
|
165
|
+
type: 'string',
|
|
166
|
+
requiresArg: true,
|
|
167
|
+
deprecated: true,
|
|
168
|
+
hidden: true,
|
|
169
|
+
},
|
|
170
|
+
'job-id': {
|
|
171
|
+
description: 'ID of the CI job that the current push will be associated with.',
|
|
172
|
+
type: 'string',
|
|
173
|
+
requiresArg: true,
|
|
174
|
+
},
|
|
175
|
+
'batch-size': {
|
|
176
|
+
description: 'Number of CI pushes to expect in a batch.',
|
|
177
|
+
type: 'number',
|
|
178
|
+
requiresArg: true,
|
|
179
|
+
},
|
|
180
|
+
region: { description: 'Specify a region.', alias: 'r', choices: regionChoices },
|
|
181
|
+
'skip-decorator': {
|
|
182
|
+
description: 'Ignore certain decorators.',
|
|
183
|
+
array: true,
|
|
184
|
+
type: 'string',
|
|
185
|
+
},
|
|
186
|
+
public: {
|
|
187
|
+
description: 'Make the API definition available to the public',
|
|
188
|
+
type: 'boolean',
|
|
189
|
+
},
|
|
190
|
+
files: {
|
|
191
|
+
description: 'List of other folders and files to upload',
|
|
192
|
+
array: true,
|
|
193
|
+
type: 'string',
|
|
194
|
+
},
|
|
195
|
+
})
|
|
196
|
+
.deprecateOption('batch-id', 'use --job-id')
|
|
197
|
+
.deprecateOption('maybeDestination')
|
|
198
|
+
.implies('job-id', 'batch-size')
|
|
199
|
+
.implies('batch-id', 'batch-size')
|
|
200
|
+
.implies('batch-size', 'job-id'),
|
|
201
|
+
(argv) => {
|
|
202
|
+
process.env.REDOCLY_CLI_COMMAND = 'push';
|
|
203
|
+
commandWrapper(transformPush(handlePush))(argv);
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
.command(
|
|
207
|
+
'lint [apis...]',
|
|
208
|
+
'Lint definition.',
|
|
209
|
+
(yargs) =>
|
|
210
|
+
yargs.positional('apis', { array: true, type: 'string', demandOption: true }).option({
|
|
211
|
+
format: {
|
|
212
|
+
description: 'Use a specific output format.',
|
|
213
|
+
choices: [
|
|
214
|
+
'stylish',
|
|
215
|
+
'codeframe',
|
|
216
|
+
'json',
|
|
217
|
+
'checkstyle',
|
|
218
|
+
'codeclimate',
|
|
219
|
+
'summary',
|
|
220
|
+
] as ReadonlyArray<OutputFormat>,
|
|
221
|
+
default: 'codeframe' as OutputFormat,
|
|
222
|
+
},
|
|
223
|
+
'max-problems': {
|
|
224
|
+
requiresArg: true,
|
|
225
|
+
description: 'Reduce output to a maximum of N problems.',
|
|
226
|
+
type: 'number',
|
|
227
|
+
default: 100,
|
|
228
|
+
},
|
|
229
|
+
'generate-ignore-file': {
|
|
230
|
+
description: 'Generate an ignore file.',
|
|
231
|
+
type: 'boolean',
|
|
232
|
+
},
|
|
233
|
+
'skip-rule': {
|
|
234
|
+
description: 'Ignore certain rules.',
|
|
235
|
+
array: true,
|
|
236
|
+
type: 'string',
|
|
237
|
+
},
|
|
238
|
+
'skip-preprocessor': {
|
|
239
|
+
description: 'Ignore certain preprocessors.',
|
|
240
|
+
array: true,
|
|
241
|
+
type: 'string',
|
|
242
|
+
},
|
|
243
|
+
'lint-config': {
|
|
244
|
+
description: 'Severity level for config file linting.',
|
|
245
|
+
choices: ['warn', 'error', 'off'] as ReadonlyArray<RuleSeverity>,
|
|
246
|
+
default: 'warn' as RuleSeverity,
|
|
247
|
+
},
|
|
248
|
+
config: {
|
|
249
|
+
description: 'Path to the config file.',
|
|
250
|
+
requiresArg: true,
|
|
251
|
+
type: 'string',
|
|
252
|
+
},
|
|
253
|
+
extends: {
|
|
254
|
+
description: 'Override extends configurations (defaults or config file settings).',
|
|
255
|
+
requiresArg: true,
|
|
256
|
+
array: true,
|
|
257
|
+
type: 'string',
|
|
258
|
+
},
|
|
259
|
+
}),
|
|
260
|
+
(argv) => {
|
|
261
|
+
process.env.REDOCLY_CLI_COMMAND = 'lint';
|
|
262
|
+
commandWrapper(handleLint)(argv);
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
.command(
|
|
266
|
+
'bundle [apis...]',
|
|
267
|
+
'Bundle definition.',
|
|
268
|
+
(yargs) =>
|
|
269
|
+
yargs.positional('apis', { array: true, type: 'string', demandOption: true }).options({
|
|
270
|
+
output: { type: 'string', alias: 'o' },
|
|
271
|
+
format: {
|
|
272
|
+
description: 'Use a specific output format.',
|
|
273
|
+
choices: ['stylish', 'codeframe', 'json', 'checkstyle'] as ReadonlyArray<OutputFormat>,
|
|
274
|
+
default: 'codeframe' as OutputFormat,
|
|
275
|
+
},
|
|
276
|
+
'max-problems': {
|
|
277
|
+
requiresArg: true,
|
|
278
|
+
description: 'Reduce output to a maximum of N problems.',
|
|
279
|
+
type: 'number',
|
|
280
|
+
default: 100,
|
|
281
|
+
},
|
|
282
|
+
ext: {
|
|
283
|
+
description: 'Bundle file extension.',
|
|
284
|
+
requiresArg: true,
|
|
285
|
+
choices: outputExtensions,
|
|
286
|
+
},
|
|
287
|
+
'skip-rule': {
|
|
288
|
+
description: 'Ignore certain rules.',
|
|
289
|
+
array: true,
|
|
290
|
+
type: 'string',
|
|
291
|
+
},
|
|
292
|
+
'skip-preprocessor': {
|
|
293
|
+
description: 'Ignore certain preprocessors.',
|
|
294
|
+
array: true,
|
|
295
|
+
type: 'string',
|
|
296
|
+
},
|
|
297
|
+
'skip-decorator': {
|
|
298
|
+
description: 'Ignore certain decorators.',
|
|
299
|
+
array: true,
|
|
300
|
+
type: 'string',
|
|
301
|
+
},
|
|
302
|
+
dereferenced: {
|
|
303
|
+
alias: 'd',
|
|
304
|
+
type: 'boolean',
|
|
305
|
+
description: 'Produce a fully dereferenced bundle.',
|
|
306
|
+
},
|
|
307
|
+
force: {
|
|
308
|
+
alias: 'f',
|
|
309
|
+
type: 'boolean',
|
|
310
|
+
description: 'Produce bundle output even when errors occur.',
|
|
311
|
+
},
|
|
312
|
+
config: {
|
|
313
|
+
description: 'Path to the config file.',
|
|
314
|
+
type: 'string',
|
|
315
|
+
},
|
|
316
|
+
lint: {
|
|
317
|
+
description: 'Lint API definitions',
|
|
318
|
+
type: 'boolean',
|
|
319
|
+
default: false,
|
|
320
|
+
},
|
|
321
|
+
metafile: {
|
|
322
|
+
description: 'Produce metadata about the bundle',
|
|
323
|
+
type: 'string',
|
|
324
|
+
},
|
|
325
|
+
extends: {
|
|
326
|
+
description: 'Override extends configurations (defaults or config file settings).',
|
|
327
|
+
requiresArg: true,
|
|
328
|
+
array: true,
|
|
329
|
+
type: 'string',
|
|
330
|
+
},
|
|
331
|
+
'remove-unused-components': {
|
|
332
|
+
description: 'Remove unused components.',
|
|
333
|
+
type: 'boolean',
|
|
334
|
+
default: false,
|
|
335
|
+
},
|
|
336
|
+
'keep-url-references': {
|
|
337
|
+
description: 'Keep absolute url references.',
|
|
338
|
+
type: 'boolean',
|
|
339
|
+
alias: 'k',
|
|
340
|
+
},
|
|
341
|
+
}),
|
|
342
|
+
(argv) => {
|
|
343
|
+
process.env.REDOCLY_CLI_COMMAND = 'bundle';
|
|
344
|
+
commandWrapper(handleBundle)(argv);
|
|
345
|
+
}
|
|
346
|
+
)
|
|
347
|
+
.command(
|
|
348
|
+
'login',
|
|
349
|
+
'Login to the Redocly API registry with an access token.',
|
|
350
|
+
async (yargs) =>
|
|
351
|
+
yargs.options({
|
|
352
|
+
verbose: {
|
|
353
|
+
description: 'Include additional output.',
|
|
354
|
+
type: 'boolean',
|
|
355
|
+
},
|
|
356
|
+
region: {
|
|
357
|
+
description: 'Specify a region.',
|
|
358
|
+
alias: 'r',
|
|
359
|
+
choices: regionChoices,
|
|
360
|
+
},
|
|
361
|
+
config: {
|
|
362
|
+
description: 'Path to the config file.',
|
|
363
|
+
requiresArg: true,
|
|
364
|
+
type: 'string',
|
|
365
|
+
},
|
|
366
|
+
}),
|
|
367
|
+
(argv) => {
|
|
368
|
+
process.env.REDOCLY_CLI_COMMAND = 'login';
|
|
369
|
+
commandWrapper(handleLogin)(argv);
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
.command(
|
|
373
|
+
'logout',
|
|
374
|
+
'Clear your stored credentials for the Redocly API registry.',
|
|
375
|
+
(yargs) => yargs,
|
|
376
|
+
async (argv) => {
|
|
377
|
+
process.env.REDOCLY_CLI_COMMAND = 'logout';
|
|
378
|
+
await commandWrapper(async () => {
|
|
379
|
+
const client = new RedoclyClient();
|
|
380
|
+
client.logout();
|
|
381
|
+
process.stdout.write('Logged out from the Redocly account. ✋\n');
|
|
382
|
+
})(argv);
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
.command(
|
|
386
|
+
'preview-docs [api]',
|
|
387
|
+
'Preview API reference docs for the specified definition.',
|
|
388
|
+
(yargs) =>
|
|
389
|
+
yargs.positional('api', { type: 'string' }).options({
|
|
390
|
+
port: {
|
|
391
|
+
alias: 'p',
|
|
392
|
+
type: 'number',
|
|
393
|
+
default: 8080,
|
|
394
|
+
description: 'Preview port.',
|
|
395
|
+
},
|
|
396
|
+
host: {
|
|
397
|
+
alias: 'h',
|
|
398
|
+
type: 'string',
|
|
399
|
+
default: '127.0.0.1',
|
|
400
|
+
description: 'Preview host.',
|
|
401
|
+
},
|
|
402
|
+
'skip-preprocessor': {
|
|
403
|
+
description: 'Ignore certain preprocessors.',
|
|
404
|
+
array: true,
|
|
405
|
+
type: 'string',
|
|
406
|
+
},
|
|
407
|
+
'skip-decorator': {
|
|
408
|
+
description: 'Ignore certain decorators.',
|
|
409
|
+
array: true,
|
|
410
|
+
type: 'string',
|
|
411
|
+
},
|
|
412
|
+
'use-community-edition': {
|
|
413
|
+
description: 'Use Redoc CE for documentation preview.',
|
|
414
|
+
type: 'boolean',
|
|
415
|
+
},
|
|
416
|
+
force: {
|
|
417
|
+
alias: 'f',
|
|
418
|
+
type: 'boolean',
|
|
419
|
+
description: 'Produce bundle output even when errors occur.',
|
|
420
|
+
},
|
|
421
|
+
config: {
|
|
422
|
+
description: 'Path to the config file.',
|
|
423
|
+
type: 'string',
|
|
424
|
+
},
|
|
425
|
+
}),
|
|
426
|
+
(argv) => {
|
|
427
|
+
process.env.REDOCLY_CLI_COMMAND = 'preview-docs';
|
|
428
|
+
commandWrapper(previewDocs)(argv);
|
|
429
|
+
}
|
|
430
|
+
)
|
|
431
|
+
.command(
|
|
432
|
+
'build-docs [api]',
|
|
433
|
+
'Produce API documentation as an HTML file',
|
|
434
|
+
(yargs) =>
|
|
435
|
+
yargs
|
|
436
|
+
.positional('api', { type: 'string' })
|
|
437
|
+
.options({
|
|
438
|
+
o: {
|
|
439
|
+
describe: 'Output destination file.',
|
|
440
|
+
alias: 'output',
|
|
441
|
+
type: 'string',
|
|
442
|
+
default: 'redoc-static.html',
|
|
443
|
+
},
|
|
444
|
+
title: {
|
|
445
|
+
describe: 'Page title.',
|
|
446
|
+
type: 'string',
|
|
447
|
+
},
|
|
448
|
+
disableGoogleFont: {
|
|
449
|
+
describe: 'Disable Google fonts.',
|
|
450
|
+
type: 'boolean',
|
|
451
|
+
default: false,
|
|
452
|
+
},
|
|
453
|
+
t: {
|
|
454
|
+
alias: 'template',
|
|
455
|
+
describe: 'Path to handlebars page template, see https://git.io/vh8fP for the example.',
|
|
456
|
+
type: 'string',
|
|
457
|
+
},
|
|
458
|
+
templateOptions: {
|
|
459
|
+
describe:
|
|
460
|
+
'Additional options to pass to the template. Use dot notation, e.g. templateOptions.metaDescription',
|
|
461
|
+
},
|
|
462
|
+
theme: {
|
|
463
|
+
describe:
|
|
464
|
+
'Redoc theme.openapi configuration. Use dot notation, e.g. theme.openapi.nativeScrollbars',
|
|
465
|
+
},
|
|
466
|
+
config: {
|
|
467
|
+
describe: 'Path to the config file.',
|
|
468
|
+
type: 'string',
|
|
469
|
+
},
|
|
470
|
+
})
|
|
471
|
+
.check((argv: any) => {
|
|
472
|
+
if (argv.theme && !argv.theme?.openapi)
|
|
473
|
+
throw Error('Invalid option: theme.openapi not set');
|
|
474
|
+
return true;
|
|
475
|
+
}),
|
|
476
|
+
async (argv) => {
|
|
477
|
+
process.env.REDOCLY_CLI_COMMAND = 'build-docs';
|
|
478
|
+
commandWrapper(handlerBuildCommand)(argv as Arguments<BuildDocsArgv>);
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
|
+
.completion('completion', 'Generate completion script.')
|
|
482
|
+
.demandCommand(1)
|
|
483
|
+
.middleware([notifyUpdateCliVersion])
|
|
484
|
+
.strict().argv;
|
package/src/js-utils.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function isObject(obj: any) {
|
|
2
|
+
const type = typeof obj;
|
|
3
|
+
return type === 'function' || (type === 'object' && !!obj);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function isEmptyObject(obj: any) {
|
|
7
|
+
return !!obj && Object.keys(obj).length === 0;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isString(str: string) {
|
|
11
|
+
return Object.prototype.toString.call(str) === '[object String]';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function keysOf<T>(obj: T) {
|
|
15
|
+
if (!obj) return [];
|
|
16
|
+
return Object.keys(obj) as (keyof T)[];
|
|
17
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { BundleOutputFormat, Region, Config } from '@redocly/openapi-core';
|
|
2
|
+
import type { LintOptions } from './commands/lint';
|
|
3
|
+
import type { BundleOptions } from './commands/bundle';
|
|
4
|
+
import type { JoinOptions } from './commands/join';
|
|
5
|
+
import type { LoginOptions } from './commands/login';
|
|
6
|
+
import type { PushOptions } from './commands/push';
|
|
7
|
+
import type { StatsOptions } from './commands/stats';
|
|
8
|
+
import type { SplitOptions } from './commands/split';
|
|
9
|
+
import type { PreviewDocsOptions } from './commands/preview-docs';
|
|
10
|
+
import type { BuildDocsArgv } from './commands/build-docs/types';
|
|
11
|
+
|
|
12
|
+
export type Totals = {
|
|
13
|
+
errors: number;
|
|
14
|
+
warnings: number;
|
|
15
|
+
ignored: number;
|
|
16
|
+
};
|
|
17
|
+
export type Entrypoint = {
|
|
18
|
+
path: string;
|
|
19
|
+
alias?: string;
|
|
20
|
+
};
|
|
21
|
+
export const outputExtensions = ['json', 'yaml', 'yml'] as ReadonlyArray<BundleOutputFormat>;
|
|
22
|
+
export type OutputExtensions = 'json' | 'yaml' | 'yml' | undefined;
|
|
23
|
+
export const regionChoices = ['us', 'eu'] as ReadonlyArray<Region>;
|
|
24
|
+
export type CommandOptions =
|
|
25
|
+
| StatsOptions
|
|
26
|
+
| SplitOptions
|
|
27
|
+
| JoinOptions
|
|
28
|
+
| PushOptions
|
|
29
|
+
| LintOptions
|
|
30
|
+
| BundleOptions
|
|
31
|
+
| LoginOptions
|
|
32
|
+
| PreviewDocsOptions
|
|
33
|
+
| BuildDocsArgv;
|
|
34
|
+
export type Skips = {
|
|
35
|
+
'skip-rule'?: string[];
|
|
36
|
+
'skip-decorator'?: string[];
|
|
37
|
+
'skip-preprocessor'?: string[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type ConfigApis = Pick<Config, 'apis' | 'configFile'>;
|