Skip to content

Commit

Permalink
refactor: requested changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleh Shumov committed Dec 2, 2024
1 parent e2a0948 commit 87bdd5e
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 60 deletions.
Empty file.
62 changes: 33 additions & 29 deletions documentation/commands/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Manage your API definition (e.g., syncing, validation, analysis, conversion, etc
* [`rdme openapi:convert [SPEC]`](#rdme-openapiconvert-spec)
* [`rdme openapi:inspect [SPEC]`](#rdme-openapiinspect-spec)
* [`rdme openapi:reduce [SPEC]`](#rdme-openapireduce-spec)
* [`rdme openapi:validate [SPEC]`](#rdme-openapivalidate-spec)
* [`rdme openapi:refs [SPEC]`](#rdme-openapirefs-spec)
* [`rdme openapi:validate [SPEC]`](#rdme-openapivalidate-spec)

## `rdme openapi [SPEC]`

Expand Down Expand Up @@ -227,70 +227,74 @@ EXAMPLES
$ rdme openapi:reduce petstore.json --path /pet/{id} --method get --method put --out petstore.reduced.json
```

## `rdme openapi:validate [SPEC]`
## `rdme openapi:refs [SPEC]`

Validate your OpenAPI/Swagger definition.
Resolves circular and recursive references in OpenAPI by replacing them with object schemas.

```
USAGE
$ rdme openapi:validate [SPEC] [--github] [--workingDirectory <value>]
$ rdme openapi:refs [SPEC] [--out <value>] [--workingDirectory <value>]
ARGUMENTS
SPEC A file/URL to your API definition
FLAGS
--github Create a new GitHub Actions workflow for this command.
--out=<value> Output file path to write processed file to
--workingDirectory=<value> Working directory (for usage with relative external references)
DESCRIPTION
Validate your OpenAPI/Swagger definition.
Resolves circular and recursive references in OpenAPI by replacing them with object schemas.
Perform a local validation of your API definition (no ReadMe account required!), which can be useful when constructing
or editing your API definition.
This command addresses limitations in ReadMe’s support for circular or recursive references within OpenAPI
specifications. It automatically identifies and replaces these references with simplified object schemas, ensuring
compatibility for seamless display in the ReadMe platform. As a result, instead of displaying an empty form, as would
occur with schemas containing such references, you will receive a flattened representation of the object, showing what
the object can potentially contain, including references to itself. Complex circular references may require manual
inspection and may not be fully resolved.
EXAMPLES
This will validate the API definition at the given URL or path:
This will resolve circular and recursive references in the OpenAPI definition at the given file or URL:
$ rdme openapi:validate [url-or-local-path-to-file]
$ rdme openapi:refs [url-or-local-path-to-file]
You can omit the file name and `rdme` will scan your working directory (and any subdirectories) for OpenAPI/Swagger
files. This approach will provide you with CLI prompts, so we do not recommend this technique in CI environments.
You can omit the file name and `rdme` will scan your working directory (and any subdirectories) for OpenAPI files.
This approach will provide you with CLI prompts, so we do not recommend this technique in CI environments.
$ rdme openapi:validate
$ rdme openapi:refs
If you wish to automate this command, you can pass in CLI arguments to bypass the prompts:
$ rdme openapi:refs petstore.json -out petstore.openapi.json
```

## `rdme openapi:refs [SPEC]`
## `rdme openapi:validate [SPEC]`

Simplify Circular References in your OpenAPI definition
Validate your OpenAPI/Swagger definition.

```
USAGE
$ rdme openapi:refs [SPEC] [--out <value>] [--title <value>] [--workingDirectory <value>]
$ rdme openapi:validate [SPEC] [--github] [--workingDirectory <value>]
ARGUMENTS
SPEC A file/URL to your API definition
FLAGS
--out=<value> Output file path to write processed file to
--title=<value> An override value for the `info.title` field in the API definition
--github Create a new GitHub Actions workflow for this command.
--workingDirectory=<value> Working directory (for usage with relative external references)
DESCRIPTION
Simplify Circular References in your OpenAPI definition
Validate your OpenAPI/Swagger definition.
This command addresses limitations in ReadMe’s support for circular or recursive references within OpenAPI specifications. It automatically identifies and replaces these references with simplified object schemas, ensuring compatibility for seamless display in the ReadMe platform. As a result, instead of displaying an empty form, as would occur with schemas containing such references, you will receive a flattened representation of the object, showing what the object can potentially contain, including references to itself. Complex circular references may require manual inspection and may not be fully resolved.
Perform a local validation of your API definition (no ReadMe account required!), which can be useful when constructing
or editing your API definition.
EXAMPLES
This will resolve circular and recursive references in the OpenAPI definition at the given file or URL:
This will validate the API definition at the given URL or path:
$ rdme openapi:refs [url-or-local-path-to-file]
$ rdme openapi:validate [url-or-local-path-to-file]
You can omit the file name and `rdme` will scan your working directory (and any subdirectories) for OpenAPI
You can omit the file name and `rdme` will scan your working directory (and any subdirectories) for OpenAPI/Swagger
files. This approach will provide you with CLI prompts, so we do not recommend this technique in CI environments.
$ rdme openapi:refs
If you wish to automate this command, you can pass in CLI arguments to bypass the prompts:
$ rdme openapi:refs petstore.json --out petstore.reduced.json
```
$ rdme openapi:validate
```
63 changes: 34 additions & 29 deletions src/commands/openapi/refs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,43 @@ import prompts from 'prompts';

import analyzeOas from '../../lib/analyzeOas.js';
import BaseCommand from '../../lib/baseCommand.js';
import { titleFlag, workingDirectoryFlag } from '../../lib/flags.js';
import { workingDirectoryFlag } from '../../lib/flags.js';
import { warn, debug } from '../../lib/logger.js';
import prepareOas from '../../lib/prepareOas.js';
import promptTerminal from '../../lib/promptWrapper.js';
import { validateFilePath } from '../../lib/validatePromptInput.js';

type SchemaCollection = Record<string, IJsonSchema>;

export default class OpenAPISolvingCircularityAndRecursiveness extends BaseCommand<
typeof OpenAPISolvingCircularityAndRecursiveness
> {
export default class OpenAPIRefsCommand extends BaseCommand<typeof OpenAPIRefsCommand> {
static summary = 'Resolves circular and recursive references in OpenAPI by replacing them with object schemas.';

static description =
'Resolves circular and recursive references in OpenAPI by replacing them with object schemas. Not all circular references can be resolved automatically.';
'This command addresses limitations in ReadMe’s support for circular or recursive references within OpenAPI specifications. It automatically identifies and replaces these references with simplified object schemas, ensuring compatibility for seamless display in the ReadMe platform. As a result, instead of displaying an empty form, as would occur with schemas containing such references, you will receive a flattened representation of the object, showing what the object can potentially contain, including references to itself. Complex circular references may require manual inspection and may not be fully resolved.';

static args = {
spec: Args.string({ description: 'A file/URL to your API definition' }),
};

static examples = [
{
description:
'This will resolve circular and recursive references in the OpenAPI definition at the given file or URL:',
command: '<%= config.bin %> <%= command.id %> [url-or-local-path-to-file]',
},
{
description:
'You can omit the file name and `rdme` will scan your working directory (and any subdirectories) for OpenAPI files. This approach will provide you with CLI prompts, so we do not recommend this technique in CI environments.',
command: '<%= config.bin %> <%= command.id %>',
},
{
description: 'If you wish to automate this command, you can pass in CLI arguments to bypass the prompts:',
command: '<%= config.bin %> <%= command.id %> petstore.json -out petstore.openapi.json',
},
];

static flags = {
out: Flags.string({ description: 'Output file path to write processed file to' }),
title: titleFlag,
workingDirectory: workingDirectoryFlag,
};

Expand Down Expand Up @@ -85,22 +101,18 @@ export default class OpenAPISolvingCircularityAndRecursiveness extends BaseComma
if (schema.type === 'object' && schema.properties) {
for (const prop of Object.keys(schema.properties)) {
let property = JSON.parse(JSON.stringify(schema.properties[prop]));
property = OpenAPISolvingCircularityAndRecursiveness.replaceRefWithObjectProxySchemes(
property,
circularRefs,
schemaName,
);
property = OpenAPIRefsCommand.replaceRefWithObjectProxySchemes(property, circularRefs, schemaName);
schema.properties[prop] = property;

// Handle arrays with item references
if (property.type === 'array' && property.items) {
property.items = JSON.parse(JSON.stringify(property.items));
property.items = OpenAPISolvingCircularityAndRecursiveness.replaceRefWithObjectProxySchemes(
property.items = OpenAPIRefsCommand.replaceRefWithObjectProxySchemes(
property.items,
circularRefs,
schemaName,
);
OpenAPISolvingCircularityAndRecursiveness.replaceRefsInSchema(property.items, circularRefs, schemaName);
OpenAPIRefsCommand.replaceRefsInSchema(property.items, circularRefs, schemaName);
}
}
}
Expand All @@ -124,11 +136,7 @@ export default class OpenAPISolvingCircularityAndRecursiveness extends BaseComma
type: 'object',
properties: { ...schemas[originalSchemaName].properties },
} as IJsonSchema;
OpenAPISolvingCircularityAndRecursiveness.replaceRefsInSchema(
schemas[refSchemaName],
circularRefs,
refSchemaName,
);
OpenAPIRefsCommand.replaceRefsInSchema(schemas[refSchemaName], circularRefs, refSchemaName);
createdRefs.add(refSchemaName);
}
}
Expand Down Expand Up @@ -219,28 +227,28 @@ export default class OpenAPISolvingCircularityAndRecursiveness extends BaseComma
* @returns {Promise<void>}
*/
static async resolveCircularRefs(openApiData: OASDocument, schemas: SchemaCollection) {
const initialCircularRefs = await OpenAPISolvingCircularityAndRecursiveness.getCircularRefsFromOas(openApiData);
const initialCircularRefs = await OpenAPIRefsCommand.getCircularRefsFromOas(openApiData);

if (initialCircularRefs.length === 0) {
throw new Error('The file does not contain circular or recursive references.');
}

debug(`Found ${initialCircularRefs.length} circular references. Attempting resolution.`);

OpenAPISolvingCircularityAndRecursiveness.replaceCircularRefs(schemas, initialCircularRefs);
OpenAPIRefsCommand.replaceCircularRefs(schemas, initialCircularRefs);

let remainingCircularRefs = await OpenAPISolvingCircularityAndRecursiveness.getCircularRefsFromOas(openApiData);
let remainingCircularRefs = await OpenAPIRefsCommand.getCircularRefsFromOas(openApiData);
let iterationCount = 0;
const maxIterations = 8;

while (remainingCircularRefs.length > 0 && iterationCount < maxIterations) {
debug(
`Iteration ${iterationCount + 1}: Resolving ${remainingCircularRefs.length} remaining circular references.`,
);
OpenAPISolvingCircularityAndRecursiveness.replaceCircularRefs(schemas, remainingCircularRefs);
OpenAPIRefsCommand.replaceCircularRefs(schemas, remainingCircularRefs);

// eslint-disable-next-line no-await-in-loop
remainingCircularRefs = await OpenAPISolvingCircularityAndRecursiveness.getCircularRefsFromOas(openApiData);
remainingCircularRefs = await OpenAPIRefsCommand.getCircularRefsFromOas(openApiData);
iterationCount += 1;
}

Expand All @@ -258,10 +266,10 @@ export default class OpenAPISolvingCircularityAndRecursiveness extends BaseComma
debug(
`Object replacement iteration ${objectReplacementIterationCount + 1}: replacing remaining circular references.`,
);
OpenAPISolvingCircularityAndRecursiveness.replaceAllRefsWithObject(schemas, remainingCircularRefs);
OpenAPIRefsCommand.replaceAllRefsWithObject(schemas, remainingCircularRefs);

// eslint-disable-next-line no-await-in-loop
remainingCircularRefs = await OpenAPISolvingCircularityAndRecursiveness.getCircularRefsFromOas(openApiData);
remainingCircularRefs = await OpenAPIRefsCommand.getCircularRefsFromOas(openApiData);
debug(
`After iteration ${objectReplacementIterationCount + 1}, remaining circular references: ${remainingCircularRefs.length}`,
);
Expand Down Expand Up @@ -293,10 +301,7 @@ export default class OpenAPISolvingCircularityAndRecursiveness extends BaseComma
const openApiData = JSON.parse(preparedSpec);

try {
await OpenAPISolvingCircularityAndRecursiveness.resolveCircularRefs(
openApiData,
openApiData.components!.schemas!,
);
await OpenAPIRefsCommand.resolveCircularRefs(openApiData, openApiData.components!.schemas!);
} catch (err) {
this.debug(`${err.message}`);
throw err;
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import OpenAPIConvertCommand from './commands/openapi/convert.js';
import OpenAPICommand from './commands/openapi/index.js';
import OpenAPIInspectCommand from './commands/openapi/inspect.js';
import OpenAPIReduceCommand from './commands/openapi/reduce.js';
import OpenAPISolvingCircularityAndRecursiveness from './commands/openapi/refs.js';
import OpenAPIRefsCommand from './commands/openapi/refs.js';
import OpenAPIValidateCommand from './commands/openapi/validate.js';
import CreateVersionCommand from './commands/versions/create.js';
import DeleteVersionCommand from './commands/versions/delete.js';
Expand Down Expand Up @@ -45,8 +45,8 @@ export const COMMANDS = {
'openapi:convert': OpenAPIConvertCommand,
'openapi:inspect': OpenAPIInspectCommand,
'openapi:reduce': OpenAPIReduceCommand,
'openapi:refs': OpenAPIRefsCommand,
'openapi:validate': OpenAPIValidateCommand,
'openapi:refs': OpenAPISolvingCircularityAndRecursiveness,

whoami: WhoAmICommand,
};

0 comments on commit 87bdd5e

Please sign in to comment.