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;