UNPKG

sveltekit-superforms

Version:

Making SvelteKit forms a pleasure to use!

106 lines (105 loc) 4.04 kB
import { assertSchema } from '../utils.js'; import { merge } from 'ts-deepmerge'; const conversionFormatTypes = [ 'unix-time', 'bigint', 'any', 'symbol', 'set', 'map', 'int64', 'stringbool' ]; /** * Normalizes the different kind of schema variations (anyOf, oneOf, union, const null, etc) * to figure out the field type, optional, nullable, etc. */ export function schemaInfo(schema, isOptional, path) { assertSchema(schema, path); const types = schemaTypes(schema, path); const array = schema.items && types.includes('array') ? (Array.isArray(schema.items) ? schema.items : [schema.items]).filter((s) => typeof s !== 'boolean') : undefined; const additionalProperties = schema.additionalProperties && typeof schema.additionalProperties === 'object' && types.includes('object') ? Object.fromEntries(Object.entries(schema.additionalProperties).filter(([, value]) => typeof value !== 'boolean')) : undefined; const properties = schema.properties && types.includes('object') ? Object.fromEntries(Object.entries(schema.properties).filter(([, value]) => typeof value !== 'boolean')) : undefined; const union = unionInfo(schema)?.filter((u) => u.type !== 'null' && u.const !== null); const result = { types: types.filter((s) => s !== 'null'), isOptional, isNullable: types.includes('null'), schema, union: union?.length ? union : undefined, array, properties, additionalProperties, required: schema.required }; if (!schema.allOf || !schema.allOf.length) { return result; } return { ...merge.withOptions({ allowUndefinedOverrides: false }, result, ...schema.allOf.map((s) => schemaInfo(s, false, []))), schema }; } function schemaTypes(schema, path) { assertSchema(schema, path); let types = schema.const === null ? ['null'] : []; if (schema.type) { types = Array.isArray(schema.type) ? schema.type : [schema.type]; } if (schema.anyOf) { types = schema.anyOf.flatMap((s) => schemaTypes(s, path)); } if (schema.oneOf) { types = schema.oneOf.flatMap((s) => schemaTypes(s, path)); } if (types.includes('array') && schema.uniqueItems) { const i = types.findIndex((t) => t === 'array'); if (i !== -1) types[i] = 'set'; } else if (schema.format && conversionFormatTypes.includes(schema.format)) { types.unshift(schema.format); // For dates and int64 (bigint), remove the integer type, as the schema format will be used // instead in the following cases if (schema.format == 'unix-time' || schema.format == 'int64') { const i = types.findIndex((t) => t == 'integer'); types.splice(i, 1); } // For bigint, remove the string type, as the schema format will be used // instead in the following cases if (schema.format == 'bigint') { const i = types.findIndex((t) => t == 'string'); types.splice(i, 1); } // For stringbool, remove the string type, as the schema format will be used // stringbool should be treated as a special string that validates to boolean if (schema.format == 'stringbool') { const i = types.findIndex((t) => t == 'string'); if (i !== -1) types.splice(i, 1); } } if (schema.const && schema.const !== null && typeof schema.const !== 'function') { types.push(typeof schema.const); } return Array.from(new Set(types)); } function unionInfo(schema) { if (!schema.oneOf && !schema.anyOf) return undefined; if (schema.oneOf && schema.oneOf.length) { return schema.oneOf.filter((s) => typeof s !== 'boolean'); } if (schema.anyOf && schema.anyOf.length) { return schema.anyOf.filter((s) => typeof s !== 'boolean'); } return undefined; }