remarkjs / remark

markdown processor powered by plugins part of the @unifiedjs collective
https://remark.js.org
MIT License
7.55k stars 352 forks source link

listItem adds extra paragraph for text children #563

Closed jepser closed 3 years ago

jepser commented 3 years ago

listItem adds an extra paragraph node

I'm using remark with slate.js, using remark-parse with unified: unified().use(markdown).use(gfm).use(remarkToSlate)

While parsing a list:

* hola
* adios

I found that the behaviour of slate wasn't the expected, I thought was something related to slate or remarkToSlate, but after checking the parser I found the issue is with listItem node from remark-parse

Your environment

Steps to reproduce

Use this codesandbox: https://codesandbox.io/s/confident-allen-1iqpv?file=/src/App.js

This is the structure that remark-parse is handling to the next processor in the pipe (check the extra paragraph node inside listItem):

{
  "type": "root",
  "children": [
    {
      "type": "list",
      "ordered": false,
      "start": null,
      "spread": false,
      "children": [
        {
          "type": "listItem",
          "spread": false,
          "checked": null,
          "children": [
            {
              "type": "paragraph",
              "children": [
                {
                  "type": "text",
                  "value": "hola",
                  "position": {
                    "start": {
                      "line": 2,
                      "column": 3,
                      "offset": 3
                    },
                    "end": {
                      "line": 2,
                      "column": 7,
                      "offset": 7
                    }
                  }
                }
              ],
              "position": {
                "start": {
                  "line": 2,
                  "column": 3,
                  "offset": 3
                },
                "end": {
                  "line": 2,
                  "column": 7,
                  "offset": 7
                }
              }
            }
          ],
          "position": {
            "start": {
              "line": 2,
              "column": 1,
              "offset": 1
            },
            "end": {
              "line": 2,
              "column": 7,
              "offset": 7
            }
          }
        },
        {
          "type": "listItem",
          "spread": false,
          "checked": null,
          "children": [
            {
              "type": "paragraph",
              "children": [
                {
                  "type": "text",
                  "value": "adios",
                  "position": {
                    "start": {
                      "line": 3,
                      "column": 3,
                      "offset": 10
                    },
                    "end": {
                      "line": 3,
                      "column": 8,
                      "offset": 15
                    }
                  }
                }
              ],
              "position": {
                "start": {
                  "line": 3,
                  "column": 3,
                  "offset": 10
                },
                "end": {
                  "line": 3,
                  "column": 8,
                  "offset": 15
                }
              }
            }
          ],
          "position": {
            "start": {
              "line": 3,
              "column": 1,
              "offset": 8
            },
            "end": {
              "line": 3,
              "column": 8,
              "offset": 15
            }
          }
        }
      ],
      "position": {
        "start": {
          "line": 2,
          "column": 1,
          "offset": 1
        },
        "end": {
          "line": 3,
          "column": 8,
          "offset": 15
        }
      }
    }
  ],
  "position": {
    "start": {
      "line": 1,
      "column": 1,
      "offset": 0
    },
    "end": {
      "line": 4,
      "column": 1,
      "offset": 16
    }
  }
}

And this is the final result (play with the

image

Expected behavior

No paragraph node inside listItem but a direct text node descendant

Actual behavior

An extra paragraph item inside listItem

ChristianMurphy commented 3 years ago

@jepser this is to spec. Commonmark has a paragraph there as well https://spec.commonmark.org/dingus/?text=*%20hola%0A*%20adios%0A%0A

If you need it removed, a remark plugin can remove it from the syntax tree, see https://unifiedjs.com/learn for creating a plugin.


Use this codesandbox: https://codesandbox.io/s/confident-allen-1iqpv?file=/src/App.js

I'm not sure how this sandbox relates? here are the imports from the sandbox:

import React, { useState, useCallback, useMemo } from "react";
import { Slate, Editable, withReact } from "slate-react";
import { Node, Editor, Transforms, Range, Point, createEditor } from "slate";
import { withHistory } from "slate-history";

It doesn't use remark or unified.

jepser commented 3 years ago

Sorry my fault, I didn't updated the codesandox 🙈, it should be updated with the code I'm referring to. But you're right I think if that's common mark I will need to create a plugin that removes that, thanks!

jepser commented 3 years ago

For future reference, I used this mdast-flatten-listitem-paragraphs npm package to fix the problem.

TrySpace commented 2 years ago

@jepser Thanks for that! I've had this issue halting progress with slate for months now.

For future reference: Deserialised Markdown to slate/mdast object issue with creating new list item, inserts empty paragraph, breaking layout and consecutive new list items. Initial listitem state broken after deserialisation.

wooorm commented 2 years ago

y’all should really solve this in the slate transform.