refactor: dedupe pierre theme loader patch

This commit is contained in:
Gustavo Madeira Santana 2026-03-27 19:50:07 -04:00
parent 793b9f8405
commit 4a3aab4ff5
No known key found for this signature in database
2 changed files with 53 additions and 73 deletions

View File

@ -1,33 +1,58 @@
import fs from "node:fs/promises";
import { createRequire } from "node:module";
import type { ThemeRegistrationResolved } from "@pierre/diffs";
import { RegisteredCustomThemes, ResolvedThemes, ResolvingThemes } from "@pierre/diffs";
type RegisteredThemeLoader = NonNullable<ReturnType<typeof RegisteredCustomThemes.get>>;
type RegisteredTheme = Awaited<ReturnType<RegisteredThemeLoader>>;
const require = createRequire(import.meta.url);
type PierreThemeName = "pierre-dark" | "pierre-light";
const diffsRequire = createRequire(import.meta.resolve("@pierre/diffs"));
const PIERRE_THEME_SPECS = [
["pierre-dark", "@pierre/theme/themes/pierre-dark.json"],
["pierre-light", "@pierre/theme/themes/pierre-light.json"],
] as const satisfies ReadonlyArray<readonly [PierreThemeName, string]>;
async function loadPierreTheme(
function createThemeLoader(
themeName: PierreThemeName,
themeSpecifier: string,
themeName: string,
): Promise<RegisteredTheme> {
const themePath = require.resolve(themeSpecifier);
return {
...(JSON.parse(await fs.readFile(themePath, "utf8")) as Record<string, unknown>),
name: themeName,
): () => Promise<ThemeRegistrationResolved> {
let cachedTheme: ThemeRegistrationResolved | undefined;
return async () => {
if (cachedTheme) {
return cachedTheme;
}
const themePath = diffsRequire.resolve(themeSpecifier);
cachedTheme = {
...(JSON.parse(await fs.readFile(themePath, "utf8")) as Record<string, unknown>),
name: themeName,
} as ThemeRegistrationResolved;
return cachedTheme;
};
}
export async function ensurePierreThemesRegistered(): Promise<void> {
// Always overwrite the upstream loaders so the Node-safe path wins even if
// @pierre/diffs registered its JSON-import loaders earlier in this process.
RegisteredCustomThemes.set("pierre-light", () =>
loadPierreTheme("@pierre/theme/themes/pierre-light.json", "pierre-light"),
);
RegisteredCustomThemes.set("pierre-dark", () =>
loadPierreTheme("@pierre/theme/themes/pierre-dark.json", "pierre-dark"),
);
ResolvedThemes.delete("pierre-light");
ResolvedThemes.delete("pierre-dark");
ResolvingThemes.delete("pierre-light");
ResolvingThemes.delete("pierre-dark");
const PIERRE_THEME_LOADERS = new Map(
PIERRE_THEME_SPECS.map(([themeName, themeSpecifier]) => [
themeName,
createThemeLoader(themeName, themeSpecifier),
]),
);
export function ensurePierreThemesRegistered(): void {
let replacedThemeLoader = false;
for (const [themeName, loader] of PIERRE_THEME_LOADERS) {
if (RegisteredCustomThemes.get(themeName) !== loader) {
RegisteredCustomThemes.set(themeName, loader);
replacedThemeLoader = true;
}
}
if (!replacedThemeLoader) {
return;
}
// If another path swapped these loaders, clear the resolver caches so the
// next render rehydrates the highlighter with the Node-safe theme source.
for (const [themeName] of PIERRE_THEME_LOADERS) {
ResolvedThemes.delete(themeName);
ResolvingThemes.delete(themeName);
}
}

View File

@ -1,12 +1,5 @@
import fs from "node:fs/promises";
import { createRequire } from "node:module";
import type {
FileContents,
FileDiffMetadata,
SupportedLanguages,
ThemeRegistrationResolved,
} from "@pierre/diffs";
import { RegisteredCustomThemes, parsePatchFiles } from "@pierre/diffs";
import type { FileContents, FileDiffMetadata, SupportedLanguages } from "@pierre/diffs";
import { parsePatchFiles } from "@pierre/diffs";
import { preloadFileDiff, preloadMultiFileDiff } from "@pierre/diffs/ssr";
import { ensurePierreThemesRegistered } from "./pierre-themes.js";
import type {
@ -21,45 +14,7 @@ import { VIEWER_LOADER_PATH } from "./viewer-assets.js";
const DEFAULT_FILE_NAME = "diff.txt";
const MAX_PATCH_FILE_COUNT = 128;
const MAX_PATCH_TOTAL_LINES = 120_000;
const diffsRequire = createRequire(import.meta.resolve("@pierre/diffs"));
let pierreThemesPatched = false;
function createThemeLoader(
themeName: "pierre-dark" | "pierre-light",
themePath: string,
): () => Promise<ThemeRegistrationResolved> {
let cachedTheme: ThemeRegistrationResolved | undefined;
return async () => {
if (cachedTheme) {
return cachedTheme;
}
const raw = await fs.readFile(themePath, "utf8");
const parsed = JSON.parse(raw) as Record<string, unknown>;
cachedTheme = {
...parsed,
name: themeName,
} as ThemeRegistrationResolved;
return cachedTheme;
};
}
function patchPierreThemeLoadersForNode24(): void {
if (pierreThemesPatched) {
return;
}
try {
const darkThemePath = diffsRequire.resolve("@pierre/theme/themes/pierre-dark.json");
const lightThemePath = diffsRequire.resolve("@pierre/theme/themes/pierre-light.json");
RegisteredCustomThemes.set("pierre-dark", createThemeLoader("pierre-dark", darkThemePath));
RegisteredCustomThemes.set("pierre-light", createThemeLoader("pierre-light", lightThemePath));
pierreThemesPatched = true;
} catch {
// Keep upstream loaders if theme files cannot be resolved.
}
}
patchPierreThemeLoadersForNode24();
ensurePierreThemesRegistered();
function escapeCssString(value: string): string {
return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
@ -376,7 +331,7 @@ async function renderBeforeAfterDiff(
input: Extract<DiffInput, { kind: "before_after" }>,
options: DiffRenderOptions,
): Promise<{ viewerBodyHtml: string; imageBodyHtml: string; fileCount: number }> {
await ensurePierreThemesRegistered();
ensurePierreThemesRegistered();
const fileName = resolveBeforeAfterFileName(input);
const lang = normalizeSupportedLanguage(input.lang);
@ -436,7 +391,7 @@ async function renderPatchDiff(
input: Extract<DiffInput, { kind: "patch" }>,
options: DiffRenderOptions,
): Promise<{ viewerBodyHtml: string; imageBodyHtml: string; fileCount: number }> {
await ensurePierreThemesRegistered();
ensurePierreThemesRegistered();
const files = parsePatchFiles(input.patch).flatMap((entry) => entry.files ?? []);
if (files.length === 0) {