UNPKG

astro-loader-pocketbase

Version:

A content loader for Astro that uses the PocketBase API

124 lines (110 loc) 3.58 kB
import { z } from "astro/zod"; import type { PocketBaseCollection, PocketBaseSchemaEntry } from "../types/pocketbase-schema.type"; export function parseSchema( collection: PocketBaseCollection, customSchemas: Record<string, z.ZodType> | undefined, hasSuperuserRights: boolean, improveTypes: boolean ): Record<string, z.ZodType> { // Prepare the schemas fields const fields: Record<string, z.ZodType> = {}; // Parse every field in the schema for (const field of collection.fields) { // Skip hidden fields if the user does not have superuser rights if (field.hidden && !hasSuperuserRights) { continue; } let fieldType; // Determine the field type and create the corresponding Zod type switch (field.type) { case "number": fieldType = z.number(); break; case "bool": fieldType = z.boolean(); break; case "date": case "autodate": // Coerce and parse the value as a date fieldType = z.coerce.date(); break; case "geoPoint": fieldType = z.object({ lon: z.number(), lat: z.number() }); break; case "select": { if (!field.values) { throw new Error( `Field ${field.name} is of type "select" but has no values defined.` ); } // Create an enum for the select values // @ts-expect-error - Zod complains because the values are not known at compile time and thus the array is not static. const values = z.enum(field.values); // Parse the field type based on the number of values it can have fieldType = parseSingleOrMultipleValues(field, values); break; } case "relation": case "file": // NOTE: Relations are currently not supported and are treated as strings // NOTE: Files are later transformed to URLs // Parse the field type based on the number of values it can have fieldType = parseSingleOrMultipleValues(field, z.string()); break; case "json": if (customSchemas && customSchemas[field.name]) { // Use the user defined custom schema for the field fieldType = customSchemas[field.name]; } else { // Parse the field as unknown JSON fieldType = z.unknown(); } break; default: // Default to a string fieldType = z.string(); break; } const isRequired = // Check if the field is required field.required || // `onCreate autodate` fields are always set (field.type === "autodate" && field.onCreate) || // Improve number and boolean types by providing default values (improveTypes && (field.type === "number" || field.type === "bool")); // If the field is not required, mark it as optional if (!isRequired) { fieldType = z.preprocess( (val) => val || undefined, z.optional(fieldType) ); } // Add the field to the fields object fields[field.name] = fieldType; } return fields; } /** * Parse the field type based on the number of values it can have * * @param field Field to parse * @param type Type of each value * * @returns The parsed field type */ function parseSingleOrMultipleValues( field: PocketBaseSchemaEntry, type: z.ZodType ): z.ZodType { // If the select allows multiple values, create an array of the enum if (field.maxSelect === undefined || field.maxSelect === 1) { return type; } return z.array(type); }