Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ const content = seeMarkReactParse(markdown);

| Option Name | Type | Default Value | Description |
| ------------------------- | ------- | -------------- | ------------------------------------------------------------------ |
| enableLatex | boolean | true | When false, LaTeX expressions are not parsed as math. |
| enableAsciimath | boolean | true | When false, AsciiMath expressions are not parsed as math. |
| enableNemeth | boolean | true | When false, the Nemeth braille math extension is disabled and `@…@` syntax is not parsed. |
| latexDelimiter | string | 'bracket' | The delimiter for LaTeX expressions. Options: 'bracket', 'dollar'. |
| documentFormat | string | 'inline' | The format of the document. Options: 'inline', 'block'. |
| imageFiles | object | { [ID]: File } | A map of image IDs to File objects for image rendering. |
Expand Down Expand Up @@ -123,6 +126,15 @@ const toc = createTableOfContents(markdown);

`createTableOfContents` parses a markdown string and returns a flat array of all h1–h6 headings in document order. The `id` of each entry is generated with the same slugify logic used by the seemark's markdown parser, so IDs are guaranteed to match the `id` prop on rendered heading components.

### Options

| Option Name | Type | Default Value | Description |
| -------------- | ------- | ------------- | ------------------------------------------------------------------------------------------- |
| enableLatex | boolean | true | When false, LaTeX expressions are not parsed as math. |
| enableAsciimath | boolean | true | When false, AsciiMath expressions are not parsed as math. |
| enableNemeth | boolean | true | When false, the Nemeth braille math extension is disabled and `@…@` syntax is not parsed. |
| latexDelimiter | string | 'bracket' | The delimiter for LaTeX expressions. Options: 'bracket', 'dollar'. Must match the renderer. |

### Return value

Each entry in the returned array has the following shape:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coseeing/see-mark",
"version": "1.8.0",
"version": "1.9.0",
"description": "A markdown parser for a11y",
"main": "./lib/see-mark.cjs",
"files": [
Expand Down
10 changes: 8 additions & 2 deletions src/markdown-processor/markdown-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,21 @@ import iframe from './marked-extentions/iframe';
export const createMarkdownProcessor = (options = {}) => {
const asciimathDelimiter = 'graveaccent';

const enableLatex = options.enableLatex !== false;
const enableAsciimath = options.enableAsciimath !== false;
const enableNemeth = options.enableNemeth !== false;

return markedProcessorFactory({
latexDelimiter: options.latexDelimiter,
asciimathDelimiter,
documentFormat: options.documentFormat,
imageFiles: options.imageFiles,
shouldBuildImageObjectURL: options.shouldBuildImageObjectURL,
enableLatex,
enableAsciimath,
extensions: [
math,
nemeth,
...(enableLatex || enableAsciimath ? [math] : []),
...(enableNemeth ? [nemeth] : []),
alert,
heading,
internalLink,
Expand Down
97 changes: 97 additions & 0 deletions src/markdown-processor/markdown-processor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ describe('markdownProcessor', () => {
expect(container).toMatchSnapshot();
});

it('should not parse nemeth braille when enableNemeth is false', () => {
const markdownContent = '@⠁⠘⠆@';
const options = {
enableNemeth: false,
latexDelimiter: 'bracket',
documentFormat: 'inline',
imageFiles: {},
};

const result = markdownProcessor(markdownContent, options);

const container = createDOMFromHTML(result);

const mathEl = getElementByType(container, SUPPORTED_COMPONENT_TYPES.MATH);

expect(mathEl).toBeNull();
});

it('should process alert', () => {
const markdownContent = `> [!WARNING]\n> Critical content demanding immediate user attention due to potential risks.`;
const options = {
Expand Down Expand Up @@ -308,6 +326,85 @@ describe('markdownProcessor', () => {
expect(container).toMatchSnapshot();
});

it('should not parse latex when enableLatex is false', () => {
const markdownContent = '\\(a+b=c\\)';
const options = {
enableLatex: false,
latexDelimiter: 'bracket',
documentFormat: 'inline',
imageFiles: {},
};

const result = markdownProcessor(markdownContent, options);

const container = createDOMFromHTML(result);

const mathEl = getElementByType(container, SUPPORTED_COMPONENT_TYPES.MATH);

expect(mathEl).toBeNull();
});

it('should not parse asciimath when enableAsciimath is false', () => {
const markdownContent = '`a+b=c`';
const options = {
enableAsciimath: false,
latexDelimiter: 'bracket',
documentFormat: 'inline',
imageFiles: {},
};

const result = markdownProcessor(markdownContent, options);

const container = createDOMFromHTML(result);

const mathEl = getElementByType(container, SUPPORTED_COMPONENT_TYPES.MATH);

expect(mathEl).toBeNull();
});

it('should still parse latex when enableAsciimath is false', () => {
const markdownContent = '\\(a+b=c\\)';
const options = {
enableAsciimath: false,
latexDelimiter: 'bracket',
documentFormat: 'inline',
imageFiles: {},
};

const result = markdownProcessor(markdownContent, options);

const container = createDOMFromHTML(result);

const mathEl = getElementByType(container, SUPPORTED_COMPONENT_TYPES.MATH);

expect(mathEl).toBeTruthy();

const payload = JSON.parse(
mathEl.getAttribute(SEE_MARK_PAYLOAD_DATA_ATTRIBUTES)
);

expect(payload.typed).toBe('latex');
});

it('should not parse any math when both enableLatex and enableAsciimath are false', () => {
const markdownContent = '\\(a+b=c\\) `a+b=c`';
const options = {
enableLatex: false,
enableAsciimath: false,
latexDelimiter: 'bracket',
documentFormat: 'inline',
imageFiles: {},
};

const result = markdownProcessor(markdownContent, options);

const container = createDOMFromHTML(result);

const mathEl = getElementByType(container, SUPPORTED_COMPONENT_TYPES.MATH);

expect(mathEl).toBeNull();
});

it('should process image link', () => {
const markdownContent = `![alt text](image-123)((https://example.com/target))`;
const options = {
Expand Down
31 changes: 23 additions & 8 deletions src/markdown-processor/marked-extentions/math.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,17 @@ const AsciiMath_delimiter_dict = {
* @param {string} options.documentFormat - Document format for MathML display ('inline' or 'block')
* @returns {Object} Marked extension object with math tokenizer and renderer
*/
const markedMath = ({ latexDelimiter, asciimathDelimiter, documentFormat }) => {
const markedMath = ({
enableLatex = true,
enableAsciimath = true,
latexDelimiter,
asciimathDelimiter,
documentFormat,
}) => {
if (!enableLatex && !enableAsciimath) {
return { extensions: [] };
}

const asciimath2mml = asciimath2mmlFactory({
htmlMathDisplay: documentFormat,
});
Expand All @@ -62,16 +72,21 @@ const markedMath = ({ latexDelimiter, asciimathDelimiter, documentFormat }) => {

const latex_restring = `(?<=[^\\\\]?)${LaTeX_delimiter.start}(.*?[^\\\\])?${LaTeX_delimiter.end}`;
const asciimath_restring = `(?<=[^\\\\]?)${AsciiMath_delimiter.start}(.*?[^\\\\])?${AsciiMath_delimiter.end}`;
const reTexMath = new RegExp(
`(.*?)(${latex_restring}|${asciimath_restring})`,
's'
);

const latex_start_restring = `(?<=[^\\\\]?)${LaTeX_delimiter.start}`;
const asciimath_start_restring = `(?<=[^\\\\]?)${AsciiMath_delimiter.start}`;
const reTexMath_start = new RegExp(
`${latex_start_restring}|${asciimath_start_restring}`
);

const matchPatterns = [
...(enableLatex ? [latex_restring] : []),
...(enableAsciimath ? [asciimath_restring] : []),
];
const startPatterns = [
...(enableLatex ? [latex_start_restring] : []),
...(enableAsciimath ? [asciimath_start_restring] : []),
];

const reTexMath = new RegExp(`(.*?)(${matchPatterns.join('|')})`, 's');
const reTexMath_start = new RegExp(startPatterns.join('|'));

return {
extensions: [
Expand Down
4 changes: 4 additions & 0 deletions src/markdown-processor/marked-wrapper/marked-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Marked } from 'marked';
import { createPositionTracker } from './position-tracker';

const markedProcessorFactory = ({
enableLatex = true,
enableAsciimath = true,
latexDelimiter,
asciimathDelimiter,
documentFormat,
Expand All @@ -25,6 +27,8 @@ const markedProcessorFactory = ({
extensions.forEach((extension) => {
marked.use(
extension({
enableLatex,
enableAsciimath,
latexDelimiter,
asciimathDelimiter,
documentFormat,
Expand Down
3 changes: 3 additions & 0 deletions src/parsers/options.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
const DEFAULT_OPTINOS = {
enableLatex: true,
enableAsciimath: true,
enableNemeth: true,
latexDelimiter: 'bracket',
documentFormat: 'inline',
imageFiles: null,
Expand Down
3 changes: 3 additions & 0 deletions src/table-of-contents/create-table-of-contents.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ function extractPlainText(inlineTokens = []) {
*/
const createTableOfContents = (markdown, options = {}) => {
const { lexer } = createMarkdownProcessor({
enableLatex: options.enableLatex !== false,
enableAsciimath: options.enableAsciimath !== false,
enableNemeth: options.enableNemeth !== false,
latexDelimiter: options.latexDelimiter ?? 'bracket',
});
const tokens = lexer(markdown);
Expand Down
Loading