From a7d3010c3dc10b378787f513026fdcbaec86284a Mon Sep 17 00:00:00 2001 From: David Biesack Date: Mon, 20 Nov 2023 11:12:01 -0500 Subject: [PATCH 1/4] add conversion of $comment to x-command in schemas --- README.md | 31 +++++++++++++++- src/converter.ts | 16 ++++++++ test/converter.spec.ts | 84 ++++++++++++++++++++++++++++++++++++++++++ test/data/openapi.yaml | 9 +++++ 4 files changed, 139 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af1311b..3753663 100644 --- a/README.md +++ b/README.md @@ -302,6 +302,36 @@ be possible (`properties`, `allOf` etc.) (Contributions welcome.) +### Rename `$comment` + +JSON Schema supports a `$comment` value for adding comments to schemas. +Some JSon shcema tools fail on this keyword. The tool replaces `$comment` with `x-comment`; +those tools that fail on `$comment` are more forgiving of `x-comment` keywords. + +```yaml + resourceTitle: + title: Resource Title + description: A Title for a business object + type: string + maxLength: 80 + $comment: >- + this maxLength must match the maxLength of + `title` in the `resourcePatch` schema. +``` + +becomes + +```yaml + resourceTitle: + title: Resource Title + description: A Title for a business object + type: string + maxLength: 80 + x-comment: >- + this maxLength must match the maxLength of + `title` in the `resourcePatch` schema. +``` + ### Remove `unevaluatedProperties` The tool removes the `unevaluatedProperties` value, introduced in later @@ -326,7 +356,6 @@ becomes title: My Response description: Response from an API operation type: object - unevaluatedProperties: false allOf: ... ``` diff --git a/src/converter.ts b/src/converter.ts index 4fe9198..375e52b 100644 --- a/src/converter.ts +++ b/src/converter.ts @@ -120,6 +120,7 @@ export class Converter { this.convertConstToEnum(); this.convertNullableTypeArray(); this.removeUnsupportedSchemaKeywords(); + this.renameSchema$comment(); return this.openapi30; } @@ -224,6 +225,21 @@ export class Converter { visitSchemaObjects(this.openapi30, schemaVisitor); } + renameSchema$comment() { + 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 json(x) { return JSON.stringify(x, null, 2); } diff --git a/test/converter.spec.ts b/test/converter.spec.ts index 4ccbf85..957322f 100644 --- a/test/converter.spec.ts +++ b/test/converter.spec.ts @@ -332,6 +332,90 @@ describe('resolver test suite', () => { done(); }); + test('Remove $id and $schema keywords', (done) => { + // const sourceFileName = path.join(__dirname, 'data/root.yaml'); // __dirname is the test dir + const input = { + openapi: '3.1.0', + components: { + schemas: { + a: { + $id: 'http://www.example.com/schemas/a', + $schema: 'https://json-schema.org/draft/2020-12/schema', + type: 'string', + }, + }, + }, + }; + const expected = { + openapi: '3.0.3', + components: { + schemas: { + a: { + type: 'string', + }, + }, + }, + }; + const converter = new Converter(input, { verbose: true }); + const converted: any = converter.convert(); + expect(converted).toEqual(expected); + done(); + }); + + test('Rename $comment to x-comment', (done) => { + const input = { + openapi: '3.1.0', + components: { + schemas: { + a: { + type: 'object', + $comment: 'a comment on schema a', + properties: { + b: { + type: 'object', + $comment: 'A comment on a.b', + properties: { + s: { + type: 'string', + $comment: 'A comment on a.b.s', + }, + }, + }, + }, + }, + }, + }, + }; + const expected = { + openapi: '3.0.3', + components: { + schemas: { + a: { + type: 'object', + 'x-comment': 'a comment on schema a', + properties: { + b: { + type: 'object', + + 'x-comment': 'A comment on a.b', + properties: { + s: { + type: 'string', + 'x-comment': 'A comment on a.b.s', + }, + }, + }, + }, + }, + }, + }, + }; + const converter = new Converter(input, { verbose: true }); + const converted: any = converter.convert(); + expect(converted).toEqual(expected); + done(); + }); + test('Convert nullable type array', (done) => { // const sourceFileName = path.join(__dirname, 'data/root.yaml'); // __dirname is the test dir const input = { diff --git a/test/data/openapi.yaml b/test/data/openapi.yaml index 44771fb..913a772 100644 --- a/test/data/openapi.yaml +++ b/test/data/openapi.yaml @@ -427,3 +427,12 @@ components: format: date-time readOnly: true example: '2021-10-30T19:06:04.250Z' + + resourceTitle: + title: Resource Title + description: A Title for a business object + type: string + maxLength: 80 + x-comment: >- + this maxLength must match the maxLength of + `title` in the `resourcePatch` schema. From 5371ef6552e75c2c7dd97562487ae5f9e629e1a7 Mon Sep 17 00:00:00 2001 From: David Biesack Date: Mon, 20 Nov 2023 11:12:50 -0500 Subject: [PATCH 2/4] increment npm package version --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d75b242..f10f379 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@apiture/openapi-down-convert", - "version": "0.8.0", + "version": "0.9.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 076079a..31cc22e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@apiture/openapi-down-convert", - "version": "0.8.0", + "version": "0.9.0", "description": "Tool to down convert OpenAPI 3.1 to OpenAPI 3.0", "main": "lib/src/index.js", "bin": { From b1daa8f8f44ed53468a647f0c82b71afdbe46bd8 Mon Sep 17 00:00:00 2001 From: David Biesack Date: Mon, 20 Nov 2023 13:20:25 -0500 Subject: [PATCH 3/4] update README for $comment conversion --- README.md | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/README.md b/README.md index 3753663..af1311b 100644 --- a/README.md +++ b/README.md @@ -302,36 +302,6 @@ be possible (`properties`, `allOf` etc.) (Contributions welcome.) -### Rename `$comment` - -JSON Schema supports a `$comment` value for adding comments to schemas. -Some JSon shcema tools fail on this keyword. The tool replaces `$comment` with `x-comment`; -those tools that fail on `$comment` are more forgiving of `x-comment` keywords. - -```yaml - resourceTitle: - title: Resource Title - description: A Title for a business object - type: string - maxLength: 80 - $comment: >- - this maxLength must match the maxLength of - `title` in the `resourcePatch` schema. -``` - -becomes - -```yaml - resourceTitle: - title: Resource Title - description: A Title for a business object - type: string - maxLength: 80 - x-comment: >- - this maxLength must match the maxLength of - `title` in the `resourcePatch` schema. -``` - ### Remove `unevaluatedProperties` The tool removes the `unevaluatedProperties` value, introduced in later @@ -356,6 +326,7 @@ becomes title: My Response description: Response from an API operation type: object + unevaluatedProperties: false allOf: ... ``` From 9e255117b1887ccd79624a91e1eb67a36c2de6de Mon Sep 17 00:00:00 2001 From: David Biesack Date: Mon, 20 Nov 2023 13:29:39 -0500 Subject: [PATCH 4/4] simplify schema $comment -> x-comment --- src/converter.ts | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/converter.ts b/src/converter.ts index 5df9aeb..94597f1 100644 --- a/src/converter.ts +++ b/src/converter.ts @@ -170,23 +170,15 @@ export class Converter { * Replace all `$comment` with `x-comment` */ convertJsonSchemaComments() { - const schemaVisitor: SchemaVisitor = (schema: SchemaObject): SchemaObject => { - for (const key in schema) { - const subSchema = schema[key]; - if (subSchema !== null && typeof subSchema === 'object') { - if (key === '$comment') { - const comment = schema['$comment']; - if (comment.length > 0) { - delete schema['$comment']; - schema['x-comment'] = comment; - this.log(`Replaces $comment with x-comment. Comment:\n${comment}`); - } - } else { - schema[key] = walkObject(subSchema, schemaVisitor); - } - } + 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 schema; + return this.walkNestedSchemaObjects(schema, schemaVisitor); }; visitSchemaObjects(this.openapi30, schemaVisitor); }