Files
outline/shared/editor/rules/tables.ts
2022-01-19 18:43:15 -08:00

77 lines
2.5 KiB
TypeScript

import MarkdownIt from "markdown-it";
import Token from "markdown-it/lib/token";
const BREAK_REGEX = /(?:^|[^\\])\\n/;
export default function markdownTables(md: MarkdownIt): void {
// insert a new rule after the "inline" rules are parsed
md.core.ruler.after("inline", "tables-pm", (state) => {
const tokens = state.tokens;
let inside = false;
for (let i = tokens.length - 1; i > 0; i--) {
if (inside) {
tokens[i].level--;
}
// convert unescaped \n in the text into real br tag
if (tokens[i].type === "inline" && tokens[i].content.match(BREAK_REGEX)) {
const existing = tokens[i].children || [];
tokens[i].children = [];
existing.forEach((child) => {
const breakParts = child.content.split(BREAK_REGEX);
// a schema agnostic way to know if a node is inline code would be
// great, for now we are stuck checking the node type.
if (breakParts.length > 1 && child.type !== "code_inline") {
breakParts.forEach((part, index) => {
const token = new Token("text", "", 1);
token.content = part.trim();
tokens[i].children?.push(token);
if (index < breakParts.length - 1) {
const brToken = new Token("br", "br", 1);
tokens[i].children?.push(brToken);
}
});
} else {
tokens[i].children?.push(child);
}
});
}
// filter out incompatible tokens from markdown-it that we don't need
// in prosemirror. thead/tbody do nothing.
if (
["thead_open", "thead_close", "tbody_open", "tbody_close"].includes(
tokens[i].type
)
) {
inside = !inside;
tokens.splice(i, 1);
}
if (["th_open", "td_open"].includes(tokens[i].type)) {
// markdown-it table parser does not return paragraphs inside the cells
// but prosemirror requires them, so we add 'em in here.
tokens.splice(i + 1, 0, new Token("paragraph_open", "p", 1));
// markdown-it table parser stores alignment as html styles, convert
// to a simple string here
const tokenAttrs = tokens[i].attrs;
if (tokenAttrs) {
const style = tokenAttrs[0][1];
tokens[i].info = style.split(":")[1];
}
}
if (["th_close", "td_close"].includes(tokens[i].type)) {
tokens.splice(i, 0, new Token("paragraph_close", "p", -1));
}
}
return false;
});
}