4
4
*/
5
5
'use strict' ;
6
6
7
+ var componentUtil = require ( '../util/component' ) ;
8
+ var ComponentList = componentUtil . List ;
9
+
7
10
// ------------------------------------------------------------------------------
8
11
// Rule Definition
9
12
// ------------------------------------------------------------------------------
10
13
11
14
module . exports = function ( context ) {
12
15
13
- var components = { } ;
16
+ var componentList = new ComponentList ( ) ;
14
17
15
18
var MISSING_MESSAGE = 'Component definition is missing display name' ;
16
19
var MISSING_MESSAGE_NAMED_COMP = '{{component}} component definition is missing display name' ;
17
20
18
- var defaultClassName = 'eslintReactComponent' ;
19
-
20
- /**
21
- * Get the component id from an ASTNode
22
- * @param {ASTNode } node The AST node being checked.
23
- * @returns {String } The component id.
24
- */
25
- function getComponentId ( node ) {
26
- if (
27
- node . type === 'MemberExpression' &&
28
- node . property && node . property . name === 'displayName' &&
29
- node . object && components [ node . object . name ]
30
- ) {
31
- return node . object . name ;
32
- }
33
-
34
- var scope = context . getScope ( ) ;
35
- while ( scope && scope . type !== 'class' ) {
36
- scope = scope . upper ;
37
- }
38
-
39
- if ( scope ) {
40
- return scope . block . id . name ;
41
- }
42
-
43
- return defaultClassName ;
44
- }
45
-
46
- /**
47
- * Get the component from an ASTNode
48
- * @param {ASTNode } node The AST node being checked.
49
- * @returns {Object } The component object.
50
- */
51
- function getComponent ( node ) {
52
- var id = getComponentId ( node ) ;
53
- if ( ! components [ id ] ) {
54
- components [ id ] = {
55
- name : id ,
56
- node : node ,
57
- hasDisplayName : false
58
- } ;
59
- }
60
- return components [ id ] ;
61
- }
62
-
63
- /**
64
- * Detect if we are in a React component by checking the render method
65
- * @param {ASTNode } node The AST node being checked.
66
- */
67
- function detectReactComponent ( node ) {
68
- var scope = context . getScope ( ) ;
69
- if (
70
- ( node . argument . type === 'Literal' && ( node . argument . value !== null && node . argument . value !== false ) ) &&
71
- ( node . argument . type !== 'JSXElement' ) &&
72
- ( scope . block . parent . key . name === 'render' )
73
- ) {
74
- return ;
75
- }
76
- var component = getComponent ( node ) ;
77
- component . isComponentDefinition = true ;
78
- }
79
-
80
- /**
81
- * Checks if we are inside a component definition
82
- * @param {ASTNode } node The AST node being checked.
83
- * @returns {Boolean } True if we are inside a component definition, false if not.
84
- */
85
- function isComponentDefinition ( node ) {
86
- var isES5Component = Boolean (
87
- node . parent &&
88
- node . parent . callee &&
89
- node . parent . callee . object &&
90
- node . parent . callee . property &&
91
- node . parent . callee . object . name === 'React' &&
92
- node . parent . callee . property . name === 'createClass'
93
- ) ;
94
- var isES6Component = getComponent ( node ) . isComponentDefinition ;
95
- return isES5Component || isES6Component ;
96
- }
97
-
98
21
/**
99
22
* Checks if we are declaring a display name
100
23
* @param {ASTNode } node The AST node being checked.
@@ -112,22 +35,23 @@ module.exports = function(context) {
112
35
* @param {ASTNode } node The AST node being checked.
113
36
*/
114
37
function markDisplayNameAsDeclared ( node ) {
115
- var component = getComponent ( node ) ;
116
- component . hasDisplayName = true ;
38
+ componentList . set ( context , node , {
39
+ hasDisplayName : true
40
+ } ) ;
117
41
}
118
42
119
43
/**
120
44
* Reports missing display name for a given component
121
- * @param {String } id The id of the component to process
45
+ * @param {Object } component The component to process
122
46
*/
123
- function reportMissingDisplayName ( id ) {
124
- if ( ! components [ id ] || components [ id ] . hasDisplayName === true ) {
47
+ function reportMissingDisplayName ( component ) {
48
+ if ( ! component || component . hasDisplayName === true ) {
125
49
return ;
126
50
}
127
51
context . report (
128
- components [ id ] . node ,
129
- id === defaultClassName ? MISSING_MESSAGE : MISSING_MESSAGE_NAMED_COMP , {
130
- component : id
52
+ component . node ,
53
+ component . name === componentUtil . DEFAULT_COMPONENT_NAME ? MISSING_MESSAGE : MISSING_MESSAGE_NAMED_COMP , {
54
+ component : component . name
131
55
}
132
56
) ;
133
57
}
@@ -142,14 +66,14 @@ module.exports = function(context) {
142
66
if ( ! isDisplayNameDeclaration ( node . property ) ) {
143
67
return ;
144
68
}
145
- markDisplayNameAsDeclared ( node ) ;
146
- } ,
147
-
148
- ObjectExpression : function ( node ) {
149
- if ( ! isComponentDefinition ( node ) ) {
69
+ var component = componentList . getByName ( node . object . name ) ;
70
+ if ( ! component ) {
150
71
return ;
151
72
}
73
+ markDisplayNameAsDeclared ( component . node ) ;
74
+ } ,
152
75
76
+ ObjectExpression : function ( node ) {
153
77
// Search for the displayName declaration
154
78
node . properties . forEach ( function ( property ) {
155
79
if ( ! isDisplayNameDeclaration ( property . key ) ) {
@@ -159,29 +83,23 @@ module.exports = function(context) {
159
83
} ) ;
160
84
} ,
161
85
162
- 'ObjectExpression:exit' : function ( node ) {
163
- if ( ! isComponentDefinition ( node ) ) {
164
- return ;
165
- }
166
-
167
- // Report missing display name for all ES5 classes
168
- reportMissingDisplayName ( defaultClassName ) ;
169
-
170
- // Reset the ES5 default object
171
- components [ defaultClassName ] = null ;
172
- } ,
173
-
174
86
'Program:exit' : function ( ) {
175
- // Report missing display name for all ES6 classes
176
- for ( var component in components ) {
177
- if ( ! components . hasOwnProperty ( component ) ) {
87
+ var list = componentList . getList ( ) ;
88
+ // Report missing display name for all classes
89
+ for ( var component in list ) {
90
+ if ( ! list . hasOwnProperty ( component ) ) {
178
91
continue ;
179
92
}
180
- reportMissingDisplayName ( component ) ;
93
+ reportMissingDisplayName ( list [ component ] ) ;
181
94
}
182
95
} ,
183
96
184
- ReturnStatement : detectReactComponent
97
+ ReturnStatement : function ( node ) {
98
+ if ( ! componentUtil . isReactComponent ( context , node ) ) {
99
+ return ;
100
+ }
101
+ componentList . set ( context , node ) ;
102
+ }
185
103
} ;
186
104
187
105
} ;
0 commit comments