mirror of
https://github.com/LukeHagar/redocly-cli.git
synced 2025-12-09 20:57:44 +00:00
feat: configurable filename separator for split command (#610)
* Make file path separator configurable in split command * chore: add tests for the file name separator * chore: update snapshots * docs: split separator option description * chore: code style fixes
This commit is contained in:
committed by
GitHub
parent
3e8b08449d
commit
1f10c7cd77
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,5 +7,6 @@ coverage/
|
||||
yarn.lock
|
||||
dist/
|
||||
lib/
|
||||
output/
|
||||
*.tar.gz
|
||||
*.tsbuildinfo
|
||||
|
||||
@@ -10,9 +10,10 @@ Positionals:
|
||||
entrypoint API definition file that you want to split [string] [required]
|
||||
|
||||
Options:
|
||||
--version Show version number. [boolean]
|
||||
--help Show help. [boolean]
|
||||
--outDir Output directory where files will be saved. [string] [required]
|
||||
--version Show version number. [boolean]
|
||||
--help Show help. [boolean]
|
||||
--outDir Output directory where files will be saved. [string] [required]
|
||||
--separator File path separator used while splitting. [string] [default: "_"]
|
||||
|
||||
Missing required argument: outDir
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ paths:
|
||||
/pets:
|
||||
$ref: paths/pets.yaml
|
||||
/pets/{petId}:
|
||||
$ref: paths/pets@{petId}.yaml
|
||||
$ref: paths/pets_{petId}.yaml
|
||||
🪓 Document: ../../../__tests__/split/oas3-no-errors/openapi.yaml is successfully split
|
||||
and all related files are saved to the directory: output
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ Option | Type | Required | Default | Description
|
||||
--------------------------|:---------:|:------------:|:-----------:|------------
|
||||
`entrypoint` | `string` | yes | - | Path to the API definition file that you want to split into a multi-file structure
|
||||
`--outDir` | `string` | yes | - | Path to the directory where you want to save split files. If the specified directory doesn't exist, it will be created automatically.
|
||||
`separator` | `string` | no | `_` | File path separator used while splitting. Will affect file names in the `paths` folder (e.g. `user_create.yaml`)
|
||||
`--help` | `boolean` | no | - | Show help
|
||||
`--version` | `boolean` | no | - | Show version number
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isSubdir } from '../utils';
|
||||
import { isSubdir, pathToFilename } from '../utils';
|
||||
|
||||
jest.mock("os");
|
||||
|
||||
@@ -40,3 +40,11 @@ describe('isSubdir', () => {
|
||||
jest.resetModules()
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
describe('pathToFilename', () => {
|
||||
it('should use correct path separator', () => {
|
||||
const processedPath = pathToFilename('/user/createWithList', '_');
|
||||
expect(processedPath).toEqual('user_createWithList');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,6 +28,7 @@ describe('#split', () => {
|
||||
{
|
||||
entrypoint: filePath,
|
||||
outDir: openapiDir,
|
||||
separator: '_',
|
||||
}
|
||||
);
|
||||
|
||||
@@ -41,12 +42,31 @@ describe('#split', () => {
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('should use the correct separator', async () => {
|
||||
const filePath = "./packages/cli/src/commands/split/__tests__/fixtures/spec.json";
|
||||
|
||||
const utils = require('../../../utils');
|
||||
jest.spyOn(utils, 'pathToFilename').mockImplementation(() => 'newFilePath');
|
||||
|
||||
await handleSplit (
|
||||
{
|
||||
entrypoint: filePath,
|
||||
outDir: openapiDir,
|
||||
separator: '_',
|
||||
}
|
||||
);
|
||||
|
||||
expect(utils.pathToFilename).toBeCalledWith(expect.anything(), '_');
|
||||
utils.pathToFilename.mockRestore();
|
||||
});
|
||||
|
||||
it('should have correct path with paths', () => {
|
||||
const openapi = require("./fixtures/spec.json");
|
||||
|
||||
jest.spyOn(openapiCore, 'slash').mockImplementation(() => 'paths/test.yaml');
|
||||
jest.spyOn(path, 'relative').mockImplementation(() => 'paths/test.yaml');
|
||||
iteratePathItems(openapi.paths, openapiDir, path.join(openapiDir, 'paths'), componentsFiles);
|
||||
iteratePathItems(openapi.paths, openapiDir, path.join(openapiDir, 'paths'), componentsFiles, '_');
|
||||
|
||||
expect(openapiCore.slash).toHaveBeenCalledWith('paths/test.yaml');
|
||||
expect(path.relative).toHaveBeenCalledWith('test', 'test/paths/test.yaml');
|
||||
|
||||
@@ -29,12 +29,13 @@ import {
|
||||
export async function handleSplit (argv: {
|
||||
entrypoint: string;
|
||||
outDir: string
|
||||
separator: string
|
||||
}) {
|
||||
const startedAt = performance.now();
|
||||
const { entrypoint, outDir } = argv;
|
||||
const { entrypoint, outDir, separator } = argv;
|
||||
validateDefinitionFileName(entrypoint!);
|
||||
const openapi = readYaml(entrypoint!) as Oas3Definition | Oas3_1Definition;
|
||||
splitDefinition(openapi, outDir);
|
||||
splitDefinition(openapi, outDir, separator);
|
||||
process.stderr.write(
|
||||
`🪓 Document: ${blue(entrypoint!)} ${green('is successfully split')}
|
||||
and all related files are saved to the directory: ${blue(outDir)} \n`,
|
||||
@@ -42,15 +43,15 @@ export async function handleSplit (argv: {
|
||||
printExecutionTime('split', startedAt, entrypoint!);
|
||||
}
|
||||
|
||||
function splitDefinition(openapi: Oas3Definition | Oas3_1Definition, openapiDir: string) {
|
||||
function splitDefinition(openapi: Oas3Definition | Oas3_1Definition, openapiDir: string, pathSeparator: string) {
|
||||
fs.mkdirSync(openapiDir, { recursive: true });
|
||||
|
||||
const componentsFiles: ComponentsFiles = {};
|
||||
iterateComponents(openapi, openapiDir, componentsFiles);
|
||||
iteratePathItems(openapi.paths, openapiDir, path.join(openapiDir, 'paths'), componentsFiles);
|
||||
iteratePathItems(openapi.paths, openapiDir, path.join(openapiDir, 'paths'), componentsFiles, pathSeparator);
|
||||
const webhooks = (openapi as Oas3_1Definition).webhooks || (openapi as Oas3Definition)['x-webhooks'];
|
||||
// use webhook_ prefix for code samples to prevent potential name-clashes with paths samples
|
||||
iteratePathItems(webhooks, openapiDir, path.join(openapiDir, 'webhooks'), componentsFiles, 'webhook_');
|
||||
iteratePathItems(webhooks, openapiDir, path.join(openapiDir, 'webhooks'), componentsFiles, pathSeparator, 'webhook_');
|
||||
|
||||
replace$Refs(openapi, openapiDir, componentsFiles);
|
||||
writeYaml(openapi, path.join(openapiDir, 'openapi.yaml'));
|
||||
@@ -247,13 +248,14 @@ function iteratePathItems(
|
||||
openapiDir: string,
|
||||
outDir: string,
|
||||
componentsFiles: object,
|
||||
pathSeparator: string,
|
||||
codeSamplesPathPrefix: string = '',
|
||||
) {
|
||||
if (!pathItems) return;
|
||||
fs.mkdirSync(outDir, { recursive: true });
|
||||
|
||||
for (const pathName of Object.keys(pathItems)) {
|
||||
const pathFile = `${path.join(outDir, pathToFilename(pathName))}.yaml`;
|
||||
const pathFile = `${path.join(outDir, pathToFilename(pathName, pathSeparator))}.yaml`;
|
||||
const pathData = pathItems[pathName] as Oas3PathItem;
|
||||
|
||||
if (isRef(pathData)) continue;
|
||||
@@ -270,7 +272,7 @@ function iteratePathItems(
|
||||
openapiDir,
|
||||
'code_samples',
|
||||
sample.lang,
|
||||
codeSamplesPathPrefix + pathToFilename(pathName),
|
||||
codeSamplesPathPrefix + pathToFilename(pathName, pathSeparator),
|
||||
method + langToExt(sample.lang),
|
||||
);
|
||||
|
||||
|
||||
@@ -46,6 +46,12 @@ yargs
|
||||
required: true,
|
||||
type: 'string',
|
||||
},
|
||||
separator: {
|
||||
description: 'File path separator used while splitting.',
|
||||
required: false,
|
||||
type: 'string',
|
||||
default: '_',
|
||||
},
|
||||
})
|
||||
.demandOption('entrypoint'),
|
||||
handleSplit,
|
||||
|
||||
@@ -66,12 +66,12 @@ export function printExecutionTime(commandName: string, startedAt: number, entry
|
||||
process.stderr.write(gray(`\n${entrypoint}: ${commandName} processed in ${elapsed}\n\n`));
|
||||
}
|
||||
|
||||
export function pathToFilename(path: string) {
|
||||
export function pathToFilename(path: string, pathSeparator: string) {
|
||||
return path
|
||||
.replace(/~1/g, '/')
|
||||
.replace(/~0/g, '~')
|
||||
.replace(/^\//, '')
|
||||
.replace(/\//g, '@');
|
||||
.replace(/\//g, pathSeparator);
|
||||
}
|
||||
|
||||
export class CircularJSONNotSupportedError extends Error {
|
||||
|
||||
Reference in New Issue
Block a user