Skip to content

Commit

Permalink
Switch math parsing library to katex (#1801)
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelfangjw committed Jun 18, 2021
1 parent 39798d1 commit 558f213
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 157 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"ag-grid-community": "^25.3.0",
"ag-grid-react": "^25.3.0",
"array-move": "^3.0.1",
"better-react-mathjax": "^1.0.2",
"classnames": "^2.3.1",
"connected-react-router": "^6.9.1",
"flexboxgrid": "^6.3.1",
Expand All @@ -67,6 +66,7 @@
"react-dropzone": "^11.3.2",
"react-hotkeys": "^2.0.0",
"react-konva": "^17.0.2-4",
"react-latex-next": "^2.0.0",
"react-mde": "^11.5.0",
"react-redux": "^7.2.4",
"react-responsive": "^8.2.0",
Expand Down
11 changes: 5 additions & 6 deletions src/features/sicp/parser/ParseJson.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const handleEpigraph = (obj: JsonType, refs: React.MutableRefObject<{}>) => {

const handleSnippet = (obj: JsonType) => {
if (obj['latex']) {
return <Pre>{handleLatex(obj['body']!, false)}</Pre>;
return <Pre>{handleLatex(obj['body']!)}</Pre>;
} else if (typeof obj['eval'] === 'boolean' && !obj['eval']) {
return <Pre>{obj['body']}</Pre>;
} else {
Expand Down Expand Up @@ -179,8 +179,8 @@ const handleText = (text: string) => {
return <p>{text}</p>;
};

const handleLatex = (math: string, inline: boolean) => {
return <SicpLatex inline={inline} math={math} />;
const handleLatex = (math: string) => {
return <SicpLatex math={math} />;
};

export const processingFunctions = {
Expand Down Expand Up @@ -210,10 +210,9 @@ export const processingFunctions = {
<Code>{obj['body']}</Code>
),

LATEX: (obj: JsonType, _refs: React.MutableRefObject<{}>) => handleLatex(obj['body']!, false),
LATEX: (obj: JsonType, _refs: React.MutableRefObject<{}>) => handleLatex(obj['body']!),

LATEXINLINE: (obj: JsonType, _refs: React.MutableRefObject<{}>) =>
handleLatex(obj['body']!, true),
LATEXINLINE: (obj: JsonType, _refs: React.MutableRefObject<{}>) => handleLatex(obj['body']!),

LI: (obj: JsonType, refs: React.MutableRefObject<{}>) => <li>{parseArr(obj['child']!, refs)}</li>,

Expand Down
25 changes: 11 additions & 14 deletions src/features/sicp/parser/__tests__/ParseJson.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { MathJaxContext } from 'better-react-mathjax';
import { mount, shallow } from 'enzyme';
import lzString from 'lz-string';
import { mathjaxConfig } from 'src/pages/sicp/Sicp';
import { CodeSnippetProps } from 'src/pages/sicp/subcomponents/CodeSnippet';

import { JsonType, parseArr, ParseJsonError, parseObj, processingFunctions } from '../ParseJson';

Expand Down Expand Up @@ -31,6 +30,10 @@ jest.mock('src/commons/utils/Constants', () => ({
interactiveSicpDataUrl: 'https://source-academy.github.io/sicp/'
}));

jest.mock('src/pages/sicp/subcomponents/CodeSnippet', () => {
return (props: CodeSnippetProps) => <div {...props}>Code Snippet</div>;
});

const mockData = {
text: {
tag: textTag,
Expand All @@ -44,21 +47,15 @@ const mockData = {

const mockRef = { current: {} };

const processTag = (tag: string, obj: JsonType, math: boolean) => {
const processTag = (tag: string, obj: JsonType) => {
obj['tag'] = tag;

return math ? (
<MathJaxContext version={3} config={mathjaxConfig}>
{processingFunctions[tag](obj, mockRef)}
</MathJaxContext>
) : (
processingFunctions[tag](obj, mockRef)
);
return processingFunctions[tag](obj, mockRef);
};

const testTagSuccessful = (obj: JsonType, tag: string, text: string = '', math = false) => {
const testTagSuccessful = (obj: JsonType, tag: string, text: string = '') => {
test(tag + ' ' + text + ' successful', () => {
const tree = shallow(processTag(tag, obj, math));
const tree = shallow(processTag(tag, obj));

expect(tree.debug()).toMatchSnapshot();
});
Expand Down Expand Up @@ -215,7 +212,7 @@ describe('Parse snippet', () => {
objLatex
];

objsToTest.forEach(obj => testTagSuccessful(obj['obj'], tag, obj['text'], true));
objsToTest.forEach(obj => testTagSuccessful(obj['obj'], tag, obj['text']));
});

describe('Parse figures', () => {
Expand Down Expand Up @@ -300,7 +297,7 @@ describe('Parse latex', () => {
body: math
};

tag.forEach(tag => testTagSuccessful(obj, tag, '', true));
tag.forEach(tag => testTagSuccessful(obj, tag, ''));
});

describe('Parse links', () => {
Expand Down
48 changes: 22 additions & 26 deletions src/features/sicp/parser/__tests__/__snapshots__/ParseJson.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ exports[`Parse figures FIGURE with image successful 1`] = `
exports[`Parse figures FIGURE with snippet successful 1`] = `
"<div className=\\"sicp-figure\\">
<CodeSnippet body=\\"1 + 1;\\" id={[undefined]} initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash={[undefined]} initialPrependHash={[undefined]} output={[undefined]} />
<Component body=\\"1 + 1;\\" id={[undefined]} initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash={[undefined]} initialPrependHash={[undefined]} output={[undefined]} />
<h5 className=\\"sicp-caption\\">
name
<span>
Expand Down Expand Up @@ -269,15 +269,15 @@ exports[`Parse heading SUBSUBHEADING successful 1`] = `
`;

exports[`Parse latex LATEX successful 1`] = `
"<ContextProvider value={{...}}>
<SicpLatex inline={false} math=\\"$test$\\" />
</ContextProvider>"
"<Latex delimiters={{...}} strict={false}>
$test$
</Latex>"
`;

exports[`Parse latex LATEXINLINE successful 1`] = `
"<ContextProvider value={{...}}>
<SicpLatex inline={true} math=\\"$test$\\" />
</ContextProvider>"
"<Latex delimiters={{...}} strict={false}>
$test$
</Latex>"
`;

exports[`Parse links FOOTNOTE_REF successful 1`] = `
Expand Down Expand Up @@ -397,37 +397,33 @@ exports[`Parse section SECTION successful 1`] = `
`;

exports[`Parse snippet SNIPPET no eval successful 1`] = `
"<ContextProvider value={{...}}>
<Component>
1 + 1;
</Component>
</ContextProvider>"
"<pre className=\\"bp3-code-block\\">
1 + 1;
</pre>"
`;
exports[`Parse snippet SNIPPET with latex successful 1`] = `
"<ContextProvider value={{...}}>
<Component>
<SicpLatex inline={false} math=\\"1 + 1;\\" />
</Component>
</ContextProvider>"
"<pre className=\\"bp3-code-block\\">
<SicpLatex math=\\"1 + 1;\\" />
</pre>"
`;

exports[`Parse snippet SNIPPET with prepend successful 1`] = `
"<ContextProvider value={{...}}>
<CodeSnippet body=\\"1 + 1;\\" id=\\"id\\" initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash=\\"MYewdgzgLgBAhjAvDAjAbgFApgalWoA\\" initialPrependHash=\\"MYewdgzgLgBAhjAvDAjAbiA\\" output={[undefined]} />
</ContextProvider>"
"<div body=\\"1 + 1;\\" id=\\"id\\" initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash=\\"MYewdgzgLgBAhjAvDAjAbgFApgalWoA\\" initialPrependHash=\\"MYewdgzgLgBAhjAvDAjAbiA\\" output={[undefined]}>
Code Snippet
</div>"
`;

exports[`Parse snippet SNIPPET without prepend successful 1`] = `
"<ContextProvider value={{...}}>
<CodeSnippet body=\\"1 + 1;\\" id=\\"id\\" initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash={[undefined]} initialPrependHash={[undefined]} output={[undefined]} />
</ContextProvider>"
"<div body=\\"1 + 1;\\" id=\\"id\\" initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash={[undefined]} initialPrependHash={[undefined]} output={[undefined]}>
Code Snippet
</div>"
`;

exports[`Parse snippet SNIPPET without prepend with output successful 1`] = `
"<ContextProvider value={{...}}>
<CodeSnippet body=\\"1 + 1;\\" id=\\"id\\" initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash={[undefined]} initialPrependHash={[undefined]} output=\\"2\\" />
</ContextProvider>"
"<div body=\\"1 + 1;\\" id=\\"id\\" initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash={[undefined]} initialPrependHash={[undefined]} output=\\"2\\">
Code Snippet
</div>"
`;
exports[`Parse styling B successful 1`] = `
Expand Down
32 changes: 11 additions & 21 deletions src/pages/sicp/Sicp.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'katex/dist/katex.min.css';

import { Classes, NonIdealState, Spinner } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { MathJaxContext } from 'better-react-mathjax';
import classNames from 'classnames';
import * as React from 'react';
import { useDispatch } from 'react-redux';
Expand All @@ -13,7 +14,7 @@ import SicpIndexPage from './subcomponents/SicpIndexPage';

type SicpProps = RouteComponentProps<{}>;

const baseUrl = Constants.interactiveSicpDataUrl + '/json/';
const baseUrl = Constants.interactiveSicpDataUrl + 'json/';
const extension = '.json';

// Context to determine which code snippet is active
Expand All @@ -22,16 +23,6 @@ export const CodeSnippetContext = React.createContext({
setActive: (x: string) => {}
});

export const mathjaxConfig = {
tex: {
inlineMath: [
['$', '$'],
['\\(', '\\)']
],
displayMath: [['\\[', '\\]']]
}
};

const loadingComponent = <NonIdealState title="Loading Content" icon={<Spinner />} />;

const unexpectedError = (
Expand Down Expand Up @@ -113,6 +104,7 @@ const Sicp: React.FC<SicpProps> = props => {
} else {
setData(errorComponent(unexpectedError));
}
setLoading(false);
});
}, [section]);

Expand Down Expand Up @@ -150,15 +142,13 @@ const Sicp: React.FC<SicpProps> = props => {
<div className={classNames('Sicp', Classes.RUNNING_TEXT, Classes.TEXT_LARGE, Classes.DARK)}>
<CodeSnippetContext.Provider value={{ active: active, setActive: handleSnippetEditorOpen }}>
<div ref={topRef} />
<MathJaxContext version={3} config={mathjaxConfig}>
{loading ? (
<div className="sicp-content">{loadingComponent}</div>
) : section === 'index' ? (
<SicpIndexPage />
) : (
<div className="sicp-content">{data}</div>
)}
</MathJaxContext>
{loading ? (
<div className="sicp-content">{loadingComponent}</div>
) : section === 'index' ? (
<SicpIndexPage />
) : (
<div className="sicp-content">{data}</div>
)}
</CodeSnippetContext.Provider>
</div>
);
Expand Down
11 changes: 2 additions & 9 deletions src/pages/sicp/subcomponents/SicpLatex.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import { MathJax } from 'better-react-mathjax';
import * as React from 'react';
import Latex from 'react-latex-next';

type SicpLatexProps = {
math: string;
inline: boolean;
};

const SicpLatex: React.FC<SicpLatexProps> = props => {
const { math, inline } = props;

return (
<MathJax inline={inline} dynamic={false}>
{math}
</MathJax>
);
return <Latex>{props.math}</Latex>;
};

export default SicpLatex;
14 changes: 2 additions & 12 deletions src/pages/sicp/subcomponents/__tests__/SicpLatex.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { MathJaxContext } from 'better-react-mathjax';
import { mount } from 'enzyme';

import { mathjaxConfig } from '../../Sicp';
import SicpLatex from '../SicpLatex';

describe('Sicp latex renders', () => {
Expand All @@ -11,11 +9,7 @@ describe('Sicp latex renders', () => {
inline: false
};

const tree = mount(
<MathJaxContext version={3} config={mathjaxConfig}>
<SicpLatex {...props} />
</MathJaxContext>
);
const tree = mount(<SicpLatex {...props} />);
expect(tree.debug()).toMatchSnapshot();
});

Expand All @@ -25,11 +19,7 @@ describe('Sicp latex renders', () => {
inline: true
};

const tree = mount(
<MathJaxContext version={3} config={mathjaxConfig}>
<SicpLatex {...props} />
</MathJaxContext>
);
const tree = mount(<SicpLatex {...props} />);
expect(tree.debug()).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Sicp latex renders correctly block 1`] = `
"<MathJaxContext version={3} config={{...}}>
<SicpLatex math=\\"1+1\\" inline={false}>
<MathJax inline={false} dynamic={false}>
<span id={[undefined]} style={{...}}>
1+1
</span>
</MathJax>
</SicpLatex>
</MathJaxContext>"
"<SicpLatex math=\\"1+1\\" inline={false}>
<Latex delimiters={{...}} strict={false}>
<span className=\\"__Latex__\\" dangerouslySetInnerHTML={{...}} />
</Latex>
</SicpLatex>"
`;

exports[`Sicp latex renders correctly inline 1`] = `
"<MathJaxContext version={3} config={{...}}>
<SicpLatex math=\\"1+1\\" inline={true}>
<MathJax inline={true} dynamic={false}>
<span id={[undefined]} style={{...}}>
1+1
</span>
</MathJax>
</SicpLatex>
</MathJaxContext>"
"<SicpLatex math=\\"1+1\\" inline={true}>
<Latex delimiters={{...}} strict={false}>
<span className=\\"__Latex__\\" dangerouslySetInnerHTML={{...}} />
</Latex>
</SicpLatex>"
`;
Loading

0 comments on commit 558f213

Please sign in to comment.