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() {