@temelj/mdx 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mod.d.mts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { HastElement as Element, HastNode as Node } from "./types.mjs";
2
2
  import { MdxArtifact, MdxCompileError, MdxCompileOptions, MdxCompiler, MdxMessage, MdxMessagePlace, MdxMessagePoint, MdxSource, remarkFrontmatterPlugin, remarkGfmPlugin } from "./compiler.mjs";
3
3
  import { HeadingIdPluginOptions, headingIdPlugin } from "./plugins/heading-id/plugin.mjs";
4
+ import { InlineMathStyle, KatexPluginOptions, katexPlugin } from "./plugins/katex/plugin.mjs";
4
5
  import { removeImportsExportsPlugin } from "./plugins/remove-imports-exports.mjs";
5
6
  import { SyntaxHighlightPluginOptions, syntaxHighlightPlugin } from "./plugins/syntax-highlight/plugin.mjs";
6
7
  import { MdxTreeProcessor, treeProcessorPlugin } from "./plugins/tree-processor/plugin.mjs";
7
8
  import "./plugins/mod.mjs";
8
- export { type Element as HastElement, type Node as HastNode, HeadingIdPluginOptions, MdxArtifact, MdxCompileError, MdxCompileOptions, MdxCompiler, MdxMessage, MdxMessagePlace, MdxMessagePoint, MdxSource, MdxTreeProcessor, SyntaxHighlightPluginOptions, headingIdPlugin, remarkFrontmatterPlugin, remarkGfmPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
9
+ export { type Element as HastElement, type Node as HastNode, HeadingIdPluginOptions, InlineMathStyle, KatexPluginOptions, MdxArtifact, MdxCompileError, MdxCompileOptions, MdxCompiler, MdxMessage, MdxMessagePlace, MdxMessagePoint, MdxSource, MdxTreeProcessor, SyntaxHighlightPluginOptions, headingIdPlugin, katexPlugin, remarkFrontmatterPlugin, remarkGfmPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
package/dist/mod.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { MdxCompileError, MdxCompiler, remarkFrontmatterPlugin, remarkGfmPlugin } from "./compiler.mjs";
2
2
  import { headingIdPlugin } from "./plugins/heading-id/plugin.mjs";
3
+ import { katexPlugin } from "./plugins/katex/plugin.mjs";
3
4
  import { removeImportsExportsPlugin } from "./plugins/remove-imports-exports.mjs";
4
5
  import { syntaxHighlightPlugin } from "./plugins/syntax-highlight/plugin.mjs";
5
6
  import { treeProcessorPlugin } from "./plugins/tree-processor/plugin.mjs";
6
7
  import "./plugins/mod.mjs";
7
- export { MdxCompileError, MdxCompiler, headingIdPlugin, remarkFrontmatterPlugin, remarkGfmPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
8
+ export { MdxCompileError, MdxCompiler, headingIdPlugin, katexPlugin, remarkFrontmatterPlugin, remarkGfmPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
@@ -0,0 +1,39 @@
1
+ import { HastNode as Node } from "../../types.mjs";
2
+ import { KatexOptions } from "katex";
3
+ import { Plugin } from "unified";
4
+ //#region src/plugins/katex/plugin.d.ts
5
+ declare const inlineMathStyleCommands: {
6
+ readonly display: string;
7
+ readonly script: string;
8
+ readonly scriptscript: string;
9
+ readonly text: string;
10
+ };
11
+ type KatexRenderOptions = Omit<KatexOptions, "displayMode" | "throwOnError">;
12
+ /**
13
+ * TeX math style applied to inline math.
14
+ *
15
+ * `"auto"` preserves the source and KaTeX's default style.
16
+ */
17
+ type InlineMathStyle = "auto" | keyof typeof inlineMathStyleCommands;
18
+ /**
19
+ * KaTeX options controlled by callers. Rendering mode and error handling are
20
+ * inferred and enforced by the plugin.
21
+ */
22
+ type KatexPluginOptions = KatexRenderOptions & {
23
+ /**
24
+ * TeX math style applied to inline-math nodes.
25
+ *
26
+ * Display and fenced math are not affected.
27
+ *
28
+ * @default "auto"
29
+ */
30
+ inlineMathStyle?: InlineMathStyle;
31
+ };
32
+ /**
33
+ * Renders HAST elements marked as inline, display, or fenced-code math with
34
+ * KaTeX.
35
+ */
36
+ declare const katexPlugin: Plugin<[Readonly<KatexPluginOptions>?], Node, Node>;
37
+ //#endregion
38
+ export { InlineMathStyle, KatexPluginOptions, katexPlugin };
39
+ //# sourceMappingURL=plugin.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.mts","names":[],"sources":["../../../src/plugins/katex/plugin.ts"],"mappings":";;;;cAgBM;WACJ;WACA;WACA;WACA;;KAGG,qBAAqB,KAAK;;;;;;KAOnB,wCAAwC;;;;;KAMxC,qBAAqB;;;;;;;;EAQ/B,kBAAkB;;;;;;cAOP,aAAa,QAAQ,SAAS,uBAAuB,MAAU"}
@@ -0,0 +1,107 @@
1
+ import { fromHtmlIsomorphic } from "hast-util-from-html-isomorphic";
2
+ import { toText } from "hast-util-to-text";
3
+ import katex from "katex";
4
+ import { SKIP, visitParents } from "unist-util-visit-parents";
5
+ //#region src/plugins/katex/plugin.ts
6
+ const mathClasses = {
7
+ display: "math-display",
8
+ inline: "math-inline",
9
+ language: "language-math"
10
+ };
11
+ const inlineMathStyleCommands = {
12
+ display: String.raw`\displaystyle`,
13
+ script: String.raw`\scriptstyle`,
14
+ scriptscript: String.raw`\scriptscriptstyle`,
15
+ text: String.raw`\textstyle`
16
+ };
17
+ /**
18
+ * Renders HAST elements marked as inline, display, or fenced-code math with
19
+ * KaTeX.
20
+ */
21
+ const katexPlugin = (options = {}) => {
22
+ const { inlineMathStyle = "auto", ...katexOptions } = options;
23
+ return (tree, file) => {
24
+ visitParents(tree, "element", (element, ancestors) => {
25
+ const classes = Array.isArray(element.properties.className) ? element.properties.className : [];
26
+ const isLanguageMath = classes.includes(mathClasses.language);
27
+ const isDisplayMath = classes.includes(mathClasses.display);
28
+ const isInlineMath = classes.includes(mathClasses.inline);
29
+ if (!isLanguageMath && !isDisplayMath && !isInlineMath) return;
30
+ let scope = element;
31
+ let parent = ancestors.at(-1);
32
+ let displayMode = isDisplayMath;
33
+ if (element.tagName === "code" && isLanguageMath && parent?.type === "element" && parent.tagName === "pre") {
34
+ scope = parent;
35
+ parent = ancestors.at(-2);
36
+ displayMode = true;
37
+ }
38
+ if (parent === void 0 || parent.type !== "element" && parent.type !== "root") return;
39
+ const value = toText(scope, { whitespace: "pre" });
40
+ const renderedValue = isInlineMath && !displayMode ? applyInlineMathStyle(value, inlineMathStyle) : value;
41
+ let result;
42
+ try {
43
+ result = renderMath(renderedValue, katexOptions, displayMode);
44
+ } catch (error) {
45
+ const cause = getOriginalRenderError(value, katexOptions, displayMode, error);
46
+ file.message("Could not render math with KaTeX", {
47
+ ancestors: [...ancestors, element],
48
+ cause,
49
+ place: element.position,
50
+ ruleId: cause.name.toLowerCase(),
51
+ source: "rehype-katex"
52
+ });
53
+ try {
54
+ result = renderMath(value, {
55
+ ...katexOptions,
56
+ strict: "ignore"
57
+ }, displayMode, false);
58
+ } catch {
59
+ result = [{
60
+ type: "element",
61
+ tagName: "span",
62
+ properties: {
63
+ className: ["katex-error"],
64
+ style: `color:${katexOptions.errorColor ?? "#cc0000"}`,
65
+ title: String(cause)
66
+ },
67
+ children: [{
68
+ type: "text",
69
+ value
70
+ }]
71
+ }];
72
+ }
73
+ }
74
+ const index = parent.children.indexOf(scope);
75
+ if (index !== -1) parent.children.splice(index, 1, ...result);
76
+ return SKIP;
77
+ });
78
+ return tree;
79
+ };
80
+ };
81
+ function getOriginalRenderError(value, options, displayMode, styledError) {
82
+ try {
83
+ katex.renderToString(value, {
84
+ ...options,
85
+ displayMode,
86
+ throwOnError: true
87
+ });
88
+ } catch (error) {
89
+ return error instanceof Error ? error : new Error(String(error));
90
+ }
91
+ return styledError instanceof Error ? styledError : new Error(String(styledError));
92
+ }
93
+ function applyInlineMathStyle(value, style) {
94
+ if (style === "auto") return value;
95
+ return `{${inlineMathStyleCommands[style]} ${value}}`;
96
+ }
97
+ function renderMath(value, options, displayMode, throwOnError = true) {
98
+ return fromHtmlIsomorphic(katex.renderToString(value, {
99
+ ...options,
100
+ displayMode,
101
+ throwOnError
102
+ }), { fragment: true }).children;
103
+ }
104
+ //#endregion
105
+ export { katexPlugin };
106
+
107
+ //# sourceMappingURL=plugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../../../src/plugins/katex/plugin.ts"],"sourcesContent":["import type { Element, ElementContent, Root } from \"hast\";\nimport type { Plugin } from \"unified\";\n\nimport { fromHtmlIsomorphic } from \"hast-util-from-html-isomorphic\";\nimport { toText } from \"hast-util-to-text\";\nimport katex, { type KatexOptions } from \"katex\";\nimport { SKIP, visitParents } from \"unist-util-visit-parents\";\n\nimport type { HastNode } from \"../../types\";\n\nconst mathClasses = {\n display: \"math-display\",\n inline: \"math-inline\",\n language: \"language-math\",\n} as const;\n\nconst inlineMathStyleCommands = {\n display: String.raw`\\displaystyle`,\n script: String.raw`\\scriptstyle`,\n scriptscript: String.raw`\\scriptscriptstyle`,\n text: String.raw`\\textstyle`,\n} as const;\n\ntype KatexRenderOptions = Omit<KatexOptions, \"displayMode\" | \"throwOnError\">;\n\n/**\n * TeX math style applied to inline math.\n *\n * `\"auto\"` preserves the source and KaTeX's default style.\n */\nexport type InlineMathStyle = \"auto\" | keyof typeof inlineMathStyleCommands;\n\n/**\n * KaTeX options controlled by callers. Rendering mode and error handling are\n * inferred and enforced by the plugin.\n */\nexport type KatexPluginOptions = KatexRenderOptions & {\n /**\n * TeX math style applied to inline-math nodes.\n *\n * Display and fenced math are not affected.\n *\n * @default \"auto\"\n */\n inlineMathStyle?: InlineMathStyle;\n};\n\n/**\n * Renders HAST elements marked as inline, display, or fenced-code math with\n * KaTeX.\n */\nexport const katexPlugin: Plugin<[Readonly<KatexPluginOptions>?], HastNode, HastNode> = (\n options = {},\n) => {\n const { inlineMathStyle = \"auto\", ...katexOptions } = options;\n\n return (tree, file) => {\n visitParents(tree as Root, \"element\", (element, ancestors) => {\n const classes = Array.isArray(element.properties.className)\n ? element.properties.className\n : [];\n const isLanguageMath = classes.includes(mathClasses.language);\n const isDisplayMath = classes.includes(mathClasses.display);\n const isInlineMath = classes.includes(mathClasses.inline);\n\n if (!isLanguageMath && !isDisplayMath && !isInlineMath) {\n return;\n }\n\n let scope: Element = element;\n let parent = ancestors.at(-1);\n let displayMode = isDisplayMath;\n\n if (\n element.tagName === \"code\" &&\n isLanguageMath &&\n parent?.type === \"element\" &&\n parent.tagName === \"pre\"\n ) {\n scope = parent;\n parent = ancestors.at(-2);\n displayMode = true;\n }\n\n if (parent === undefined || (parent.type !== \"element\" && parent.type !== \"root\")) {\n return;\n }\n\n const value = toText(scope, { whitespace: \"pre\" });\n const renderedValue =\n isInlineMath && !displayMode ? applyInlineMathStyle(value, inlineMathStyle) : value;\n let result: ElementContent[];\n\n try {\n result = renderMath(renderedValue, katexOptions, displayMode);\n } catch (error) {\n const cause = getOriginalRenderError(value, katexOptions, displayMode, error);\n\n file.message(\"Could not render math with KaTeX\", {\n ancestors: [...ancestors, element],\n cause,\n place: element.position,\n ruleId: cause.name.toLowerCase(),\n source: \"rehype-katex\",\n });\n\n try {\n result = renderMath(value, { ...katexOptions, strict: \"ignore\" }, displayMode, false);\n } catch {\n result = [\n {\n type: \"element\",\n tagName: \"span\",\n properties: {\n className: [\"katex-error\"],\n style: `color:${katexOptions.errorColor ?? \"#cc0000\"}`,\n title: String(cause),\n },\n children: [{ type: \"text\", value }],\n },\n ];\n }\n }\n\n const index = parent.children.indexOf(scope);\n if (index !== -1) {\n parent.children.splice(index, 1, ...result);\n }\n\n return SKIP;\n });\n\n return tree;\n };\n};\n\nfunction getOriginalRenderError(\n value: string,\n options: Readonly<KatexRenderOptions>,\n displayMode: boolean,\n styledError: unknown,\n): Error {\n try {\n katex.renderToString(value, {\n ...options,\n displayMode,\n throwOnError: true,\n });\n } catch (error) {\n return error instanceof Error ? error : new Error(String(error));\n }\n\n return styledError instanceof Error ? styledError : new Error(String(styledError));\n}\n\nfunction applyInlineMathStyle(value: string, style: InlineMathStyle): string {\n if (style === \"auto\") {\n return value;\n }\n\n return `{${inlineMathStyleCommands[style]} ${value}}`;\n}\n\nfunction renderMath(\n value: string,\n options: Readonly<KatexRenderOptions>,\n displayMode: boolean,\n throwOnError = true,\n): ElementContent[] {\n const html = katex.renderToString(value, {\n ...options,\n displayMode,\n throwOnError,\n });\n const root = fromHtmlIsomorphic(html, { fragment: true });\n\n // KaTeX emits an HTML fragment and therefore cannot produce doctypes.\n return root.children as ElementContent[];\n}\n"],"mappings":";;;;;AAUA,MAAM,cAAc;CAClB,SAAS;CACT,QAAQ;CACR,UAAU;AACZ;AAEA,MAAM,0BAA0B;CAC9B,SAAS,OAAO,GAAG;CACnB,QAAQ,OAAO,GAAG;CAClB,cAAc,OAAO,GAAG;CACxB,MAAM,OAAO,GAAG;AAClB;;;;;AA8BA,MAAa,eACX,UAAU,CAAC,MACR;CACH,MAAM,EAAE,kBAAkB,QAAQ,GAAG,iBAAiB;CAEtD,QAAQ,MAAM,SAAS;EACrB,aAAa,MAAc,YAAY,SAAS,cAAc;GAC5D,MAAM,UAAU,MAAM,QAAQ,QAAQ,WAAW,SAAS,IACtD,QAAQ,WAAW,YACnB,CAAC;GACL,MAAM,iBAAiB,QAAQ,SAAS,YAAY,QAAQ;GAC5D,MAAM,gBAAgB,QAAQ,SAAS,YAAY,OAAO;GAC1D,MAAM,eAAe,QAAQ,SAAS,YAAY,MAAM;GAExD,IAAI,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,cACxC;GAGF,IAAI,QAAiB;GACrB,IAAI,SAAS,UAAU,GAAG,EAAE;GAC5B,IAAI,cAAc;GAElB,IACE,QAAQ,YAAY,UACpB,kBACA,QAAQ,SAAS,aACjB,OAAO,YAAY,OACnB;IACA,QAAQ;IACR,SAAS,UAAU,GAAG,EAAE;IACxB,cAAc;GAChB;GAEA,IAAI,WAAW,KAAA,KAAc,OAAO,SAAS,aAAa,OAAO,SAAS,QACxE;GAGF,MAAM,QAAQ,OAAO,OAAO,EAAE,YAAY,MAAM,CAAC;GACjD,MAAM,gBACJ,gBAAgB,CAAC,cAAc,qBAAqB,OAAO,eAAe,IAAI;GAChF,IAAI;GAEJ,IAAI;IACF,SAAS,WAAW,eAAe,cAAc,WAAW;GAC9D,SAAS,OAAO;IACd,MAAM,QAAQ,uBAAuB,OAAO,cAAc,aAAa,KAAK;IAE5E,KAAK,QAAQ,oCAAoC;KAC/C,WAAW,CAAC,GAAG,WAAW,OAAO;KACjC;KACA,OAAO,QAAQ;KACf,QAAQ,MAAM,KAAK,YAAY;KAC/B,QAAQ;IACV,CAAC;IAED,IAAI;KACF,SAAS,WAAW,OAAO;MAAE,GAAG;MAAc,QAAQ;KAAS,GAAG,aAAa,KAAK;IACtF,QAAQ;KACN,SAAS,CACP;MACE,MAAM;MACN,SAAS;MACT,YAAY;OACV,WAAW,CAAC,aAAa;OACzB,OAAO,SAAS,aAAa,cAAc;OAC3C,OAAO,OAAO,KAAK;MACrB;MACA,UAAU,CAAC;OAAE,MAAM;OAAQ;MAAM,CAAC;KACpC,CACF;IACF;GACF;GAEA,MAAM,QAAQ,OAAO,SAAS,QAAQ,KAAK;GAC3C,IAAI,UAAU,IACZ,OAAO,SAAS,OAAO,OAAO,GAAG,GAAG,MAAM;GAG5C,OAAO;EACT,CAAC;EAED,OAAO;CACT;AACF;AAEA,SAAS,uBACP,OACA,SACA,aACA,aACO;CACP,IAAI;EACF,MAAM,eAAe,OAAO;GAC1B,GAAG;GACH;GACA,cAAc;EAChB,CAAC;CACH,SAAS,OAAO;EACd,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;CACjE;CAEA,OAAO,uBAAuB,QAAQ,cAAc,IAAI,MAAM,OAAO,WAAW,CAAC;AACnF;AAEA,SAAS,qBAAqB,OAAe,OAAgC;CAC3E,IAAI,UAAU,QACZ,OAAO;CAGT,OAAO,IAAI,wBAAwB,OAAO,GAAG,MAAM;AACrD;AAEA,SAAS,WACP,OACA,SACA,aACA,eAAe,MACG;CASlB,OAHa,mBALA,MAAM,eAAe,OAAO;EACvC,GAAG;EACH;EACA;CACF,CACmC,GAAG,EAAE,UAAU,KAAK,CAG7C,CAAC,CAAC;AACd"}
@@ -1,5 +1,6 @@
1
1
  import { HeadingIdPluginOptions, headingIdPlugin } from "./heading-id/plugin.mjs";
2
+ import { InlineMathStyle, KatexPluginOptions, katexPlugin } from "./katex/plugin.mjs";
2
3
  import { removeImportsExportsPlugin } from "./remove-imports-exports.mjs";
3
4
  import { SyntaxHighlightPluginOptions, syntaxHighlightPlugin } from "./syntax-highlight/plugin.mjs";
4
5
  import { MdxTreeProcessor, treeProcessorPlugin } from "./tree-processor/plugin.mjs";
5
- export { HeadingIdPluginOptions, MdxTreeProcessor, SyntaxHighlightPluginOptions, headingIdPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
6
+ export { HeadingIdPluginOptions, InlineMathStyle, KatexPluginOptions, MdxTreeProcessor, SyntaxHighlightPluginOptions, headingIdPlugin, katexPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
@@ -1,5 +1,6 @@
1
1
  import { headingIdPlugin } from "./heading-id/plugin.mjs";
2
+ import { katexPlugin } from "./katex/plugin.mjs";
2
3
  import { removeImportsExportsPlugin } from "./remove-imports-exports.mjs";
3
4
  import { syntaxHighlightPlugin } from "./syntax-highlight/plugin.mjs";
4
5
  import { treeProcessorPlugin } from "./tree-processor/plugin.mjs";
5
- export { headingIdPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
6
+ export { headingIdPlugin, katexPlugin, removeImportsExportsPlugin, syntaxHighlightPlugin, treeProcessorPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temelj/mdx",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "MDX processing utilities.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -25,8 +25,10 @@
25
25
  "@types/hast": "^3.0.5",
26
26
  "github-slugger": "^2.0.0",
27
27
  "hast": "^1.0.0",
28
+ "hast-util-from-html-isomorphic": "^2.0.0",
28
29
  "hast-util-to-string": "^3.0.1",
29
- "rehype-katex": "^7.0.1",
30
+ "hast-util-to-text": "^4.0.2",
31
+ "katex": "^0.18.1",
30
32
  "remark-frontmatter": "^5.0.0",
31
33
  "remark-gfm": "^4.0.1",
32
34
  "remark-math": "^6.0.0",
@@ -35,6 +37,7 @@
35
37
  "unified": "^11.0.5",
36
38
  "unist-util-remove": "^4.0.0",
37
39
  "unist-util-visit": "^5.1.0",
40
+ "unist-util-visit-parents": "^6.0.2",
38
41
  "vfile": "^6.0.3",
39
42
  "vfile-matter": "^5.0.1",
40
43
  "@temelj/iterator": "0.13.0",