You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
2.2 KiB
JavaScript

/* eslint no-constant-condition:0 */
const findEndOfMath = function(delimiter, text, startIndex) {
// Adapted from
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
let index = startIndex;
let braceLevel = 0;
const delimLength = delimiter.length;
while (index < text.length) {
const character = text[index];
if (braceLevel <= 0 &&
text.slice(index, index + delimLength) === delimiter) {
return index;
} else if (character === "\\") {
index++;
} else if (character === "{") {
braceLevel++;
} else if (character === "}") {
braceLevel--;
}
index++;
}
return -1;
};
const escapeRegex = function(string) {
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
};
const amsRegex = /^\\begin{/;
const splitAtDelimiters = function(text, delimiters) {
let index;
const data = [];
const regexLeft = new RegExp(
"(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")"
);
while (true) {
index = text.search(regexLeft);
if (index === -1) {
break;
}
if (index > 0) {
data.push({
type: "text",
data: text.slice(0, index),
});
text = text.slice(index); // now text starts with delimiter
}
// ... so this always succeeds:
const i = delimiters.findIndex((delim) => text.startsWith(delim.left));
index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
if (index === -1) {
break;
}
const rawData = text.slice(0, index + delimiters[i].right.length);
const math = amsRegex.test(rawData)
? rawData
: text.slice(delimiters[i].left.length, index);
data.push({
type: "math",
data: math,
rawData,
display: delimiters[i].display,
});
text = text.slice(index + delimiters[i].right.length);
}
if (text !== "") {
data.push({
type: "text",
data: text,
});
}
return data;
};
export default splitAtDelimiters;