mirror of
https://github.com/Lifeforge-app/lifeforge.git
synced 2026-06-28 14:55:45 +00:00
Former-commit-id: 586191279315595e220678ceecf0874411939166 [formerly 1f55a3206ba247b80a76df22e32af6ec0779b60a] [formerly 1bacdd219527be876d47e6f9c90bd5d02827436d [formerly 88124105327ab95503b159bc610935e16b84fbfa]] Former-commit-id: 1a634282b836db0ad2b88ee143c170e955c42f37 [formerly 0f5f331fa9846a66196c04deda637f08315e4d46] Former-commit-id: 3558fed9aa9dc3016906a086a63cb462e9fc8866
200 lines
5.4 KiB
TypeScript
200 lines
5.4 KiB
TypeScript
import chalk from 'chalk'
|
|
import dotenv from 'dotenv'
|
|
import fs from 'fs'
|
|
import _ from 'lodash'
|
|
import path from 'path'
|
|
import Pocketbase, { type CollectionModel } from 'pocketbase'
|
|
import prettier from 'prettier'
|
|
|
|
dotenv.config({
|
|
path: path.resolve(__dirname, '../server/env/.env.local')
|
|
})
|
|
|
|
if (!process.env.PB_HOST || !process.env.PB_EMAIL || !process.env.PB_PASSWORD) {
|
|
console.error(
|
|
'Please provide PB_HOST, PB_EMAIL, and PB_PASSWORD in your environment variables.'
|
|
)
|
|
process.exit(1)
|
|
}
|
|
|
|
const pb = new Pocketbase(process.env.PB_HOST)
|
|
|
|
let SCHEMA_STRING = `
|
|
import flattenSchemas from '@functions/utils/flattenSchema'
|
|
import { z } from 'zod/v4'
|
|
|
|
export const SCHEMAS = {
|
|
`
|
|
|
|
try {
|
|
await pb
|
|
.collection('_superusers')
|
|
.authWithPassword(process.env.PB_EMAIL, process.env.PB_PASSWORD)
|
|
|
|
if (!pb.authStore.isSuperuser || !pb.authStore.isValid) {
|
|
console.error('Invalid credentials.')
|
|
process.exit(1)
|
|
}
|
|
} catch {
|
|
console.error('Server is not reachable or credentials are invalid.')
|
|
process.exit(1)
|
|
}
|
|
|
|
const allModules = [
|
|
...fs.readdirSync('./server/src/apps', { withFileTypes: true }),
|
|
...fs.readdirSync('./server/src/core/lib', { withFileTypes: true })
|
|
]
|
|
|
|
const modulesMap: Record<string, CollectionModel[]> = {}
|
|
|
|
const allCollections = await pb.collections.getFullList()
|
|
const collections = allCollections.filter(e => !e.system)
|
|
for (const collection of collections) {
|
|
const module = allModules.find(e =>
|
|
collection.name.startsWith(_.snakeCase(e.name))
|
|
)
|
|
if (!module) {
|
|
console.log(
|
|
chalk.yellow('[WARNING]') +
|
|
` Collection ${collection.name} does not have a corresponding module.`
|
|
)
|
|
|
|
continue
|
|
}
|
|
|
|
if (!modulesMap[module.name]) {
|
|
modulesMap[module.name] = []
|
|
}
|
|
modulesMap[module.name]?.push(collection)
|
|
}
|
|
|
|
console.log(
|
|
chalk.green('[INFO]') +
|
|
` Found ${Object.values(modulesMap).flat().length} collections across ${Object.keys(modulesMap).length} modules.`
|
|
)
|
|
|
|
for (const module of allModules) {
|
|
if (!modulesMap[module.name]) {
|
|
continue
|
|
}
|
|
|
|
const collections = modulesMap[module.name]
|
|
|
|
if (!collections) {
|
|
console.warn(
|
|
chalk.yellow('[WARNING]') +
|
|
` No collections found for module ${chalk.bold(module.name)}.`
|
|
)
|
|
continue
|
|
}
|
|
|
|
const moduleName = collections[0].name.split('__')[0]
|
|
|
|
SCHEMA_STRING += ` ${moduleName}: {\n`
|
|
|
|
for (const collection of collections ?? []) {
|
|
console.log(
|
|
chalk.blue('[INFO]') +
|
|
` Found ${collection.fields.length} fields in collection ${chalk.bold(
|
|
collection.name
|
|
)} in module ${chalk.bold(moduleName)}.`
|
|
)
|
|
const zodSchemaObject: Record<string, string> = {}
|
|
|
|
for (const field of collection.fields) {
|
|
if (field.name === 'id') {
|
|
// Skip fields that are auto-generated by PocketBase
|
|
continue
|
|
}
|
|
|
|
switch (field.type) {
|
|
case 'text':
|
|
zodSchemaObject[field.name] = 'z.string()'
|
|
break
|
|
case 'richtext':
|
|
zodSchemaObject[field.name] = 'z.string()'
|
|
break
|
|
case 'number':
|
|
zodSchemaObject[field.name] = 'z.number()'
|
|
break
|
|
case 'bool':
|
|
zodSchemaObject[field.name] = 'z.boolean()'
|
|
break
|
|
case 'email':
|
|
zodSchemaObject[field.name] = 'z.email()'
|
|
break
|
|
case 'url':
|
|
zodSchemaObject[field.name] = 'z.url()'
|
|
break
|
|
case 'date':
|
|
zodSchemaObject[field.name] = 'z.string()'
|
|
break
|
|
case 'autodate':
|
|
zodSchemaObject[field.name] = 'z.string()'
|
|
break
|
|
case 'select':
|
|
const value = [...field.values, ...(field.required ? [] : [''])]
|
|
zodSchemaObject[field.name] =
|
|
field.maxSelect > 1
|
|
? `z.array(z.enum(${JSON.stringify(value)}))`
|
|
: `z.enum(${JSON.stringify(value)})`
|
|
break
|
|
case 'file':
|
|
zodSchemaObject[field.name] =
|
|
field.maxSelect > 1 ? 'z.array(z.string())' : 'z.string()'
|
|
break
|
|
case 'relation':
|
|
zodSchemaObject[field.name] =
|
|
field.maxSelect > 1 ? `z.array(z.string())` : `z.string()`
|
|
break
|
|
case 'json':
|
|
zodSchemaObject[field.name] = 'z.any()'
|
|
break
|
|
case 'geoPoint':
|
|
zodSchemaObject[field.name] =
|
|
'z.object({ lat: z.number(), lon: z.number() })'
|
|
break
|
|
case 'password':
|
|
zodSchemaObject[field.name] = 'z.string()'
|
|
break
|
|
default:
|
|
console.warn(
|
|
chalk.yellow('[WARNING]') +
|
|
` Unknown field type ${field.type} for field ${field.name} in collection ${collection.name}.`
|
|
)
|
|
continue
|
|
}
|
|
}
|
|
|
|
const zodSchemaString = `z.object({\n${Object.entries(zodSchemaObject)
|
|
.map(([key, value]) => ` ${key}: ${value},`)
|
|
.join('\n')}\n}),`
|
|
SCHEMA_STRING += ` ${collection.name.split('__').pop()}: ${zodSchemaString}\n`
|
|
|
|
console.log(
|
|
chalk.green('[INFO]') +
|
|
` Generated Zod schema for collection ${chalk.bold(
|
|
collection.name
|
|
)} in module ${chalk.bold(moduleName)}.`
|
|
)
|
|
}
|
|
|
|
SCHEMA_STRING += ` },\n`
|
|
}
|
|
|
|
SCHEMA_STRING += `}
|
|
|
|
const COLLECTION_SCHEMAS = flattenSchemas(SCHEMAS)
|
|
|
|
export default COLLECTION_SCHEMAS
|
|
`
|
|
|
|
const formattedSchemaString = await prettier.format(SCHEMA_STRING, {
|
|
parser: 'typescript'
|
|
})
|
|
|
|
fs.writeFileSync(
|
|
path.resolve(__dirname, '../server/src/core/schema.ts'),
|
|
formattedSchemaString
|
|
)
|