UNPKG

@samchon/openapi

Version:

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

213 lines (202 loc) 8.56 kB
import { OpenApiV3Downgrader } from "../../converters/OpenApiV3Downgrader.mjs"; import { OpenApiV3Upgrader } from "../../converters/OpenApiV3Upgrader.mjs"; import { LlmTypeCheckerV3 } from "../../utils/LlmTypeCheckerV3.mjs"; import { OpenApiConstraintShifter } from "../../utils/OpenApiConstraintShifter.mjs"; import { OpenApiTypeChecker } from "../../utils/OpenApiTypeChecker.mjs"; import { OpenApiValidator } from "../../utils/OpenApiValidator.mjs"; import { LlmDescriptionInverter } from "./LlmDescriptionInverter.mjs"; import { LlmParametersFinder } from "./LlmParametersComposer.mjs"; var LlmSchemaV3Composer; (function(LlmSchemaV3Composer) { LlmSchemaV3Composer.IS_DEFS = false; LlmSchemaV3Composer.DEFAULT_CONFIG = { recursive: 3, constraint: true }; LlmSchemaV3Composer.parameters = props => { const entity = LlmParametersFinder.parameters({ ...props, method: "LlmSchemaV3Composer.parameters" }); if (entity.success === false) return entity; const result = LlmSchemaV3Composer.schema(props); if (result.success === false) return result; return { success: true, value: { ...result.value, additionalProperties: false } }; }; LlmSchemaV3Composer.schema = props => { const reasons = []; OpenApiTypeChecker.visit({ closure: (next, accessor) => { if (props.validate) reasons.push(...props.validate(next, accessor)); if (OpenApiTypeChecker.isTuple(next)) reasons.push({ accessor, schema: next, message: "LLM does not allow tuple type." }); else if (OpenApiTypeChecker.isReference(next)) { const key = next.$ref.split("#/components/schemas/")[1]; if (props.components.schemas?.[key] === undefined) { reasons.push({ schema: next, message: `${accessor}: unable to find reference type ${JSON.stringify(key)}.`, accessor }); } } }, components: props.components, schema: props.schema, accessor: props.accessor, refAccessor: props.refAccessor }); if (reasons.length > 0) return { success: false, error: { method: "LlmSchemaV3Composer.schema", message: "Failed to compose LLM schema of v3", reasons } }; const escaped = OpenApiTypeChecker.escape({ ...props, recursive: props.config.recursive }); if (escaped.success === false) return { success: false, error: { method: "LlmSchemaV3Composer.schema", message: "Failed to compose LLM schema of v3", reasons: escaped.error.reasons } }; const downgraded = OpenApiV3Downgrader.downgradeSchema({ original: { schemas: {} }, downgraded: {} })(escaped.value); LlmTypeCheckerV3.visit({ closure: next => { if (LlmTypeCheckerV3.isOneOf(next) && next.discriminator !== undefined) delete next.discriminator; else if (LlmTypeCheckerV3.isObject(next)) { next.properties ?? (next.properties = {}); next.required ?? (next.required = []); } if (props.config.constraint === false) { if (LlmTypeCheckerV3.isInteger(next) || LlmTypeCheckerV3.isNumber(next)) OpenApiConstraintShifter.shiftNumeric(next); else if (LlmTypeCheckerV3.isString(next)) OpenApiConstraintShifter.shiftString(next); else if (LlmTypeCheckerV3.isArray(next)) OpenApiConstraintShifter.shiftArray(next); } }, schema: downgraded }); return { success: true, value: downgraded }; }; LlmSchemaV3Composer.separateParameters = props => { const [llm, human] = separateObject({ predicate: props.predicate, schema: props.parameters }); return { llm: llm ?? { type: "object", properties: {}, additionalProperties: false, required: [] }, human, validate: llm ? OpenApiValidator.create({ components: {}, schema: LlmSchemaV3Composer.invert({ schema: llm }), required: true, equals: props.equals }) : undefined }; }; const separateStation = props => { if (props.predicate(props.schema) === true) return [ null, props.schema ]; else if (LlmTypeCheckerV3.isUnknown(props.schema) || LlmTypeCheckerV3.isOneOf(props.schema)) return [ props.schema, null ]; else if (LlmTypeCheckerV3.isObject(props.schema)) return separateObject({ predicate: props.predicate, schema: props.schema }); else if (LlmTypeCheckerV3.isArray(props.schema)) return separateArray({ predicate: props.predicate, schema: props.schema }); return [ props.schema, null ]; }; const separateArray = props => { const [x, y] = separateStation({ predicate: props.predicate, schema: props.schema.items }); return [ x !== null ? { ...props.schema, items: x } : null, y !== null ? { ...props.schema, items: y } : null ]; }; const separateObject = props => { if (Object.keys(props.schema.properties ?? {}).length === 0 && !!props.schema.additionalProperties === false) return [ props.schema, null ]; const llm = { ...props.schema, properties: {}, additionalProperties: props.schema.additionalProperties }; const human = { ...props.schema, properties: {}, additionalProperties: props.schema.additionalProperties }; for (const [key, value] of Object.entries(props.schema.properties ?? {})) { const [x, y] = separateStation({ predicate: props.predicate, schema: value }); if (x !== null) llm.properties[key] = x; if (y !== null) human.properties[key] = y; } if (typeof props.schema.additionalProperties === "object" && props.schema.additionalProperties !== null) { const [dx, dy] = separateStation({ predicate: props.predicate, schema: props.schema.additionalProperties }); llm.additionalProperties = dx ?? false; human.additionalProperties = dy ?? false; } return [ !!Object.keys(llm.properties).length || !!llm.additionalProperties ? shrinkRequired(llm) : null, !!Object.keys(human.properties).length || !!human.additionalProperties ? shrinkRequired(human) : null ]; }; const shrinkRequired = s => { s.required = s.required.filter((key => s.properties[key] !== undefined)); return s; }; LlmSchemaV3Composer.invert = props => { const upgraded = OpenApiV3Upgrader.convertSchema({})(props.schema); OpenApiTypeChecker.visit({ closure: schema => { if (OpenApiTypeChecker.isArray(schema)) Object.assign(schema, { ...schema, ...LlmDescriptionInverter.array(schema.description) }); else if (OpenApiTypeChecker.isInteger(schema) || OpenApiTypeChecker.isNumber(schema)) Object.assign(schema, { ...schema, ...LlmDescriptionInverter.numeric(schema.description) }); else if (OpenApiTypeChecker.isString(schema)) Object.assign(schema, { ...schema, ...LlmDescriptionInverter.string(schema.description) }); }, components: {}, schema: upgraded }); return upgraded; }; })(LlmSchemaV3Composer || (LlmSchemaV3Composer = {})); export { LlmSchemaV3Composer }; //# sourceMappingURL=LlmSchemaV3Composer.mjs.map