@redocly/cli 1.0.0-beta.126 → 1.0.0-beta.128
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/lib/__tests__/utils.test.js +19 -0
- package/lib/index.js +5 -1
- package/lib/update-version-notifier.d.ts +2 -0
- package/lib/update-version-notifier.js +100 -0
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +13 -5
- package/package.json +5 -3
- package/src/__mocks__/@redocly/openapi-core.ts +0 -80
- package/src/__mocks__/documents.ts +0 -63
- package/src/__mocks__/fs.ts +0 -6
- package/src/__mocks__/perf_hooks.ts +0 -3
- package/src/__mocks__/redoc.ts +0 -2
- package/src/__mocks__/utils.ts +0 -19
- package/src/__tests__/commands/build-docs.test.ts +0 -61
- package/src/__tests__/commands/bundle.test.ts +0 -169
- package/src/__tests__/commands/join.test.ts +0 -114
- package/src/__tests__/commands/lint.test.ts +0 -166
- package/src/__tests__/commands/push-region.test.ts +0 -51
- package/src/__tests__/commands/push.test.ts +0 -364
- package/src/__tests__/fixtures/config.ts +0 -21
- package/src/__tests__/utils.test.ts +0 -441
- package/src/assert-node-version.ts +0 -8
- package/src/commands/build-docs/index.ts +0 -56
- package/src/commands/build-docs/template.hbs +0 -23
- package/src/commands/build-docs/types.ts +0 -26
- package/src/commands/build-docs/utils.ts +0 -112
- package/src/commands/bundle.ts +0 -170
- package/src/commands/join.ts +0 -810
- package/src/commands/lint.ts +0 -161
- package/src/commands/login.ts +0 -21
- package/src/commands/preview-docs/index.ts +0 -183
- package/src/commands/preview-docs/preview-server/default.hbs +0 -24
- package/src/commands/preview-docs/preview-server/hot.js +0 -42
- package/src/commands/preview-docs/preview-server/oauth2-redirect.html +0 -21
- package/src/commands/preview-docs/preview-server/preview-server.ts +0 -156
- package/src/commands/preview-docs/preview-server/server.ts +0 -91
- package/src/commands/push.ts +0 -387
- package/src/commands/split/__tests__/fixtures/samples.json +0 -61
- package/src/commands/split/__tests__/fixtures/spec.json +0 -70
- package/src/commands/split/__tests__/fixtures/webhooks.json +0 -88
- package/src/commands/split/__tests__/index.test.ts +0 -137
- package/src/commands/split/index.ts +0 -378
- package/src/commands/split/types.ts +0 -85
- package/src/commands/stats.ts +0 -117
- package/src/custom.d.ts +0 -1
- package/src/index.ts +0 -431
- package/src/js-utils.ts +0 -17
- package/src/types.ts +0 -28
- package/src/utils.ts +0 -472
- package/tsconfig.json +0 -9
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -320,6 +320,18 @@ describe('handleErrors', () => {
|
|
|
320
320
|
expect(process.stderr.write).toHaveBeenCalledWith(`Detected circular reference which can't be converted to JSON.\n` +
|
|
321
321
|
`Try to use ${colorette_1.blue('yaml')} output or remove ${colorette_1.blue('--dereferenced')}.\n\n`);
|
|
322
322
|
});
|
|
323
|
+
it('should handle SyntaxError', () => {
|
|
324
|
+
const testError = new SyntaxError('Unexpected identifier');
|
|
325
|
+
testError.stack = 'test stack';
|
|
326
|
+
try {
|
|
327
|
+
utils_1.handleError(testError, ref);
|
|
328
|
+
}
|
|
329
|
+
catch (e) {
|
|
330
|
+
expect(e).toEqual(testError);
|
|
331
|
+
}
|
|
332
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
333
|
+
expect(process.stderr.write).toHaveBeenCalledWith('Syntax error: Unexpected identifier test stack\n\n');
|
|
334
|
+
});
|
|
323
335
|
it('should throw unknown error', () => {
|
|
324
336
|
const testError = new Error('Test error');
|
|
325
337
|
try {
|
|
@@ -357,3 +369,10 @@ describe('checkIfRulesetExist', () => {
|
|
|
357
369
|
expect(process.exit).not.toHaveBeenCalled();
|
|
358
370
|
});
|
|
359
371
|
});
|
|
372
|
+
describe('cleanColors', () => {
|
|
373
|
+
it('should remove colors from string', () => {
|
|
374
|
+
const stringWithColors = `String for ${colorette_1.red('test')}`;
|
|
375
|
+
const result = utils_1.cleanColors(stringWithColors);
|
|
376
|
+
expect(result).not.toMatch(/\x1b\[\d+m/g);
|
|
377
|
+
});
|
|
378
|
+
});
|
package/lib/index.js
CHANGED
|
@@ -23,10 +23,13 @@ const lint_1 = require("./commands/lint");
|
|
|
23
23
|
const bundle_1 = require("./commands/bundle");
|
|
24
24
|
const login_1 = require("./commands/login");
|
|
25
25
|
const build_docs_1 = require("./commands/build-docs");
|
|
26
|
+
const update_version_notifier_1 = require("./update-version-notifier");
|
|
26
27
|
const version = require('../package.json').version;
|
|
28
|
+
update_version_notifier_1.cacheLatestVersion();
|
|
27
29
|
yargs
|
|
28
30
|
.version('version', 'Show version number.', version)
|
|
29
31
|
.help('help', 'Show help.')
|
|
32
|
+
.parserConfiguration({ 'greedy-arrays': false })
|
|
30
33
|
.command('stats [api]', 'Gathering statistics for a document.', (yargs) => yargs.positional('api', { type: 'string' }).option({
|
|
31
34
|
config: { description: 'Specify path to the config file.', type: 'string' },
|
|
32
35
|
format: {
|
|
@@ -328,7 +331,7 @@ yargs
|
|
|
328
331
|
process.env.REDOCLY_CLI_COMMAND = 'preview-docs';
|
|
329
332
|
preview_docs_1.previewDocs(argv);
|
|
330
333
|
})
|
|
331
|
-
.command('build-docs [api]', 'build definition into
|
|
334
|
+
.command('build-docs [api]', 'build definition into an HTML file', (yargs) => yargs
|
|
332
335
|
.positional('api', { type: 'string' })
|
|
333
336
|
.options({
|
|
334
337
|
o: {
|
|
@@ -378,4 +381,5 @@ yargs
|
|
|
378
381
|
}))
|
|
379
382
|
.completion('completion', 'Generate completion script.')
|
|
380
383
|
.demandCommand(1)
|
|
384
|
+
.middleware([update_version_notifier_1.notifyUpdateCliVersion])
|
|
381
385
|
.strict().argv;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.cacheLatestVersion = exports.notifyUpdateCliVersion = void 0;
|
|
13
|
+
const os_1 = require("os");
|
|
14
|
+
const path_1 = require("path");
|
|
15
|
+
const fs_1 = require("fs");
|
|
16
|
+
const semver_1 = require("semver");
|
|
17
|
+
const node_fetch_1 = require("node-fetch");
|
|
18
|
+
const colorette_1 = require("colorette");
|
|
19
|
+
const utils_1 = require("./utils");
|
|
20
|
+
const { version, name } = require('../package.json');
|
|
21
|
+
const VERSION_CACHE_FILE = 'redocly-cli-version';
|
|
22
|
+
const SPACE_TO_BORDER = 4;
|
|
23
|
+
const INTERVAL_TO_CHECK = 1000 * 60 * 60 * 12;
|
|
24
|
+
const SHOULD_NOT_NOTIFY = process.env.NODE_ENV === 'test' || process.env.CI || !!process.env.LAMBDA_TASK_ROOT;
|
|
25
|
+
const notifyUpdateCliVersion = () => {
|
|
26
|
+
if (SHOULD_NOT_NOTIFY) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const latestVersion = fs_1.readFileSync(path_1.join(os_1.tmpdir(), VERSION_CACHE_FILE)).toString();
|
|
31
|
+
if (isNewVersionAvailable(version, latestVersion)) {
|
|
32
|
+
renderUpdateBanner(version, latestVersion);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
exports.notifyUpdateCliVersion = notifyUpdateCliVersion;
|
|
40
|
+
const isNewVersionAvailable = (current, latest) => semver_1.compare(current, latest) < 0;
|
|
41
|
+
const getLatestVersion = (packageName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
const latestUrl = `http://registry.npmjs.org/${packageName}/latest`;
|
|
43
|
+
const response = yield node_fetch_1.default(latestUrl);
|
|
44
|
+
const info = yield response.json();
|
|
45
|
+
return info.version;
|
|
46
|
+
});
|
|
47
|
+
const cacheLatestVersion = () => {
|
|
48
|
+
if (!isNeedToBeCached() || SHOULD_NOT_NOTIFY) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
getLatestVersion(name)
|
|
52
|
+
.then((version) => {
|
|
53
|
+
const lastCheckFile = path_1.join(os_1.tmpdir(), VERSION_CACHE_FILE);
|
|
54
|
+
fs_1.writeFileSync(lastCheckFile, version);
|
|
55
|
+
})
|
|
56
|
+
.catch(() => { });
|
|
57
|
+
};
|
|
58
|
+
exports.cacheLatestVersion = cacheLatestVersion;
|
|
59
|
+
const renderUpdateBanner = (current, latest) => {
|
|
60
|
+
const messageLines = [
|
|
61
|
+
`A new version of ${colorette_1.cyan('Redocly CLI')} (${colorette_1.green(latest)}) is available.`,
|
|
62
|
+
`Update now: \`${colorette_1.cyan('npm i -g @redocly/cli@latest')}\`.`,
|
|
63
|
+
`Changelog: https://redocly.com/docs/cli/changelog/`,
|
|
64
|
+
];
|
|
65
|
+
const maxLength = Math.max(...messageLines.map((line) => utils_1.cleanColors(line).length));
|
|
66
|
+
const border = colorette_1.yellow('═'.repeat(maxLength + SPACE_TO_BORDER));
|
|
67
|
+
const banner = `
|
|
68
|
+
${colorette_1.yellow('╔' + border + '╗')}
|
|
69
|
+
${colorette_1.yellow('║' + ' '.repeat(maxLength + SPACE_TO_BORDER) + '║')}
|
|
70
|
+
${messageLines
|
|
71
|
+
.map((line, index) => {
|
|
72
|
+
return getLineWithPadding(maxLength, line, index);
|
|
73
|
+
})
|
|
74
|
+
.join('\n')}
|
|
75
|
+
${colorette_1.yellow('║' + ' '.repeat(maxLength + SPACE_TO_BORDER) + '║')}
|
|
76
|
+
${colorette_1.yellow('╚' + border + '╝')}
|
|
77
|
+
`;
|
|
78
|
+
process.stderr.write(banner);
|
|
79
|
+
};
|
|
80
|
+
const getLineWithPadding = (maxLength, line, index) => {
|
|
81
|
+
const padding = ' '.repeat(maxLength - utils_1.cleanColors(line).length);
|
|
82
|
+
const extraSpaces = index !== 0 ? ' '.repeat(SPACE_TO_BORDER) : '';
|
|
83
|
+
return `${extraSpaces}${colorette_1.yellow('║')} ${line}${padding} ${colorette_1.yellow('║')}`;
|
|
84
|
+
};
|
|
85
|
+
const isNeedToBeCached = () => {
|
|
86
|
+
try {
|
|
87
|
+
// Last version from npm is stored in a file in the OS temp folder
|
|
88
|
+
const versionFile = path_1.join(os_1.tmpdir(), VERSION_CACHE_FILE);
|
|
89
|
+
if (!fs_1.existsSync(versionFile)) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
const now = new Date().getTime();
|
|
93
|
+
const stats = fs_1.statSync(versionFile);
|
|
94
|
+
const lastCheck = stats.mtime.getTime();
|
|
95
|
+
return now - lastCheck >= INTERVAL_TO_CHECK;
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
};
|
package/lib/utils.d.ts
CHANGED
|
@@ -38,3 +38,4 @@ export declare function loadConfigAndHandleErrors(options?: {
|
|
|
38
38
|
}): Promise<Config>;
|
|
39
39
|
export declare function sortTopLevelKeysForOas(document: Oas3Definition | Oas2Definition): Oas3Definition | Oas2Definition;
|
|
40
40
|
export declare function checkIfRulesetExist(rules: typeof StyleguideConfig.prototype.rules): void;
|
|
41
|
+
export declare function cleanColors(input: string): string;
|
package/lib/utils.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.checkIfRulesetExist = exports.sortTopLevelKeysForOas = exports.loadConfigAndHandleErrors = exports.isSubdir = exports.exitWithError = exports.printUnusedWarnings = exports.getOutputFileName = exports.printConfigLintTotals = exports.printLintTotals = exports.handleError = exports.pluralize = exports.writeYaml = exports.readYaml = exports.promptUser = exports.saveBundle = exports.dumpBundle = exports.CircularJSONNotSupportedError = exports.langToExt = exports.escapeLanguageName = exports.pathToFilename = exports.printExecutionTime = exports.getExecutionTime = exports.getFallbackApisOrExit = void 0;
|
|
12
|
+
exports.cleanColors = exports.checkIfRulesetExist = exports.sortTopLevelKeysForOas = exports.loadConfigAndHandleErrors = exports.isSubdir = exports.exitWithError = exports.printUnusedWarnings = exports.getOutputFileName = exports.printConfigLintTotals = exports.printLintTotals = exports.handleError = exports.pluralize = exports.writeYaml = exports.readYaml = exports.promptUser = exports.saveBundle = exports.dumpBundle = exports.CircularJSONNotSupportedError = exports.langToExt = exports.escapeLanguageName = exports.pathToFilename = exports.printExecutionTime = exports.getExecutionTime = exports.getFallbackApisOrExit = void 0;
|
|
13
13
|
const path_1 = require("path");
|
|
14
14
|
const colorette_1 = require("colorette");
|
|
15
15
|
const perf_hooks_1 = require("perf_hooks");
|
|
@@ -202,6 +202,7 @@ function pluralize(label, num) {
|
|
|
202
202
|
}
|
|
203
203
|
exports.pluralize = pluralize;
|
|
204
204
|
function handleError(e, ref) {
|
|
205
|
+
var _a, _b;
|
|
205
206
|
switch (e.constructor) {
|
|
206
207
|
case openapi_core_1.ResolveError:
|
|
207
208
|
return exitWithError(`Failed to resolve api definition at ${ref}:\n\n - ${e.message}.`);
|
|
@@ -213,9 +214,11 @@ function handleError(e, ref) {
|
|
|
213
214
|
`Try to use ${colorette_1.blue('yaml')} output or remove ${colorette_1.blue('--dereferenced')}.\n\n`);
|
|
214
215
|
return process.exit(1);
|
|
215
216
|
}
|
|
217
|
+
case SyntaxError:
|
|
218
|
+
return exitWithError(`Syntax error: ${e.message} ${(_b = (_a = e.stack) === null || _a === void 0 ? void 0 : _a.split('\n\n')) === null || _b === void 0 ? void 0 : _b[0]}`);
|
|
216
219
|
default: {
|
|
217
|
-
process.stderr.write(`Something went wrong when processing ${ref}:\n\n - ${e.message}.\n\n`);
|
|
218
|
-
process.
|
|
220
|
+
process.stderr.write(colorette_1.red(`Something went wrong when processing ${ref}:\n\n - ${e.message}.\n\n`));
|
|
221
|
+
process.exit(1);
|
|
219
222
|
throw e;
|
|
220
223
|
}
|
|
221
224
|
}
|
|
@@ -238,7 +241,7 @@ function printLintTotals(totals, definitionsCount) {
|
|
|
238
241
|
process.stderr.write(colorette_1.green(`Woohoo! Your OpenAPI ${pluralize('definition is', definitionsCount)} valid. 🎉\n${ignored}`));
|
|
239
242
|
}
|
|
240
243
|
if (totals.errors > 0) {
|
|
241
|
-
process.stderr.write(colorette_1.gray(`run \`
|
|
244
|
+
process.stderr.write(colorette_1.gray(`run \`redocly lint --generate-ignore-file\` to add all problems to the ignore file.\n`));
|
|
242
245
|
}
|
|
243
246
|
process.stderr.write('\n');
|
|
244
247
|
}
|
|
@@ -314,7 +317,7 @@ function loadConfigAndHandleErrors(options = {}) {
|
|
|
314
317
|
return yield openapi_core_1.loadConfig(options);
|
|
315
318
|
}
|
|
316
319
|
catch (e) {
|
|
317
|
-
|
|
320
|
+
handleError(e, '');
|
|
318
321
|
return new openapi_core_1.Config({ apis: {}, styleguide: {} });
|
|
319
322
|
}
|
|
320
323
|
});
|
|
@@ -384,3 +387,8 @@ function checkIfRulesetExist(rules) {
|
|
|
384
387
|
}
|
|
385
388
|
}
|
|
386
389
|
exports.checkIfRulesetExist = checkIfRulesetExist;
|
|
390
|
+
function cleanColors(input) {
|
|
391
|
+
// eslint-disable-next-line no-control-regex
|
|
392
|
+
return input.replace(/\x1b\[\d+m/g, '');
|
|
393
|
+
}
|
|
394
|
+
exports.cleanColors = cleanColors;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/cli",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.128",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"Roman Hotsiy <roman@redoc.ly> (https://redoc.ly/)"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@redocly/openapi-core": "1.0.0-beta.
|
|
36
|
+
"@redocly/openapi-core": "1.0.0-beta.128",
|
|
37
37
|
"assert-node-version": "^1.0.3",
|
|
38
38
|
"chokidar": "^3.5.1",
|
|
39
39
|
"colorette": "^1.2.0",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"react": "^17.0.1",
|
|
46
46
|
"react-dom": "^17.0.1",
|
|
47
47
|
"redoc": "~2.0.0",
|
|
48
|
+
"semver": "^7.5.1",
|
|
48
49
|
"simple-websocket": "^9.0.0",
|
|
49
50
|
"styled-components": "5.3.3",
|
|
50
51
|
"yargs": "17.0.1"
|
|
@@ -54,7 +55,8 @@
|
|
|
54
55
|
"@types/react": "^17.0.8",
|
|
55
56
|
"@types/react-dom": "^17.0.5",
|
|
56
57
|
"@types/styled-components": "^5.1.1",
|
|
57
|
-
"@types/yargs": "
|
|
58
|
+
"@types/yargs": "17.0.5",
|
|
59
|
+
"@types/semver": "^7.5.0",
|
|
58
60
|
"typescript": "^4.0.3"
|
|
59
61
|
}
|
|
60
62
|
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { ConfigFixture } from './../../__tests__/fixtures/config';
|
|
2
|
-
import { Document } from '@redocly/openapi-core';
|
|
3
|
-
import { firstDocument, secondDocument } from '../documents';
|
|
4
|
-
|
|
5
|
-
export const __redoclyClient = {
|
|
6
|
-
isAuthorizedWithRedocly: jest.fn().mockResolvedValue(true),
|
|
7
|
-
isAuthorizedWithRedoclyByRegion: jest.fn().mockResolvedValue(true),
|
|
8
|
-
login: jest.fn(),
|
|
9
|
-
registryApi: {
|
|
10
|
-
setAccessTokens: jest.fn(),
|
|
11
|
-
authStatus: jest.fn(),
|
|
12
|
-
prepareFileUpload: jest.fn().mockResolvedValue({
|
|
13
|
-
signedUploadUrl: 'signedUploadUrl',
|
|
14
|
-
filePath: 'filePath',
|
|
15
|
-
}),
|
|
16
|
-
pushApi: jest.fn(),
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const RedoclyClient = jest.fn(() => __redoclyClient);
|
|
21
|
-
export const loadConfig = jest.fn(() => ConfigFixture);
|
|
22
|
-
export const getMergedConfig = jest.fn();
|
|
23
|
-
export const lint = jest.fn();
|
|
24
|
-
export const bundle = jest.fn(() => ({ bundle: { parsed: null }, problems: null }));
|
|
25
|
-
export const getTotals = jest.fn(() => ({ errors: 0 }));
|
|
26
|
-
export const formatProblems = jest.fn();
|
|
27
|
-
export const slash = jest.fn();
|
|
28
|
-
export const findConfig = jest.fn();
|
|
29
|
-
export const doesYamlFileExist = jest.fn();
|
|
30
|
-
export const bundleDocument = jest.fn(() => Promise.resolve({ problems: {} }));
|
|
31
|
-
export const detectOpenAPI = jest.fn();
|
|
32
|
-
export const isAbsoluteUrl = jest.fn();
|
|
33
|
-
|
|
34
|
-
export class BaseResolver {
|
|
35
|
-
cache = new Map<string, Promise<Document | ResolveError>>();
|
|
36
|
-
|
|
37
|
-
getFiles = jest.fn();
|
|
38
|
-
resolveExternalRef = jest.fn();
|
|
39
|
-
loadExternalRef = jest.fn;
|
|
40
|
-
parseDocument = jest.fn();
|
|
41
|
-
resolveDocument = jest
|
|
42
|
-
.fn()
|
|
43
|
-
.mockImplementationOnce(() =>
|
|
44
|
-
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: firstDocument })
|
|
45
|
-
)
|
|
46
|
-
.mockImplementationOnce(() =>
|
|
47
|
-
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: secondDocument })
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class ResolveError extends Error {
|
|
52
|
-
constructor(public originalError: Error) {
|
|
53
|
-
super(originalError.message);
|
|
54
|
-
Object.setPrototypeOf(this, ResolveError.prototype);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export class YamlParseError extends Error {
|
|
59
|
-
constructor(public originalError: Error) {
|
|
60
|
-
super(originalError.message);
|
|
61
|
-
Object.setPrototypeOf(this, YamlParseError.prototype);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export enum OasVersion {
|
|
66
|
-
Version2 = 'oas2',
|
|
67
|
-
Version3_0 = 'oas3_0',
|
|
68
|
-
Version3_1 = 'oas3_1',
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export enum Oas3Operations {
|
|
72
|
-
get = 'get',
|
|
73
|
-
put = 'put',
|
|
74
|
-
post = 'post',
|
|
75
|
-
delete = 'delete',
|
|
76
|
-
options = 'options',
|
|
77
|
-
head = 'head',
|
|
78
|
-
patch = 'patch',
|
|
79
|
-
trace = 'trace',
|
|
80
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export const firstDocument = {
|
|
2
|
-
openapi: '3.0.0',
|
|
3
|
-
servers: [{ url: 'http://localhost:8080' }],
|
|
4
|
-
info: {
|
|
5
|
-
description: 'example test',
|
|
6
|
-
version: '1.0.0',
|
|
7
|
-
title: 'Swagger Petstore',
|
|
8
|
-
termsOfService: 'http://swagger.io/terms/',
|
|
9
|
-
license: {
|
|
10
|
-
name: 'Apache 2.0',
|
|
11
|
-
url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
paths: {
|
|
15
|
-
'/GETUser/{userId}': {
|
|
16
|
-
summary: 'get user by id',
|
|
17
|
-
description: 'user info',
|
|
18
|
-
servers: [{ url: '/user' }, { url: '/pet', description: 'pet server' }],
|
|
19
|
-
|
|
20
|
-
get: {
|
|
21
|
-
tags: ['pet'],
|
|
22
|
-
summary: 'Find pet by ID',
|
|
23
|
-
description: 'Returns a single pet',
|
|
24
|
-
operationId: 'getPetById',
|
|
25
|
-
servers: [{ url: '/pet' }],
|
|
26
|
-
},
|
|
27
|
-
parameters: [{ name: 'param1', in: 'header', schema: { description: 'string' } }],
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
components: {},
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const secondDocument = {
|
|
34
|
-
openapi: '3.0.0',
|
|
35
|
-
servers: [{ url: 'http://localhost:8080' }],
|
|
36
|
-
info: {
|
|
37
|
-
description: 'example test',
|
|
38
|
-
version: '1.0.0',
|
|
39
|
-
title: 'Swagger Petstore',
|
|
40
|
-
termsOfService: 'http://swagger.io/terms/',
|
|
41
|
-
license: {
|
|
42
|
-
name: 'Apache 2.0',
|
|
43
|
-
url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
post: {
|
|
47
|
-
'/GETUser/{userId}': {
|
|
48
|
-
summary: 'get user',
|
|
49
|
-
description: 'user information',
|
|
50
|
-
servers: [{ url: '/user' }, { url: '/pet', description: '' }],
|
|
51
|
-
|
|
52
|
-
get: {
|
|
53
|
-
tags: ['pet'],
|
|
54
|
-
summary: 'Find pet by ID',
|
|
55
|
-
description: 'Returns a single pet',
|
|
56
|
-
operationId: 'getPetById',
|
|
57
|
-
servers: [{ url: '/pet' }],
|
|
58
|
-
},
|
|
59
|
-
parameters: [{ name: 'param1', in: 'header', schema: { description: 'string' } }],
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
components: {},
|
|
63
|
-
};
|
package/src/__mocks__/fs.ts
DELETED
package/src/__mocks__/redoc.ts
DELETED
package/src/__mocks__/utils.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ConfigFixture } from '../__tests__/fixtures/config';
|
|
2
|
-
|
|
3
|
-
export const getFallbackApisOrExit = jest.fn((entrypoints) =>
|
|
4
|
-
entrypoints.map((path: string) => ({ path }))
|
|
5
|
-
);
|
|
6
|
-
export const dumpBundle = jest.fn(() => '');
|
|
7
|
-
export const slash = jest.fn();
|
|
8
|
-
export const pluralize = jest.fn();
|
|
9
|
-
export const getExecutionTime = jest.fn();
|
|
10
|
-
export const printExecutionTime = jest.fn();
|
|
11
|
-
export const printUnusedWarnings = jest.fn();
|
|
12
|
-
export const printLintTotals = jest.fn();
|
|
13
|
-
export const getOutputFileName = jest.fn(() => ({ outputFile: 'test.yaml', ext: 'yaml' }));
|
|
14
|
-
export const handleError = jest.fn();
|
|
15
|
-
export const exitWithError = jest.fn();
|
|
16
|
-
export const writeYaml = jest.fn();
|
|
17
|
-
export const loadConfigAndHandleErrors = jest.fn(() => ConfigFixture);
|
|
18
|
-
export const checkIfRulesetExist = jest.fn();
|
|
19
|
-
export const sortTopLevelKeysForOas = jest.fn((document) => document);
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { createStore, loadAndBundleSpec } from 'redoc';
|
|
2
|
-
import { renderToString } from 'react-dom/server';
|
|
3
|
-
import { handlerBuildCommand } from '../../commands/build-docs';
|
|
4
|
-
import { BuildDocsArgv } from '../../commands/build-docs/types';
|
|
5
|
-
import { getPageHTML } from '../../commands/build-docs/utils';
|
|
6
|
-
import { getFallbackApisOrExit } from '../../utils';
|
|
7
|
-
|
|
8
|
-
jest.mock('redoc');
|
|
9
|
-
jest.mock('fs');
|
|
10
|
-
jest.mock('../../utils');
|
|
11
|
-
|
|
12
|
-
const config = {
|
|
13
|
-
output: '',
|
|
14
|
-
cdn: false,
|
|
15
|
-
title: 'Test',
|
|
16
|
-
disableGoogleFont: false,
|
|
17
|
-
templateFileName: '',
|
|
18
|
-
templateOptions: {},
|
|
19
|
-
redocOptions: {},
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
jest.mock('react-dom/server', () => ({
|
|
23
|
-
renderToString: jest.fn(),
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
jest.mock('handlebars', () => ({
|
|
27
|
-
compile: jest.fn(() => jest.fn(() => '<html></html>')),
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
|
-
jest.mock('mkdirp', () => ({
|
|
31
|
-
sync: jest.fn(),
|
|
32
|
-
}));
|
|
33
|
-
|
|
34
|
-
describe('build-docs', () => {
|
|
35
|
-
it('should return correct html and call function for ssr', async () => {
|
|
36
|
-
const result = await getPageHTML({}, '../some-path/openapi.yaml', {
|
|
37
|
-
...config,
|
|
38
|
-
redocCurrentVersion: '2.0.0',
|
|
39
|
-
});
|
|
40
|
-
expect(renderToString).toBeCalledTimes(1);
|
|
41
|
-
expect(createStore).toBeCalledTimes(1);
|
|
42
|
-
expect(result).toBe('<html></html>');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should work correctly when calling handlerBuildCommand', async () => {
|
|
46
|
-
const processExitMock = jest.spyOn(process, 'exit').mockImplementation();
|
|
47
|
-
await handlerBuildCommand({
|
|
48
|
-
o: '',
|
|
49
|
-
cdn: false,
|
|
50
|
-
title: 'test',
|
|
51
|
-
disableGoogleFont: false,
|
|
52
|
-
template: '',
|
|
53
|
-
templateOptions: {},
|
|
54
|
-
theme: { openapi: {} },
|
|
55
|
-
api: '../some-path/openapi.yaml',
|
|
56
|
-
} as BuildDocsArgv);
|
|
57
|
-
expect(loadAndBundleSpec).toBeCalledTimes(1);
|
|
58
|
-
expect(getFallbackApisOrExit).toBeCalledTimes(1);
|
|
59
|
-
expect(processExitMock).toBeCalledTimes(0);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { lint, bundle, getTotals, getMergedConfig } from '@redocly/openapi-core';
|
|
2
|
-
|
|
3
|
-
import { handleBundle } from '../../commands/bundle';
|
|
4
|
-
import { handleError } from '../../utils';
|
|
5
|
-
import SpyInstance = jest.SpyInstance;
|
|
6
|
-
|
|
7
|
-
jest.mock('@redocly/openapi-core');
|
|
8
|
-
jest.mock('../../utils');
|
|
9
|
-
|
|
10
|
-
(getMergedConfig as jest.Mock).mockImplementation((config) => config);
|
|
11
|
-
|
|
12
|
-
describe('bundle', () => {
|
|
13
|
-
let processExitMock: SpyInstance;
|
|
14
|
-
let exitCb: any;
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
processExitMock = jest.spyOn(process, 'exit').mockImplementation();
|
|
18
|
-
jest.spyOn(process, 'once').mockImplementation((_e, cb) => {
|
|
19
|
-
exitCb = cb;
|
|
20
|
-
return process.on(_e, cb);
|
|
21
|
-
});
|
|
22
|
-
jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
(lint as jest.Mock).mockClear();
|
|
27
|
-
(bundle as jest.Mock).mockClear();
|
|
28
|
-
(getTotals as jest.Mock).mockReset();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('bundles definitions w/o linting', async () => {
|
|
32
|
-
const apis = ['foo.yaml', 'bar.yaml'];
|
|
33
|
-
|
|
34
|
-
await handleBundle(
|
|
35
|
-
{
|
|
36
|
-
apis,
|
|
37
|
-
ext: 'yaml',
|
|
38
|
-
format: 'codeframe',
|
|
39
|
-
},
|
|
40
|
-
'1.0.0'
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
expect(lint).toBeCalledTimes(0);
|
|
44
|
-
expect(bundle).toBeCalledTimes(apis.length);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('exits with code 0 when bundles definitions', async () => {
|
|
48
|
-
const apis = ['foo.yaml', 'bar.yaml', 'foobar.yaml'];
|
|
49
|
-
|
|
50
|
-
await handleBundle(
|
|
51
|
-
{
|
|
52
|
-
apis,
|
|
53
|
-
ext: 'yaml',
|
|
54
|
-
format: 'codeframe',
|
|
55
|
-
},
|
|
56
|
-
'1.0.0'
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
exitCb?.();
|
|
60
|
-
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('bundles definitions w/ linting', async () => {
|
|
64
|
-
const apis = ['foo.yaml', 'bar.yaml', 'foobar.yaml'];
|
|
65
|
-
|
|
66
|
-
(getTotals as jest.Mock).mockReturnValue({
|
|
67
|
-
errors: 0,
|
|
68
|
-
warnings: 0,
|
|
69
|
-
ignored: 0,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
await handleBundle(
|
|
73
|
-
{
|
|
74
|
-
apis,
|
|
75
|
-
ext: 'yaml',
|
|
76
|
-
format: 'codeframe',
|
|
77
|
-
lint: true,
|
|
78
|
-
},
|
|
79
|
-
'1.0.0'
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
expect(lint).toBeCalledTimes(apis.length);
|
|
83
|
-
expect(bundle).toBeCalledTimes(apis.length);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('exits with code 0 when bundles definitions w/linting w/o errors', async () => {
|
|
87
|
-
const apis = ['foo.yaml', 'bar.yaml', 'foobar.yaml'];
|
|
88
|
-
|
|
89
|
-
await handleBundle(
|
|
90
|
-
{
|
|
91
|
-
apis,
|
|
92
|
-
ext: 'yaml',
|
|
93
|
-
format: 'codeframe',
|
|
94
|
-
lint: true,
|
|
95
|
-
},
|
|
96
|
-
'1.0.0'
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
exitCb?.();
|
|
100
|
-
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('exits with code 1 when bundles definitions w/linting w/errors', async () => {
|
|
104
|
-
const apis = ['foo.yaml'];
|
|
105
|
-
|
|
106
|
-
(getTotals as jest.Mock).mockReturnValue({
|
|
107
|
-
errors: 1,
|
|
108
|
-
warnings: 0,
|
|
109
|
-
ignored: 0,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
await handleBundle(
|
|
113
|
-
{
|
|
114
|
-
apis,
|
|
115
|
-
ext: 'yaml',
|
|
116
|
-
format: 'codeframe',
|
|
117
|
-
lint: true,
|
|
118
|
-
},
|
|
119
|
-
'1.0.0'
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
expect(lint).toBeCalledTimes(apis.length);
|
|
123
|
-
exitCb?.();
|
|
124
|
-
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('handleError is called when bundles an invalid definition', async () => {
|
|
128
|
-
const apis = ['invalid.json'];
|
|
129
|
-
|
|
130
|
-
(bundle as jest.Mock).mockImplementationOnce(() => {
|
|
131
|
-
throw new Error('Invalid definition');
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
await handleBundle(
|
|
135
|
-
{
|
|
136
|
-
apis,
|
|
137
|
-
ext: 'json',
|
|
138
|
-
format: 'codeframe',
|
|
139
|
-
lint: false,
|
|
140
|
-
},
|
|
141
|
-
'1.0.0'
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
expect(handleError).toHaveBeenCalledTimes(1);
|
|
145
|
-
expect(handleError).toHaveBeenCalledWith(new Error('Invalid definition'), 'invalid.json');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it("handleError isn't called when bundles a valid definition", async () => {
|
|
149
|
-
const apis = ['foo.yaml'];
|
|
150
|
-
|
|
151
|
-
(getTotals as jest.Mock).mockReturnValue({
|
|
152
|
-
errors: 0,
|
|
153
|
-
warnings: 0,
|
|
154
|
-
ignored: 0,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
await handleBundle(
|
|
158
|
-
{
|
|
159
|
-
apis,
|
|
160
|
-
ext: 'yaml',
|
|
161
|
-
format: 'codeframe',
|
|
162
|
-
lint: false,
|
|
163
|
-
},
|
|
164
|
-
'1.0.0'
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
expect(handleError).toHaveBeenCalledTimes(0);
|
|
168
|
-
});
|
|
169
|
-
});
|