diff --git a/src/scripts/import-open-api.ts b/src/scripts/import-open-api.ts index 7888fe88..df23a3e6 100644 --- a/src/scripts/import-open-api.ts +++ b/src/scripts/import-open-api.ts @@ -38,6 +38,8 @@ export const isReference = (property: any): property is ReferenceObject => { * @ref https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types */ export const getScalar = (item: SchemaObject) => { + const nullable = item.nullable ? " | null" : ""; + switch (item.type) { case "int32": case "int64": @@ -46,30 +48,26 @@ export const getScalar = (item: SchemaObject) => { case "long": case "float": case "double": - return "number"; + return "number" + nullable; case "boolean": - return "boolean"; + return "boolean" + nullable; case "array": - return getArray(item); - - case "object": - return getObject(item); + return getArray(item) + nullable; case "string": - return item.enum ? `"${item.enum.join(`" | "`)}"` : "string"; - case "byte": case "binary": case "date": case "dateTime": case "date-time": case "password": - return "string"; + return (item.enum ? `"${item.enum.join(`" | "`)}"` : "string") + nullable; + case "object": default: - return getObject(item); + return getObject(item) + nullable; } }; @@ -436,7 +434,11 @@ export const generateSchemasDefinition = (schemas: ComponentsObject["schemas"] = return ( Object.entries(schemas) .map(([name, schema]) => - (!schema.type || schema.type === "object") && !schema.allOf && !schema.oneOf && !isReference(schema) + (!schema.type || schema.type === "object") && + !schema.allOf && + !schema.oneOf && + !isReference(schema) && + !schema.nullable ? generateInterface(name, schema) : `export type ${pascal(name)} = ${resolveValue(schema)};`, ) diff --git a/src/scripts/tests/import-open-api.test.ts b/src/scripts/tests/import-open-api.test.ts index 8eb85594..eaeed765 100644 --- a/src/scripts/tests/import-open-api.test.ts +++ b/src/scripts/tests/import-open-api.test.ts @@ -69,6 +69,11 @@ describe("scripts/import-open-api", () => { { item: { type: "password" }, expected: "string" }, { item: { type: "string", enum: ["foo", "bar"] }, expected: `"foo" | "bar"` }, { item: { type: "customType" }, expected: "any" }, + { item: { type: "integer", nullable: true }, expected: "number | null" }, + { item: { type: "boolean", nullable: true }, expected: "boolean | null" }, + { item: { type: "string", nullable: true }, expected: "string | null" }, + { item: { type: "object", nullable: true }, expected: "{} | null" }, + { item: { type: "object", $ref: "#/components/schemas/Foo", nullable: true }, expected: "Foo | null" }, ].map(({ item, expected }) => it(`should return ${expected} as type for ${item.type}`, () => { expect(getScalar(item)).toEqual(expected); @@ -283,6 +288,24 @@ describe("scripts/import-open-api", () => { expect(generateSchemasDefinition(schema)).toContain(`export interface NewPet {name: string; tag?: string}`); }); + it("should declare an interface for simple object (nullable)", () => { + const schema = { + NewPet: { + required: ["name"], + nullable: true, + properties: { + name: { + type: "string", + }, + tag: { + type: "string", + }, + }, + }, + }; + expect(generateSchemasDefinition(schema)).toContain(`export type NewPet = {name: string; tag?: string} | null`); + }); + it("should declare a type for union object", () => { const schema = { Pet: { @@ -317,6 +340,17 @@ describe("scripts/import-open-api", () => { expect(generateSchemasDefinition(schema)).toContain(`export type PetName = string;`); }); + it("should declare a type for all others types (nullable)", () => { + const schema = { + PetName: { + type: "string", + nullable: true, + }, + }; + + expect(generateSchemasDefinition(schema)).toContain(`export type PetName = string | null;`); + }); + it("should deal with aliases", () => { const schema = { Wolf: {