CODEBASE: Generate display data for math notation at built time and remove runtime mathjax dependency (#2447)

This commit is contained in:
catloversg
2026-01-18 05:41:24 +07:00
committed by GitHub
parent be16b2a375
commit c8e3eb2050
25 changed files with 910 additions and 584 deletions

View File

@@ -0,0 +1,46 @@
import { readFileSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import remarkMath from "remark-math";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import { unified } from "unified";
import { createPlugin } from "../../src/ThirdParty/RehypePlugin.mjs";
import { convertToMML, walkDir } from "./utils.mjs";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const data = {};
const parser = unified().use(remarkParse).use(remarkMath);
const tool = unified()
.use(remarkRehype)
.use(
createPlugin(function () {
return {
render(value) {
data[value] = convertToMML(value);
return [];
},
};
}),
);
function processDir(dir) {
walkDir(dir, (filePath) => {
tool.runSync(parser.parse(readFileSync(filePath)));
});
}
processDir(resolve(__dirname, "../../src/Documentation/doc/en"));
const notationInput = JSON.parse(readFileSync(resolve(__dirname, "../../src/Documentation/data/MathNotation.json")));
for (const value of Object.values(notationInput)) {
data[value] = convertToMML(value);
}
console.log(`Generated MathML data for ${Object.keys(data).length} notation entries`);
writeFileSync(resolve(__dirname, "../../src/Documentation/data/MathNotationOutput.json"), JSON.stringify(data), {
encoding: "utf-8",
});

View File

@@ -1,27 +1,25 @@
const fs = require("fs");
const path = require("path");
import { writeFileSync } from "node:fs";
import { dirname, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { walkDir } from "./utils.mjs";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const docFiles = [];
const nsDocFiles = [];
const docImagesFiles = [];
const docRoot = path.resolve(__dirname, "../../src/Documentation/doc");
const markdownRoot = path.resolve(__dirname, "../../markdown");
const docImagesRoot = path.resolve(__dirname, "../../src/Documentation/images");
const addFileToListOfDocPages = (files, root, filePath) => {
const docRoot = resolve(__dirname, "../../src/Documentation/doc");
const markdownRoot = resolve(__dirname, "../../markdown");
const docImagesRoot = resolve(__dirname, "../../src/Documentation/images");
function addFileToListOfDocPages(files, root, filePath) {
// Windows path uses "\", so we need to replace it with "/".
files.push(path.relative(root, filePath).replace(/\\/g, "/"));
};
const processDir = (dir) => {
if (!fs.existsSync(dir)) {
return;
}
console.log(dir);
for (const file of fs.readdirSync(dir).sort((a, b) => a.localeCompare(b, "en-US"))) {
const filePath = path.join(dir, file);
if (fs.lstatSync(filePath).isDirectory()) {
processDir(filePath);
continue;
}
files.push(relative(root, filePath).replace(/\\/g, "/"));
}
function processDir(dir) {
walkDir(dir, (filePath) => {
if (filePath.startsWith(docRoot)) {
addFileToListOfDocPages(docFiles, docRoot, filePath);
} else if (filePath.startsWith(markdownRoot)) {
@@ -29,8 +27,8 @@ const processDir = (dir) => {
} else {
addFileToListOfDocPages(docImagesFiles, docImagesRoot, filePath);
}
}
};
});
}
processDir(docRoot);
processDir(markdownRoot);
@@ -68,9 +66,4 @@ export const nsApiPages = Object.keys(AllPages)
export const DocImages: Record<string, string> = {};
${docImagesFiles.map((f) => `DocImages["${f}"] = docImages_${f.replaceAll(/\.|-/g, "_")};\n`).join("")}`;
fs.writeFile(path.resolve(__dirname, "../../src/Documentation/pages.ts"), autogeneratedContent, (err) => {
if (err) {
console.error(err);
}
// file written successfully
});
writeFileSync(resolve(__dirname, "../../src/Documentation/pages.ts"), autogeneratedContent, { encoding: "utf-8" });

View File

@@ -0,0 +1,63 @@
import { existsSync, lstatSync, readdirSync } from "node:fs";
import { join } from "node:path";
import { mathjax } from "@mathjax/src/js/mathjax.js";
import { TeX } from "@mathjax/src/js/input/tex.js";
import { liteAdaptor } from "@mathjax/src/js/adaptors/liteAdaptor.js";
import { RegisterHTMLHandler } from "@mathjax/src/js/handlers/html.js";
import "@mathjax/src/js/util/asyncLoad/esm.js";
import { SerializedMmlVisitor } from "@mathjax/src/js/core/MmlTree/SerializedMmlVisitor.js";
import "@mathjax/src/js/input/tex/base/BaseConfiguration.js";
import "@mathjax/src/js/input/tex/ams/AmsConfiguration.js";
import "@mathjax/src/js/input/tex/newcommand/NewcommandConfiguration.js";
import "@mathjax/src/js/input/tex/noundefined/NoUndefinedConfiguration.js";
import xmlFormat from "xml-formatter";
export function walkDir(dir, callback) {
if (!existsSync(dir)) {
return;
}
console.log(`Processing ${dir}`);
for (const file of readdirSync(dir).sort((a, b) => a.localeCompare(b, "en-US"))) {
const filePath = join(dir, file);
if (lstatSync(filePath).isDirectory()) {
walkDir(filePath, callback);
continue;
}
callback(filePath);
}
}
const adaptor = liteAdaptor();
RegisterHTMLHandler(adaptor);
const tex = new TeX({
packages: ["base", "ams", "newcommand", "noundefined"],
formatError(jax, err) {
console.error(jax, err);
process.exit(1);
},
});
const visitor = new SerializedMmlVisitor();
const docMML = mathjax.document("", { InputJax: tex });
export function convertToMML(value) {
const node = docMML.convert(value, {
// Do not set "display" css property. The display mode will be decided by the rehype plugin.
display: false,
});
node.walkTree((node) => {
const attributes = node.attributes;
// Remove unnecessary attributes.
attributes.unset("data-latex");
attributes.unset("data-latex-item");
});
const mathJaxOutput = visitor.visitTree(node, docMML);
return xmlFormat.minify(mathJaxOutput, {
filter: (node) => node.type !== "Comment",
collapseContent: true,
});
}

View File

@@ -13,12 +13,16 @@ rm input/bitburner.api.json && rm -r input
echo ""
echo "Bundling ingame documentation..."
node tools/bundle-doc/index.js
node tools/bundle-doc/index.mjs
echo ""
echo "Add generated docs to git..."
# This git add is needed due to documenter using wrong line endings. Console spam discarded.
git add markdown/ 2> /dev/null && git add tsdoc-metadata.json 2> /dev/null
echo ""
echo "Generate math notation output..."
node tools/bundle-doc/generate-math-notation-output.mjs
echo ""
echo "Documentation build completed."