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

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;