Created
May 31, 2022 16:26
-
-
Save hanford/e15a0f3be981beb91602a6b1c82fa39a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { ListNode, ListType } from '@lexical/list'; | |
import type { ElementNode } from 'lexical'; | |
import type { ElementTransformer } from '@lexical/markdown'; | |
import { | |
BOLD_ITALIC_STAR, | |
BOLD_ITALIC_UNDERSCORE, | |
BOLD_STAR, | |
BOLD_UNDERSCORE, | |
CHECK_LIST, | |
CODE, | |
HEADING, | |
INLINE_CODE, | |
ITALIC_STAR, | |
ITALIC_UNDERSCORE, | |
LINK, | |
QUOTE, | |
STRIKETHROUGH, | |
TextFormatTransformer, | |
TextMatchTransformer, | |
Transformer, | |
} from '@lexical/markdown'; | |
import { $createListItemNode, $createListNode, $isListItemNode, $isListNode } from '@lexical/list'; | |
const listReplace = (listType: ListType, indentSize: number): ElementTransformer['replace'] => { | |
return (parentNode, children, match) => { | |
const previousNode = parentNode.getPreviousSibling(); | |
const listItem = $createListItemNode(listType === 'check' ? match[3] === 'x' : undefined); | |
if ($isListNode(previousNode) && previousNode.getListType() === listType) { | |
previousNode.append(listItem); | |
parentNode.remove(); | |
} else { | |
const list = $createListNode(listType, listType === 'number' ? Number(match[2]) : undefined); | |
list.append(listItem); | |
parentNode.replace(list); | |
} | |
listItem.append(...children); | |
listItem.select(0, 0); | |
const indent = Math.floor(match[1].length / indentSize); | |
if (indent) { | |
listItem.setIndent(indent); | |
} | |
}; | |
}; | |
const listExport = ( | |
listNode: ListNode, | |
exportChildren: (node: ElementNode) => string, | |
depth: number, | |
indentSize: number, | |
): string => { | |
const output = []; | |
const children = listNode.getChildren(); | |
let index = 0; | |
for (const listItemNode of children) { | |
if ($isListItemNode(listItemNode)) { | |
if (listItemNode.getChildrenSize() === 1) { | |
const firstChild = listItemNode.getFirstChild(); | |
if ($isListNode(firstChild)) { | |
output.push(listExport(firstChild, exportChildren, depth + 1, indentSize)); | |
continue; | |
} | |
} | |
const indent = ' '.repeat(depth * indentSize); | |
const listType = listNode.getListType(); | |
const prefix = | |
listType === 'number' | |
? `${listNode.getStart() + index}. ` | |
: listType === 'check' | |
? `- [${listItemNode.getChecked() ? 'x' : ' '}] ` | |
: '- '; | |
output.push(indent + prefix + exportChildren(listItemNode)); | |
index++; | |
} | |
} | |
return output.join('\n'); | |
}; | |
const UNORDERED_LIST_TRANSFORM: ElementTransformer = { | |
export: (node, exportChildren) => { | |
return $isListNode(node) ? listExport(node, exportChildren, 0, 2) : null; | |
}, | |
regExp: /^(\s*)[-*+]\s/, | |
replace: listReplace('bullet', 2), | |
type: 'element', | |
}; | |
const ORDERED_LIST_TRANSFORM: ElementTransformer = { | |
export: (node, exportChildren) => { | |
return $isListNode(node) ? listExport(node, exportChildren, 0, 3) : null; | |
}, | |
regExp: /^(\s*)(\d{1,})\.\s/, | |
replace: listReplace('number', 3), | |
type: 'element', | |
}; | |
const ELEMENT_TRANSFORMERS: ElementTransformer[] = [ | |
HEADING, | |
QUOTE, | |
CODE, | |
ORDERED_LIST_TRANSFORM, | |
CHECK_LIST, | |
UNORDERED_LIST_TRANSFORM, | |
]; | |
// Order of text format transformers matters: | |
// | |
// - code should go first as it prevents any transformations inside | |
// - then longer tags match (e.g. ** or __ should go before * or _) | |
const TEXT_FORMAT_TRANSFORMERS: TextFormatTransformer[] = [ | |
INLINE_CODE, | |
BOLD_ITALIC_STAR, | |
BOLD_ITALIC_UNDERSCORE, | |
BOLD_STAR, | |
BOLD_UNDERSCORE, | |
ITALIC_STAR, | |
ITALIC_UNDERSCORE, | |
STRIKETHROUGH, | |
]; | |
const TEXT_MATCH_TRANSFORMERS: TextMatchTransformer[] = [LINK]; | |
export const TRANSFORMERS: Transformer[] = [ | |
...ELEMENT_TRANSFORMERS, | |
...TEXT_FORMAT_TRANSFORMERS, | |
...TEXT_MATCH_TRANSFORMERS, | |
]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment