44 */
55'use strict' ;
66
7+ var componentUtil = require ( '../util/component' ) ;
8+ var ComponentList = componentUtil . List ;
9+
710// ------------------------------------------------------------------------------
811// Rule Definition
912// ------------------------------------------------------------------------------
1013
1114module . exports = function ( context ) {
1215
13- var components = { } ;
16+ var componentList = new ComponentList ( ) ;
1417
1518 var MISSING_MESSAGE = 'Component definition is missing display name' ;
1619 var MISSING_MESSAGE_NAMED_COMP = '{{component}} component definition is missing display name' ;
1720
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-
9821 /**
9922 * Checks if we are declaring a display name
10023 * @param {ASTNode } node The AST node being checked.
@@ -112,22 +35,23 @@ module.exports = function(context) {
11235 * @param {ASTNode } node The AST node being checked.
11336 */
11437 function markDisplayNameAsDeclared ( node ) {
115- var component = getComponent ( node ) ;
116- component . hasDisplayName = true ;
38+ componentList . set ( context , node , {
39+ hasDisplayName : true
40+ } ) ;
11741 }
11842
11943 /**
12044 * 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
12246 */
123- function reportMissingDisplayName ( id ) {
124- if ( ! components [ id ] || components [ id ] . hasDisplayName === true ) {
47+ function reportMissingDisplayName ( component ) {
48+ if ( ! component || component . hasDisplayName === true ) {
12549 return ;
12650 }
12751 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
13155 }
13256 ) ;
13357 }
@@ -142,14 +66,14 @@ module.exports = function(context) {
14266 if ( ! isDisplayNameDeclaration ( node . property ) ) {
14367 return ;
14468 }
145- markDisplayNameAsDeclared ( node ) ;
146- } ,
147-
148- ObjectExpression : function ( node ) {
149- if ( ! isComponentDefinition ( node ) ) {
69+ var component = componentList . getByName ( node . object . name ) ;
70+ if ( ! component ) {
15071 return ;
15172 }
73+ markDisplayNameAsDeclared ( component . node ) ;
74+ } ,
15275
76+ ObjectExpression : function ( node ) {
15377 // Search for the displayName declaration
15478 node . properties . forEach ( function ( property ) {
15579 if ( ! isDisplayNameDeclaration ( property . key ) ) {
@@ -159,29 +83,23 @@ module.exports = function(context) {
15983 } ) ;
16084 } ,
16185
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-
17486 '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 ) ) {
17891 continue ;
17992 }
180- reportMissingDisplayName ( component ) ;
93+ reportMissingDisplayName ( list [ component ] ) ;
18194 }
18295 } ,
18396
184- ReturnStatement : detectReactComponent
97+ ReturnStatement : function ( node ) {
98+ if ( ! componentUtil . isReactComponent ( context , node ) ) {
99+ return ;
100+ }
101+ componentList . set ( context , node ) ;
102+ }
185103 } ;
186104
187105} ;
0 commit comments