From b989c29d9bb66b8975ec92cec366e7095d92a304 Mon Sep 17 00:00:00 2001
From: Evgenii Fedoseev <zorox112@yandex-team.ru>
Date: Wed, 1 Mar 2023 00:07:41 +0300
Subject: [PATCH] fix(includers/openapi): add default type for enum

---
 .../includers/batteries/openapi/constants.ts  |  4 +++
 .../batteries/openapi/generators/traverse.ts  | 29 +++++++++++++++----
 .../includers/batteries/openapi/types.ts      |  6 +++-
 3 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/src/services/includers/batteries/openapi/constants.ts b/src/services/includers/batteries/openapi/constants.ts
index d1ab64333..625426b1c 100644
--- a/src/services/includers/batteries/openapi/constants.ts
+++ b/src/services/includers/batteries/openapi/constants.ts
@@ -20,6 +20,8 @@ const SPEC_RENDER_MODE_HIDDEN = 'hidden';
 const SPEC_SECTION_NAME = 'Specification';
 const SPEC_SECTION_TYPE = 'Open API';
 
+const SUPPORTED_ENUM_TYPES = ['string', 'number'] as const;
+
 export {
     TAG_NAMES_FIELD,
     BLOCK,
@@ -42,6 +44,7 @@ export {
     SPEC_RENDER_MODE_HIDDEN,
     SPEC_SECTION_NAME,
     SPEC_SECTION_TYPE,
+    SUPPORTED_ENUM_TYPES,
 };
 
 export default {
@@ -66,4 +69,5 @@ export default {
     SPEC_RENDER_MODE_HIDDEN,
     SPEC_SECTION_NAME,
     SPEC_SECTION_TYPE,
+    SUPPORTED_ENUM_TYPES,
 };
diff --git a/src/services/includers/batteries/openapi/generators/traverse.ts b/src/services/includers/batteries/openapi/generators/traverse.ts
index 84141d269..dc2c9af7b 100644
--- a/src/services/includers/batteries/openapi/generators/traverse.ts
+++ b/src/services/includers/batteries/openapi/generators/traverse.ts
@@ -1,8 +1,9 @@
-import {Refs} from '../types';
+import {JsType, Refs, SupportedEnumType} from '../types';
 import {JSONSchema6} from 'json-schema';
 import {table} from './common';
 import slugify from 'slugify';
 import {concatNewLine} from '../../common';
+import {SUPPORTED_ENUM_TYPES} from '../constants';
 
 type TableRow = [string, string, string];
 
@@ -20,7 +21,7 @@ export function tableFromSchema(allRefs: Refs, schema: JSONSchema6): {content: s
         const description = prepareComplexDescription('', schema);
         const content = table([
             ['Type', 'Description'],
-            [schema.type, description],
+            [inferType(schema), description],
         ]);
         return {content, tableRefs: []};
     }
@@ -64,7 +65,7 @@ export function prepareTableRowData(allRefs: Refs, value: JSONSchema6, key?: str
     if (ref) {
         return {type: anchor(ref), description, ref};
     }
-    if (value.type === 'array') {
+    if (inferType(value) === 'array') {
         if (!value.items || value.items === true || Array.isArray(value.items)) {
             throw Error(`unsupported array items for ${key}`);
         }
@@ -76,7 +77,7 @@ export function prepareTableRowData(allRefs: Refs, value: JSONSchema6, key?: str
             ref: inner.ref,
         };
     }
-    return {type: `${value.type}`, description: prepareComplexDescription(description, value)};
+    return {type: `${inferType(value)}`, description: prepareComplexDescription(description, value)};
 }
 
 function prepareComplexDescription(baseDescription: string, value: JSONSchema6): string {
@@ -144,7 +145,7 @@ function prepareSampleElement(key: string, v: OpenJSONSchemaDefinition, required
         return undefined;
     }
     const downCallstack = callstack.concat(value);
-    switch (value.type) {
+    switch (inferType(value)) {
         case 'object':
             return prepareSampleObject(value, downCallstack);
         case 'array':
@@ -234,3 +235,21 @@ function merge(value: OpenJSONSchemaDefinition): OpenJSONSchema {
 function isRequired(key: string, value: JSONSchema6): boolean {
     return value.required?.includes(key) ?? false;
 }
+
+function inferType(value: OpenJSONSchema): Exclude<JSONSchema6['type'], undefined> {
+    if (value.type) {
+        return value.type;
+    }
+    if (value.enum) {
+        const enumType = typeof value.enum[0];
+        if (isSupportedEnumType(enumType)) {
+            return enumType;
+        }
+        throw new Error('Unsupported enum type');
+    }
+    throw new Error('Unsupported value type');
+}
+
+function isSupportedEnumType(enumType: JsType): enumType is SupportedEnumType {
+    return SUPPORTED_ENUM_TYPES.some((type) => enumType === type);
+}
diff --git a/src/services/includers/batteries/openapi/types.ts b/src/services/includers/batteries/openapi/types.ts
index a6f7692b2..1dfb5d42e 100644
--- a/src/services/includers/batteries/openapi/types.ts
+++ b/src/services/includers/batteries/openapi/types.ts
@@ -1,6 +1,6 @@
 import {JSONSchema6} from 'json-schema';
 
-import {SPEC_RENDER_MODE_DEFAULT, SPEC_RENDER_MODE_HIDDEN} from './constants';
+import {SPEC_RENDER_MODE_DEFAULT, SPEC_RENDER_MODE_HIDDEN, SUPPORTED_ENUM_TYPES} from './constants';
 
 export const titleDepths = [1, 2, 3, 4, 5, 6] as const;
 
@@ -146,3 +146,7 @@ export type Schema = {
 export type Refs = { [typeName: string]: JSONSchema6 };
 
 export type LeadingPageSpecRenderMode = typeof SPEC_RENDER_MODE_DEFAULT | typeof SPEC_RENDER_MODE_HIDDEN;
+
+export type JsType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function';
+
+export type SupportedEnumType = typeof SUPPORTED_ENUM_TYPES[number];