@samitouri / QOS-React-2 / commits / 88c94683d6

Revert "Move defaultProps resolution and type validation to the descriptor"

This reverts commit ff52e3df00ab7ed1375f46d81c122a614e202bb9. Too many things broke with transferPropsTo

Paul O’Shannessy committed May 6, 2014 at 09:09 UTC 88c94683d687e28429d08d2aa046755f67e2d70b
5 files changed +205 -386
src/browser/ReactDOM.js
-7
@@ -20,7 +20,6 @@
20 "use strict";
21
22 var ReactDescriptor = require('ReactDescriptor');
23 -var ReactDescriptorValidator = require('ReactDescriptorValidator');
23 var ReactDOMComponent = require('ReactDOMComponent');
24
25 var mergeInto = require('mergeInto');
@@ -51,12 +50,6 @@ function createDOMComponentClass(omitClose, tag) {
50
51 var ConvenienceConstructor = ReactDescriptor.createFactory(Constructor);
52
54 - if (__DEV__) {
55 - return ReactDescriptorValidator.createFactory(
56 - ConvenienceConstructor
57 - );
58 - }
59 -
53 return ConvenienceConstructor;
54 }
55
src/core/ReactCompositeComponent.js
+37 -45
@@ -22,7 +22,6 @@ var ReactComponent = require('ReactComponent');
22 var ReactContext = require('ReactContext');
23 var ReactCurrentOwner = require('ReactCurrentOwner');
24 var ReactDescriptor = require('ReactDescriptor');
25 -var ReactDescriptorValidator = require('ReactDescriptorValidator');
25 var ReactEmptyComponent = require('ReactEmptyComponent');
26 var ReactErrorUtils = require('ReactErrorUtils');
27 var ReactOwner = require('ReactOwner');
@@ -329,17 +328,18 @@ var ReactCompositeComponentInterface = {
328 * which all other static methods are defined.
329 */
330 var RESERVED_SPEC_KEYS = {
332 - displayName: function(Constructor, displayName) {
333 - Constructor.displayName = displayName;
331 + displayName: function(ConvenienceConstructor, displayName) {
332 + ConvenienceConstructor.type.displayName = displayName;
333 },
335 - mixins: function(Constructor, mixins) {
334 + mixins: function(ConvenienceConstructor, mixins) {
335 if (mixins) {
336 for (var i = 0; i < mixins.length; i++) {
338 - mixSpecIntoComponent(Constructor, mixins[i]);
337 + mixSpecIntoComponent(ConvenienceConstructor, mixins[i]);
338 }
339 }
340 },
342 - childContextTypes: function(Constructor, childContextTypes) {
341 + childContextTypes: function(ConvenienceConstructor, childContextTypes) {
342 + var Constructor = ConvenienceConstructor.type;
343 validateTypeDef(
344 Constructor,
345 childContextTypes,
@@ -350,7 +350,8 @@ var RESERVED_SPEC_KEYS = {
350 childContextTypes
351 );
352 },
353 - contextTypes: function(Constructor, contextTypes) {
353 + contextTypes: function(ConvenienceConstructor, contextTypes) {
354 + var Constructor = ConvenienceConstructor.type;
355 validateTypeDef(
356 Constructor,
357 contextTypes,
@@ -358,21 +359,8 @@ var RESERVED_SPEC_KEYS = {
359 );
360 Constructor.contextTypes = merge(Constructor.contextTypes, contextTypes);
361 },
361 - /**
362 - * Special case getDefaultProps which should move into statics but requires
363 - * automatic merging.
364 - */
365 - getDefaultProps: function(Constructor, getDefaultProps) {
366 - if (Constructor.getDefaultProps) {
367 - Constructor.getDefaultProps = createMergedResultFunction(
368 - Constructor.getDefaultProps,
369 - getDefaultProps
370 - );
371 - } else {
372 - Constructor.getDefaultProps = getDefaultProps;
373 - }
374 - },
375 - propTypes: function(Constructor, propTypes) {
362 + propTypes: function(ConvenienceConstructor, propTypes) {
363 + var Constructor = ConvenienceConstructor.type;
364 validateTypeDef(
365 Constructor,
366 propTypes,
@@ -380,8 +368,8 @@ var RESERVED_SPEC_KEYS = {
368 );
369 Constructor.propTypes = merge(Constructor.propTypes, propTypes);
370 },
383 - statics: function(Constructor, statics) {
384 - mixStaticSpecIntoComponent(Constructor, statics);
371 + statics: function(ConvenienceConstructor, statics) {
372 + mixStaticSpecIntoComponent(ConvenienceConstructor, statics);
373 }
374 };
375
@@ -449,7 +437,7 @@ function validateLifeCycleOnReplaceState(instance) {
437 * Custom version of `mixInto` which handles policy validation and reserved
438 * specification keys when building `ReactCompositeComponent` classses.
439 */
452 -function mixSpecIntoComponent(Constructor, spec) {
440 +function mixSpecIntoComponent(ConvenienceConstructor, spec) {
441 invariant(
442 !ReactDescriptor.isValidFactory(spec),
443 'ReactCompositeComponent: You\'re attempting to ' +
@@ -461,6 +449,7 @@ function mixSpecIntoComponent(Constructor, spec) {
449 'use a component as a mixin. Instead, just use a regular object.'
450 );
451
452 + var Constructor = ConvenienceConstructor.type;
453 var proto = Constructor.prototype;
454 for (var name in spec) {
455 var property = spec[name];
@@ -471,7 +460,7 @@ function mixSpecIntoComponent(Constructor, spec) {
460 validateMethodOverride(proto, name);
461
462 if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
474 - RESERVED_SPEC_KEYS[name](Constructor, property);
463 + RESERVED_SPEC_KEYS[name](ConvenienceConstructor, property);
464 } else {
465 // Setup methods on prototype:
466 // The following member methods should not be automatically bound:
@@ -532,7 +521,7 @@ function mixSpecIntoComponent(Constructor, spec) {
521 }
522 }
523
535 -function mixStaticSpecIntoComponent(Constructor, statics) {
524 +function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) {
525 if (!statics) {
526 return;
527 }
@@ -542,10 +531,10 @@ function mixStaticSpecIntoComponent(Constructor, statics) {
531 continue;
532 }
533
545 - var isInherited = name in Constructor;
534 + var isInherited = name in ConvenienceConstructor;
535 var result = property;
536 if (isInherited) {
548 - var existingProperty = Constructor[name];
537 + var existingProperty = ConvenienceConstructor[name];
538 var existingType = typeof existingProperty;
539 var propertyType = typeof property;
540 invariant(
@@ -558,7 +547,8 @@ function mixStaticSpecIntoComponent(Constructor, statics) {
547 );
548 result = createChainedFunction(existingProperty, property);
549 }
561 - Constructor[name] = result;
550 + ConvenienceConstructor[name] = result;
551 + ConvenienceConstructor.type[name] = result;
552 }
553 }
554
@@ -733,6 +723,7 @@ var ReactCompositeComponentMixin = {
723 this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
724
725 this.context = this._processContext(this._descriptor._context);
726 + this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
727 this.props = this._processProps(this.props);
728
729 if (this.__reactAutoBindMap) {
@@ -790,6 +781,8 @@ var ReactCompositeComponentMixin = {
781 }
782 this._compositeLifeCycleState = null;
783
784 + this._defaultProps = null;
785 +
786 this._renderedComponent.unmountComponent();
787 this._renderedComponent = null;
788
@@ -928,6 +921,12 @@ var ReactCompositeComponentMixin = {
921 */
922 _processProps: function(newProps) {
923 var props = merge(newProps);
924 + var defaultProps = this._defaultProps;
925 + for (var propName in defaultProps) {
926 + if (typeof props[propName] === 'undefined') {
927 + props[propName] = defaultProps[propName];
928 + }
929 + }
930 if (__DEV__) {
931 var propTypes = this.constructor.propTypes;
932 if (propTypes) {
@@ -946,8 +945,6 @@ var ReactCompositeComponentMixin = {
945 * @private
946 */
947 _checkPropTypes: function(propTypes, props, location) {
949 - // TODO: Stop validating prop types here and only use the descriptor
950 - // validation.
948 var componentName = this.constructor.displayName;
949 for (var propName in propTypes) {
950 if (propTypes.hasOwnProperty(propName)) {
@@ -1313,11 +1310,16 @@ var ReactCompositeComponent = {
1310 Constructor.prototype = new ReactCompositeComponentBase();
1311 Constructor.prototype.constructor = Constructor;
1312
1313 + var ConvenienceConstructor = ReactDescriptor.createFactory(Constructor);
1314 +
1315 + // TODO: Move statics off of the convenience constructor. That way the
1316 + // factory can be created independently from the main class.
1317 +
1318 injectedMixins.forEach(
1317 - mixSpecIntoComponent.bind(null, Constructor)
1319 + mixSpecIntoComponent.bind(null, ConvenienceConstructor)
1320 );
1321
1320 - mixSpecIntoComponent(Constructor, spec);
1322 + mixSpecIntoComponent(ConvenienceConstructor, spec);
1323
1324 invariant(
1325 Constructor.prototype.render,
@@ -1346,17 +1348,7 @@ var ReactCompositeComponent = {
1348 }
1349 }
1350
1349 - var descriptorFactory = ReactDescriptor.createFactory(Constructor);
1350 -
1351 - if (__DEV__) {
1352 - return ReactDescriptorValidator.createFactory(
1353 - descriptorFactory,
1354 - Constructor.propTypes,
1355 - Constructor.contextTypes
1356 - );
1357 - }
1358 -
1359 - return descriptorFactory;
1351 + return ConvenienceConstructor;
1352 },
1353
1354 injection: {
src/core/ReactDescriptor.js
+166 -49
@@ -21,9 +21,165 @@
21 var ReactContext = require('ReactContext');
22 var ReactCurrentOwner = require('ReactCurrentOwner');
23
24 -var merge = require('merge');
24 +var monitorCodeUse = require('monitorCodeUse');
25 var warning = require('warning');
26
27 +/**
28 + * Warn if there's no key explicitly set on dynamic arrays of children or
29 + * object keys are not valid. This allows us to keep track of children between
30 + * updates.
31 + */
32 +var ownerHasKeyUseWarning = {
33 + 'react_key_warning': {},
34 + 'react_numeric_key_warning': {}
35 +};
36 +var ownerHasMonitoredObjectMap = {};
37 +
38 +var NUMERIC_PROPERTY_REGEX = /^\d+$/;
39 +
40 +/**
41 + * Gets the current owner's displayName for use in warnings.
42 + *
43 + * @internal
44 + * @return {?string} Display name or undefined
45 + */
46 +function getCurrentOwnerDisplayName() {
47 + var current = ReactCurrentOwner.current;
48 + return current && current.constructor.displayName || undefined;
49 +}
50 +
51 +/**
52 + * Warn if the component doesn't have an explicit key assigned to it.
53 + * This component is in an array. The array could grow and shrink or be
54 + * reordered. All children that haven't already been validated are required to
55 + * have a "key" property assigned to it.
56 + *
57 + * @internal
58 + * @param {ReactComponent} component Component that requires a key.
59 + * @param {*} parentType component's parent's type.
60 + */
61 +function validateExplicitKey(component, parentType) {
62 + if (component._store.validated || component.props.key != null) {
63 + return;
64 + }
65 + component._store.validated = true;
66 +
67 + warnAndMonitorForKeyUse(
68 + 'react_key_warning',
69 + 'Each child in an array should have a unique "key" prop.',
70 + component,
71 + parentType
72 + );
73 +}
74 +
75 +/**
76 + * Warn if the key is being defined as an object property but has an incorrect
77 + * value.
78 + *
79 + * @internal
80 + * @param {string} name Property name of the key.
81 + * @param {ReactComponent} component Component that requires a key.
82 + * @param {*} parentType component's parent's type.
83 + */
84 +function validatePropertyKey(name, component, parentType) {
85 + if (!NUMERIC_PROPERTY_REGEX.test(name)) {
86 + return;
87 + }
88 + warnAndMonitorForKeyUse(
89 + 'react_numeric_key_warning',
90 + 'Child objects should have non-numeric keys so ordering is preserved.',
91 + component,
92 + parentType
93 + );
94 +}
95 +
96 +/**
97 + * Shared warning and monitoring code for the key warnings.
98 + *
99 + * @internal
100 + * @param {string} warningID The id used when logging.
101 + * @param {string} message The base warning that gets output.
102 + * @param {ReactComponent} component Component that requires a key.
103 + * @param {*} parentType component's parent's type.
104 + */
105 +function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
106 + var ownerName = getCurrentOwnerDisplayName();
107 + var parentName = parentType.displayName;
108 +
109 + var useName = ownerName || parentName;
110 + var memoizer = ownerHasKeyUseWarning[warningID];
111 + if (memoizer.hasOwnProperty(useName)) {
112 + return;
113 + }
114 + memoizer[useName] = true;
115 +
116 + message += ownerName ?
117 + ` Check the render method of ${ownerName}.` :
118 + ` Check the renderComponent call using <${parentName}>.`;
119 +
120 + // Usually the current owner is the offender, but if it accepts children as a
121 + // property, it may be the creator of the child that's responsible for
122 + // assigning it a key.
123 + var childOwnerName = null;
124 + if (component._owner && component._owner !== ReactCurrentOwner.current) {
125 + // Name of the component that originally created this child.
126 + childOwnerName = component._owner.constructor.displayName;
127 +
128 + message += ` It was passed a child from ${childOwnerName}.`;
129 + }
130 +
131 + message += ' See http://fb.me/react-warning-keys for more information.';
132 + monitorCodeUse(warningID, {
133 + component: useName,
134 + componentOwner: childOwnerName
135 + });
136 + console.warn(message);
137 +}
138 +
139 +/**
140 + * Log that we're using an object map. We're considering deprecating this
141 + * feature and replace it with proper Map and ImmutableMap data structures.
142 + *
143 + * @internal
144 + */
145 +function monitorUseOfObjectMap() {
146 + var currentName = getCurrentOwnerDisplayName() || '';
147 + if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) {
148 + return;
149 + }
150 + ownerHasMonitoredObjectMap[currentName] = true;
151 + monitorCodeUse('react_object_map_children');
152 +}
153 +
154 +/**
155 + * Ensure that every component either is passed in a static location, in an
156 + * array with an explicit keys property defined, or in an object literal
157 + * with valid key property.
158 + *
159 + * @internal
160 + * @param {*} component Statically passed child of any type.
161 + * @param {*} parentType component's parent's type.
162 + * @return {boolean}
163 + */
164 +function validateChildKeys(component, parentType) {
165 + if (Array.isArray(component)) {
166 + for (var i = 0; i < component.length; i++) {
167 + var child = component[i];
168 + if (ReactDescriptor.isValidDescriptor(child)) {
169 + validateExplicitKey(child, parentType);
170 + }
171 + }
172 + } else if (ReactDescriptor.isValidDescriptor(component)) {
173 + // This component was passed in a valid location.
174 + component._store.validated = true;
175 + } else if (component && typeof component === 'object') {
176 + monitorUseOfObjectMap();
177 + for (var name in component) {
178 + validatePropertyKey(name, component[name], parentType);
179 + }
180 + }
181 +}
182 +
183 /**
184 * Warn for mutations.
185 *
@@ -81,26 +237,6 @@ function defineMutationMembrane(prototype) {
237 }
238 }
239
84 -/**
85 - * Transfer static properties from the source to the target. Functions are
86 - * rebound to have this reflect the original source.
87 - */
88 -function proxyStaticMethods(target, source) {
89 - if (typeof source !== 'function') {
90 - return;
91 - }
92 - for (var key in source) {
93 - if (source.hasOwnProperty(key)) {
94 - var value = source[key];
95 - if (typeof value === 'function') {
96 - target[key] = value.bind(source);
97 - } else {
98 - target[key] = value;
99 - }
100 - }
101 - }
102 -}
103 -
240 /**
241 * Base constructor for all React descriptors. This is only used to make this
242 * work with a dynamic instanceof check. Nothing should live on this prototype.
@@ -118,44 +254,29 @@ ReactDescriptor.createFactory = function(type) {
254
255 var descriptorPrototype = Object.create(ReactDescriptor.prototype);
256
121 - var defaultProps = type.getDefaultProps && type.getDefaultProps();
122 -
257 var factory = function(props, children) {
124 - // For consistency we currently allocate a new object for every descriptor.
125 - // This protects the descriptor from being mutated by the original props
126 - // object being mutated. It also protects the original props object from
127 - // being mutated by children arguments and default props. This behavior
128 - // comes with a performance cost and could be deprecated in the future.
129 - // It could also be optimized with a smarter JSX transform.
258 if (props == null) {
259 props = {};
132 - } else if (typeof props === 'object') {
133 - props = merge(props);
260 }
261
136 - // Children can be more than one argument, and those are transferred onto
137 - // the newly allocated props object.
262 + // Children can be more than one argument
263 var childrenLength = arguments.length - 1;
264 if (childrenLength === 1) {
265 + if (__DEV__) {
266 + validateChildKeys(children, type);
267 + }
268 props.children = children;
269 } else if (childrenLength > 1) {
270 var childArray = Array(childrenLength);
271 for (var i = 0; i < childrenLength; i++) {
272 + if (__DEV__) {
273 + validateChildKeys(arguments[i + 1], type);
274 + }
275 childArray[i] = arguments[i + 1];
276 }
277 props.children = childArray;
278 }
279
149 - // Resolve default props
150 - if (defaultProps) {
151 - for (var propName in defaultProps) {
152 - if (typeof props[propName] === 'undefined') {
153 - props[propName] = defaultProps[propName];
154 - }
155 - }
156 - }
157 -
158 - // Initialize the descriptor object
280 var descriptor = Object.create(descriptorPrototype);
281
282 // Record the component responsible for creating this descriptor.
@@ -168,13 +289,10 @@ ReactDescriptor.createFactory = function(type) {
289 if (__DEV__) {
290 // The validation flag and props are currently mutative. We put them on
291 // an external backing store so that we can freeze the whole object.
171 - // This can be replaced with a WeakMap once they are implemented in
172 - // commonly used development environments.
292 descriptor._store = { validated: false, props: props };
293
294 // We're not allowed to set props directly on the object so we early
176 - // return and rely on the prototype membrane to forward to the backing
177 - // store.
295 + // return and rely on the prototype membrane toward to the backing store.
296 if (useMutationMembrane) {
297 Object.freeze(descriptor);
298 return descriptor;
@@ -183,6 +301,7 @@ ReactDescriptor.createFactory = function(type) {
301
302 descriptor.props = props;
303 return descriptor;
304 +
305 };
306
307 // Currently we expose the prototype of the descriptor so that
@@ -197,8 +316,6 @@ ReactDescriptor.createFactory = function(type) {
316 factory.type = type;
317 descriptorPrototype.type = type;
318
200 - proxyStaticMethods(factory, type);
201 -
319 // Expose a unique constructor on the prototype is that this works with type
320 // systems that compare constructor properties: <Foo />.constructor === Foo
321 // This may be controversial since it requires a known factory function.
src/core/ReactDescriptorValidator.js deleted
-283
@@ -1,283 +0,0 @@
1 -/**
2 - * Copyright 2014 Facebook, Inc.
3 - *
4 - * Licensed under the Apache License, Version 2.0 (the "License");
5 - * you may not use this file except in compliance with the License.
6 - * You may obtain a copy of the License at
7 - *
8 - * http://www.apache.org/licenses/LICENSE-2.0
9 - *
10 - * Unless required by applicable law or agreed to in writing, software
11 - * distributed under the License is distributed on an "AS IS" BASIS,
12 - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 - * See the License for the specific language governing permissions and
14 - * limitations under the License.
15 - *
16 - * @providesModule ReactDescriptorValidator
17 - */
18 -
19 -/**
20 - * ReactDescriptorValidator provides a wrapper around a descriptor factory
21 - * which validates the props passed to the descriptor. This is intended to be
22 - * used only in DEV and could be replaced by a static type checker for languages
23 - * that support it.
24 - */
25 -
26 -"use strict";
27 -
28 -var ReactDescriptor = require('ReactDescriptor');
29 -var ReactPropTypeLocations = require('ReactPropTypeLocations');
30 -var ReactCurrentOwner = require('ReactCurrentOwner');
31 -
32 -var monitorCodeUse = require('monitorCodeUse');
33 -
34 -/**
35 - * Warn if there's no key explicitly set on dynamic arrays of children or
36 - * object keys are not valid. This allows us to keep track of children between
37 - * updates.
38 - */
39 -var ownerHasKeyUseWarning = {
40 - 'react_key_warning': {},
41 - 'react_numeric_key_warning': {}
42 -};
43 -var ownerHasMonitoredObjectMap = {};
44 -
45 -var loggedTypeFailures = {};
46 -
47 -var NUMERIC_PROPERTY_REGEX = /^\d+$/;
48 -
49 -/**
50 - * Gets the current owner's displayName for use in warnings.
51 - *
52 - * @internal
53 - * @return {?string} Display name or undefined
54 - */
55 -function getCurrentOwnerDisplayName() {
56 - var current = ReactCurrentOwner.current;
57 - return current && current.constructor.displayName || undefined;
58 -}
59 -
60 -/**
61 - * Warn if the component doesn't have an explicit key assigned to it.
62 - * This component is in an array. The array could grow and shrink or be
63 - * reordered. All children that haven't already been validated are required to
64 - * have a "key" property assigned to it.
65 - *
66 - * @internal
67 - * @param {ReactComponent} component Component that requires a key.
68 - * @param {*} parentType component's parent's type.
69 - */
70 -function validateExplicitKey(component, parentType) {
71 - if (component._store.validated || component.props.key != null) {
72 - return;
73 - }
74 - component._store.validated = true;
75 -
76 - warnAndMonitorForKeyUse(
77 - 'react_key_warning',
78 - 'Each child in an array should have a unique "key" prop.',
79 - component,
80 - parentType
81 - );
82 -}
83 -
84 -/**
85 - * Warn if the key is being defined as an object property but has an incorrect
86 - * value.
87 - *
88 - * @internal
89 - * @param {string} name Property name of the key.
90 - * @param {ReactComponent} component Component that requires a key.
91 - * @param {*} parentType component's parent's type.
92 - */
93 -function validatePropertyKey(name, component, parentType) {
94 - if (!NUMERIC_PROPERTY_REGEX.test(name)) {
95 - return;
96 - }
97 - warnAndMonitorForKeyUse(
98 - 'react_numeric_key_warning',
99 - 'Child objects should have non-numeric keys so ordering is preserved.',
100 - component,
101 - parentType
102 - );
103 -}
104 -
105 -/**
106 - * Shared warning and monitoring code for the key warnings.
107 - *
108 - * @internal
109 - * @param {string} warningID The id used when logging.
110 - * @param {string} message The base warning that gets output.
111 - * @param {ReactComponent} component Component that requires a key.
112 - * @param {*} parentType component's parent's type.
113 - */
114 -function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
115 - var ownerName = getCurrentOwnerDisplayName();
116 - var parentName = parentType.displayName;
117 -
118 - var useName = ownerName || parentName;
119 - var memoizer = ownerHasKeyUseWarning[warningID];
120 - if (memoizer.hasOwnProperty(useName)) {
121 - return;
122 - }
123 - memoizer[useName] = true;
124 -
125 - message += ownerName ?
126 - ` Check the render method of ${ownerName}.` :
127 - ` Check the renderComponent call using <${parentName}>.`;
128 -
129 - // Usually the current owner is the offender, but if it accepts children as a
130 - // property, it may be the creator of the child that's responsible for
131 - // assigning it a key.
132 - var childOwnerName = null;
133 - if (component._owner && component._owner !== ReactCurrentOwner.current) {
134 - // Name of the component that originally created this child.
135 - childOwnerName = component._owner.constructor.displayName;
136 -
137 - message += ` It was passed a child from ${childOwnerName}.`;
138 - }
139 -
140 - message += ' See http://fb.me/react-warning-keys for more information.';
141 - monitorCodeUse(warningID, {
142 - component: useName,
143 - componentOwner: childOwnerName
144 - });
145 - console.warn(message);
146 -}
147 -
148 -/**
149 - * Log that we're using an object map. We're considering deprecating this
150 - * feature and replace it with proper Map and ImmutableMap data structures.
151 - *
152 - * @internal
153 - */
154 -function monitorUseOfObjectMap() {
155 - var currentName = getCurrentOwnerDisplayName() || '';
156 - if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) {
157 - return;
158 - }
159 - ownerHasMonitoredObjectMap[currentName] = true;
160 - monitorCodeUse('react_object_map_children');
161 -}
162 -
163 -/**
164 - * Ensure that every component either is passed in a static location, in an
165 - * array with an explicit keys property defined, or in an object literal
166 - * with valid key property.
167 - *
168 - * @internal
169 - * @param {*} component Statically passed child of any type.
170 - * @param {*} parentType component's parent's type.
171 - * @return {boolean}
172 - */
173 -function validateChildKeys(component, parentType) {
174 - if (Array.isArray(component)) {
175 - for (var i = 0; i < component.length; i++) {
176 - var child = component[i];
177 - if (ReactDescriptor.isValidDescriptor(child)) {
178 - validateExplicitKey(child, parentType);
179 - }
180 - }
181 - } else if (ReactDescriptor.isValidDescriptor(component)) {
182 - // This component was passed in a valid location.
183 - component._store.validated = true;
184 - } else if (component && typeof component === 'object') {
185 - monitorUseOfObjectMap();
186 - for (var name in component) {
187 - validatePropertyKey(name, component[name], parentType);
188 - }
189 - }
190 -}
191 -
192 -/**
193 - * Assert that the props are valid
194 - *
195 - * @param {string} componentName Name of the component for error messages.
196 - * @param {object} propTypes Map of prop name to a ReactPropType
197 - * @param {object} props
198 - * @param {string} location e.g. "prop", "context", "child context"
199 - * @private
200 - */
201 -function checkPropTypes(componentName, propTypes, props, location) {
202 - for (var propName in propTypes) {
203 - if (propTypes.hasOwnProperty(propName)) {
204 - var error;
205 - // Prop type validation may throw. In case they do, we don't want to
206 - // fail the render phase where it didn't fail before. So we log it.
207 - // After these have been cleaned up, we'll let them throw.
208 - try {
209 - error = propTypes[propName](props, propName, componentName, location);
210 - } catch (ex) {
211 - error = ex;
212 - }
213 - if (error instanceof Error && !(error.message in loggedTypeFailures)) {
214 - // Only monitor this failure once because there tends to be a lot of the
215 - // same error.
216 - loggedTypeFailures[error.message] = true;
217 - // This will soon use the warning module
218 - monitorCodeUse(
219 - 'react_failed_descriptor_type_check',
220 - { message: error.message }
221 - );
222 - }
223 - }
224 - }
225 -}
226 -
227 -var ReactDescriptorValidator = {
228 -
229 - /**
230 - * Wraps a descriptor factory function in another function which validates
231 - * the props and context of the descriptor and warns about any failed type
232 - * checks.
233 - *
234 - * @param {function} factory The original descriptor factory
235 - * @param {object?} propTypes A prop type definition set
236 - * @param {object?} contextTypes A context type definition set
237 - * @return {object} The component descriptor, which may be invalid.
238 - * @private
239 - */
240 - createFactory: function(factory, propTypes, contextTypes) {
241 - var validatedFactory = function(props, children) {
242 - var descriptor = factory.apply(this, arguments);
243 -
244 - for (var i = 1; i < arguments.length; i++) {
245 - validateChildKeys(arguments[i], descriptor.type);
246 - }
247 -
248 - var name = descriptor.type.displayName;
249 - if (propTypes) {
250 - checkPropTypes(
251 - name,
252 - propTypes,
253 - descriptor.props,
254 - ReactPropTypeLocations.prop
255 - );
256 - }
257 - if (contextTypes) {
258 - checkPropTypes(
259 - name,
260 - contextTypes,
261 - descriptor._context,
262 - ReactPropTypeLocations.context
263 - );
264 - }
265 - return descriptor;
266 - };
267 -
268 - validatedFactory.prototype = factory.prototype;
269 - validatedFactory.type = factory.type;
270 -
271 - // Copy static properties
272 - for (var key in factory) {
273 - if (factory.hasOwnProperty(key)) {
274 - validatedFactory[key] = factory[key];
275 - }
276 - }
277 -
278 - return validatedFactory;
279 - }
280 -
281 -};
282 -
283 -module.exports = ReactDescriptorValidator;
src/core/__tests__/ReactPropTypes-test.js
+2 -2
@@ -614,7 +614,7 @@ describe('Custom validator', function() {
614 var instance = <Component num={5} />;
615 instance = ReactTestUtils.renderIntoDocument(instance);
616
617 - expect(spy.argsForCall.length).toBe(2); // temp double validation
617 + expect(spy.argsForCall.length).toBe(1);
618 expect(spy.argsForCall[0][1]).toBe('num');
619 expect(spy.argsForCall[0][2]).toBe('Component');
620 });
@@ -632,7 +632,7 @@ describe('Custom validator', function() {
632 var instance = <Component bla={5} />;
633 instance = ReactTestUtils.renderIntoDocument(instance);
634
635 - expect(spy.argsForCall.length).toBe(2); // temp double validation
635 + expect(spy.argsForCall.length).toBe(1);
636 });
637
638 it('should have received the validator\'s return value', function() {