I am using Marked.js for parsing Markdown. The original Markdown language does not support different ordered list styles, for instance, lettered ones, like HTML. I would like to introduce this function to the parser. Below is my JavaScript code:
const customList = {
name: "customList",
level: "block",
start(src) {
return src.match(/(?:^|n)(s*)(-|+|*|d+.|[A-Za-z]+.|[iIvVxX]+.)(s+)/)?.index;
},
tokenizer(src, tokens) {
const rule = /^([^Srn]*)(-|+|*|d+.|[A-Za-z]+.|[iIvVxX]+.)(s+)(.*)/;
const textRule = /^([^Srn]*)(.*)/;
const match = rule.exec(src);
let style;
if (match) {
if (/-/.test(match[2])) style = "-";
else if (/+/.test(match[2])) style = "+";
else if (/*/.test(match[2])) style = "*";
else if (/d+./.test(match[2])) style = "1";
else if (/[IVX]+./.test(match[2])) style = "I";
else if (/[ivx]+./.test(match[2])) style = "i";
else if (/[A-Z]+./.test(match[2])) style = "A";
else if (/[a-z]+./.test(match[2])) style = "a";
const items = [];
let remainingSrc = src;
let prevIndent = match[1].length;
let itemText = "", raw = "";
while (remainingSrc) {
const itemMatch = rule.exec(remainingSrc);
const textMatch = textRule.exec(remainingSrc);
if (itemMatch && itemMatch[1].length === prevIndent) {
let itemStyle;
if (/-/.test(itemMatch[2])) itemStyle = "-";
else if (/+/.test(itemMatch[2])) itemStyle = "+";
else if (/*/.test(itemMatch[2])) itemStyle = "*";
else if (/d+./.test(itemMatch[2])) itemStyle = "1";
else if (/[IVX]+./.test(itemMatch[2])) itemStyle = "I";
else if (/[ivx]+./.test(itemMatch[2])) itemStyle = "i";
else if (/[A-Z]+./.test(itemMatch[2])) itemStyle = "A";
else if (/[a-z]+./.test(itemMatch[2])) itemStyle = "a";
else break;
if (itemStyle !== style) break;
if (itemText) {
const itemTokens = [];
this.lexer.inlineTokens(itemText, itemTokens);
items.push({
type: "customListItem",
raw: raw,
tokens: itemTokens
});
}
itemText = itemMatch[4].trim();
raw = itemMatch[0];
remainingSrc = remainingSrc.slice(itemMatch[0].length + 1);
}
else if (textMatch && textMatch[1].length === prevIndent) {
itemText += "n" + textMatch[2];
raw += "n" + textMatch[0];
remainingSrc = remainingSrc.slice(textMatch[0].length + 1);
}
else break;
}
if (itemText) {
const itemTokens = [];
this.lexer.inlineTokens(itemText, itemTokens);
items.push({
type: "customListItem",
raw: raw,
tokens: itemTokens
});
}
const token = {
type: "customList",
raw: src.slice(0, src.length - remainingSrc.length),
style: style,
items: items
};
return token;
}
},
renderer(token) {
const listItems = token.items.map(item =>
`<li>${this.parser.parseInline(item.tokens)}</li>`
).join('n');
if (token.style === "-" || token.style === "+" || token.style === "*") return `<ul>n${listItems}n</ul>n`;
else if (token.style === "1" || token.style === "I" || token.style === "i" || token.style === "A" || token.style === "a") return `<ol type="${token.style}">n${listItems}n</ol>n`;
},
childTokens: ["items"]
};
marked.use({ extensions: [customList] });
It works normally in most cases:
Example 1
marked.parse(" 1. firstn 2. secondn 3. third")
Output
<ol type="1">
<li>first</li>
<li>second</li>
<li>third</li>
</ol>
Example 2
marked.parse("A. firstnB. secondn* firstn* second")
Output
<ol type="A">
<li>first</li>
<li>second</li>
</ol>
<ul>
<li>first</li>
<li>second</li>
</ul>
However, when I try this:
marked.parse("1 + 1")
The output becomes:
<p>1</p>
<ul>
<li>1</li>
</ul>
I expect that only the list markers appearing at the beginning of a line (surrounded by whitespaces) will be detected as a list.
I tried getting some values of the variables by adding console.log(src)
in the tokenizer function. Surprisingly, I receive two outputs when I try the above case.
1 + 1
+ 1
Why is this occurring? I am sorry that I am new to JavaScript, and the code may look clumsy. If you need more information, please let me know. Thanks a lot.