Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

report unsupported macros by katex and expand user-define commands #99

Merged
merged 16 commits into from
Jun 12, 2024
Merged
42 changes: 42 additions & 0 deletions packages/unified-latex-to-pretext/libs/report-and-expand-macros.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as Ast from "@unified-latex/unified-latex-types";
import { newcommandMatcher, newcommandMacroToSubstitutionAst } from "@unified-latex/unified-latex-util-macros";
import { anyMacro, match } from "@unified-latex/unified-latex-util-match";
import { visit } from "@unified-latex/unified-latex-util-visit";
import { KATEX_SUPPORT } from "./pre-conversion-subs/katex-subs";
import { replaceNode } from "@unified-latex/unified-latex-util-replace";

/**
* Return list of macros unsupported by Katex
*/
export function report_macros(ast: Ast.Ast): string[] {
renee-k marked this conversation as resolved.
Show resolved Hide resolved
let unsupported: string[] = [];
renee-k marked this conversation as resolved.
Show resolved Hide resolved

// match a macro supported by Katex
const isSupported = match.createMacroMatcher(KATEX_SUPPORT.macros);

// visit all nodes
visit(ast, (node, info) => {
// macro in math mode
if (anyMacro(node) && info.context.hasMathModeAncestor) {
const macro_name = node.content;
renee-k marked this conversation as resolved.
Show resolved Hide resolved

// check if not supported by katex
if (!isSupported(node)) {
unsupported.push(macro_name);
}
}
});

return unsupported;
}

/**
* Expands user-defined macros
*/
export function expand_user_macros(ast: Ast.Ast): void {
renee-k marked this conversation as resolved.
Show resolved Hide resolved
replaceNode(ast, (node) => {
if (anyMacro(node) && newcommandMatcher(node)) {
return newcommandMacroToSubstitutionAst(node);
}
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { describe, it, expect } from "vitest";
import Prettier from "prettier";
import util from "util";
import { getParser } from "@unified-latex/unified-latex-util-parse";
import { report_macros, expand_user_macros } from "../libs/report-and-expand-macros";
import { printRaw } from "@unified-latex/unified-latex-util-print-raw";

// Make console.log pretty-print by default
const origLog = console.log;
console.log = (...args) => {
origLog(...args.map((x) => util.inspect(x, false, 10, true)));
};

describe("unified-latex-to-pretext:report-and-expand-macro", () => {
let value: string;

it("can reported unsupported macros", () => {
value = String.raw`$\mathbb{R} \fakemacro{X}$`;

const parser = getParser();
const ast = parser.parse(value);

expect(report_macros(ast)).toEqual(["fakemacro"]);
});

it("can report no unsupported macros in mathmode", () => {
value = String.raw`$\mathbb{R} \frac{1}{2} \cup$`;

const parser = getParser();
const ast = parser.parse(value);

expect(report_macros(ast)).toEqual([]);
});

it("can report no unsupported macros not in mathmode", () => {
renee-k marked this conversation as resolved.
Show resolved Hide resolved
value = String.raw`\underline{text} \textbf{bold} \subsection{section}`;

const parser = getParser();
const ast = parser.parse(value);

expect(report_macros(ast)).toEqual([]);
});
renee-k marked this conversation as resolved.
Show resolved Hide resolved

it("can expand newcommand", () => {
value = String.raw`\newcommand{\foo}{\bar{#1}}`;

const parser = getParser();
const ast = parser.parse(value);

expand_user_macros(ast)

expect(printRaw(ast)).toEqual("\\bar{#1}");
});
renee-k marked this conversation as resolved.
Show resolved Hide resolved

it("can expand renewcommand", () => {
value = String.raw`\renewcommand{\mathbb{N}}{\N}`;

const parser = getParser();
const ast = parser.parse(value);

expand_user_macros(ast)

expect(printRaw(ast)).toEqual("\\N");
});

it("can expand multiple user-defined commands", () => {
value = String.raw`\newcommand{\join}{\vee} \renewcommand{\vee}{\foo}`;

const parser = getParser();
const ast = parser.parse(value);

expand_user_macros(ast)

expect(printRaw(ast)).toEqual("\\vee \\foo");
});
});