50
return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
51
}
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);
70
}
71
+ // Implicit key determined by the index in the set
72
+ return index.toString(36);
73
}
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) {
76
const type = typeof children;
77
78
if (type === 'undefined' || type === 'boolean') {
100
}
101
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
+ }
130
return 1;
131
}
132
140
for (let i = 0; i < children.length; i++) {
141
child = children[i];
142
nextName = nextNamePrefix + getComponentKey(child, i);
152
- subtreeCount += traverseAllChildrenImpl(
143
+ subtreeCount += mapIntoArray(
144
child,
145
+ array,
146
+ escapedPrefix,
147
nextName,
148
callback,
156
- traverseContext,
149
);
150
}
151
} else {
180
while (!(step = iterator.next()).done) {
181
child = step.value;
182
nextName = nextNamePrefix + getComponentKey(child, ii++);
191
- subtreeCount += traverseAllChildrenImpl(
183
+ subtreeCount += mapIntoArray(
184
child,
185
+ array,
186
+ escapedPrefix,
187
nextName,
188
callback,
195
- traverseContext,
189
);
190
}
191
} else if (type === 'object') {
211
return subtreeCount;
212
}
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
-
214
/**
215
* Maps children that are typically specified as `props.children`.
216
*
229
return children;
230
}
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
+ );
243
return result;
244
}
245
253
* @return {number} The number of children.
254
*/
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
+ );
282
}
283
284
/**
288
* See https://reactjs.org/docs/react-api.html#reactchildrentoarray
289
*/
290
function toArray(children) {
378
- const result = [];
379
- mapIntoWithKeyPrefixInternal(children, result, null, child => child);
380
- return result;
291
+ return mapChildren(children, child => child) || [];
292
}
293
294
/**