You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
3.0 KiB
152 lines
3.0 KiB
4 years ago
|
const { inspect } = require("util");
|
||
|
function* prepare(str) {
|
||
|
for (let i = 0; i < str.length; i++) {
|
||
|
yield {
|
||
|
current: str[i],
|
||
|
next: (n = 1) => str.slice(i + 1, i + 1 + n),
|
||
|
prev: (n = 1) => str.slice(i - n, i),
|
||
|
skip: (n = 1) => (i += n),
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function Parse(str, inner = false) {
|
||
|
let context = null;
|
||
|
let buffer = "";
|
||
|
let AST = [];
|
||
|
let link = "";
|
||
|
|
||
|
const flush = () => {
|
||
|
if (buffer) {
|
||
|
if (context === null && inner) {
|
||
|
AST.push(buffer);
|
||
|
} else {
|
||
|
if (context === "url") {
|
||
|
AST.push({
|
||
|
type: context,
|
||
|
children: Parse(buffer, true),
|
||
|
url: link,
|
||
|
});
|
||
|
} else {
|
||
|
AST.push({
|
||
|
type: context || "text",
|
||
|
children: context === null ? [buffer] : Parse(buffer, true),
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
buffer = "";
|
||
|
}
|
||
|
context = null;
|
||
|
link = "";
|
||
|
};
|
||
|
|
||
|
for (const char of prepare(str)) {
|
||
|
const currentContext = context;
|
||
|
if (
|
||
|
(!context || context === "bold") &&
|
||
|
char.current === "*" &&
|
||
|
char.next() === "*"
|
||
|
) {
|
||
|
flush();
|
||
|
if (!currentContext) {
|
||
|
context = "bold";
|
||
|
}
|
||
|
char.skip();
|
||
|
} else if ((!context || context === "italics") && char.current === "_") {
|
||
|
flush();
|
||
|
if (!currentContext) {
|
||
|
context = "italics";
|
||
|
}
|
||
|
} else if (
|
||
|
(!context || context === "strikethrough") &&
|
||
|
char.current === "~" &&
|
||
|
char.next() === "~"
|
||
|
) {
|
||
|
flush();
|
||
|
if (!currentContext) {
|
||
|
context = "strikethrough";
|
||
|
}
|
||
|
char.skip();
|
||
|
} else if (
|
||
|
(!context || context === "underline") &&
|
||
|
char.current === "=" &&
|
||
|
char.next() === "="
|
||
|
) {
|
||
|
flush();
|
||
|
if (!currentContext) {
|
||
|
context = "underline";
|
||
|
}
|
||
|
char.skip();
|
||
|
} else if (
|
||
|
(char.current === "[" || char.current === "]") &&
|
||
|
(!context || context === "link")
|
||
|
) {
|
||
|
if (char.current === "[") {
|
||
|
flush();
|
||
|
context = "link";
|
||
|
}
|
||
|
if (inner) {
|
||
|
buffer += char.current;
|
||
|
}
|
||
|
} else if (
|
||
|
(context === "link" || !context || context === "url") &&
|
||
|
(char.current === "(" || char.current === ")") &&
|
||
|
!inner
|
||
|
) {
|
||
|
if (char.prev() === "]") {
|
||
|
if (!currentContext || currentContext === "link") {
|
||
|
context = "url";
|
||
|
}
|
||
|
} else {
|
||
|
flush();
|
||
|
}
|
||
|
} else {
|
||
|
if (context === "url") {
|
||
|
link += char.current;
|
||
|
} else {
|
||
|
buffer += char.current;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const updater = char => {
|
||
|
context = null;
|
||
|
let result = Parse(buffer);
|
||
|
for (const check of result) {
|
||
|
if (check.type !== "text") {
|
||
|
if (!AST.length) {
|
||
|
buffer = char;
|
||
|
flush();
|
||
|
}
|
||
|
AST.push(check);
|
||
|
buffer = "";
|
||
|
} else {
|
||
|
buffer = check.children[0];
|
||
|
if (!AST.length) {
|
||
|
buffer = char + buffer;
|
||
|
}
|
||
|
flush();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if (context === "bold") {
|
||
|
updater("**");
|
||
|
} else if (context === "italics") {
|
||
|
updater("_");
|
||
|
} else if (context === "strikethrough") {
|
||
|
updater("~~");
|
||
|
} else if (context == "underline") {
|
||
|
updater("==");
|
||
|
}
|
||
|
|
||
|
if (buffer) {
|
||
|
context = null;
|
||
|
flush();
|
||
|
}
|
||
|
|
||
|
return AST;
|
||
|
}
|
||
|
|
||
|
module.exports = Parse;
|