@samchon/openapi
Version:
Universal OpenAPI to LLM function calling schemas. Transform any Swagger/OpenAPI document into type-safe schemas for OpenAI, Claude, Qwen, and more.
1 lines • 14.9 kB
Source Map (JSON)
{"version":3,"file":"OpenApiOneOfValidator.mjs","sources":["../../../src/utils/internal/OpenApiOneOfValidator.ts"],"sourcesContent":["import { OpenApi } from \"../../OpenApi\";\nimport { MapUtil } from \"../MapUtil\";\nimport { OpenApiTypeChecker } from \"../OpenApiTypeChecker\";\nimport { IOpenApiValidatorContext } from \"./IOpenApiValidatorContext\";\nimport { OpenApiStationValidator } from \"./OpenApiStationValidator\";\n\nexport namespace OpenApiOneOfValidator {\n export const validate = (\n ctx: IOpenApiValidatorContext<OpenApi.IJsonSchema.IOneOf>,\n ): boolean => {\n const discriminator: IDiscriminator = getDiscriminator(ctx);\n for (const item of discriminator.branches)\n if (item.predicator(ctx.value))\n return OpenApiStationValidator.validate({\n ...ctx,\n schema: item.schema,\n });\n if (discriminator.branches.length !== 0)\n return validate({\n ...ctx,\n schema: {\n oneOf: discriminator.remainders,\n },\n });\n const matched: OpenApi.IJsonSchema | undefined =\n discriminator.remainders.find(\n (schema) =>\n OpenApiStationValidator.validate({\n ...ctx,\n schema,\n exceptionable: false,\n equals: false,\n }) === true,\n );\n if (matched === undefined) return ctx.report(ctx);\n return ctx.equals === true\n ? OpenApiStationValidator.validate({\n ...ctx,\n schema: matched,\n })\n : true;\n };\n\n const getDiscriminator = (\n ctx: IOpenApiValidatorContext<OpenApi.IJsonSchema.IOneOf>,\n ): IDiscriminator => {\n const resolvedList: IFlatSchema[] = ctx.schema.oneOf.map((schema) =>\n getFlattened({\n components: ctx.components,\n schema,\n visited: new Set(),\n }),\n );\n\n // FIND ANY TYPE\n const anything: IFlatSchema | undefined = resolvedList.find((resolved) =>\n OpenApiTypeChecker.isUnknown(resolved.escaped),\n );\n if (anything)\n return {\n branches: [],\n remainders: [anything.schema],\n };\n\n // CHECK NULLABLES\n const nullables: IFlatSchema<OpenApi.IJsonSchema.INull>[] =\n resolvedList.filter(\n (resolved): resolved is IFlatSchema<OpenApi.IJsonSchema.INull> =>\n OpenApiTypeChecker.isNull(resolved.schema),\n );\n const significant: IFlatSchema<OpenApi.IJsonSchema>[] = resolvedList.filter(\n (resolved) => false === OpenApiTypeChecker.isNull(resolved.escaped),\n );\n if (significant.length === 1)\n return {\n branches: [\n {\n schema: significant[0].schema,\n predicator: (value) => value !== null,\n },\n ],\n remainders: nullables.map((nullable) => nullable.schema),\n };\n\n // DISCRIMINATIONS\n const tuples = significant.filter((flat) =>\n OpenApiTypeChecker.isTuple(flat.escaped),\n );\n const arrays = significant.filter(\n (flat): flat is IFlatSchema<OpenApi.IJsonSchema.IArray> =>\n OpenApiTypeChecker.isArray(flat.escaped),\n );\n const branches: IDiscriminatorBranch[] = [\n ...(tuples.length === 0 && arrays.length !== 0\n ? discriminateArrays(\n ctx,\n significant.filter(\n (flat): flat is IFlatSchema<OpenApi.IJsonSchema.IArray> =>\n OpenApiTypeChecker.isArray(flat.schema),\n ),\n )\n : []),\n ...discriminateObjects(\n ctx,\n significant.filter(\n (flat): flat is IFlatSchema<OpenApi.IJsonSchema.IObject> =>\n OpenApiTypeChecker.isObject(flat.escaped),\n ),\n tuples.length + arrays.length === 0,\n ),\n ];\n return {\n branches,\n remainders: ctx.schema.oneOf.filter(\n (x) => branches.some((y) => y.schema === x) === false,\n ),\n };\n };\n\n const discriminateArrays = (\n ctx: IOpenApiValidatorContext<OpenApi.IJsonSchema.IOneOf>,\n arraySchemas: IFlatSchema<OpenApi.IJsonSchema.IArray>[],\n ): IDiscriminatorBranch[] => {\n if (arraySchemas.length === 1)\n return [\n {\n schema: arraySchemas[0].schema,\n predicator: (value) => Array.isArray(value),\n },\n ];\n return arraySchemas\n .filter((flat, i, array) =>\n array.every(\n (item, j) =>\n i === j ||\n OpenApiTypeChecker.covers({\n components: ctx.components,\n x: item.escaped.items,\n y: flat.escaped.items,\n }) === false,\n ),\n )\n .map(\n (flat) =>\n ({\n schema: flat.schema,\n predicator: (value) =>\n Array.isArray(value) &&\n (value.length === 0 ||\n OpenApiStationValidator.validate({\n ...ctx,\n schema: (flat.escaped as OpenApi.IJsonSchema.IArray).items,\n value: value[0]!,\n path: `${ctx.path}[0]`,\n exceptionable: false,\n equals: false,\n })),\n }) satisfies IDiscriminatorBranch,\n );\n };\n\n const discriminateObjects = (\n ctx: IOpenApiValidatorContext<OpenApi.IJsonSchema.IOneOf>,\n objectSchemas: IFlatSchema<OpenApi.IJsonSchema.IObject>[],\n noArray: boolean,\n ): IDiscriminatorBranch[] => {\n if (objectSchemas.length === 1)\n return [\n {\n schema: objectSchemas[0].schema,\n predicator: noArray\n ? (value) => typeof value === \"object\" && value !== null\n : (value) =>\n typeof value === \"object\" &&\n value !== null &&\n Array.isArray(value) === false,\n },\n ];\n\n // KEEP ONLY REQUIRED PROPERTIES\n objectSchemas = objectSchemas\n .filter(\n (flat) =>\n flat.escaped.properties !== undefined &&\n flat.escaped.required !== undefined,\n )\n .map(\n (flat) =>\n ({\n ...flat,\n escaped: {\n ...flat.escaped,\n properties: Object.fromEntries(\n Object.entries(flat.escaped.properties ?? {}).map(\n ([key, value]) => [\n key,\n getFlattened({\n components: ctx.components,\n schema: value,\n visited: new Set(),\n }).escaped,\n ],\n ),\n ),\n },\n }) satisfies IFlatSchema<OpenApi.IJsonSchema.IObject>,\n );\n\n // PROPERTY MATRIX\n const matrix: Map<string, Array<OpenApi.IJsonSchema | null>> = new Map();\n objectSchemas.forEach((obj, i) => {\n for (const [key, value] of Object.entries(obj.escaped.properties ?? {})) {\n if (!!obj.escaped.required?.includes(key) === false) continue;\n MapUtil.take(matrix)(key)(() =>\n new Array(objectSchemas.length).fill(null),\n )[i] = value;\n }\n });\n\n // THE BRANCHES\n return objectSchemas\n .map((obj, i) => {\n const candidates: string[] = [];\n for (const [key, value] of Object.entries(\n obj.escaped.properties ?? {},\n )) {\n if (!!obj.escaped.required?.includes(key) === false) continue;\n\n const neighbors: OpenApi.IJsonSchema[] = matrix\n .get(key)!\n .filter((_oppo, j) => i !== j)\n .filter((oppo) => oppo !== null);\n const unique: boolean = OpenApiTypeChecker.isConstant(value)\n ? neighbors.every(\n (oppo) =>\n OpenApiTypeChecker.isConstant(oppo) &&\n value.const !== oppo.const,\n )\n : neighbors.length === 0;\n if (unique) candidates.push(key);\n }\n if (candidates.length === 0) return null;\n const top: string =\n candidates.find((key) =>\n OpenApiTypeChecker.isConstant(obj.escaped.properties![key]),\n ) ?? candidates[0];\n const target: OpenApi.IJsonSchema = obj.escaped.properties![top];\n return {\n schema: obj.schema,\n predicator: OpenApiTypeChecker.isConstant(target)\n ? (value) =>\n typeof value === \"object\" &&\n value !== null &&\n (value as any)[top] === target.const\n : (value) =>\n typeof value === \"object\" &&\n value !== null &&\n (value as any)[top] !== undefined,\n } satisfies IDiscriminatorBranch;\n })\n .filter((b) => b !== null);\n };\n}\n\nconst getFlattened = (props: {\n components: OpenApi.IComponents;\n schema: OpenApi.IJsonSchema;\n visited: Set<string>;\n}): IFlatSchema => {\n if (OpenApiTypeChecker.isReference(props.schema)) {\n const key: string = props.schema.$ref.split(\"/\").pop() ?? \"\";\n if (props.visited.has(key))\n return {\n schema: props.schema,\n escaped: {},\n };\n props.visited.add(key);\n return {\n ...getFlattened({\n components: props.components,\n schema: props.components.schemas?.[key] ?? {},\n visited: props.visited,\n }),\n schema: props.schema,\n };\n }\n return {\n schema: props.schema,\n escaped: props.schema,\n };\n};\n\ninterface IDiscriminator {\n branches: IDiscriminatorBranch[];\n remainders: OpenApi.IJsonSchema[];\n}\n\ninterface IDiscriminatorBranch {\n schema: OpenApi.IJsonSchema;\n predicator: (value: unknown) => boolean;\n}\n\ninterface IFlatSchema<\n Schema extends OpenApi.IJsonSchema = OpenApi.IJsonSchema,\n> {\n schema: OpenApi.IJsonSchema;\n escaped: Schema;\n}\n"],"names":["OpenApiOneOfValidator","validate","ctx","discriminator","getDiscriminator","item","branches","predicator","value","OpenApiStationValidator","schema","length","oneOf","remainders","matched","find","exceptionable","equals","undefined","report","resolvedList","map","getFlattened","components","visited","Set","anything","resolved","OpenApiTypeChecker","isUnknown","escaped","nullables","filter","isNull","significant","nullable","tuples","flat","isTuple","arrays","isArray","discriminateArrays","discriminateObjects","isObject","x","some","y","arraySchemas","Array","i","array","every","j","covers","items","path","objectSchemas","noArray","properties","required","Object","fromEntries","entries","key","matrix","Map","forEach","obj","includes","MapUtil","take","fill","candidates","neighbors","get","_oppo","oppo","unique","isConstant","const","push","top","target","b","props","isReference","$ref","split","pop","has","add","schemas"],"mappings":"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"}