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
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ const content = seeMarkReactParse(markdown);
| ------------------------- | ------- | -------------- | ------------------------------------------------------------------ |
| 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. |
| enableNemeth | boolean | true | When false, the Nemeth braille math extension is disabled. |
| latexDelimiter | string | 'bracket' | The delimiter for LaTeX expressions. Options: 'bracket', 'dollar'. |
| asciimathDelimiter | string | 'graveaccent' | The delimiter for AsciiMath expressions. Options: 'graveaccent', 'asciimath'. |
| nemethDelimiter | string | 'at' | The delimiter for Nemeth braille expressions. Options: 'at' (`@…@`), 'nemeth' (`\n…\n`). |
| 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. |
| shouldBuildImageObjectURL | boolean | false | should build image object URL. |
Expand Down Expand Up @@ -132,8 +134,10 @@ const toc = createTableOfContents(markdown);
| -------------- | ------- | ------------- | ------------------------------------------------------------------------------------------- |
| 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. |
| enableNemeth | boolean | true | When false, the Nemeth braille math extension is disabled. |
| latexDelimiter | string | 'bracket' | The delimiter for LaTeX expressions. Options: 'bracket', 'dollar'. Must match the renderer. |
| asciimathDelimiter | string | 'graveaccent' | The delimiter for AsciiMath expressions. Options: 'graveaccent', 'asciimath'. Must match the renderer. |
| nemethDelimiter | string | 'at' | The delimiter for Nemeth braille expressions. Options: 'at' (`@…@`), 'nemeth' (`\n…\n`). Must match the renderer. |

### Return value

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.9.0",
"version": "1.10.0",
"description": "A markdown parser for a11y",
"main": "./lib/see-mark.cjs",
"files": [
Expand Down

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/markdown-processor/markdown-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import imageDisplayLink from './marked-extentions/image-display-link';
import iframe from './marked-extentions/iframe';

export const createMarkdownProcessor = (options = {}) => {
const asciimathDelimiter = 'graveaccent';
const asciimathDelimiter = options.asciimathDelimiter || 'graveaccent';
const nemethDelimiter = options.nemethDelimiter || 'at';

const enableLatex = options.enableLatex !== false;
const enableAsciimath = options.enableAsciimath !== false;
Expand All @@ -25,6 +26,7 @@ export const createMarkdownProcessor = (options = {}) => {
return markedProcessorFactory({
latexDelimiter: options.latexDelimiter,
asciimathDelimiter,
nemethDelimiter,
documentFormat: options.documentFormat,
imageFiles: options.imageFiles,
shouldBuildImageObjectURL: options.shouldBuildImageObjectURL,
Expand Down
81 changes: 81 additions & 0 deletions src/markdown-processor/markdown-processor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,59 @@ describe('markdownProcessor', () => {
expect(container).toMatchSnapshot();
});

it('should handle asciimath expressions with graveaccent delimiter', () => {
const markdownContent = '`a+b=c`';
const options = {
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('asciimath');
expect(payload.math).toBe('a+b=c');
expect(payload.mathMl).toBeTruthy();
expect(payload.svg).toBeTruthy();
});

it('should handle asciimath expressions with asciimath delimiter', () => {
const markdownContent = '\\aa+b=c\\a';
const options = {
asciimathDelimiter: 'asciimath',
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('asciimath');
expect(payload.math).toBe('a+b=c');
expect(payload.mathMl).toBeTruthy();
expect(payload.svg).toBeTruthy();
});

it('should handle nemeth braille math expressions', () => {
const markdownContent = '@⠁⠘⠆@';
const options = {
Expand Down Expand Up @@ -91,6 +144,34 @@ describe('markdownProcessor', () => {
expect(container).toMatchSnapshot();
});

it('should handle nemeth braille math expressions with backslash-n delimiter', () => {
const markdownContent = '\\n⠁⠘⠆\\n';
const options = {
latexDelimiter: 'bracket',
nemethDelimiter: 'nemeth',
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('nemeth');
expect(payload.latex).toBe('a^2');
expect(payload.math).toBe('⠁⠘⠆');
expect(payload.mathMl).toBeTruthy();
expect(payload.svg).toBeTruthy();
});

it('should not parse nemeth braille when enableNemeth is false', () => {
const markdownContent = '@⠁⠘⠆@';
const options = {
Expand Down
12 changes: 10 additions & 2 deletions src/markdown-processor/marked-extentions/nemeth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import { createRenderer } from './helpers';
import { SUPPORTED_COMPONENT_TYPES } from '../../shared/supported-components';

// ^@<braille U+2800-U+28FF>@
const reNemeth = /^@([\u2800-\u28FF]+)@/;
const reNemethAt = /^@([\u2800-\u28FF]+)@/;
// ^\n<braille U+2800-U+28FF>\n (literal backslash+n)
const reNemethN = /^\\n([\u2800-\u28FF]+)\\n/;

const markedNemeth = ({ documentFormat }) => {
const markedNemeth = ({ documentFormat, nemethDelimiter = 'at' }) => {
const reNemeth = nemethDelimiter === 'nemeth' ? reNemethN : reNemethAt;
const latex2mml = latex2mmlFactory({ htmlMathDisplay: documentFormat });

return {
Expand All @@ -16,6 +19,11 @@ const markedNemeth = ({ documentFormat }) => {
name: 'nemeth',
level: 'inline',
start(src) {
if (nemethDelimiter === 'nemeth') {
// literal \n followed by braille char
const result = src.match(/\\n(?=[\u2800-\u28FF])/);
return result?.index ?? Infinity;
}
// @ followed by braille char (disambiguates from @[ and @!)
const result = src.match(/@(?=[\u2800-\u28FF])/);
return result?.index ?? Infinity;
Expand Down
2 changes: 2 additions & 0 deletions src/markdown-processor/marked-wrapper/marked-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const markedProcessorFactory = ({
enableAsciimath = true,
latexDelimiter,
asciimathDelimiter,
nemethDelimiter,
documentFormat,
imageFiles = {},
shouldBuildImageObjectURL = false,
Expand All @@ -31,6 +32,7 @@ const markedProcessorFactory = ({
enableAsciimath,
latexDelimiter,
asciimathDelimiter,
nemethDelimiter,
documentFormat,
imageFiles,
shouldBuildImageObjectURL,
Expand Down
6 changes: 6 additions & 0 deletions src/table-of-contents/create-table-of-contents.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ function extractPlainText(inlineTokens = []) {
* Must match the value used by the markdown renderer so that math tokens
* inside headings are recognised and their text is correctly extracted.
* Defaults to 'bracket'.
* @param {string} [options.asciimathDelimiter] - AsciiMath delimiter style ('graveaccent', 'asciimath').
* Must match the value used by the markdown renderer. Defaults to 'graveaccent'.
* @param {string} [options.nemethDelimiter] - Nemeth delimiter style ('at', 'nemeth').
* Must match the value used by the markdown renderer. Defaults to 'at'.
* @returns {{ level: number, id: string, text: string }[]}
*
* @example
Expand All @@ -49,6 +53,8 @@ const createTableOfContents = (markdown, options = {}) => {
enableAsciimath: options.enableAsciimath !== false,
enableNemeth: options.enableNemeth !== false,
latexDelimiter: options.latexDelimiter ?? 'bracket',
asciimathDelimiter: options.asciimathDelimiter ?? 'graveaccent',
nemethDelimiter: options.nemethDelimiter ?? 'at',
});
const tokens = lexer(markdown);
const usedIds = new Map();
Expand Down
10 changes: 4 additions & 6 deletions src/table-of-contents/create-table-of-contents.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,10 @@ describe('createTableOfContents', () => {
expect(result[0].id).toBe('hello-world');
});

// FIXME: backtick code spans conflict with the graveaccent AsciiMath delimiter.
// With seemark's math extension registered, `npm install` is tokenised as a
// math token instead of a native code span, so text extraction drops the
// expression.
it.skip('should strip code span markdown from text field', () => {
const result = createTableOfContents('## Use `npm install`');
it('should strip code span markdown from text field', () => {
const result = createTableOfContents('## Use `npm install`', {
asciimathDelimiter: 'asciimath', // backtick code spans conflict with the graveaccent AsciiMath delimiter
});

expect(result[0].text).toBe('Use npm install');
expect(result[0].id).toBe('use-npm-install');
Expand Down