UNPKG

@alexop/openapi-zod-client

Version:

[![Screenshot 2022-11-12 at 18 52 25](https://user-images.githubusercontent.com/47224540/201487856-ffc4c862-6f31-4de1-8ef1-3981fabf3416.png)](https://openapi-zod-client.vercel.app/)

354 lines (345 loc) 10.7 kB
import SwaggerParser from "@apidevtools/swagger-parser"; import type { OpenAPIObject, SchemaObject } from "openapi3-ts"; import { get } from "pastable/server"; import { expect, test } from "vitest"; import { getOpenApiDependencyGraph } from "./getOpenApiDependencyGraph"; import { topologicalSort } from "./topologicalSort"; import { asComponentSchema } from "./utils"; test("petstore.yaml", async () => { const openApiDoc = (await SwaggerParser.parse("./tests/petstore.yaml")) as OpenAPIObject; const getSchemaByRef = (ref: string) => get(openApiDoc, ref.replace("#/", "").replaceAll("/", ".")) as SchemaObject; const { refsDependencyGraph: result, deepDependencyGraph } = getOpenApiDependencyGraph( Object.keys(openApiDoc.components?.schemas || {}).map((name) => asComponentSchema(name)), getSchemaByRef ); expect(result).toMatchInlineSnapshot(` { "#/components/schemas/Customer": Set { "#/components/schemas/Address", }, "#/components/schemas/Pet": Set { "#/components/schemas/Category", "#/components/schemas/Tag", }, } `); expect(topologicalSort(result)).toMatchInlineSnapshot(` [ "#/components/schemas/Address", "#/components/schemas/Customer", "#/components/schemas/Category", "#/components/schemas/Tag", "#/components/schemas/Pet", ] `); expect(deepDependencyGraph).toMatchInlineSnapshot(` { "#/components/schemas/Customer": Set { "#/components/schemas/Address", }, "#/components/schemas/Pet": Set { "#/components/schemas/Category", "#/components/schemas/Tag", }, } `); expect(topologicalSort(deepDependencyGraph)).toMatchInlineSnapshot(` [ "#/components/schemas/Address", "#/components/schemas/Customer", "#/components/schemas/Category", "#/components/schemas/Tag", "#/components/schemas/Pet", ] `); }); test("complex relations", () => { const schemas = { Basic: { type: "object", properties: { prop: { type: "string" }, second: { type: "number" } } }, WithNested: { type: "object", properties: { nested: { type: "string" }, nestedRef: { $ref: "DeepNested" } } }, ObjectWithArrayOfRef: { type: "object", properties: { exampleProp: { type: "string" }, another: { type: "number" }, link: { type: "array", items: { $ref: "WithNested" } }, someReference: { $ref: "Basic" }, }, }, DeepNested: { type: "object", properties: { deep: { type: "boolean" } } }, Root: { type: "object", properties: { str: { type: "string" }, reference: { $ref: "ObjectWithArrayOfRef", }, inline: { type: "object", properties: { nested_prop: { type: "boolean" }, }, }, another: { $ref: "WithNested" }, basic: { $ref: "Basic" }, differentPropSameRef: { $ref: "Basic" }, }, }, } as Record<string, SchemaObject>; const getSchemaByRef = (ref: string) => schemas[ref]!; const { refsDependencyGraph: result, deepDependencyGraph } = getOpenApiDependencyGraph( Object.keys(schemas), getSchemaByRef ); expect(result).toMatchInlineSnapshot(` { "ObjectWithArrayOfRef": Set { "WithNested", "Basic", }, "Root": Set { "ObjectWithArrayOfRef", "WithNested", "Basic", }, "WithNested": Set { "DeepNested", }, } `); expect(topologicalSort(result)).toMatchInlineSnapshot(` [ "DeepNested", "WithNested", "Basic", "ObjectWithArrayOfRef", "Root", ] `); expect(deepDependencyGraph).toMatchInlineSnapshot(` { "ObjectWithArrayOfRef": Set { "WithNested", "DeepNested", "Basic", }, "Root": Set { "ObjectWithArrayOfRef", "WithNested", "DeepNested", "Basic", }, "WithNested": Set { "DeepNested", }, } `); expect(topologicalSort(deepDependencyGraph)).toMatchInlineSnapshot(` [ "DeepNested", "WithNested", "Basic", "ObjectWithArrayOfRef", "Root", ] `); }); test("recursive relations", () => { const UserWithFriends = { type: "object", properties: { name: { type: "string" }, parent: { $ref: "UserWithFriends" }, friends: { type: "array", items: { $ref: "Friend" } }, bestFriend: { $ref: "Friend" }, }, } as SchemaObject; const Friend = { type: "object", properties: { nickname: { type: "string" }, user: { $ref: "UserWithFriends" }, circle: { type: "array", items: { $ref: "Friend" } }, }, } as SchemaObject; const schemas = { UserWithFriends, Friend } as Record<string, SchemaObject>; const getSchemaByRef = (ref: string) => schemas[ref]!; const { refsDependencyGraph: result, deepDependencyGraph } = getOpenApiDependencyGraph( Object.keys(schemas), getSchemaByRef ); expect(result).toMatchInlineSnapshot(` { "Friend": Set { "UserWithFriends", "Friend", }, "UserWithFriends": Set { "UserWithFriends", "Friend", }, } `); expect(topologicalSort(result)).toMatchInlineSnapshot(` [ "Friend", "UserWithFriends", ] `); expect(deepDependencyGraph).toMatchInlineSnapshot(` { "Friend": Set { "UserWithFriends", "Friend", }, "UserWithFriends": Set { "UserWithFriends", "Friend", }, } `); expect(topologicalSort(deepDependencyGraph)).toMatchInlineSnapshot(` [ "Friend", "UserWithFriends", ] `); }); test("recursive relations along with some basics schemas", () => { const schemas = { UserWithFriends: { type: "object", properties: { name: { type: "string" }, parent: { $ref: "UserWithFriends" }, friends: { type: "array", items: { $ref: "Friend" } }, bestFriend: { $ref: "Friend" }, withNested: { $ref: "WithNested" }, }, }, Friend: { type: "object", properties: { nickname: { type: "string" }, user: { $ref: "UserWithFriends" }, circle: { type: "array", items: { $ref: "Friend" } }, basic: { $ref: "Basic" }, }, }, Basic: { type: "object", properties: { prop: { type: "string" }, second: { type: "number" } } }, WithNested: { type: "object", properties: { nested: { type: "string" }, nestedRef: { $ref: "DeepNested" } } }, ObjectWithArrayOfRef: { type: "object", properties: { exampleProp: { type: "string" }, another: { type: "number" }, link: { type: "array", items: { $ref: "WithNested" } }, someReference: { $ref: "Basic" }, }, }, DeepNested: { type: "object", properties: { deep: { type: "boolean" } } }, Root: { type: "object", properties: { str: { type: "string" }, reference: { $ref: "ObjectWithArrayOfRef", }, inline: { type: "object", properties: { nested_prop: { type: "boolean" }, }, }, another: { $ref: "WithNested" }, basic: { $ref: "Basic" }, differentPropSameRef: { $ref: "Basic" }, }, }, } as Record<string, SchemaObject>; const getSchemaByRef = (ref: string) => schemas[ref]!; const { refsDependencyGraph: result, deepDependencyGraph } = getOpenApiDependencyGraph( Object.keys(schemas), getSchemaByRef ); expect(result).toMatchInlineSnapshot(` { "Friend": Set { "UserWithFriends", "Friend", "Basic", }, "ObjectWithArrayOfRef": Set { "WithNested", "Basic", }, "Root": Set { "ObjectWithArrayOfRef", "WithNested", "Basic", }, "UserWithFriends": Set { "UserWithFriends", "Friend", "WithNested", }, "WithNested": Set { "DeepNested", }, } `); expect(topologicalSort(result)).toMatchInlineSnapshot(` [ "Basic", "Friend", "DeepNested", "WithNested", "UserWithFriends", "ObjectWithArrayOfRef", "Root", ] `); expect(deepDependencyGraph).toMatchInlineSnapshot(` { "Friend": Set { "UserWithFriends", "Friend", "WithNested", "DeepNested", "Basic", }, "ObjectWithArrayOfRef": Set { "WithNested", "DeepNested", "Basic", }, "Root": Set { "ObjectWithArrayOfRef", "WithNested", "DeepNested", "Basic", }, "UserWithFriends": Set { "UserWithFriends", "Friend", "Basic", "WithNested", "DeepNested", }, "WithNested": Set { "DeepNested", }, } `); expect(topologicalSort(deepDependencyGraph)).toMatchInlineSnapshot(` [ "DeepNested", "WithNested", "Basic", "Friend", "UserWithFriends", "ObjectWithArrayOfRef", "Root", ] `); });