UNPKG

@samchon/openapi

Version:

OpenAPI definitions and converters for 'typia' and 'nestia'.

1 lines 14.5 kB
{"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 return discriminator.branches.length === 0\n ? discriminator.remainders\n .map((schema) =>\n OpenApiStationValidator.validate({\n ...ctx,\n schema,\n exceptionable: false,\n }),\n )\n .some((v) => v) || ctx.report(ctx)\n : validate({\n ...ctx,\n schema: {\n oneOf: discriminator.remainders,\n },\n });\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 }),\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 })),\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","remainders","map","exceptionable","some","v","report","oneOf","resolvedList","getFlattened","components","visited","Set","anything","find","resolved","OpenApiTypeChecker","isUnknown","escaped","nullables","filter","isNull","significant","nullable","tuples","flat","isTuple","arrays","isArray","discriminateArrays","discriminateObjects","isObject","x","y","arraySchemas","Array","i","array","every","j","covers","items","path","objectSchemas","noArray","properties","undefined","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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"}