@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.
Files changed (51) hide show
  1. package/lib/__tests__/utils.test.js +19 -0
  2. package/lib/index.js +5 -1
  3. package/lib/update-version-notifier.d.ts +2 -0
  4. package/lib/update-version-notifier.js +100 -0
  5. package/lib/utils.d.ts +1 -0
  6. package/lib/utils.js +13 -5
  7. package/package.json +5 -3
  8. package/src/__mocks__/@redocly/openapi-core.ts +0 -80
  9. package/src/__mocks__/documents.ts +0 -63
  10. package/src/__mocks__/fs.ts +0 -6
  11. package/src/__mocks__/perf_hooks.ts +0 -3
  12. package/src/__mocks__/redoc.ts +0 -2
  13. package/src/__mocks__/utils.ts +0 -19
  14. package/src/__tests__/commands/build-docs.test.ts +0 -61
  15. package/src/__tests__/commands/bundle.test.ts +0 -169
  16. package/src/__tests__/commands/join.test.ts +0 -114
  17. package/src/__tests__/commands/lint.test.ts +0 -166
  18. package/src/__tests__/commands/push-region.test.ts +0 -51
  19. package/src/__tests__/commands/push.test.ts +0 -364
  20. package/src/__tests__/fixtures/config.ts +0 -21
  21. package/src/__tests__/utils.test.ts +0 -441
  22. package/src/assert-node-version.ts +0 -8
  23. package/src/commands/build-docs/index.ts +0 -56
  24. package/src/commands/build-docs/template.hbs +0 -23
  25. package/src/commands/build-docs/types.ts +0 -26
  26. package/src/commands/build-docs/utils.ts +0 -112
  27. package/src/commands/bundle.ts +0 -170
  28. package/src/commands/join.ts +0 -810
  29. package/src/commands/lint.ts +0 -161
  30. package/src/commands/login.ts +0 -21
  31. package/src/commands/preview-docs/index.ts +0 -183
  32. package/src/commands/preview-docs/preview-server/default.hbs +0 -24
  33. package/src/commands/preview-docs/preview-server/hot.js +0 -42
  34. package/src/commands/preview-docs/preview-server/oauth2-redirect.html +0 -21
  35. package/src/commands/preview-docs/preview-server/preview-server.ts +0 -156
  36. package/src/commands/preview-docs/preview-server/server.ts +0 -91
  37. package/src/commands/push.ts +0 -387
  38. package/src/commands/split/__tests__/fixtures/samples.json +0 -61
  39. package/src/commands/split/__tests__/fixtures/spec.json +0 -70
  40. package/src/commands/split/__tests__/fixtures/webhooks.json +0 -88
  41. package/src/commands/split/__tests__/index.test.ts +0 -137
  42. package/src/commands/split/index.ts +0 -378
  43. package/src/commands/split/types.ts +0 -85
  44. package/src/commands/stats.ts +0 -117
  45. package/src/custom.d.ts +0 -1
  46. package/src/index.ts +0 -431
  47. package/src/js-utils.ts +0 -17
  48. package/src/types.ts +0 -28
  49. package/src/utils.ts +0 -472
  50. package/tsconfig.json +0 -9
  51. 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 zero-dependency HTML-file', (yargs) => yargs
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,2 @@
1
+ export declare const notifyUpdateCliVersion: () => void;
2
+ export declare const cacheLatestVersion: () => void;
@@ -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.exitCode = 1;
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 \`openapi lint --generate-ignore-file\` to add all problems to the ignore file.\n`));
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
- exitWithError(e.message);
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.126",
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.126",
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": "16.0.2",
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
- };
@@ -1,6 +0,0 @@
1
- export const existsSync = jest.fn();
2
- export const readFileSync = jest.fn(() => '');
3
- export const statSync = jest.fn(() => ({ size: 0 }));
4
- export const createReadStream = jest.fn();
5
- export const writeFileSync = jest.fn();
6
- export const mkdirSync = jest.fn();
@@ -1,3 +0,0 @@
1
- export const performance = {
2
- now: jest.fn(),
3
- };
@@ -1,2 +0,0 @@
1
- export const loadAndBundleSpec = jest.fn(() => Promise.resolve({ openapi: '3.0.0' }));
2
- export const createStore = jest.fn(() => Promise.resolve({ toJS: jest.fn(() => '{}') }));
@@ -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
- });