import { Plugin, PluginKey } from 'prosemirror-state' import { Slice, Fragment, MarkType } from 'prosemirror-model' export default function (regexp: RegExp, type: MarkType, getAttrs?: (match: any) => any): Plugin { const handler = (fragment: Fragment, parent?: any) => { const nodes: any[] = [] fragment.forEach(child => { if (child.isText && child.text) { const { text } = child let pos = 0 let match // eslint-disable-next-line while ((match = regexp.exec(text)) !== null) { const outerMatch = Math.max(match.length - 2, 0) const innerMatch = Math.max(match.length - 1, 0) if (parent.type.allowsMarkType(type)) { const start = match.index const matchStart = start + match[0].indexOf(match[outerMatch]) const matchEnd = matchStart + match[outerMatch].length const textStart = matchStart + match[outerMatch].lastIndexOf(match[innerMatch]) const textEnd = textStart + match[innerMatch].length const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs // adding text before markdown to nodes if (matchStart > 0) { nodes.push(child.cut(pos, matchStart)) } // adding the markdown part to nodes nodes.push(child .cut(textStart, textEnd) .mark(type.create(attrs).addToSet(child.marks))) pos = matchEnd } } // adding rest of text to nodes if (pos < text.length) { nodes.push(child.cut(pos)) } } else { nodes.push(child.copy(handler(child.content, child))) } }) return Fragment.fromArray(nodes) } return new Plugin({ key: new PluginKey('markPasteRule'), props: { transformPasted: slice => { return new Slice(handler(slice.content), slice.openStart, slice.openEnd) }, }, }) }