Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@apiture/openapi-down-convert

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@apiture/openapi-down-convert - npm Package Compare versions

Comparing version 0.9.0 to 0.10.0

2

lib/package.json
{
"name": "@apiture/openapi-down-convert",
"version": "0.9.0",
"version": "0.10.0",
"description": "Tool to down convert OpenAPI 3.1 to OpenAPI 3.0",

@@ -5,0 +5,0 @@ "main": "lib/src/index.js",

@@ -24,2 +24,3 @@ #!/usr/bin/env node

.option('-v, --verbose', 'Verbose output')
.option('--convert-schema-comments', 'Convert $comment to x-comment instead of deleting $comment values')
.parse(args);

@@ -37,2 +38,3 @@ const opts = cli.opts();

scopeDescriptionFile: opts.scopes,
convertSchemaComments: opts.convertSchemaComments,
};

@@ -39,0 +41,0 @@ const converter = new converter_1.Converter(source, cOpts);

@@ -8,2 +8,3 @@ export interface ConverterOptions {

scopeDescriptionFile?: string;
convertSchemaComments?: boolean;
}

@@ -18,2 +19,4 @@ export declare class Converter {

private scopeDescriptions;
private convertSchemaComments;
private returnCode;
constructor(openapiDocument: object, options?: ConverterOptions);

@@ -23,5 +26,5 @@ private loadScopeDescriptions;

private warn;
private error;
convert(): object;
convertJsonSchemaExamples(): void;
convertJsonSchemaComments(): void;
private walkNestedSchemaObjects;

@@ -32,2 +35,5 @@ convertConstToEnum(): void;

renameSchema$comment(): void;
private deleteSchema$comment;
convertJsonSchemaContentMediaType(): void;
convertJsonSchemaContentEncoding(): void;
private json;

@@ -34,0 +40,0 @@ convertSecuritySchemes(): void;

@@ -14,2 +14,4 @@ "use strict";

this.scopeDescriptions = undefined;
this.convertSchemaComments = false;
this.returnCode = 0;
this.openapi30 = Converter.deepClone(openapiDocument);

@@ -22,2 +24,3 @@ this.verbose = Boolean(options === null || options === void 0 ? void 0 : options.verbose);

this.loadScopeDescriptions(options === null || options === void 0 ? void 0 : options.scopeDescriptionFile);
this.convertSchemaComments = options === null || options === void 0 ? void 0 : options.convertSchemaComments;
}

@@ -41,2 +44,9 @@ loadScopeDescriptions(scopeDescriptionFile) {

}
error(...message) {
if (!message[0].startsWith('Error')) {
message[0] = `Error: ${message[0]}`;
}
this.returnCode++;
console.error(...message);
}
convert() {

@@ -52,7 +62,16 @@ this.log('Converting from OpenAPI 3.1 to 3.0');

this.convertJsonSchemaExamples();
this.convertJsonSchemaComments();
this.convertJsonSchemaContentEncoding();
this.convertJsonSchemaContentMediaType();
this.convertConstToEnum();
this.convertNullableTypeArray();
this.removeUnsupportedSchemaKeywords();
this.renameSchema$comment();
if (this.convertSchemaComments) {
this.renameSchema$comment();
}
else {
this.deleteSchema$comment();
}
if (this.returnCode > 0) {
throw new Error('Cannot down convert this OpenAPI definition.');
}
return this.openapi30;

@@ -91,13 +110,2 @@ }

}
convertJsonSchemaComments() {
const schemaVisitor = (schema) => {
if (schema.hasOwnProperty('$comment')) {
schema['x-comment'] = schema['$comment'];
delete schema['$comment'];
this.log(`schema $comment renamed to x-comment`);
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
(0, RefVisitor_1.visitSchemaObjects)(this.openapi30, schemaVisitor);
}
walkNestedSchemaObjects(schema, schemaVisitor) {

@@ -163,2 +171,65 @@ for (const key in schema) {

}
deleteSchema$comment() {
const schemaVisitor = (schema) => {
if (schema.hasOwnProperty('$comment')) {
const comment = schema['$comment'];
delete schema['$comment'];
this.log(`schema $comment deleted: ${comment}`);
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
(0, RefVisitor_1.visitSchemaObjects)(this.openapi30, schemaVisitor);
}
convertJsonSchemaContentMediaType() {
const schemaVisitor = (schema) => {
if (schema.hasOwnProperty('type') &&
schema['type'] === 'string' &&
schema.hasOwnProperty('contentMediaType') &&
schema['contentMediaType'] === 'application/octet-stream') {
if (schema.hasOwnProperty('format')) {
if (schema['format'] === 'binary') {
this.log(`Deleted schema contentMediaType: application/octet-stream (leaving format: binary)`);
delete schema['contentMediaType'];
}
else {
this.error(`Unable to down-convert schema with contentMediaType: application/octet-stream to format: binary because the schema already has a format (${schema['format']})`);
}
}
else {
delete schema['contentMediaType'];
schema['format'] = 'binary';
this.log(`Converted schema contentMediaType: application/octet-stream to format: binary`);
}
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
(0, RefVisitor_1.visitSchemaObjects)(this.openapi30, schemaVisitor);
}
convertJsonSchemaContentEncoding() {
const schemaVisitor = (schema) => {
if (schema.hasOwnProperty('type') && schema['type'] === 'string' && schema.hasOwnProperty('contentEncoding')) {
if (schema['contentEncoding'] === 'base64') {
if (schema.hasOwnProperty('format')) {
if (schema['format'] === 'byte') {
this.log(`Deleted schema contentEncoding: base64 (leaving format: byte)`);
delete schema['contentEncoding'];
}
else {
this.error(`Unable to down-convert schema contentEncoding: base64 to format: byte because the schema already has a format (${schema['format']})`);
}
}
else {
delete schema['contentEncoding'];
schema['format'] = 'byte';
this.log(`Converted schema: 'contentEncoding: base64' to 'format: byte'`);
}
}
else {
this.error(`Unable to down-convert contentEncoding: ${schema['contentEncoding']}`);
}
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
(0, RefVisitor_1.visitSchemaObjects)(this.openapi30, schemaVisitor);
}
json(x) {

@@ -165,0 +236,0 @@ return JSON.stringify(x, null, 2);

@@ -21,3 +21,4 @@ "use strict";

const schema = schemas[schemaName];
schemas[schemaName] = schemaCallback(schema);
const newSchema = schemaCallback(schema);
schemas[schemaName] = newSchema;
}

@@ -24,0 +25,0 @@ }

{
"name": "@apiture/openapi-down-convert",
"version": "0.9.0",
"version": "0.10.0",
"description": "Tool to down convert OpenAPI 3.1 to OpenAPI 3.0",

@@ -5,0 +5,0 @@ "main": "lib/src/index.js",

@@ -75,2 +75,7 @@ # OpenAPI Down Convert

--oidc-to-oath2 <scopes> Convert openIdConnect security to oath2.
--convertJsonComments If used, convert `$comment` in JSON schemas
to `x-comment`. If omitted, delete
all `$comment` in JSON schemas.
(Use `--verbose` to log deletion
to stdout)
-s, --scopes <scopes> If set, this JSON/YAML file describes the OpenID scopes.

@@ -83,4 +88,10 @@ This is an alias for --oidc-to-oath2

The verbose mode logs the changes to standard error output stream.
The verbose mode logs all changes to standard error output stream.
The tool returns a 0 status code upon success or a non-zero status code
if it finds constructs that cannot be down-converted, such as
using `contentMediaType: application/octet-stream` with a `format`
other than `binary`, or if a schema has `contentEncoding: base64`
and has an existing `format` that is not already `base64`.
The tool only supports local file-based documents, not URLs.

@@ -175,4 +186,4 @@ Download such files to convert:

**Note** This transformation is disabled by default because it breaks `openapi-generator` 5.4 in
cases where the referenced schema is an array.
**Note** This transformation is disabled by default because it breaks
`openapi-generator` 5.4 in cases where the referenced schema is an array.
It generates Typescript types for such cases as

@@ -229,3 +240,3 @@

becomes
becomes

@@ -242,3 +253,3 @@ ```yaml

### Convert type arrays to nullable
### &DownArrowBar; Convert type arrays to nullable

@@ -310,7 +321,7 @@ If a schema has a type array of exactly two values, and one of them

### Remove `unevaluatedProperties`
### &DownArrowBar; Remove `unevaluatedProperties`
The tool removes the `unevaluatedProperties` value, introduced in later
versions of JSON Schema,
as this is not supported in OAS 3.0 JSON Schema Draft 4
as this is not supported in JSON Schema Draft 4
used in OAS 3.0.

@@ -340,10 +351,23 @@

### Rename `$comment` as `x-comment`
The tool removes any `$id` or `$schema` keywords that may appear
inside schema objects.
The tool renames the `$comment` keyword in schema objects as `x-comment`
as `$comment` is not supported in OAS 3.0 JSON Schema Draft 4
used in OAS 3.0. and can cause problems with some tools.
`x-comment` is more easily ignored since it does not start with `$`.
### &DownArrowBar; Convert `$comment` to `x-comment`
For exmample,
JSON Schema introduced `$comment` in schemas in 2020-12.
Since OAS 3.0 uses JSON Schema Draft 4, and some tools
will flag `$comment` as invalid, this tool removes these comments.
An earlier version of the tool converted `$comment` to `x-comment`
However, other tools which do not allow `$comment` may not not support
`x-comment` either.
Use the `--convert-schema-comments` CLI option or set
`convertSchemaComments` to `true`
in the `Converter` constructor options
to requst conversion of
`$comment` to `x-comment` rather than deleting `$comment`.
For example,
```yaml

@@ -375,14 +399,68 @@ Problems:

### Remove schema `$id` and `$schema`
### Convert `contentEncoding: base64` to `format: byte`
The tool removes any `$id` or `$schema` keywords that may appear
inside schema objects.
JSON Schema Draft 7 and later uses `contentEncoding` to specify
[the encoding of non-JSON string content]
(https://json-schema.org/understanding-json-schema/reference/non_json_data).
Draft 4 supports `format: byte` for `Base64` encoded strings.
This tool converts `type: string` schemas as follows:
<!-- markdownlint-disable MD033 -->
<table>
<tr>
<th>OAS 3.1 schema</th>
<th>OAS 3.0 schema</th>
</tr>
2
<tr>
<td>
<pre>
type: string
contentEncoding: base64
</pre>
</td>
<td>
<pre>
type: string
format: byte
</pre>
</td>
</tr>
<tr>
<td>
<pre>
type: string
contentMediaType: 'application/octet-stream'
</pre>
</td>
<td>
<pre>
type: string
format: binary
</pre>
</td>
</tr>
</table>
## Unsupported down conversions
Currently, the tool does not support the following situations.
Contributions welcome!
* `openapi-down-convert` does not convert `exclusiveMinimum` and `exclusiveMaximum`
as defined in JSON Schema 2012-12; these handled differently in JSON Schema Draft 4
used in OAS 3.0. Contributions welcome!
* Webhooks are not addressed. Contributions welcome!
as defined in JSON Schema 2012-12; these handled differently in JSON Schema Draft 4
used in OAS 3.0.
* Webhooks are not addressed.
* The tool only supports self-contained documents. It does not follow or resolve
external `$ref` documents embedded in the source document.
external `$ref` documents embedded in the source document.
* Request body and response body `content` object transformations, such as
reversing `content: { 'application/octet-stream': {} }` as
described in [Migrating from OpenAPI 3.0 to 3.1.0](https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0)
* Converting other `contentEncoding` values (`7bit`, `8bit`, `binary`,
`quoted-printable`, `base16`, `base32`) (Note: `contentEncoding: base64` is supported by
converting to `format: byte` as listed above.)
* Converting `contentMediaType: 'type/subtype` to `media: { type: 'type/subtype'}` for non-JSON data.

@@ -28,2 +28,3 @@ #!/usr/bin/env node

.option('-v, --verbose', 'Verbose output')
.option('--convert-schema-comments', 'Convert $comment to x-comment instead of deleting $comment values')
.parse(args);

@@ -41,2 +42,3 @@ const opts = cli.opts();

scopeDescriptionFile: opts.scopes,
convertSchemaComments: opts.convertSchemaComments,
};

@@ -43,0 +45,0 @@ const converter = new Converter(source, cOpts);

@@ -48,2 +48,8 @@ import * as v8 from 'v8';

scopeDescriptionFile?: string;
/** Earlier versions of the tool converted $comment to x-comment
* in JSON Schemas. The tool now deletes $comment values by default.
* Use this option to preserve the conversion and not delete
* comments.
*/
convertSchemaComments?: boolean;
}

@@ -60,2 +66,4 @@

private scopeDescriptions = undefined;
private convertSchemaComments = false;
private returnCode = 0;

@@ -74,2 +82,3 @@ /**

this.loadScopeDescriptions(options?.scopeDescriptionFile);
this.convertSchemaComments = options?.convertSchemaComments;
}

@@ -110,2 +119,16 @@

/**
* Log an error message to `console.error` stream. Prefix the message string with `Error: `
* if it does not already start with `'Error'`. Increments the `returnCode`, causing
* the CLI to throw an Error when done.
* @param message parameters for `console.error`
*/
private error(...message) {
if (!message[0].startsWith('Error')) {
message[0] = `Error: ${message[0]}`;
}
this.returnCode++;
console.error(...message);
}
/**
* Convert the OpenAPI document to 3.0

@@ -124,7 +147,15 @@ * @returns the converted document. The input is not modified.

this.convertJsonSchemaExamples();
this.convertJsonSchemaComments();
this.convertJsonSchemaContentEncoding();
this.convertJsonSchemaContentMediaType();
this.convertConstToEnum();
this.convertNullableTypeArray();
this.removeUnsupportedSchemaKeywords();
this.renameSchema$comment();
if (this.convertSchemaComments) {
this.renameSchema$comment();
} else {
this.deleteSchema$comment();
}
if (this.returnCode > 0) {
throw new Error('Cannot down convert this OpenAPI definition.');
}
return this.openapi30;

@@ -172,21 +203,2 @@ }

/**
* OpenAPI 3.1 uses JSON Schema 2020-12 which allows schema `$comment`;
* OpenAPI 3.0 uses JSON Scheme Draft 7 does not allow it.
* Replace all `$comment` with `x-comment`
*/
convertJsonSchemaComments() {
const schemaVisitor: SchemaVisitor =
(schema: SchemaObject): SchemaObject =>
{
if (schema.hasOwnProperty('$comment')) {
schema['x-comment'] = schema['$comment'];
delete schema['$comment'];
this.log(`schema $comment renamed to x-comment`);
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
visitSchemaObjects(this.openapi30, schemaVisitor);
}
private walkNestedSchemaObjects(schema, schemaVisitor) {

@@ -255,5 +267,3 @@ for (const key in schema) {

renameSchema$comment() {
const schemaVisitor: SchemaVisitor =
(schema: SchemaObject): SchemaObject =>
{
const schemaVisitor: SchemaVisitor = (schema: SchemaObject): SchemaObject => {
if (schema.hasOwnProperty('$comment')) {

@@ -269,3 +279,93 @@ schema['x-comment'] = schema['$comment'];

private deleteSchema$comment() {
const schemaVisitor: SchemaVisitor = (schema: SchemaObject): SchemaObject => {
if (schema.hasOwnProperty('$comment')) {
const comment = schema['$comment'];
delete schema['$comment'];
this.log(`schema $comment deleted: ${comment}`);
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
visitSchemaObjects(this.openapi30, schemaVisitor);
}
/**
* Convert
* ```
* contentMediaType: 'application/octet-stream'
* ```
* to
* ```
* format: binary
* ```
* in `type: string` schemas.
* Warn if schema has a `format` already and it is not `binary`.
*/
convertJsonSchemaContentMediaType() {
const schemaVisitor: SchemaVisitor = (schema: SchemaObject): SchemaObject => {
if (
schema.hasOwnProperty('type') &&
schema['type'] === 'string' &&
schema.hasOwnProperty('contentMediaType') &&
schema['contentMediaType'] === 'application/octet-stream'
) {
if (schema.hasOwnProperty('format')) {
if (schema['format'] === 'binary') {
this.log(`Deleted schema contentMediaType: application/octet-stream (leaving format: binary)`);
delete schema['contentMediaType'];
} else {
this.error(
`Unable to down-convert schema with contentMediaType: application/octet-stream to format: binary because the schema already has a format (${schema['format']})`,
);
}
} else {
delete schema['contentMediaType'];
schema['format'] = 'binary';
this.log(`Converted schema contentMediaType: application/octet-stream to format: binary`);
}
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
visitSchemaObjects(this.openapi30, schemaVisitor);
}
/**
* Convert
* ```
* contentEncoding: base64
* ```
* to
* ```
* format: byte
* ```
* in `type: string` schemas. It is an error if the schema has a `format` already
* and it is not `byte`.
*/
convertJsonSchemaContentEncoding() {
const schemaVisitor: SchemaVisitor = (schema: SchemaObject): SchemaObject => {
if (schema.hasOwnProperty('type') && schema['type'] === 'string' && schema.hasOwnProperty('contentEncoding')) {
if (schema['contentEncoding'] === 'base64') {
if (schema.hasOwnProperty('format')) {
if (schema['format'] === 'byte') {
this.log(`Deleted schema contentEncoding: base64 (leaving format: byte)`);
delete schema['contentEncoding'];
} else {
this.error(
`Unable to down-convert schema contentEncoding: base64 to format: byte because the schema already has a format (${schema['format']})`,
);
}
} else {
delete schema['contentEncoding'];
schema['format'] = 'byte';
this.log(`Converted schema: 'contentEncoding: base64' to 'format: byte'`);
}
} else {
this.error(`Unable to down-convert contentEncoding: ${schema['contentEncoding']}`);
}
}
return this.walkNestedSchemaObjects(schema, schemaVisitor);
};
visitSchemaObjects(this.openapi30, schemaVisitor);
}
private json(x) {

@@ -272,0 +372,0 @@ return JSON.stringify(x, null, 2);

@@ -65,3 +65,4 @@ /* eslint-disable @typescript-eslint/no-explicit-any */

const schema = schemas[schemaName];
schemas[schemaName] = schemaCallback(schema);
const newSchema = schemaCallback(schema);
schemas[schemaName] = newSchema;
}

@@ -68,0 +69,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc