@redocly/cli 1.8.2 → 1.9.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.
@@ -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.iteratePathItems = exports.handleSplit = void 0;
12
+ exports.iteratePathItems = exports.crawl = exports.startsWithComponents = exports.handleSplit = void 0;
13
13
  const colorette_1 = require("colorette");
14
14
  const fs = require("fs");
15
15
  const openapi_core_1 = require("@redocly/openapi-core");
@@ -44,9 +44,10 @@ function splitDefinition(openapi, openapiDir, pathSeparator, ext) {
44
44
  replace$Refs(openapi, openapiDir, componentsFiles);
45
45
  (0, miscellaneous_1.writeToFileByExtension)(openapi, path.join(openapiDir, `openapi.${ext}`));
46
46
  }
47
- function isStartsWithComponents(node) {
48
- return node.startsWith(types_1.componentsPath);
47
+ function startsWithComponents(node) {
48
+ return node.startsWith(`#/${types_1.COMPONENTS}/`);
49
49
  }
50
+ exports.startsWithComponents = startsWithComponents;
50
51
  function isSupportedExtension(filename) {
51
52
  return filename.endsWith('.yaml') || filename.endsWith('.yml') || filename.endsWith('.json');
52
53
  }
@@ -92,22 +93,22 @@ function traverseDirectoryDeepCallback(filename, directory, componentsFiles) {
92
93
  function crawl(object, visitor) {
93
94
  if (!(0, js_utils_1.isObject)(object))
94
95
  return;
96
+ visitor(object);
95
97
  for (const key of Object.keys(object)) {
96
- visitor(object, key);
97
98
  crawl(object[key], visitor);
98
99
  }
99
100
  }
101
+ exports.crawl = crawl;
100
102
  function replace$Refs(obj, relativeFrom, componentFiles = {}) {
101
103
  crawl(obj, (node) => {
102
- if (node.$ref && (0, js_utils_1.isString)(node.$ref) && isStartsWithComponents(node.$ref)) {
104
+ if (node.$ref && typeof node.$ref === 'string' && startsWithComponents(node.$ref)) {
103
105
  replace(node, '$ref');
104
106
  }
105
- else if (node.discriminator &&
106
- node.discriminator.mapping &&
107
- (0, js_utils_1.isObject)(node.discriminator.mapping)) {
107
+ else if ((0, js_utils_1.isObject)(node.discriminator) && (0, js_utils_1.isObject)(node.discriminator.mapping)) {
108
108
  const { mapping } = node.discriminator;
109
109
  for (const name of Object.keys(mapping)) {
110
- if ((0, js_utils_1.isString)(mapping[name]) && isStartsWithComponents(mapping[name])) {
110
+ const mappingPointer = mapping[name];
111
+ if (typeof mappingPointer === 'string' && startsWithComponents(mappingPointer)) {
111
112
  replace(node.discriminator.mapping, name);
112
113
  }
113
114
  }
@@ -4,14 +4,13 @@ export type Definition = Oas3_1Definition | Oas3Definition | Oas2Definition;
4
4
  export interface ComponentsFiles {
5
5
  [schemas: string]: any;
6
6
  }
7
- export interface refObj {
7
+ export interface RefObject {
8
8
  [$ref: string]: string;
9
9
  }
10
10
  export declare const COMPONENTS = "components";
11
11
  export declare const PATHS = "paths";
12
12
  export declare const WEBHOOKS = "webhooks";
13
13
  export declare const xWEBHOOKS = "x-webhooks";
14
- export declare const componentsPath = "#/components/";
15
14
  export declare enum OPENAPI3_METHOD {
16
15
  get = "get",
17
16
  put = "put",
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OPENAPI3_COMPONENT_NAMES = exports.OPENAPI3_COMPONENT = exports.OPENAPI3_METHOD_NAMES = exports.OPENAPI3_METHOD = exports.componentsPath = exports.xWEBHOOKS = exports.WEBHOOKS = exports.PATHS = exports.COMPONENTS = void 0;
3
+ exports.OPENAPI3_COMPONENT_NAMES = exports.OPENAPI3_COMPONENT = exports.OPENAPI3_METHOD_NAMES = exports.OPENAPI3_METHOD = exports.xWEBHOOKS = exports.WEBHOOKS = exports.PATHS = exports.COMPONENTS = void 0;
4
4
  exports.COMPONENTS = 'components';
5
5
  exports.PATHS = 'paths';
6
6
  exports.WEBHOOKS = 'webhooks';
7
7
  exports.xWEBHOOKS = 'x-webhooks';
8
- exports.componentsPath = `#/${exports.COMPONENTS}/`;
9
8
  var OPENAPI3_METHOD;
10
9
  (function (OPENAPI3_METHOD) {
11
10
  OPENAPI3_METHOD["get"] = "get";
@@ -1,4 +1,5 @@
1
- export declare function isObject(obj: any): boolean;
1
+ export declare function isObject(obj: unknown): obj is Record<string, unknown>;
2
2
  export declare function isEmptyObject(obj: any): boolean;
3
3
  export declare function isString(str: string): boolean;
4
4
  export declare function keysOf<T>(obj: T): (keyof T)[];
5
+ export declare function capitalize(s: string): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.keysOf = exports.isString = exports.isEmptyObject = exports.isObject = void 0;
3
+ exports.capitalize = exports.keysOf = exports.isString = exports.isEmptyObject = exports.isObject = void 0;
4
4
  function isObject(obj) {
5
5
  const type = typeof obj;
6
6
  return type === 'function' || (type === 'object' && !!obj);
@@ -20,3 +20,10 @@ function keysOf(obj) {
20
20
  return Object.keys(obj);
21
21
  }
22
22
  exports.keysOf = keysOf;
23
+ function capitalize(s) {
24
+ if ((s === null || s === void 0 ? void 0 : s.length) > 0) {
25
+ return s[0].toUpperCase() + s.slice(1);
26
+ }
27
+ return s;
28
+ }
29
+ exports.capitalize = capitalize;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/cli",
3
- "version": "1.8.2",
3
+ "version": "1.9.1",
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.8.2",
39
+ "@redocly/openapi-core": "1.9.1",
40
40
  "abort-controller": "^3.0.0",
41
41
  "chokidar": "^3.5.1",
42
42
  "colorette": "^1.2.0",
@@ -1,5 +1,5 @@
1
1
  import { ConfigFixture } from './../../__tests__/fixtures/config';
2
- import { firstDocument, secondDocument } from '../documents';
2
+ import { firstDocument, secondDocument, thirdDocument } from '../documents';
3
3
 
4
4
  import type { Document } from '@redocly/openapi-core';
5
5
 
@@ -47,6 +47,9 @@ export class BaseResolver {
47
47
  )
48
48
  .mockImplementationOnce(() =>
49
49
  Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: secondDocument })
50
+ )
51
+ .mockImplementationOnce(() =>
52
+ Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: thirdDocument })
50
53
  );
51
54
  }
52
55
 
@@ -4,7 +4,7 @@ export const firstDocument = {
4
4
  info: {
5
5
  description: 'example test',
6
6
  version: '1.0.0',
7
- title: 'Swagger Petstore',
7
+ title: 'First API',
8
8
  termsOfService: 'http://swagger.io/terms/',
9
9
  license: {
10
10
  name: 'Apache 2.0',
@@ -36,7 +36,7 @@ export const secondDocument = {
36
36
  info: {
37
37
  description: 'example test',
38
38
  version: '1.0.0',
39
- title: 'Swagger Petstore',
39
+ title: 'Second API',
40
40
  termsOfService: 'http://swagger.io/terms/',
41
41
  license: {
42
42
  name: 'Apache 2.0',
@@ -61,3 +61,64 @@ export const secondDocument = {
61
61
  },
62
62
  components: {},
63
63
  };
64
+
65
+ export const thirdDocument = {
66
+ openapi: '3.0.0',
67
+ info: {
68
+ title: 'Third API',
69
+ version: '1.0',
70
+ },
71
+ servers: [
72
+ {
73
+ url: 'https://api.server.test/v1',
74
+ },
75
+ ],
76
+ paths: {},
77
+ components: {
78
+ schemas: {
79
+ SchemaWithNull: {
80
+ type: 'string',
81
+ default: null,
82
+ nullable: true,
83
+ },
84
+ SchemaWithRef: {
85
+ type: 'object',
86
+ properties: {
87
+ schemaType: {
88
+ type: 'string',
89
+ enum: ['foo'],
90
+ },
91
+ foo: {
92
+ $ref: '#/components/schemas/SchemaWithNull',
93
+ },
94
+ },
95
+ },
96
+ SchemaWithDiscriminator: {
97
+ discriminator: {
98
+ propertyName: 'schemaType',
99
+ mapping: {
100
+ foo: '#/components/schemas/SchemaWithRef',
101
+ bar: '#/components/schemas/SchemaWithNull',
102
+ },
103
+ },
104
+ oneOf: [
105
+ {
106
+ $ref: '#/components/schemas/SchemaWithRef',
107
+ },
108
+ {
109
+ type: 'object',
110
+ properties: {
111
+ schemaType: {
112
+ type: 'string',
113
+ enum: ['bar'],
114
+ },
115
+ bar: {
116
+ type: 'string',
117
+ },
118
+ },
119
+ },
120
+ ],
121
+ },
122
+ },
123
+ },
124
+ };
@@ -1,7 +1,7 @@
1
- import { handleJoin } from '../../commands/join';
2
- import { exitWithError, writeToFileByExtension, writeYaml } from '../../utils/miscellaneous';
3
1
  import { yellow } from 'colorette';
4
2
  import { detectSpec } from '@redocly/openapi-core';
3
+ import { handleJoin } from '../../commands/join';
4
+ import { exitWithError, writeToFileByExtension } from '../../utils/miscellaneous';
5
5
  import { loadConfig } from '../../__mocks__/@redocly/openapi-core';
6
6
  import { ConfigFixture } from '../fixtures/config';
7
7
 
@@ -9,7 +9,7 @@ jest.mock('../../utils/miscellaneous');
9
9
 
10
10
  jest.mock('colorette');
11
11
 
12
- describe('handleJoin fails', () => {
12
+ describe('handleJoin', () => {
13
13
  const colloreteYellowMock = yellow as jest.Mock<any, any>;
14
14
  colloreteYellowMock.mockImplementation((string: string) => string);
15
15
 
@@ -181,4 +181,138 @@ describe('handleJoin fails', () => {
181
181
  expect(config.styleguide.skipDecorators).not.toHaveBeenCalled();
182
182
  expect(config.styleguide.skipPreprocessors).not.toHaveBeenCalled();
183
183
  });
184
+
185
+ it('should handle join with prefix-components-with-info-prop and null values', async () => {
186
+ (detectSpec as jest.Mock).mockReturnValue('oas3_0');
187
+
188
+ await handleJoin(
189
+ {
190
+ apis: ['first.yaml', 'second.yaml', 'third.yaml'],
191
+ 'prefix-components-with-info-prop': 'title',
192
+ output: 'join-result.yaml',
193
+ },
194
+ ConfigFixture as any,
195
+ 'cli-version'
196
+ );
197
+
198
+ expect(writeToFileByExtension).toHaveBeenCalledWith(
199
+ {
200
+ openapi: '3.0.0',
201
+ info: {
202
+ description: 'example test',
203
+ version: '1.0.0',
204
+ title: 'First API',
205
+ termsOfService: 'http://swagger.io/terms/',
206
+ license: {
207
+ name: 'Apache 2.0',
208
+ url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
209
+ },
210
+ },
211
+ servers: [
212
+ {
213
+ url: 'http://localhost:8080',
214
+ },
215
+ {
216
+ url: 'https://api.server.test/v1',
217
+ },
218
+ ],
219
+ tags: [
220
+ {
221
+ name: 'pet',
222
+ 'x-displayName': 'pet',
223
+ },
224
+ ],
225
+ paths: {
226
+ '/GETUser/{userId}': {
227
+ summary: 'get user by id',
228
+ description: 'user info',
229
+ servers: [
230
+ {
231
+ url: '/user',
232
+ },
233
+ {
234
+ url: '/pet',
235
+ description: 'pet server',
236
+ },
237
+ ],
238
+ get: {
239
+ tags: ['pet'],
240
+ summary: 'Find pet by ID',
241
+ description: 'Returns a single pet',
242
+ operationId: 'getPetById',
243
+ servers: [
244
+ {
245
+ url: '/pet',
246
+ },
247
+ ],
248
+ },
249
+ parameters: [
250
+ {
251
+ name: 'param1',
252
+ in: 'header',
253
+ schema: {
254
+ description: 'string',
255
+ },
256
+ },
257
+ ],
258
+ },
259
+ },
260
+ components: {
261
+ schemas: {
262
+ 'Third API_SchemaWithNull': {
263
+ type: 'string',
264
+ default: null,
265
+ nullable: true,
266
+ },
267
+ 'Third API_SchemaWithRef': {
268
+ type: 'object',
269
+ properties: {
270
+ schemaType: {
271
+ type: 'string',
272
+ enum: ['foo'],
273
+ },
274
+ foo: {
275
+ $ref: '#/components/schemas/Third API_SchemaWithNull',
276
+ },
277
+ },
278
+ },
279
+ 'Third API_SchemaWithDiscriminator': {
280
+ discriminator: {
281
+ propertyName: 'schemaType',
282
+ mapping: {
283
+ foo: '#/components/schemas/Third API_SchemaWithRef',
284
+ bar: '#/components/schemas/Third API_SchemaWithNull',
285
+ },
286
+ },
287
+ oneOf: [
288
+ {
289
+ $ref: '#/components/schemas/Third API_SchemaWithRef',
290
+ },
291
+ {
292
+ type: 'object',
293
+ properties: {
294
+ schemaType: {
295
+ type: 'string',
296
+ enum: ['bar'],
297
+ },
298
+ bar: {
299
+ type: 'string',
300
+ },
301
+ },
302
+ },
303
+ ],
304
+ },
305
+ },
306
+ },
307
+ 'x-tagGroups': [
308
+ {
309
+ name: 'First API',
310
+ tags: ['pet'],
311
+ },
312
+ ],
313
+ },
314
+ 'join-result.yaml',
315
+ true
316
+ );
317
+ });
184
318
  });
@@ -90,7 +90,7 @@ describe('handlePushStatus()', () => {
90
90
  );
91
91
  expect(process.stdout.write).toHaveBeenCalledTimes(1);
92
92
  expect(process.stdout.write).toHaveBeenCalledWith(
93
- '🚀 PREVIEW deployment succeeded.\nPreview URL: https://test-url\n'
93
+ '🚀 Preview deploy success.\nPreview URL: https://test-url\n'
94
94
  );
95
95
  });
96
96
 
@@ -110,10 +110,10 @@ describe('handlePushStatus()', () => {
110
110
  );
111
111
  expect(process.stdout.write).toHaveBeenCalledTimes(2);
112
112
  expect(process.stdout.write).toHaveBeenCalledWith(
113
- '🚀 PREVIEW deployment succeeded.\nPreview URL: https://test-url\n'
113
+ '🚀 Preview deploy success.\nPreview URL: https://test-url\n'
114
114
  );
115
115
  expect(process.stdout.write).toHaveBeenCalledWith(
116
- '🚀 PRODUCTION deployment succeeded.\nPreview URL: https://test-url\n'
116
+ '🚀 Production deploy success.\nProduction URL: https://test-url\n'
117
117
  );
118
118
  });
119
119
 
@@ -139,7 +139,7 @@ describe('handlePushStatus()', () => {
139
139
  mockConfig
140
140
  );
141
141
  expect(exitWithError).toHaveBeenCalledWith(
142
- '❌ PREVIEW deployment failed.\nPreview URL: https://test-url'
142
+ '❌ Preview deploy fail.\nPreview URL: https://test-url'
143
143
  );
144
144
  });
145
145
 
@@ -176,7 +176,7 @@ describe('handlePushStatus()', () => {
176
176
  );
177
177
  expect(process.stdout.write).toHaveBeenCalledTimes(4);
178
178
  expect(process.stdout.write).toHaveBeenCalledWith(
179
- '🚀 PREVIEW deployment succeeded.\nPreview URL: https://test-url\n'
179
+ '🚀 Preview deploy success.\nPreview URL: https://test-url\n'
180
180
  );
181
181
  expect(process.stdout.write).toHaveBeenCalledWith('\nScorecard:');
182
182
  expect(process.stdout.write).toHaveBeenCalledWith(
@@ -5,6 +5,7 @@ import { Spinner } from '../../utils/spinner';
5
5
  import { DeploymentError } from '../utils';
6
6
  import { yellow } from 'colorette';
7
7
  import { ReuniteApiClient, getApiKeys, getDomain } from '../api';
8
+ import { capitalize } from '../../utils/js-utils';
8
9
 
9
10
  import type { DeploymentStatus, PushResponse, ScorecardItem } from '../api/types';
10
11
 
@@ -177,15 +178,15 @@ function displayDeploymentAndBuildStatus({
177
178
  case 'success':
178
179
  spinner.stop();
179
180
  return process.stdout.write(
180
- `${colors.green(
181
- `🚀 ${buildType.toLocaleUpperCase()} deployment succeeded.`
182
- )}\n${colors.magenta('Preview URL')}: ${colors.cyan(previewUrl!)}\n`
181
+ `${colors.green(`🚀 ${capitalize(buildType)} deploy success.`)}\n${colors.magenta(
182
+ `${capitalize(buildType)} URL`
183
+ )}: ${colors.cyan(previewUrl!)}\n`
183
184
  );
184
185
  case 'failed':
185
186
  spinner.stop();
186
187
  throw new DeploymentError(
187
- `${colors.red(`❌ ${buildType.toLocaleUpperCase()} deployment failed.`)}\n${colors.magenta(
188
- 'Preview URL'
188
+ `${colors.red(`❌ ${capitalize(buildType)} deploy fail.`)}\n${colors.magenta(
189
+ `${capitalize(buildType)} URL`
189
190
  )}: ${colors.cyan(previewUrl!)}`
190
191
  );
191
192
  case 'pending':