type TokenIdentifier = { rx: RegExp; parse: (s: string) => Token; search?: (s: string, start: number, end: number) => { start: number; end: number; text: string; lastIndex: number; }; }; export const TokenIdentifiers = new Map< string, TokenIdentifier >(); // TokenIdentifiers.set("p", { // rx: /\n{2,}((?:.|\n)*?)\n{2,}/g, // parse(s) { // const [_, content] = s.match(new RegExp(this.rx, ""))!; // return { // // content, // content, // raw: s, // metadata: {}, // type: "p", // uuid: crypto.randomUUID(), // }; // }, // }); const rendersContentOnly = true; const rendersChildrenOnly = true; TokenIdentifiers.set("card", { rx: /\[{2}\n+([\s\S]*?)\n+\]{2}/g, parse(s) { return { content: s.match(new RegExp(this.rx, ""))?.at(1) || "Unable to parse card", raw: s, metadata: {}, type: "card", uuid: crypto.randomUUID(), }; }, }); TokenIdentifiers.set("code", { rx: /`{3}\n+((?:.|\n)*?)\n+`{3}/g, parse(s) { return { content: s.match(new RegExp(this.rx, ""))?.at(1) || "Unable to parse code", raw: s, metadata: {}, type: "code", uuid: crypto.randomUUID(), rendersContentOnly, }; }, }); TokenIdentifiers.set("list", { rx: /^\s*-\s([\s\S]*?)\n\n/gm, parse(s) { return { content: s.match(new RegExp(this.rx, ""))?.at(1) || "Unable to parse list", raw: s, metadata: { initialDepth: s.replace("\n", "").split("-").at(0)?.length.toString() || "1", }, type: "list", uuid: crypto.randomUUID(), rendersChildrenOnly, }; }, }); TokenIdentifiers.set("list-item", { rx: /^\s*-\s(.*?)$/gm, parse(s) { return { content: s.match(new RegExp(this.rx, ""))?.at(1) || "Unable to parse list-item", raw: s, metadata: { initialDepth: s.replace("\n", "").split("-").at(0)?.length.toString() || "1", }, type: "list-item", uuid: crypto.randomUUID(), }; }, }); TokenIdentifiers.set("grid", { search(s, start, end) { const rx = /(?>/g, parse(s) { const [_, title, content] = s.match(new RegExp(this.rx, ""))!; return { // content, content, raw: s, metadata: { title }, type: "popover", uuid: crypto.randomUUID(), rendersContentOnly, }; }, }); TokenIdentifiers.set("accordion", { rx: /\[accordion(\s.*?)?]\n+((?:.|\n)*?)\n+\[\/accordion\]/g, parse(s) { const [_, title, content] = s.match(new RegExp(this.rx, ""))!; return { // content, content, raw: s, metadata: { title }, type: "accordion", uuid: crypto.randomUUID(), }; }, }); TokenIdentifiers.set("p", { // rx: /(?<=\n)\n?([\s\S]*?)\n(?=\n)/g, rx: /(?<=\n\n)([\s\S]*?)(?=\n\n)/g, parse(s) { // const [_, content] = s.match(new RegExp(this.rx, ""))!; return { // content, content: s, raw: s, metadata: {}, type: "p", uuid: crypto.randomUUID(), }; }, }); // const p = TokenIdentifiers.get("p"); // TokenIdentifiers.clear(); // p && TokenIdentifiers.set("p", p); function findMatchingClosedParenthesis( str: string, openRegex: RegExp, closedRegex: RegExp, ): number | null { let openings = 0; let closings = 0; openRegex = new RegExp(openRegex, "g"); closedRegex = new RegExp(closedRegex, "g"); let lastOpeningSuccessIndex = 0; let lastClosingSuccessIndex = 0; debugger; do { const openingMatch = openRegex.exec(str); const closingMatch = closedRegex.exec(str); if ((openingMatch && !closingMatch)) { throw Error("Things have gone horribly wrong"); } // if ((!openingMatch && closingMatch) || (!openingMatch && !closingMatch)) break; if ( openingMatch && closingMatch && openingMatch.index < closingMatch.index ) { openings++; lastOpeningSuccessIndex = openingMatch.index + openingMatch[0].length; closedRegex.lastIndex = lastClosingSuccessIndex; } else if ( (!openingMatch && closingMatch) || (openingMatch && closingMatch && openingMatch.index > closingMatch.index) ) { closings++; lastClosingSuccessIndex = closingMatch.index + closingMatch[0].length; openRegex.lastIndex = lastOpeningSuccessIndex; } else { return closingMatch?.index ?? null; } } while (openings > closings); return closedRegex.lastIndex; }