Moved unknown-prop warning into a devtool
Jim committed
Dec 3, 2015 at 07:02 UTC
30ef056731f10a094661b0d288c68fbe0c044161
5 files changed
+118
-95
src/renderers/dom/ReactDOM.js
+3
@@ -15,6 +15,7 @@
15
16
var ReactDOMComponentTree = require('ReactDOMComponentTree');
17
var ReactDOMDevtools = require('ReactDOMDevtools');
18
+var ReactDOMUnknownPropertyDevtool = require('ReactDOMUnknownPropertyDevtool');
19
var ReactDefaultInjection = require('ReactDefaultInjection');
20
var ReactMount = require('ReactMount');
21
var ReactPerf = require('ReactPerf');
@@ -136,6 +137,8 @@ if (__DEV__) {
137
break;
138
}
139
}
140
+
141
+ ReactDOMDevtools.addDevtool(new ReactDOMUnknownPropertyDevtool());
142
}
143
}
144
src/renderers/dom/shared/DOMPropertyOperations.js
+4
-60
@@ -12,7 +12,7 @@
12
'use strict';
13
14
var DOMProperty = require('DOMProperty');
15
-var EventPluginRegistry = require('EventPluginRegistry');
15
+var ReactDOMDevtools = require('ReactDOMDevtools');
16
var ReactPerf = require('ReactPerf');
17
18
var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
@@ -51,59 +51,6 @@ function shouldIgnoreValue(propertyInfo, value) {
51
(propertyInfo.hasOverloadedBooleanValue && value === false);
52
}
53
54
-if (__DEV__) {
55
- var reactProps = {
56
- children: true,
57
- dangerouslySetInnerHTML: true,
58
- key: true,
59
- ref: true,
60
- };
61
- var warnedProperties = {};
62
-
63
- var warnUnknownProperty = function(name) {
64
- if (reactProps.hasOwnProperty(name) && reactProps[name] ||
65
- warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
66
- return;
67
- }
68
-
69
- warnedProperties[name] = true;
70
- var lowerCasedName = name.toLowerCase();
71
-
72
- // data-* attributes should be lowercase; suggest the lowercase version
73
- var standardName = (
74
- DOMProperty.isCustomAttribute(lowerCasedName) ?
75
- lowerCasedName :
76
- DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
77
- DOMProperty.getPossibleStandardName[lowerCasedName] :
78
- null
79
- );
80
-
81
- // For now, only warn when we have a suggested correction. This prevents
82
- // logging too much when using transferPropsTo.
83
- warning(
84
- standardName == null,
85
- 'Unknown DOM property %s. Did you mean %s?',
86
- name,
87
- standardName
88
- );
89
-
90
- var registrationName = (
91
- EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(
92
- lowerCasedName
93
- ) ?
94
- EventPluginRegistry.possibleRegistrationNames[lowerCasedName] :
95
- null
96
- );
97
-
98
- warning(
99
- registrationName == null,
100
- 'Unknown event handler property %s. Did you mean `%s`?',
101
- name,
102
- registrationName
103
- );
104
- };
105
-}
106
-
54
/**
55
* Operations for dealing with DOM properties.
56
*/
@@ -140,6 +87,7 @@ var DOMPropertyOperations = {
87
* @return {?string} Markup string, or null if the property was invalid.
88
*/
89
createMarkupForProperty: function(name, value) {
90
+ ReactDOMDevtools.emitEvent('createMarkupForProperty', {name, value});
91
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
92
DOMProperty.properties[name] : null;
93
if (propertyInfo) {
@@ -157,8 +105,6 @@ var DOMPropertyOperations = {
105
return '';
106
}
107
return name + '=' + quoteAttributeValueForBrowser(value);
160
- } else if (__DEV__) {
161
- warnUnknownProperty(name);
108
}
109
return null;
110
},
@@ -185,6 +131,7 @@ var DOMPropertyOperations = {
131
* @param {*} value
132
*/
133
setValueForProperty: function(node, name, value) {
134
+ ReactDOMDevtools.emitEvent('setValueForProperty', {node, name, value});
135
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
136
DOMProperty.properties[name] : null;
137
if (propertyInfo) {
@@ -219,8 +166,6 @@ var DOMPropertyOperations = {
166
}
167
} else if (DOMProperty.isCustomAttribute(name)) {
168
DOMPropertyOperations.setValueForAttribute(node, name, value);
222
- } else if (__DEV__) {
223
- warnUnknownProperty(name);
169
}
170
},
171
@@ -242,6 +187,7 @@ var DOMPropertyOperations = {
187
* @param {string} name
188
*/
189
deleteValueForProperty: function(node, name) {
190
+ ReactDOMDevtools.emitEvent('deleteValueForProperty', {node, name});
191
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
192
DOMProperty.properties[name] : null;
193
if (propertyInfo) {
@@ -263,8 +209,6 @@ var DOMPropertyOperations = {
209
}
210
} else if (DOMProperty.isCustomAttribute(name)) {
211
node.removeAttribute(name);
266
- } else if (__DEV__) {
267
- warnUnknownProperty(name);
212
}
213
},
214
src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js
-35
@@ -50,41 +50,6 @@ describe('DOMPropertyOperations', function() {
50
)).toBe('id="simple"');
51
});
52
53
- it('should warn about incorrect casing on properties', function() {
54
- spyOn(console, 'error');
55
- expect(DOMPropertyOperations.createMarkupForProperty(
56
- 'tabindex',
57
- '1'
58
- )).toBe(null);
59
- expect(console.error.argsForCall.length).toBe(1);
60
- expect(console.error.argsForCall[0][0]).toContain('tabIndex');
61
- });
62
-
63
- it('should warn about incorrect casing on event handlers', function() {
64
- spyOn(console, 'error');
65
- expect(DOMPropertyOperations.createMarkupForProperty(
66
- 'onclick',
67
- '1'
68
- )).toBe(null);
69
- expect(DOMPropertyOperations.createMarkupForProperty(
70
- 'onKeydown',
71
- '1'
72
- )).toBe(null);
73
- expect(console.error.argsForCall.length).toBe(2);
74
- expect(console.error.argsForCall[0][0]).toContain('onClick');
75
- expect(console.error.argsForCall[1][0]).toContain('onKeyDown');
76
- });
77
-
78
- it('should warn about class', function() {
79
- spyOn(console, 'error');
80
- expect(DOMPropertyOperations.createMarkupForProperty(
81
- 'class',
82
- 'muffins'
83
- )).toBe(null);
84
- expect(console.error.argsForCall.length).toBe(1);
85
- expect(console.error.argsForCall[0][0]).toContain('className');
86
- });
87
-
53
it('should create markup for boolean properties', function() {
54
expect(DOMPropertyOperations.createMarkupForProperty(
55
'checked',
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+23
@@ -1087,5 +1087,28 @@ describe('ReactDOMComponent', function() {
1087
'See Link > a > ... > Link > a.'
1088
);
1089
});
1090
+
1091
+ it('should warn about incorrect casing on properties', function() {
1092
+ spyOn(console, 'error');
1093
+ ReactDOMServer.renderToString(React.createElement('input', {type: 'text', tabindex: '1'}));
1094
+ expect(console.error.argsForCall.length).toBe(1);
1095
+ expect(console.error.argsForCall[0][0]).toContain('tabIndex');
1096
+ });
1097
+
1098
+ it('should warn about incorrect casing on event handlers', function() {
1099
+ spyOn(console, 'error');
1100
+ ReactDOMServer.renderToString(React.createElement('input', {type: 'text', onclick: '1'}));
1101
+ ReactDOMServer.renderToString(React.createElement('input', {type: 'text', onKeydown: '1'}));
1102
+ expect(console.error.argsForCall.length).toBe(2);
1103
+ expect(console.error.argsForCall[0][0]).toContain('onClick');
1104
+ expect(console.error.argsForCall[1][0]).toContain('onKeyDown');
1105
+ });
1106
+
1107
+ it('should warn about class', function() {
1108
+ spyOn(console, 'error');
1109
+ ReactDOMServer.renderToString(React.createElement('div', {class: 'muffins'}));
1110
+ expect(console.error.argsForCall.length).toBe(1);
1111
+ expect(console.error.argsForCall[0][0]).toContain('className');
1112
+ });
1113
});
1114
});
src/renderers/dom/shared/devtools/ReactDOMUnknownPropertyDevtool.js
new
+88
@@ -0,0 +1,88 @@
1
+/**
2
+ * Copyright 2013-2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactDOMUnknownPropertyDevtool
10
+ */
11
+
12
+'use strict';
13
+
14
+var DOMProperty = require('DOMProperty');
15
+var EventPluginRegistry = require('EventPluginRegistry');
16
+
17
+var warning = require('warning');
18
+
19
+if (__DEV__) {
20
+ var reactProps = {
21
+ children: true,
22
+ dangerouslySetInnerHTML: true,
23
+ key: true,
24
+ ref: true,
25
+ };
26
+ var warnedProperties = {};
27
+
28
+ var warnUnknownProperty = function(name) {
29
+ if (reactProps.hasOwnProperty(name) && reactProps[name] ||
30
+ warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
31
+ return;
32
+ }
33
+
34
+ warnedProperties[name] = true;
35
+ var lowerCasedName = name.toLowerCase();
36
+
37
+ // data-* attributes should be lowercase; suggest the lowercase version
38
+ var standardName = (
39
+ DOMProperty.isCustomAttribute(lowerCasedName) ?
40
+ lowerCasedName :
41
+ DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
42
+ DOMProperty.getPossibleStandardName[lowerCasedName] :
43
+ null
44
+ );
45
+
46
+ // For now, only warn when we have a suggested correction. This prevents
47
+ // logging too much when using transferPropsTo.
48
+ warning(
49
+ standardName == null,
50
+ 'Unknown DOM property %s. Did you mean %s?',
51
+ name,
52
+ standardName
53
+ );
54
+
55
+ var registrationName = (
56
+ EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(
57
+ lowerCasedName
58
+ ) ?
59
+ EventPluginRegistry.possibleRegistrationNames[lowerCasedName] :
60
+ null
61
+ );
62
+
63
+ warning(
64
+ registrationName == null,
65
+ 'Unknown event handler property %s. Did you mean `%s`?',
66
+ name,
67
+ registrationName
68
+ );
69
+ };
70
+}
71
+
72
+class ReactDOMUnknownPropertyDevtool {
73
+ handleEvent(eventName, eventData) {
74
+ switch (eventName) {
75
+ case 'createMarkupForProperty':
76
+ case 'setValueForProperty':
77
+ case 'deleteValueForProperty':
78
+ var name = eventData.name;
79
+ if (!DOMProperty.properties.hasOwnProperty(name) &&
80
+ !DOMProperty.isCustomAttribute(name)) {
81
+ warnUnknownProperty(name);
82
+ }
83
+ break;
84
+ }
85
+ }
86
+}
87
+
88
+module.exports = ReactDOMUnknownPropertyDevtool;