33 * SPDX-License-Identifier: AGPL-3.0-or-later
44 */
55
6- /* eslint-disable jsdoc/require-param-type */
76/* eslint-disable jsdoc/require-param-description */
87
98/*
2423 * https://github.com/ProseMirror/prosemirror-markdown#class-markdownserializer
2524 */
2625
26+ import type { MarkType , Node , NodeType , Schema , Slice } from '@tiptap/pm/model'
27+
2728import { Extension , getExtensionField } from '@tiptap/core'
2829import { DOMParser } from '@tiptap/pm/model'
2930import { Plugin , PluginKey } from '@tiptap/pm/state'
3031import { defaultMarkdownSerializer , MarkdownSerializer } from 'prosemirror-markdown'
3132import markdownit from '../markdownit/index.js'
3233import transformPastedHTML from './transformPastedHTML.ts'
3334
35+ declare module '@tiptap/core' {
36+ interface MarkConfig {
37+ toMarkdown : {
38+ default : null
39+ }
40+ }
41+ interface NodeConfig {
42+ toMarkdown : {
43+ default : null
44+ }
45+ }
46+ }
47+
3448const Markdown = Extension . create ( {
3549 name : 'markdown' ,
3650
@@ -76,7 +90,7 @@ const Markdown = Extension.create({
7690 } ,
7791 clipboardTextParser ( str , $context , _ , view ) {
7892 const parser = DOMParser . fromSchema ( view . state . schema )
79- const doc = document . cloneNode ( false )
93+ const doc = document . cloneNode ( false ) as Document
8094 const dom = doc . createElement ( 'div' )
8195 if ( shiftKey ) {
8296 // Treat double newlines as paragraph breaks when pasting as plaintext
@@ -96,20 +110,22 @@ const Markdown = Extension.create({
96110 } )
97111 } ,
98112 clipboardTextSerializer : ( slice ) => {
99- const traverseNodes = ( slice ) => {
113+ const traverseNodes = ( slice : Slice | Node ) => {
100114 if (
101115 slice . content . childCount > 1
102- || slice . content . firstChild ?. childCount > 1
116+ || ( slice . content . firstChild ?. childCount ?? 0 ) > 1
103117 ) {
104118 // Selected several nodes or several children of one block node
105119 return clipboardSerializer ( this . editor . schema ) . serialize ( slice . content )
106- } else if ( slice . isLeaf ) {
107- return slice . textContent
108- } else {
120+ } else if ( slice . content . firstChild ?. isLeaf ) {
121+ return slice . content . firstChild . textContent
122+ } else if ( slice . content . firstChild ) {
109123 // Only one block node selected, copy it's child content
110124 // Required to not copy wrapping block node when selecting e.g. one table
111125 // cell, one list item or the content of block quotes/callouts.
112126 return traverseNodes ( slice . content . firstChild )
127+ } else {
128+ return '' // empty fragment
113129 }
114130 }
115131
@@ -129,15 +145,17 @@ const Markdown = Extension.create({
129145 * @param schema.nodes
130146 * @param schema.marks
131147 */
132- function createMarkdownSerializer ( { nodes, marks } ) {
148+ function createMarkdownSerializer ( schema : {
149+ nodes : Record < string , NodeType >
150+ marks : Record < string , MarkType >
151+ } ) {
133152 return {
134153 serializer : new MarkdownSerializer (
135- extractNodesToMarkdown ( nodes ) ,
136- extractMarksToMarkdown ( marks ) ,
154+ extractNodesToMarkdown ( schema . nodes ) ,
155+ extractMarksToMarkdown ( schema . marks ) ,
137156 ) ,
138- serialize ( content , options ) {
157+ serialize ( content : Node ) {
139158 return this . serializer . serialize ( content , {
140- ...options ,
141159 tightLists : true ,
142160 } )
143161 } ,
@@ -146,19 +164,16 @@ function createMarkdownSerializer({ nodes, marks }) {
146164
147165/**
148166 *
149- * @param root0
150- * @param root0.nodes
151- * @param root0.marks
167+ * @param schema or the editorc
152168 */
153- function clipboardSerializer ( { nodes , marks } ) {
169+ function clipboardSerializer ( schema : Schema ) {
154170 return {
155171 serializer : new MarkdownSerializer (
156- extractNodesToMarkdown ( nodes ) ,
157- extractToPlaintext ( marks ) ,
172+ extractNodesToMarkdown ( schema . nodes ) ,
173+ extractToPlaintext ( schema . marks ) ,
158174 ) ,
159- serialize ( content , options ) {
175+ serialize ( content : Node ) {
160176 return this . serializer . serialize ( content , {
161- ...options ,
162177 tightLists : true ,
163178 } )
164179 } ,
@@ -169,7 +184,7 @@ function clipboardSerializer({ nodes, marks }) {
169184 *
170185 * @param marks
171186 */
172- function extractToPlaintext ( marks ) {
187+ function extractToPlaintext ( marks : Record < string , MarkType > ) {
173188 const blankMark = {
174189 open : '' ,
175190 close : '' ,
@@ -186,7 +201,7 @@ function extractToPlaintext(marks) {
186201 *
187202 * @param nodesOrMarks
188203 */
189- function extractToMarkdown ( nodesOrMarks ) {
204+ function extractToMarkdown ( nodesOrMarks : Record < string , ( NodeType | MarkType ) > ) {
190205 const nodeOrMarkEntries = Object . entries ( nodesOrMarks )
191206 . map ( ( [ name , nodeOrMark ] ) => [ name , nodeOrMark . spec . toMarkdown ] )
192207 . filter ( ( [ , toMarkdown ] ) => toMarkdown )
@@ -198,7 +213,7 @@ function extractToMarkdown(nodesOrMarks) {
198213 *
199214 * @param nodes
200215 */
201- function extractNodesToMarkdown ( nodes ) {
216+ function extractNodesToMarkdown ( nodes : Record < string , NodeType > ) {
202217 const defaultNodes = convertNames ( defaultMarkdownSerializer . nodes )
203218 const nodesToMarkdown = extractToMarkdown ( nodes )
204219 return { ...defaultNodes , ...nodesToMarkdown }
@@ -208,21 +223,24 @@ function extractNodesToMarkdown(nodes) {
208223 *
209224 * @param marks
210225 */
211- function extractMarksToMarkdown ( marks ) {
226+ function extractMarksToMarkdown ( marks : Record < string , MarkType > ) {
212227 const defaultMarks = convertNames ( defaultMarkdownSerializer . marks )
213228 const marksToMarkdown = extractToMarkdown ( marks )
214229 return { ...defaultMarks , ...marksToMarkdown }
215230}
216231
232+ type NodeSerializerSpecs = typeof defaultMarkdownSerializer . nodes
233+ type MarkSerializerSpecs = typeof defaultMarkdownSerializer . marks
234+
217235/**
218236 *
219- * @param object
237+ * @param specs
220238 */
221- function convertNames ( object ) {
222- const convert = ( name ) => {
239+ function convertNames ( specs : NodeSerializerSpecs | MarkSerializerSpecs ) {
240+ const convert = ( name : string ) => {
223241 return name . replace ( / _ ( \w ) / g, ( _m , letter ) => letter . toUpperCase ( ) )
224242 }
225- return Object . fromEntries ( Object . entries ( object ) . map ( ( [ name , value ] ) => [ convert ( name ) , value ] ) )
243+ return Object . fromEntries ( Object . entries ( specs ) . map ( ( [ name , value ] ) => [ convert ( name ) , value ] ) )
226244}
227245
228246export { createMarkdownSerializer }
0 commit comments