@redocly/cli 1.0.0-beta.125 → 1.0.0-beta.127

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 (67) hide show
  1. package/lib/__mocks__/@redocly/openapi-core.d.ts +20 -2
  2. package/lib/__mocks__/@redocly/openapi-core.js +17 -1
  3. package/lib/__mocks__/utils.d.ts +12 -0
  4. package/lib/__mocks__/utils.js +3 -1
  5. package/lib/__tests__/commands/join.test.js +21 -0
  6. package/lib/__tests__/commands/lint.test.js +9 -0
  7. package/lib/__tests__/commands/push.test.js +16 -0
  8. package/lib/__tests__/fixtures/config.d.ts +10 -0
  9. package/lib/__tests__/fixtures/config.js +10 -0
  10. package/lib/__tests__/utils.test.js +151 -0
  11. package/lib/commands/build-docs/utils.js +6 -2
  12. package/lib/commands/bundle.js +3 -2
  13. package/lib/commands/join.d.ts +2 -0
  14. package/lib/commands/join.js +17 -1
  15. package/lib/commands/lint.js +4 -0
  16. package/lib/commands/preview-docs/index.js +1 -1
  17. package/lib/commands/push.js +3 -3
  18. package/lib/index.js +6 -0
  19. package/lib/update-version-notifier.d.ts +2 -0
  20. package/lib/update-version-notifier.js +100 -0
  21. package/lib/utils.d.ts +4 -1
  22. package/lib/utils.js +82 -13
  23. package/package.json +5 -3
  24. package/src/__mocks__/@redocly/openapi-core.ts +0 -66
  25. package/src/__mocks__/documents.ts +0 -63
  26. package/src/__mocks__/fs.ts +0 -6
  27. package/src/__mocks__/perf_hooks.ts +0 -3
  28. package/src/__mocks__/redoc.ts +0 -2
  29. package/src/__mocks__/utils.ts +0 -17
  30. package/src/__tests__/commands/build-docs.test.ts +0 -61
  31. package/src/__tests__/commands/bundle.test.ts +0 -169
  32. package/src/__tests__/commands/join.test.ts +0 -83
  33. package/src/__tests__/commands/lint.test.ts +0 -154
  34. package/src/__tests__/commands/push-region.test.ts +0 -51
  35. package/src/__tests__/commands/push.test.ts +0 -342
  36. package/src/__tests__/fixtures/config.ts +0 -11
  37. package/src/__tests__/utils.test.ts +0 -263
  38. package/src/assert-node-version.ts +0 -8
  39. package/src/commands/build-docs/index.ts +0 -56
  40. package/src/commands/build-docs/template.hbs +0 -23
  41. package/src/commands/build-docs/types.ts +0 -26
  42. package/src/commands/build-docs/utils.ts +0 -108
  43. package/src/commands/bundle.ts +0 -163
  44. package/src/commands/join.ts +0 -789
  45. package/src/commands/lint.ts +0 -154
  46. package/src/commands/login.ts +0 -21
  47. package/src/commands/preview-docs/index.ts +0 -182
  48. package/src/commands/preview-docs/preview-server/default.hbs +0 -24
  49. package/src/commands/preview-docs/preview-server/hot.js +0 -42
  50. package/src/commands/preview-docs/preview-server/oauth2-redirect.html +0 -21
  51. package/src/commands/preview-docs/preview-server/preview-server.ts +0 -156
  52. package/src/commands/preview-docs/preview-server/server.ts +0 -91
  53. package/src/commands/push.ts +0 -387
  54. package/src/commands/split/__tests__/fixtures/samples.json +0 -61
  55. package/src/commands/split/__tests__/fixtures/spec.json +0 -70
  56. package/src/commands/split/__tests__/fixtures/webhooks.json +0 -88
  57. package/src/commands/split/__tests__/index.test.ts +0 -137
  58. package/src/commands/split/index.ts +0 -378
  59. package/src/commands/split/types.ts +0 -85
  60. package/src/commands/stats.ts +0 -117
  61. package/src/custom.d.ts +0 -1
  62. package/src/index.ts +0 -429
  63. package/src/js-utils.ts +0 -17
  64. package/src/types.ts +0 -28
  65. package/src/utils.ts +0 -393
  66. package/tsconfig.json +0 -9
  67. package/tsconfig.tsbuildinfo +0 -1
@@ -1,5 +1,5 @@
1
1
  /// <reference types="jest" />
2
- import { Document, ResolveError } from '@redocly/openapi-core';
2
+ import { Document } from '@redocly/openapi-core';
3
3
  export declare const __redoclyClient: {
4
4
  isAuthorizedWithRedocly: jest.Mock<any, any>;
5
5
  isAuthorizedWithRedoclyByRegion: jest.Mock<any, any>;
@@ -31,6 +31,16 @@ export declare const loadConfig: jest.Mock<{
31
31
  saveIgnore: jest.Mock<any, any>;
32
32
  skipDecorators: jest.Mock<any, any>;
33
33
  ignore: null;
34
+ decorators: {
35
+ oas2: {};
36
+ oas3_0: {};
37
+ oas3_1: {};
38
+ };
39
+ preprocessors: {
40
+ oas2: {};
41
+ oas3_0: {};
42
+ oas3_1: {};
43
+ };
34
44
  };
35
45
  }, []>;
36
46
  export declare const getMergedConfig: jest.Mock<any, any>;
@@ -54,13 +64,21 @@ export declare const bundleDocument: jest.Mock<Promise<{
54
64
  export declare const detectOpenAPI: jest.Mock<any, any>;
55
65
  export declare const isAbsoluteUrl: jest.Mock<any, any>;
56
66
  export declare class BaseResolver {
57
- cache: Map<string, Promise<ResolveError | Document>>;
67
+ cache: Map<string, Promise<Document | ResolveError>>;
58
68
  getFiles: jest.Mock<any, any>;
59
69
  resolveExternalRef: jest.Mock<any, any>;
60
70
  loadExternalRef: typeof jest.fn;
61
71
  parseDocument: jest.Mock<any, any>;
62
72
  resolveDocument: jest.Mock<any, any>;
63
73
  }
74
+ export declare class ResolveError extends Error {
75
+ originalError: Error;
76
+ constructor(originalError: Error);
77
+ }
78
+ export declare class YamlParseError extends Error {
79
+ originalError: Error;
80
+ constructor(originalError: Error);
81
+ }
64
82
  export declare enum OasVersion {
65
83
  Version2 = "oas2",
66
84
  Version3_0 = "oas3_0",
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Oas3Operations = exports.OasVersion = exports.BaseResolver = exports.isAbsoluteUrl = exports.detectOpenAPI = exports.bundleDocument = exports.doesYamlFileExist = exports.findConfig = exports.slash = exports.formatProblems = exports.getTotals = exports.bundle = exports.lint = exports.getMergedConfig = exports.loadConfig = exports.RedoclyClient = exports.__redoclyClient = void 0;
3
+ exports.Oas3Operations = exports.OasVersion = exports.YamlParseError = exports.ResolveError = exports.BaseResolver = exports.isAbsoluteUrl = exports.detectOpenAPI = exports.bundleDocument = exports.doesYamlFileExist = exports.findConfig = exports.slash = exports.formatProblems = exports.getTotals = exports.bundle = exports.lint = exports.getMergedConfig = exports.loadConfig = exports.RedoclyClient = exports.__redoclyClient = void 0;
4
4
  const config_1 = require("./../../__tests__/fixtures/config");
5
5
  const documents_1 = require("../documents");
6
6
  exports.__redoclyClient = {
@@ -44,6 +44,22 @@ class BaseResolver {
44
44
  }
45
45
  }
46
46
  exports.BaseResolver = BaseResolver;
47
+ class ResolveError extends Error {
48
+ constructor(originalError) {
49
+ super(originalError.message);
50
+ this.originalError = originalError;
51
+ Object.setPrototypeOf(this, ResolveError.prototype);
52
+ }
53
+ }
54
+ exports.ResolveError = ResolveError;
55
+ class YamlParseError extends Error {
56
+ constructor(originalError) {
57
+ super(originalError.message);
58
+ this.originalError = originalError;
59
+ Object.setPrototypeOf(this, YamlParseError.prototype);
60
+ }
61
+ }
62
+ exports.YamlParseError = YamlParseError;
47
63
  var OasVersion;
48
64
  (function (OasVersion) {
49
65
  OasVersion["Version2"] = "oas2";
@@ -23,5 +23,17 @@ export declare const loadConfigAndHandleErrors: jest.Mock<{
23
23
  saveIgnore: jest.Mock<any, any>;
24
24
  skipDecorators: jest.Mock<any, any>;
25
25
  ignore: null;
26
+ decorators: {
27
+ oas2: {};
28
+ oas3_0: {};
29
+ oas3_1: {};
30
+ };
31
+ preprocessors: {
32
+ oas2: {};
33
+ oas3_0: {};
34
+ oas3_1: {};
35
+ };
26
36
  };
27
37
  }, []>;
38
+ export declare const checkIfRulesetExist: jest.Mock<any, any>;
39
+ export declare const sortTopLevelKeysForOas: jest.Mock<any, [document: any]>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.loadConfigAndHandleErrors = exports.writeYaml = exports.exitWithError = exports.handleError = exports.getOutputFileName = exports.printLintTotals = exports.printUnusedWarnings = exports.printExecutionTime = exports.getExecutionTime = exports.pluralize = exports.slash = exports.dumpBundle = exports.getFallbackApisOrExit = void 0;
3
+ exports.sortTopLevelKeysForOas = exports.checkIfRulesetExist = exports.loadConfigAndHandleErrors = exports.writeYaml = exports.exitWithError = exports.handleError = exports.getOutputFileName = exports.printLintTotals = exports.printUnusedWarnings = exports.printExecutionTime = exports.getExecutionTime = exports.pluralize = exports.slash = exports.dumpBundle = exports.getFallbackApisOrExit = void 0;
4
4
  const config_1 = require("../__tests__/fixtures/config");
5
5
  exports.getFallbackApisOrExit = jest.fn((entrypoints) => entrypoints.map((path) => ({ path })));
6
6
  exports.dumpBundle = jest.fn(() => '');
@@ -15,3 +15,5 @@ exports.handleError = jest.fn();
15
15
  exports.exitWithError = jest.fn();
16
16
  exports.writeYaml = jest.fn();
17
17
  exports.loadConfigAndHandleErrors = jest.fn(() => config_1.ConfigFixture);
18
+ exports.checkIfRulesetExist = jest.fn();
19
+ exports.sortTopLevelKeysForOas = jest.fn((document) => document);
@@ -13,6 +13,7 @@ const join_1 = require("../../commands/join");
13
13
  const utils_1 = require("../../utils");
14
14
  const colorette_1 = require("colorette");
15
15
  const openapi_core_1 = require("@redocly/openapi-core");
16
+ const openapi_core_2 = require("../../__mocks__/@redocly/openapi-core");
16
17
  jest.mock('../../utils');
17
18
  jest.mock('colorette');
18
19
  describe('handleJoin fails', () => {
@@ -60,4 +61,24 @@ describe('handleJoin fails', () => {
60
61
  }, 'cli-version');
61
62
  expect(utils_1.writeYaml).toHaveBeenCalledWith(expect.any(Object), 'output.yml', expect.any(Boolean));
62
63
  }));
64
+ it('should call skipDecorators and skipPreprocessors', () => __awaiter(void 0, void 0, void 0, function* () {
65
+ openapi_core_1.detectOpenAPI.mockReturnValue('oas3_0');
66
+ yield join_1.handleJoin({
67
+ apis: ['first.yaml', 'second.yaml'],
68
+ }, 'cli-version');
69
+ const config = openapi_core_2.loadConfig();
70
+ expect(config.styleguide.skipDecorators).toHaveBeenCalled();
71
+ expect(config.styleguide.skipPreprocessors).toHaveBeenCalled();
72
+ }));
73
+ it('should not call skipDecorators and skipPreprocessors', () => __awaiter(void 0, void 0, void 0, function* () {
74
+ openapi_core_1.detectOpenAPI.mockReturnValue('oas3_0');
75
+ yield join_1.handleJoin({
76
+ apis: ['first.yaml', 'second.yaml'],
77
+ decorate: true,
78
+ preprocess: true,
79
+ }, 'cli-version');
80
+ const config = openapi_core_2.loadConfig();
81
+ expect(config.styleguide.skipDecorators).not.toHaveBeenCalled();
82
+ expect(config.styleguide.skipPreprocessors).not.toHaveBeenCalled();
83
+ }));
63
84
  });
@@ -68,6 +68,15 @@ describe('handleLint', () => {
68
68
  yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { 'generate-ignore-file': true }), versionMock);
69
69
  expect(getMergedConfigMock).toHaveBeenCalled();
70
70
  }));
71
+ it('should check if ruleset exist', () => __awaiter(void 0, void 0, void 0, function* () {
72
+ yield lint_1.handleLint(argvMock, versionMock);
73
+ expect(utils_1.checkIfRulesetExist).toHaveBeenCalledTimes(1);
74
+ }));
75
+ it('should fail if apis not provided', () => __awaiter(void 0, void 0, void 0, function* () {
76
+ yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { apis: [] }), versionMock);
77
+ expect(utils_1.getFallbackApisOrExit).toHaveBeenCalledTimes(1);
78
+ expect(utils_1.exitWithError).toHaveBeenCalledWith('No APIs were provided');
79
+ }));
71
80
  });
72
81
  describe('loop through entrypints and lint stage', () => {
73
82
  it('should call getMergedConfig and lint ', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -173,6 +173,22 @@ describe('push', () => {
173
173
  expect(utils_1.exitWithError).toBeCalledTimes(1);
174
174
  expect(utils_1.exitWithError).toHaveBeenLastCalledWith('Api not found. Please make sure you have provided the correct data in the config file.');
175
175
  }));
176
+ it('push should work and encode name with spaces', () => __awaiter(void 0, void 0, void 0, function* () {
177
+ const encodeURIComponentSpy = jest.spyOn(global, 'encodeURIComponent');
178
+ utils_1.loadConfigAndHandleErrors.mockImplementation(() => {
179
+ return Object.assign(Object.assign({}, config_1.ConfigFixture), { organization: 'test_org', apis: { 'my test api@v1': { root: 'path' } } });
180
+ });
181
+ yield push_1.handlePush({
182
+ upsert: true,
183
+ destination: 'my test api@v1',
184
+ branchName: 'test',
185
+ public: true,
186
+ 'batch-id': '123',
187
+ 'batch-size': 2,
188
+ });
189
+ expect(encodeURIComponentSpy).toHaveReturnedWith('my%20test%20api');
190
+ expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
191
+ }));
176
192
  });
177
193
  describe('transformPush', () => {
178
194
  it('should adapt the existing syntax', () => {
@@ -8,5 +8,15 @@ export declare const ConfigFixture: {
8
8
  saveIgnore: jest.Mock<any, any>;
9
9
  skipDecorators: jest.Mock<any, any>;
10
10
  ignore: null;
11
+ decorators: {
12
+ oas2: {};
13
+ oas3_0: {};
14
+ oas3_1: {};
15
+ };
16
+ preprocessors: {
17
+ oas2: {};
18
+ oas3_0: {};
19
+ oas3_1: {};
20
+ };
11
21
  };
12
22
  };
@@ -10,5 +10,15 @@ exports.ConfigFixture = {
10
10
  saveIgnore: jest.fn(),
11
11
  skipDecorators: jest.fn(),
12
12
  ignore: null,
13
+ decorators: {
14
+ oas2: {},
15
+ oas3_0: {},
16
+ oas3_1: {},
17
+ },
18
+ preprocessors: {
19
+ oas2: {},
20
+ oas3_0: {},
21
+ oas3_1: {},
22
+ },
13
23
  },
14
24
  };
@@ -14,6 +14,7 @@ const openapi_core_1 = require("@redocly/openapi-core");
14
14
  const colorette_1 = require("colorette");
15
15
  const fs_1 = require("fs");
16
16
  const path = require("path");
17
+ const process = require("process");
17
18
  jest.mock('os');
18
19
  jest.mock('colorette');
19
20
  jest.mock('fs');
@@ -213,3 +214,153 @@ describe('langToExt', () => {
213
214
  expect(utils_1.langToExt('JavaScript')).toBe('.js');
214
215
  });
215
216
  });
217
+ describe('sorTopLevelKeysForOas', () => {
218
+ it('should sort oas3 top level keys', () => {
219
+ const openApi = {
220
+ openapi: '3.0.0',
221
+ components: {},
222
+ security: [],
223
+ tags: [],
224
+ servers: [],
225
+ paths: {},
226
+ info: {},
227
+ externalDocs: {},
228
+ webhooks: [],
229
+ 'x-webhooks': [],
230
+ jsonSchemaDialect: '',
231
+ };
232
+ const orderedKeys = [
233
+ 'openapi',
234
+ 'info',
235
+ 'jsonSchemaDialect',
236
+ 'servers',
237
+ 'security',
238
+ 'tags',
239
+ 'externalDocs',
240
+ 'paths',
241
+ 'webhooks',
242
+ 'x-webhooks',
243
+ 'components',
244
+ ];
245
+ const result = utils_1.sortTopLevelKeysForOas(openApi);
246
+ Object.keys(result).forEach((key, index) => {
247
+ expect(key).toEqual(orderedKeys[index]);
248
+ });
249
+ });
250
+ it('should sort oas2 top level keys', () => {
251
+ const openApi = {
252
+ swagger: '2.0.0',
253
+ security: [],
254
+ tags: [],
255
+ paths: {},
256
+ info: {},
257
+ externalDocs: {},
258
+ host: '',
259
+ basePath: '',
260
+ securityDefinitions: [],
261
+ schemes: [],
262
+ consumes: [],
263
+ parameters: [],
264
+ produces: [],
265
+ definitions: [],
266
+ responses: [],
267
+ };
268
+ const orderedKeys = [
269
+ 'swagger',
270
+ 'info',
271
+ 'host',
272
+ 'basePath',
273
+ 'schemes',
274
+ 'consumes',
275
+ 'produces',
276
+ 'security',
277
+ 'tags',
278
+ 'externalDocs',
279
+ 'paths',
280
+ 'definitions',
281
+ 'parameters',
282
+ 'responses',
283
+ 'securityDefinitions',
284
+ ];
285
+ const result = utils_1.sortTopLevelKeysForOas(openApi);
286
+ Object.keys(result).forEach((key, index) => {
287
+ expect(key).toEqual(orderedKeys[index]);
288
+ });
289
+ });
290
+ });
291
+ describe('handleErrors', () => {
292
+ const ref = 'openapi/test.yaml';
293
+ const redColoretteMocks = colorette_1.red;
294
+ beforeEach(() => {
295
+ jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
296
+ jest.spyOn(process, 'exit').mockImplementation((code) => code);
297
+ redColoretteMocks.mockImplementation((text) => text);
298
+ });
299
+ afterEach(() => {
300
+ jest.clearAllMocks();
301
+ });
302
+ it('should handle ResolveError', () => {
303
+ const resolveError = new openapi_core_1.ResolveError(new Error('File not found'));
304
+ utils_1.handleError(resolveError, ref);
305
+ expect(redColoretteMocks).toHaveBeenCalledTimes(1);
306
+ expect(process.exit).toHaveBeenCalledWith(1);
307
+ expect(process.stderr.write).toHaveBeenCalledWith(`Failed to resolve api definition at openapi/test.yaml:\n\n - File not found.\n\n`);
308
+ });
309
+ it('should handle YamlParseError', () => {
310
+ const yamlParseError = new openapi_core_1.YamlParseError(new Error('Invalid yaml'), {});
311
+ utils_1.handleError(yamlParseError, ref);
312
+ expect(redColoretteMocks).toHaveBeenCalledTimes(1);
313
+ expect(process.exit).toHaveBeenCalledWith(1);
314
+ expect(process.stderr.write).toHaveBeenCalledWith(`Failed to parse api definition at openapi/test.yaml:\n\n - Invalid yaml.\n\n`);
315
+ });
316
+ it('should handle CircularJSONNotSupportedError', () => {
317
+ const circularError = new utils_1.CircularJSONNotSupportedError(new Error('Circular json'));
318
+ utils_1.handleError(circularError, ref);
319
+ expect(process.exit).toHaveBeenCalledWith(1);
320
+ expect(process.stderr.write).toHaveBeenCalledWith(`Detected circular reference which can't be converted to JSON.\n` +
321
+ `Try to use ${colorette_1.blue('yaml')} output or remove ${colorette_1.blue('--dereferenced')}.\n\n`);
322
+ });
323
+ it('should throw unknown error', () => {
324
+ const testError = new Error('Test error');
325
+ try {
326
+ utils_1.handleError(testError, ref);
327
+ }
328
+ catch (e) {
329
+ expect(e).toEqual(testError);
330
+ }
331
+ expect(process.stderr.write).toHaveBeenCalledWith(`Something went wrong when processing openapi/test.yaml:\n\n - Test error.\n\n`);
332
+ });
333
+ });
334
+ describe('checkIfRulesetExist', () => {
335
+ beforeEach(() => {
336
+ jest.spyOn(process, 'exit').mockImplementation((code) => code);
337
+ });
338
+ afterEach(() => {
339
+ jest.clearAllMocks();
340
+ });
341
+ it('should exit if rules not provided', () => {
342
+ const rules = {
343
+ oas2: {},
344
+ oas3_0: {},
345
+ oas3_1: {},
346
+ };
347
+ utils_1.checkIfRulesetExist(rules);
348
+ expect(process.exit).toHaveBeenCalledWith(1);
349
+ });
350
+ it('should not exit if rules provided', () => {
351
+ const rules = {
352
+ oas2: { 'operation-4xx-response': 'error' },
353
+ oas3_0: {},
354
+ oas3_1: {},
355
+ };
356
+ utils_1.checkIfRulesetExist(rules);
357
+ expect(process.exit).not.toHaveBeenCalled();
358
+ });
359
+ });
360
+ describe('cleanColors', () => {
361
+ it('should remove colors from string', () => {
362
+ const stringWithColors = `String for ${colorette_1.red('test')}`;
363
+ const result = utils_1.cleanColors(stringWithColors);
364
+ expect(result).not.toMatch(/\x1b\[\d+m/g);
365
+ });
366
+ });
@@ -40,7 +40,7 @@ function getObjectOrJSON(openapiOptions, config) {
40
40
  break;
41
41
  default: {
42
42
  if (config) {
43
- process.stderr.write(`Found ${config.configFile} and using theme.openapi options`);
43
+ process.stderr.write(`Found ${config.configFile} and using theme.openapi options\n`);
44
44
  return config.theme.openapi ? config.theme.openapi : {};
45
45
  }
46
46
  return {};
@@ -58,7 +58,11 @@ function getPageHTML(api, pathToApi, { cdn, title, disableGoogleFont, templateFi
58
58
  const html = server_1.renderToString(sheet.collectStyles(react_1.createElement(redoc_1.Redoc, { store })));
59
59
  const state = yield store.toJS();
60
60
  const css = sheet.getStyleTags();
61
- templateFileName = templateFileName ? templateFileName : path_1.join(__dirname, './template.hbs');
61
+ templateFileName = templateFileName
62
+ ? templateFileName
63
+ : (redocOptions === null || redocOptions === void 0 ? void 0 : redocOptions.htmlTemplate)
64
+ ? redocOptions.htmlTemplate
65
+ : path_1.join(__dirname, './template.hbs');
62
66
  const template = handlebars_1.compile(fs_1.readFileSync(templateFileName).toString());
63
67
  return template({
64
68
  redocHTML: `
@@ -47,6 +47,7 @@ function handleBundle(argv, version) {
47
47
  styleguide.skipPreprocessors(argv['skip-preprocessor']);
48
48
  styleguide.skipDecorators(argv['skip-decorator']);
49
49
  if (argv.lint) {
50
+ utils_1.checkIfRulesetExist(styleguide.rules);
50
51
  if (config.styleguide.recommendedFallback) {
51
52
  process.stderr.write(`No configurations were provided -- using built in ${colorette_1.blue('recommended')} configuration by default.\n\n`);
52
53
  }
@@ -78,11 +79,11 @@ function handleBundle(argv, version) {
78
79
  const { outputFile, ext } = utils_1.getOutputFileName(path, apis.length, argv.output, argv.ext);
79
80
  if (fileTotals.errors === 0 || argv.force) {
80
81
  if (!argv.output) {
81
- const output = utils_1.dumpBundle(result.parsed, argv.ext || 'yaml', argv.dereferenced);
82
+ const output = utils_1.dumpBundle(utils_1.sortTopLevelKeysForOas(result.parsed), argv.ext || 'yaml', argv.dereferenced);
82
83
  process.stdout.write(output);
83
84
  }
84
85
  else {
85
- const output = utils_1.dumpBundle(result.parsed, ext, argv.dereferenced);
86
+ const output = utils_1.dumpBundle(utils_1.sortTopLevelKeysForOas(result.parsed), ext, argv.dereferenced);
86
87
  utils_1.saveBundle(outputFile, output);
87
88
  }
88
89
  }
@@ -1,6 +1,8 @@
1
1
  declare type JoinArgv = {
2
2
  apis: string[];
3
3
  lint?: boolean;
4
+ decorate?: boolean;
5
+ preprocess?: boolean;
4
6
  'prefix-tags-with-info-prop'?: string;
5
7
  'prefix-tags-with-filename'?: boolean;
6
8
  'prefix-components-with-info-prop'?: string;
@@ -41,6 +41,22 @@ function handleJoin(argv, packageVersion) {
41
41
  const apis = yield utils_1.getFallbackApisOrExit(argv.apis, config);
42
42
  const externalRefResolver = new openapi_core_1.BaseResolver(config.resolve);
43
43
  const documents = yield Promise.all(apis.map(({ path }) => externalRefResolver.resolveDocument(null, path, true)));
44
+ if (!argv.decorate) {
45
+ const decorators = new Set([
46
+ ...Object.keys(config.styleguide.decorators.oas3_0),
47
+ ...Object.keys(config.styleguide.decorators.oas3_1),
48
+ ...Object.keys(config.styleguide.decorators.oas2),
49
+ ]);
50
+ config.styleguide.skipDecorators(Array.from(decorators));
51
+ }
52
+ if (!argv.preprocess) {
53
+ const preprocessors = new Set([
54
+ ...Object.keys(config.styleguide.preprocessors.oas3_0),
55
+ ...Object.keys(config.styleguide.preprocessors.oas3_1),
56
+ ...Object.keys(config.styleguide.preprocessors.oas2),
57
+ ]);
58
+ config.styleguide.skipPreprocessors(Array.from(preprocessors));
59
+ }
44
60
  const bundleResults = yield Promise.all(documents.map((document) => openapi_core_1.bundleDocument({
45
61
  document,
46
62
  config: config.styleguide,
@@ -120,7 +136,7 @@ function handleJoin(argv, packageVersion) {
120
136
  if (potentialConflictsTotal) {
121
137
  return utils_1.exitWithError(`Please fix conflicts before running ${colorette_1.yellow('join')}.`);
122
138
  }
123
- utils_1.writeYaml(joinedDef, specFilename, noRefs);
139
+ utils_1.writeYaml(utils_1.sortTopLevelKeysForOas(joinedDef), specFilename, noRefs);
124
140
  utils_1.printExecutionTime('join', startedAt, specFilename);
125
141
  function populateTags({ api, apiFilename, tags, potentialConflicts, tagsPrefix, componentsPrefix, }) {
126
142
  if (!joinedDef.hasOwnProperty(Tags)) {
@@ -25,6 +25,9 @@ function handleLint(argv, version) {
25
25
  processRawConfig: lintConfigCallback(argv, version),
26
26
  });
27
27
  const apis = yield utils_1.getFallbackApisOrExit(argv.apis, config);
28
+ if (!apis.length) {
29
+ return utils_1.exitWithError('No APIs were provided');
30
+ }
28
31
  if (argv['generate-ignore-file']) {
29
32
  config.styleguide.ignore = {}; // clear ignore
30
33
  }
@@ -36,6 +39,7 @@ function handleLint(argv, version) {
36
39
  const startedAt = perf_hooks_1.performance.now();
37
40
  const resolvedConfig = openapi_core_1.getMergedConfig(config, alias);
38
41
  const { styleguide } = resolvedConfig;
42
+ utils_1.checkIfRulesetExist(styleguide.rules);
39
43
  styleguide.skipRules(argv['skip-rule']);
40
44
  styleguide.skipPreprocessors(argv['skip-preprocessor']);
41
45
  if (styleguide.recommendedFallback) {
@@ -103,7 +103,7 @@ function previewDocs(argv) {
103
103
  styleguide.skipPreprocessors(argv['skip-preprocessor']);
104
104
  styleguide.skipDecorators(argv['skip-decorator']);
105
105
  const referenceDocs = (_a = resolvedConfig.theme) === null || _a === void 0 ? void 0 : _a.openapi;
106
- redocOptions = Object.assign(Object.assign({}, referenceDocs), { useCommunityEdition: argv['use-community-edition'] || (referenceDocs === null || referenceDocs === void 0 ? void 0 : referenceDocs.useCommunityEdition), licenseKey: process.env.REDOCLY_LICENSE_KEY || (referenceDocs === null || referenceDocs === void 0 ? void 0 : referenceDocs.licenseKey) });
106
+ redocOptions = Object.assign(Object.assign({}, referenceDocs), { useCommunityEdition: argv['use-community-edition'] || (referenceDocs === null || referenceDocs === void 0 ? void 0 : referenceDocs.useCommunityEdition), licenseKey: process.env.REDOCLY_LICENSE_KEY || (referenceDocs === null || referenceDocs === void 0 ? void 0 : referenceDocs.licenseKey), whiteLabel: true });
107
107
  return resolvedConfig;
108
108
  });
109
109
  }
@@ -70,6 +70,7 @@ function handlePush(argv) {
70
70
  const resolvedConfig = openapi_core_1.getMergedConfig(config, apiNameAndVersion);
71
71
  resolvedConfig.styleguide.skipDecorators(argv['skip-decorator']);
72
72
  const [name, version = DEFAULT_VERSION] = apiNameAndVersion.split('@');
73
+ const encodedName = encodeURIComponent(name);
73
74
  try {
74
75
  let rootFilePath = '';
75
76
  const filePaths = [];
@@ -80,7 +81,7 @@ function handlePush(argv) {
80
81
  for (const file of filesToUpload.files) {
81
82
  const { signedUploadUrl, filePath } = yield client.registryApi.prepareFileUpload({
82
83
  organizationId,
83
- name,
84
+ name: encodedName,
84
85
  version,
85
86
  filesHash,
86
87
  filename: file.keyOnS3,
@@ -101,7 +102,7 @@ function handlePush(argv) {
101
102
  process.stdout.write('\n');
102
103
  yield client.registryApi.pushApi({
103
104
  organizationId,
104
- name,
105
+ name: encodedName,
105
106
  version,
106
107
  rootFilePath,
107
108
  filePaths,
@@ -234,7 +235,6 @@ function parseDestination(destination) {
234
235
  function getDestinationProps(destination, organization) {
235
236
  const groups = destination && parseDestination(destination);
236
237
  if (groups) {
237
- groups.name && (groups.name = encodeURIComponent(groups.name));
238
238
  return {
239
239
  organizationId: groups.organizationId || organization,
240
240
  name: groups.name,
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: {
@@ -68,6 +71,8 @@ yargs
68
71
  })
69
72
  .option({
70
73
  lint: { description: 'Lint definitions', type: 'boolean', default: false },
74
+ decorate: { description: 'Run decorators', type: 'boolean', default: false },
75
+ preprocess: { description: 'Run preprocessors', type: 'boolean', default: false },
71
76
  'prefix-tags-with-info-prop': {
72
77
  description: 'Prefix tags with property value from info object.',
73
78
  requiresArg: true,
@@ -376,4 +381,5 @@ yargs
376
381
  }))
377
382
  .completion('completion', 'Generate completion script.')
378
383
  .demandCommand(1)
384
+ .middleware([update_version_notifier_1.notifyUpdateCliVersion])
379
385
  .strict().argv;
@@ -0,0 +1,2 @@
1
+ export declare const notifyUpdateCliVersion: () => void;
2
+ export declare const cacheLatestVersion: () => void;