import path from "path"; import fs from "fs"; import { AppData } from "../data/app-data"; import grabDirNames from "../data/grab-dir-names"; import setSQLiteClient from "./set-sqlite-client"; import grabDBDir from "../utils/grab-db-dir"; import { loadDataFile, resolveAndLoadDataFile, supportedDataFileNames, } from "../utils/resolve-and-load-data-file"; /** * # Load config, schema and the SQLite client into globals * @description Runs once per process. Later calls return the loaded * globals. */ export default function init() { if (global.CONFIG && global.DB_SCHEMA && global.SQLITE_CLIENT) { return { config: global.CONFIG, dbSchema: global.DB_SCHEMA }; } const { ROOT_DIR } = grabDirNames(); const { ConfigFileName } = AppData; const loadedConfig = resolveAndLoadDataFile(ROOT_DIR, ConfigFileName); if (!loadedConfig) { throw new Error(`Please create a ${supportedDataFileNames(ConfigFileName)} file at the root of your project. (Looked in ${ROOT_DIR})`); } const Config = loadedConfig.data; if (!Config || typeof Config !== "object") { throw new Error(`Invalid config in \`${loadedConfig.path}\`. Expected a config object${isCodeFile(loadedConfig) ? " (export default)" : ""}.`); } if (!Config.db_name) { throw new Error(`\`db_name\` is required in your config`); } const { db_dir, backup_dir } = grabDBDir({ config: Config }); if (!fs.existsSync(db_dir)) { fs.mkdirSync(db_dir, { recursive: true }); } const loadedSchema = loadSchema({ config: Config, db_dir }); const DbSchema = loadedSchema.data; if (!DbSchema || typeof DbSchema !== "object") { throw new Error(`Invalid schema in \`${loadedSchema.path}\`. Expected a schema object${isCodeFile(loadedSchema) ? " (export default)" : ""}.`); } if (!fs.existsSync(backup_dir)) { fs.mkdirSync(backup_dir, { recursive: true }); } global.CONFIG = Config; global.DB_SCHEMA = DbSchema; global.CONFIG_FILE_PATH = loadedConfig.path; global.SCHEMA_FILE_PATH = loadedSchema.path; setSQLiteClient({ config: Config }); return { config: Config, dbSchema: DbSchema }; } /** * # Load the schema file * @description Uses `db_schema_file_name` when set, otherwise * `schema.ts|js|json|yaml|yml` in `db_dir`. */ function loadSchema({ config, db_dir, }) { if (config.db_schema_file_name) { const schema_file_path = path.join(db_dir, config.db_schema_file_name); const extension = path.extname(schema_file_path); const supported = AppData.SupportedDataFileExtensions.find((ext) => ext === extension); if (!supported) { throw new Error(`Unsupported schema file \`${config.db_schema_file_name}\`. Use one of: ${AppData.SupportedDataFileExtensions.join(", ")}`); } if (!fs.existsSync(schema_file_path)) { throw new Error(`Schema file not found: ${schema_file_path}`); } const resolved = { path: schema_file_path, basename: path.basename(schema_file_path), extension: supported, format: supported === ".yml" ? "yaml" : supported.slice(1), }; return { ...resolved, data: loadDataFile(resolved), }; } const loaded = resolveAndLoadDataFile(db_dir, AppData.DbSchemaFileName); if (!loaded) { throw new Error(`Please create a schema file (${supportedDataFileNames(AppData.DbSchemaFileName)}) in \`${db_dir}\`, or set \`db_schema_file_name\` in your config.`); } return loaded; } function isCodeFile(file) { return file.format === "ts" || file.format === "js"; }