66 * @typedef {import('../state.js').State } State
77 */
88
9+ /**
10+ * @typedef ExtractResult
11+ * Result of extracting a leading checkbox.
12+ * @property {Element | undefined } checkbox
13+ * The checkbox that was removed, if any.
14+ * @property {Element } rest
15+ * If there was a leading checkbox, a deep clone of the node w/o the leading
16+ * checkbox; otherwise a reference to the given, untouched, node.
17+ */
18+
919import { phrasing } from 'hast-util-phrasing'
1020
1121/**
@@ -19,15 +29,14 @@ import {phrasing} from 'hast-util-phrasing'
1929export function li ( state , node ) {
2030 // If the list item starts with a checkbox, remove the checkbox and mark the
2131 // list item as a GFM task list item.
22- const { cleanNode, checkbox} = extractLeadingCheckbox ( node )
23- const checked = checkbox && Boolean ( checkbox . properties . checked )
24-
25- const spread = spreadout ( cleanNode )
26- const children = state . toFlow ( state . all ( cleanNode ) )
32+ const { rest, checkbox} = extractLeadingCheckbox ( node )
33+ const checked = checkbox ? Boolean ( checkbox . properties . checked ) : null
34+ const spread = spreadout ( rest )
35+ const children = state . toFlow ( state . all ( rest ) )
2736
2837 /** @type {ListItem } */
2938 const result = { type : 'listItem' , spread, checked, children}
30- state . patch ( cleanNode , result )
39+ state . patch ( node , result )
3140 return result
3241}
3342
@@ -75,23 +84,36 @@ function spreadout(node) {
7584}
7685
7786/**
78- * If the first bit of content in an element is a checkbox, create a copy of
79- * the element that does not include the checkbox and return the cleaned up
80- * copy alongside the checkbox that was removed. If there was no leading
81- * checkbox, this returns the original element unaltered (not a copy).
87+ * Extract a leading checkbox from a list item.
88+ *
89+ * If there was a leading checkbox, makes a deep clone of the node w/o the
90+ * leading checkbox; otherwise a reference to the given, untouched, node is
91+ * given back.
92+ *
93+ * So for example:
94+ *
95+ * ```html
96+ * <li><input type="checkbox">Text</li>
97+ * ```
8298 *
83- * This detects trees like:
84- * `<li><input type="checkbox">Text</li>`
85- * And returns a tree like:
86- * `<li>Text</li>`
99+ * …becomes:
87100 *
88- * Or with nesting:
89- * `<li><p><input type="checkbox">Text</p></li>`
90- * Which returns a tree like:
91- * `<li><p>Text</p></li>`
101+ * ```html
102+ * <li>Text</li>
103+ * ```
104+ *
105+ * ```html
106+ * <li><p><input type="checkbox">Text</p></li>
107+ * ```
108+ *
109+ * …becomes:
110+ *
111+ * ```html
112+ * <li><p>Text</p></li>
113+ * ```
92114 *
93115 * @param {Readonly<Element> } node
94- * @returns {{cleanNode: Element, checkbox: Element | null} }
116+ * @returns {ExtractResult }
95117 */
96118function extractLeadingCheckbox ( node ) {
97119 const head = node . children [ 0 ]
@@ -103,31 +125,25 @@ function extractLeadingCheckbox(node) {
103125 head . properties &&
104126 ( head . properties . type === 'checkbox' || head . properties . type === 'radio' )
105127 ) {
106- return {
107- cleanNode : { ...node , children : node . children . slice ( 1 ) } ,
108- checkbox : head
109- }
128+ const rest = { ...node , children : node . children . slice ( 1 ) }
129+ return { checkbox : head , rest}
110130 }
111131
112- // The checkbox may be nested in another element. If the first element has
113- // children, look for a leading checkbox inside it.
132+ // The checkbox may be nested in another element.
133+ // If the first element has children, look for a leading checkbox inside it.
114134 //
115- // NOTE: this only handles nesting in `<p>` elements, which is most common.
116- // It' s possible a leading checkbox might be nested in other types of flow or
135+ // This only handles nesting in `<p>` elements, which is most common.
136+ // It’ s possible a leading checkbox might be nested in other types of flow or
117137 // phrasing elements (and *deeply* nested, which is not possible with `<p>`).
118138 // Limiting things to `<p>` elements keeps this simpler for now.
119139 if ( head && head . type === 'element' && head . tagName === 'p' ) {
120- const { cleanNode : cleanHead , checkbox} = extractLeadingCheckbox ( head )
140+ const { checkbox, rest : restHead } = extractLeadingCheckbox ( head )
141+
121142 if ( checkbox ) {
122- return {
123- cleanNode : {
124- ...node ,
125- children : [ cleanHead , ...node . children . slice ( 1 ) ]
126- } ,
127- checkbox
128- }
143+ const rest = { ...node , children : [ restHead , ...node . children . slice ( 1 ) ] }
144+ return { checkbox, rest}
129145 }
130146 }
131147
132- return { cleanNode : node , checkbox : null }
148+ return { checkbox : undefined , rest : node }
133149}
0 commit comments