Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions test/__tests__/create-element-to-jsx-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ describe('create-element-to-jsx', () => {
test('create-element-to-jsx', 'create-element-to-jsx-literal-prop');

test('create-element-to-jsx', 'create-element-to-jsx-call-as-children');

test('create-element-to-jsx', 'create-element-to-jsx-react-spread');

test('create-element-to-jsx', 'create-element-to-jsx-object-assign');
});

it('raises when it does not recognize a property type', () => {
const jscodeshift = require('jscodeshift');
const transform = require('../../transforms/create-element-to-jsx');
const source = `
var React = require("react/addons");
React.createElement("foo", 1)
`;

expect(() => transform({source}, {jscodeshift}, {}))
.toThrow('Unexpected attribute of type "Literal"');
});

});
7 changes: 7 additions & 0 deletions test/create-element-to-jsx-object-assign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var React = require('react/addons');

React.createElement(Foo, Object.assign({
'foo': 'bar'
}, props, {
'bar': 'foo'
}));
3 changes: 3 additions & 0 deletions test/create-element-to-jsx-object-assign.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var React = require('react/addons');

<Foo foo="bar" {...props} bar="foo" />;
7 changes: 7 additions & 0 deletions test/create-element-to-jsx-react-spread.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var React = require('react/addons');

React.createElement(Foo, React.__spread({
'foo': 'bar'
}, props, {
'bar': 'foo'
}));
3 changes: 3 additions & 0 deletions test/create-element-to-jsx-react-spread.output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var React = require('react/addons');

<Foo foo="bar" {...props} bar="foo" />;
88 changes: 53 additions & 35 deletions transforms/create-element-to-jsx.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,61 @@ module.exports = function(file, api, options) {
const root = j(file.source);
const ReactUtils = require('./utils/ReactUtils')(j);

const convertObjectExpressionToJSXAttributes = (objectExpression) => {
if (objectExpression.type === 'Identifier') {
return [j.jsxSpreadAttribute(objectExpression)];
}

if (!objectExpression.properties) {
return [];
}

const attributes = objectExpression.properties.map((property) => {
if (property.type === 'SpreadProperty') {
return j.jsxSpreadAttribute(property.argument);
} else if (property.type === 'Property') {
const propertyValueType = property.value.type;

let value;
if (propertyValueType === 'Literal' && typeof property.value.value === 'string') {
value = j.literal(property.value.value);
} else {
value = j.jsxExpressionContainer(property.value);
}
const convertExpressionToJSXAttributes = (expression) => {
const isReactSpread = expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.object.name === 'React' &&
expression.callee.property.name === '__spread';

const isObjectAssign = expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.object.name === 'Object' &&
expression.callee.property.name === 'assign';

if (expression.type === 'Identifier') {
return [j.jsxSpreadAttribute(expression)];
} else if (isReactSpread || isObjectAssign) {
const jsxAttributes = [];

expression.arguments.forEach((expression) =>
jsxAttributes.push(...convertExpressionToJSXAttributes(expression))
);

let propertyKeyName;
if (property.key.type === 'Literal') {
propertyKeyName = property.key.value;
} else {
propertyKeyName = property.key.name;
return jsxAttributes;
} else if (expression.type === 'ObjectExpression') {
const attributes = expression.properties.map((property) => {
if (property.type === 'SpreadProperty') {
return j.jsxSpreadAttribute(property.argument);
} else if (property.type === 'Property') {
const propertyValueType = property.value.type;

let value;
if (propertyValueType === 'Literal' && typeof property.value.value === 'string') {
value = j.literal(property.value.value);
} else {
value = j.jsxExpressionContainer(property.value);
}

let propertyKeyName;
if (property.key.type === 'Literal') {
propertyKeyName = property.key.value;
} else {
propertyKeyName = property.key.name;
}

return j.jsxAttribute(
j.jsxIdentifier(propertyKeyName),
value
);
}
});

return j.jsxAttribute(
j.jsxIdentifier(propertyKeyName),
value
);
}
});

return attributes;
return attributes;
} else if (expression.type === 'Literal' && expression.value === null) {
return [];
} else {
throw new Error(`Unexpected attribute of type "${expression.type}"`);
}
};

const convertNodeToJSX = (node) => {
Expand All @@ -49,7 +67,7 @@ module.exports = function(file, api, options) {
const elementName = elementType === 'Literal' ? args[0].value : args[0].name;
const props = args[1];

const attributes = convertObjectExpressionToJSXAttributes(props);
const attributes = convertExpressionToJSXAttributes(props);

const children = node.value.arguments.slice(2).map((child, index) => {
if (child.type === 'Literal' && typeof child.value === 'string') {
Expand Down