diff --git a/package.json b/package.json index 1b23f52..af08a45 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@samchon/openapi", - "version": "1.2.0", + "version": "1.2.1", "description": "OpenAPI definitions and converters for 'typia' and 'nestia'.", "main": "./lib/index.js", "module": "./lib/index.mjs", diff --git a/src/converters/OpenApiV3Downgrader.ts b/src/converters/OpenApiV3Downgrader.ts index fdb8697..3991901 100644 --- a/src/converters/OpenApiV3Downgrader.ts +++ b/src/converters/OpenApiV3Downgrader.ts @@ -208,31 +208,29 @@ export namespace OpenApiV3Downgrader { items: downgradeSchema(collection)(schema.items), }); else if (OpenApiTypeChecker.isTuple(schema)) - union.push({ + visit({ ...schema, - items: ((): OpenApiV3.IJsonSchema => { - if (schema.additionalItems === true) return {}; - const elements = [ + type: "array", + items: { + oneOf: [ ...schema.prefixItems, - ...(typeof schema.additionalItems === "object" - ? [downgradeSchema(collection)(schema.additionalItems)] + ...(typeof schema.additionalItems === "object" && + schema.additionalItems !== null + ? [schema.additionalItems] : []), - ]; - if (elements.length === 0) return {}; - return { - oneOf: elements.map(downgradeSchema(collection) as any), - }; - })(), - minItems: schema.prefixItems.length, + ], + }, + minItems: schema.minItems ?? schema.prefixItems.length, maxItems: - !!schema.additionalItems === true + schema.maxItems ?? + (schema.additionalItems === true ? undefined - : schema.prefixItems.length, + : schema.prefixItems.length), ...{ prefixItems: undefined, additionalItems: undefined, }, - }); + } satisfies OpenApi.IJsonSchema.IArray); else if (OpenApiTypeChecker.isObject(schema)) union.push({ ...schema, diff --git a/src/converters/SwaggerV2Downgrader.ts b/src/converters/SwaggerV2Downgrader.ts index 2dd08b5..ee4a380 100644 --- a/src/converters/SwaggerV2Downgrader.ts +++ b/src/converters/SwaggerV2Downgrader.ts @@ -228,34 +228,29 @@ export namespace SwaggerV2Downgrader { : undefined, }); else if (OpenApiTypeChecker.isTuple(schema)) - union.push({ + visit({ ...schema, - items: ((): SwaggerV2.IJsonSchema => { - if (schema.additionalItems === true) return {}; - const elements = [ + type: "array", + items: { + oneOf: [ ...schema.prefixItems, - ...(typeof schema.additionalItems === "object" - ? [downgradeSchema(collection)(schema.additionalItems)] + ...(typeof schema.additionalItems === "object" && + schema.additionalItems !== null + ? [schema.additionalItems] : []), - ]; - if (elements.length === 0) return {}; - return { - "x-oneOf": elements.map(downgradeSchema(collection) as any), - }; - })(), - minItems: schema.prefixItems.length, + ], + }, + minItems: schema.minItems ?? schema.prefixItems.length, maxItems: - !!schema.additionalItems === true + schema.maxItems ?? + (schema.additionalItems === true ? undefined - : schema.prefixItems.length, + : schema.prefixItems.length), ...{ prefixItems: undefined, additionalItems: undefined, }, - examples: schema.examples - ? Object.values(schema.examples) - : undefined, - }); + } satisfies OpenApi.IJsonSchema.IArray); else if (OpenApiTypeChecker.isObject(schema)) union.push({ ...schema, @@ -285,16 +280,18 @@ export namespace SwaggerV2Downgrader { const insert = (value: any): void => { const matched: SwaggerV2.IJsonSchema.INumber | undefined = union.find( (u) => - (u as SwaggerV2.IJsonSchema.__ISignificant).type === value, + (u as SwaggerV2.IJsonSchema.__ISignificant).type === + typeof value, ) as SwaggerV2.IJsonSchema.INumber | undefined; if (matched !== undefined) { matched.enum ??= []; matched.enum.push(value); } else union.push({ type: typeof value as "number", enum: [value] }); - if (OpenApiTypeChecker.isConstant(schema)) insert(schema.const); - else if (OpenApiTypeChecker.isOneOf(schema)) - schema.oneOf.forEach(insert); }; + if (OpenApiTypeChecker.isConstant(schema)) insert(schema.const); + else if (OpenApiTypeChecker.isOneOf(schema)) + for (const u of schema.oneOf) + if (OpenApiTypeChecker.isConstant(u)) insert(u.const); }; visit(input); diff --git a/test/features/openapi/test_json_schema_downgrade_v20_tuple.ts b/test/features/openapi/test_json_schema_downgrade_v20_tuple.ts new file mode 100644 index 0000000..6d945ba --- /dev/null +++ b/test/features/openapi/test_json_schema_downgrade_v20_tuple.ts @@ -0,0 +1,35 @@ +import { TestValidator } from "@nestia/e2e"; +import { SwaggerV2Downgrader } from "@samchon/openapi/lib/converters/SwaggerV2Downgrader"; +import typia from "typia"; + +export const test_json_schema_downgrade_v20_tuple = (): void => { + const collection = typia.json.application<[[false, 1, 2, "three", null]]>(); + const schema = SwaggerV2Downgrader.downgradeSchema({ + original: collection.components, + downgraded: {}, + })(collection.schemas[0]); + TestValidator.equals("tuple")(schema)({ + type: "array", + items: { + "x-oneOf": [ + { + type: "boolean", + enum: [false], + "x-nullable": true, + }, + { + type: "number", + enum: [1, 2], + "x-nullable": true, + }, + { + type: "string", + enum: ["three"], + "x-nullable": true, + }, + ], + }, + minItems: 5, + maxItems: 5, + }); +}; diff --git a/test/features/openapi/test_json_schema_downgrade_v30_tuple.ts b/test/features/openapi/test_json_schema_downgrade_v30_tuple.ts new file mode 100644 index 0000000..fc0bff9 --- /dev/null +++ b/test/features/openapi/test_json_schema_downgrade_v30_tuple.ts @@ -0,0 +1,35 @@ +import { TestValidator } from "@nestia/e2e"; +import { OpenApiV3Downgrader } from "@samchon/openapi/lib/converters/OpenApiV3Downgrader"; +import typia from "typia"; + +export const test_json_schema_downgrade_v30_tuple = (): void => { + const collection = typia.json.application<[[false, 1, 2, "three", null]]>(); + const schema = OpenApiV3Downgrader.downgradeSchema({ + original: collection.components, + downgraded: {}, + })(collection.schemas[0]); + TestValidator.equals("tuple")(schema)({ + type: "array", + items: { + oneOf: [ + { + type: "boolean", + enum: [false], + nullable: true, + }, + { + type: "number", + enum: [1, 2], + nullable: true, + }, + { + type: "string", + enum: ["three"], + nullable: true, + }, + ], + }, + minItems: 5, + maxItems: 5, + }); +};