Moved unknown-prop warning into a devtool

This commit is contained in:
Jim
2015-12-14 16:29:04 -08:00
committed by jim
parent a55ab282fa
commit 30ef056731
5 changed files with 118 additions and 95 deletions
+3
View File
@@ -15,6 +15,7 @@
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactDOMDevtools = require('ReactDOMDevtools');
var ReactDOMUnknownPropertyDevtool = require('ReactDOMUnknownPropertyDevtool');
var ReactDefaultInjection = require('ReactDefaultInjection');
var ReactMount = require('ReactMount');
var ReactPerf = require('ReactPerf');
@@ -136,6 +137,8 @@ if (__DEV__) {
break;
}
}
ReactDOMDevtools.addDevtool(new ReactDOMUnknownPropertyDevtool());
}
}
@@ -12,7 +12,7 @@
'use strict';
var DOMProperty = require('DOMProperty');
var EventPluginRegistry = require('EventPluginRegistry');
var ReactDOMDevtools = require('ReactDOMDevtools');
var ReactPerf = require('ReactPerf');
var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
@@ -51,59 +51,6 @@ function shouldIgnoreValue(propertyInfo, value) {
(propertyInfo.hasOverloadedBooleanValue && value === false);
}
if (__DEV__) {
var reactProps = {
children: true,
dangerouslySetInnerHTML: true,
key: true,
ref: true,
};
var warnedProperties = {};
var warnUnknownProperty = function(name) {
if (reactProps.hasOwnProperty(name) && reactProps[name] ||
warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
return;
}
warnedProperties[name] = true;
var lowerCasedName = name.toLowerCase();
// data-* attributes should be lowercase; suggest the lowercase version
var standardName = (
DOMProperty.isCustomAttribute(lowerCasedName) ?
lowerCasedName :
DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
DOMProperty.getPossibleStandardName[lowerCasedName] :
null
);
// For now, only warn when we have a suggested correction. This prevents
// logging too much when using transferPropsTo.
warning(
standardName == null,
'Unknown DOM property %s. Did you mean %s?',
name,
standardName
);
var registrationName = (
EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(
lowerCasedName
) ?
EventPluginRegistry.possibleRegistrationNames[lowerCasedName] :
null
);
warning(
registrationName == null,
'Unknown event handler property %s. Did you mean `%s`?',
name,
registrationName
);
};
}
/**
* Operations for dealing with DOM properties.
*/
@@ -140,6 +87,7 @@ var DOMPropertyOperations = {
* @return {?string} Markup string, or null if the property was invalid.
*/
createMarkupForProperty: function(name, value) {
ReactDOMDevtools.emitEvent('createMarkupForProperty', {name, value});
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
DOMProperty.properties[name] : null;
if (propertyInfo) {
@@ -157,8 +105,6 @@ var DOMPropertyOperations = {
return '';
}
return name + '=' + quoteAttributeValueForBrowser(value);
} else if (__DEV__) {
warnUnknownProperty(name);
}
return null;
},
@@ -185,6 +131,7 @@ var DOMPropertyOperations = {
* @param {*} value
*/
setValueForProperty: function(node, name, value) {
ReactDOMDevtools.emitEvent('setValueForProperty', {node, name, value});
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
DOMProperty.properties[name] : null;
if (propertyInfo) {
@@ -219,8 +166,6 @@ var DOMPropertyOperations = {
}
} else if (DOMProperty.isCustomAttribute(name)) {
DOMPropertyOperations.setValueForAttribute(node, name, value);
} else if (__DEV__) {
warnUnknownProperty(name);
}
},
@@ -242,6 +187,7 @@ var DOMPropertyOperations = {
* @param {string} name
*/
deleteValueForProperty: function(node, name) {
ReactDOMDevtools.emitEvent('deleteValueForProperty', {node, name});
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
DOMProperty.properties[name] : null;
if (propertyInfo) {
@@ -263,8 +209,6 @@ var DOMPropertyOperations = {
}
} else if (DOMProperty.isCustomAttribute(name)) {
node.removeAttribute(name);
} else if (__DEV__) {
warnUnknownProperty(name);
}
},
@@ -50,41 +50,6 @@ describe('DOMPropertyOperations', function() {
)).toBe('id="simple"');
});
it('should warn about incorrect casing on properties', function() {
spyOn(console, 'error');
expect(DOMPropertyOperations.createMarkupForProperty(
'tabindex',
'1'
)).toBe(null);
expect(console.error.argsForCall.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain('tabIndex');
});
it('should warn about incorrect casing on event handlers', function() {
spyOn(console, 'error');
expect(DOMPropertyOperations.createMarkupForProperty(
'onclick',
'1'
)).toBe(null);
expect(DOMPropertyOperations.createMarkupForProperty(
'onKeydown',
'1'
)).toBe(null);
expect(console.error.argsForCall.length).toBe(2);
expect(console.error.argsForCall[0][0]).toContain('onClick');
expect(console.error.argsForCall[1][0]).toContain('onKeyDown');
});
it('should warn about class', function() {
spyOn(console, 'error');
expect(DOMPropertyOperations.createMarkupForProperty(
'class',
'muffins'
)).toBe(null);
expect(console.error.argsForCall.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain('className');
});
it('should create markup for boolean properties', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'checked',
@@ -1087,5 +1087,28 @@ describe('ReactDOMComponent', function() {
'See Link > a > ... > Link > a.'
);
});
it('should warn about incorrect casing on properties', function() {
spyOn(console, 'error');
ReactDOMServer.renderToString(React.createElement('input', {type: 'text', tabindex: '1'}));
expect(console.error.argsForCall.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain('tabIndex');
});
it('should warn about incorrect casing on event handlers', function() {
spyOn(console, 'error');
ReactDOMServer.renderToString(React.createElement('input', {type: 'text', onclick: '1'}));
ReactDOMServer.renderToString(React.createElement('input', {type: 'text', onKeydown: '1'}));
expect(console.error.argsForCall.length).toBe(2);
expect(console.error.argsForCall[0][0]).toContain('onClick');
expect(console.error.argsForCall[1][0]).toContain('onKeyDown');
});
it('should warn about class', function() {
spyOn(console, 'error');
ReactDOMServer.renderToString(React.createElement('div', {class: 'muffins'}));
expect(console.error.argsForCall.length).toBe(1);
expect(console.error.argsForCall[0][0]).toContain('className');
});
});
});
@@ -0,0 +1,88 @@
/**
* Copyright 2013-2015, 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 ReactDOMUnknownPropertyDevtool
*/
'use strict';
var DOMProperty = require('DOMProperty');
var EventPluginRegistry = require('EventPluginRegistry');
var warning = require('warning');
if (__DEV__) {
var reactProps = {
children: true,
dangerouslySetInnerHTML: true,
key: true,
ref: true,
};
var warnedProperties = {};
var warnUnknownProperty = function(name) {
if (reactProps.hasOwnProperty(name) && reactProps[name] ||
warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
return;
}
warnedProperties[name] = true;
var lowerCasedName = name.toLowerCase();
// data-* attributes should be lowercase; suggest the lowercase version
var standardName = (
DOMProperty.isCustomAttribute(lowerCasedName) ?
lowerCasedName :
DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
DOMProperty.getPossibleStandardName[lowerCasedName] :
null
);
// For now, only warn when we have a suggested correction. This prevents
// logging too much when using transferPropsTo.
warning(
standardName == null,
'Unknown DOM property %s. Did you mean %s?',
name,
standardName
);
var registrationName = (
EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(
lowerCasedName
) ?
EventPluginRegistry.possibleRegistrationNames[lowerCasedName] :
null
);
warning(
registrationName == null,
'Unknown event handler property %s. Did you mean `%s`?',
name,
registrationName
);
};
}
class ReactDOMUnknownPropertyDevtool {
handleEvent(eventName, eventData) {
switch (eventName) {
case 'createMarkupForProperty':
case 'setValueForProperty':
case 'deleteValueForProperty':
var name = eventData.name;
if (!DOMProperty.properties.hasOwnProperty(name) &&
!DOMProperty.isCustomAttribute(name)) {
warnUnknownProperty(name);
}
break;
}
}
}
module.exports = ReactDOMUnknownPropertyDevtool;