diff --git a/vendor/fbtransform/transforms/__tests__/react-test.js b/vendor/fbtransform/transforms/__tests__/react-test.js
new file mode 100644
index 0000000000..546db630d7
--- /dev/null
+++ b/vendor/fbtransform/transforms/__tests__/react-test.js
@@ -0,0 +1,360 @@
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @emails javascript@lists.facebook.com
+ */
+"use strict";
+
+require('mock-modules').autoMockOff();
+
+describe('react jsx', function() {
+ var transformAll = require('../../syntax.js').transformAll;
+
+ var transform = function(code, options, excludes) {
+ return transformAll(
+ code,
+ options,
+ (excludes || []).concat(['sourcemeta', 'allocate'])
+ );
+ };
+
+ it('should convert simple tags', function() {
+ var code = [
+ '/**@jsx React.DOM*/',
+ 'var x =
;'
+ ].join('\n');
+ var result = [
+ '/**@jsx React.DOM*/',
+ 'var x = React.DOM.div(null);'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should convert simple text', function() {
+ var code = [
+ '/**@jsx React.DOM*/\n' +
+ 'var x = text
;'
+ ].join('\n');
+ var result = [
+ '/**@jsx React.DOM*/',
+ 'var x = React.DOM.div(null, "text");'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should have correct comma in nested children', function() {
+ var code = [
+ '/**@jsx React.DOM*/',
+ 'var x = ',
+ '
',
+ '
{foo}
{bar}',
+ '
',
+ '
;'
+ ].join('\n');
+ var result = [
+ '/**@jsx React.DOM*/',
+ 'var x = React.DOM.div(null, ',
+ ' React.DOM.div(null, React.DOM.br(null)), ',
+ ' Component(null, foo, React.DOM.br(null), bar), ',
+ ' React.DOM.br(null)',
+ ');'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should avoid wrapping in extra parens if not needed', function() {
+ // Try with a single composite child, wrapped in a div.
+ var code = [
+ '/**@jsx React.DOM*/',
+ 'var x = ',
+ ' ',
+ '
;'
+ ].join('\n');
+ var result = [
+ '/**@jsx React.DOM*/',
+ 'var x = React.DOM.div(null, ',
+ ' Component(null)',
+ ');'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+
+ // Try with a single interpolated child, wrapped in a div.
+ code = [
+ '/**@jsx React.DOM*/',
+ 'var x = ',
+ ' {this.props.children}',
+ '
;'
+ ].join('\n');
+ result = [
+ '/**@jsx React.DOM*/',
+ 'var x = React.DOM.div(null, ',
+ ' this.props.children',
+ ');'
+ ].join('\n');
+ expect(transform(code).code).toEqual(result);
+
+ // Try with a single interpolated child, wrapped in a composite.
+ code = [
+ '/**@jsx React.DOM*/',
+ 'var x = ',
+ ' {this.props.children}',
+ ';'
+ ].join('\n');
+ result = [
+ '/**@jsx React.DOM*/',
+ 'var x = Composite(null, ',
+ ' this.props.children',
+ ');'
+ ].join('\n');
+ expect(transform(code).code).toEqual(result);
+
+ // Try with a single composite child, wrapped in a composite.
+ code = [
+ '/**@jsx React.DOM*/',
+ 'var x = ',
+ ' ',
+ ';'
+ ].join('\n');
+ result = [
+ '/**@jsx React.DOM*/',
+ 'var x = Composite(null, ',
+ ' Composite2(null)',
+ ');'
+ ].join('\n');
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should insert commas after expressions before whitespace', function() {
+ var code = [
+ '/**@jsx React.DOM*/',
+ 'var x =',
+ ' ',
+ '
;'
+ ].join('\n');
+ var result = [
+ '/**@jsx React.DOM*/',
+ 'var x =',
+ ' React.DOM.div({',
+ ' attr1: ',
+ ' "foo" + "bar", ',
+ ' ',
+ ' attr2: ',
+ ' "foo" + "bar" +',
+ ' ',
+ ' "baz" + "bug", ',
+ ' ',
+ ' attr3: ',
+ ' "foo" + "bar" +',
+ ' "baz" + "bug", ',
+ ' // Extra line here.',
+ ' ',
+ ' attr4: "baz"}',
+ ' );'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should properly handle comments adjacent to children', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'var x = (',
+ ' ',
+ ' {/* A comment at the beginning */}',
+ ' {/* A second comment at the beginning */}',
+ ' ',
+ ' {/* A nested comment */}',
+ ' ',
+ ' {/* A sandwiched comment */}',
+ '
',
+ ' {/* A comment at the end */}',
+ ' {/* A second comment at the end */}',
+ '
',
+ ');'
+ ].join('\n');
+ var result = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'var x = (',
+ ' React.DOM.div(null, ',
+ ' /* A comment at the beginning */',
+ ' /* A second comment at the beginning */',
+ ' React.DOM.span(null',
+ ' /* A nested comment */',
+ ' ), ',
+ ' /* A sandwiched comment */',
+ ' React.DOM.br(null)',
+ ' /* A comment at the end */',
+ ' /* A second comment at the end */',
+ ' )',
+ ');'
+ ].join('\n');
+
+ expect(transform(code).code).toBe(result);
+ });
+
+ it('should properly handle comments between props', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'var x = (',
+ ' ',
+ ' ',
+ '
',
+ ');'
+ ].join('\n');
+ var result = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'var x = (',
+ ' React.DOM.div({',
+ ' /* a multi-line',
+ ' comment */',
+ ' attr1: "foo"}, ',
+ ' React.DOM.span({// a double-slash comment',
+ ' attr2: "bar"}',
+ ' )',
+ ' )',
+ ');'
+ ].join('\n');
+
+ expect(transform(code).code).toBe(result);
+ });
+
+ it('should not strip tags with a single child of ', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ '
;'
+ ].join('\n');
+ var result = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'React.DOM.div(null, "\u00A0");'
+ ].join('\n');
+
+ expect(transform(code).code).toBe(result);
+ });
+
+ it('should not strip even coupled with other whitespace', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ '
;'
+ ].join('\n');
+ var result = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'React.DOM.div(null, "\u00A0 ");'
+ ].join('\n');
+
+ expect(transform(code).code).toBe(result);
+ });
+
+ it('should handle hasOwnProperty correctly', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'testing;'
+ ].join('\n');
+ var result = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'hasOwnProperty(null, "testing");'
+ ].join('\n');
+
+ expect(transform(code).code).toBe(result);
+ });
+
+ it('should allow constructor as prop', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ ';'
+ ].join('\n');
+ var result = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'Component({constructor: "foo"});'
+ ].join('\n');
+
+ expect(transform(code).code).toBe(result);
+ });
+
+ it('should allow JS namespacing', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ ';'
+ ].join('\n');
+ var result = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ 'Namespace.Component(null);'
+ ].join('\n');
+
+ expect(transform(code).code).toBe(result);
+ });
+
+ it('should disallow XML namespacing', function() {
+ var code = [
+ '/**',
+ ' * @jsx React.DOM',
+ ' */',
+ ';'
+ ].join('\n');
+
+ expect(() => transform(code)).toThrow();
+ });
+
+});
diff --git a/vendor/fbtransform/transforms/__tests__/reactDisplayName-test.js b/vendor/fbtransform/transforms/__tests__/reactDisplayName-test.js
new file mode 100644
index 0000000000..f833f268e8
--- /dev/null
+++ b/vendor/fbtransform/transforms/__tests__/reactDisplayName-test.js
@@ -0,0 +1,150 @@
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @emails javascript@lists.facebook.com
+ */
+"use strict";
+
+require('mock-modules').autoMockOff();
+
+var transformAll = require('../../syntax.js').transformAll;
+
+function transform(source) {
+ return transformAll(source, {}, ['allocate']);
+}
+
+describe('react displayName jsx', function() {
+
+ it('should only inject displayName if missing', function() {
+ var code = [
+ '/** @jsx React.DOM */',
+ '"use strict";',
+ 'var Whateva = React.createClass({',
+ ' displayName: \'Whateva\',',
+ ' render: function() {',
+ ' return ...whateva.
;',
+ ' }',
+ '});'
+ ].join('\n');
+
+ var result = [
+ '/** @jsx React.DOM */',
+ '"use strict";',
+ 'var Whateva = React.createClass({',
+ ' displayName: \'Whateva\',',
+ ' render: function() {',
+ ' return React.DOM.div({className: "whateva"}, "...whateva.");',
+ ' }',
+ '});'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should inject displayName in simple assignment', () => {
+ var code = [
+ '/** @jsx React.DOM */',
+ 'var Component = React.createClass({',
+ ' render: function() {',
+ ' return ;',
+ ' }',
+ '});'
+ ].join('\n');
+
+ var result = [
+ '/** @jsx React.DOM */',
+ 'var Component = React.createClass({displayName: \'Component\',',
+ ' render: function() {',
+ ' return React.DOM.div(null);',
+ ' }',
+ '});'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should inject displayName in simple assignment without var', () => {
+ var code = [
+ '/** @jsx React.DOM */',
+ 'var Component;',
+ 'Component = React.createClass({',
+ ' render: function() {',
+ ' return ;',
+ ' }',
+ '});'
+ ].join('\n');
+
+ var result = [
+ '/** @jsx React.DOM */',
+ 'var Component;',
+ 'Component = React.createClass({displayName: \'Component\',',
+ ' render: function() {',
+ ' return React.DOM.div(null);',
+ ' }',
+ '});'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should inject displayName in property assignment', () => {
+ var code = [
+ '/** @jsx React.DOM */',
+ 'exports.Component = React.createClass({',
+ ' render: function() {',
+ ' return ;',
+ ' }',
+ '});'
+ ].join('\n');
+
+ var result = [
+ '/** @jsx React.DOM */',
+ 'exports.Component = React.createClass({displayName: \'Component\',',
+ ' render: function() {',
+ ' return React.DOM.div(null);',
+ ' }',
+ '});'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+ it('should inject displayName in object declaration', () => {
+ var code = [
+ '/** @jsx React.DOM */',
+ 'exports = {',
+ ' Component: React.createClass({',
+ ' render: function() {',
+ ' return ;',
+ ' }',
+ ' })',
+ '};'
+ ].join('\n');
+
+ var result = [
+ '/** @jsx React.DOM */',
+ 'exports = {',
+ ' Component: React.createClass({displayName: \'Component\',',
+ ' render: function() {',
+ ' return React.DOM.div(null);',
+ ' }',
+ ' })',
+ '};'
+ ].join('\n');
+
+ expect(transform(code).code).toEqual(result);
+ });
+
+});