mirror of
https://github.com/LukeHagar/redocly-cli.git
synced 2025-12-06 04:21:09 +00:00
feat: extend split and join commands to produce JSON output (#1305)
This commit is contained in:
5
.changeset/plenty-mugs-suffer.md
Normal file
5
.changeset/plenty-mugs-suffer.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@redocly/cli': minor
|
||||
---
|
||||
|
||||
Add JSON output support to the `split` and `join` commands.
|
||||
@@ -161,6 +161,19 @@ describe('E2E', () => {
|
||||
const result = getCommandOutput(args, folderPath);
|
||||
(<any>expect(result)).toMatchSpecificSnapshot(join(folderPath, 'snapshot.js'));
|
||||
});
|
||||
|
||||
test('openapi json file', () => {
|
||||
const folderPath = join(__dirname, `split/openapi-json-file`);
|
||||
const file = '../../../__tests__/split/openapi-json-file/openapi.json';
|
||||
|
||||
const args = getParams('../../../packages/cli/src/index.ts', 'split', [
|
||||
file,
|
||||
'--outDir=output',
|
||||
]);
|
||||
|
||||
const result = getCommandOutput(args, folderPath);
|
||||
(<any>expect(result)).toMatchSpecificSnapshot(join(folderPath, 'snapshot.js'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('join', () => {
|
||||
@@ -214,6 +227,46 @@ describe('E2E', () => {
|
||||
const result = getCommandOutput(args, testPath);
|
||||
(<any>expect(result)).toMatchSpecificSnapshot(join(testPath, 'snapshot.js'));
|
||||
});
|
||||
|
||||
describe('files with different extensions', () => {
|
||||
const joinParameters: {
|
||||
name: string;
|
||||
folder: string;
|
||||
entrypoints: string[];
|
||||
snapshot: string;
|
||||
output?: string;
|
||||
}[] = [
|
||||
{
|
||||
name: 'first entrypoint is a json file',
|
||||
folder: 'json-and-yaml-input',
|
||||
entrypoints: ['foo.json', 'bar.yaml'],
|
||||
snapshot: 'json-output.snapshot.js',
|
||||
},
|
||||
{
|
||||
name: 'first entrypoint is a yaml file',
|
||||
folder: 'json-and-yaml-input',
|
||||
entrypoints: ['bar.yaml', 'foo.json'],
|
||||
snapshot: 'yaml-output.snapshot.js',
|
||||
},
|
||||
{
|
||||
name: 'json output file',
|
||||
folder: 'yaml-input-and-json-output',
|
||||
entrypoints: ['foo.yaml', 'bar.yaml'],
|
||||
output: 'openapi.json',
|
||||
snapshot: 'snapshot.js',
|
||||
},
|
||||
];
|
||||
|
||||
test.each(joinParameters)('test with option: %s', (parameters) => {
|
||||
const testPath = join(__dirname, `join/${parameters.folder}`);
|
||||
const argsWithOption = parameters.output
|
||||
? [...parameters.entrypoints, ...[`-o=${parameters.output}`]]
|
||||
: parameters.entrypoints;
|
||||
const args = getParams('../../../packages/cli/src/index.ts', 'join', argsWithOption);
|
||||
const result = getCommandOutput(args, testPath);
|
||||
(<any>expect(result)).toMatchSpecificSnapshot(join(testPath, parameters.snapshot));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('bundle', () => {
|
||||
|
||||
23
__tests__/join/json-and-yaml-input/bar.yaml
Normal file
23
__tests__/join/json-and-yaml-input/bar.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Example API
|
||||
description: This is an example API.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: https://redocly-example.com/api
|
||||
paths:
|
||||
/users/{userId}:
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
description: ID of the user
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
summary: Get user by ID
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'404':
|
||||
description: Not found
|
||||
49
__tests__/join/json-and-yaml-input/foo.json
Normal file
49
__tests__/join/json-and-yaml-input/foo.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Example API",
|
||||
"description": "This is an example API.",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://redocly-example.com/api"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}/orders/{orderId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"in": "path",
|
||||
"description": "ID of the user",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orderId",
|
||||
"in": "path",
|
||||
"description": "ID of the order",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"x-private": true,
|
||||
"summary": "Get an order by ID for a specific user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
__tests__/join/json-and-yaml-input/json-output.snapshot.js
Normal file
117
__tests__/join/json-and-yaml-input/json-output.snapshot.js
Normal file
@@ -0,0 +1,117 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`E2E join files with different extensions test with option: {
|
||||
name: 'first entrypoint is a json file',
|
||||
folder: 'json-and-yaml-input',
|
||||
entrypoints: [Array],
|
||||
snapshot: 'json-output.snapshot.js'
|
||||
} 1`] = `
|
||||
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Example API",
|
||||
"description": "This is an example API.",
|
||||
"version": "<version>"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://redocly-example.com/api"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "foo_other",
|
||||
"x-displayName": "other"
|
||||
},
|
||||
{
|
||||
"name": "bar_other",
|
||||
"x-displayName": "other"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}/orders/{orderId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"in": "path",
|
||||
"description": "ID of the user",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orderId",
|
||||
"in": "path",
|
||||
"description": "ID of the order",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"x-private": true,
|
||||
"summary": "Get an order by ID for a specific user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"foo_other"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/{userId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"in": "path",
|
||||
"description": "ID of the user",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"summary": "Get user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"bar_other"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {},
|
||||
"x-tagGroups": [
|
||||
{
|
||||
"name": "foo",
|
||||
"tags": [
|
||||
"foo_other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bar",
|
||||
"tags": [
|
||||
"bar_other"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
openapi.json: join processed in <test>ms
|
||||
|
||||
|
||||
`;
|
||||
76
__tests__/join/json-and-yaml-input/yaml-output.snapshot.js
Normal file
76
__tests__/join/json-and-yaml-input/yaml-output.snapshot.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`E2E join files with different extensions test with option: {
|
||||
name: 'first entrypoint is a yaml file',
|
||||
folder: 'json-and-yaml-input',
|
||||
entrypoints: [Array],
|
||||
snapshot: 'yaml-output.snapshot.js'
|
||||
} 1`] = `
|
||||
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Example API
|
||||
description: This is an example API.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: https://redocly-example.com/api
|
||||
tags:
|
||||
- name: bar_other
|
||||
x-displayName: other
|
||||
- name: foo_other
|
||||
x-displayName: other
|
||||
paths:
|
||||
/users/{userId}:
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
description: ID of the user
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
summary: Get user by ID
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- bar_other
|
||||
/users/{userId}/orders/{orderId}:
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
description: ID of the user
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
- name: orderId
|
||||
in: path
|
||||
description: ID of the order
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
x-private: true
|
||||
summary: Get an order by ID for a specific user
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'404':
|
||||
description: Not found
|
||||
tags:
|
||||
- foo_other
|
||||
components: {}
|
||||
x-tagGroups:
|
||||
- name: bar
|
||||
tags:
|
||||
- bar_other
|
||||
- name: foo
|
||||
tags:
|
||||
- foo_other
|
||||
|
||||
openapi.yaml: join processed in <test>ms
|
||||
|
||||
|
||||
`;
|
||||
84
__tests__/join/multi-references-to-one-file/openapi.yaml
Normal file
84
__tests__/join/multi-references-to-one-file/openapi.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Sample API
|
||||
description: My sample api
|
||||
version: 0.0.1
|
||||
license:
|
||||
name: Internal
|
||||
url: https://mycompany.com/license
|
||||
tags:
|
||||
- name: GetSingleFoo
|
||||
description: Get a single foo
|
||||
x-displayName: GetSingleFoo
|
||||
- name: Foo
|
||||
description: All foo operations
|
||||
x-displayName: Foo
|
||||
- name: foo_other
|
||||
x-displayName: other
|
||||
- name: CreateBar
|
||||
description: Create a new Bar
|
||||
x-displayName: CreateBar
|
||||
- name: bar_other
|
||||
x-displayName: other
|
||||
paths:
|
||||
/foo/{id}:
|
||||
get:
|
||||
summary: Returns a single foo
|
||||
operationId: getFoo
|
||||
responses:
|
||||
'200':
|
||||
description: One single Food
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Response'
|
||||
tags:
|
||||
- foo_other
|
||||
/bar/:
|
||||
post:
|
||||
summary: Create a single bar
|
||||
operationId: createBar
|
||||
responses:
|
||||
'200':
|
||||
description: One single bar
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Response'
|
||||
tags:
|
||||
- bar_other
|
||||
components:
|
||||
schemas:
|
||||
FooObject:
|
||||
type: object
|
||||
properties:
|
||||
x:
|
||||
type: string
|
||||
'y':
|
||||
type: string
|
||||
Response:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
subFoo:
|
||||
$ref: '#/components/schemas/FooObject'
|
||||
x-tagGroups:
|
||||
- name: foo
|
||||
tags:
|
||||
- GetSingleFoo
|
||||
- Foo
|
||||
- foo_other
|
||||
description: My sample api
|
||||
- name: bar
|
||||
tags:
|
||||
- CreateBar
|
||||
- bar_other
|
||||
23
__tests__/join/yaml-input-and-json-output/bar.yaml
Normal file
23
__tests__/join/yaml-input-and-json-output/bar.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Example API
|
||||
description: This is an example API.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: https://redocly-example.com/api
|
||||
paths:
|
||||
/users/{userId}:
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
description: ID of the user
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
summary: Get user by ID
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'404':
|
||||
description: Not found
|
||||
30
__tests__/join/yaml-input-and-json-output/foo.yaml
Normal file
30
__tests__/join/yaml-input-and-json-output/foo.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Example API
|
||||
description: This is an example API.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: https://redocly-example.com/api
|
||||
paths:
|
||||
/users/{userId}/orders/{orderId}:
|
||||
parameters:
|
||||
- name: userId
|
||||
in: path
|
||||
description: ID of the user
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
- name: orderId
|
||||
in: path
|
||||
description: ID of the order
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
x-private: true
|
||||
summary: Get an order by ID for a specific user
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'404':
|
||||
description: Not found
|
||||
118
__tests__/join/yaml-input-and-json-output/snapshot.js
Normal file
118
__tests__/join/yaml-input-and-json-output/snapshot.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`E2E join files with different extensions test with option: {
|
||||
name: 'json output file',
|
||||
folder: 'yaml-input-and-json-output',
|
||||
entrypoints: [Array],
|
||||
output: 'openapi.json',
|
||||
snapshot: 'snapshot.js'
|
||||
} 1`] = `
|
||||
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Example API",
|
||||
"description": "This is an example API.",
|
||||
"version": "<version>"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://redocly-example.com/api"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "foo_other",
|
||||
"x-displayName": "other"
|
||||
},
|
||||
{
|
||||
"name": "bar_other",
|
||||
"x-displayName": "other"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}/orders/{orderId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"in": "path",
|
||||
"description": "ID of the user",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orderId",
|
||||
"in": "path",
|
||||
"description": "ID of the order",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"x-private": true,
|
||||
"summary": "Get an order by ID for a specific user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"foo_other"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/{userId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "userId",
|
||||
"in": "path",
|
||||
"description": "ID of the user",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"summary": "Get user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"bar_other"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {},
|
||||
"x-tagGroups": [
|
||||
{
|
||||
"name": "foo",
|
||||
"tags": [
|
||||
"foo_other"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bar",
|
||||
"tags": [
|
||||
"bar_other"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
openapi.json: join processed in <test>ms
|
||||
|
||||
|
||||
`;
|
||||
165
__tests__/split/openapi-json-file/openapi.json
Normal file
165
__tests__/split/openapi-json-file/openapi.json
Normal file
@@ -0,0 +1,165 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore",
|
||||
"license": {
|
||||
"name": "MIT"
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://petstore.swagger.io/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"get": {
|
||||
"summary": "List all pets",
|
||||
"operationId": "listPets",
|
||||
"tags": ["pets"],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"description": "How many items to return at one time (max 100)",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A paged array of pets",
|
||||
"headers": {
|
||||
"x-next": {
|
||||
"description": "A link to the next page of responses",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Pets"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"summary": "Create a pet",
|
||||
"operationId": "createPets",
|
||||
"tags": ["pets"],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Null response"
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/pets/{petId}": {
|
||||
"get": {
|
||||
"summary": "Info for a specific pet",
|
||||
"operationId": "showPetById",
|
||||
"tags": ["pets"],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "petId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The id of the pet to retrieve",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Expected response to a valid request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Pet"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Pet": {
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"tag": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Pets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Pet"
|
||||
}
|
||||
},
|
||||
"Error": {
|
||||
"type": "object",
|
||||
"required": ["code", "message"],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
184
__tests__/split/openapi-json-file/snapshot.js
Normal file
184
__tests__/split/openapi-json-file/snapshot.js
Normal file
@@ -0,0 +1,184 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`E2E split openapi json file 1`] = `
|
||||
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"tag": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./Pet.json"
|
||||
}
|
||||
}{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}{
|
||||
"get": {
|
||||
"summary": "List all pets",
|
||||
"operationId": "listPets",
|
||||
"tags": [
|
||||
"pets"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"description": "How many items to return at one time (max 100)",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A paged array of pets",
|
||||
"headers": {
|
||||
"x-next": {
|
||||
"description": "A link to the next page of responses",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Pets"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"summary": "Create a pet",
|
||||
"operationId": "createPets",
|
||||
"tags": [
|
||||
"pets"
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Null response"
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}{
|
||||
"get": {
|
||||
"summary": "Info for a specific pet",
|
||||
"operationId": "showPetById",
|
||||
"tags": [
|
||||
"pets"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "petId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The id of the pet to retrieve",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Expected response to a valid request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Pet"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"version": "<version>",
|
||||
"title": "Swagger Petstore",
|
||||
"license": {
|
||||
"name": "MIT"
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://petstore.swagger.io/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"$ref": "paths/pets.json"
|
||||
},
|
||||
"/pets/{petId}": {
|
||||
"$ref": "paths/pets_{petId}.json"
|
||||
}
|
||||
}
|
||||
}🪓 Document: ../../../__tests__/split/openapi-json-file/openapi.json is successfully split
|
||||
and all related files are saved to the directory: output
|
||||
|
||||
../../../__tests__/split/openapi-json-file/openapi.json: split processed in <test>ms
|
||||
|
||||
|
||||
`;
|
||||
@@ -14,9 +14,9 @@ With Redocly CLI, you can solve this problem by using the `join` command that ca
|
||||
|
||||
To easily distinguish the origin of OpenAPI objects and properties, you can optionally instruct the `join` command to append custom prefixes to them.
|
||||
|
||||
The `join` command accepts both YAML and JSON files, which you can mix in the resulting `openapi.yaml` file. Setting a custom name for this file can be achieved by providing it through the `--output` argument. Any existing file is overwritten.
|
||||
The `join` command accepts both YAML and JSON files, which you can mix in the resulting `openapi.yaml` or `openapi.json` file. Setting a custom name and extension for this file can be achieved by providing it through the `--output` argument. Any existing file is overwritten. If the `--output` option is not provided, the command uses the extension of the first entry point file.
|
||||
|
||||
Apart from providing individual API description files as the input, you can also specify the path to a folder that contains multiple API description files and match them with a wildcard (for example, `myproject/openapi/*.yaml`). The `join` command collects all matching files and combines them into one file.
|
||||
Apart from providing individual API description files as the input, you can also specify the path to a folder that contains multiple API description files and match them with a wildcard (for example, `myproject/openapi/*.(yaml/json)`). The `join` command collects all matching files and combines them into one file.
|
||||
|
||||
### Usage
|
||||
|
||||
@@ -43,7 +43,7 @@ redocly join --version
|
||||
| --help | boolean | Show help. |
|
||||
| --lint | boolean | Lint API description files. |
|
||||
| --lint-config | string | Specify the severity level for the configuration file. <br/> **Possible values:** `warn`, `error`, `off`. Default value is `warn`. |
|
||||
| --output, -o | string | Name for the joined output file. Defaults to `openapi.yaml`. **If the file already exists, it's overwritten.** |
|
||||
| --output, -o | string | Name for the joined output file. Defaults to `openapi.yaml` or `openapi.json` (Depends on the extension of the first input file). **If the file already exists, it's overwritten.** |
|
||||
| --prefix-components-with-info-prop | string | Prefix components with property value from info object. See the [prefix-components-with-info-prop section](#prefix-components-with-info-prop) below. |
|
||||
| --prefix-tags-with-filename | string | Prefix tags with property value from file name. See the [prefix-tags-with-filename section](#prefix-tags-with-filename) below. |
|
||||
| --prefix-tags-with-info-prop | boolean | Prefix tags with property value from info object. See the [prefix-tags-with-info-prop](#prefix-tags-with-info-prop) section. |
|
||||
@@ -274,7 +274,7 @@ components:
|
||||
|
||||
### Custom output file
|
||||
|
||||
By default, the CLI tool writes the joined file as `openapi.yaml` in the current working directory. Use the optional `--output` argument to provide an alternative output file path.
|
||||
By default, the CLI tool writes the joined file as `openapi.yaml` or `openapi.json` in the current working directory. Use the optional `--output` argument to provide an alternative output file path.
|
||||
|
||||
```bash Command
|
||||
redocly join --output=openapi-custom.yaml
|
||||
|
||||
@@ -31,6 +31,7 @@ export const doesYamlFileExist = jest.fn();
|
||||
export const bundleDocument = jest.fn(() => Promise.resolve({ problems: {} }));
|
||||
export const detectSpec = jest.fn();
|
||||
export const isAbsoluteUrl = jest.fn();
|
||||
export const stringifyYaml = jest.fn((data) => data);
|
||||
|
||||
export class BaseResolver {
|
||||
cache = new Map<string, Promise<Document | ResolveError>>();
|
||||
|
||||
@@ -17,3 +17,5 @@ export const writeYaml = jest.fn();
|
||||
export const loadConfigAndHandleErrors = jest.fn(() => ConfigFixture);
|
||||
export const checkIfRulesetExist = jest.fn();
|
||||
export const sortTopLevelKeysForOas = jest.fn((document) => document);
|
||||
export const getAndValidateFileExtension = jest.fn((fileName: string) => fileName.split('.').pop());
|
||||
export const writeToFileByExtension = jest.fn();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { handleJoin } from '../../commands/join';
|
||||
import { exitWithError, writeYaml } from '../../utils';
|
||||
import { exitWithError, writeToFileByExtension, writeYaml } from '../../utils';
|
||||
import { yellow } from 'colorette';
|
||||
import { detectSpec } from '@redocly/openapi-core';
|
||||
import { loadConfig } from '../../__mocks__/@redocly/openapi-core';
|
||||
import { ConfigFixture } from '../fixtures/config';
|
||||
|
||||
jest.mock('../../utils');
|
||||
|
||||
jest.mock('colorette');
|
||||
|
||||
describe('handleJoin fails', () => {
|
||||
@@ -80,7 +81,7 @@ describe('handleJoin fails', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should call writeYaml function', async () => {
|
||||
it('should call writeToFileByExtension function', async () => {
|
||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||
await handleJoin(
|
||||
{
|
||||
@@ -90,10 +91,14 @@ describe('handleJoin fails', () => {
|
||||
'cli-version'
|
||||
);
|
||||
|
||||
expect(writeYaml).toHaveBeenCalledWith(expect.any(Object), 'openapi.yaml', expect.any(Boolean));
|
||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
'openapi.yaml',
|
||||
expect.any(Boolean)
|
||||
);
|
||||
});
|
||||
|
||||
it('should call writeYaml function for OpenAPI 3.1', async () => {
|
||||
it('should call writeToFileByExtension function for OpenAPI 3.1', async () => {
|
||||
(detectSpec as jest.Mock).mockReturnValue('oas3_1');
|
||||
await handleJoin(
|
||||
{
|
||||
@@ -103,10 +108,14 @@ describe('handleJoin fails', () => {
|
||||
'cli-version'
|
||||
);
|
||||
|
||||
expect(writeYaml).toHaveBeenCalledWith(expect.any(Object), 'openapi.yaml', expect.any(Boolean));
|
||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
'openapi.yaml',
|
||||
expect.any(Boolean)
|
||||
);
|
||||
});
|
||||
|
||||
it('should call writeYaml function with custom output file', async () => {
|
||||
it('should call writeToFileByExtension function with custom output file', async () => {
|
||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||
await handleJoin(
|
||||
{
|
||||
@@ -117,7 +126,28 @@ describe('handleJoin fails', () => {
|
||||
'cli-version'
|
||||
);
|
||||
|
||||
expect(writeYaml).toHaveBeenCalledWith(expect.any(Object), 'output.yml', expect.any(Boolean));
|
||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
'output.yml',
|
||||
expect.any(Boolean)
|
||||
);
|
||||
});
|
||||
|
||||
it('should call writeToFileByExtension function with json file extension', async () => {
|
||||
(detectSpec as jest.Mock).mockReturnValue('oas3_0');
|
||||
await handleJoin(
|
||||
{
|
||||
apis: ['first.json', 'second.yaml'],
|
||||
},
|
||||
ConfigFixture as any,
|
||||
'cli-version'
|
||||
);
|
||||
|
||||
expect(writeToFileByExtension).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
'openapi.json',
|
||||
expect.any(Boolean)
|
||||
);
|
||||
});
|
||||
|
||||
it('should call skipDecorators and skipPreprocessors', async () => {
|
||||
|
||||
@@ -12,6 +12,10 @@ import {
|
||||
HandledError,
|
||||
cleanArgs,
|
||||
cleanRawInput,
|
||||
getAndValidateFileExtension,
|
||||
writeYaml,
|
||||
writeJson,
|
||||
writeToFileByExtension,
|
||||
} from '../utils';
|
||||
import {
|
||||
ResolvedApi,
|
||||
@@ -19,11 +23,13 @@ import {
|
||||
isAbsoluteUrl,
|
||||
ResolveError,
|
||||
YamlParseError,
|
||||
stringifyYaml,
|
||||
} from '@redocly/openapi-core';
|
||||
import { blue, red, yellow } from 'colorette';
|
||||
import { existsSync, statSync } from 'fs';
|
||||
import { existsSync, statSync, writeFileSync } from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as process from 'process';
|
||||
import * as utils from '../utils';
|
||||
|
||||
jest.mock('os');
|
||||
jest.mock('colorette');
|
||||
@@ -554,4 +560,42 @@ describe('cleanRawInput', () => {
|
||||
'redocly lint file-json --format stylish --extends=minimal --skip-rule operation-4xx-response'
|
||||
);
|
||||
});
|
||||
|
||||
describe('validateFileExtension', () => {
|
||||
it('should return current file extension', () => {
|
||||
expect(getAndValidateFileExtension('test.json')).toEqual('json');
|
||||
});
|
||||
|
||||
it('should return yaml and print warning if file extension does not supported', () => {
|
||||
const stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
||||
(yellow as jest.Mock<any, any>).mockImplementation((text: string) => text);
|
||||
|
||||
expect(getAndValidateFileExtension('test.xml')).toEqual('yaml');
|
||||
expect(stderrMock).toHaveBeenCalledWith(`Unsupported file extension: xml. Using yaml.\n`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeToFileByExtension', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(process.stderr, 'write').mockImplementation(jest.fn());
|
||||
(yellow as jest.Mock<any, any>).mockImplementation((text: string) => text);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should call stringifyYaml function', () => {
|
||||
writeToFileByExtension('test data', 'test.yaml');
|
||||
expect(stringifyYaml).toHaveBeenCalledWith('test data', { noRefs: false });
|
||||
expect(process.stderr.write).toHaveBeenCalledWith(`test data`);
|
||||
});
|
||||
|
||||
it('should call JSON.stringify function', () => {
|
||||
const stringifySpy = jest.spyOn(JSON, 'stringify').mockImplementation((data) => data);
|
||||
writeToFileByExtension('test data', 'test.json');
|
||||
expect(stringifySpy).toHaveBeenCalledWith('test data', null, 2);
|
||||
expect(process.stderr.write).toHaveBeenCalledWith(`test data`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,9 +25,10 @@ import {
|
||||
printExecutionTime,
|
||||
handleError,
|
||||
printLintTotals,
|
||||
writeYaml,
|
||||
exitWithError,
|
||||
sortTopLevelKeysForOas,
|
||||
getAndValidateFileExtension,
|
||||
writeToFileByExtension,
|
||||
} from '../utils';
|
||||
import { isObject, isString, keysOf } from '../js-utils';
|
||||
import {
|
||||
@@ -70,16 +71,19 @@ export type JoinOptions = {
|
||||
|
||||
export async function handleJoin(argv: JoinOptions, config: Config, packageVersion: string) {
|
||||
const startedAt = performance.now();
|
||||
|
||||
if (argv.apis.length < 2) {
|
||||
return exitWithError(`At least 2 apis should be provided. \n\n`);
|
||||
}
|
||||
|
||||
const fileExtension = getAndValidateFileExtension(argv.output || argv.apis[0]);
|
||||
|
||||
const {
|
||||
'prefix-components-with-info-prop': prefixComponentsWithInfoProp,
|
||||
'prefix-tags-with-filename': prefixTagsWithFilename,
|
||||
'prefix-tags-with-info-prop': prefixTagsWithInfoProp,
|
||||
'without-x-tag-groups': withoutXTagGroups,
|
||||
output: specFilename = 'openapi.yaml',
|
||||
output: specFilename = `openapi.${fileExtension}`,
|
||||
} = argv;
|
||||
|
||||
const usedTagsOptions = [
|
||||
@@ -229,7 +233,8 @@ export async function handleJoin(argv: JoinOptions, config: Config, packageVersi
|
||||
return exitWithError(`Please fix conflicts before running ${yellow('join')}.`);
|
||||
}
|
||||
|
||||
writeYaml(sortTopLevelKeysForOas(joinedDef), specFilename, noRefs);
|
||||
writeToFileByExtension(sortTopLevelKeysForOas(joinedDef), specFilename, noRefs);
|
||||
|
||||
printExecutionTime('join', startedAt, specFilename);
|
||||
|
||||
function populateTags({
|
||||
|
||||
@@ -3,12 +3,13 @@ import * as path from 'path';
|
||||
import * as openapiCore from '@redocly/openapi-core';
|
||||
import { ComponentsFiles } from '../types';
|
||||
import { blue, green } from 'colorette';
|
||||
import { writeToFileByExtension } from '../../../utils';
|
||||
|
||||
const utils = require('../../../utils');
|
||||
|
||||
jest.mock('../../../utils', () => ({
|
||||
...jest.requireActual('../../../utils'),
|
||||
writeYaml: jest.fn(),
|
||||
writeToFileByExtension: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@redocly/openapi-core', () => ({
|
||||
@@ -65,7 +66,9 @@ describe('#split', () => {
|
||||
openapiDir,
|
||||
path.join(openapiDir, 'paths'),
|
||||
componentsFiles,
|
||||
'_'
|
||||
'_',
|
||||
undefined,
|
||||
'yaml'
|
||||
);
|
||||
|
||||
expect(openapiCore.slash).toHaveBeenCalledWith('paths/test.yaml');
|
||||
@@ -82,7 +85,9 @@ describe('#split', () => {
|
||||
openapiDir,
|
||||
path.join(openapiDir, 'webhooks'),
|
||||
componentsFiles,
|
||||
'webhook_'
|
||||
'webhook_',
|
||||
undefined,
|
||||
'yaml'
|
||||
);
|
||||
|
||||
expect(openapiCore.slash).toHaveBeenCalledWith('webhooks/test.yaml');
|
||||
@@ -99,7 +104,9 @@ describe('#split', () => {
|
||||
openapiDir,
|
||||
path.join(openapiDir, 'webhooks'),
|
||||
componentsFiles,
|
||||
'webhook_'
|
||||
'webhook_',
|
||||
undefined,
|
||||
'yaml'
|
||||
);
|
||||
|
||||
expect(openapiCore.slash).toHaveBeenCalledWith('webhooks/test.yaml');
|
||||
@@ -118,7 +125,9 @@ describe('#split', () => {
|
||||
openapiDir,
|
||||
path.join(openapiDir, 'paths'),
|
||||
componentsFiles,
|
||||
'_'
|
||||
'_',
|
||||
undefined,
|
||||
'yaml'
|
||||
);
|
||||
|
||||
expect(utils.escapeLanguageName).nthCalledWith(1, 'C#');
|
||||
|
||||
@@ -10,10 +10,11 @@ import {
|
||||
printExecutionTime,
|
||||
pathToFilename,
|
||||
readYaml,
|
||||
writeYaml,
|
||||
exitWithError,
|
||||
escapeLanguageName,
|
||||
langToExt,
|
||||
writeToFileByExtension,
|
||||
getAndValidateFileExtension,
|
||||
} from '../../utils';
|
||||
import { isString, isObject, isEmptyObject } from '../../js-utils';
|
||||
import {
|
||||
@@ -46,8 +47,9 @@ export async function handleSplit(argv: SplitOptions) {
|
||||
const startedAt = performance.now();
|
||||
const { api, outDir, separator } = argv;
|
||||
validateDefinitionFileName(api!);
|
||||
const ext = getAndValidateFileExtension(api);
|
||||
const openapi = readYaml(api!) as Oas3Definition | Oas3_1Definition;
|
||||
splitDefinition(openapi, outDir, separator);
|
||||
splitDefinition(openapi, outDir, separator, ext);
|
||||
process.stderr.write(
|
||||
`🪓 Document: ${blue(api!)} ${green('is successfully split')}
|
||||
and all related files are saved to the directory: ${blue(outDir)} \n`
|
||||
@@ -58,18 +60,21 @@ export async function handleSplit(argv: SplitOptions) {
|
||||
function splitDefinition(
|
||||
openapi: Oas3Definition | Oas3_1Definition,
|
||||
openapiDir: string,
|
||||
pathSeparator: string
|
||||
pathSeparator: string,
|
||||
ext: string
|
||||
) {
|
||||
fs.mkdirSync(openapiDir, { recursive: true });
|
||||
|
||||
const componentsFiles: ComponentsFiles = {};
|
||||
iterateComponents(openapi, openapiDir, componentsFiles);
|
||||
iterateComponents(openapi, openapiDir, componentsFiles, ext);
|
||||
iteratePathItems(
|
||||
openapi.paths,
|
||||
openapiDir,
|
||||
path.join(openapiDir, 'paths'),
|
||||
componentsFiles,
|
||||
pathSeparator
|
||||
pathSeparator,
|
||||
undefined,
|
||||
ext
|
||||
);
|
||||
const webhooks =
|
||||
(openapi as Oas3_1Definition).webhooks || (openapi as Oas3Definition)['x-webhooks'];
|
||||
@@ -80,11 +85,12 @@ function splitDefinition(
|
||||
path.join(openapiDir, 'webhooks'),
|
||||
componentsFiles,
|
||||
pathSeparator,
|
||||
'webhook_'
|
||||
'webhook_',
|
||||
ext
|
||||
);
|
||||
|
||||
replace$Refs(openapi, openapiDir, componentsFiles);
|
||||
writeYaml(openapi, path.join(openapiDir, 'openapi.yaml'));
|
||||
writeToFileByExtension(openapi, path.join(openapiDir, `openapi.${ext}`));
|
||||
}
|
||||
|
||||
function isStartsWithComponents(node: string) {
|
||||
@@ -135,7 +141,7 @@ function traverseDirectoryDeepCallback(
|
||||
if (isNotYaml(filename)) return;
|
||||
const pathData = readYaml(filename);
|
||||
replace$Refs(pathData, directory, componentsFiles);
|
||||
writeYaml(pathData, filename);
|
||||
writeToFileByExtension(pathData, filename);
|
||||
}
|
||||
|
||||
function crawl(object: any, visitor: any) {
|
||||
@@ -251,8 +257,8 @@ function extractFileNameFromPath(filename: string) {
|
||||
return path.basename(filename, path.extname(filename));
|
||||
}
|
||||
|
||||
function getFileNamePath(componentDirPath: string, componentName: string) {
|
||||
return path.join(componentDirPath, componentName) + '.yaml';
|
||||
function getFileNamePath(componentDirPath: string, componentName: string, ext: string) {
|
||||
return path.join(componentDirPath, componentName) + `.${ext}`;
|
||||
}
|
||||
|
||||
function gatherComponentsFiles(
|
||||
@@ -278,13 +284,14 @@ function iteratePathItems(
|
||||
outDir: string,
|
||||
componentsFiles: object,
|
||||
pathSeparator: string,
|
||||
codeSamplesPathPrefix: string = ''
|
||||
codeSamplesPathPrefix: string = '',
|
||||
ext: string
|
||||
) {
|
||||
if (!pathItems) return;
|
||||
fs.mkdirSync(outDir, { recursive: true });
|
||||
|
||||
for (const pathName of Object.keys(pathItems)) {
|
||||
const pathFile = `${path.join(outDir, pathToFilename(pathName, pathSeparator))}.yaml`;
|
||||
const pathFile = `${path.join(outDir, pathToFilename(pathName, pathSeparator))}.${ext}`;
|
||||
const pathData = pathItems[pathName] as Oas3PathItem;
|
||||
|
||||
if (isRef(pathData)) continue;
|
||||
@@ -314,7 +321,7 @@ function iteratePathItems(
|
||||
};
|
||||
}
|
||||
}
|
||||
writeYaml(pathData, pathFile);
|
||||
writeToFileByExtension(pathData, pathFile);
|
||||
pathItems[pathName] = {
|
||||
$ref: slash(path.relative(openapiDir, pathFile)),
|
||||
};
|
||||
@@ -326,7 +333,8 @@ function iteratePathItems(
|
||||
function iterateComponents(
|
||||
openapi: Oas3Definition | Oas3_1Definition,
|
||||
openapiDir: string,
|
||||
componentsFiles: ComponentsFiles
|
||||
componentsFiles: ComponentsFiles,
|
||||
ext: string
|
||||
) {
|
||||
const { components } = openapi;
|
||||
if (components) {
|
||||
@@ -340,7 +348,7 @@ function iterateComponents(
|
||||
function iterateAndGatherComponentsFiles(componentType: Oas3ComponentName) {
|
||||
const componentDirPath = path.join(componentsDir, componentType);
|
||||
for (const componentName of Object.keys(components?.[componentType] || {})) {
|
||||
const filename = getFileNamePath(componentDirPath, componentName);
|
||||
const filename = getFileNamePath(componentDirPath, componentName, ext);
|
||||
gatherComponentsFiles(components!, componentsFiles, componentType, componentName, filename);
|
||||
}
|
||||
}
|
||||
@@ -350,7 +358,7 @@ function iterateComponents(
|
||||
const componentDirPath = path.join(componentsDir, componentType);
|
||||
createComponentDir(componentDirPath, componentType);
|
||||
for (const componentName of Object.keys(components?.[componentType] || {})) {
|
||||
const filename = getFileNamePath(componentDirPath, componentName);
|
||||
const filename = getFileNamePath(componentDirPath, componentName, ext);
|
||||
const componentData = components?.[componentType]?.[componentName];
|
||||
replace$Refs(componentData, path.dirname(filename), componentsFiles);
|
||||
implicitlyReferenceDiscriminator(
|
||||
@@ -369,7 +377,7 @@ function iterateComponents(
|
||||
)
|
||||
);
|
||||
} else {
|
||||
writeYaml(componentData, filename);
|
||||
writeToFileByExtension(componentData, filename);
|
||||
}
|
||||
|
||||
if (isNotSecurityComponentType(componentType)) {
|
||||
|
||||
@@ -127,7 +127,6 @@ yargs
|
||||
describe: 'Output file',
|
||||
alias: 'o',
|
||||
type: 'string',
|
||||
default: 'openapi.yaml',
|
||||
},
|
||||
config: {
|
||||
description: 'Path to the config file.',
|
||||
|
||||
@@ -25,7 +25,14 @@ import {
|
||||
RedoclyClient,
|
||||
} from '@redocly/openapi-core';
|
||||
import { ConfigValidationError } from '@redocly/openapi-core/lib/config';
|
||||
import { Totals, outputExtensions, Entrypoint, ConfigApis, CommandOptions } from './types';
|
||||
import {
|
||||
Totals,
|
||||
outputExtensions,
|
||||
Entrypoint,
|
||||
ConfigApis,
|
||||
CommandOptions,
|
||||
OutputExtensions,
|
||||
} from './types';
|
||||
import { isEmptyObject } from '@redocly/openapi-core/lib/utils';
|
||||
import { Arguments } from 'yargs';
|
||||
import { version } from './update-version-notifier';
|
||||
@@ -209,6 +216,17 @@ export function readYaml(filename: string) {
|
||||
return parseYaml(fs.readFileSync(filename, 'utf-8'), { filename });
|
||||
}
|
||||
|
||||
export function writeToFileByExtension(data: unknown, filePath: string, noRefs?: boolean) {
|
||||
const ext = getAndValidateFileExtension(filePath);
|
||||
|
||||
if (ext === 'json') {
|
||||
writeJson(data, filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
writeYaml(data, filePath, noRefs);
|
||||
}
|
||||
|
||||
export function writeYaml(data: any, filename: string, noRefs = false) {
|
||||
const content = stringifyYaml(data, { noRefs });
|
||||
|
||||
@@ -220,6 +238,27 @@ export function writeYaml(data: any, filename: string, noRefs = false) {
|
||||
fs.writeFileSync(filename, content);
|
||||
}
|
||||
|
||||
export function writeJson(data: unknown, filename: string) {
|
||||
const content = JSON.stringify(data, null, 2);
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
process.stderr.write(content);
|
||||
return;
|
||||
}
|
||||
fs.mkdirSync(dirname(filename), { recursive: true });
|
||||
fs.writeFileSync(filename, content);
|
||||
}
|
||||
|
||||
export function getAndValidateFileExtension(fileName: string): NonNullable<OutputExtensions> {
|
||||
const ext = fileName.split('.').pop();
|
||||
|
||||
if (['yaml', 'yml', 'json'].includes(ext!)) {
|
||||
return ext as NonNullable<OutputExtensions>;
|
||||
}
|
||||
process.stderr.write(yellow(`Unsupported file extension: ${ext}. Using yaml.\n`));
|
||||
return 'yaml';
|
||||
}
|
||||
|
||||
export function pluralize(label: string, num: number) {
|
||||
if (label.endsWith('is')) {
|
||||
[label] = label.split(' ');
|
||||
|
||||
Reference in New Issue
Block a user