@@ -15,12 +15,18 @@ const DEFAULTS = {
15
15
} ;
16
16
17
17
const UNKNOWN_MESSAGE = 'Unknown property \'{{name}}\' found, use \'{{standardName}}\' instead' ;
18
+ const WRONG_TAG_MESSAGE = 'Invalid property \'{{name}}\' found on tag \'{{tagName}}\', but it is only allowed on: {{allowedTags}}' ;
18
19
19
20
const DOM_ATTRIBUTE_NAMES = {
20
21
'accept-charset' : 'acceptCharset' ,
21
22
class : 'className' ,
22
23
for : 'htmlFor' ,
23
- 'http-equiv' : 'httpEquiv'
24
+ 'http-equiv' : 'httpEquiv' ,
25
+ crossOrigin : 'crossorigin'
26
+ } ;
27
+
28
+ const ATTRIBUTE_TAGS_MAP = {
29
+ crossorigin : [ 'script' , 'img' , 'video' ]
24
30
} ;
25
31
26
32
const SVGDOM_ATTRIBUTE_NAMES = {
@@ -112,7 +118,7 @@ const DOM_PROPERTY_NAMES = [
112
118
// Standard
113
119
'acceptCharset' , 'accessKey' , 'allowFullScreen' , 'allowTransparency' , 'autoComplete' , 'autoFocus' , 'autoPlay' ,
114
120
'cellPadding' , 'cellSpacing' , 'charSet' , 'classID' , 'className' , 'colSpan' , 'contentEditable' , 'contextMenu' ,
115
- 'crossOrigin' , ' dateTime', 'encType' , 'formAction' , 'formEncType' , 'formMethod' , 'formNoValidate' , 'formTarget' ,
121
+ 'dateTime' , 'encType' , 'formAction' , 'formEncType' , 'formMethod' , 'formNoValidate' , 'formTarget' ,
116
122
'frameBorder' , 'hrefLang' , 'htmlFor' , 'httpEquiv' , 'inputMode' , 'keyParams' , 'keyType' , 'marginHeight' , 'marginWidth' ,
117
123
'maxLength' , 'mediaGroup' , 'minLength' , 'noValidate' , 'onAnimationEnd' , 'onAnimationIteration' , 'onAnimationStart' ,
118
124
'onBlur' , 'onChange' , 'onClick' , 'onContextMenu' , 'onCopy' , 'onCompositionEnd' , 'onCompositionStart' ,
@@ -149,6 +155,18 @@ function isTagName(node) {
149
155
return false ;
150
156
}
151
157
158
+ /**
159
+ * Extracts the tag name for the JSXAttribute
160
+ * @param {Object } node - JSXAttribute being tested.
161
+ * @returns {String } tag name
162
+ */
163
+ function getTagName ( node ) {
164
+ if ( node && node . parent && node . parent . name && node . parent . name ) {
165
+ return node . parent . name . name ;
166
+ }
167
+ return null ;
168
+ }
169
+
152
170
/**
153
171
* Get the standard name of the attribute.
154
172
* @param {String } name - Name of the attribute.
@@ -209,8 +227,26 @@ module.exports = {
209
227
JSXAttribute : function ( node ) {
210
228
const ignoreNames = getIgnoreConfig ( ) ;
211
229
const name = sourceCode . getText ( node . name ) ;
230
+ if ( ignoreNames . indexOf ( name ) >= 0 ) {
231
+ return ;
232
+ }
233
+
234
+ const tagName = getTagName ( node ) ;
235
+ const allowedTags = ATTRIBUTE_TAGS_MAP [ name ] ;
236
+ if ( tagName && allowedTags && / [ ^ A - Z ] / . test ( tagName . charAt ( 0 ) ) && allowedTags . indexOf ( tagName ) === - 1 ) {
237
+ context . report ( {
238
+ node : node ,
239
+ message : WRONG_TAG_MESSAGE ,
240
+ data : {
241
+ name : name ,
242
+ tagName : tagName ,
243
+ allowedTags : allowedTags . join ( ', ' )
244
+ }
245
+ } ) ;
246
+ }
247
+
212
248
const standardName = getStandardName ( name ) ;
213
- if ( ! isTagName ( node ) || ! standardName || ignoreNames . indexOf ( name ) >= 0 ) {
249
+ if ( ! isTagName ( node ) || ! standardName ) {
214
250
return ;
215
251
}
216
252
context . report ( {
0 commit comments