From 00652a8f381f065a45cf8204294306fb4c772f6f Mon Sep 17 00:00:00 2001 From: Jianye Xi <59603451+jianyexi@users.noreply.github.com> Date: Tue, 10 Jan 2023 13:19:23 +0800 Subject: [PATCH] fix rule index & support additionalProperties:true (#263) * fix rule index * fix additional properties boolean * add removed test * fix test * fix test * fix test Co-authored-by: jianyexi --- docs/README.md | 8 ++- package-lock.json | 4 +- package.json | 2 +- src/lib/util/resolveSwagger.ts | 57 +++++++++++++++++++++ src/test/additional-properties/new.json | 67 +++++++++++++++++++++++++ src/test/additional-properties/old.json | 67 +++++++++++++++++++++++++ src/test/test.ts | 63 +++++++++++++++++++++++ 7 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 src/test/additional-properties/new.json create mode 100644 src/test/additional-properties/old.json diff --git a/docs/README.md b/docs/README.md index 1f017ad6..3f2f953a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -90,4 +90,10 @@ [1045 - AddedOptionalProperty](rules/1045.md) -[1046 - RemovedOptionalParameter](rules/1046.md) \ No newline at end of file +[1046 - RemovedOptionalParameter](rules/1046.md) + +[1047 - XmsEnumChanged](rules/1047.md) + +[1048 - AddedXmsEnum](rules/1048.md) + +[1049 - RemovedXmsEnum](rules/1049.md) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 230a5e82..323d1268 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@azure/oad", - "version": "0.9.5", + "version": "0.10.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@azure/oad", - "version": "0.9.5", + "version": "0.10.4", "license": "MIT", "dependencies": { "@ts-common/fs": "^0.2.0", diff --git a/package.json b/package.json index 80bcf2c7..0d22cc07 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@azure/oad", - "version": "0.10.3", + "version": "0.10.4", "author": { "name": "Microsoft Corporation", "email": "azsdkteam@microsoft.com", diff --git a/src/lib/util/resolveSwagger.ts b/src/lib/util/resolveSwagger.ts index a65e89ac..bdf07b1b 100644 --- a/src/lib/util/resolveSwagger.ts +++ b/src/lib/util/resolveSwagger.ts @@ -102,6 +102,7 @@ export class ResolveSwagger { this.unifyXMsPaths() this.ConvertPathLevelParameter() this.ExpandDefinitions() + this.ConvertAdditionalProperty() this.generateNew() return this.innerSwagger } @@ -145,6 +146,62 @@ export class ResolveSwagger { } } } + + public ConvertAdditionalProperty() { + if (!this.innerSwagger) { + throw new Error("Null swagger object") + } + const swagger = this.innerSwagger as any + const paths = swagger.paths + if (paths && paths instanceof Object && toArray(sm.keys(paths)).length > 0) { + for (const v of sm.values(paths)) { + for (const [key, o] of sm.entries(v as any)) { + if (key.toLowerCase() !== "parameters") { + const operationParam = (o as any).parameters ? (o as any).parameters : [] + operationParam.forEach((v: any) => v.schema && this.transformAdditionalProperty(v.schema)) + const responses = (o as any).responses ? sm.values((o as any).responses) : [] + responses.forEach((v: any) => v.schema && this.transformAdditionalProperty(v.schema)) + } else { + sm.values(o as any).forEach((v: any) => v.schema && this.transformAdditionalProperty(v.schema)) + } + } + } + } + if (swagger.definitions) { + for (const o of sm.values(swagger.definitions)) { + this.transformAdditionalProperty(o) + } + } + if (swagger.parameters) { + for (const o of sm.values(swagger.parameters)) { + if ((o as any).schema) { + this.transformAdditionalProperty((o as any).schema) + } + } + } + } + + private transformAdditionalProperty(schema: any) { + if (typeof schema?.additionalProperties === "boolean") { + if (!schema?.additionalProperties) { + delete schema.additionalProperties + } else { + schema.additionalProperties = {} + } + } + if (schema.properties) { + for (const v of sm.values(schema.properties)) { + this.transformAdditionalProperty(v) + } + } + + if (schema.allOf) { + for (const v of sm.values(schema.allOf)) { + this.transformAdditionalProperty(v) + } + } + } + private ExpandDefinitions() { if (!this.innerSwagger) { throw new Error("Null swagger object") diff --git a/src/test/additional-properties/new.json b/src/test/additional-properties/new.json new file mode 100644 index 00000000..6840d737 --- /dev/null +++ b/src/test/additional-properties/new.json @@ -0,0 +1,67 @@ +{ + "swagger": "2.0", + "info": { + "title": "common_parameter_check_04", + "version": "1.0" + }, + "parameters": { + "P0": { + "name": "p0", + "in": "query", + "type": "string" + }, + "P2": { + "name": "p2", + "in": "body", + "schema": { + "type": "object", + "additionalProperties": true + } + } + }, + "host": "localhost:8000", + "schemes": [ "http", "https" ], + "paths": { + "/api/Operations": { + "parameters": [ + { + "$ref": "#/parameters/P0" + }, + { + "$ref": "#/parameters/P2" + } + ], + "get": { + "operationId": "Operations_Get", + "produces": [ + "text/plain" + ], + "responses": { + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "additionalProperties": true + } + }, + "200": { + "description": "operation successfully .", + "schema": { + "$ref":"#/definitions/Foo" + } + } + } + } + } + }, + "definitions": { + "Foo": { + "type":"object", + "properties": { + "bar": { + "type":"object", + "additionalProperties":true + } + } + } + } +} diff --git a/src/test/additional-properties/old.json b/src/test/additional-properties/old.json new file mode 100644 index 00000000..75567d83 --- /dev/null +++ b/src/test/additional-properties/old.json @@ -0,0 +1,67 @@ +{ + "swagger": "2.0", + "info": { + "title": "common_parameter_check_04", + "version": "1.0" + }, + "parameters": { + "P0": { + "name": "p0", + "in": "query", + "type": "string" + }, + "P2": { + "name": "p2", + "in": "body", + "schema": { + "type": "object", + "additionalProperties": false + } + } + }, + "host": "localhost:8000", + "schemes": [ "http", "https" ], + "paths": { + "/api/Operations": { + "parameters": [ + { + "$ref": "#/parameters/P0" + }, + { + "$ref": "#/parameters/P2" + } + ], + "get": { + "operationId": "Operations_Get", + "produces": [ + "text/plain" + ], + "responses": { + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "additionalProperties": true + } + }, + "200": { + "description": "operation successfully .", + "schema": { + "$ref":"#/definitions/Foo" + } + } + } + } + } + }, + "definitions": { + "Foo": { + "type":"object", + "properties": { + "bar": { + "type":"object", + "additionalProperties":true + } + } + } + } +} diff --git a/src/test/test.ts b/src/test/test.ts index 18bf4139..8b542529 100644 --- a/src/test/test.ts +++ b/src/test/test.ts @@ -732,4 +732,67 @@ describe("index", () => { ] assert.deepStrictEqual(result, expected) }) + + it("Additional Properties is boolean", async () => { + const diff = new index.OpenApiDiff({}) + const oldFile = "src/test/additional-properties/old.json" + const newFile = "src/test/additional-properties/new.json" + const resultStr = await diff.compare(oldFile, newFile) + const result = JSON.parse(resultStr) + const newFilePath = fileUrl(path.resolve(newFile)) + const oldFilePath = fileUrl(path.resolve(oldFile)) + const expected = [ + { + id: "1001", + code: "NoVersionChange", + message: "The versions have not changed.", + old: { + ref: `${oldFilePath}#`, + path: "", + location: `${oldFilePath}:1:1` + }, + new: { + ref: `${newFilePath}#`, + path: "", + location: `${newFilePath}:1:1` + }, + type: "Info", + docUrl: "https://github.com/Azure/openapi-diff/tree/master/docs/rules/1001.md", + mode: "Update" + }, + { + code: "AddedAdditionalProperties", + docUrl: "https://github.com/Azure/openapi-diff/tree/master/docs/rules/1021.md", + id: "1021", + message: "The new version adds an 'additionalProperties' element.", + mode: "Addition", + new: { + location: ``, + path: "paths./api/Operations.get.parameters", + ref: `` + }, + old: {}, + type: "Error" + }, + { + code: "AddedAdditionalProperties", + docUrl: "https://github.com/Azure/openapi-diff/tree/master/docs/rules/1021.md", + id: "1021", + message: "The new version adds an 'additionalProperties' element.", + mode: "Addition", + new: { + location: `${newFilePath}:16:7`, + path: "parameters.P2.schema", + ref: `${newFilePath}#/parameters/P2/schema` + }, + old: { + location: `${oldFilePath}:16:7`, + path: "parameters.P2.schema", + ref: `${oldFilePath}#/parameters/P2/schema` + }, + type: "Error" + } + ] + assert.deepStrictEqual(result, expected) + }) })