diff --git a/__tests__/html2/markdown/math3.html b/__tests__/html2/markdown/math3.html
index cae136727d..cad76722ba 100644
--- a/__tests__/html2/markdown/math3.html
+++ b/__tests__/html2/markdown/math3.html
@@ -22,8 +22,7 @@
## Basic Math
-1. Simple arithmetic:
-\(2 + 2 = 4\)
+1. Simple arithmetic: \(2 + 2 = 4\)
2. Fractions:
\[\frac{1}{2} + \frac{1}{3} = \frac{5}{6}\]
@@ -83,11 +82,9 @@
## Invalid input examples
-12. Wrong expression is rendered:
-\(2++2\)
+12. Wrong expression is rendered: \(2++2\)
-13. Inline closing delimeter is required:
-\(x^2
+13. Inline closing delimeter is required: \(x^2
14. Katex syntax error:
\[\int_0^\infty e^{-x} dx = 1 +}\]
diff --git a/__tests__/html2/markdown/math3.html.snap-1.png b/__tests__/html2/markdown/math3.html.snap-1.png
index 31e802f8e3..502cff1203 100644
Binary files a/__tests__/html2/markdown/math3.html.snap-1.png and b/__tests__/html2/markdown/math3.html.snap-1.png differ
diff --git a/__tests__/html2/markdown/math3.html.snap-2.png b/__tests__/html2/markdown/math3.html.snap-2.png
index bf7c5b62ec..618d83f6da 100644
Binary files a/__tests__/html2/markdown/math3.html.snap-2.png and b/__tests__/html2/markdown/math3.html.snap-2.png differ
diff --git a/__tests__/html2/markdown/math3.html.snap-3.png b/__tests__/html2/markdown/math3.html.snap-3.png
index 2af56c96b0..c5819cc0bd 100644
Binary files a/__tests__/html2/markdown/math3.html.snap-3.png and b/__tests__/html2/markdown/math3.html.snap-3.png differ
diff --git a/packages/bundle/src/markdown/mathExtension/math.ts b/packages/bundle/src/markdown/mathExtension/math.ts
index 764f7c1535..01d0479d3d 100644
--- a/packages/bundle/src/markdown/mathExtension/math.ts
+++ b/packages/bundle/src/markdown/mathExtension/math.ts
@@ -1,20 +1,20 @@
import type { Extension } from 'micromark-util-types';
-import { BACKSLASH, DOLLAR } from './constants';
-import { createTokenizer } from './tokenizer';
+import { BACKSLASH, CLOSE_BRACKET, CLOSE_PAREN, DOLLAR, OPEN_BRACKET, OPEN_PAREN } from './constants';
+import makeConstructTokenizer from './tokenizer';
export default function math(): Extension {
- const construct = {
+ const makeConstruct = (...args: Parameters) => ({
name: 'math',
- tokenize: createTokenizer
- };
+ tokenize: makeConstructTokenizer(...args)
+ });
return {
text: {
- [BACKSLASH]: construct
+ [BACKSLASH]: makeConstruct({ OPEN_CODE: OPEN_PAREN, CLOSE_CODE: CLOSE_PAREN })
},
flow: {
- [BACKSLASH]: construct,
- [DOLLAR]: construct
+ [BACKSLASH]: makeConstruct({ OPEN_CODE: OPEN_BRACKET, CLOSE_CODE: CLOSE_BRACKET }),
+ [DOLLAR]: makeConstruct({ OPEN_CODE: DOLLAR, CLOSE_CODE: DOLLAR })
}
} as any;
}
diff --git a/packages/bundle/src/markdown/mathExtension/tokenizer.ts b/packages/bundle/src/markdown/mathExtension/tokenizer.ts
index 90c9441353..a38431e565 100644
--- a/packages/bundle/src/markdown/mathExtension/tokenizer.ts
+++ b/packages/bundle/src/markdown/mathExtension/tokenizer.ts
@@ -1,4 +1,3 @@
-/* eslint-disable no-magic-numbers */
/* eslint-disable @typescript-eslint/no-use-before-define */
import { BACKSLASH, OPEN_PAREN, CLOSE_PAREN, OPEN_BRACKET, CLOSE_BRACKET, DOLLAR } from './constants';
import { markdownLineEnding } from 'micromark-util-character';
@@ -6,88 +5,71 @@ import { type Code, type Effects, type State } from 'micromark-util-types';
type MathTokenTypes = 'math' | 'mathChunk';
+type OpenCode = typeof OPEN_BRACKET | typeof OPEN_PAREN | typeof DOLLAR;
+type CloseCode = typeof CLOSE_BRACKET | typeof CLOSE_PAREN | typeof DOLLAR;
+
type MathEffects = Omit & {
enter(type: MathTokenTypes): void;
exit(type: MathTokenTypes): void;
};
-export function createTokenizer(effects: MathEffects, ok: State, nok: State) {
- let expectedCloseDelimiter: number;
- let dollarDelimiterCount = 0;
+/**
+ * Creates a math tokenizer for specified delimiter pair
+ * @param OPEN_CODE - Opening delimiter code
+ * @param CLOSE_CODE - Closing delimiter code
+ */
+export default ({ OPEN_CODE, CLOSE_CODE }: { OPEN_CODE: OpenCode; CLOSE_CODE: CloseCode }) =>
+ function createTokenizer(effects: MathEffects, ok: State, nok: State) {
+ return start;
+
+ function start(code: Code): State {
+ if (code === BACKSLASH || (code === DOLLAR && OPEN_CODE === DOLLAR)) {
+ effects.enter('math');
+ effects.enter('mathChunk');
+ effects.consume(code);
+ return openDelimiter;
+ }
+
+ return nok(code);
+ }
- return start;
+ function openDelimiter(code: Code): State {
+ if (code !== OPEN_CODE) {
+ return nok(code);
+ }
- function start(code: Code): State {
- if (code === BACKSLASH || code === DOLLAR) {
- effects.enter('math');
- effects.enter('mathChunk');
effects.consume(code);
- dollarDelimiterCount = code === DOLLAR ? 1 : 0;
- return openDelimiter;
+ return content;
}
- return nok(code);
- }
-
- function openDelimiter(code: Code): State {
- switch (code) {
- case OPEN_PAREN:
- expectedCloseDelimiter = CLOSE_PAREN;
- break;
- case OPEN_BRACKET:
- expectedCloseDelimiter = CLOSE_BRACKET;
- break;
- case DOLLAR:
- expectedCloseDelimiter = DOLLAR;
- dollarDelimiterCount++;
- if (dollarDelimiterCount !== 2) {
- return nok(code);
- }
- break;
- default:
+ function content(code: Code): State {
+ if (code === null) {
return nok(code);
- }
- effects.consume(code);
- return content;
- }
+ }
- function content(code: Code): State {
- if (code === null) {
- return nok(code);
- }
+ if (code === BACKSLASH || (CLOSE_CODE === DOLLAR && code === DOLLAR)) {
+ effects.consume(code);
+ return maybeCloseDelimiter;
+ }
- if (code === BACKSLASH || (dollarDelimiterCount && code === DOLLAR)) {
effects.consume(code);
- code === DOLLAR && dollarDelimiterCount--;
- return maybeCloseDelimiter;
- }
- effects.consume(code);
+ if (markdownLineEnding(code)) {
+ effects.exit('mathChunk');
+ effects.enter('mathChunk');
+ }
- if (markdownLineEnding(code)) {
- effects.exit('mathChunk');
- effects.enter('mathChunk');
+ return content;
}
- return content;
- }
-
- function maybeCloseDelimiter(code: Code): State {
- if (code === expectedCloseDelimiter) {
- code === DOLLAR && dollarDelimiterCount--;
- if (dollarDelimiterCount !== 0) {
- return nok(code);
+ function maybeCloseDelimiter(code: Code): State {
+ if (code === CLOSE_CODE) {
+ effects.consume(code);
+ effects.exit('mathChunk');
+ effects.exit('math');
+ return ok;
}
- effects.consume(code);
- effects.exit('mathChunk');
- effects.exit('math');
-
- dollarDelimiterCount = 0;
- expectedCloseDelimiter = undefined;
- return ok;
+ return content(code);
}
-
- return content(code);
- }
-}
+ };