ProseMirror / prosemirror-markdown

ProseMirror Markdown integration
https://prosemirror.net
MIT License
344 stars 81 forks source link

Wrong parsing of emphasis and strong emphasis formatting #82

Open susnux opened 2 years ago

susnux commented 2 years ago

From CommonMark example 431:

**foo *bar **baz**
bim* bop**

should be parsed as:

<p><strong>foo <em>bar <strong>baz</strong>
bim</em> bop</strong></p>

Using just markdown-it this works as expected but the defaultMarkdownParser creates this incorrect representation:

<p><strong>foo </strong><em><strong>bar baz</strong>
bim</em> bop</p>

Invalid parsing of emphasis and strong emphasis

marijnh commented 2 years ago

ProseMirror does not allow marks of the same type to be nested like this. I guess the markdown parser could be a bit more graceful about this (just ignoring the inner opening and closing strong tokens).

susnux commented 2 years ago

ProseMirror does not allow marks of the same type to be nested like this.

Well one could workaround this as ProseMirror supports multiple marks of the same type if they have different attributes. Meaning you have to set excludes: '' for the marks em and strong and add a nesting attribute to them.

e.g. something like this:

function nesting(...types) {
  const fn = (node) => {
    let el = (node as HTMLElement).parentElement
    let nesting = 0
    while(el !== null) {
      if ([...arguments].includes(el.tagName)) nesting++
      el = el.parentElement
    }
    return {nesting: nesting}
  }
  return fn
}

// ... inside the schema:
marks: {
    em: {
      attrs: {
        nesting: {
          default: null
        }
      },
      parseDOM: [
        {tag: "i", getAttrs: nesting("EM", "I")},
        {tag: "em", getAttrs: nesting("EM", "I")},
      ],
      toDOM() { return ["em"] },
      excludes: ''
    },

    strong: {
      excludes: '',
      attrs: {
        nesting: {
          default: null
        }
      },
      parseDOM: [
        {tag: "b", getAttrs: nesting("STRONG", "B")},
        {tag: "strong", getAttrs: nesting("STRONG", "B")},
      ],
      toDOM() { return ["strong"] }
    },
}