Use full chain of member expressions when generating display names.
Assumed to be namespaced names (with the exception of "exports", which is special-cased).
Mihai Parparita committed
Mar 17, 2015 at 16:29 UTC
fea7bc5968bf5e2acc164df2773a6b8ac5a53c70
2 files changed
+83
-9
vendor/fbtransform/transforms/__tests__/react-displayName-test.js
+41
@@ -87,6 +87,47 @@ describe('react displayName jsx', function() {
87
});
88
89
it('should inject displayName in property assignment', () => {
90
+ var code = [
91
+ 'ns.Component = React.createClass({',
92
+ ' render: function() {',
93
+ ' return null;',
94
+ ' }',
95
+ '});'
96
+ ].join('\n');
97
+
98
+ var result = [
99
+ 'ns.Component = React.createClass({displayName: "ns.Component",',
100
+ ' render: function() {',
101
+ ' return null;',
102
+ ' }',
103
+ '});'
104
+ ].join('\n');
105
+
106
+ expect(transform(code).code).toEqual(result);
107
+ });
108
+
109
+ it('should inject displayName in chained property assignment', () => {
110
+ var code = [
111
+ 'ns.ns1.Component = React.createClass({',
112
+ ' render: function() {',
113
+ ' return null;',
114
+ ' }',
115
+ '});'
116
+ ].join('\n');
117
+
118
+ var result = [
119
+ 'ns.ns1.Component = React.createClass({displayName: "ns.ns1.Component",',
120
+ ' render: function() {',
121
+ ' return null;',
122
+ ' }',
123
+ '});'
124
+ ].join('\n');
125
+
126
+ expect(transform(code).code).toEqual(result);
127
+ });
128
+
129
+
130
+ it('should inject displayName in exports property assignment', () => {
131
var code = [
132
'exports.Component = React.createClass({',
133
' render: function() {',
vendor/fbtransform/transforms/reactDisplayName.js
+42
-9
@@ -12,7 +12,7 @@
12
var Syntax = require('jstransform').Syntax;
13
var utils = require('jstransform/src/utils');
14
15
-function addDisplayName(displayName, object, state) {
15
+function shouldAddDisplayName(object) {
16
if (object &&
17
object.type === Syntax.CallExpression &&
18
object.callee.type === Syntax.MemberExpression &&
@@ -30,12 +30,37 @@ function addDisplayName(displayName, object, state) {
30
property.key.value;
31
return value !== 'displayName';
32
});
33
+ return safe;
34
+ }
35
+ return false;
36
+}
37
34
- if (safe) {
35
- utils.catchup(object.arguments[0].range[0] + 1, state);
36
- utils.append('displayName: "' + displayName + '",', state);
38
+/**
39
+ * If `expr` is an Identifier or MemberExpression node made of identifiers and
40
+ * dot accesses, return a list of the identifier parts. Other nodes return null.
41
+ *
42
+ * Examples:
43
+ *
44
+ * MyComponent -> ['MyComponent']
45
+ * namespace.MyComponent -> ['namespace', 'MyComponent']
46
+ * namespace['foo'] -> null
47
+ * namespace['foo'].bar -> ['bar']
48
+ */
49
+function flattenIdentifierOrMemberExpression(expr) {
50
+ if (expr.type === Syntax.Identifier) {
51
+ return [expr.name];
52
+ } else if (expr.type === Syntax.MemberExpression) {
53
+ if (!expr.computed && expr.property.type === Syntax.Identifier) {
54
+ var flattenedObject = flattenIdentifierOrMemberExpression(expr.object);
55
+ if (flattenedObject) {
56
+ flattenedObject.push(expr.property.name);
57
+ return flattenedObject;
58
+ } else {
59
+ return [expr.property.name];
60
+ }
61
}
62
}
63
+ return null;
64
}
65
66
/**
@@ -55,6 +80,7 @@ function addDisplayName(displayName, object, state) {
80
* Also catches:
81
*
82
* MyComponent = React.createClass(...);
83
+ * namespace.MyComponent = React.createClass(...);
84
* exports.MyComponent = React.createClass(...);
85
* module.exports = {MyComponent: React.createClass(...)};
86
*/
@@ -72,11 +98,18 @@ function visitReactDisplayName(traverse, object, path, state) {
98
right = object.init;
99
}
100
75
- if (left && left.type === Syntax.MemberExpression) {
76
- left = left.property;
77
- }
78
- if (left && left.type === Syntax.Identifier) {
79
- addDisplayName(left.name, right, state);
101
+ if (right && shouldAddDisplayName(right)) {
102
+ var displayNamePath = flattenIdentifierOrMemberExpression(left);
103
+ if (displayNamePath) {
104
+ if (displayNamePath.length > 1 && displayNamePath[0] === 'exports') {
105
+ displayNamePath.shift();
106
+ }
107
+
108
+ var displayName = displayNamePath.join('.');
109
+
110
+ utils.catchup(right.arguments[0].range[0] + 1, state);
111
+ utils.append('displayName: "' + displayName + '",', state);
112
+ }
113
}
114
}
115