@@ -50,58 +50,29 @@ function escapeUserProvidedKey(text) {
5050 return ( '' + text ) . replace ( userProvidedKeyEscapeRegex , '$&/' ) ;
5151}
5252
53- const POOL_SIZE = 10 ;
54- const traverseContextPool = [ ] ;
55- function getPooledTraverseContext (
56- mapResult ,
57- keyPrefix ,
58- mapFunction ,
59- mapContext ,
60- ) {
61- if ( traverseContextPool . length ) {
62- const traverseContext = traverseContextPool . pop ( ) ;
63- traverseContext . result = mapResult ;
64- traverseContext . keyPrefix = keyPrefix ;
65- traverseContext . func = mapFunction ;
66- traverseContext . context = mapContext ;
67- traverseContext . count = 0 ;
68- return traverseContext ;
69- } else {
70- return {
71- result : mapResult ,
72- keyPrefix : keyPrefix ,
73- func : mapFunction ,
74- context : mapContext ,
75- count : 0 ,
76- } ;
77- }
78- }
79-
80- function releaseTraverseContext ( traverseContext ) {
81- traverseContext . result = null ;
82- traverseContext . keyPrefix = null ;
83- traverseContext . func = null ;
84- traverseContext . context = null ;
85- traverseContext . count = 0 ;
86- if ( traverseContextPool . length < POOL_SIZE ) {
87- traverseContextPool . push ( traverseContext ) ;
53+ /**
54+ * Generate a key string that identifies a component within a set.
55+ *
56+ * @param {* } component A component that could contain a manual key.
57+ * @param {number } index Index that is used if a manual key is not provided.
58+ * @return {string }
59+ */
60+ function getComponentKey ( component , index ) {
61+ // Do some typechecking here since we call this blindly. We want to ensure
62+ // that we don't block potential future ES APIs.
63+ if (
64+ typeof component === 'object' &&
65+ component !== null &&
66+ component . key != null
67+ ) {
68+ // Explicit key
69+ return escape ( component . key ) ;
8870 }
71+ // Implicit key determined by the index in the set
72+ return index . toString ( 36 ) ;
8973}
9074
91- /**
92- * @param {?* } children Children tree container.
93- * @param {!string } nameSoFar Name of the key path so far.
94- * @param {!function } callback Callback to invoke with each child found.
95- * @param {?* } traverseContext Used to pass information throughout the traversal
96- * process.
97- * @return {!number } The number of children in this subtree.
98- */
99- function traverseAllChildrenImpl (
100- children ,
101- nameSoFar ,
102- callback ,
103- traverseContext ,
104- ) {
75+ function mapIntoArray ( children , array , escapedPrefix , nameSoFar , callback ) {
10576 const type = typeof children ;
10677
10778 if ( type === 'undefined' || type === 'boolean' ) {
@@ -129,13 +100,33 @@ function traverseAllChildrenImpl(
129100 }
130101
131102 if ( invokeCallback ) {
132- callback (
133- traverseContext ,
134- children ,
135- // If it's the only child, treat the name as if it was wrapped in an array
136- // so that it's consistent if the number of children grows.
137- nameSoFar === '' ? SEPARATOR + getComponentKey ( children , 0 ) : nameSoFar ,
138- ) ;
103+ const child = children ;
104+ let mappedChild = callback ( child ) ;
105+ // If it's the only child, treat the name as if it was wrapped in an array
106+ // so that it's consistent if the number of children grows:
107+ let childKey =
108+ nameSoFar === '' ? SEPARATOR + getComponentKey ( child , 0 ) : nameSoFar ;
109+ if ( Array . isArray ( mappedChild ) ) {
110+ let escapedChildKey = '' ;
111+ if ( childKey != null ) {
112+ escapedChildKey = escapeUserProvidedKey ( childKey ) + '/' ;
113+ }
114+ mapIntoArray ( mappedChild , array , escapedChildKey , c => c ) ;
115+ } else if ( mappedChild != null ) {
116+ if ( isValidElement ( mappedChild ) ) {
117+ mappedChild = cloneAndReplaceKey (
118+ mappedChild ,
119+ // Keep both the (mapped) and old keys if they differ, just as
120+ // traverseAllChildren used to do for objects as children
121+ escapedPrefix +
122+ ( mappedChild . key && ( ! child || child . key !== mappedChild . key )
123+ ? escapeUserProvidedKey ( mappedChild . key ) + '/'
124+ : '' ) +
125+ childKey ,
126+ ) ;
127+ }
128+ array . push ( mappedChild ) ;
129+ }
139130 return 1 ;
140131 }
141132
@@ -149,11 +140,12 @@ function traverseAllChildrenImpl(
149140 for ( let i = 0 ; i < children . length ; i ++ ) {
150141 child = children [ i ] ;
151142 nextName = nextNamePrefix + getComponentKey ( child , i ) ;
152- subtreeCount += traverseAllChildrenImpl (
143+ subtreeCount += mapIntoArray (
153144 child ,
145+ array ,
146+ escapedPrefix ,
154147 nextName ,
155148 callback ,
156- traverseContext ,
157149 ) ;
158150 }
159151 } else {
@@ -188,11 +180,12 @@ function traverseAllChildrenImpl(
188180 while ( ! ( step = iterator . next ( ) ) . done ) {
189181 child = step . value ;
190182 nextName = nextNamePrefix + getComponentKey ( child , ii ++ ) ;
191- subtreeCount += traverseAllChildrenImpl (
183+ subtreeCount += mapIntoArray (
192184 child ,
185+ array ,
186+ escapedPrefix ,
193187 nextName ,
194188 callback ,
195- traverseContext ,
196189 ) ;
197190 }
198191 } else if ( type === 'object' ) {
@@ -218,121 +211,6 @@ function traverseAllChildrenImpl(
218211 return subtreeCount ;
219212}
220213
221- /**
222- * Traverses children that are typically specified as `props.children`, but
223- * might also be specified through attributes:
224- *
225- * - `traverseAllChildren(this.props.children, ...)`
226- * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
227- *
228- * The `traverseContext` is an optional argument that is passed through the
229- * entire traversal. It can be used to store accumulations or anything else that
230- * the callback might find relevant.
231- *
232- * @param {?* } children Children tree object.
233- * @param {!function } callback To invoke upon traversing each child.
234- * @param {?* } traverseContext Context for traversal.
235- * @return {!number } The number of children in this subtree.
236- */
237- function traverseAllChildren ( children , callback , traverseContext ) {
238- if ( children == null ) {
239- return 0 ;
240- }
241-
242- return traverseAllChildrenImpl ( children , '' , callback , traverseContext ) ;
243- }
244-
245- /**
246- * Generate a key string that identifies a component within a set.
247- *
248- * @param {* } component A component that could contain a manual key.
249- * @param {number } index Index that is used if a manual key is not provided.
250- * @return {string }
251- */
252- function getComponentKey ( component , index ) {
253- // Do some typechecking here since we call this blindly. We want to ensure
254- // that we don't block potential future ES APIs.
255- if (
256- typeof component === 'object' &&
257- component !== null &&
258- component . key != null
259- ) {
260- // Explicit key
261- return escape ( component . key ) ;
262- }
263- // Implicit key determined by the index in the set
264- return index . toString ( 36 ) ;
265- }
266-
267- function forEachSingleChild ( bookKeeping , child , name ) {
268- const { func, context} = bookKeeping ;
269- func . call ( context , child , bookKeeping . count ++ ) ;
270- }
271-
272- /**
273- * Iterates through children that are typically specified as `props.children`.
274- *
275- * See https://reactjs.org/docs/react-api.html#reactchildrenforeach
276- *
277- * The provided forEachFunc(child, index) will be called for each
278- * leaf child.
279- *
280- * @param {?* } children Children tree container.
281- * @param {function(*, int) } forEachFunc
282- * @param {* } forEachContext Context for forEachContext.
283- */
284- function forEachChildren ( children , forEachFunc , forEachContext ) {
285- if ( children == null ) {
286- return children ;
287- }
288- const traverseContext = getPooledTraverseContext (
289- null ,
290- null ,
291- forEachFunc ,
292- forEachContext ,
293- ) ;
294- traverseAllChildren ( children , forEachSingleChild , traverseContext ) ;
295- releaseTraverseContext ( traverseContext ) ;
296- }
297-
298- function mapSingleChildIntoContext ( bookKeeping , child , childKey ) {
299- const { result, keyPrefix, func, context} = bookKeeping ;
300-
301- let mappedChild = func . call ( context , child , bookKeeping . count ++ ) ;
302- if ( Array . isArray ( mappedChild ) ) {
303- mapIntoWithKeyPrefixInternal ( mappedChild , result , childKey , c => c ) ;
304- } else if ( mappedChild != null ) {
305- if ( isValidElement ( mappedChild ) ) {
306- mappedChild = cloneAndReplaceKey (
307- mappedChild ,
308- // Keep both the (mapped) and old keys if they differ, just as
309- // traverseAllChildren used to do for objects as children
310- keyPrefix +
311- ( mappedChild . key && ( ! child || child . key !== mappedChild . key )
312- ? escapeUserProvidedKey ( mappedChild . key ) + '/'
313- : '' ) +
314- childKey ,
315- ) ;
316- }
317- result . push ( mappedChild ) ;
318- }
319- }
320-
321- function mapIntoWithKeyPrefixInternal ( children , array , prefix , func , context ) {
322- let escapedPrefix = '' ;
323- if ( prefix != null ) {
324- escapedPrefix = escapeUserProvidedKey ( prefix ) + '/' ;
325- }
326- const traverseContext = getPooledTraverseContext (
327- array ,
328- escapedPrefix ,
329- func ,
330- context ,
331- ) ;
332- traverseAllChildren ( children , mapSingleChildIntoContext , traverseContext ) ;
333- releaseTraverseContext ( traverseContext ) ;
334- }
335-
336214/**
337215 * Maps children that are typically specified as `props.children`.
338216 *
@@ -351,7 +229,17 @@ function mapChildren(children, func, context) {
351229 return children ;
352230 }
353231 const result = [ ] ;
354- mapIntoWithKeyPrefixInternal ( children , result , null , func , context ) ;
232+ let count = 0 ;
233+ mapIntoArray (
234+ children ,
235+ result ,
236+ '' ,
237+ '' ,
238+ function ( child ) {
239+ return func . call ( context , child , count ++ ) ;
240+ } ,
241+ context ,
242+ ) ;
355243 return result ;
356244}
357245
@@ -365,7 +253,32 @@ function mapChildren(children, func, context) {
365253 * @return {number } The number of children.
366254 */
367255function countChildren ( children ) {
368- return traverseAllChildren ( children , ( ) => null , null ) ;
256+ let n = 0 ;
257+ mapChildren ( children , ( ) => n ++ ) ;
258+ return n ;
259+ }
260+
261+ /**
262+ * Iterates through children that are typically specified as `props.children`.
263+ *
264+ * See https://reactjs.org/docs/react-api.html#reactchildrenforeach
265+ *
266+ * The provided forEachFunc(child, index) will be called for each
267+ * leaf child.
268+ *
269+ * @param {?* } children Children tree container.
270+ * @param {function(*, int) } forEachFunc
271+ * @param {* } forEachContext Context for forEachContext.
272+ */
273+ function forEachChildren ( children , forEachFunc , forEachContext ) {
274+ mapChildren (
275+ children ,
276+ function ( ) {
277+ forEachFunc . apply ( this , arguments ) ;
278+ // Don't return anything.
279+ } ,
280+ forEachContext ,
281+ ) ;
369282}
370283
371284/**
@@ -375,9 +288,7 @@ function countChildren(children) {
375288 * See https://reactjs.org/docs/react-api.html#reactchildrentoarray
376289 */
377290function toArray ( children ) {
378- const result = [ ] ;
379- mapIntoWithKeyPrefixInternal ( children , result , null , child => child ) ;
380- return result ;
291+ return mapChildren ( children , child => child ) || [ ] ;
381292}
382293
383294/**
0 commit comments