@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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @redocly/cli
2
2
 
3
+ ## 1.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Adds support for using logical AND for the security schema so that the `join` command generates the correct schema.
8
+ - Fixed a bug with resolving $refs to file names that contain the hash symbol.
9
+ - Fixed a problem where the `join` command did not process schemas containing `null` values when the `--prefix-components-with-info-prop` option was used.'
10
+ - Updated @redocly/openapi-core to v1.9.1.
11
+
12
+ ## 1.9.0
13
+
14
+ ### Minor Changes
15
+
16
+ - - Removed descriptions adding for x-tagGroups for the `join` command. Descriptions in x-tagGroups are not supported and cause errors on linting.
17
+ - Updated `info.title` to be used as a name in x-tagGroups instead of a file name for the `join` command, so you can now join files with the same names.
18
+ - Added new `no-required-schema-properties-undefined` rule to check if each required schema property is defined.
19
+
20
+ ### Patch Changes
21
+
22
+ - Fixed an issue where using the `--prefix-components-with-info-prop` option with the `join` command caused `$refs` to include duplicated prefixes.
23
+ - Fixed an issue where `$ref`s ending in `#` (instead of `#/`) would break the application.
24
+ - Updated @redocly/openapi-core to v1.9.0.
25
+
3
26
  ## 1.8.2
4
27
 
5
28
  ### Patch Changes
@@ -41,7 +41,8 @@ class BaseResolver {
41
41
  this.resolveDocument = jest
42
42
  .fn()
43
43
  .mockImplementationOnce(() => Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: documents_1.firstDocument }))
44
- .mockImplementationOnce(() => Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: documents_1.secondDocument }));
44
+ .mockImplementationOnce(() => Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: documents_1.secondDocument }))
45
+ .mockImplementationOnce(() => Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: documents_1.thirdDocument }));
45
46
  }
46
47
  }
47
48
  exports.BaseResolver = BaseResolver;
@@ -90,3 +90,61 @@ export declare const secondDocument: {
90
90
  };
91
91
  components: {};
92
92
  };
93
+ export declare const thirdDocument: {
94
+ openapi: string;
95
+ info: {
96
+ title: string;
97
+ version: string;
98
+ };
99
+ servers: {
100
+ url: string;
101
+ }[];
102
+ paths: {};
103
+ components: {
104
+ schemas: {
105
+ SchemaWithNull: {
106
+ type: string;
107
+ default: null;
108
+ nullable: boolean;
109
+ };
110
+ SchemaWithRef: {
111
+ type: string;
112
+ properties: {
113
+ schemaType: {
114
+ type: string;
115
+ enum: string[];
116
+ };
117
+ foo: {
118
+ $ref: string;
119
+ };
120
+ };
121
+ };
122
+ SchemaWithDiscriminator: {
123
+ discriminator: {
124
+ propertyName: string;
125
+ mapping: {
126
+ foo: string;
127
+ bar: string;
128
+ };
129
+ };
130
+ oneOf: ({
131
+ $ref: string;
132
+ type?: undefined;
133
+ properties?: undefined;
134
+ } | {
135
+ type: string;
136
+ properties: {
137
+ schemaType: {
138
+ type: string;
139
+ enum: string[];
140
+ };
141
+ bar: {
142
+ type: string;
143
+ };
144
+ };
145
+ $ref?: undefined;
146
+ })[];
147
+ };
148
+ };
149
+ };
150
+ };
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.secondDocument = exports.firstDocument = void 0;
3
+ exports.thirdDocument = exports.secondDocument = exports.firstDocument = void 0;
4
4
  exports.firstDocument = {
5
5
  openapi: '3.0.0',
6
6
  servers: [{ url: 'http://localhost:8080' }],
7
7
  info: {
8
8
  description: 'example test',
9
9
  version: '1.0.0',
10
- title: 'Swagger Petstore',
10
+ title: 'First API',
11
11
  termsOfService: 'http://swagger.io/terms/',
12
12
  license: {
13
13
  name: 'Apache 2.0',
@@ -37,7 +37,7 @@ exports.secondDocument = {
37
37
  info: {
38
38
  description: 'example test',
39
39
  version: '1.0.0',
40
- title: 'Swagger Petstore',
40
+ title: 'Second API',
41
41
  termsOfService: 'http://swagger.io/terms/',
42
42
  license: {
43
43
  name: 'Apache 2.0',
@@ -61,3 +61,63 @@ exports.secondDocument = {
61
61
  },
62
62
  components: {},
63
63
  };
64
+ exports.thirdDocument = {
65
+ openapi: '3.0.0',
66
+ info: {
67
+ title: 'Third API',
68
+ version: '1.0',
69
+ },
70
+ servers: [
71
+ {
72
+ url: 'https://api.server.test/v1',
73
+ },
74
+ ],
75
+ paths: {},
76
+ components: {
77
+ schemas: {
78
+ SchemaWithNull: {
79
+ type: 'string',
80
+ default: null,
81
+ nullable: true,
82
+ },
83
+ SchemaWithRef: {
84
+ type: 'object',
85
+ properties: {
86
+ schemaType: {
87
+ type: 'string',
88
+ enum: ['foo'],
89
+ },
90
+ foo: {
91
+ $ref: '#/components/schemas/SchemaWithNull',
92
+ },
93
+ },
94
+ },
95
+ SchemaWithDiscriminator: {
96
+ discriminator: {
97
+ propertyName: 'schemaType',
98
+ mapping: {
99
+ foo: '#/components/schemas/SchemaWithRef',
100
+ bar: '#/components/schemas/SchemaWithNull',
101
+ },
102
+ },
103
+ oneOf: [
104
+ {
105
+ $ref: '#/components/schemas/SchemaWithRef',
106
+ },
107
+ {
108
+ type: 'object',
109
+ properties: {
110
+ schemaType: {
111
+ type: 'string',
112
+ enum: ['bar'],
113
+ },
114
+ bar: {
115
+ type: 'string',
116
+ },
117
+ },
118
+ },
119
+ ],
120
+ },
121
+ },
122
+ },
123
+ };
@@ -9,15 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const join_1 = require("../../commands/join");
13
- const miscellaneous_1 = require("../../utils/miscellaneous");
14
12
  const colorette_1 = require("colorette");
15
13
  const openapi_core_1 = require("@redocly/openapi-core");
14
+ const join_1 = require("../../commands/join");
15
+ const miscellaneous_1 = require("../../utils/miscellaneous");
16
16
  const openapi_core_2 = require("../../__mocks__/@redocly/openapi-core");
17
17
  const config_1 = require("../fixtures/config");
18
18
  jest.mock('../../utils/miscellaneous');
19
19
  jest.mock('colorette');
20
- describe('handleJoin fails', () => {
20
+ describe('handleJoin', () => {
21
21
  const colloreteYellowMock = colorette_1.yellow;
22
22
  colloreteYellowMock.mockImplementation((string) => string);
23
23
  it('should call exitWithError because only one entrypoint', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -105,4 +105,127 @@ describe('handleJoin fails', () => {
105
105
  expect(config.styleguide.skipDecorators).not.toHaveBeenCalled();
106
106
  expect(config.styleguide.skipPreprocessors).not.toHaveBeenCalled();
107
107
  }));
108
+ it('should handle join with prefix-components-with-info-prop and null values', () => __awaiter(void 0, void 0, void 0, function* () {
109
+ openapi_core_1.detectSpec.mockReturnValue('oas3_0');
110
+ yield (0, join_1.handleJoin)({
111
+ apis: ['first.yaml', 'second.yaml', 'third.yaml'],
112
+ 'prefix-components-with-info-prop': 'title',
113
+ output: 'join-result.yaml',
114
+ }, config_1.ConfigFixture, 'cli-version');
115
+ expect(miscellaneous_1.writeToFileByExtension).toHaveBeenCalledWith({
116
+ openapi: '3.0.0',
117
+ info: {
118
+ description: 'example test',
119
+ version: '1.0.0',
120
+ title: 'First API',
121
+ termsOfService: 'http://swagger.io/terms/',
122
+ license: {
123
+ name: 'Apache 2.0',
124
+ url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
125
+ },
126
+ },
127
+ servers: [
128
+ {
129
+ url: 'http://localhost:8080',
130
+ },
131
+ {
132
+ url: 'https://api.server.test/v1',
133
+ },
134
+ ],
135
+ tags: [
136
+ {
137
+ name: 'pet',
138
+ 'x-displayName': 'pet',
139
+ },
140
+ ],
141
+ paths: {
142
+ '/GETUser/{userId}': {
143
+ summary: 'get user by id',
144
+ description: 'user info',
145
+ servers: [
146
+ {
147
+ url: '/user',
148
+ },
149
+ {
150
+ url: '/pet',
151
+ description: 'pet server',
152
+ },
153
+ ],
154
+ get: {
155
+ tags: ['pet'],
156
+ summary: 'Find pet by ID',
157
+ description: 'Returns a single pet',
158
+ operationId: 'getPetById',
159
+ servers: [
160
+ {
161
+ url: '/pet',
162
+ },
163
+ ],
164
+ },
165
+ parameters: [
166
+ {
167
+ name: 'param1',
168
+ in: 'header',
169
+ schema: {
170
+ description: 'string',
171
+ },
172
+ },
173
+ ],
174
+ },
175
+ },
176
+ components: {
177
+ schemas: {
178
+ 'Third API_SchemaWithNull': {
179
+ type: 'string',
180
+ default: null,
181
+ nullable: true,
182
+ },
183
+ 'Third API_SchemaWithRef': {
184
+ type: 'object',
185
+ properties: {
186
+ schemaType: {
187
+ type: 'string',
188
+ enum: ['foo'],
189
+ },
190
+ foo: {
191
+ $ref: '#/components/schemas/Third API_SchemaWithNull',
192
+ },
193
+ },
194
+ },
195
+ 'Third API_SchemaWithDiscriminator': {
196
+ discriminator: {
197
+ propertyName: 'schemaType',
198
+ mapping: {
199
+ foo: '#/components/schemas/Third API_SchemaWithRef',
200
+ bar: '#/components/schemas/Third API_SchemaWithNull',
201
+ },
202
+ },
203
+ oneOf: [
204
+ {
205
+ $ref: '#/components/schemas/Third API_SchemaWithRef',
206
+ },
207
+ {
208
+ type: 'object',
209
+ properties: {
210
+ schemaType: {
211
+ type: 'string',
212
+ enum: ['bar'],
213
+ },
214
+ bar: {
215
+ type: 'string',
216
+ },
217
+ },
218
+ },
219
+ ],
220
+ },
221
+ },
222
+ },
223
+ 'x-tagGroups': [
224
+ {
225
+ name: 'First API',
226
+ tags: ['pet'],
227
+ },
228
+ ],
229
+ }, 'join-result.yaml', true);
230
+ }));
108
231
  });
@@ -76,7 +76,7 @@ describe('handlePushStatus()', () => {
76
76
  'max-execution-time': 1000,
77
77
  }, mockConfig);
78
78
  expect(process.stdout.write).toHaveBeenCalledTimes(1);
79
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 PREVIEW deployment succeeded.\nPreview URL: https://test-url\n');
79
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://test-url\n');
80
80
  }));
81
81
  it('should return success push status for preview and production builds', () => __awaiter(void 0, void 0, void 0, function* () {
82
82
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
@@ -89,8 +89,8 @@ describe('handlePushStatus()', () => {
89
89
  'max-execution-time': 1000,
90
90
  }, mockConfig);
91
91
  expect(process.stdout.write).toHaveBeenCalledTimes(2);
92
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 PREVIEW deployment succeeded.\nPreview URL: https://test-url\n');
93
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 PRODUCTION deployment succeeded.\nPreview URL: https://test-url\n');
92
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://test-url\n');
93
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Production deploy success.\nProduction URL: https://test-url\n');
94
94
  }));
95
95
  it('should return failed push status for preview build', () => __awaiter(void 0, void 0, void 0, function* () {
96
96
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
@@ -108,7 +108,7 @@ describe('handlePushStatus()', () => {
108
108
  pushId: 'test-push-id',
109
109
  'max-execution-time': 1000,
110
110
  }, mockConfig);
111
- expect(miscellaneous_1.exitWithError).toHaveBeenCalledWith('❌ PREVIEW deployment failed.\nPreview URL: https://test-url');
111
+ expect(miscellaneous_1.exitWithError).toHaveBeenCalledWith('❌ Preview deploy fail.\nPreview URL: https://test-url');
112
112
  }));
113
113
  it('should return success push status for preview build and print scorecards', () => __awaiter(void 0, void 0, void 0, function* () {
114
114
  process.env.REDOCLY_AUTHORIZATION = 'test-api-key';
@@ -137,7 +137,7 @@ describe('handlePushStatus()', () => {
137
137
  'max-execution-time': 1000,
138
138
  }, mockConfig);
139
139
  expect(process.stdout.write).toHaveBeenCalledTimes(4);
140
- expect(process.stdout.write).toHaveBeenCalledWith('🚀 PREVIEW deployment succeeded.\nPreview URL: https://test-url\n');
140
+ expect(process.stdout.write).toHaveBeenCalledWith('🚀 Preview deploy success.\nPreview URL: https://test-url\n');
141
141
  expect(process.stdout.write).toHaveBeenCalledWith('\nScorecard:');
142
142
  expect(process.stdout.write).toHaveBeenCalledWith('\n Name: test-name\n Status: success\n URL: test-url\n Description: test-description\n');
143
143
  expect(process.stdout.write).toHaveBeenCalledWith('\n');
@@ -16,6 +16,7 @@ const spinner_1 = require("../../utils/spinner");
16
16
  const utils_1 = require("../utils");
17
17
  const colorette_1 = require("colorette");
18
18
  const api_1 = require("../api");
19
+ const js_utils_1 = require("../../utils/js-utils");
19
20
  const INTERVAL = 5000;
20
21
  function handlePushStatus(argv, config) {
21
22
  return __awaiter(this, void 0, void 0, function* () {
@@ -131,10 +132,10 @@ function displayDeploymentAndBuildStatus({ status, previewUrl, spinner, buildTyp
131
132
  switch (status) {
132
133
  case 'success':
133
134
  spinner.stop();
134
- return process.stdout.write(`${colors.green(`🚀 ${buildType.toLocaleUpperCase()} deployment succeeded.`)}\n${colors.magenta('Preview URL')}: ${colors.cyan(previewUrl)}\n`);
135
+ return process.stdout.write(`${colors.green(`🚀 ${(0, js_utils_1.capitalize)(buildType)} deploy success.`)}\n${colors.magenta(`${(0, js_utils_1.capitalize)(buildType)} URL`)}: ${colors.cyan(previewUrl)}\n`);
135
136
  case 'failed':
136
137
  spinner.stop();
137
- throw new utils_1.DeploymentError(`${colors.red(`❌ ${buildType.toLocaleUpperCase()} deployment failed.`)}\n${colors.magenta('Preview URL')}: ${colors.cyan(previewUrl)}`);
138
+ throw new utils_1.DeploymentError(`${colors.red(`❌ ${(0, js_utils_1.capitalize)(buildType)} deploy fail.`)}\n${colors.magenta(`${(0, js_utils_1.capitalize)(buildType)} URL`)}: ${colors.cyan(previewUrl)}`);
138
139
  case 'pending':
139
140
  return wait
140
141
  ? spinner.start(`${colors.yellow(`Pending ${buildType}`)}`)
@@ -1,4 +1,5 @@
1
- import { Config, RuleSeverity } from '@redocly/openapi-core';
1
+ import { Config } from '@redocly/openapi-core';
2
+ import type { RuleSeverity } from '@redocly/openapi-core';
2
3
  export type JoinOptions = {
3
4
  apis: string[];
4
5
  lint?: boolean;
@@ -18,7 +18,7 @@ const openapi_core_1 = require("@redocly/openapi-core");
18
18
  const miscellaneous_1 = require("../utils/miscellaneous");
19
19
  const js_utils_1 = require("../utils/js-utils");
20
20
  const types_1 = require("./split/types");
21
- const COMPONENTS = 'components';
21
+ const split_1 = require("./split");
22
22
  const Tags = 'tags';
23
23
  const xTagGroups = 'x-tagGroups';
24
24
  let potentialConflictsTotal = 0;
@@ -112,13 +112,14 @@ function handleJoin(argv, config, packageVersion) {
112
112
  const tagsPrefix = prefixTagsWithFilename
113
113
  ? apiFilename
114
114
  : getInfoPrefix(info, prefixTagsWithInfoProp, 'tags');
115
- const componentsPrefix = getInfoPrefix(info, prefixComponentsWithInfoProp, COMPONENTS);
115
+ const componentsPrefix = getInfoPrefix(info, prefixComponentsWithInfoProp, types_1.COMPONENTS);
116
116
  if (openapi.hasOwnProperty('x-tagGroups')) {
117
117
  process.stderr.write((0, colorette_1.yellow)(`warning: x-tagGroups at ${(0, colorette_1.blue)(api)} will be skipped \n`));
118
118
  }
119
119
  const context = {
120
120
  api,
121
121
  apiFilename,
122
+ apiTitle: info === null || info === void 0 ? void 0 : info.title,
122
123
  tags,
123
124
  potentialConflicts,
124
125
  tagsPrefix,
@@ -128,7 +129,6 @@ function handleJoin(argv, config, packageVersion) {
128
129
  populateTags(context);
129
130
  }
130
131
  collectServers(openapi);
131
- collectInfoDescriptions(openapi, context);
132
132
  collectExternalDocs(openapi, context);
133
133
  collectPaths(openapi, context);
134
134
  collectComponents(openapi, context);
@@ -144,7 +144,7 @@ function handleJoin(argv, config, packageVersion) {
144
144
  }
145
145
  (0, miscellaneous_1.writeToFileByExtension)((0, miscellaneous_1.sortTopLevelKeysForOas)(joinedDef), specFilename, noRefs);
146
146
  (0, miscellaneous_1.printExecutionTime)('join', startedAt, specFilename);
147
- function populateTags({ api, apiFilename, tags, potentialConflicts, tagsPrefix, componentsPrefix, }) {
147
+ function populateTags({ api, apiFilename, apiTitle, tags, potentialConflicts, tagsPrefix, componentsPrefix, }) {
148
148
  if (!joinedDef.hasOwnProperty(Tags)) {
149
149
  joinedDef[Tags] = [];
150
150
  }
@@ -176,9 +176,10 @@ function handleJoin(argv, config, packageVersion) {
176
176
  }
177
177
  }
178
178
  if (!withoutXTagGroups) {
179
- createXTagGroups(apiFilename);
179
+ const groupName = apiTitle || apiFilename;
180
+ createXTagGroups(groupName);
180
181
  if (!tagDuplicate) {
181
- populateXTagGroups(entrypointTagName, getIndexGroup(apiFilename));
182
+ populateXTagGroups(entrypointTagName, getIndexGroup(groupName));
182
183
  }
183
184
  }
184
185
  const doesEntrypointExist = !potentialConflicts.tags.all[entrypointTagName] ||
@@ -190,17 +191,17 @@ function handleJoin(argv, config, packageVersion) {
190
191
  ];
191
192
  }
192
193
  }
193
- function getIndexGroup(apiFilename) {
194
- return joinedDef[xTagGroups].findIndex((item) => item.name === apiFilename);
194
+ function getIndexGroup(name) {
195
+ return joinedDef[xTagGroups].findIndex((item) => item.name === name);
195
196
  }
196
- function createXTagGroups(apiFilename) {
197
+ function createXTagGroups(name) {
197
198
  if (!joinedDef.hasOwnProperty(xTagGroups)) {
198
199
  joinedDef[xTagGroups] = [];
199
200
  }
200
- if (!joinedDef[xTagGroups].some((g) => g.name === apiFilename)) {
201
- joinedDef[xTagGroups].push({ name: apiFilename, tags: [] });
201
+ if (!joinedDef[xTagGroups].some((g) => g.name === name)) {
202
+ joinedDef[xTagGroups].push({ name, tags: [] });
202
203
  }
203
- const indexGroup = getIndexGroup(apiFilename);
204
+ const indexGroup = getIndexGroup(name);
204
205
  if (!joinedDef[xTagGroups][indexGroup].hasOwnProperty(Tags)) {
205
206
  joinedDef[xTagGroups][indexGroup][Tags] = [];
206
207
  }
@@ -223,18 +224,6 @@ function handleJoin(argv, config, packageVersion) {
223
224
  }
224
225
  }
225
226
  }
226
- function collectInfoDescriptions(openapi, { apiFilename, componentsPrefix }) {
227
- const { info } = openapi;
228
- if (info === null || info === void 0 ? void 0 : info.description) {
229
- const groupIndex = joinedDef[xTagGroups] ? getIndexGroup(apiFilename) : -1;
230
- if (joinedDef.hasOwnProperty(xTagGroups) &&
231
- groupIndex !== -1 &&
232
- joinedDef[xTagGroups][groupIndex]['tags'] &&
233
- joinedDef[xTagGroups][groupIndex]['tags'].length) {
234
- joinedDef[xTagGroups][groupIndex]['description'] = addComponentsPrefix(info.description, componentsPrefix);
235
- }
236
- }
237
- }
238
227
  function collectExternalDocs(openapi, { api }) {
239
228
  const { externalDocs } = openapi;
240
229
  if (externalDocs) {
@@ -245,7 +234,7 @@ function handleJoin(argv, config, packageVersion) {
245
234
  joinedDef['externalDocs'] = externalDocs;
246
235
  }
247
236
  }
248
- function collectPaths(openapi, { apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }) {
237
+ function collectPaths(openapi, { apiFilename, apiTitle, api, potentialConflicts, tagsPrefix, componentsPrefix, }) {
249
238
  const { paths } = openapi;
250
239
  const operationsSet = new Set((0, js_utils_1.keysOf)(types_1.OPENAPI3_METHOD));
251
240
  if (paths) {
@@ -365,6 +354,7 @@ function handleJoin(argv, config, packageVersion) {
365
354
  populateTags({
366
355
  api,
367
356
  apiFilename,
357
+ apiTitle,
368
358
  tags: formatTags(tags),
369
359
  potentialConflicts,
370
360
  tagsPrefix,
@@ -376,6 +366,7 @@ function handleJoin(argv, config, packageVersion) {
376
366
  populateTags({
377
367
  api,
378
368
  apiFilename,
369
+ apiTitle,
379
370
  tags: formatTags(['other']),
380
371
  potentialConflicts,
381
372
  tagsPrefix: tagsPrefix || apiFilename,
@@ -399,13 +390,13 @@ function handleJoin(argv, config, packageVersion) {
399
390
  function collectComponents(openapi, { api, potentialConflicts, componentsPrefix }) {
400
391
  const { components } = openapi;
401
392
  if (components) {
402
- if (!joinedDef.hasOwnProperty(COMPONENTS)) {
403
- joinedDef[COMPONENTS] = {};
393
+ if (!joinedDef.hasOwnProperty(types_1.COMPONENTS)) {
394
+ joinedDef[types_1.COMPONENTS] = {};
404
395
  }
405
396
  for (const [component, componentObj] of Object.entries(components)) {
406
- if (!potentialConflicts[COMPONENTS].hasOwnProperty(component)) {
407
- potentialConflicts[COMPONENTS][component] = {};
408
- joinedDef[COMPONENTS][component] = {};
397
+ if (!potentialConflicts[types_1.COMPONENTS].hasOwnProperty(component)) {
398
+ potentialConflicts[types_1.COMPONENTS][component] = {};
399
+ joinedDef[types_1.COMPONENTS][component] = {};
409
400
  }
410
401
  for (const item of Object.keys(componentObj)) {
411
402
  const componentPrefix = addPrefix(item, componentsPrefix);
@@ -418,7 +409,7 @@ function handleJoin(argv, config, packageVersion) {
418
409
  }
419
410
  }
420
411
  }
421
- function collectWebhooks(oasVersion, openapi, { apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }) {
412
+ function collectWebhooks(oasVersion, openapi, { apiFilename, apiTitle, api, potentialConflicts, tagsPrefix, componentsPrefix, }) {
422
413
  const webhooks = oasVersion === openapi_core_1.SpecVersion.OAS3_1 ? 'webhooks' : 'x-webhooks';
423
414
  const openapiWebhooks = openapi[webhooks];
424
415
  if (openapiWebhooks) {
@@ -443,6 +434,7 @@ function handleJoin(argv, config, packageVersion) {
443
434
  populateTags({
444
435
  api,
445
436
  apiFilename,
437
+ apiTitle,
446
438
  tags: formatTags(tags),
447
439
  potentialConflicts,
448
440
  tagsPrefix,
@@ -457,7 +449,7 @@ function handleJoin(argv, config, packageVersion) {
457
449
  var _a;
458
450
  const firstApi = documents[0];
459
451
  const openapi = firstApi.parsed;
460
- const componentsPrefix = getInfoPrefix(openapi.info, prefixComponentsWithInfoProp, COMPONENTS);
452
+ const componentsPrefix = getInfoPrefix(openapi.info, prefixComponentsWithInfoProp, types_1.COMPONENTS);
461
453
  if (!openapi.openapi)
462
454
  (0, miscellaneous_1.exitWithError)('Version of specification is not found in. \n');
463
455
  if (!openapi.info)
@@ -489,7 +481,7 @@ function iteratePotentialConflicts(potentialConflicts, withoutXTagGroups) {
489
481
  for (const [key, value] of Object.entries(potentialConflicts[group])) {
490
482
  const conflicts = filterConflicts(value);
491
483
  if (conflicts.length) {
492
- if (group === COMPONENTS) {
484
+ if (group === types_1.COMPONENTS) {
493
485
  for (const [_, conflict] of Object.entries(conflicts)) {
494
486
  if (validateComponentsDifference(conflict[1])) {
495
487
  conflict[1] = conflict[1].map((c) => Object.keys(c)[0]);
@@ -548,8 +540,11 @@ function addComponentsPrefix(description, componentsPrefix) {
548
540
  function addSecurityPrefix(security, componentsPrefix) {
549
541
  return componentsPrefix
550
542
  ? security === null || security === void 0 ? void 0 : security.map((s) => {
551
- const key = Object.keys(s)[0];
552
- return { [componentsPrefix + '_' + key]: s[key] };
543
+ const joinedSecuritySchema = {};
544
+ for (const [key, value] of Object.entries(s)) {
545
+ Object.assign(joinedSecuritySchema, { [componentsPrefix + '_' + key]: value });
546
+ }
547
+ return joinedSecuritySchema;
553
548
  })
554
549
  : security;
555
550
  }
@@ -579,27 +574,18 @@ function validateApi(document, config, externalRefResolver, packageVersion) {
579
574
  }
580
575
  });
581
576
  }
582
- function crawl(object, visitor) {
583
- if (!(0, js_utils_1.isObject)(object))
584
- return;
585
- for (const key of Object.keys(object)) {
586
- visitor(object, key);
587
- crawl(object[key], visitor);
588
- }
589
- }
590
577
  function replace$Refs(obj, componentsPrefix) {
591
- crawl(obj, (node) => {
592
- if (node.$ref && (0, js_utils_1.isString)(node.$ref) && node.$ref.startsWith(`#/${COMPONENTS}/`)) {
578
+ (0, split_1.crawl)(obj, (node) => {
579
+ if (node.$ref && typeof node.$ref === 'string' && (0, split_1.startsWithComponents)(node.$ref)) {
593
580
  const name = path.basename(node.$ref);
594
581
  node.$ref = node.$ref.replace(name, componentsPrefix + '_' + name);
595
582
  }
596
- else if (node.discriminator &&
597
- node.discriminator.mapping &&
598
- (0, js_utils_1.isObject)(node.discriminator.mapping)) {
583
+ else if ((0, js_utils_1.isObject)(node.discriminator) && (0, js_utils_1.isObject)(node.discriminator.mapping)) {
599
584
  const { mapping } = node.discriminator;
600
585
  for (const name of Object.keys(mapping)) {
601
- if ((0, js_utils_1.isString)(mapping[name]) && mapping[name].startsWith(`#/${COMPONENTS}/`)) {
602
- mapping[name] = mapping[name]
586
+ const mappingPointer = mapping[name];
587
+ if (typeof mappingPointer === 'string' && (0, split_1.startsWithComponents)(mappingPointer)) {
588
+ mapping[name] = mappingPointer
603
589
  .split('/')
604
590
  .map((name, i, arr) => {
605
591
  return arr.length - 1 === i && !name.includes(componentsPrefix)
@@ -1,4 +1,4 @@
1
- import { Oas3PathItem, Referenced } from './types';
1
+ import type { Oas3PathItem, Referenced } from './types';
2
2
  export type SplitOptions = {
3
3
  api: string;
4
4
  outDir: string;
@@ -6,5 +6,7 @@ export type SplitOptions = {
6
6
  config?: string;
7
7
  };
8
8
  export declare function handleSplit(argv: SplitOptions): Promise<void>;
9
+ export declare function startsWithComponents(node: string): boolean;
10
+ export declare function crawl(object: unknown, visitor: (node: Record<string, unknown>) => void): void;
9
11
  declare function iteratePathItems(pathItems: Record<string, Referenced<Oas3PathItem>> | undefined, openapiDir: string, outDir: string, componentsFiles: object, pathSeparator: string, codeSamplesPathPrefix: string | undefined, ext: string): void;
10
12
  export { iteratePathItems };