@samitouri / QOS-React-2 / commits / fea7bc5968

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