104 lines
2.5 KiB
TypeScript
104 lines
2.5 KiB
TypeScript
import { zipArrays } from "../zip";
|
|
import { tokenizeLine } from "./tokenizeLine";
|
|
import { tokenizeBlock } from "./tokenizeBlock";
|
|
import { tokenizeParagraph } from "./tokenizeParagraph";
|
|
|
|
export const createElements = (body: string) => {
|
|
const tokens = tokenize(body);
|
|
|
|
return tokens;
|
|
};
|
|
|
|
const tokenize = (body: string) => {
|
|
body = body.replace(/\n?<!--(.*?)-->\n?/gs, "");
|
|
|
|
const paragraphs = body.split("\n\n");
|
|
|
|
const blockTokens: BlockToken[] = [];
|
|
const paragraphTokens: ParagraphToken[] = [];
|
|
|
|
for (const paragraph of paragraphs) {
|
|
const block = tokenizeBlock(paragraph);
|
|
let openBT = blockTokens.findLast((bt) => !bt.closed);
|
|
if (block) {
|
|
if (typeof block === "string") {
|
|
if (openBT) {
|
|
openBT.closed = true;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (openBT) {
|
|
openBT.children.push(block);
|
|
block.parent = openBT.type;
|
|
}
|
|
blockTokens.push(block);
|
|
continue;
|
|
}
|
|
|
|
if (!openBT) {
|
|
openBT = {
|
|
children: [],
|
|
closed: false,
|
|
metadata: {},
|
|
type: "block",
|
|
uuid: crypto.randomUUID(),
|
|
};
|
|
blockTokens.push(openBT);
|
|
}
|
|
|
|
const multiline = tokenizeParagraph(paragraph);
|
|
let openP = paragraphTokens.findLast((p) => !p.closed);
|
|
if (multiline) {
|
|
if (Array.isArray(multiline)) {
|
|
if (openP) {
|
|
openP.closed = true;
|
|
openP.content = openP.content.concat(multiline);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
openBT.children.push(multiline);
|
|
paragraphTokens.push(multiline);
|
|
continue;
|
|
} else if (openP && !openP?.allowsInline) {
|
|
openP.content.push({
|
|
line: paragraph,
|
|
raw: paragraph,
|
|
type: "text",
|
|
uuid: crypto.randomUUID(),
|
|
});
|
|
}
|
|
|
|
// I don't think the closed check is necessary, but just in case
|
|
// if (openP && !openP.closed && !openP.allowsInline) continue;
|
|
if (!openP) {
|
|
openP = {
|
|
allowsInline: true,
|
|
closed: true,
|
|
content: [],
|
|
metadata: {},
|
|
type: "p",
|
|
uuid: crypto.randomUUID(),
|
|
};
|
|
openBT.children.push(openP);
|
|
paragraphTokens.push(openP);
|
|
}
|
|
|
|
const lines = paragraph.split("\n");
|
|
let previous;
|
|
for (const line of lines) {
|
|
const singleLine = tokenizeLine(line, previous);
|
|
|
|
if (singleLine) {
|
|
if (singleLine !== previous) {
|
|
openP.content.push(singleLine);
|
|
}
|
|
previous = singleLine;
|
|
}
|
|
}
|
|
}
|
|
|
|
return blockTokens.filter((b) => !b.parent);
|
|
};
|