2 * @fileoverview Prevent missing displayName in a React component definition
3 * @author Yannick Croissant
7 var componentUtil = require('../util/component');
8 var ComponentList = componentUtil.List;
10 // ------------------------------------------------------------------------------
12 // ------------------------------------------------------------------------------
14 module.exports = function(context) {
16 var componentList = new ComponentList();
18 var MISSING_MESSAGE = 'Component definition is missing display name';
19 var MISSING_MESSAGE_NAMED_COMP = '{{component}} component definition is missing display name';
22 * Checks if the component must be validated
23 * @param {Object} component The component to process
24 * @returns {Boolean} True if the component must be validated, false if not.
26 function mustBeValidated(component) {
29 component.isReactComponent &&
30 !component.hasDisplayName
35 * Checks if we are declaring a display name
36 * @param {ASTNode} node The AST node being checked.
37 * @returns {Boolean} True if we are declaring a display name, false if not.
39 function isDisplayNameDeclaration(node) {
41 // Special case for class properties
42 // (babel-eslint does not expose property name so we have to rely on tokens)
43 if (node.type === 'ClassProperty') {
44 var tokens = context.getFirstTokens(node, 2);
45 if (tokens[0].value === 'displayName' || tokens[1].value === 'displayName') {
53 node.name === 'displayName'
58 * Mark a prop type as declared
59 * @param {ASTNode} node The AST node being checked.
61 function markDisplayNameAsDeclared(node) {
62 componentList.set(context, node, {
68 * Reports missing display name for a given component
69 * @param {Object} component The component to process
71 function reportMissingDisplayName(component) {
74 component.name === componentUtil.DEFAULT_COMPONENT_NAME ? MISSING_MESSAGE : MISSING_MESSAGE_NAMED_COMP, {
75 component: component.name
80 // --------------------------------------------------------------------------
82 // --------------------------------------------------------------------------
86 ClassProperty: function(node) {
87 if (!isDisplayNameDeclaration(node)) {
91 markDisplayNameAsDeclared(node);
94 MemberExpression: function(node) {
95 if (!isDisplayNameDeclaration(node.property)) {
98 var component = componentList.getByName(node.object.name);
102 markDisplayNameAsDeclared(component.node);
105 MethodDefinition: function(node) {
106 if (!isDisplayNameDeclaration(node.key)) {
109 markDisplayNameAsDeclared(node);
112 ObjectExpression: function(node) {
113 // Search for the displayName declaration
114 node.properties.forEach(function(property) {
115 if (!isDisplayNameDeclaration(property.key)) {
118 markDisplayNameAsDeclared(node);
122 'Program:exit': function() {
123 var list = componentList.getList();
124 // Report missing display name for all classes
125 for (var component in list) {
126 if (!list.hasOwnProperty(component) || !mustBeValidated(list[component])) {
129 reportMissingDisplayName(list[component]);
133 ReturnStatement: function(node) {
134 if (!componentUtil.isReactComponent(context, node)) {
137 componentList.set(context, node, {
138 isReactComponent: true