This commit is contained in:
Morten Olsen
2023-03-26 22:15:07 +02:00
commit 9b1a067d56
80 changed files with 7889 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
import { resolve } from "path";
import { decode } from "html-entities";
import { marked } from "marked";
import remark from "remark";
import visit from "unist-util-visit";
import { Bundler } from "../../bundler";
import { createImage } from "../../resources/image";
import { renderer } from "./latex";
type MarkdownBundleImagesOptions = {
cwd: string;
content: string;
bundler: Bundler;
};
const markdownBundleImages = async ({
bundler,
cwd,
content,
}: MarkdownBundleImagesOptions) => {
const result = await remark()
.use(() => (tree) => {
visit(tree, "image", (node) => {
if (!("url" in node)) {
return;
}
const url = node.url as string;
const path = resolve(cwd, url);
const image = createImage({
image: path,
bundler,
format: "webp",
});
const newUrl = image;
node.url = newUrl;
});
})
.process(content);
return String(result);
};
type MarkdownToLatexOptions = {
root: string;
content: string;
};
const markdownToLatex = ({ root, content }: MarkdownToLatexOptions) => {
const render: any = {
...renderer(0),
};
const latex = marked(content, {
renderer: render,
});
return decode(latex);
};
export { markdownBundleImages, markdownToLatex };

View File

@@ -0,0 +1,91 @@
import { decode } from "html-entities";
import { existsSync } from "fs";
const latexTypes = ["", "section", "subsection", "paragraph", "subparagraph"];
const sanitize = (text?: string) => {
if (!text) {
return "";
}
return decode(text)
.replace("&", "\\&")
.replace("_", "\\_")
.replace(/([^\\])\}/g, "$1\\}")
.replace(/([^\\])\{/g, "$1\\{")
.replace(/[^\\]\[/g, "\\[")
.replace(/#/g, "\\#");
};
type Renderer = (depth: number) => {
heading?: (text: string, depth: number) => string;
code?: (input: string) => string;
text?: (input: string) => string;
paragraph?: (input: string) => string;
list?: (input: string) => string;
listitem?: (input: string) => string;
link?: (href: string, text: string) => string;
strong?: (text: string) => string;
em?: (text: string) => string;
codespan?: (code: string) => string;
image?: (link: string) => string;
};
const renderer = (outerDepth: number) => ({
heading: (text: string, depth: number) => {
return `\\${latexTypes[outerDepth + depth]}{${sanitize(text)}}\n\n`;
},
code: (input: string) => {
return `
\\begin{lstlisting}
${input}
\\end{lstlisting}
`;
},
text: (input: string) => {
return sanitize(input);
},
blockquote: (input: string) => {
return sanitize(input);
},
paragraph: (input: string) => {
return `${input}\n\n`;
},
list: (input: string) => {
return `
\\begin{itemize}
${input}
\\end{itemize}
`;
},
listitem: (input: string) => {
return `\\item{${input}}`;
},
link: (href: string, text: string) => {
if (!text || text === href) {
return `\\url{${sanitize(href)}}`;
}
return `${sanitize(text)} (\\url{${sanitize(href)}})`;
},
strong: (text: string) => {
return `\\textbf{${sanitize(text)}}`;
},
em: (text: string) => {
return `\\textbf{${sanitize(text)}}`;
},
codespan: (code: string) => {
return `\\texttt{${sanitize(code)}}`;
},
image: (link: string) => {
if (!existsSync(link)) {
return "Online image not supported";
}
return `\\begin{figure}[h!]
\\includegraphics[width=0.5\\textwidth]{${link}}
\\centering
\\end{figure}
`;
},
});
export type { Renderer };
export { sanitize, renderer };

View File

@@ -0,0 +1,27 @@
import { Observable } from "../../observable";
const forEach = async <T extends Observable<any[]>>(
observable: T,
fn: (
value: T extends Observable<infer U>
? U extends Array<infer A>
? A
: never
: never
) => Promise<void>
) => {
const knownValues = new Set();
const update = async () => {
for (let value of await observable.data) {
if (knownValues.has(value)) {
continue;
}
await fn(value);
knownValues.add(value);
}
};
await update();
observable.subscribe(update);
};
export { forEach };