import { JSONSchema7 } from 'json-schema' import { GetString, Model, ModelNotGeneric, ModelProperty, ModelType } from '../types/model.types' import { getId } from '../utils/get-id' import { createProperty } from './create-property' import { MODELS_PARAMETER_VALUE, PARAMETER_VALUE } from './get-string-result' import { globalDefinitions } from './global' import copy from 'fast-copy' export const createModel = >( properties: T, name?: string ): Model => { const id = `m${getId()}` const schema: JSONSchema7 = { $id: id, type: 'object', additionalProperties: false, } if (name) { schema.title = name } let usedReferences: string[] = [] const usedModels: Record = {} const body: GetString[] = [] for (const propertyName in properties) { const property = properties[propertyName] const { isRequired } = property const output = createProperty(propertyName, property, (id) => usedReferences.push(id)) if (!schema.properties) { schema.properties = {} } schema.properties[propertyName] = output.schema if (!schema.required) { schema.required = [] } if (isRequired) { schema.required.push(propertyName) } if (typeof property.type === 'function') { usedReferences = [...usedReferences, ...property.type.usedReferences] usedModels[propertyName] = property.type } body.push(output.getString) } const getBody = (propertyName?: string) => body.map((exec) => exec(propertyName)).join('\n') // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func const EvalFunction = new Function( PARAMETER_VALUE, MODELS_PARAMETER_VALUE, ` const output = {}; ${getBody()} return output` ) const resultFunction: unknown = function (data: unknown) { return EvalFunction(data, usedModels) } const result = resultFunction as Model result.model = undefined as unknown as ModelType result.getSchema = (config) => { if (!config?.returnFullSchema) { return copy(schema) } const newSchema = copy(schema) for (const usedReference of usedReferences) { const referenceSchema = globalDefinitions.get(usedReference) if (referenceSchema) { if (!newSchema.definitions) { newSchema.definitions = {} } newSchema.definitions[usedReference] = referenceSchema } } return newSchema } globalDefinitions.set(id, schema) result.properties = properties result.getBody = getBody result.usedReferences = usedReferences return result }