55 lines
2.4 KiB
TypeScript
55 lines
2.4 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
export function getRepoRoot(cwd = process.cwd()): string {
|
|
const candidates = [cwd, path.resolve(cwd, ".."), path.resolve(cwd, "../.."), path.resolve(cwd, "../../..")];
|
|
const root = candidates.find(
|
|
(candidate) => fs.existsSync(path.join(candidate, "package.json")) && fs.existsSync(path.join(candidate, "apps/web/app"))
|
|
);
|
|
|
|
return root ?? cwd;
|
|
}
|
|
|
|
export function resolveRepoPath(relativePath: string, cwd = process.cwd()): string {
|
|
const repoRoot = getRepoRoot(cwd);
|
|
const normalizedPath = relativePath.replaceAll("\\", "/");
|
|
if (normalizedPath === "app" || normalizedPath.startsWith("app/") || normalizedPath === "public" || normalizedPath.startsWith("public/")) {
|
|
throw new Error(`Use apps/web/${normalizedPath} instead of legacy root ${normalizedPath}`);
|
|
}
|
|
const candidates = [path.join(repoRoot, normalizedPath)];
|
|
|
|
return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0];
|
|
}
|
|
|
|
export function repoPathExists(relativePath: string, cwd = process.cwd()): boolean {
|
|
return fs.existsSync(resolveRepoPath(relativePath, cwd));
|
|
}
|
|
|
|
export function readRepoFile(relativePath: string, cwd = process.cwd()): string {
|
|
return fs.readFileSync(resolveRepoPath(relativePath, cwd), "utf8");
|
|
}
|
|
|
|
export function readRepoDir(relativePath: string, cwd = process.cwd()): string[] {
|
|
return fs.readdirSync(resolveRepoPath(relativePath, cwd));
|
|
}
|
|
|
|
export function readMergedLocaleNamespace<T>(locale: string, namespace: string, cwd = process.cwd()): T {
|
|
const overrides = JSON.parse(readRepoFile(`apps/web/public/locales/${locale}/${namespace}.json`, cwd)) as unknown;
|
|
if (!locale.endsWith("-formal")) return overrides as T;
|
|
|
|
const baseLocale = locale.slice(0, -"-formal".length);
|
|
const base = JSON.parse(readRepoFile(`apps/web/public/locales/${baseLocale}/${namespace}.json`, cwd)) as unknown;
|
|
return mergeJsonObjects(base, overrides) as T;
|
|
}
|
|
|
|
function mergeJsonObjects(base: unknown, overrides: unknown): unknown {
|
|
if (!isJsonObject(base) || !isJsonObject(overrides)) return overrides;
|
|
const merged: Record<string, unknown> = { ...base };
|
|
for (const [key, value] of Object.entries(overrides)) merged[key] = mergeJsonObjects(merged[key], value);
|
|
return merged;
|
|
}
|
|
|
|
function isJsonObject(value: unknown): value is Record<string, unknown> {
|
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
}
|