1+ /**
2+ * @typedef {import('hast-util-is-element').TestFunctionAnything } TestFunctionAnything
3+ * @typedef {import('hast').Parent['children'][number] } HastChild
4+ * @typedef {import('hast').Text } HastText
5+ * @typedef {import('hast').Comment } HastComment
6+ * @typedef {import('hast').Root } HastRoot
7+ * @typedef {import('hast').Element } HastElement
8+ * @typedef {import('hast').Properties } HastProperties
9+ * @typedef {HastChild|HastRoot } HastNode
10+ * @typedef {HastRoot|HastElement } HastParent
11+ *
12+ * @typedef {'normal'|'pre'|'nowrap'|'pre-wrap' } Whitespace
13+ * @typedef {boolean } BreakValue
14+ * @typedef {1|2 } BreakNumber
15+ * @typedef {'\n' } BreakForce
16+ * @typedef {BreakValue|BreakNumber } BreakBefore
17+ * @typedef {BreakValue|BreakNumber|BreakForce } BreakAfter
18+ *
19+ * @typedef CollectionOptions
20+ * @property {Whitespace } whitespace
21+ * @property {BreakBefore } breakBefore
22+ * @property {BreakAfter } breakAfter
23+ */
24+
125import repeat from 'repeat-string'
226import { convertElement } from 'hast-util-is-element'
327import { findAfter } from 'unist-util-find-after'
@@ -73,18 +97,33 @@ var blockOrCaption = convertElement([
7397 'xmp' // Flow content (legacy)
7498] )
7599
76- // Implementation of the `innerText` getter:
77- // <https://html.spec.whatwg.org/#the-innertext-idl-attribute>
78- // Note that we act as if `node` is being rendered, and as if we’re a
79- // CSS-supporting user agent.
100+ /**
101+ * Implementation of the `innerText` getter:
102+ * <https://html.spec.whatwg.org/#the-innertext-idl-attribute>
103+ * Note that we act as if `node` is being rendered, and as if we’re a
104+ * CSS-supporting user agent.
105+ *
106+ * @param {HastNode } node
107+ * @returns {string }
108+ */
80109export function toText ( node ) {
110+ /** @type {Array.<HastChild> } */
111+ // @ts -ignore looks like a parent.
81112 var children = node . children || [ ]
82113 var block = blockOrCaption ( node )
83- var whitespace = inferWhitespace ( node , { } )
114+ var whitespace = inferWhitespace ( node , {
115+ whitespace : 'normal' ,
116+ breakBefore : false ,
117+ breakAfter : false
118+ } )
84119 var index = - 1
120+ /** @type {Array.<string|BreakNumber> } */
85121 var results
122+ /** @type {Array.<string> } */
86123 var result
124+ /** @type {string|BreakNumber } */
87125 var value
126+ /** @type {number } */
88127 var count
89128
90129 // Treat `text` and `comment` as having normal white-space.
@@ -96,11 +135,7 @@ export function toText(node) {
96135 // Nodes without children are treated as a void element, so `doctype` is thus
97136 // ignored.
98137 if ( node . type === 'text' || node . type === 'comment' ) {
99- return collectText ( node , {
100- whitespace,
101- breakBefore : true ,
102- breakAfter : true
103- } )
138+ return collectText ( node , { whitespace, breakBefore : true , breakAfter : true } )
104139 }
105140
106141 // 1. If this element is not being rendered, or if the user agent is a
@@ -124,7 +159,8 @@ export function toText(node) {
124159 // positive integer (a required line break count).
125160 // 3.2. For each item item in current, append item to results.
126161 results = results . concat (
127- innerTextCollection ( children [ index ] , index , node , {
162+ // @ts -ignore Looks like a parent.
163+ innerTextCollection ( children [ index ] , node , {
128164 whitespace,
129165 breakBefore : index ? null : block ,
130166 breakAfter :
@@ -159,31 +195,47 @@ export function toText(node) {
159195 return result . join ( '' )
160196}
161197
162- // <https://html.spec.whatwg.org/#inner-text-collection-steps>
163- function innerTextCollection ( node , index , parent , options ) {
198+ /**
199+ * <https://html.spec.whatwg.org/#inner-text-collection-steps>
200+ *
201+ * @param {HastNode } node
202+ * @param {HastParent } parent
203+ * @param {CollectionOptions } options
204+ * @returns {Array.<string|BreakNumber> }
205+ */
206+ function innerTextCollection ( node , parent , options ) {
164207 if ( node . type === 'element' ) {
165- return collectElement ( node , index , parent , options )
208+ return collectElement ( node , parent , options )
166209 }
167210
168211 if ( node . type === 'text' ) {
169212 return [
170213 options . whitespace === 'normal'
171214 ? collectText ( node , options )
172- : collectPreText ( node , options )
215+ : collectPreText ( node )
173216 ]
174217 }
175218
176219 return [ ]
177220}
178221
179- // Collect an element.
180- function collectElement ( node , _ , parent , options ) {
222+ /**
223+ * Collect an element.
224+ *
225+ * @param {HastElement } node
226+ * @param {HastParent } parent
227+ * @param {CollectionOptions } options
228+ */
229+ function collectElement ( node , parent , options ) {
181230 // First we infer the `white-space` property.
182231 var whitespace = inferWhitespace ( node , options )
183232 var children = node . children || [ ]
184233 var index = - 1
234+ /** @type {Array.<string|BreakNumber> } */
185235 var items = [ ]
236+ /** @type {BreakNumber } */
186237 var prefix
238+ /** @type {BreakNumber|BreakForce } */
187239 var suffix
188240
189241 // We’re ignoring point 3, and exiting without any content here, because we
@@ -244,9 +296,9 @@ function collectElement(node, _, parent, options) {
244296 // results to a single list.
245297 while ( ++ index < children . length ) {
246298 items = items . concat (
247- innerTextCollection ( children [ index ] , index , node , {
299+ innerTextCollection ( children [ index ] , node , {
248300 whitespace,
249- breakBefore : index ? null : prefix ,
301+ breakBefore : index ? undefined : prefix ,
250302 breakAfter :
251303 index < children . length - 1 ? br ( children [ index + 1 ] ) : suffix
252304 } )
@@ -270,29 +322,40 @@ function collectElement(node, _, parent, options) {
270322 return items
271323}
272324
273- // 4. If node is a Text node, then for each CSS text box produced by node,
274- // in content order, compute the text of the box after application of the
275- // CSS `white-space` processing rules and `text-transform` rules, set
276- // items to the list of the resulting strings, and return items.
277- // The CSS `white-space` processing rules are slightly modified:
278- // collapsible spaces at the end of lines are always collapsed, but they
279- // are only removed if the line is the last line of the block, or it ends
280- // with a br element.
281- // Soft hyphens should be preserved.
282- //
283- // Note: See `collectText` and `collectPreText`.
284- // Note: we don’t deal with `text-transform`, no element has that by
285- // default.
286- //
287- // See: <https://drafts.csswg.org/css-text/#white-space-phase-1>
325+ /**
326+ * 4. If node is a Text node, then for each CSS text box produced by node,
327+ * in content order, compute the text of the box after application of the
328+ * CSS `white-space` processing rules and `text-transform` rules, set
329+ * items to the list of the resulting strings, and return items.
330+ * The CSS `white-space` processing rules are slightly modified:
331+ * collapsible spaces at the end of lines are always collapsed, but they
332+ * are only removed if the line is the last line of the block, or it ends
333+ * with a br element.
334+ * Soft hyphens should be preserved.
335+ *
336+ * Note: See `collectText` and `collectPreText`.
337+ * Note: we don’t deal with `text-transform`, no element has that by
338+ * default.
339+ *
340+ * See: <https://drafts.csswg.org/css-text/#white-space-phase-1>
341+ *
342+ * @param {HastText|HastComment } node
343+ * @param {CollectionOptions } options
344+ * @returns {string }
345+ */
288346function collectText ( node , options ) {
289347 var value = String ( node . value )
348+ /** @type {Array.<string> } */
290349 var lines = [ ]
350+ /** @type {Array.<string> } */
291351 var result = [ ]
292352 var start = 0
293353 var index = - 1
354+ /** @type {RegExpMatchArray } */
294355 var match
356+ /** @type {number } */
295357 var end
358+ /** @type {string } */
296359 var join
297360
298361 while ( start < value . length ) {
@@ -303,7 +366,7 @@ function collectText(node, options) {
303366 lines . push (
304367 // Any sequence of collapsible spaces and tabs immediately preceding or
305368 // following a segment break is removed.
306- trimAndcollapseSpacesAndTabs (
369+ trimAndCollapseSpacesAndTabs (
307370 // [...] ignoring bidi formatting characters (characters with the
308371 // Bidi_Control property [UAX9]: ALM, LTR, RTL, LRE-RLO, LRI-PDI) as if
309372 // they were not there.
@@ -362,20 +425,34 @@ function collectText(node, options) {
362425 return result . join ( '' )
363426}
364427
428+ /**
429+ * @param {HastText|HastComment } node
430+ * @returns {string }
431+ */
365432function collectPreText ( node ) {
366433 return String ( node . value )
367434}
368435
369- // 3. Every collapsible tab is converted to a collapsible space (U+0020).
370- // 4. Any collapsible space immediately following another collapsible
371- // space—even one outside the boundary of the inline containing that
372- // space, provided both spaces are within the same inline formatting
373- // context—is collapsed to have zero advance width. (It is invisible,
374- // but retains its soft wrap opportunity, if any.)
375- function trimAndcollapseSpacesAndTabs ( value , breakBefore , breakAfter ) {
436+ /**
437+ * 3. Every collapsible tab is converted to a collapsible space (U+0020).
438+ * 4. Any collapsible space immediately following another collapsible
439+ * space—even one outside the boundary of the inline containing that
440+ * space, provided both spaces are within the same inline formatting
441+ * context—is collapsed to have zero advance width. (It is invisible,
442+ * but retains its soft wrap opportunity, if any.)
443+ *
444+ * @param {string } value
445+ * @param {BreakBefore } breakBefore
446+ * @param {BreakAfter } breakAfter
447+ * @returns {string }
448+ */
449+ function trimAndCollapseSpacesAndTabs ( value , breakBefore , breakAfter ) {
450+ /** @type {Array.<string> } */
376451 var result = [ ]
377452 var start = 0
453+ /** @type {RegExpMatchArray } */
378454 var match
455+ /** @type {number } */
379456 var end
380457
381458 while ( start < value . length ) {
@@ -406,34 +483,46 @@ function trimAndcollapseSpacesAndTabs(value, breakBefore, breakAfter) {
406483 return result . join ( ' ' )
407484}
408485
409- // We don’t support void elements here (so `nobr wbr` -> `normal` is ignored).
486+ /**
487+ * We don’t support void elements here (so `nobr wbr` -> `normal` is ignored).
488+ *
489+ * @param {HastNode } node
490+ * @param {CollectionOptions } options
491+ * @returns {Whitespace }
492+ */
410493function inferWhitespace ( node , options ) {
411- var props = node . properties || { }
412- var inherit = options . whitespace || 'normal'
413-
414- switch ( node . tagName ) {
415- case 'listing' :
416- case 'plaintext' :
417- case 'xmp' :
418- return 'pre'
419- case 'nobr' :
420- return 'nowrap'
421- case 'pre' :
422- return props . wrap ? 'pre-wrap' : 'pre'
423- case 'td' :
424- case 'th' :
425- return props . noWrap ? 'nowrap' : inherit
426- case 'textarea' :
427- return 'pre-wrap'
428- default :
429- return inherit
494+ /** @type {HastProperties } */
495+ var props
496+
497+ if ( node . type === 'element' ) {
498+ props = node . properties || { }
499+ switch ( node . tagName ) {
500+ case 'listing' :
501+ case 'plaintext' :
502+ case 'xmp' :
503+ return 'pre'
504+ case 'nobr' :
505+ return 'nowrap'
506+ case 'pre' :
507+ return props . wrap ? 'pre-wrap' : 'pre'
508+ case 'td' :
509+ case 'th' :
510+ return props . noWrap ? 'nowrap' : options . whitespace
511+ case 'textarea' :
512+ return 'pre-wrap'
513+ default :
514+ }
430515 }
516+
517+ return options . whitespace
431518}
432519
520+ /** @type {TestFunctionAnything } */
433521function hidden ( node ) {
434- return ( node . properties || { } ) . hidden
522+ return Boolean ( ( node . properties || { } ) . hidden )
435523}
436524
525+ /** @type {TestFunctionAnything } */
437526function closedDialog ( node ) {
438527 return node . tagName === 'dialog' && ! ( node . properties || { } ) . open
439528}
0 commit comments