import { readdirSync, readFileSync, writeFileSync, statSync } from "fs"; import { join } from "path"; const OUTPUT_FILE = "./registry.json"; const VALID_CATEGORIES = ["Skin", "Texture", "World", "Mod", "DLC"]; const REQUIRED_FIELDS = ["id", "name", "author", "description", "category", "thumbnail", "zips", "version"]; const IGNORED_DIRS = [".git", ".github", "scripts"]; function validateMeta(meta, pkgDir) { const errors = []; for (const field of REQUIRED_FIELDS) { if (meta[field] === undefined || meta[field] === null) { errors.push(`missing required field: "${field}"`); } } if (meta.id && meta.id !== pkgDir) { errors.push(`id "${meta.id}" does not match folder name "${pkgDir}"`); } if (meta.category) { const cats = Array.isArray(meta.category) ? meta.category : [meta.category]; for (const cat of cats) { if (!VALID_CATEGORIES.includes(cat)) { errors.push(`invalid category "${cat}", must be one of: ${VALID_CATEGORIES.join(", ")}`); } } } if (meta.version && !/^\d+\.\d+\.\d+$/.test(meta.version)) { errors.push(`version "${meta.version}" is not valid semver (expected x.y.z)`); } return errors; } function stripJsonComments(str) { return str.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, ""); } const packages = []; const allErrors = []; let entries; try { entries = readdirSync("."); } catch { console.error(`how the hell did you run me if the directory doesn't exist???`); process.exit(1); } for (const entry of entries) { const pkgPath = entry; if (!statSync(pkgPath).isDirectory()) continue; if (!statSync(pkgPath).isDirectory() || IGNORED_DIRS.includes(entry) || entry.startsWith(".")) continue; const metaPath = join(pkgPath, "meta.json"); let raw; try { raw = readFileSync(metaPath, "utf8"); } catch { allErrors.push({ package: entry, errors: ["meta.json not found"] }); continue; } let meta; try { meta = JSON.parse(stripJsonComments(raw)); } catch (e) { allErrors.push({ package: entry, errors: [`meta.json is invalid JSON: ${e.message}`] }); continue; } const errors = validateMeta(meta, entry); if (errors.length > 0) { allErrors.push({ package: entry, errors }); continue; } packages.push(meta); } if (allErrors.length > 0) { console.error("Validation failed:\n"); for (const { package: pkg, errors } of allErrors) { console.error(` ${pkg}/meta.json`); for (const err of errors) { console.error(` - ${err}`); } } process.exit(1); } const registry = { generated_at: new Date().toISOString(), count: packages.length, packages, }; writeFileSync(OUTPUT_FILE, JSON.stringify(registry, null, 2)); console.log(`registry.json generated with ${packages.length} package(s)`);