UNPKG

react-native-macos

Version:

A framework for building native macOS apps using React

194 lines (174 loc) 5.84 kB
/** * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule traverseStackChildren */ 'use strict'; var REACT_ELEMENT_TYPE = require('ReactElementSymbol'); var getIteratorFn = require('getIteratorFn'); var invariant = require('fbjs/lib/invariant'); var KeyEscapeUtils = require('KeyEscapeUtils'); var warning = require('fbjs/lib/warning'); if (__DEV__) { var { getCurrentStackAddendum, } = require('ReactGlobalSharedState').ReactComponentTreeHook; } var SEPARATOR = '.'; var SUBSEPARATOR = ':'; /** * This is inlined from ReactElement since this file is shared between * isomorphic and renderers. We could extract this to a * */ /** * TODO: Test that a single child and an array with one item have the same key * pattern. */ var didWarnAboutMaps = false; /** * Generate a key string that identifies a component within a set. * * @param {*} component A component that could contain a manual key. * @param {number} index Index that is used if a manual key is not provided. * @return {string} */ function getComponentKey(component, index) { // Do some typechecking here since we call this blindly. We want to ensure // that we don't block potential future ES APIs. if (component && typeof component === 'object' && component.key != null) { // Explicit key return KeyEscapeUtils.escape(component.key); } // Implicit key determined by the index in the set return index.toString(36); } /** * @param {?*} children Children tree container. * @param {!string} nameSoFar Name of the key path so far. * @param {!function} callback Callback to invoke with each child found. * @param {?*} traverseContext Used to pass information throughout the traversal * process. * @return {!number} The number of children in this subtree. */ function traverseStackChildrenImpl( children, nameSoFar, callback, traverseContext, ) { var type = typeof children; if (type === 'undefined' || type === 'boolean') { // All of the above are perceived as null. children = null; } if ( children === null || type === 'string' || type === 'number' || // The following is inlined from ReactElement. This means we can optimize // some checks. React Fiber also inlines this logic for similar purposes. (type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) ) { callback( traverseContext, children, // If it's the only child, treat the name as if it was wrapped in an array // so that it's consistent if the number of children grows. nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar, ); return 1; } var child; var nextName; var subtreeCount = 0; // Count of children found in the current subtree. var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { child = children[i]; nextName = nextNamePrefix + getComponentKey(child, i); subtreeCount += traverseStackChildrenImpl( child, nextName, callback, traverseContext, ); } } else { var iteratorFn = getIteratorFn(children); if (iteratorFn) { if (__DEV__) { // Warn about using Maps as children if (iteratorFn === children.entries) { warning( didWarnAboutMaps, 'Using Maps as children is unsupported and will likely yield ' + 'unexpected results. Convert it to a sequence/iterable of keyed ' + 'ReactElements instead.%s', getCurrentStackAddendum(), ); didWarnAboutMaps = true; } } var iterator = iteratorFn.call(children); var step; var ii = 0; while (!(step = iterator.next()).done) { child = step.value; nextName = nextNamePrefix + getComponentKey(child, ii++); subtreeCount += traverseStackChildrenImpl( child, nextName, callback, traverseContext, ); } } else if (type === 'object') { var addendum = ''; if (__DEV__) { addendum = ' If you meant to render a collection of children, use an array ' + 'instead.' + getCurrentStackAddendum(); } var childrenString = '' + children; invariant( false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum, ); } } return subtreeCount; } /** * Traverses children that are typically specified as `props.children`, but * might also be specified through attributes: * * - `traverseStackChildren(this.props.children, ...)` * - `traverseStackChildren(this.props.leftPanelChildren, ...)` * * The `traverseContext` is an optional argument that is passed through the * entire traversal. It can be used to store accumulations or anything else that * the callback might find relevant. * * @param {?*} children Children tree object. * @param {!function} callback To invoke upon traversing each child. * @param {?*} traverseContext Context for traversal. * @return {!number} The number of children in this subtree. */ function traverseStackChildren(children, callback, traverseContext) { if (children == null) { return 0; } return traverseStackChildrenImpl(children, '', callback, traverseContext); } module.exports = traverseStackChildren;