From 46a457e0ccc654001658bdc705232970d749f263 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 16 Jul 2024 11:49:48 +0200 Subject: [PATCH] [OAS] Better support for enums (#188198) Close https://github.com/elastic/kibana/issues/182658 --- oas_docs/bundle.json | 184 ++++-------------- oas_docs/bundle.serverless.json | 184 ++++-------------- .../post_process_mutations/index.ts | 3 +- .../mutations/enum.test.ts | 117 +++++++++++ .../post_process_mutations/mutations/enum.ts | 26 +++ .../post_process_mutations/mutations/index.ts | 2 + 6 files changed, 227 insertions(+), 289 deletions(-) create mode 100644 packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.test.ts create mode 100644 packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.ts diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index 1dfcdd50639b3..5ccacb4c8acfb 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -12,33 +12,14 @@ "additionalProperties": false, "properties": { "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" } }, "required": [ @@ -129,33 +110,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -186,33 +148,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -250,33 +193,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -308,33 +232,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -376,21 +281,12 @@ "type": "string" }, "build_flavor": { - "anyOf": [ - { - "enum": [ - "serverless" - ], - "type": "string" - }, - { - "enum": [ - "traditional" - ], - "type": "string" - } + "description": "The build flavour determines configuration and behavior of Kibana. On premise users will almost always run the \"traditional\" flavour, while other flavours are reserved for Elastic-specific use cases.", + "enum": [ + "serverless", + "traditional" ], - "description": "The build flavour determines configuration and behavior of Kibana. On premise users will almost always run the \"traditional\" flavour, while other flavours are reserved for Elastic-specific use cases." + "type": "string" }, "build_hash": { "description": "A unique hash value representing the git commit of this Kibana build.", diff --git a/oas_docs/bundle.serverless.json b/oas_docs/bundle.serverless.json index 1dfcdd50639b3..5ccacb4c8acfb 100644 --- a/oas_docs/bundle.serverless.json +++ b/oas_docs/bundle.serverless.json @@ -12,33 +12,14 @@ "additionalProperties": false, "properties": { "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" } }, "required": [ @@ -129,33 +110,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -186,33 +148,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -250,33 +193,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -308,33 +232,14 @@ "type": "string" }, "level": { - "anyOf": [ - { - "enum": [ - "available" - ], - "type": "string" - }, - { - "enum": [ - "degraded" - ], - "type": "string" - }, - { - "enum": [ - "unavailable" - ], - "type": "string" - }, - { - "enum": [ - "critical" - ], - "type": "string" - } + "description": "Service status levels as human and machine readable values.", + "enum": [ + "available", + "degraded", + "unavailable", + "critical" ], - "description": "Service status levels as human and machine readable values." + "type": "string" }, "meta": { "additionalProperties": {}, @@ -376,21 +281,12 @@ "type": "string" }, "build_flavor": { - "anyOf": [ - { - "enum": [ - "serverless" - ], - "type": "string" - }, - { - "enum": [ - "traditional" - ], - "type": "string" - } + "description": "The build flavour determines configuration and behavior of Kibana. On premise users will almost always run the \"traditional\" flavour, while other flavours are reserved for Elastic-specific use cases.", + "enum": [ + "serverless", + "traditional" ], - "description": "The build flavour determines configuration and behavior of Kibana. On premise users will almost always run the \"traditional\" flavour, while other flavours are reserved for Elastic-specific use cases." + "type": "string" }, "build_hash": { "description": "A unique hash value representing the git commit of this Kibana build.", diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts index 7d693f085ef17..f1d0c90de1d0f 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts @@ -60,9 +60,10 @@ const walkSchema = (ctx: IContext, schema: Schema): void => { } else { for (const arrayContainer of arrayContainers) { if (schema[arrayContainer]) { - schema[arrayContainer].forEach((s: OpenAPIV3.SchemaObject, idx: number) => { + schema[arrayContainer].forEach((s: OpenAPIV3.SchemaObject) => { walkSchema(ctx, s); }); + mutations.processEnum(schema); break; } } diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.test.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.test.ts new file mode 100644 index 0000000000000..5c783e739d045 --- /dev/null +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { OpenAPIV3 } from 'openapi-types'; +import { processEnum } from './enum'; + +describe('processEnum', () => { + it.each([ + { + name: 'when there is no anyOf property does not change input', + input: {} as OpenAPIV3.SchemaObject, + expected: {}, + }, + { + name: 'converts anyOf to enum if all items are enum and of the same type', + input: { + anyOf: [ + { + type: 'string', + enum: ['a', 'b'], + }, + { + type: 'string', + enum: ['c', 'd'], + }, + { + type: 'string', + enum: ['e'], + }, + ], + description: 'description', + } as OpenAPIV3.SchemaObject, + expected: { + type: 'string', + enum: ['a', 'b', 'c', 'd', 'e'], + description: 'description', + }, + }, + { + name: 'does not change input if item types are different', + input: { + anyOf: [ + { + type: 'string', + enum: ['a'], + }, + { + type: 'number', + enum: [1], + }, + ], + } as OpenAPIV3.SchemaObject, + expected: { + anyOf: [ + { + type: 'string', + enum: ['a'], + }, + { + type: 'number', + enum: [1], + }, + ], + }, + }, + { + name: 'if anyOf contains a ref does not change input', + input: { + anyOf: [ + { + $ref: '#/components/schemas/Ref', + }, + { + type: 'string', + enum: ['a'], + }, + ], + } as OpenAPIV3.SchemaObject, + expected: { + anyOf: [ + { + $ref: '#/components/schemas/Ref', + }, + { + type: 'string', + enum: ['a'], + }, + ], + }, + }, + { + name: 'if anyOf contains non-enums does not change input', + input: { + anyOf: [ + { + type: 'object', + }, + ], + } as OpenAPIV3.SchemaObject, + expected: { + anyOf: [ + { + type: 'object', + }, + ], + }, + }, + ])('$name', ({ input, expected }) => { + processEnum(input); + expect(input).toEqual(expected); + }); +}); diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.ts new file mode 100644 index 0000000000000..7bbb7ae2c26d0 --- /dev/null +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/enum.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { OpenAPIV3 } from 'openapi-types'; +import { isReferenceObject } from '../../../common'; + +export const processEnum = (schema: OpenAPIV3.SchemaObject) => { + if (!schema.anyOf) return; + const result: unknown[] = []; + let type: OpenAPIV3.SchemaObject['type']; + for (const item of schema.anyOf!) { + if (isReferenceObject(item) || !item.enum || !item.type) return; + if (type && type !== item.type) return; + + type = item.type; + result.push(...item.enum); + } + schema.type = type; + schema.enum = result; + delete schema.anyOf; +}; diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts index 0dd6cb5dc2f84..e3887717769ac 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts @@ -68,3 +68,5 @@ export const processAnyType = (schema: OpenAPIV3.SchemaObject): void => { }; export { processObject } from './object'; + +export { processEnum } from './enum';