@@ -4,18 +4,39 @@ module.exports = wrap
4
4
5
5
wrap . needed = needed
6
6
7
+ var extend = require ( 'extend' )
7
8
var phrasing = require ( 'mdast-util-phrasing' )
8
9
9
- // Wrap all runs of mdast phrasing content in `paragraph` nodes.
10
10
function wrap ( nodes ) {
11
+ return runs ( nodes , onphrasing )
12
+
13
+ function onphrasing ( nodes ) {
14
+ var head = nodes [ 0 ]
15
+
16
+ if (
17
+ nodes . length === 1 &&
18
+ head . type === 'text' &&
19
+ ( head . value === ' ' || head . value === '\n' )
20
+ ) {
21
+ return [ ]
22
+ }
23
+
24
+ return { type : 'paragraph' , children : nodes }
25
+ }
26
+ }
27
+
28
+ // Wrap all runs of mdast phrasing content in `paragraph` nodes.
29
+ function runs ( nodes , onphrasing , onnonphrasing ) {
30
+ var nonphrasing = onnonphrasing || identity
11
31
var result = [ ]
12
- var length = nodes . length
32
+ var flattened = flatten ( nodes )
33
+ var length = flattened . length
13
34
var index = - 1
14
35
var node
15
36
var queue
16
37
17
38
while ( ++ index < length ) {
18
- node = nodes [ index ]
39
+ node = flattened [ index ]
19
40
20
41
if ( phrasing ( node ) ) {
21
42
if ( queue === undefined ) {
@@ -24,42 +45,114 @@ function wrap(nodes) {
24
45
25
46
queue . push ( node )
26
47
} else {
27
- flush ( )
28
- result . push ( node )
48
+ add ( )
49
+ result = result . concat ( nonphrasing ( node ) )
29
50
}
30
51
}
31
52
32
- flush ( )
53
+ add ( )
33
54
34
55
return result
35
56
36
- function flush ( ) {
57
+ function add ( ) {
37
58
if ( queue !== undefined ) {
38
- if (
39
- queue . length !== 1 ||
40
- queue [ 0 ] . type !== 'text' ||
41
- ( queue [ 0 ] . value !== ' ' && queue [ 0 ] . value !== '\n' )
42
- ) {
43
- result . push ( { type : 'paragraph' , children : queue } )
44
- }
59
+ result = result . concat ( onphrasing ( queue ) )
45
60
}
46
61
47
62
queue = undefined
48
63
}
49
64
}
50
65
66
+ // Flatten a list of nodes.
67
+ function flatten ( nodes ) {
68
+ var length = nodes . length
69
+ var index = - 1
70
+ var flattened = [ ]
71
+ var node
72
+
73
+ while ( ++ index < length ) {
74
+ node = nodes [ index ]
75
+
76
+ // Straddling: some elements are *weird*.
77
+ // Namely: `map`, `ins`, `del`, and `a`, as they are hybrid elements.
78
+ // See: <https://html.spec.whatwg.org/#paragraphs>.
79
+ // Paragraphs are the weirdest of them all.
80
+ // See the straddling fixture for more info!
81
+ // `ins` is ignored in mdast, so we don’t need to worry about that.
82
+ // `map` maps to its content, so we don’t need to worry about that either.
83
+ // `del` maps to `delete` and `a` to `link`, so we do handle those.
84
+ // What we’ll do is split `node` over each of its children.
85
+ if (
86
+ ( node . type === 'delete' || node . type === 'link' ) &&
87
+ needed ( node . children )
88
+ ) {
89
+ flattened = flattened . concat ( split ( node ) )
90
+ } else {
91
+ flattened . push ( node )
92
+ }
93
+ }
94
+
95
+ return flattened
96
+ }
97
+
51
98
// Check if there are non-phrasing mdast nodes returned.
52
99
// This is needed if a fragment is given, which could just be a sentence, and
53
100
// doesn’t need a wrapper paragraph.
54
101
function needed ( nodes ) {
55
102
var length = nodes . length
56
103
var index = - 1
104
+ var node
105
+ var children
57
106
58
107
while ( ++ index < length ) {
59
- if ( ! phrasing ( nodes [ index ] ) ) {
108
+ node = nodes [ index ]
109
+ children = node . children
110
+
111
+ if ( ! phrasing ( node ) || ( children && needed ( children ) ) ) {
60
112
return true
61
113
}
62
114
}
63
115
64
116
return false
65
117
}
118
+
119
+ function split ( node ) {
120
+ return runs ( node . children , onphrasing , onnonphrasing )
121
+
122
+ // Use `child`, add `parent` as its first child, put the original children
123
+ // into `parent`.
124
+ function onnonphrasing ( child ) {
125
+ var parent = extend ( true , { } , shallow ( node ) )
126
+ var copy = shallow ( child )
127
+
128
+ copy . children = [ parent ]
129
+ parent . children = child . children
130
+
131
+ return copy
132
+ }
133
+
134
+ // Use `parent`, put the phrasing run inside it.
135
+ function onphrasing ( nodes ) {
136
+ var parent = extend ( true , { } , shallow ( node ) )
137
+ parent . children = nodes
138
+ return parent
139
+ }
140
+ }
141
+
142
+ // Shallow copy of a node, excluding its children.
143
+ function shallow ( node ) {
144
+ var copy = { }
145
+ var key
146
+
147
+ for ( key in node ) {
148
+ if ( key !== 'children' ) {
149
+ copy [ key ] = node [ key ]
150
+ }
151
+ }
152
+
153
+ return copy
154
+ }
155
+
156
+ function identity ( n ) {
157
+ return n
158
+ }
0 commit comments