@redocly/cli 1.0.0 → 1.0.1

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 (57) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/commands/build-docs/index.js +2 -4
  3. package/lib/commands/build-docs/utils.d.ts +1 -1
  4. package/lib/commands/build-docs/utils.js +3 -3
  5. package/package.json +2 -2
  6. package/src/__mocks__/@redocly/openapi-core.ts +80 -0
  7. package/src/__mocks__/documents.ts +63 -0
  8. package/src/__mocks__/fs.ts +6 -0
  9. package/src/__mocks__/perf_hooks.ts +3 -0
  10. package/src/__mocks__/redoc.ts +2 -0
  11. package/src/__mocks__/utils.ts +19 -0
  12. package/src/__tests__/commands/build-docs.test.ts +62 -0
  13. package/src/__tests__/commands/bundle.test.ts +150 -0
  14. package/src/__tests__/commands/join.test.ts +122 -0
  15. package/src/__tests__/commands/lint.test.ts +190 -0
  16. package/src/__tests__/commands/push-region.test.ts +58 -0
  17. package/src/__tests__/commands/push.test.ts +492 -0
  18. package/src/__tests__/fetch-with-timeout.test.ts +35 -0
  19. package/src/__tests__/fixtures/config.ts +21 -0
  20. package/src/__tests__/fixtures/openapi.json +0 -0
  21. package/src/__tests__/fixtures/openapi.yaml +0 -0
  22. package/src/__tests__/fixtures/redocly.yaml +0 -0
  23. package/src/__tests__/utils.test.ts +564 -0
  24. package/src/__tests__/wrapper.test.ts +57 -0
  25. package/src/assert-node-version.ts +8 -0
  26. package/src/commands/build-docs/index.ts +50 -0
  27. package/src/commands/build-docs/template.hbs +23 -0
  28. package/src/commands/build-docs/types.ts +24 -0
  29. package/src/commands/build-docs/utils.ts +110 -0
  30. package/src/commands/bundle.ts +177 -0
  31. package/src/commands/join.ts +811 -0
  32. package/src/commands/lint.ts +151 -0
  33. package/src/commands/login.ts +27 -0
  34. package/src/commands/preview-docs/index.ts +190 -0
  35. package/src/commands/preview-docs/preview-server/default.hbs +24 -0
  36. package/src/commands/preview-docs/preview-server/hot.js +42 -0
  37. package/src/commands/preview-docs/preview-server/oauth2-redirect.html +21 -0
  38. package/src/commands/preview-docs/preview-server/preview-server.ts +156 -0
  39. package/src/commands/preview-docs/preview-server/server.ts +91 -0
  40. package/src/commands/push.ts +441 -0
  41. package/src/commands/split/__tests__/fixtures/samples.json +61 -0
  42. package/src/commands/split/__tests__/fixtures/spec.json +70 -0
  43. package/src/commands/split/__tests__/fixtures/webhooks.json +85 -0
  44. package/src/commands/split/__tests__/index.test.ts +137 -0
  45. package/src/commands/split/index.ts +385 -0
  46. package/src/commands/split/types.ts +85 -0
  47. package/src/commands/stats.ts +119 -0
  48. package/src/custom.d.ts +1 -0
  49. package/src/fetch-with-timeout.ts +21 -0
  50. package/src/index.ts +484 -0
  51. package/src/js-utils.ts +17 -0
  52. package/src/types.ts +40 -0
  53. package/src/update-version-notifier.ts +106 -0
  54. package/src/utils.ts +590 -0
  55. package/src/wrapper.ts +42 -0
  56. package/tsconfig.json +9 -0
  57. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,190 @@
1
+ import { handleLint, LintOptions } from '../../commands/lint';
2
+ import {
3
+ getMergedConfig,
4
+ lint,
5
+ getTotals,
6
+ formatProblems,
7
+ doesYamlFileExist,
8
+ } from '@redocly/openapi-core';
9
+ import {
10
+ getFallbackApisOrExit,
11
+ getExecutionTime,
12
+ printUnusedWarnings,
13
+ handleError,
14
+ exitWithError,
15
+ loadConfigAndHandleErrors,
16
+ checkIfRulesetExist,
17
+ } from '../../utils';
18
+ import { ConfigFixture } from '../fixtures/config';
19
+ import { performance } from 'perf_hooks';
20
+ import { commandWrapper } from '../../wrapper';
21
+ import { Arguments } from 'yargs';
22
+ import { blue } from 'colorette';
23
+
24
+ jest.mock('@redocly/openapi-core');
25
+ jest.mock('../../utils');
26
+ jest.mock('perf_hooks');
27
+
28
+ jest.mock('../../update-version-notifier', () => ({
29
+ version: '1.0.0',
30
+ }));
31
+
32
+ const argvMock = {
33
+ apis: ['openapi.yaml'],
34
+ 'lint-config': 'off',
35
+ format: 'codeframe',
36
+ } as Arguments<LintOptions>;
37
+
38
+ describe('handleLint', () => {
39
+ let processExitMock: jest.SpyInstance;
40
+ let exitCb: any;
41
+ const getMergedConfigMock = getMergedConfig as jest.Mock<any, any>;
42
+
43
+ beforeEach(() => {
44
+ jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
45
+ (performance.now as jest.Mock<any, any>).mockImplementation(() => 42);
46
+ processExitMock = jest.spyOn(process, 'exit').mockImplementation();
47
+ jest.spyOn(process, 'once').mockImplementation((_e, cb) => {
48
+ exitCb = cb;
49
+ return process.on(_e, cb);
50
+ });
51
+ getMergedConfigMock.mockReturnValue(ConfigFixture);
52
+ (doesYamlFileExist as jest.Mock<any, any>).mockImplementation(
53
+ (path) => path === 'redocly.yaml'
54
+ );
55
+ });
56
+
57
+ afterEach(() => {
58
+ getMergedConfigMock.mockReset();
59
+ });
60
+
61
+ describe('loadConfig and getEnrtypoints stage', () => {
62
+ it('should fail if config file does not exist', async () => {
63
+ await commandWrapper(handleLint)({ ...argvMock, config: 'config.yaml' });
64
+ expect(exitWithError).toHaveBeenCalledWith(
65
+ 'Please, provide valid path to the configuration file'
66
+ );
67
+ });
68
+
69
+ it('should call loadConfigAndHandleErrors and getFallbackApisOrExit', async () => {
70
+ await commandWrapper(handleLint)(argvMock);
71
+ expect(loadConfigAndHandleErrors).toHaveBeenCalledWith({
72
+ configPath: undefined,
73
+ customExtends: undefined,
74
+ processRawConfig: undefined,
75
+ });
76
+ expect(getFallbackApisOrExit).toHaveBeenCalled();
77
+ });
78
+
79
+ it('should call loadConfig with args if such exist', async () => {
80
+ await commandWrapper(handleLint)({
81
+ ...argvMock,
82
+ config: 'redocly.yaml',
83
+ extends: ['some/path'],
84
+ });
85
+ expect(loadConfigAndHandleErrors).toHaveBeenCalledWith({
86
+ configPath: 'redocly.yaml',
87
+ customExtends: ['some/path'],
88
+ processRawConfig: undefined,
89
+ });
90
+ });
91
+
92
+ it('should call mergedConfig with clear ignore if `generate-ignore-file` argv', async () => {
93
+ await commandWrapper(handleLint)({ ...argvMock, 'generate-ignore-file': true });
94
+ expect(getMergedConfigMock).toHaveBeenCalled();
95
+ });
96
+
97
+ it('should check if ruleset exist', async () => {
98
+ await commandWrapper(handleLint)(argvMock);
99
+ expect(checkIfRulesetExist).toHaveBeenCalledTimes(1);
100
+ });
101
+
102
+ it('should fail if apis not provided', async () => {
103
+ await commandWrapper(handleLint)({ ...argvMock, apis: [] });
104
+ expect(getFallbackApisOrExit).toHaveBeenCalledTimes(1);
105
+ expect(exitWithError).toHaveBeenCalledWith('No APIs were provided');
106
+ });
107
+ });
108
+
109
+ describe('loop through entrypoints and lint stage', () => {
110
+ it('should call getMergedConfig and lint ', async () => {
111
+ await commandWrapper(handleLint)(argvMock);
112
+ expect(performance.now).toHaveBeenCalled();
113
+ expect(getMergedConfigMock).toHaveBeenCalled();
114
+ expect(lint).toHaveBeenCalled();
115
+ });
116
+
117
+ it('should call skipRules,skipPreprocessors and addIgnore with argv', async () => {
118
+ (lint as jest.Mock<any, any>).mockResolvedValueOnce(['problem']);
119
+ await commandWrapper(handleLint)({
120
+ ...argvMock,
121
+ 'skip-preprocessor': ['preprocessor'],
122
+ 'skip-rule': ['rule'],
123
+ 'generate-ignore-file': true,
124
+ });
125
+ expect(ConfigFixture.styleguide.skipRules).toHaveBeenCalledWith(['rule']);
126
+ expect(ConfigFixture.styleguide.skipPreprocessors).toHaveBeenCalledWith(['preprocessor']);
127
+ });
128
+
129
+ it('should call formatProblems and getExecutionTime with argv', async () => {
130
+ (lint as jest.Mock<any, any>).mockResolvedValueOnce(['problem']);
131
+ await commandWrapper(handleLint)({ ...argvMock, 'max-problems': 2, format: 'stylish' });
132
+ expect(getTotals).toHaveBeenCalledWith(['problem']);
133
+ expect(formatProblems).toHaveBeenCalledWith(['problem'], {
134
+ format: 'stylish',
135
+ maxProblems: 2,
136
+ totals: { errors: 0 },
137
+ version: '1.0.0',
138
+ });
139
+ expect(getExecutionTime).toHaveBeenCalledWith(42);
140
+ });
141
+
142
+ it('should catch error in handleError if something fails', async () => {
143
+ (lint as jest.Mock<any, any>).mockRejectedValueOnce('error');
144
+ await commandWrapper(handleLint)(argvMock);
145
+ expect(handleError).toHaveBeenCalledWith('error', 'openapi.yaml');
146
+ });
147
+ });
148
+
149
+ describe('erros and warning handle after lint stage', () => {
150
+ it('should call printLintTotals and printLintTotals', async () => {
151
+ await commandWrapper(handleLint)(argvMock);
152
+ expect(printUnusedWarnings).toHaveBeenCalled();
153
+ });
154
+
155
+ it('should call exit with 0 if no errors', async () => {
156
+ (loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
157
+ return { ...ConfigFixture };
158
+ });
159
+ await commandWrapper(handleLint)(argvMock);
160
+ await exitCb?.();
161
+ expect(processExitMock).toHaveBeenCalledWith(0);
162
+ });
163
+
164
+ it('should exit with 1 if total errors > 0', async () => {
165
+ (getTotals as jest.Mock<any, any>).mockReturnValueOnce({ errors: 1 });
166
+ await commandWrapper(handleLint)(argvMock);
167
+ await exitCb?.();
168
+ expect(processExitMock).toHaveBeenCalledWith(1);
169
+ });
170
+
171
+ it('should use recommended fallback if no config', async () => {
172
+ (getMergedConfig as jest.Mock).mockImplementation(() => {
173
+ return {
174
+ styleguide: {
175
+ recommendedFallback: true,
176
+ rules: {},
177
+ skipRules: jest.fn(),
178
+ skipPreprocessors: jest.fn(),
179
+ },
180
+ };
181
+ });
182
+ await commandWrapper(handleLint)(argvMock);
183
+ expect(process.stderr.write).toHaveBeenCalledWith(
184
+ `No configurations were provided -- using built in ${blue(
185
+ 'recommended'
186
+ )} configuration by default.\n\n`
187
+ );
188
+ });
189
+ });
190
+ });
@@ -0,0 +1,58 @@
1
+ import { getMergedConfig } from '@redocly/openapi-core';
2
+ import { handlePush } from '../../commands/push';
3
+ import { promptClientToken } from '../../commands/login';
4
+ import { ConfigFixture } from '../fixtures/config';
5
+
6
+ jest.mock('fs');
7
+ jest.mock('node-fetch', () => ({
8
+ default: jest.fn(() => ({
9
+ ok: true,
10
+ json: jest.fn().mockResolvedValue({}),
11
+ })),
12
+ }));
13
+ jest.mock('@redocly/openapi-core');
14
+ jest.mock('../../commands/login');
15
+ jest.mock('../../utils');
16
+
17
+ (getMergedConfig as jest.Mock).mockImplementation((config) => config);
18
+
19
+ const mockPromptClientToken = promptClientToken as jest.MockedFunction<typeof promptClientToken>;
20
+
21
+ describe('push-with-region', () => {
22
+ const redoclyClient = require('@redocly/openapi-core').__redoclyClient;
23
+ redoclyClient.isAuthorizedWithRedoclyByRegion = jest.fn().mockResolvedValue(false);
24
+
25
+ beforeAll(() => {
26
+ jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
27
+ });
28
+
29
+ it('should call login with default domain when region is US', async () => {
30
+ redoclyClient.domain = 'redoc.ly';
31
+ await handlePush(
32
+ {
33
+ upsert: true,
34
+ api: 'spec.json',
35
+ destination: '@org/my-api@1.0.0',
36
+ branchName: 'test',
37
+ },
38
+ ConfigFixture as any
39
+ );
40
+ expect(mockPromptClientToken).toBeCalledTimes(1);
41
+ expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
42
+ });
43
+
44
+ it('should call login with EU domain when region is EU', async () => {
45
+ redoclyClient.domain = 'eu.redocly.com';
46
+ await handlePush(
47
+ {
48
+ upsert: true,
49
+ api: 'spec.json',
50
+ destination: '@org/my-api@1.0.0',
51
+ branchName: 'test',
52
+ },
53
+ ConfigFixture as any
54
+ );
55
+ expect(mockPromptClientToken).toBeCalledTimes(1);
56
+ expect(mockPromptClientToken).toHaveBeenCalledWith(redoclyClient.domain);
57
+ });
58
+ });