diff --git a/lib/handlers/li.js b/lib/handlers/li.js index 1784ceb..017a34d 100644 --- a/lib/handlers/li.js +++ b/lib/handlers/li.js @@ -4,6 +4,8 @@ * @typedef {import('../state.js').State} State */ +import {phrasing} from 'hast-util-phrasing' + /** * @param {State} state * State. @@ -42,15 +44,56 @@ export function li(state, node) { } } - const children = state.toFlow(state.all(clone || node)) + if (!clone) clone = node + + const spread = spreadout(clone) + const children = state.toFlow(state.all(clone)) /** @type {ListItem} */ - const result = { - type: 'listItem', - spread: children.length > 1, - checked, - children - } - state.patch(node, result) + const result = {type: 'listItem', spread, checked, children} + state.patch(clone, result) return result } + +/** + * Check if an element should spread out. + * + * The reason to spread out a markdown list item is primarily whether writing + * the equivalent in markdown, would yield a spread out item. + * + * A spread out item results in `

` and `

` tags. + * Otherwise, the phrasing would be output directly. + * We can check for that: if there’s a `

` element, spread it out. + * + * But what if there are no paragraphs? + * In that case, we can also assume that if two “block” things were written in + * an item, that it is spread out, because blocks are typically joined by blank + * lines, which also means a spread item. + * + * Lastly, because in HTML things can be wrapped in a `

` or similar, we + * delve into non-phrasing elements here to figure out if they themselves + * contain paragraphs or 2 or more flow non-phrasing elements. + * + * @param {Element} node + * @returns {boolean} + */ +function spreadout(node) { + let index = -1 + let seenFlow = false + + while (++index < node.children.length) { + const child = node.children[index] + + if (child.type === 'element') { + if (phrasing(child)) continue + + if (child.tagName === 'p' || seenFlow || spreadout(child)) { + return true + } + + seenFlow = true + } + } + + return false +} diff --git a/test/fixtures/dl/index.json b/test/fixtures/dl/index.json index a875830..fe70035 100644 --- a/test/fixtures/dl/index.json +++ b/test/fixtures/dl/index.json @@ -1,3 +1,5 @@ { + "": "spread can’t be losslessly translated between HTML <> markdown", + "tree": false, "fragment": true } diff --git a/test/fixtures/dl/index.md b/test/fixtures/dl/index.md index 1150ed7..f538704 100644 --- a/test/fixtures/dl/index.md +++ b/test/fixtures/dl/index.md @@ -22,7 +22,9 @@ Charlie. * Firefox * A web browser. + * A Red Panda. + * ```js charlie(); ``` diff --git a/test/fixtures/ol/index.json b/test/fixtures/ol/index.json index a875830..fe70035 100644 --- a/test/fixtures/ol/index.json +++ b/test/fixtures/ol/index.json @@ -1,3 +1,5 @@ { + "": "spread can’t be losslessly translated between HTML <> markdown", + "tree": false, "fragment": true } diff --git a/test/fixtures/ol/index.md b/test/fixtures/ol/index.md index 16f435a..6c4b2f6 100644 --- a/test/fixtures/ol/index.md +++ b/test/fixtures/ol/index.md @@ -1,5 +1,7 @@ 2. Alpha + 3. Bravo + 4. ```js charlie(); ``` @@ -27,23 +29,31 @@ Bar. Baz. 1. + 2. Something else Qux. 1. Something else + 2. Quux. 1. Something else + 2. Quuux. 1. [x] Bravo + 2. [ ] Charlie + 3. [x] Delta + 4. [ ] Echo + 5. [ ] **Foxtrot** + 6. [ ] **Golf** diff --git a/test/fixtures/ul/index.json b/test/fixtures/ul/index.json index a875830..fe70035 100644 --- a/test/fixtures/ul/index.json +++ b/test/fixtures/ul/index.json @@ -1,3 +1,5 @@ { + "": "spread can’t be losslessly translated between HTML <> markdown", + "tree": false, "fragment": true } diff --git a/test/fixtures/ul/index.md b/test/fixtures/ul/index.md index cc1d379..490718a 100644 --- a/test/fixtures/ul/index.md +++ b/test/fixtures/ul/index.md @@ -1,5 +1,7 @@ * Alpha + * Bravo + * ```js charlie(); ``` @@ -27,23 +29,31 @@ Bar. Baz. * + * Something else Qux. * Something else + * Quux. * Something else + * Quuux. * [x] Bravo + * [ ] Charlie + * [x] Delta + * [ ] Echo + * [ ] **Foxtrot** + * [ ] **Golf**