import { mkdir, readdir, readFile, writeFile } from "node:fs/promises"; import { watch } from "node:fs"; import { dirname, join } from "node:path"; import { transform } from "lightningcss"; import { githubDarkTheme, githubLightTheme } from "../themes"; import { createStylesheet } from "../styles/index"; import { syncLocales } from "./locale"; const root = process.cwd(); const minify = process.argv.includes("--minify"); const watchMode = process.argv.includes("--watch"); const themes = [ { filename: "theme-github-dev.css", source: githubLightTheme, }, { filename: "theme-github-dev-dark.css", source: githubDarkTheme, }, ]; async function writeIfChanged(output: string, content: Buffer | string) { try { const current = await readFile(output); if (Buffer.compare(current, Buffer.from(content)) === 0) { return; } } catch { // Missing files are created below. } await mkdir(dirname(output), { recursive: true }); await writeFile(output, content); } async function syncDir(source: string, target: string, ignoredNames = new Set()) { const entries = await readdir(source, { withFileTypes: true }); await Promise.all( entries.map(async (entry) => { if (ignoredNames.has(entry.name)) { return; } const sourcePath = join(source, entry.name); const targetPath = join(target, entry.name); if (entry.isDirectory()) { await syncDir(sourcePath, targetPath); return; } if (entry.isFile()) { await writeIfChanged(targetPath, await readFile(sourcePath)); } }), ); } async function build() { const cssOutputs = await Promise.all( themes.flatMap((theme) => { const result = transform({ filename: theme.filename, code: Buffer.from(createStylesheet(theme.source)), minify, targets: { chrome: 108 << 16, firefox: 108 << 16, safari: 16 << 16, }, }); return [ writeIfChanged(join(root, "dist", theme.filename), result.code), writeIfChanged(join(root, ".gitea", "custom", "public", "assets", "css", theme.filename), result.code), ]; }), ); await Promise.all([ syncDir(join(root, "templates"), join(root, ".gitea", "custom", "templates")), syncDir(join(root, "options"), join(root, ".gitea", "custom", "options"), new Set(["locale", "locale-overrides"])), ]); await syncLocales(); console.log(`built ${cssOutputs.length} css outputs`); } await build(); if (watchMode) { console.log("watching styles, themes, and src"); const watchedDirs = [join(root, "styles"), join(root, "themes"), join(root, "src")]; const watchers = watchedDirs.map((dir) => watch(dir, { recursive: true }, async (_eventType, filename) => { if (filename?.endsWith(".ts")) { await build(); } }), ); process.on("SIGINT", () => { watchers.forEach((watcher) => watcher.close()); process.exit(0); }); }