@redocly/cli 1.0.0-beta.109 → 1.0.0-beta.111

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 (45) hide show
  1. package/lib/__mocks__/fs.d.ts +2 -0
  2. package/lib/__mocks__/fs.js +3 -1
  3. package/lib/__mocks__/redoc.d.ts +7 -0
  4. package/lib/__mocks__/redoc.js +5 -0
  5. package/lib/__tests__/commands/build-docs.test.d.ts +1 -0
  6. package/lib/__tests__/commands/build-docs.test.js +61 -0
  7. package/lib/__tests__/commands/lint.test.js +10 -2
  8. package/lib/__tests__/commands/push.test.js +28 -0
  9. package/lib/__tests__/utils.test.js +21 -0
  10. package/lib/commands/build-docs/index.d.ts +2 -0
  11. package/lib/commands/build-docs/index.js +50 -0
  12. package/lib/commands/build-docs/template.hbs +23 -0
  13. package/lib/commands/build-docs/types.d.ts +25 -0
  14. package/lib/commands/build-docs/types.js +2 -0
  15. package/lib/commands/build-docs/utils.d.ts +8 -0
  16. package/lib/commands/build-docs/utils.js +100 -0
  17. package/lib/commands/bundle.js +1 -1
  18. package/lib/commands/lint.js +5 -1
  19. package/lib/commands/preview-docs/index.d.ts +1 -1
  20. package/lib/commands/preview-docs/index.js +1 -1
  21. package/lib/commands/push.d.ts +1 -0
  22. package/lib/commands/push.js +15 -3
  23. package/lib/commands/stats.js +1 -1
  24. package/lib/index.js +59 -0
  25. package/lib/utils.js +8 -2
  26. package/package.json +13 -6
  27. package/src/__mocks__/fs.ts +2 -0
  28. package/src/__mocks__/redoc.ts +2 -0
  29. package/src/__tests__/commands/build-docs.test.ts +61 -0
  30. package/src/__tests__/commands/lint.test.ts +10 -2
  31. package/src/__tests__/commands/push.test.ts +33 -1
  32. package/src/__tests__/utils.test.ts +14 -1
  33. package/src/commands/build-docs/index.ts +49 -0
  34. package/src/commands/build-docs/template.hbs +23 -0
  35. package/src/commands/build-docs/types.ts +26 -0
  36. package/src/commands/build-docs/utils.ts +112 -0
  37. package/src/commands/bundle.ts +1 -1
  38. package/src/commands/lint.ts +5 -5
  39. package/src/commands/preview-docs/index.ts +2 -2
  40. package/src/commands/push.ts +17 -3
  41. package/src/commands/stats.ts +1 -1
  42. package/src/custom.d.ts +1 -0
  43. package/src/index.ts +67 -0
  44. package/src/utils.ts +8 -1
  45. package/tsconfig.tsbuildinfo +1 -1
@@ -5,3 +5,5 @@ export declare const statSync: jest.Mock<{
5
5
  size: number;
6
6
  }, []>;
7
7
  export declare const createReadStream: jest.Mock<any, any>;
8
+ export declare const writeFileSync: jest.Mock<any, any>;
9
+ export declare const mkdirSync: jest.Mock<any, any>;
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createReadStream = exports.statSync = exports.readFileSync = exports.existsSync = void 0;
3
+ exports.mkdirSync = exports.writeFileSync = exports.createReadStream = exports.statSync = exports.readFileSync = exports.existsSync = void 0;
4
4
  exports.existsSync = jest.fn();
5
5
  exports.readFileSync = jest.fn(() => '');
6
6
  exports.statSync = jest.fn(() => ({ size: 0 }));
7
7
  exports.createReadStream = jest.fn();
8
+ exports.writeFileSync = jest.fn();
9
+ exports.mkdirSync = jest.fn();
@@ -0,0 +1,7 @@
1
+ /// <reference types="jest" />
2
+ export declare const loadAndBundleSpec: jest.Mock<Promise<{
3
+ openapi: string;
4
+ }>, []>;
5
+ export declare const createStore: jest.Mock<Promise<{
6
+ toJS: jest.Mock<string, []>;
7
+ }>, []>;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createStore = exports.loadAndBundleSpec = void 0;
4
+ exports.loadAndBundleSpec = jest.fn(() => Promise.resolve({ openapi: '3.0.0' }));
5
+ exports.createStore = jest.fn(() => Promise.resolve({ toJS: jest.fn(() => '{}') }));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
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
+ const redoc_1 = require("redoc");
13
+ const server_1 = require("react-dom/server");
14
+ const build_docs_1 = require("../../commands/build-docs");
15
+ const utils_1 = require("../../commands/build-docs/utils");
16
+ const utils_2 = require("../../utils");
17
+ jest.mock('redoc');
18
+ jest.mock('fs');
19
+ jest.mock('../../utils');
20
+ const config = {
21
+ output: '',
22
+ cdn: false,
23
+ title: 'Test',
24
+ disableGoogleFont: false,
25
+ templateFileName: '',
26
+ templateOptions: {},
27
+ redocOptions: {},
28
+ };
29
+ jest.mock('react-dom/server', () => ({
30
+ renderToString: jest.fn(),
31
+ }));
32
+ jest.mock('handlebars', () => ({
33
+ compile: jest.fn(() => jest.fn(() => '<html></html>')),
34
+ }));
35
+ jest.mock('mkdirp', () => ({
36
+ sync: jest.fn(),
37
+ }));
38
+ describe('build-docs', () => {
39
+ it('should return correct html and call function for ssr', () => __awaiter(void 0, void 0, void 0, function* () {
40
+ const result = yield utils_1.getPageHTML({}, '../some-path/openapi.yaml', Object.assign(Object.assign({}, config), { redocCurrentVersion: '2.0.0' }));
41
+ expect(server_1.renderToString).toBeCalledTimes(1);
42
+ expect(redoc_1.createStore).toBeCalledTimes(1);
43
+ expect(result).toBe('<html></html>');
44
+ }));
45
+ it('should work correctly when calling handlerBuildCommand', () => __awaiter(void 0, void 0, void 0, function* () {
46
+ const processExitMock = jest.spyOn(process, 'exit').mockImplementation();
47
+ yield build_docs_1.handlerBuildCommand({
48
+ o: '',
49
+ cdn: false,
50
+ title: 'test',
51
+ disableGoogleFont: false,
52
+ template: '',
53
+ templateOptions: {},
54
+ features: { openapi: {} },
55
+ api: '../some-path/openapi.yaml',
56
+ });
57
+ expect(redoc_1.loadAndBundleSpec).toBeCalledTimes(1);
58
+ expect(utils_2.getFallbackApisOrExit).toBeCalledTimes(1);
59
+ expect(processExitMock).toBeCalledTimes(0);
60
+ }));
61
+ });
@@ -49,12 +49,20 @@ describe('handleLint', () => {
49
49
  }));
50
50
  it('should call loadConfig and getFallbackApisOrExit', () => __awaiter(void 0, void 0, void 0, function* () {
51
51
  yield lint_1.handleLint(argvMock, versionMock);
52
- expect(openapi_core_1.loadConfig).toHaveBeenCalledWith(undefined, undefined, undefined);
52
+ expect(openapi_core_1.loadConfig).toHaveBeenCalledWith({
53
+ configPath: undefined,
54
+ customExtends: undefined,
55
+ processRawConfig: undefined,
56
+ });
53
57
  expect(utils_1.getFallbackApisOrExit).toHaveBeenCalled();
54
58
  }));
55
59
  it('should call loadConfig with args if such exist', () => __awaiter(void 0, void 0, void 0, function* () {
56
60
  yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { config: 'redocly.yaml', extends: ['some/path'] }), versionMock);
57
- expect(openapi_core_1.loadConfig).toHaveBeenCalledWith('redocly.yaml', ['some/path'], undefined);
61
+ expect(openapi_core_1.loadConfig).toHaveBeenCalledWith({
62
+ configPath: 'redocly.yaml',
63
+ customExtends: ['some/path'],
64
+ processRawConfig: undefined,
65
+ });
58
66
  }));
59
67
  it('should call mergedConfig with clear ignore if `generate-ignore-file` argv', () => __awaiter(void 0, void 0, void 0, function* () {
60
68
  yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { 'generate-ignore-file': true }), versionMock);
@@ -9,9 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const fs = require("fs");
12
13
  const openapi_core_1 = require("@redocly/openapi-core");
13
14
  const utils_1 = require("../../utils");
14
15
  const push_1 = require("../../commands/push");
16
+ const config_1 = require("../fixtures/config");
15
17
  jest.mock('fs');
16
18
  jest.mock('node-fetch', () => ({
17
19
  default: jest.fn(() => ({
@@ -76,6 +78,32 @@ describe('push', () => {
76
78
  });
77
79
  expect(utils_1.exitWithError).toBeCalledTimes(1);
78
80
  }));
81
+ it('push with --files', () => __awaiter(void 0, void 0, void 0, function* () {
82
+ openapi_core_1.loadConfig.mockImplementation(({ files }) => {
83
+ return Object.assign(Object.assign({}, config_1.ConfigFixture), { files });
84
+ });
85
+ //@ts-ignore
86
+ fs.statSync.mockImplementation(() => {
87
+ return { isDirectory: () => false, size: 10 };
88
+ });
89
+ yield push_1.handlePush({
90
+ upsert: true,
91
+ api: 'spec.json',
92
+ destination: '@org/my-api@1.0.0',
93
+ public: true,
94
+ files: ['./resouces/1.md', './resouces/2.md'],
95
+ });
96
+ expect(redoclyClient.registryApi.pushApi).toHaveBeenLastCalledWith({
97
+ filePaths: ['filePath', 'filePath', 'filePath'],
98
+ isUpsert: true,
99
+ isPublic: true,
100
+ name: 'my-api',
101
+ organizationId: 'org',
102
+ rootFilePath: 'filePath',
103
+ version: '1.0.0',
104
+ });
105
+ expect(redoclyClient.registryApi.prepareFileUpload).toBeCalledTimes(3);
106
+ }));
79
107
  });
80
108
  describe('transformPush', () => {
81
109
  it('should adapt the existing syntax', () => {
@@ -1,4 +1,13 @@
1
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
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  const utils_1 = require("../utils");
4
13
  const colorette_1 = require("colorette");
@@ -41,6 +50,18 @@ describe('pathToFilename', () => {
41
50
  expect(processedPath).toEqual('user_createWithList');
42
51
  });
43
52
  });
53
+ describe('getFallbackApisOrExit', () => {
54
+ it('should find alias by filename', () => __awaiter(void 0, void 0, void 0, function* () {
55
+ const entry = yield utils_1.getFallbackApisOrExit(['./test.yaml'], {
56
+ apis: {
57
+ main: {
58
+ root: 'test.yaml',
59
+ },
60
+ },
61
+ });
62
+ expect(entry).toEqual([{ path: './test.yaml', alias: 'main' }]);
63
+ }));
64
+ });
44
65
  describe('printConfigLintTotals', () => {
45
66
  const totalProblemsMock = {
46
67
  errors: 1,
@@ -0,0 +1,2 @@
1
+ import type { BuildDocsArgv } from './types';
2
+ export declare const handlerBuildCommand: (argv: BuildDocsArgv) => Promise<void>;
@@ -0,0 +1,50 @@
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.handlerBuildCommand = void 0;
13
+ const redoc_1 = require("redoc");
14
+ const path_1 = require("path");
15
+ const fs_1 = require("fs");
16
+ const perf_hooks_1 = require("perf_hooks");
17
+ const utils_1 = require("./utils");
18
+ const utils_2 = require("../../utils");
19
+ const openapi_core_1 = require("@redocly/openapi-core");
20
+ const handlerBuildCommand = (argv) => __awaiter(void 0, void 0, void 0, function* () {
21
+ var _a;
22
+ const startedAt = perf_hooks_1.performance.now();
23
+ const configFromFile = yield openapi_core_1.loadConfig({ configPath: argv.config });
24
+ const config = openapi_core_1.getMergedConfig(configFromFile, argv.api);
25
+ const apis = yield utils_2.getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
26
+ const { path: pathToApi } = apis[0];
27
+ const options = {
28
+ output: argv.o,
29
+ cdn: argv.cdn,
30
+ title: argv.title,
31
+ disableGoogleFont: argv.disableGoogleFont,
32
+ templateFileName: argv.template,
33
+ templateOptions: argv.templateOptions || {},
34
+ redocOptions: utils_1.getObjectOrJSON((_a = argv.features) === null || _a === void 0 ? void 0 : _a.openapi, config),
35
+ };
36
+ const redocCurrentVersion = require('../../../package.json').dependencies.redoc.substring(1); // remove ~
37
+ try {
38
+ const elapsed = utils_2.getExecutionTime(startedAt);
39
+ const api = yield redoc_1.loadAndBundleSpec(utils_1.isURL(pathToApi) ? pathToApi : path_1.resolve(argv.config ? path_1.dirname(argv.config) : '', pathToApi));
40
+ const pageHTML = yield utils_1.getPageHTML(api, pathToApi, Object.assign(Object.assign({}, options), { redocCurrentVersion }));
41
+ fs_1.mkdirSync(path_1.dirname(options.output), { recursive: true });
42
+ fs_1.writeFileSync(options.output, pageHTML);
43
+ const sizeInKiB = Math.ceil(Buffer.byteLength(pageHTML) / 1024);
44
+ process.stderr.write(`\n🎉 bundled successfully in: ${options.output} (${sizeInKiB} KiB) [⏱ ${elapsed}].\n`);
45
+ }
46
+ catch (e) {
47
+ utils_2.exitWithError(e);
48
+ }
49
+ });
50
+ exports.handlerBuildCommand = handlerBuildCommand;
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta charset="utf8" />
6
+ <title>{{title}}</title>
7
+ <!-- needed for adaptive design -->
8
+ <meta name="viewport" content="width=device-width, initial-scale=1">
9
+ <style>
10
+ body {
11
+ padding: 0;
12
+ margin: 0;
13
+ }
14
+ </style>
15
+ {{{redocHead}}}
16
+ {{#unless disableGoogleFont}}<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">{{/unless}}
17
+ </head>
18
+
19
+ <body>
20
+ {{{redocHTML}}}
21
+ </body>
22
+
23
+ </html>
@@ -0,0 +1,25 @@
1
+ export declare type BuildDocsOptions = {
2
+ watch?: boolean;
3
+ cdn?: boolean;
4
+ output?: string;
5
+ title?: string;
6
+ disableGoogleFont?: boolean;
7
+ port?: number;
8
+ templateFileName?: string;
9
+ templateOptions?: any;
10
+ redocOptions?: any;
11
+ redocCurrentVersion: string;
12
+ };
13
+ export declare type BuildDocsArgv = {
14
+ api: string;
15
+ o: string;
16
+ cdn: boolean;
17
+ title?: string;
18
+ disableGoogleFont?: boolean;
19
+ template?: string;
20
+ templateOptions: Record<string, any>;
21
+ features: {
22
+ openapi: string | Record<string, unknown>;
23
+ };
24
+ config?: string;
25
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import type { BuildDocsOptions } from './types';
2
+ import type { Config } from '@redocly/openapi-core';
3
+ export declare function getObjectOrJSON(openapiOptions: string | Record<string, unknown>, config: Config): JSON | Record<string, unknown> | Config;
4
+ export declare function getPageHTML(api: any, pathToApi: string, { cdn, title, disableGoogleFont, templateFileName, templateOptions, redocOptions, redocCurrentVersion, }: BuildDocsOptions): Promise<string>;
5
+ export declare function isURL(str: string): boolean;
6
+ export declare function sanitizeJSONString(str: string): string;
7
+ export declare function escapeClosingScriptTag(str: string): string;
8
+ export declare function escapeUnicode(str: string): string;
@@ -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.escapeUnicode = exports.escapeClosingScriptTag = exports.sanitizeJSONString = exports.isURL = exports.getPageHTML = exports.getObjectOrJSON = void 0;
13
+ const React = require("react");
14
+ const redoc_1 = require("redoc");
15
+ const server_1 = require("react-dom/server");
16
+ const styled_components_1 = require("styled-components");
17
+ const handlebars_1 = require("handlebars");
18
+ const path_1 = require("path");
19
+ const fs_1 = require("fs");
20
+ const colorette_1 = require("colorette");
21
+ const utils_1 = require("../../utils");
22
+ function getObjectOrJSON(openapiOptions, config) {
23
+ switch (typeof openapiOptions) {
24
+ case 'object':
25
+ return openapiOptions;
26
+ case 'string':
27
+ try {
28
+ if (fs_1.existsSync(openapiOptions) && fs_1.lstatSync(openapiOptions).isFile()) {
29
+ return JSON.parse(fs_1.readFileSync(openapiOptions, 'utf-8'));
30
+ }
31
+ else {
32
+ return JSON.parse(openapiOptions);
33
+ }
34
+ }
35
+ catch (e) {
36
+ process.stderr.write(colorette_1.red(`Encountered error:\n\n${openapiOptions}\n\nis neither a file with a valid JSON object neither a stringified JSON object.`));
37
+ utils_1.exitWithError(e);
38
+ }
39
+ break;
40
+ default: {
41
+ if (config) {
42
+ process.stderr.write(`Found ${config.configFile} and using features.openapi options`);
43
+ return config['features.openapi'];
44
+ }
45
+ return {};
46
+ }
47
+ }
48
+ return {};
49
+ }
50
+ exports.getObjectOrJSON = getObjectOrJSON;
51
+ function getPageHTML(api, pathToApi, { cdn, title, disableGoogleFont, templateFileName, templateOptions, redocOptions = {}, redocCurrentVersion, }) {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ process.stderr.write('Prerendering docs');
54
+ const apiUrl = redocOptions.specUrl || (isURL(pathToApi) ? pathToApi : undefined);
55
+ const store = yield redoc_1.createStore(api, apiUrl, redocOptions);
56
+ const sheet = new styled_components_1.ServerStyleSheet();
57
+ const html = server_1.renderToString(sheet.collectStyles(React.createElement(redoc_1.Redoc, { store })));
58
+ const state = yield store.toJS();
59
+ const css = sheet.getStyleTags();
60
+ templateFileName = templateFileName ? templateFileName : path_1.join(__dirname, './template.hbs');
61
+ const template = handlebars_1.compile(fs_1.readFileSync(templateFileName).toString());
62
+ return template({
63
+ redocHTML: `
64
+ <div id="redoc">${html || ''}</div>
65
+ <script>
66
+ ${`const __redoc_state = ${sanitizeJSONString(JSON.stringify(state))};` || ''}
67
+
68
+ var container = document.getElementById('redoc');
69
+ Redoc.${'hydrate(__redoc_state, container)'};
70
+
71
+ </script>`,
72
+ redocHead: (cdn
73
+ ? '<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>'
74
+ : `<script src="https://cdn.redoc.ly/redoc/v${redocCurrentVersion}/bundles/redoc.standalone.js"></script>`) +
75
+ css,
76
+ title: title || api.info.title || 'ReDoc documentation',
77
+ disableGoogleFont,
78
+ templateOptions,
79
+ });
80
+ });
81
+ }
82
+ exports.getPageHTML = getPageHTML;
83
+ function isURL(str) {
84
+ return /^(https?:)\/\//m.test(str);
85
+ }
86
+ exports.isURL = isURL;
87
+ function sanitizeJSONString(str) {
88
+ return escapeClosingScriptTag(escapeUnicode(str));
89
+ }
90
+ exports.sanitizeJSONString = sanitizeJSONString;
91
+ // see http://www.thespanner.co.uk/2011/07/25/the-json-specification-is-now-wrong/
92
+ function escapeClosingScriptTag(str) {
93
+ return str.replace(/<\/script>/g, '<\\/script>');
94
+ }
95
+ exports.escapeClosingScriptTag = escapeClosingScriptTag;
96
+ // see http://www.thespanner.co.uk/2011/07/25/the-json-specification-is-now-wrong/
97
+ function escapeUnicode(str) {
98
+ return str.replace(/\u2028|\u2029/g, (m) => '\\u202' + (m === '\u2028' ? '8' : '9'));
99
+ }
100
+ exports.escapeUnicode = escapeUnicode;
@@ -29,7 +29,7 @@ const fs_1 = require("fs");
29
29
  function handleBundle(argv, version) {
30
30
  var _a, _b, _c, _d;
31
31
  return __awaiter(this, void 0, void 0, function* () {
32
- const config = yield openapi_core_1.loadConfig(argv.config, argv.extends);
32
+ const config = yield openapi_core_1.loadConfig({ configPath: argv.config, customExtends: argv.extends });
33
33
  const removeUnusedComponents = argv['remove-unused-components'] &&
34
34
  !((_b = (_a = config.rawConfig.styleguide) === null || _a === void 0 ? void 0 : _a.decorators) === null || _b === void 0 ? void 0 : _b.hasOwnProperty('remove-unused-components'));
35
35
  const apis = yield utils_1.getFallbackApisOrExit(argv.apis, config);
@@ -19,7 +19,11 @@ function handleLint(argv, version) {
19
19
  if (argv.config && !openapi_core_1.doesYamlFileExist(argv.config)) {
20
20
  return utils_1.exitWithError('Please, provide valid path to the configuration file');
21
21
  }
22
- const config = yield openapi_core_1.loadConfig(argv.config, argv.extends, lintConfigCallback(argv, version));
22
+ const config = yield openapi_core_1.loadConfig({
23
+ configPath: argv.config,
24
+ customExtends: argv.extends,
25
+ processRawConfig: lintConfigCallback(argv, version),
26
+ });
23
27
  const apis = yield utils_1.getFallbackApisOrExit(argv.apis, config);
24
28
  if (argv['generate-ignore-file']) {
25
29
  config.styleguide.ignore = {}; // clear ignore
@@ -1,4 +1,4 @@
1
- import type { Skips } from 'cli/src/types';
1
+ import type { Skips } from '../../types';
2
2
  export declare function previewDocs(argv: {
3
3
  port: number;
4
4
  host: string;
@@ -94,7 +94,7 @@ function previewDocs(argv) {
94
94
  });
95
95
  function reloadConfig() {
96
96
  return __awaiter(this, void 0, void 0, function* () {
97
- const config = yield openapi_core_1.loadConfig(argv.config);
97
+ const config = yield openapi_core_1.loadConfig({ configPath: argv.config });
98
98
  const redoclyClient = new openapi_core_1.RedoclyClient();
99
99
  isAuthorizedWithRedocly = yield redoclyClient.isAuthorizedWithRedocly();
100
100
  const resolvedConfig = openapi_core_1.getMergedConfig(config, argv.api);
@@ -9,6 +9,7 @@ declare type PushArgs = {
9
9
  region?: Region;
10
10
  'skip-decorator'?: string[];
11
11
  public?: boolean;
12
+ files?: string[];
12
13
  };
13
14
  export declare function handlePush(argv: PushArgs): Promise<void>;
14
15
  export declare function getDestinationProps(destination: string | undefined, organization: string | undefined): (string | undefined)[];
@@ -33,9 +33,8 @@ const login_1 = require("./login");
33
33
  const DEFAULT_VERSION = 'latest';
34
34
  function handlePush(argv) {
35
35
  return __awaiter(this, void 0, void 0, function* () {
36
- const config = yield openapi_core_1.loadConfig();
37
- const region = argv.region || config.region;
38
- const client = new openapi_core_1.RedoclyClient(region);
36
+ const config = yield openapi_core_1.loadConfig({ region: argv.region, files: argv.files });
37
+ const client = new openapi_core_1.RedoclyClient(config.region);
39
38
  const isAuthorized = yield client.isAuthorizedWithRedoclyByRegion();
40
39
  if (!isAuthorized) {
41
40
  const clientToken = yield login_1.promptClientToken(client.domain);
@@ -182,6 +181,19 @@ function collectFilesToUpload(api, config) {
182
181
  }
183
182
  files.push(...filterPluginFilesByExt(Array.from(pluginFiles)).map((f) => getFileEntry(f)));
184
183
  }
184
+ if (config.files) {
185
+ const otherFiles = new Set();
186
+ for (const file of config.files) {
187
+ if (fs.statSync(file).isDirectory()) {
188
+ const fileList = getFilesList(file, []);
189
+ fileList.forEach((f) => otherFiles.add(f));
190
+ }
191
+ else {
192
+ otherFiles.add(file);
193
+ }
194
+ }
195
+ files.push(...Array.from(otherFiles).map((f) => getFileEntry(f)));
196
+ }
185
197
  return {
186
198
  files,
187
199
  root: path.resolve(apiPath),
@@ -54,7 +54,7 @@ function printStats(statsAccumulator, api, format) {
54
54
  }
55
55
  function handleStats(argv) {
56
56
  return __awaiter(this, void 0, void 0, function* () {
57
- const config = yield openapi_core_1.loadConfig(argv.config);
57
+ const config = yield openapi_core_1.loadConfig({ configPath: argv.config });
58
58
  const [{ path }] = yield utils_1.getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
59
59
  const externalRefResolver = new openapi_core_1.BaseResolver(config.resolve);
60
60
  const { bundle: document } = yield openapi_core_1.bundle({ config, ref: path });
package/lib/index.js CHANGED
@@ -22,6 +22,7 @@ const push_1 = require("./commands/push");
22
22
  const lint_1 = require("./commands/lint");
23
23
  const bundle_1 = require("./commands/bundle");
24
24
  const login_1 = require("./commands/login");
25
+ const build_docs_1 = require("./commands/build-docs");
25
26
  const version = require('../package.json').version;
26
27
  yargs
27
28
  .version('version', 'Show version number.', version)
@@ -117,6 +118,11 @@ yargs
117
118
  description: 'Make API registry available to the public',
118
119
  type: 'boolean',
119
120
  },
121
+ files: {
122
+ description: 'List of other folders and files to upload',
123
+ array: true,
124
+ type: 'string',
125
+ },
120
126
  })
121
127
  .implies('batch-id', 'batch-size')
122
128
  .implies('batch-size', 'batch-id'), (argv) => {
@@ -243,6 +249,11 @@ yargs
243
249
  type: 'boolean',
244
250
  default: false,
245
251
  },
252
+ 'keep-url-references': {
253
+ description: 'Keep absolute url references.',
254
+ type: 'boolean',
255
+ alias: 'k',
256
+ },
246
257
  }), (argv) => {
247
258
  process.env.REDOCLY_CLI_COMMAND = 'bundle';
248
259
  bundle_1.handleBundle(argv, version);
@@ -309,6 +320,54 @@ yargs
309
320
  process.env.REDOCLY_CLI_COMMAND = 'preview-docs';
310
321
  preview_docs_1.previewDocs(argv);
311
322
  })
323
+ .command('build-docs [api]', 'build definition into zero-dependency HTML-file', (yargs) => yargs
324
+ .positional('api', { type: 'string' })
325
+ .options({
326
+ o: {
327
+ describe: 'Output file',
328
+ alias: 'output',
329
+ type: 'string',
330
+ default: 'redoc-static.html',
331
+ },
332
+ title: {
333
+ describe: 'Page Title',
334
+ type: 'string',
335
+ },
336
+ disableGoogleFont: {
337
+ describe: 'Disable Google Font',
338
+ type: 'boolean',
339
+ default: false,
340
+ },
341
+ cdn: {
342
+ describe: 'Do not include Redoc source code into html page, use link to CDN instead',
343
+ type: 'boolean',
344
+ default: false,
345
+ },
346
+ t: {
347
+ alias: 'template',
348
+ describe: 'Path to handlebars page template, see https://git.io/vh8fP for the example',
349
+ type: 'string',
350
+ },
351
+ templateOptions: {
352
+ describe: 'Additional options that you want pass to template. Use dot notation, e.g. templateOptions.metaDescription',
353
+ },
354
+ features: {
355
+ describe: 'Redoc features.openapi, use dot notation, e.g. features.openapi.nativeScrollbars',
356
+ },
357
+ config: {
358
+ describe: 'Specify path to the config file.',
359
+ type: 'string',
360
+ },
361
+ })
362
+ .check((argv) => {
363
+ var _a;
364
+ if (argv.features && !((_a = argv.features) === null || _a === void 0 ? void 0 : _a.openapi))
365
+ throw Error('Invalid option: features.openapi not set');
366
+ return true;
367
+ }), (argv) => __awaiter(void 0, void 0, void 0, function* () {
368
+ process.env.REDOCLY_CLI_COMMAND = 'build-docs';
369
+ build_docs_1.handlerBuildCommand(argv);
370
+ }))
312
371
  .completion('completion', 'Generate completion script.')
313
372
  .demandCommand(1)
314
373
  .strict().argv;
package/lib/utils.js CHANGED
@@ -45,10 +45,16 @@ function isNotEmptyArray(args) {
45
45
  return Array.isArray(args) && !!args.length;
46
46
  }
47
47
  function getAliasOrPath(config, aliasOrPath) {
48
- var _a;
48
+ var _a, _b, _c;
49
49
  return config.apis[aliasOrPath]
50
50
  ? { path: (_a = config.apis[aliasOrPath]) === null || _a === void 0 ? void 0 : _a.root, alias: aliasOrPath }
51
- : { path: aliasOrPath };
51
+ : {
52
+ path: aliasOrPath,
53
+ // find alias by path, take the first match
54
+ alias: (_c = (_b = Object.entries(config.apis).find(([_alias, api]) => {
55
+ return path.resolve(api.root) === path.resolve(aliasOrPath);
56
+ })) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : undefined,
57
+ };
52
58
  }
53
59
  function expandGlobsInEntrypoints(args, config) {
54
60
  return __awaiter(this, void 0, void 0, function* () {