@redocly/cli 1.0.0-beta.102 → 1.0.0-beta.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/__mocks__/@redocly/openapi-core.d.ts +4 -0
- package/lib/__mocks__/@redocly/openapi-core.js +4 -5
- package/lib/__mocks__/perf_hooks.d.ts +4 -0
- package/lib/__mocks__/perf_hooks.js +6 -0
- package/lib/__mocks__/utils.d.ts +0 -3
- package/lib/__mocks__/utils.js +1 -2
- package/lib/__tests__/commands/lint.test.d.ts +1 -0
- package/lib/__tests__/commands/lint.test.js +106 -0
- package/lib/__tests__/commands/push.test.js +30 -1
- package/lib/__tests__/fixtures/config.d.ts +12 -0
- package/lib/__tests__/fixtures/config.js +14 -0
- package/lib/__tests__/utils.test.js +39 -1
- package/lib/commands/lint.d.ts +5 -3
- package/lib/commands/lint.js +24 -1
- package/lib/commands/preview-docs/preview-server/oauth2-redirect.html +1 -1
- package/lib/commands/preview-docs/preview-server/preview-server.js +3 -3
- package/lib/commands/push.d.ts +2 -1
- package/lib/commands/push.js +11 -1
- package/lib/index.js +25 -5
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +14 -2
- package/package.json +2 -2
- package/src/__mocks__/@redocly/openapi-core.ts +4 -4
- package/src/__mocks__/perf_hooks.ts +3 -0
- package/src/__mocks__/utils.ts +0 -1
- package/src/__tests__/commands/lint.test.ts +133 -0
- package/src/__tests__/commands/push.test.ts +34 -1
- package/src/__tests__/fixtures/config.ts +11 -0
- package/src/__tests__/utils.test.ts +52 -2
- package/src/commands/lint.ts +58 -17
- package/src/commands/preview-docs/preview-server/oauth2-redirect.html +1 -1
- package/src/commands/preview-docs/preview-server/preview-server.ts +3 -3
- package/src/commands/push.ts +20 -2
- package/src/index.ts +36 -15
- package/src/utils.ts +19 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -24,9 +24,12 @@ export declare const RedoclyClient: jest.Mock<{
|
|
|
24
24
|
export declare const loadConfig: jest.Mock<{
|
|
25
25
|
configFile: null;
|
|
26
26
|
lint: {
|
|
27
|
+
addIgnore: jest.Mock<any, any>;
|
|
27
28
|
skipRules: jest.Mock<any, any>;
|
|
28
29
|
skipPreprocessors: jest.Mock<any, any>;
|
|
30
|
+
saveIgnore: jest.Mock<any, any>;
|
|
29
31
|
skipDecorators: jest.Mock<any, any>;
|
|
32
|
+
ignore: null;
|
|
30
33
|
};
|
|
31
34
|
}, []>;
|
|
32
35
|
export declare const getMergedConfig: jest.Mock<any, any>;
|
|
@@ -42,3 +45,4 @@ export declare const getTotals: jest.Mock<{
|
|
|
42
45
|
}, []>;
|
|
43
46
|
export declare const formatProblems: jest.Mock<any, any>;
|
|
44
47
|
export declare const slash: jest.Mock<any, any>;
|
|
48
|
+
export declare const findConfig: jest.Mock<any, any>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.slash = exports.formatProblems = exports.getTotals = exports.bundle = exports.lint = exports.getMergedConfig = exports.loadConfig = exports.RedoclyClient = exports.__redoclyClient = void 0;
|
|
3
|
+
exports.findConfig = exports.slash = exports.formatProblems = exports.getTotals = exports.bundle = exports.lint = exports.getMergedConfig = exports.loadConfig = exports.RedoclyClient = exports.__redoclyClient = void 0;
|
|
4
|
+
const config_1 = require("./../../__tests__/fixtures/config");
|
|
4
5
|
exports.__redoclyClient = {
|
|
5
6
|
isAuthorizedWithRedocly: jest.fn().mockResolvedValue(true),
|
|
6
7
|
isAuthorizedWithRedoclyByRegion: jest.fn().mockResolvedValue(true),
|
|
@@ -16,13 +17,11 @@ exports.__redoclyClient = {
|
|
|
16
17
|
},
|
|
17
18
|
};
|
|
18
19
|
exports.RedoclyClient = jest.fn(() => exports.__redoclyClient);
|
|
19
|
-
exports.loadConfig = jest.fn(() =>
|
|
20
|
-
configFile: null,
|
|
21
|
-
lint: { skipRules: jest.fn(), skipPreprocessors: jest.fn(), skipDecorators: jest.fn() },
|
|
22
|
-
}));
|
|
20
|
+
exports.loadConfig = jest.fn(() => config_1.ConfigFixture);
|
|
23
21
|
exports.getMergedConfig = jest.fn();
|
|
24
22
|
exports.lint = jest.fn();
|
|
25
23
|
exports.bundle = jest.fn(() => ({ bundle: { parsed: null }, problems: null }));
|
|
26
24
|
exports.getTotals = jest.fn(() => ({ errors: 0 }));
|
|
27
25
|
exports.formatProblems = jest.fn();
|
|
28
26
|
exports.slash = jest.fn();
|
|
27
|
+
exports.findConfig = jest.fn();
|
package/lib/__mocks__/utils.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
/// <reference types="jest" />
|
|
2
2
|
export declare const getFallbackEntryPointsOrExit: jest.Mock<any, [entrypoints: any]>;
|
|
3
|
-
export declare const getTotals: jest.Mock<{
|
|
4
|
-
errors: number;
|
|
5
|
-
}, []>;
|
|
6
3
|
export declare const dumpBundle: jest.Mock<string, []>;
|
|
7
4
|
export declare const slash: jest.Mock<any, any>;
|
|
8
5
|
export declare const pluralize: jest.Mock<any, any>;
|
package/lib/__mocks__/utils.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.exitWithError = exports.handleError = exports.getOutputFileName = exports.printLintTotals = exports.printUnusedWarnings = exports.printExecutionTime = exports.getExecutionTime = exports.pluralize = exports.slash = exports.dumpBundle = exports.
|
|
3
|
+
exports.exitWithError = exports.handleError = exports.getOutputFileName = exports.printLintTotals = exports.printUnusedWarnings = exports.printExecutionTime = exports.getExecutionTime = exports.pluralize = exports.slash = exports.dumpBundle = exports.getFallbackEntryPointsOrExit = void 0;
|
|
4
4
|
exports.getFallbackEntryPointsOrExit = jest.fn((entrypoints) => entrypoints.map(() => ({ path: '' })));
|
|
5
|
-
exports.getTotals = jest.fn(() => ({ errors: 0 }));
|
|
6
5
|
exports.dumpBundle = jest.fn(() => '');
|
|
7
6
|
exports.slash = jest.fn();
|
|
8
7
|
exports.pluralize = jest.fn();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
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 lint_1 = require("../../commands/lint");
|
|
13
|
+
const openapi_core_1 = require("@redocly/openapi-core");
|
|
14
|
+
const utils_1 = require("../../utils");
|
|
15
|
+
const config_1 = require("../fixtures/config");
|
|
16
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
17
|
+
jest.mock('@redocly/openapi-core');
|
|
18
|
+
jest.mock('../../utils');
|
|
19
|
+
jest.mock('perf_hooks');
|
|
20
|
+
const argvMock = {
|
|
21
|
+
entrypoints: ['openapi.yaml'],
|
|
22
|
+
'lint-config': 'off',
|
|
23
|
+
format: 'codeframe',
|
|
24
|
+
};
|
|
25
|
+
const versionMock = '1.0.0';
|
|
26
|
+
describe('handleLint', () => {
|
|
27
|
+
let processExitMock;
|
|
28
|
+
let exitCb;
|
|
29
|
+
const getMergedConfigMock = openapi_core_1.getMergedConfig;
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
|
32
|
+
perf_hooks_1.performance.now.mockImplementation(() => 42);
|
|
33
|
+
processExitMock = jest.spyOn(process, 'exit').mockImplementation();
|
|
34
|
+
jest.spyOn(process, 'once').mockImplementation((_e, cb) => {
|
|
35
|
+
exitCb = cb;
|
|
36
|
+
return process.on(_e, cb);
|
|
37
|
+
});
|
|
38
|
+
getMergedConfigMock.mockReturnValue(config_1.ConfigFixture);
|
|
39
|
+
});
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
getMergedConfigMock.mockReset();
|
|
42
|
+
});
|
|
43
|
+
describe('loadConfig and getEnrtypoints stage', () => {
|
|
44
|
+
it('shoul call loadConfig and getFallbackEntryPointsOrExit', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
yield lint_1.handleLint(argvMock, versionMock);
|
|
46
|
+
expect(openapi_core_1.loadConfig).toHaveBeenCalledWith(undefined, undefined, undefined);
|
|
47
|
+
expect(utils_1.getFallbackEntryPointsOrExit).toHaveBeenCalled();
|
|
48
|
+
}));
|
|
49
|
+
it('should call loadConfig with args if such exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { config: '/path/redocly.yaml', extends: ['some/path'] }), versionMock);
|
|
51
|
+
expect(openapi_core_1.loadConfig).toHaveBeenCalledWith('/path/redocly.yaml', ['some/path'], undefined);
|
|
52
|
+
}));
|
|
53
|
+
it('should call mergedConfig with clear ignore if `generate-ignore-file` argv', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
54
|
+
yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { 'generate-ignore-file': true }), versionMock);
|
|
55
|
+
expect(getMergedConfigMock).toHaveBeenCalled();
|
|
56
|
+
}));
|
|
57
|
+
});
|
|
58
|
+
describe('loop through entrypints and lint stage', () => {
|
|
59
|
+
it('should call getMergedConfig and lint ', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
+
yield lint_1.handleLint(argvMock, versionMock);
|
|
61
|
+
expect(perf_hooks_1.performance.now).toHaveBeenCalled();
|
|
62
|
+
expect(getMergedConfigMock).toHaveBeenCalled();
|
|
63
|
+
expect(openapi_core_1.lint).toHaveBeenCalled();
|
|
64
|
+
}));
|
|
65
|
+
it('should call skipRules,skipPreprocessors and addIgnore with argv', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
66
|
+
openapi_core_1.lint.mockResolvedValueOnce(['problem']);
|
|
67
|
+
yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { 'skip-preprocessor': ['preprocessor'], 'skip-rule': ['rule'], 'generate-ignore-file': true }), versionMock);
|
|
68
|
+
expect(config_1.ConfigFixture.lint.skipRules).toHaveBeenCalledWith(['rule']);
|
|
69
|
+
expect(config_1.ConfigFixture.lint.skipPreprocessors).toHaveBeenCalledWith(['preprocessor']);
|
|
70
|
+
}));
|
|
71
|
+
it('should call formatProblems and getExecutionTime with argv', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
|
+
openapi_core_1.lint.mockResolvedValueOnce(['problem']);
|
|
73
|
+
yield lint_1.handleLint(Object.assign(Object.assign({}, argvMock), { 'max-problems': 2, format: 'stylish' }), versionMock);
|
|
74
|
+
expect(openapi_core_1.getTotals).toHaveBeenCalledWith(['problem']);
|
|
75
|
+
expect(openapi_core_1.formatProblems).toHaveBeenCalledWith(['problem'], {
|
|
76
|
+
format: 'stylish',
|
|
77
|
+
maxProblems: 2,
|
|
78
|
+
totals: { errors: 0 },
|
|
79
|
+
version: versionMock,
|
|
80
|
+
});
|
|
81
|
+
expect(utils_1.getExecutionTime).toHaveBeenCalledWith(42);
|
|
82
|
+
}));
|
|
83
|
+
it('should catch error in handleError if something fails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
84
|
+
openapi_core_1.lint.mockRejectedValueOnce('error');
|
|
85
|
+
yield lint_1.handleLint(argvMock, versionMock);
|
|
86
|
+
expect(utils_1.handleError).toHaveBeenCalledWith('error', '');
|
|
87
|
+
}));
|
|
88
|
+
});
|
|
89
|
+
describe('erros and warning handle after lint stage', () => {
|
|
90
|
+
it('should call printLintTotals and printLintTotals', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
91
|
+
yield lint_1.handleLint(argvMock, versionMock);
|
|
92
|
+
expect(utils_1.printUnusedWarnings).toHaveBeenCalled();
|
|
93
|
+
}));
|
|
94
|
+
it('should call exit with 0 if no errors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
+
yield lint_1.handleLint(argvMock, versionMock);
|
|
96
|
+
exitCb === null || exitCb === void 0 ? void 0 : exitCb();
|
|
97
|
+
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
98
|
+
}));
|
|
99
|
+
it('should exit with 1 if tootals error > 0', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
100
|
+
openapi_core_1.getTotals.mockReturnValueOnce({ errors: 1 });
|
|
101
|
+
yield lint_1.handleLint(argvMock, versionMock);
|
|
102
|
+
exitCb === null || exitCb === void 0 ? void 0 : exitCb();
|
|
103
|
+
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
104
|
+
}));
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const openapi_core_1 = require("@redocly/openapi-core");
|
|
13
|
+
const utils_1 = require("../../utils");
|
|
13
14
|
const push_1 = require("../../commands/push");
|
|
14
15
|
jest.mock('fs');
|
|
15
16
|
jest.mock('node-fetch', () => ({
|
|
@@ -32,7 +33,9 @@ describe('push', () => {
|
|
|
32
33
|
entrypoint: 'spec.json',
|
|
33
34
|
destination: '@org/my-api@1.0.0',
|
|
34
35
|
branchName: 'test',
|
|
35
|
-
'public': true
|
|
36
|
+
'public': true,
|
|
37
|
+
'batch-id': '123',
|
|
38
|
+
'batch-size': 2,
|
|
36
39
|
});
|
|
37
40
|
expect(redoclyClient.registryApi.prepareFileUpload).toBeCalledTimes(1);
|
|
38
41
|
expect(redoclyClient.registryApi.pushApi).toBeCalledTimes(1);
|
|
@@ -45,8 +48,34 @@ describe('push', () => {
|
|
|
45
48
|
organizationId: 'org',
|
|
46
49
|
rootFilePath: 'filePath',
|
|
47
50
|
version: '1.0.0',
|
|
51
|
+
batchId: '123',
|
|
52
|
+
batchSize: 2,
|
|
48
53
|
});
|
|
49
54
|
}));
|
|
55
|
+
it('fails if batchId value is an empty string', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
|
+
yield push_1.handlePush({
|
|
57
|
+
upsert: true,
|
|
58
|
+
entrypoint: 'spec.json',
|
|
59
|
+
destination: '@org/my-api@1.0.0',
|
|
60
|
+
branchName: 'test',
|
|
61
|
+
'public': true,
|
|
62
|
+
'batch-id': ' ',
|
|
63
|
+
'batch-size': 2,
|
|
64
|
+
});
|
|
65
|
+
expect(utils_1.exitWithError).toBeCalledTimes(1);
|
|
66
|
+
}));
|
|
67
|
+
it('fails if batchSize value is less than 2', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
68
|
+
yield push_1.handlePush({
|
|
69
|
+
upsert: true,
|
|
70
|
+
entrypoint: 'spec.json',
|
|
71
|
+
destination: '@org/my-api@1.0.0',
|
|
72
|
+
branchName: 'test',
|
|
73
|
+
'public': true,
|
|
74
|
+
'batch-id': '123',
|
|
75
|
+
'batch-size': 1,
|
|
76
|
+
});
|
|
77
|
+
expect(utils_1.exitWithError).toBeCalledTimes(1);
|
|
78
|
+
}));
|
|
50
79
|
});
|
|
51
80
|
describe('transformPush', () => {
|
|
52
81
|
it('should adapt the existing syntax', () => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="jest" />
|
|
2
|
+
export declare const ConfigFixture: {
|
|
3
|
+
configFile: null;
|
|
4
|
+
lint: {
|
|
5
|
+
addIgnore: jest.Mock<any, any>;
|
|
6
|
+
skipRules: jest.Mock<any, any>;
|
|
7
|
+
skipPreprocessors: jest.Mock<any, any>;
|
|
8
|
+
saveIgnore: jest.Mock<any, any>;
|
|
9
|
+
skipDecorators: jest.Mock<any, any>;
|
|
10
|
+
ignore: null;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConfigFixture = void 0;
|
|
4
|
+
exports.ConfigFixture = {
|
|
5
|
+
configFile: null,
|
|
6
|
+
lint: {
|
|
7
|
+
addIgnore: jest.fn(),
|
|
8
|
+
skipRules: jest.fn(),
|
|
9
|
+
skipPreprocessors: jest.fn(),
|
|
10
|
+
saveIgnore: jest.fn(),
|
|
11
|
+
skipDecorators: jest.fn(),
|
|
12
|
+
ignore: null,
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const utils_1 = require("../utils");
|
|
4
|
-
|
|
4
|
+
const colorette_1 = require("colorette");
|
|
5
|
+
jest.mock('os');
|
|
6
|
+
jest.mock('colorette');
|
|
5
7
|
describe('isSubdir', () => {
|
|
6
8
|
it('can correctly determine if subdir', () => {
|
|
7
9
|
[
|
|
@@ -39,3 +41,39 @@ describe('pathToFilename', () => {
|
|
|
39
41
|
expect(processedPath).toEqual('user_createWithList');
|
|
40
42
|
});
|
|
41
43
|
});
|
|
44
|
+
describe('printConfigLintTotals', () => {
|
|
45
|
+
const totalProblemsMock = {
|
|
46
|
+
errors: 1,
|
|
47
|
+
warnings: 0,
|
|
48
|
+
ignored: 0,
|
|
49
|
+
};
|
|
50
|
+
const redColoretteMocks = colorette_1.red;
|
|
51
|
+
const yellowColoretteMocks = colorette_1.yellow;
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
yellowColoretteMocks.mockImplementation((text) => text);
|
|
54
|
+
redColoretteMocks.mockImplementation((text) => text);
|
|
55
|
+
jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
|
56
|
+
});
|
|
57
|
+
it('should print errors if such exist', () => {
|
|
58
|
+
utils_1.printConfigLintTotals(totalProblemsMock);
|
|
59
|
+
expect(process.stderr.write).toHaveBeenCalledWith('❌ Your config has 1 error.\n');
|
|
60
|
+
expect(redColoretteMocks).toHaveBeenCalledWith('❌ Your config has 1 error.\n');
|
|
61
|
+
});
|
|
62
|
+
it('should print warnign and error', () => {
|
|
63
|
+
utils_1.printConfigLintTotals(Object.assign(Object.assign({}, totalProblemsMock), { warnings: 2 }));
|
|
64
|
+
expect(process.stderr.write).toHaveBeenCalledWith('❌ Your config has 1 error and 2 warnings.\n');
|
|
65
|
+
expect(redColoretteMocks).toHaveBeenCalledWith('❌ Your config has 1 error and 2 warnings.\n');
|
|
66
|
+
});
|
|
67
|
+
it('should print warnign if no error', () => {
|
|
68
|
+
utils_1.printConfigLintTotals(Object.assign(Object.assign({}, totalProblemsMock), { errors: 0, warnings: 2 }));
|
|
69
|
+
expect(process.stderr.write).toHaveBeenCalledWith('You have 2 warnings.\n');
|
|
70
|
+
expect(yellowColoretteMocks).toHaveBeenCalledWith('You have 2 warnings.\n');
|
|
71
|
+
});
|
|
72
|
+
it('should print nothing if no error and no warnings', () => {
|
|
73
|
+
const result = utils_1.printConfigLintTotals(Object.assign(Object.assign({}, totalProblemsMock), { errors: 0 }));
|
|
74
|
+
expect(result).toBeUndefined();
|
|
75
|
+
expect(process.stderr.write).toHaveBeenCalledTimes(0);
|
|
76
|
+
expect(yellowColoretteMocks).toHaveBeenCalledTimes(0);
|
|
77
|
+
expect(redColoretteMocks).toHaveBeenCalledTimes(0);
|
|
78
|
+
});
|
|
79
|
+
});
|
package/lib/commands/lint.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { OutputFormat } from '@redocly/openapi-core';
|
|
2
|
-
export declare
|
|
1
|
+
import { OutputFormat, RuleSeverity } from '@redocly/openapi-core';
|
|
2
|
+
export declare type LintOptions = {
|
|
3
3
|
entrypoints: string[];
|
|
4
4
|
'max-problems'?: number;
|
|
5
5
|
'generate-ignore-file'?: boolean;
|
|
6
6
|
'skip-rule'?: string[];
|
|
7
7
|
'skip-preprocessor'?: string[];
|
|
8
|
+
'lint-config': RuleSeverity;
|
|
8
9
|
extends?: string[];
|
|
9
10
|
config?: string;
|
|
10
11
|
format: OutputFormat;
|
|
11
|
-
}
|
|
12
|
+
};
|
|
13
|
+
export declare function handleLint(argv: LintOptions, version: string): Promise<void>;
|
package/lib/commands/lint.js
CHANGED
|
@@ -16,7 +16,7 @@ const colorette_1 = require("colorette");
|
|
|
16
16
|
const perf_hooks_1 = require("perf_hooks");
|
|
17
17
|
function handleLint(argv, version) {
|
|
18
18
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
-
const config = yield openapi_core_1.loadConfig(argv.config, argv.extends);
|
|
19
|
+
const config = yield openapi_core_1.loadConfig(argv.config, argv.extends, lintConfigCallback(argv, version));
|
|
20
20
|
const entrypoints = yield utils_1.getFallbackEntryPointsOrExit(argv.entrypoints, config);
|
|
21
21
|
if (argv['generate-ignore-file']) {
|
|
22
22
|
config.lint.ignore = {}; // clear ignore
|
|
@@ -78,3 +78,26 @@ function handleLint(argv, version) {
|
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
exports.handleLint = handleLint;
|
|
81
|
+
function lintConfigCallback(argv, version) {
|
|
82
|
+
if (argv['lint-config'] === 'off') {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
return (config) => __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
const { 'max-problems': maxProblems, format } = argv;
|
|
87
|
+
const configPath = openapi_core_1.findConfig(argv.config) || '';
|
|
88
|
+
const stringYaml = openapi_core_1.stringifyYaml(config);
|
|
89
|
+
const configContent = openapi_core_1.makeDocumentFromString(stringYaml, configPath);
|
|
90
|
+
const problems = yield openapi_core_1.lintConfig({
|
|
91
|
+
document: configContent,
|
|
92
|
+
severity: argv['lint-config'],
|
|
93
|
+
});
|
|
94
|
+
const fileTotals = openapi_core_1.getTotals(problems);
|
|
95
|
+
openapi_core_1.formatProblems(problems, {
|
|
96
|
+
format,
|
|
97
|
+
maxProblems,
|
|
98
|
+
totals: fileTotals,
|
|
99
|
+
version,
|
|
100
|
+
});
|
|
101
|
+
utils_1.printConfigLintTotals(fileTotals);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
</style>
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
|
-
<script src="https://cdn.
|
|
18
|
+
<script src="https://cdn.redoc.ly/reference-docs/latest/oauth2-redirect.js"></script>
|
|
19
19
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
20
20
|
</body>
|
|
21
21
|
</html>
|
|
@@ -32,15 +32,15 @@ function getPageHTML(htmlTemplate, redocOptions = {}, useRedocPro, wsPort) {
|
|
|
32
32
|
<script src="/simplewebsocket.min.js"></script>
|
|
33
33
|
<script src="/hot.js"></script>
|
|
34
34
|
<script src="${useRedocPro
|
|
35
|
-
? 'https://cdn.
|
|
36
|
-
: 'https://cdn.
|
|
35
|
+
? 'https://cdn.redoc.ly/reference-docs/latest/redocly-reference-docs.min.js'
|
|
36
|
+
: 'https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js'}"></script>
|
|
37
37
|
`,
|
|
38
38
|
redocHTML: `
|
|
39
39
|
<div id="redoc"></div>
|
|
40
40
|
<script>
|
|
41
41
|
var container = document.getElementById('redoc');
|
|
42
42
|
${useRedocPro
|
|
43
|
-
? "window[window.__REDOC_EXPORT].setPublicPath('https://cdn.
|
|
43
|
+
? "window[window.__REDOC_EXPORT].setPublicPath('https://cdn.redoc.ly/reference-docs/latest/');"
|
|
44
44
|
: ''}
|
|
45
45
|
window[window.__REDOC_EXPORT].init("/openapi.json", ${JSON.stringify(redocOptions)}, container)
|
|
46
46
|
</script>`,
|
package/lib/commands/push.d.ts
CHANGED
package/lib/commands/push.js
CHANGED
|
@@ -43,6 +43,8 @@ function handlePush(argv) {
|
|
|
43
43
|
}
|
|
44
44
|
const startedAt = perf_hooks_1.performance.now();
|
|
45
45
|
const { destination, branchName, upsert } = argv;
|
|
46
|
+
const batchId = argv['batch-id'];
|
|
47
|
+
const batchSize = argv['batch-size'];
|
|
46
48
|
if (destination &&
|
|
47
49
|
!(validateDestination(destination) || validateDestinationWithoutOrganization(destination))) {
|
|
48
50
|
utils_1.exitWithError(`Destination argument value is not valid, please use the right format: ${colorette_1.yellow('<@organization-id/api-name@api-version>')}`);
|
|
@@ -55,6 +57,12 @@ function handlePush(argv) {
|
|
|
55
57
|
if (name && version && !entrypoint) {
|
|
56
58
|
utils_1.exitWithError(`No entrypoint found that matches ${colorette_1.blue(`${name}@${version}`)}. Please make sure you have provided the correct data in the config file.`);
|
|
57
59
|
}
|
|
60
|
+
if (batchId && !batchId.trim()) {
|
|
61
|
+
utils_1.exitWithError(`The ${colorette_1.blue(`batch-id`)} option value is not valid, please avoid using an empty string.`);
|
|
62
|
+
}
|
|
63
|
+
if (batchSize && batchSize < 2) {
|
|
64
|
+
utils_1.exitWithError(`The ${colorette_1.blue(`batch-size`)} option value is not valid, please use the integer bigger than 1.`);
|
|
65
|
+
}
|
|
58
66
|
const apis = entrypoint ? { [`${name}@${version}`]: { root: entrypoint } } : config.apis;
|
|
59
67
|
for (const [apiNameAndVersion, { root: entrypoint }] of Object.entries(apis)) {
|
|
60
68
|
const resolvedConfig = openapi_core_1.getMergedConfig(config, apiNameAndVersion);
|
|
@@ -97,7 +105,9 @@ function handlePush(argv) {
|
|
|
97
105
|
filePaths,
|
|
98
106
|
branch: branchName,
|
|
99
107
|
isUpsert: upsert,
|
|
100
|
-
isPublic: argv['public']
|
|
108
|
+
isPublic: argv['public'],
|
|
109
|
+
batchId: batchId,
|
|
110
|
+
batchSize: batchSize,
|
|
101
111
|
});
|
|
102
112
|
}
|
|
103
113
|
catch (error) {
|
package/lib/index.js
CHANGED
|
@@ -78,8 +78,8 @@ yargs
|
|
|
78
78
|
},
|
|
79
79
|
'without-x-tag-groups': {
|
|
80
80
|
description: 'Skip automated x-tagGroups creation',
|
|
81
|
-
type: 'boolean'
|
|
82
|
-
}
|
|
81
|
+
type: 'boolean',
|
|
82
|
+
},
|
|
83
83
|
}), (argv) => {
|
|
84
84
|
join_1.handleJoin(argv, version);
|
|
85
85
|
})
|
|
@@ -90,18 +90,29 @@ yargs
|
|
|
90
90
|
.option({
|
|
91
91
|
branch: { type: 'string', alias: 'b' },
|
|
92
92
|
upsert: { type: 'boolean', alias: 'u' },
|
|
93
|
-
'
|
|
93
|
+
'batch-id': {
|
|
94
|
+
description: 'Specifies the ID of the CI job that the current push will be associated with.',
|
|
95
|
+
type: 'string',
|
|
96
|
+
requiresArg: true,
|
|
97
|
+
},
|
|
98
|
+
'batch-size': {
|
|
99
|
+
description: 'Specifies the total number of CI jobs planned to be pushed.',
|
|
100
|
+
type: 'number',
|
|
101
|
+
requiresArg: true,
|
|
102
|
+
},
|
|
94
103
|
region: { description: 'Specify a region.', alias: 'r', choices: types_1.regionChoices },
|
|
95
104
|
'skip-decorator': {
|
|
96
105
|
description: 'Ignore certain decorators.',
|
|
97
106
|
array: true,
|
|
98
107
|
type: 'string',
|
|
99
108
|
},
|
|
100
|
-
|
|
109
|
+
public: {
|
|
101
110
|
description: 'Make API registry available to the public',
|
|
102
111
|
type: 'boolean',
|
|
103
112
|
},
|
|
104
|
-
})
|
|
113
|
+
})
|
|
114
|
+
.implies('batch-id', 'batch-size')
|
|
115
|
+
.implies('batch-size', 'batch-id'), push_1.transformPush(push_1.handlePush))
|
|
105
116
|
.command('lint [entrypoints...]', 'Lint definition.', (yargs) => yargs.positional('entrypoints', { array: true, type: 'string', demandOption: true }).option({
|
|
106
117
|
format: {
|
|
107
118
|
description: 'Use a specific output format.',
|
|
@@ -134,6 +145,15 @@ yargs
|
|
|
134
145
|
array: true,
|
|
135
146
|
type: 'string',
|
|
136
147
|
},
|
|
148
|
+
'lint-config': {
|
|
149
|
+
description: 'Apply severity for linting the config file.',
|
|
150
|
+
choices: [
|
|
151
|
+
'warn',
|
|
152
|
+
'error',
|
|
153
|
+
'off',
|
|
154
|
+
],
|
|
155
|
+
default: 'warn',
|
|
156
|
+
},
|
|
137
157
|
config: {
|
|
138
158
|
description: 'Specify path to the config file.',
|
|
139
159
|
requiresArg: true,
|
package/lib/utils.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare function writeYaml(data: any, filename: string, noRefs?: boolean)
|
|
|
17
17
|
export declare function pluralize(label: string, num: number): string;
|
|
18
18
|
export declare function handleError(e: Error, ref: string): void;
|
|
19
19
|
export declare function printLintTotals(totals: Totals, definitionsCount: number): void;
|
|
20
|
+
export declare function printConfigLintTotals(totals: Totals): void;
|
|
20
21
|
export declare function getOutputFileName(entrypoint: string, entries: number, output?: string, ext?: BundleOutputFormat): {
|
|
21
22
|
outputFile: string;
|
|
22
23
|
ext: BundleOutputFormat;
|
package/lib/utils.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.isSubdir = exports.exitWithError = exports.printUnusedWarnings = exports.getOutputFileName = exports.printLintTotals = exports.handleError = exports.pluralize = exports.writeYaml = exports.readYaml = exports.promptUser = exports.saveBundle = exports.dumpBundle = exports.CircularJSONNotSupportedError = exports.escapeLanguageName = exports.pathToFilename = exports.printExecutionTime = exports.getExecutionTime = exports.getFallbackEntryPointsOrExit = void 0;
|
|
12
|
+
exports.isSubdir = exports.exitWithError = exports.printUnusedWarnings = exports.getOutputFileName = exports.printConfigLintTotals = exports.printLintTotals = exports.handleError = exports.pluralize = exports.writeYaml = exports.readYaml = exports.promptUser = exports.saveBundle = exports.dumpBundle = exports.CircularJSONNotSupportedError = exports.escapeLanguageName = exports.pathToFilename = exports.printExecutionTime = exports.getExecutionTime = exports.getFallbackEntryPointsOrExit = void 0;
|
|
13
13
|
const path_1 = require("path");
|
|
14
14
|
const colorette_1 = require("colorette");
|
|
15
15
|
const perf_hooks_1 = require("perf_hooks");
|
|
@@ -211,6 +211,18 @@ function printLintTotals(totals, definitionsCount) {
|
|
|
211
211
|
process.stderr.write('\n');
|
|
212
212
|
}
|
|
213
213
|
exports.printLintTotals = printLintTotals;
|
|
214
|
+
function printConfigLintTotals(totals) {
|
|
215
|
+
if (totals.errors > 0) {
|
|
216
|
+
process.stderr.write(colorette_1.red(`❌ Your config has ${totals.errors} ${pluralize('error', totals.errors)}${totals.warnings > 0
|
|
217
|
+
? ` and ${totals.warnings} ${pluralize('warning', totals.warnings)}`
|
|
218
|
+
: ''}.\n`));
|
|
219
|
+
}
|
|
220
|
+
else if (totals.warnings > 0) {
|
|
221
|
+
process.stderr.write(colorette_1.yellow(`You have ${totals.warnings} ${pluralize('warning', totals.warnings)}.\n`));
|
|
222
|
+
}
|
|
223
|
+
;
|
|
224
|
+
}
|
|
225
|
+
exports.printConfigLintTotals = printConfigLintTotals;
|
|
214
226
|
function getOutputFileName(entrypoint, entries, output, ext) {
|
|
215
227
|
if (!output) {
|
|
216
228
|
return { outputFile: 'stdout', ext: ext || 'yaml' };
|
|
@@ -248,7 +260,7 @@ function printUnusedWarnings(config) {
|
|
|
248
260
|
process.stderr.write(colorette_1.yellow(`[WARNING] Unused decorators found in ${colorette_1.blue(config.configFile || '')}: ${decorators.join(', ')}.\n`));
|
|
249
261
|
}
|
|
250
262
|
if (rules.length || preprocessors.length) {
|
|
251
|
-
process.stderr.write(`Check the spelling and verify
|
|
263
|
+
process.stderr.write(`Check the spelling and verify the added plugin prefix.\n`);
|
|
252
264
|
}
|
|
253
265
|
}
|
|
254
266
|
exports.printUnusedWarnings = printUnusedWarnings;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/cli",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.103",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"Andriy Leliv <andriy@redoc.ly> (https://redoc.ly/)"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@redocly/openapi-core": "1.0.0-beta.
|
|
38
|
+
"@redocly/openapi-core": "1.0.0-beta.103",
|
|
39
39
|
"assert-node-version": "^1.0.3",
|
|
40
40
|
"chokidar": "^3.5.1",
|
|
41
41
|
"colorette": "^1.2.0",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ConfigFixture } from './../../__tests__/fixtures/config';
|
|
2
|
+
|
|
1
3
|
export const __redoclyClient = {
|
|
2
4
|
isAuthorizedWithRedocly: jest.fn().mockResolvedValue(true),
|
|
3
5
|
isAuthorizedWithRedoclyByRegion: jest.fn().mockResolvedValue(true),
|
|
@@ -14,13 +16,11 @@ export const __redoclyClient = {
|
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
export const RedoclyClient = jest.fn(() => __redoclyClient);
|
|
17
|
-
export const loadConfig = jest.fn(() =>
|
|
18
|
-
configFile: null,
|
|
19
|
-
lint: { skipRules: jest.fn(), skipPreprocessors: jest.fn(), skipDecorators: jest.fn() },
|
|
20
|
-
}));
|
|
19
|
+
export const loadConfig = jest.fn(() => ConfigFixture);
|
|
21
20
|
export const getMergedConfig = jest.fn();
|
|
22
21
|
export const lint = jest.fn();
|
|
23
22
|
export const bundle = jest.fn(() => ({ bundle: { parsed: null }, problems: null }));
|
|
24
23
|
export const getTotals = jest.fn(() => ({ errors: 0 }));
|
|
25
24
|
export const formatProblems = jest.fn();
|
|
26
25
|
export const slash = jest.fn();
|
|
26
|
+
export const findConfig = jest.fn();
|
package/src/__mocks__/utils.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export const getFallbackEntryPointsOrExit = jest.fn((entrypoints) => entrypoints.map(() => ({ path: '' })));
|
|
2
|
-
export const getTotals = jest.fn(() => ({ errors: 0 }));
|
|
3
2
|
export const dumpBundle = jest.fn(() => '');
|
|
4
3
|
export const slash = jest.fn();
|
|
5
4
|
export const pluralize = jest.fn();
|