UNPKG

react-pivot

Version:

React-Pivot is a data-grid component with pivot-table-like functionality for data display, filtering, and exploration.

279 lines (249 loc) 8.53 kB
/** * Copyright 2014, 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 ReactElementValidator */ /** * ReactElementValidator provides a wrapper around a element factory * which validates the props passed to the element. This is intended to be * used only in DEV and could be replaced by a static type checker for languages * that support it. */ "use strict"; var ReactElement = require("./ReactElement"); var ReactPropTypeLocations = require("./ReactPropTypeLocations"); var ReactCurrentOwner = require("./ReactCurrentOwner"); var monitorCodeUse = require("./monitorCodeUse"); var warning = require("./warning"); /** * Warn if there's no key explicitly set on dynamic arrays of children or * object keys are not valid. This allows us to keep track of children between * updates. */ var ownerHasKeyUseWarning = { 'react_key_warning': {}, 'react_numeric_key_warning': {} }; var ownerHasMonitoredObjectMap = {}; var loggedTypeFailures = {}; var NUMERIC_PROPERTY_REGEX = /^\d+$/; /** * Gets the current owner's displayName for use in warnings. * * @internal * @return {?string} Display name or undefined */ function getCurrentOwnerDisplayName() { var current = ReactCurrentOwner.current; return current && current.constructor.displayName || undefined; } /** * Warn if the component doesn't have an explicit key assigned to it. * This component is in an array. The array could grow and shrink or be * reordered. All children that haven't already been validated are required to * have a "key" property assigned to it. * * @internal * @param {ReactComponent} component Component that requires a key. * @param {*} parentType component's parent's type. */ function validateExplicitKey(component, parentType) { if (component._store.validated || component.key != null) { return; } component._store.validated = true; warnAndMonitorForKeyUse( 'react_key_warning', 'Each child in an array should have a unique "key" prop.', component, parentType ); } /** * Warn if the key is being defined as an object property but has an incorrect * value. * * @internal * @param {string} name Property name of the key. * @param {ReactComponent} component Component that requires a key. * @param {*} parentType component's parent's type. */ function validatePropertyKey(name, component, parentType) { if (!NUMERIC_PROPERTY_REGEX.test(name)) { return; } warnAndMonitorForKeyUse( 'react_numeric_key_warning', 'Child objects should have non-numeric keys so ordering is preserved.', component, parentType ); } /** * Shared warning and monitoring code for the key warnings. * * @internal * @param {string} warningID The id used when logging. * @param {string} message The base warning that gets output. * @param {ReactComponent} component Component that requires a key. * @param {*} parentType component's parent's type. */ function warnAndMonitorForKeyUse(warningID, message, component, parentType) { var ownerName = getCurrentOwnerDisplayName(); var parentName = parentType.displayName; var useName = ownerName || parentName; var memoizer = ownerHasKeyUseWarning[warningID]; if (memoizer.hasOwnProperty(useName)) { return; } memoizer[useName] = true; message += ownerName ? (" Check the render method of " + ownerName + ".") : (" Check the renderComponent call using <" + parentName + ">."); // Usually the current owner is the offender, but if it accepts children as a // property, it may be the creator of the child that's responsible for // assigning it a key. var childOwnerName = null; if (component._owner && component._owner !== ReactCurrentOwner.current) { // Name of the component that originally created this child. childOwnerName = component._owner.constructor.displayName; message += (" It was passed a child from " + childOwnerName + "."); } message += ' See http://fb.me/react-warning-keys for more information.'; monitorCodeUse(warningID, { component: useName, componentOwner: childOwnerName }); console.warn(message); } /** * Log that we're using an object map. We're considering deprecating this * feature and replace it with proper Map and ImmutableMap data structures. * * @internal */ function monitorUseOfObjectMap() { var currentName = getCurrentOwnerDisplayName() || ''; if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) { return; } ownerHasMonitoredObjectMap[currentName] = true; monitorCodeUse('react_object_map_children'); } /** * Ensure that every component either is passed in a static location, in an * array with an explicit keys property defined, or in an object literal * with valid key property. * * @internal * @param {*} component Statically passed child of any type. * @param {*} parentType component's parent's type. * @return {boolean} */ function validateChildKeys(component, parentType) { if (Array.isArray(component)) { for (var i = 0; i < component.length; i++) { var child = component[i]; if (ReactElement.isValidElement(child)) { validateExplicitKey(child, parentType); } } } else if (ReactElement.isValidElement(component)) { // This component was passed in a valid location. component._store.validated = true; } else if (component && typeof component === 'object') { monitorUseOfObjectMap(); for (var name in component) { validatePropertyKey(name, component[name], parentType); } } } /** * Assert that the props are valid * * @param {string} componentName Name of the component for error messages. * @param {object} propTypes Map of prop name to a ReactPropType * @param {object} props * @param {string} location e.g. "prop", "context", "child context" * @private */ function checkPropTypes(componentName, propTypes, props, location) { for (var propName in propTypes) { if (propTypes.hasOwnProperty(propName)) { var error; // Prop type validation may throw. In case they do, we don't want to // fail the render phase where it didn't fail before. So we log it. // After these have been cleaned up, we'll let them throw. try { error = propTypes[propName](props, propName, componentName, location); } catch (ex) { error = ex; } if (error instanceof Error && !(error.message in loggedTypeFailures)) { // Only monitor this failure once because there tends to be a lot of the // same error. loggedTypeFailures[error.message] = true; // This will soon use the warning module monitorCodeUse( 'react_failed_descriptor_type_check', { message: error.message } ); } } } } var ReactElementValidator = { createElement: function(type, props, children) { // We warn in this case but don't throw. We expect the element creation to // succeed and there will likely be errors in render. ("production" !== process.env.NODE_ENV ? warning( type != null, 'React.createElement: type should not be null or undefined. It should ' + 'be a string (for DOM elements) or a ReactClass (for composite ' + 'components).' ) : null); var element = ReactElement.createElement.apply(this, arguments); // The result can be nullish if a mock or a custom function is used. // TODO: Drop this when these are no longer allowed as the type argument. if (element == null) { return element; } for (var i = 2; i < arguments.length; i++) { validateChildKeys(arguments[i], type); } if (type) { var name = type.displayName; if (type.propTypes) { checkPropTypes( name, type.propTypes, element.props, ReactPropTypeLocations.prop ); } if (type.contextTypes) { checkPropTypes( name, type.contextTypes, element._context, ReactPropTypeLocations.context ); } } return element; }, createFactory: function(type) { var validatedFactory = ReactElementValidator.createElement.bind( null, type ); validatedFactory.type = type; return validatedFactory; } }; module.exports = ReactElementValidator;