@@ -50,58 +50,29 @@ function escapeUserProvidedKey(text) {
50
50
return ( '' + text ) . replace ( userProvidedKeyEscapeRegex , '$&/' ) ;
51
51
}
52
52
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 ) ;
88
70
}
71
+ // Implicit key determined by the index in the set
72
+ return index . toString ( 36 ) ;
89
73
}
90
74
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 ) {
105
76
const type = typeof children ;
106
77
107
78
if ( type === 'undefined' || type === 'boolean' ) {
@@ -129,13 +100,33 @@ function traverseAllChildrenImpl(
129
100
}
130
101
131
102
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
+ }
139
130
return 1 ;
140
131
}
141
132
@@ -149,11 +140,12 @@ function traverseAllChildrenImpl(
149
140
for ( let i = 0 ; i < children . length ; i ++ ) {
150
141
child = children [ i ] ;
151
142
nextName = nextNamePrefix + getComponentKey ( child , i ) ;
152
- subtreeCount += traverseAllChildrenImpl (
143
+ subtreeCount += mapIntoArray (
153
144
child ,
145
+ array ,
146
+ escapedPrefix ,
154
147
nextName ,
155
148
callback ,
156
- traverseContext ,
157
149
) ;
158
150
}
159
151
} else {
@@ -188,11 +180,12 @@ function traverseAllChildrenImpl(
188
180
while ( ! ( step = iterator . next ( ) ) . done ) {
189
181
child = step . value ;
190
182
nextName = nextNamePrefix + getComponentKey ( child , ii ++ ) ;
191
- subtreeCount += traverseAllChildrenImpl (
183
+ subtreeCount += mapIntoArray (
192
184
child ,
185
+ array ,
186
+ escapedPrefix ,
193
187
nextName ,
194
188
callback ,
195
- traverseContext ,
196
189
) ;
197
190
}
198
191
} else if ( type === 'object' ) {
@@ -218,121 +211,6 @@ function traverseAllChildrenImpl(
218
211
return subtreeCount ;
219
212
}
220
213
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
-
336
214
/**
337
215
* Maps children that are typically specified as `props.children`.
338
216
*
@@ -351,7 +229,17 @@ function mapChildren(children, func, context) {
351
229
return children ;
352
230
}
353
231
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
+ ) ;
355
243
return result ;
356
244
}
357
245
@@ -365,7 +253,32 @@ function mapChildren(children, func, context) {
365
253
* @return {number } The number of children.
366
254
*/
367
255
function 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
+ ) ;
369
282
}
370
283
371
284
/**
@@ -375,9 +288,7 @@ function countChildren(children) {
375
288
* See https://reactjs.org/docs/react-api.html#reactchildrentoarray
376
289
*/
377
290
function toArray ( children ) {
378
- const result = [ ] ;
379
- mapIntoWithKeyPrefixInternal ( children , result , null , child => child ) ;
380
- return result ;
291
+ return mapChildren ( children , child => child ) || [ ] ;
381
292
}
382
293
383
294
/**
0 commit comments