@redocly/cli 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +5 -5
- package/lib/__mocks__/utils.d.ts +1 -0
- package/lib/__mocks__/utils.js +2 -1
- package/lib/__tests__/utils.test.js +18 -0
- package/lib/commands/bundle.js +9 -15
- package/lib/commands/join.d.ts +0 -1
- package/lib/commands/join.js +1 -0
- package/lib/commands/lint.d.ts +3 -2
- package/lib/commands/lint.js +3 -5
- package/lib/commands/preview-project/constants.d.ts +14 -0
- package/lib/commands/preview-project/constants.js +22 -0
- package/lib/commands/preview-project/index.d.ts +2 -0
- package/lib/commands/preview-project/index.js +58 -0
- package/lib/commands/preview-project/types.d.ts +10 -0
- package/lib/commands/preview-project/types.js +2 -0
- package/lib/commands/split/index.js +3 -3
- package/lib/index.js +39 -8
- package/lib/types.d.ts +2 -1
- package/lib/utils.d.ts +4 -2
- package/lib/utils.js +28 -2
- package/package.json +2 -2
- package/src/__mocks__/utils.ts +1 -0
- package/src/__tests__/utils.test.ts +18 -0
- package/src/commands/bundle.ts +9 -21
- package/src/commands/join.ts +3 -1
- package/src/commands/lint.ts +7 -10
- package/src/commands/preview-project/constants.ts +23 -0
- package/src/commands/preview-project/index.ts +58 -0
- package/src/commands/preview-project/types.ts +12 -0
- package/src/commands/split/index.ts +3 -3
- package/src/index.ts +46 -8
- package/src/types.ts +4 -1
- package/src/utils.ts +36 -3
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @redocly/cli
|
|
2
2
|
|
|
3
|
+
## 1.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added a `preview` command that starts a local preview server for Redocly projects that use products that are currently in a pre-release stage.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Fixed an issue with resolving references after splitting API descriptions written in the json format.
|
|
12
|
+
- Added filename extension support for more `x-codeSamples` languages.
|
|
13
|
+
- Fixed a problem where the linter incorrectly returned an error for valid examples that contain references.
|
|
14
|
+
- Updated @redocly/openapi-core to v1.7.0.
|
|
15
|
+
|
|
16
|
+
## 1.6.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- Added the ability to use `$ref` in the Redocly config file. This ability allows users to split up big config files and maintain their constituent parts independently.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Deprecated `--lint` option in the `join` command. The options are marked for removal in a future release. Use the [lint command](https://redocly.com/docs/cli/commands/lint/) separately to lint your APIs.
|
|
25
|
+
- Updated @redocly/openapi-core to v1.6.0.
|
|
26
|
+
|
|
3
27
|
## 1.5.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Then you can use it as `redocly [command] [options]`, for example:
|
|
|
28
28
|
redocly lint path-to-root-file.yaml
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
The minimum required versions of Node.js and NPM are 14.19.0 and 7.0.0 respectively.
|
|
32
32
|
|
|
33
33
|
### Docker
|
|
34
34
|
|
|
@@ -63,11 +63,11 @@ Your API reference docs are in `redoc-static.html` by default. You can customize
|
|
|
63
63
|
|
|
64
64
|
### Bundle multiple OpenAPI documents
|
|
65
65
|
|
|
66
|
-
Having one massive OpenAPI description can be annoying, so most people split them up into multiple documents via `$ref`, only to later find out some tools don't support `$ref
|
|
66
|
+
Having one massive OpenAPI description can be annoying, so most people split them up into multiple documents via `$ref`, only to later find out some tools don't support `$ref` or don't support multiple documents. Redocly CLI to the rescue! It has a `bundle` command you can use to recombine all of those documents back into one single document. The bundled output that Redocly CLI provides is clean, tidy, and looks like a human made it.
|
|
67
67
|
|
|
68
68
|
### Automate API guidelines with Linting
|
|
69
69
|
|
|
70
|
-
Check your API matches the expected API guidelines by using the `lint` command. API guidelines are an important piece of API governance
|
|
70
|
+
Check that your API matches the expected API guidelines by using the `lint` command. API guidelines are an important piece of API governance. They help to keep APIs consistent by enforcing the same standards and naming conventions, and they can also guide API teams through potential security hazards and other pitfalls. Automating API guidelines means you can keep APIs consistent and secure throughout their lifecycle. Even better, you can shape the design of the API before it even exists by combining API linting with a design-first API workflow.
|
|
71
71
|
|
|
72
72
|
Our API linter is designed for speed on even large documents, and it's easy to run locally, in CI, or anywhere you need it. It's also designed for humans, with meaningful error messages to help you get your API right every time.
|
|
73
73
|
|
|
@@ -79,9 +79,9 @@ redocly lint openapi.yaml
|
|
|
79
79
|
|
|
80
80
|
**Configure the rules** as you wish. Other API Linters use complicated identifiers like JSONPath, but Redocly makes life easy with simple expressions that understand the OpenAPI structure. You can either use the [built-in rules](https://redocly.com/docs/cli/rules) to mix-and-match your ideal API guidelines, or break out the tools to build your own.
|
|
81
81
|
|
|
82
|
-
**Format the output** in whatever way you need
|
|
82
|
+
**Format the output** in whatever way you need. The `stylish` output is as good as it sounds, but if you need JSON or Checkstyle outputs to integrate with other tools, the `lint` command can output those too.
|
|
83
83
|
|
|
84
|
-
**Multiple files supported** so you don't need to bundle your API description to lint it
|
|
84
|
+
**Multiple files supported** so you don't need to bundle your API description to lint it; just point Redocly CLI at the "entry point" (e.g.: `openapi.yaml`) and it handles the rest.
|
|
85
85
|
|
|
86
86
|
[Learn more about API standards and configuring Redocly rules](https://redocly.com/docs/cli/api-standards).
|
|
87
87
|
|
package/lib/__mocks__/utils.d.ts
CHANGED
|
@@ -39,3 +39,4 @@ export declare const checkIfRulesetExist: jest.Mock<any, any>;
|
|
|
39
39
|
export declare const sortTopLevelKeysForOas: jest.Mock<any, [document: any]>;
|
|
40
40
|
export declare const getAndValidateFileExtension: jest.Mock<string | undefined, [fileName: string]>;
|
|
41
41
|
export declare const writeToFileByExtension: jest.Mock<any, any>;
|
|
42
|
+
export declare const checkForDeprecatedOptions: jest.Mock<any, any>;
|
package/lib/__mocks__/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.writeToFileByExtension = exports.getAndValidateFileExtension = 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;
|
|
3
|
+
exports.checkForDeprecatedOptions = exports.writeToFileByExtension = exports.getAndValidateFileExtension = 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(() => '');
|
|
@@ -19,3 +19,4 @@ exports.checkIfRulesetExist = jest.fn();
|
|
|
19
19
|
exports.sortTopLevelKeysForOas = jest.fn((document) => document);
|
|
20
20
|
exports.getAndValidateFileExtension = jest.fn((fileName) => fileName.split('.').pop());
|
|
21
21
|
exports.writeToFileByExtension = jest.fn();
|
|
22
|
+
exports.checkForDeprecatedOptions = jest.fn();
|
|
@@ -235,6 +235,24 @@ describe('langToExt', () => {
|
|
|
235
235
|
['javascript', '.js'],
|
|
236
236
|
['js', '.js'],
|
|
237
237
|
['python', '.py'],
|
|
238
|
+
['c', '.c'],
|
|
239
|
+
['c++', '.cpp'],
|
|
240
|
+
['coffeescript', '.litcoffee'],
|
|
241
|
+
['dart', '.dart'],
|
|
242
|
+
['elixir', '.ex'],
|
|
243
|
+
['go', '.go'],
|
|
244
|
+
['groovy', '.groovy'],
|
|
245
|
+
['java', '.java'],
|
|
246
|
+
['kotlin', '.kt'],
|
|
247
|
+
['objective-c', '.m'],
|
|
248
|
+
['perl', '.pl'],
|
|
249
|
+
['powershell', '.ps1'],
|
|
250
|
+
['ruby', '.rb'],
|
|
251
|
+
['rust', '.rs'],
|
|
252
|
+
['scala', '.sc'],
|
|
253
|
+
['swift', '.swift'],
|
|
254
|
+
['typescript', '.ts'],
|
|
255
|
+
['tsx', '.tsx'],
|
|
238
256
|
])('should infer file extension from lang - %s', (lang, expected) => {
|
|
239
257
|
expect((0, utils_1.langToExt)(lang)).toBe(expected);
|
|
240
258
|
});
|
package/lib/commands/bundle.js
CHANGED
|
@@ -26,6 +26,7 @@ const utils_1 = require("../utils");
|
|
|
26
26
|
const perf_hooks_1 = require("perf_hooks");
|
|
27
27
|
const colorette_1 = require("colorette");
|
|
28
28
|
const fs_1 = require("fs");
|
|
29
|
+
const utils_2 = require("../utils");
|
|
29
30
|
function handleBundle(argv, config, version) {
|
|
30
31
|
var _a, _b, _c, _d, _e;
|
|
31
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -34,7 +35,14 @@ function handleBundle(argv, config, version) {
|
|
|
34
35
|
const apis = yield (0, utils_1.getFallbackApisOrExit)(argv.apis, config);
|
|
35
36
|
const totals = { errors: 0, warnings: 0, ignored: 0 };
|
|
36
37
|
const maxProblems = argv['max-problems'];
|
|
37
|
-
|
|
38
|
+
const deprecatedOptions = [
|
|
39
|
+
'lint',
|
|
40
|
+
'format',
|
|
41
|
+
'skip-rule',
|
|
42
|
+
'extends',
|
|
43
|
+
'max-problems',
|
|
44
|
+
];
|
|
45
|
+
(0, utils_2.checkForDeprecatedOptions)(argv, deprecatedOptions);
|
|
38
46
|
for (const { path, alias } of apis) {
|
|
39
47
|
try {
|
|
40
48
|
const startedAt = perf_hooks_1.performance.now();
|
|
@@ -129,17 +137,3 @@ function handleBundle(argv, config, version) {
|
|
|
129
137
|
});
|
|
130
138
|
}
|
|
131
139
|
exports.handleBundle = handleBundle;
|
|
132
|
-
function checkForDeprecatedOptions(argv) {
|
|
133
|
-
const deprecatedOptions = [
|
|
134
|
-
'lint',
|
|
135
|
-
'format',
|
|
136
|
-
'skip-rule',
|
|
137
|
-
'extends',
|
|
138
|
-
'max-problems',
|
|
139
|
-
];
|
|
140
|
-
for (const option of deprecatedOptions) {
|
|
141
|
-
if (argv[option]) {
|
|
142
|
-
process.stderr.write((0, colorette_1.yellow)(`[WARNING] "${option}" option is deprecated and will be removed in a future release. \n\n`));
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
package/lib/commands/join.d.ts
CHANGED
|
@@ -10,7 +10,6 @@ export type JoinOptions = {
|
|
|
10
10
|
'without-x-tag-groups'?: boolean;
|
|
11
11
|
output?: string;
|
|
12
12
|
config?: string;
|
|
13
|
-
extends?: undefined;
|
|
14
13
|
'lint-config'?: RuleSeverity;
|
|
15
14
|
};
|
|
16
15
|
export declare function handleJoin(argv: JoinOptions, config: Config, packageVersion: string): Promise<void>;
|
package/lib/commands/join.js
CHANGED
|
@@ -28,6 +28,7 @@ function handleJoin(argv, config, packageVersion) {
|
|
|
28
28
|
if (argv.apis.length < 2) {
|
|
29
29
|
return (0, utils_1.exitWithError)(`At least 2 apis should be provided. \n\n`);
|
|
30
30
|
}
|
|
31
|
+
(0, utils_1.checkForDeprecatedOptions)(argv, ['lint']);
|
|
31
32
|
const fileExtension = (0, utils_1.getAndValidateFileExtension)(argv.output || argv.apis[0]);
|
|
32
33
|
const { 'prefix-components-with-info-prop': prefixComponentsWithInfoProp, 'prefix-tags-with-filename': prefixTagsWithFilename, 'prefix-tags-with-info-prop': prefixTagsWithInfoProp, 'without-x-tag-groups': withoutXTagGroups, output: specFilename = `openapi.${fileExtension}`, } = argv;
|
|
33
34
|
const usedTagsOptions = [
|
package/lib/commands/lint.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Config } from '@redocly/openapi-core';
|
|
2
|
-
import type { OutputFormat,
|
|
2
|
+
import type { OutputFormat, Document, RuleSeverity } from '@redocly/openapi-core';
|
|
3
|
+
import type { ResolvedRefMap } from '@redocly/openapi-core/lib/resolve';
|
|
3
4
|
import type { CommandOptions, Skips } from '../types';
|
|
4
5
|
export type LintOptions = {
|
|
5
6
|
apis?: string[];
|
|
@@ -11,4 +12,4 @@ export type LintOptions = {
|
|
|
11
12
|
'lint-config'?: RuleSeverity;
|
|
12
13
|
} & Omit<Skips, 'skip-decorator'>;
|
|
13
14
|
export declare function handleLint(argv: LintOptions, config: Config, version: string): Promise<void>;
|
|
14
|
-
export declare function lintConfigCallback(argv: CommandOptions & Record<string, undefined>, version: string): ((
|
|
15
|
+
export declare function lintConfigCallback(argv: CommandOptions & Record<string, undefined>, version: string): ((document: Document, resolvedRefMap: ResolvedRefMap) => Promise<void>) | undefined;
|
package/lib/commands/lint.js
CHANGED
|
@@ -90,12 +90,10 @@ function lintConfigCallback(argv, version) {
|
|
|
90
90
|
// we can't print config lint results as it will break json output
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
|
-
return (
|
|
94
|
-
const configPath = (0, openapi_core_1.findConfig)(argv.config) || '';
|
|
95
|
-
const stringYaml = (0, openapi_core_1.stringifyYaml)(config);
|
|
96
|
-
const configContent = (0, openapi_core_1.makeDocumentFromString)(stringYaml, configPath);
|
|
93
|
+
return (document, resolvedRefMap) => __awaiter(this, void 0, void 0, function* () {
|
|
97
94
|
const problems = yield (0, openapi_core_1.lintConfig)({
|
|
98
|
-
document
|
|
95
|
+
document,
|
|
96
|
+
resolvedRefMap,
|
|
99
97
|
severity: (argv['lint-config'] || 'warn'),
|
|
100
98
|
});
|
|
101
99
|
const fileTotals = (0, openapi_core_1.getTotals)(problems);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Product } from './types';
|
|
2
|
+
export declare const PRODUCT_PACKAGES: {
|
|
3
|
+
realm: string;
|
|
4
|
+
'redoc-revel': string;
|
|
5
|
+
'revel-reef': string;
|
|
6
|
+
'redoc-reef': string;
|
|
7
|
+
redoc: string;
|
|
8
|
+
revel: string;
|
|
9
|
+
reef: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const PRODUCT_NAMES: {
|
|
12
|
+
[key in Product]: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const PRODUCT_PLANS: readonly ["pro", "enterprise"];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PRODUCT_PLANS = exports.PRODUCT_NAMES = exports.PRODUCT_PACKAGES = void 0;
|
|
4
|
+
exports.PRODUCT_PACKAGES = {
|
|
5
|
+
realm: '@redocly/realm',
|
|
6
|
+
'redoc-revel': '@redocly/redoc-revel',
|
|
7
|
+
'revel-reef': '@redocly/revel-reef',
|
|
8
|
+
'redoc-reef': '@redocly/redoc-reef',
|
|
9
|
+
redoc: '@redocly/redoc',
|
|
10
|
+
revel: '@redocly/revel',
|
|
11
|
+
reef: '@redocly/reef',
|
|
12
|
+
};
|
|
13
|
+
exports.PRODUCT_NAMES = {
|
|
14
|
+
redoc: 'Redoc',
|
|
15
|
+
revel: 'Revel',
|
|
16
|
+
reef: 'Reef',
|
|
17
|
+
realm: 'Realm',
|
|
18
|
+
'redoc-revel': 'Redoc + Revel',
|
|
19
|
+
'redoc-reef': 'Redoc + Reef',
|
|
20
|
+
'revel-reef': 'Revel + Reef',
|
|
21
|
+
};
|
|
22
|
+
exports.PRODUCT_PLANS = ['pro', 'enterprise'];
|
|
@@ -0,0 +1,58 @@
|
|
|
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.previewProject = void 0;
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const fs_1 = require("fs");
|
|
15
|
+
const child_process_1 = require("child_process");
|
|
16
|
+
const constants_1 = require("./constants");
|
|
17
|
+
const previewProject = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
+
const { plan, port } = args;
|
|
19
|
+
const projectDir = args['source-dir'];
|
|
20
|
+
const product = args.product || tryGetProductFromPackageJson(projectDir);
|
|
21
|
+
if (!isValidProduct(product)) {
|
|
22
|
+
process.stderr.write(`Invalid product ${product}`);
|
|
23
|
+
throw new Error(`Project preview launch failed`);
|
|
24
|
+
}
|
|
25
|
+
const productName = constants_1.PRODUCT_NAMES[product];
|
|
26
|
+
const packageName = constants_1.PRODUCT_PACKAGES[product];
|
|
27
|
+
process.stdout.write(`\nLaunching preview of ${productName} ${plan} using NPX\n\n`);
|
|
28
|
+
(0, child_process_1.spawn)('npx', ['-y', packageName, 'develop', `--plan=${plan}`, `--port=${port || 4000}`], {
|
|
29
|
+
stdio: 'inherit',
|
|
30
|
+
cwd: projectDir,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
exports.previewProject = previewProject;
|
|
34
|
+
const isValidProduct = (product) => {
|
|
35
|
+
if (!product) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return !!constants_1.PRODUCT_NAMES[product];
|
|
39
|
+
};
|
|
40
|
+
const tryGetProductFromPackageJson = (projectDir) => {
|
|
41
|
+
const packageJsonPath = path.join(process.cwd(), projectDir, 'package.json');
|
|
42
|
+
if ((0, fs_1.existsSync)(packageJsonPath)) {
|
|
43
|
+
try {
|
|
44
|
+
const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, 'utf-8'));
|
|
45
|
+
const packageJsonDeps = packageJson.dependencies || {};
|
|
46
|
+
for (const [product, packageName] of Object.entries(constants_1.PRODUCT_PACKAGES)) {
|
|
47
|
+
if (packageJsonDeps[packageName]) {
|
|
48
|
+
process.stdout.write(`\n${packageName} detected in project's 'package.json'`);
|
|
49
|
+
return product;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
process.stdout.write(`Invalid 'package.json': ${packageJsonPath}. Using Realm.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return 'realm';
|
|
58
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PRODUCT_PACKAGES, PRODUCT_PLANS } from './constants';
|
|
2
|
+
export type Product = keyof typeof PRODUCT_PACKAGES;
|
|
3
|
+
export type ProductPlan = typeof PRODUCT_PLANS[number];
|
|
4
|
+
export type PreviewProjectOptions = {
|
|
5
|
+
product?: Product | string;
|
|
6
|
+
plan: ProductPlan | string;
|
|
7
|
+
port?: number;
|
|
8
|
+
'source-dir': string;
|
|
9
|
+
config: string | undefined;
|
|
10
|
+
};
|
|
@@ -47,8 +47,8 @@ function splitDefinition(openapi, openapiDir, pathSeparator, ext) {
|
|
|
47
47
|
function isStartsWithComponents(node) {
|
|
48
48
|
return node.startsWith(types_1.componentsPath);
|
|
49
49
|
}
|
|
50
|
-
function
|
|
51
|
-
return
|
|
50
|
+
function isSupportedExtension(filename) {
|
|
51
|
+
return filename.endsWith('.yaml') || filename.endsWith('.yml') || filename.endsWith('.json');
|
|
52
52
|
}
|
|
53
53
|
function loadFile(fileName) {
|
|
54
54
|
try {
|
|
@@ -83,7 +83,7 @@ function traverseDirectoryDeep(directory, callback, componentsFiles) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
function traverseDirectoryDeepCallback(filename, directory, componentsFiles) {
|
|
86
|
-
if (
|
|
86
|
+
if (!isSupportedExtension(filename))
|
|
87
87
|
return;
|
|
88
88
|
const pathData = (0, utils_1.readYaml)(filename);
|
|
89
89
|
replace$Refs(pathData, directory, componentsFiles);
|
package/lib/index.js
CHANGED
|
@@ -26,6 +26,8 @@ const build_docs_1 = require("./commands/build-docs");
|
|
|
26
26
|
const update_version_notifier_1 = require("./update-version-notifier");
|
|
27
27
|
const wrapper_1 = require("./wrapper");
|
|
28
28
|
const update_version_notifier_2 = require("./update-version-notifier");
|
|
29
|
+
const preview_project_1 = require("./commands/preview-project");
|
|
30
|
+
const constants_1 = require("./commands/preview-project/constants");
|
|
29
31
|
if (!('replaceAll' in String.prototype)) {
|
|
30
32
|
require('core-js/actual/string/replace-all');
|
|
31
33
|
}
|
|
@@ -82,14 +84,14 @@ yargs
|
|
|
82
84
|
process.env.REDOCLY_CLI_COMMAND = 'split';
|
|
83
85
|
(0, wrapper_1.commandWrapper)(split_1.handleSplit)(argv);
|
|
84
86
|
})
|
|
85
|
-
.command('join [apis...]', 'Join
|
|
87
|
+
.command('join [apis...]', 'Join multiple API descriptions into one [experimental].', (yargs) => yargs
|
|
86
88
|
.positional('apis', {
|
|
87
89
|
array: true,
|
|
88
90
|
type: 'string',
|
|
89
91
|
demandOption: true,
|
|
90
92
|
})
|
|
91
93
|
.option({
|
|
92
|
-
lint: { description: 'Lint
|
|
94
|
+
lint: { description: 'Lint descriptions', type: 'boolean', default: false, hidden: true },
|
|
93
95
|
decorate: { description: 'Run decorators', type: 'boolean', default: false },
|
|
94
96
|
preprocess: { description: 'Run preprocessors', type: 'boolean', default: false },
|
|
95
97
|
'prefix-tags-with-info-prop': {
|
|
@@ -112,7 +114,7 @@ yargs
|
|
|
112
114
|
type: 'boolean',
|
|
113
115
|
},
|
|
114
116
|
output: {
|
|
115
|
-
|
|
117
|
+
description: 'Output file.',
|
|
116
118
|
alias: 'o',
|
|
117
119
|
type: 'string',
|
|
118
120
|
},
|
|
@@ -203,7 +205,7 @@ yargs
|
|
|
203
205
|
process.env.REDOCLY_CLI_COMMAND = 'push';
|
|
204
206
|
(0, wrapper_1.commandWrapper)((0, push_1.transformPush)(push_1.handlePush))(argv);
|
|
205
207
|
})
|
|
206
|
-
.command('lint [apis...]', 'Lint
|
|
208
|
+
.command('lint [apis...]', 'Lint an API description.', (yargs) => yargs.positional('apis', { array: true, type: 'string', demandOption: true }).option({
|
|
207
209
|
format: {
|
|
208
210
|
description: 'Use a specific output format.',
|
|
209
211
|
choices: [
|
|
@@ -256,8 +258,12 @@ yargs
|
|
|
256
258
|
process.env.REDOCLY_CLI_COMMAND = 'lint';
|
|
257
259
|
(0, wrapper_1.commandWrapper)(lint_1.handleLint)(argv);
|
|
258
260
|
})
|
|
259
|
-
.command('bundle [apis...]', 'Bundle
|
|
260
|
-
output: {
|
|
261
|
+
.command('bundle [apis...]', 'Bundle a multi-file API description to a single file.', (yargs) => yargs.positional('apis', { array: true, type: 'string', demandOption: true }).options({
|
|
262
|
+
output: {
|
|
263
|
+
type: 'string',
|
|
264
|
+
description: 'Output file.',
|
|
265
|
+
alias: 'o',
|
|
266
|
+
},
|
|
261
267
|
format: {
|
|
262
268
|
description: 'Use a specific output format.',
|
|
263
269
|
choices: ['stylish', 'codeframe', 'json', 'checkstyle'],
|
|
@@ -369,7 +375,32 @@ yargs
|
|
|
369
375
|
process.stdout.write('Logged out from the Redocly account. ✋\n');
|
|
370
376
|
}))(argv);
|
|
371
377
|
}))
|
|
372
|
-
.command('preview
|
|
378
|
+
.command('preview', 'Preview Redocly project using one of the product NPM packages.', (yargs) => yargs.options({
|
|
379
|
+
product: {
|
|
380
|
+
type: 'string',
|
|
381
|
+
choices: ['redoc', 'revel', 'reef', 'realm', 'redoc-revel', 'redoc-reef', 'revel-reef'],
|
|
382
|
+
description: "Product used to launch preview. Default is inferred from project's package.json or 'realm' is used.",
|
|
383
|
+
},
|
|
384
|
+
plan: {
|
|
385
|
+
type: 'string',
|
|
386
|
+
choices: constants_1.PRODUCT_PLANS,
|
|
387
|
+
default: 'enterprise',
|
|
388
|
+
},
|
|
389
|
+
port: {
|
|
390
|
+
type: 'number',
|
|
391
|
+
description: 'Preview port.',
|
|
392
|
+
default: 4000,
|
|
393
|
+
},
|
|
394
|
+
'source-dir': {
|
|
395
|
+
alias: 'd',
|
|
396
|
+
type: 'string',
|
|
397
|
+
description: 'Project directory.',
|
|
398
|
+
default: '.',
|
|
399
|
+
},
|
|
400
|
+
}), (argv) => {
|
|
401
|
+
(0, wrapper_1.commandWrapper)(preview_project_1.previewProject)(argv);
|
|
402
|
+
})
|
|
403
|
+
.command('preview-docs [api]', 'Preview API reference docs for an API description.', (yargs) => yargs.positional('api', { type: 'string' }).options({
|
|
373
404
|
port: {
|
|
374
405
|
alias: 'p',
|
|
375
406
|
type: 'number',
|
|
@@ -462,7 +493,7 @@ yargs
|
|
|
462
493
|
process.env.REDOCLY_CLI_COMMAND = 'build-docs';
|
|
463
494
|
(0, wrapper_1.commandWrapper)(build_docs_1.handlerBuildCommand)(argv);
|
|
464
495
|
}))
|
|
465
|
-
.completion('completion', 'Generate
|
|
496
|
+
.completion('completion', 'Generate autocomplete script for `redocly` command.')
|
|
466
497
|
.demandCommand(1)
|
|
467
498
|
.middleware([update_version_notifier_1.notifyUpdateCliVersion])
|
|
468
499
|
.strict().argv;
|
package/lib/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { StatsOptions } from './commands/stats';
|
|
|
8
8
|
import type { SplitOptions } from './commands/split';
|
|
9
9
|
import type { PreviewDocsOptions } from './commands/preview-docs';
|
|
10
10
|
import type { BuildDocsArgv } from './commands/build-docs/types';
|
|
11
|
+
import type { PreviewProjectOptions } from './commands/preview-project/types';
|
|
11
12
|
export type Totals = {
|
|
12
13
|
errors: number;
|
|
13
14
|
warnings: number;
|
|
@@ -20,7 +21,7 @@ export type Entrypoint = {
|
|
|
20
21
|
export declare const outputExtensions: readonly BundleOutputFormat[];
|
|
21
22
|
export type OutputExtensions = 'json' | 'yaml' | 'yml' | undefined;
|
|
22
23
|
export declare const regionChoices: readonly Region[];
|
|
23
|
-
export type CommandOptions = StatsOptions | SplitOptions | JoinOptions | PushOptions | LintOptions | BundleOptions | LoginOptions | PreviewDocsOptions | BuildDocsArgv;
|
|
24
|
+
export type CommandOptions = StatsOptions | SplitOptions | JoinOptions | PushOptions | LintOptions | BundleOptions | LoginOptions | PreviewDocsOptions | BuildDocsArgv | PreviewProjectOptions;
|
|
24
25
|
export type Skips = {
|
|
25
26
|
'skip-rule'?: string[];
|
|
26
27
|
'skip-decorator'?: string[];
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { BundleOutputFormat, StyleguideConfig,
|
|
1
|
+
import { BundleOutputFormat, StyleguideConfig, Region, Config, Oas3Definition, Oas2Definition } from '@redocly/openapi-core';
|
|
2
2
|
import { Totals, Entrypoint, ConfigApis, CommandOptions, OutputExtensions } from './types';
|
|
3
3
|
import { Arguments } from 'yargs';
|
|
4
|
+
import type { RawConfigProcessor } from '@redocly/openapi-core/lib/config';
|
|
4
5
|
export declare function getFallbackApisOrExit(argsApis: string[] | undefined, config: ConfigApis): Promise<Entrypoint[]>;
|
|
5
6
|
export declare function getExecutionTime(startedAt: number): string;
|
|
6
7
|
export declare function printExecutionTime(commandName: string, startedAt: number, api: string): void;
|
|
@@ -38,7 +39,7 @@ export declare function isSubdir(parent: string, dir: string): boolean;
|
|
|
38
39
|
export declare function loadConfigAndHandleErrors(options?: {
|
|
39
40
|
configPath?: string;
|
|
40
41
|
customExtends?: string[];
|
|
41
|
-
processRawConfig?:
|
|
42
|
+
processRawConfig?: RawConfigProcessor;
|
|
42
43
|
files?: string[];
|
|
43
44
|
region?: Region;
|
|
44
45
|
}): Promise<Config | void>;
|
|
@@ -64,3 +65,4 @@ export type Analytics = {
|
|
|
64
65
|
};
|
|
65
66
|
export declare function cleanArgs(args: CommandOptions): Record<string, unknown>;
|
|
66
67
|
export declare function cleanRawInput(argv: string[]): string;
|
|
68
|
+
export declare function checkForDeprecatedOptions<T>(argv: T, deprecatedOptions: Array<keyof T>): void;
|
package/lib/utils.js
CHANGED
|
@@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
20
20
|
return t;
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.cleanRawInput = exports.cleanArgs = exports.sendTelemetry = exports.cleanColors = exports.checkIfRulesetExist = exports.sortTopLevelKeysForOas = exports.loadConfigAndHandleErrors = exports.isSubdir = exports.exitWithError = exports.printUnusedWarnings = exports.getOutputFileName = exports.printConfigLintTotals = exports.printLintTotals = exports.HandledError = exports.handleError = exports.pluralize = exports.getAndValidateFileExtension = exports.writeJson = exports.writeYaml = exports.writeToFileByExtension = exports.readYaml = exports.promptUser = exports.saveBundle = exports.dumpBundle = exports.CircularJSONNotSupportedError = exports.langToExt = exports.escapeLanguageName = exports.pathToFilename = exports.printExecutionTime = exports.getExecutionTime = exports.getFallbackApisOrExit = void 0;
|
|
23
|
+
exports.checkForDeprecatedOptions = exports.cleanRawInput = exports.cleanArgs = exports.sendTelemetry = exports.cleanColors = exports.checkIfRulesetExist = exports.sortTopLevelKeysForOas = exports.loadConfigAndHandleErrors = exports.isSubdir = exports.exitWithError = exports.printUnusedWarnings = exports.getOutputFileName = exports.printConfigLintTotals = exports.printLintTotals = exports.HandledError = exports.handleError = exports.pluralize = exports.getAndValidateFileExtension = exports.writeJson = exports.writeYaml = exports.writeToFileByExtension = exports.readYaml = exports.promptUser = exports.saveBundle = exports.dumpBundle = exports.CircularJSONNotSupportedError = exports.langToExt = exports.escapeLanguageName = exports.pathToFilename = exports.printExecutionTime = exports.getExecutionTime = exports.getFallbackApisOrExit = void 0;
|
|
24
24
|
const fetch_with_timeout_1 = require("./fetch-with-timeout");
|
|
25
25
|
const path_1 = require("path");
|
|
26
26
|
const colorette_1 = require("colorette");
|
|
@@ -31,11 +31,11 @@ const readline = require("readline");
|
|
|
31
31
|
const stream_1 = require("stream");
|
|
32
32
|
const child_process_1 = require("child_process");
|
|
33
33
|
const openapi_core_1 = require("@redocly/openapi-core");
|
|
34
|
-
const config_1 = require("@redocly/openapi-core/lib/config");
|
|
35
34
|
const types_1 = require("./types");
|
|
36
35
|
const utils_1 = require("@redocly/openapi-core/lib/utils");
|
|
37
36
|
const update_version_notifier_1 = require("./update-version-notifier");
|
|
38
37
|
const push_1 = require("./commands/push");
|
|
38
|
+
const config_1 = require("@redocly/openapi-core/lib/config");
|
|
39
39
|
function getFallbackApisOrExit(argsApis, config) {
|
|
40
40
|
return __awaiter(this, void 0, void 0, function* () {
|
|
41
41
|
const { apis } = config;
|
|
@@ -127,6 +127,24 @@ function langToExt(lang) {
|
|
|
127
127
|
javascript: '.js',
|
|
128
128
|
js: '.js',
|
|
129
129
|
python: '.py',
|
|
130
|
+
c: '.c',
|
|
131
|
+
'c++': '.cpp',
|
|
132
|
+
coffeescript: '.litcoffee',
|
|
133
|
+
dart: '.dart',
|
|
134
|
+
elixir: '.ex',
|
|
135
|
+
go: '.go',
|
|
136
|
+
groovy: '.groovy',
|
|
137
|
+
java: '.java',
|
|
138
|
+
kotlin: '.kt',
|
|
139
|
+
'objective-c': '.m',
|
|
140
|
+
perl: '.pl',
|
|
141
|
+
powershell: '.ps1',
|
|
142
|
+
ruby: '.rb',
|
|
143
|
+
rust: '.rs',
|
|
144
|
+
scala: '.sc',
|
|
145
|
+
swift: '.swift',
|
|
146
|
+
typescript: '.ts',
|
|
147
|
+
tsx: '.tsx',
|
|
130
148
|
};
|
|
131
149
|
return langObj[lang.toLowerCase()];
|
|
132
150
|
}
|
|
@@ -524,3 +542,11 @@ function cleanRawInput(argv) {
|
|
|
524
542
|
return argv.map((entry) => entry.split('=').map(cleanString).join('=')).join(' ');
|
|
525
543
|
}
|
|
526
544
|
exports.cleanRawInput = cleanRawInput;
|
|
545
|
+
function checkForDeprecatedOptions(argv, deprecatedOptions) {
|
|
546
|
+
for (const option of deprecatedOptions) {
|
|
547
|
+
if (argv[option]) {
|
|
548
|
+
process.stderr.write((0, colorette_1.yellow)(`[WARNING] "${String(option)}" option is deprecated and will be removed in a future release. \n\n`));
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
exports.checkForDeprecatedOptions = checkForDeprecatedOptions;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"Roman Hotsiy <roman@redoc.ly> (https://redoc.ly/)"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@redocly/openapi-core": "1.
|
|
39
|
+
"@redocly/openapi-core": "1.7.0",
|
|
40
40
|
"chokidar": "^3.5.1",
|
|
41
41
|
"colorette": "^1.2.0",
|
|
42
42
|
"core-js": "^3.32.1",
|
package/src/__mocks__/utils.ts
CHANGED
|
@@ -19,3 +19,4 @@ export const checkIfRulesetExist = jest.fn();
|
|
|
19
19
|
export const sortTopLevelKeysForOas = jest.fn((document) => document);
|
|
20
20
|
export const getAndValidateFileExtension = jest.fn((fileName: string) => fileName.split('.').pop());
|
|
21
21
|
export const writeToFileByExtension = jest.fn();
|
|
22
|
+
export const checkForDeprecatedOptions = jest.fn();
|
|
@@ -295,6 +295,24 @@ describe('langToExt', () => {
|
|
|
295
295
|
['javascript', '.js'],
|
|
296
296
|
['js', '.js'],
|
|
297
297
|
['python', '.py'],
|
|
298
|
+
['c', '.c'],
|
|
299
|
+
['c++', '.cpp'],
|
|
300
|
+
['coffeescript', '.litcoffee'],
|
|
301
|
+
['dart', '.dart'],
|
|
302
|
+
['elixir', '.ex'],
|
|
303
|
+
['go', '.go'],
|
|
304
|
+
['groovy', '.groovy'],
|
|
305
|
+
['java', '.java'],
|
|
306
|
+
['kotlin', '.kt'],
|
|
307
|
+
['objective-c', '.m'],
|
|
308
|
+
['perl', '.pl'],
|
|
309
|
+
['powershell', '.ps1'],
|
|
310
|
+
['ruby', '.rb'],
|
|
311
|
+
['rust', '.rs'],
|
|
312
|
+
['scala', '.sc'],
|
|
313
|
+
['swift', '.swift'],
|
|
314
|
+
['typescript', '.ts'],
|
|
315
|
+
['tsx', '.tsx'],
|
|
298
316
|
])('should infer file extension from lang - %s', (lang, expected) => {
|
|
299
317
|
expect(langToExt(lang)).toBe(expected);
|
|
300
318
|
});
|
package/src/commands/bundle.ts
CHANGED
|
@@ -23,6 +23,7 @@ import type { OutputExtensions, Skips, Totals } from '../types';
|
|
|
23
23
|
import { performance } from 'perf_hooks';
|
|
24
24
|
import { blue, gray, green, yellow } from 'colorette';
|
|
25
25
|
import { writeFileSync } from 'fs';
|
|
26
|
+
import { checkForDeprecatedOptions } from '../utils';
|
|
26
27
|
|
|
27
28
|
export type BundleOptions = {
|
|
28
29
|
apis?: string[];
|
|
@@ -47,8 +48,15 @@ export async function handleBundle(argv: BundleOptions, config: Config, version:
|
|
|
47
48
|
const apis = await getFallbackApisOrExit(argv.apis, config);
|
|
48
49
|
const totals: Totals = { errors: 0, warnings: 0, ignored: 0 };
|
|
49
50
|
const maxProblems = argv['max-problems'];
|
|
51
|
+
const deprecatedOptions: Array<keyof BundleOptions> = [
|
|
52
|
+
'lint',
|
|
53
|
+
'format',
|
|
54
|
+
'skip-rule',
|
|
55
|
+
'extends',
|
|
56
|
+
'max-problems',
|
|
57
|
+
];
|
|
50
58
|
|
|
51
|
-
checkForDeprecatedOptions(argv);
|
|
59
|
+
checkForDeprecatedOptions(argv, deprecatedOptions);
|
|
52
60
|
|
|
53
61
|
for (const { path, alias } of apis) {
|
|
54
62
|
try {
|
|
@@ -177,23 +185,3 @@ export async function handleBundle(argv: BundleOptions, config: Config, version:
|
|
|
177
185
|
throw new Error('Bundle failed.');
|
|
178
186
|
}
|
|
179
187
|
}
|
|
180
|
-
|
|
181
|
-
function checkForDeprecatedOptions(argv: BundleOptions) {
|
|
182
|
-
const deprecatedOptions: Array<keyof BundleOptions> = [
|
|
183
|
-
'lint',
|
|
184
|
-
'format',
|
|
185
|
-
'skip-rule',
|
|
186
|
-
'extends',
|
|
187
|
-
'max-problems',
|
|
188
|
-
];
|
|
189
|
-
|
|
190
|
-
for (const option of deprecatedOptions) {
|
|
191
|
-
if (argv[option]) {
|
|
192
|
-
process.stderr.write(
|
|
193
|
-
yellow(
|
|
194
|
-
`[WARNING] "${option}" option is deprecated and will be removed in a future release. \n\n`
|
|
195
|
-
)
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|