@redocly/cli 1.0.0-beta.108 → 1.0.0-beta.109
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 +28 -0
- package/lib/__mocks__/@redocly/openapi-core.js +35 -1
- package/lib/__mocks__/documents.d.ts +92 -0
- package/lib/__mocks__/documents.js +63 -0
- package/lib/__mocks__/utils.d.ts +1 -0
- package/lib/__mocks__/utils.js +2 -1
- package/lib/__tests__/commands/join.test.js +14 -0
- package/lib/commands/join.js +121 -43
- package/lib/commands/lint.js +4 -0
- package/lib/commands/split/types.d.ts +9 -9
- package/lib/commands/split/types.js +18 -18
- package/lib/commands/stats.js +2 -2
- package/lib/index.js +1 -0
- package/lib/js-utils.d.ts +1 -0
- package/lib/js-utils.js +7 -1
- package/lib/utils.js +1 -0
- package/package.json +2 -2
- package/src/__mocks__/@redocly/openapi-core.ts +38 -0
- package/src/__mocks__/documents.ts +63 -0
- package/src/__mocks__/utils.ts +1 -0
- package/src/__tests__/commands/join.test.ts +23 -1
- package/src/commands/join.ts +161 -52
- package/src/commands/lint.ts +5 -0
- package/src/commands/split/types.ts +17 -17
- package/src/commands/stats.ts +2 -2
- package/src/index.ts +1 -0
- package/src/js-utils.ts +5 -0
- package/src/utils.ts +1 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ConfigFixture } from './../../__tests__/fixtures/config';
|
|
2
|
+
import { Document, ResolveError } from '@redocly/openapi-core';
|
|
3
|
+
import { firstDocument, secondDocument } from '../documents';
|
|
2
4
|
|
|
3
5
|
export const __redoclyClient = {
|
|
4
6
|
isAuthorizedWithRedocly: jest.fn().mockResolvedValue(true),
|
|
@@ -25,3 +27,39 @@ export const formatProblems = jest.fn();
|
|
|
25
27
|
export const slash = jest.fn();
|
|
26
28
|
export const findConfig = jest.fn();
|
|
27
29
|
export const doesYamlFileExist = jest.fn();
|
|
30
|
+
export const bundleDocument = jest.fn(() => Promise.resolve({ problems: {} }));
|
|
31
|
+
export const detectOpenAPI = jest.fn();
|
|
32
|
+
|
|
33
|
+
export class BaseResolver {
|
|
34
|
+
cache = new Map<string, Promise<Document | ResolveError>>();
|
|
35
|
+
|
|
36
|
+
getFiles = jest.fn();
|
|
37
|
+
resolveExternalRef = jest.fn();
|
|
38
|
+
loadExternalRef = jest.fn;
|
|
39
|
+
parseDocument = jest.fn();
|
|
40
|
+
resolveDocument = jest
|
|
41
|
+
.fn()
|
|
42
|
+
.mockImplementationOnce(() =>
|
|
43
|
+
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: firstDocument })
|
|
44
|
+
)
|
|
45
|
+
.mockImplementationOnce(() =>
|
|
46
|
+
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: secondDocument })
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export enum OasVersion {
|
|
51
|
+
Version2 = 'oas2',
|
|
52
|
+
Version3_0 = 'oas3_0',
|
|
53
|
+
Version3_1 = 'oas3_1',
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export enum Oas3Operations {
|
|
57
|
+
get = 'get',
|
|
58
|
+
put = 'put',
|
|
59
|
+
post = 'post',
|
|
60
|
+
delete = 'delete',
|
|
61
|
+
options = 'options',
|
|
62
|
+
head = 'head',
|
|
63
|
+
patch = 'patch',
|
|
64
|
+
trace = 'trace',
|
|
65
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const firstDocument = {
|
|
2
|
+
openapi: '3.0.0',
|
|
3
|
+
servers: [{ url: 'http://localhost:8080' }],
|
|
4
|
+
info: {
|
|
5
|
+
description: 'example test',
|
|
6
|
+
version: '1.0.0',
|
|
7
|
+
title: 'Swagger Petstore',
|
|
8
|
+
termsOfService: 'http://swagger.io/terms/',
|
|
9
|
+
license: {
|
|
10
|
+
name: 'Apache 2.0',
|
|
11
|
+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
paths: {
|
|
15
|
+
'/GETUser/{userId}': {
|
|
16
|
+
summary: 'get user by id',
|
|
17
|
+
description: 'user info',
|
|
18
|
+
servers: [{ url: '/user' }, { url: '/pet', description: 'pet server' }],
|
|
19
|
+
|
|
20
|
+
get: {
|
|
21
|
+
tags: ['pet'],
|
|
22
|
+
summary: 'Find pet by ID',
|
|
23
|
+
description: 'Returns a single pet',
|
|
24
|
+
operationId: 'getPetById',
|
|
25
|
+
servers: [{ url: '/pet' }],
|
|
26
|
+
},
|
|
27
|
+
parameters: [{ name: 'param1', in: 'header', schema: { description: 'string' } }],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
components: {},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const secondDocument = {
|
|
34
|
+
openapi: '3.0.0',
|
|
35
|
+
servers: [{ url: 'http://localhost:8080' }],
|
|
36
|
+
info: {
|
|
37
|
+
description: 'example test',
|
|
38
|
+
version: '1.0.0',
|
|
39
|
+
title: 'Swagger Petstore',
|
|
40
|
+
termsOfService: 'http://swagger.io/terms/',
|
|
41
|
+
license: {
|
|
42
|
+
name: 'Apache 2.0',
|
|
43
|
+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
post: {
|
|
47
|
+
'/GETUser/{userId}': {
|
|
48
|
+
summary: 'get user',
|
|
49
|
+
description: 'user information',
|
|
50
|
+
servers: [{ url: '/user' }, { url: '/pet', description: '' }],
|
|
51
|
+
|
|
52
|
+
get: {
|
|
53
|
+
tags: ['pet'],
|
|
54
|
+
summary: 'Find pet by ID',
|
|
55
|
+
description: 'Returns a single pet',
|
|
56
|
+
operationId: 'getPetById',
|
|
57
|
+
servers: [{ url: '/pet' }],
|
|
58
|
+
},
|
|
59
|
+
parameters: [{ name: 'param1', in: 'header', schema: { description: 'string' } }],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
components: {},
|
|
63
|
+
};
|
package/src/__mocks__/utils.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { handleJoin } from '../../commands/join';
|
|
2
|
-
import { exitWithError } from '../../utils';
|
|
2
|
+
import { exitWithError, writeYaml } from '../../utils';
|
|
3
3
|
import { yellow } from 'colorette';
|
|
4
|
+
import { detectOpenAPI } from '@redocly/openapi-core';
|
|
4
5
|
|
|
5
6
|
jest.mock('../../utils');
|
|
6
7
|
jest.mock('colorette');
|
|
@@ -44,4 +45,25 @@ describe('handleJoin fails', () => {
|
|
|
44
45
|
`You use prefix-tags-with-filename, without-x-tag-groups together.\nPlease choose only one! \n\n`
|
|
45
46
|
);
|
|
46
47
|
});
|
|
48
|
+
|
|
49
|
+
it('should call exitWithError because Only OpenAPI 3 is supported', async () => {
|
|
50
|
+
await handleJoin(
|
|
51
|
+
{
|
|
52
|
+
apis: ['first.yaml', 'second.yaml'],
|
|
53
|
+
},
|
|
54
|
+
'cli-version'
|
|
55
|
+
);
|
|
56
|
+
expect(exitWithError).toHaveBeenCalledWith('Only OpenAPI 3 is supported: undefined \n\n');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should call writeYaml function', async () => {
|
|
60
|
+
(detectOpenAPI as jest.Mock).mockReturnValue('oas3_0');
|
|
61
|
+
await handleJoin(
|
|
62
|
+
{
|
|
63
|
+
apis: ['first.yaml', 'second.yaml'],
|
|
64
|
+
},
|
|
65
|
+
'cli-version'
|
|
66
|
+
);
|
|
67
|
+
expect(writeYaml).toHaveBeenCalled();
|
|
68
|
+
});
|
|
47
69
|
});
|
package/src/commands/join.ts
CHANGED
|
@@ -26,7 +26,9 @@ import {
|
|
|
26
26
|
writeYaml,
|
|
27
27
|
exitWithError,
|
|
28
28
|
} from '../utils';
|
|
29
|
-
import { isObject, isString } from '../js-utils';
|
|
29
|
+
import { isObject, isString, keysOf } from '../js-utils';
|
|
30
|
+
import { Oas3Parameter, Oas3PathItem, Oas3Server } from '@redocly/openapi-core/lib/typings/openapi';
|
|
31
|
+
import { OPENAPI3_METHOD } from './split/types';
|
|
30
32
|
|
|
31
33
|
const COMPONENTS = 'components';
|
|
32
34
|
const Tags = 'tags';
|
|
@@ -332,73 +334,180 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
|
|
|
332
334
|
{ apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }: JoinDocumentContext
|
|
333
335
|
) {
|
|
334
336
|
const { paths } = openapi;
|
|
337
|
+
const operationsSet = new Set(keysOf<typeof OPENAPI3_METHOD>(OPENAPI3_METHOD));
|
|
335
338
|
if (paths) {
|
|
336
339
|
if (!joinedDef.hasOwnProperty('paths')) {
|
|
337
340
|
joinedDef['paths'] = {};
|
|
338
341
|
}
|
|
339
|
-
|
|
342
|
+
|
|
343
|
+
for (const path of keysOf(paths)) {
|
|
340
344
|
if (!joinedDef.paths.hasOwnProperty(path)) {
|
|
341
345
|
joinedDef.paths[path] = {};
|
|
342
346
|
}
|
|
343
347
|
if (!potentialConflicts.paths.hasOwnProperty(path)) {
|
|
344
348
|
potentialConflicts.paths[path] = {};
|
|
345
349
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const { operationId } = pathOperation;
|
|
353
|
-
if (operationId) {
|
|
354
|
-
if (!potentialConflicts.paths.hasOwnProperty('operationIds')) {
|
|
355
|
-
potentialConflicts.paths['operationIds'] = {};
|
|
356
|
-
}
|
|
357
|
-
potentialConflicts.paths.operationIds[operationId] = [
|
|
358
|
-
...(potentialConflicts.paths.operationIds[operationId] || []),
|
|
359
|
-
api,
|
|
360
|
-
];
|
|
350
|
+
|
|
351
|
+
const pathItem = paths[path] as Oas3PathItem;
|
|
352
|
+
|
|
353
|
+
for (const field of keysOf(pathItem)) {
|
|
354
|
+
if (operationsSet.has(field as OPENAPI3_METHOD)) {
|
|
355
|
+
collectPathOperation(pathItem, path, field as OPENAPI3_METHOD);
|
|
361
356
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
joinedDef.paths[path][operation].tags = tags.map((tag: string) =>
|
|
365
|
-
addPrefix(tag, tagsPrefix)
|
|
366
|
-
);
|
|
367
|
-
populateTags({
|
|
368
|
-
api,
|
|
369
|
-
apiFilename,
|
|
370
|
-
tags: formatTags(tags),
|
|
371
|
-
potentialConflicts,
|
|
372
|
-
tagsPrefix,
|
|
373
|
-
componentsPrefix,
|
|
374
|
-
});
|
|
375
|
-
} else {
|
|
376
|
-
joinedDef.paths[path][operation]['tags'] = [
|
|
377
|
-
addPrefix('other', tagsPrefix || apiFilename),
|
|
378
|
-
];
|
|
379
|
-
populateTags({
|
|
380
|
-
api,
|
|
381
|
-
apiFilename,
|
|
382
|
-
tags: formatTags(['other']),
|
|
383
|
-
potentialConflicts,
|
|
384
|
-
tagsPrefix: tagsPrefix || apiFilename,
|
|
385
|
-
componentsPrefix,
|
|
386
|
-
});
|
|
357
|
+
if (field === 'servers') {
|
|
358
|
+
collectPathServers(pathItem, path);
|
|
387
359
|
}
|
|
388
|
-
if (
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
);
|
|
393
|
-
} else if (pathOperation.security) {
|
|
394
|
-
joinedDef.paths[path][operation].security = addSecurityPrefix(
|
|
395
|
-
pathOperation.security,
|
|
396
|
-
componentsPrefix!
|
|
397
|
-
);
|
|
360
|
+
if (field === 'parameters') {
|
|
361
|
+
collectPathParameters(pathItem, path);
|
|
362
|
+
}
|
|
363
|
+
if (typeof pathItem[field] === 'string') {
|
|
364
|
+
collectPathStringFields(pathItem, path, field);
|
|
398
365
|
}
|
|
399
366
|
}
|
|
400
367
|
}
|
|
401
368
|
}
|
|
369
|
+
|
|
370
|
+
function collectPathStringFields(
|
|
371
|
+
pathItem: Oas3PathItem,
|
|
372
|
+
path: string | number,
|
|
373
|
+
field: keyof Oas3PathItem
|
|
374
|
+
) {
|
|
375
|
+
const fieldValue = pathItem[field];
|
|
376
|
+
if (
|
|
377
|
+
joinedDef.paths[path].hasOwnProperty(field) &&
|
|
378
|
+
joinedDef.paths[path][field] !== fieldValue
|
|
379
|
+
) {
|
|
380
|
+
process.stderr.write(yellow(`warning: different ${field} values in ${path}\n`));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
joinedDef.paths[path][field] = fieldValue;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function collectPathServers(pathItem: Oas3PathItem, path: string | number) {
|
|
387
|
+
if (!pathItem.servers) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (!joinedDef.paths[path].hasOwnProperty('servers')) {
|
|
392
|
+
joinedDef.paths[path].servers = [];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
for (const server of pathItem.servers) {
|
|
396
|
+
let isFoundServer = false;
|
|
397
|
+
for (const pathServer of joinedDef.paths[path].servers) {
|
|
398
|
+
if (pathServer.url === server.url) {
|
|
399
|
+
if (!isServersEqual(pathServer, server)) {
|
|
400
|
+
exitWithError(`Different server values for (${server.url}) in ${path}`);
|
|
401
|
+
}
|
|
402
|
+
isFoundServer = true;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (!isFoundServer) {
|
|
407
|
+
joinedDef.paths[path].servers.push(server);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function collectPathParameters(pathItem: Oas3PathItem, path: string | number) {
|
|
413
|
+
if (!pathItem.parameters) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (!joinedDef.paths[path].hasOwnProperty('parameters')) {
|
|
417
|
+
joinedDef.paths[path].parameters = [];
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
for (const parameter of pathItem.parameters as Oas3Parameter[]) {
|
|
421
|
+
let isFoundParameter = false;
|
|
422
|
+
for (const pathParameter of joinedDef.paths[path].parameters) {
|
|
423
|
+
if (pathParameter.name === parameter.name && pathParameter.in === parameter.in) {
|
|
424
|
+
if (!isEqual(pathParameter.schema, parameter.schema)) {
|
|
425
|
+
exitWithError(`Different parameter schemas for (${parameter.name}) in ${path}`);
|
|
426
|
+
}
|
|
427
|
+
isFoundParameter = true;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (!isFoundParameter) {
|
|
432
|
+
joinedDef.paths[path].parameters.push(parameter);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function collectPathOperation(
|
|
438
|
+
pathItem: Oas3PathItem,
|
|
439
|
+
path: string | number,
|
|
440
|
+
operation: OPENAPI3_METHOD
|
|
441
|
+
) {
|
|
442
|
+
const pathOperation = pathItem[operation];
|
|
443
|
+
|
|
444
|
+
if (!pathOperation) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
joinedDef.paths[path][operation] = pathOperation;
|
|
449
|
+
potentialConflicts.paths[path][operation] = [
|
|
450
|
+
...(potentialConflicts.paths[path][operation] || []),
|
|
451
|
+
api,
|
|
452
|
+
];
|
|
453
|
+
|
|
454
|
+
const { operationId } = pathOperation;
|
|
455
|
+
|
|
456
|
+
if (operationId) {
|
|
457
|
+
if (!potentialConflicts.paths.hasOwnProperty('operationIds')) {
|
|
458
|
+
potentialConflicts.paths['operationIds'] = {};
|
|
459
|
+
}
|
|
460
|
+
potentialConflicts.paths.operationIds[operationId] = [
|
|
461
|
+
...(potentialConflicts.paths.operationIds[operationId] || []),
|
|
462
|
+
api,
|
|
463
|
+
];
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const { tags, security } = joinedDef.paths[path][operation];
|
|
467
|
+
|
|
468
|
+
if (tags) {
|
|
469
|
+
joinedDef.paths[path][operation].tags = tags.map((tag: string) =>
|
|
470
|
+
addPrefix(tag, tagsPrefix)
|
|
471
|
+
);
|
|
472
|
+
populateTags({
|
|
473
|
+
api,
|
|
474
|
+
apiFilename,
|
|
475
|
+
tags: formatTags(tags),
|
|
476
|
+
potentialConflicts,
|
|
477
|
+
tagsPrefix,
|
|
478
|
+
componentsPrefix,
|
|
479
|
+
});
|
|
480
|
+
} else {
|
|
481
|
+
joinedDef.paths[path][operation]['tags'] = [addPrefix('other', tagsPrefix || apiFilename)];
|
|
482
|
+
populateTags({
|
|
483
|
+
api,
|
|
484
|
+
apiFilename,
|
|
485
|
+
tags: formatTags(['other']),
|
|
486
|
+
potentialConflicts,
|
|
487
|
+
tagsPrefix: tagsPrefix || apiFilename,
|
|
488
|
+
componentsPrefix,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
if (!security && openapi.hasOwnProperty('security')) {
|
|
492
|
+
joinedDef.paths[path][operation]['security'] = addSecurityPrefix(
|
|
493
|
+
openapi.security,
|
|
494
|
+
componentsPrefix!
|
|
495
|
+
);
|
|
496
|
+
} else if (pathOperation.security) {
|
|
497
|
+
joinedDef.paths[path][operation].security = addSecurityPrefix(
|
|
498
|
+
pathOperation.security,
|
|
499
|
+
componentsPrefix!
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function isServersEqual(serverOne: Oas3Server, serverTwo: Oas3Server) {
|
|
506
|
+
if (serverOne.description === serverTwo.description) {
|
|
507
|
+
return isEqual(serverOne.variables, serverTwo.variables);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return false;
|
|
402
511
|
}
|
|
403
512
|
|
|
404
513
|
function collectComponents(
|
package/src/commands/lint.ts
CHANGED
|
@@ -127,6 +127,11 @@ function lintConfigCallback(argv: LintOptions, version: string) {
|
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
if (argv.format === 'json') {
|
|
131
|
+
// we can't print config lint results as it will break json output
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
130
135
|
return async (config: RawConfig) => {
|
|
131
136
|
const { 'max-problems': maxProblems, format } = argv;
|
|
132
137
|
const configPath = findConfig(argv.config) || '';
|
|
@@ -38,26 +38,26 @@ export const WEBHOOKS = 'webhooks';
|
|
|
38
38
|
export const xWEBHOOKS = 'x-webhooks';
|
|
39
39
|
export const componentsPath = `#/${COMPONENTS}/`;
|
|
40
40
|
|
|
41
|
-
enum OPENAPI3_METHOD {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
export enum OPENAPI3_METHOD {
|
|
42
|
+
get = 'get',
|
|
43
|
+
put = 'put',
|
|
44
|
+
post = 'post',
|
|
45
|
+
delete = 'delete',
|
|
46
|
+
options = 'options',
|
|
47
|
+
head = 'head',
|
|
48
|
+
patch = 'patch',
|
|
49
|
+
trace = 'trace',
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export const OPENAPI3_METHOD_NAMES: OPENAPI3_METHOD[] = [
|
|
53
|
-
OPENAPI3_METHOD.
|
|
54
|
-
OPENAPI3_METHOD.
|
|
55
|
-
OPENAPI3_METHOD.
|
|
56
|
-
OPENAPI3_METHOD.
|
|
57
|
-
OPENAPI3_METHOD.
|
|
58
|
-
OPENAPI3_METHOD.
|
|
59
|
-
OPENAPI3_METHOD.
|
|
60
|
-
OPENAPI3_METHOD.
|
|
53
|
+
OPENAPI3_METHOD.get,
|
|
54
|
+
OPENAPI3_METHOD.put,
|
|
55
|
+
OPENAPI3_METHOD.post,
|
|
56
|
+
OPENAPI3_METHOD.delete,
|
|
57
|
+
OPENAPI3_METHOD.options,
|
|
58
|
+
OPENAPI3_METHOD.head,
|
|
59
|
+
OPENAPI3_METHOD.patch,
|
|
60
|
+
OPENAPI3_METHOD.trace,
|
|
61
61
|
];
|
|
62
62
|
|
|
63
63
|
export enum OPENAPI3_COMPONENT {
|
package/src/commands/stats.ts
CHANGED
|
@@ -90,7 +90,7 @@ export async function handleStats(argv: { config?: string; api?: string; format:
|
|
|
90
90
|
|
|
91
91
|
const resolvedRefMap = await resolveDocument({
|
|
92
92
|
rootDocument: document,
|
|
93
|
-
rootType: types.
|
|
93
|
+
rootType: types.Root,
|
|
94
94
|
externalRefResolver,
|
|
95
95
|
});
|
|
96
96
|
|
|
@@ -107,7 +107,7 @@ export async function handleStats(argv: { config?: string; api?: string; format:
|
|
|
107
107
|
|
|
108
108
|
walkDocument({
|
|
109
109
|
document,
|
|
110
|
-
rootType: types.
|
|
110
|
+
rootType: types.Root,
|
|
111
111
|
normalizedVisitors: statsVisitor,
|
|
112
112
|
resolvedRefMap,
|
|
113
113
|
ctx,
|
package/src/index.ts
CHANGED
package/src/js-utils.ts
CHANGED
|
@@ -10,3 +10,8 @@ export function isEmptyObject(obj: any) {
|
|
|
10
10
|
export function isString(str: string) {
|
|
11
11
|
return Object.prototype.toString.call(str) === '[object String]';
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
export function keysOf<T>(obj: T) {
|
|
15
|
+
if (!obj) return [];
|
|
16
|
+
return Object.keys(obj) as (keyof T)[];
|
|
17
|
+
}
|