67 lines
2.9 KiB
JavaScript
67 lines
2.9 KiB
JavaScript
/** Generate the offline KaTeX CSS/license module used by Quiz video export. */
|
|
import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { createRequire } from 'node:module';
|
|
import { fileURLToPath } from 'node:url';
|
|
import path from 'node:path';
|
|
import prettier from 'prettier';
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
const root = path.join(here, '..');
|
|
const katexDir = path.dirname(require.resolve('katex/package.json'));
|
|
const katexVersion = require('katex/package.json').version;
|
|
const sourceCss = readFileSync(path.join(katexDir, 'dist', 'katex.min.css'), 'utf8');
|
|
const license = readFileSync(path.join(katexDir, 'LICENSE'), 'utf8');
|
|
const publicFontDir = path.join(root, 'public', 'vendor', 'video-export', 'fonts');
|
|
const publicFontBase = '/vendor/video-export/fonts';
|
|
const exportFontBase = 'assets/fonts';
|
|
mkdirSync(publicFontDir, { recursive: true });
|
|
|
|
const faces = [];
|
|
const assets = [];
|
|
for (const [, body] of sourceCss.matchAll(/@font-face\{([^}]*)\}/g)) {
|
|
const woff2 = body.match(/url\(fonts\/([^)]+\.woff2)\)/);
|
|
if (!woff2) continue;
|
|
const filename = woff2[1];
|
|
copyFileSync(path.join(katexDir, 'dist', 'fonts', filename), path.join(publicFontDir, filename));
|
|
const declaration = (pattern) => body.match(pattern)?.[0] ?? '';
|
|
faces.push(
|
|
`@font-face{${declaration(/font-family:[^;]+/)};${declaration(/font-style:[^;]+/)};${declaration(/font-weight:[^;]+/)};font-display:block;src:url("__OPENMAIC_QUIZ_FONT_BASE__/${filename}") format("woff2")}`,
|
|
);
|
|
assets.push({
|
|
path: `${exportFontBase}/${filename}`,
|
|
sourceUrl: `${publicFontBase}/${filename}`,
|
|
});
|
|
}
|
|
if (faces.length !== 20) {
|
|
throw new Error(`Expected 20 KaTeX WOFF2 faces, found ${faces.length}`);
|
|
}
|
|
|
|
const rules = sourceCss.replace(/@font-face\{[^}]*\}/g, '');
|
|
const cssTemplate = `${faces.join('')}\n${rules}`;
|
|
const contents = `/**
|
|
* GENERATED FILE — do not edit by hand.
|
|
* Complete KaTeX ${katexVersion} CSS with all 20 WOFF2 fonts emitted as
|
|
* deterministic project-relative binary assets.
|
|
* Regenerate with \`pnpm gen:video-export-katex\`.
|
|
*/
|
|
const KATEX_CSS_TEMPLATE = ${JSON.stringify(cssTemplate)};
|
|
export const KATEX_MEASUREMENT_CSS = KATEX_CSS_TEMPLATE.replaceAll(
|
|
'__OPENMAIC_QUIZ_FONT_BASE__',
|
|
${JSON.stringify(publicFontBase)},
|
|
);
|
|
export const KATEX_EXPORT_CSS = KATEX_CSS_TEMPLATE.replaceAll(
|
|
'__OPENMAIC_QUIZ_FONT_BASE__',
|
|
${JSON.stringify(exportFontBase)},
|
|
);
|
|
export const KATEX_FONT_ASSETS = ${JSON.stringify(assets)} as const;
|
|
export const KATEX_MIT_LICENSE = ${JSON.stringify(license)};
|
|
`;
|
|
|
|
const outFile = path.join(root, 'lib', 'video-export', 'emit-hyperframes', 'katex-assets.ts');
|
|
const config = await prettier.resolveConfig(outFile);
|
|
writeFileSync(outFile, await prettier.format(contents, { ...config, parser: 'typescript' }));
|
|
console.log(
|
|
`[video-export-katex] emitted ${faces.length} KaTeX ${katexVersion} WOFF2 assets and complete CSS`,
|
|
);
|