import esutils from "esutils";
export default ({ types: t }) => {
function convertAttributesAssign(attributes) {
const args = [];
for (let i = 0, current; i < attributes.length; i++) {
const node = attributes[i];
if (t.isJSXSpreadAttribute(node)) {
if (i === 0) {
args.push(t.objectExpression([]));
}
current = null;
args.push(node.argument);
} else {
const name = getAttributeName(node);
const value = getAttributeValue(node);
if (!current) {
current = t.objectExpression([]);
args.push(current);
}
current.properties.push(t.objectProperty(name, value));
}
}
return t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("assign")),
args
);
}
function convertAttributeSpread(node) {
if (t.isJSXSpreadAttribute(node)) {
return t.spreadElement(node.argument);
}
const name = getAttributeName(node);
const value = getAttributeValue(node);
return t.inherits(t.objectProperty(name, value), node);
}
function getAttributeName(node) {
if (t.isJSXNamespacedName(node.name)) {
return t.stringLiteral(
node.name.namespace.name + ":" + node.name.name.name
);
}
if (esutils.keyword.isIdentifierNameES6(node.name.name)) {
return t.identifier(node.name.name);
}
return t.stringLiteral(node.name.name);
}
function getAttributeValue(node) {
let value = node.value || t.booleanLiteral(true);
if (t.isJSXExpressionContainer(value)) {
value = value.expression;
} else if (t.isStringLiteral(value)) {
value.value = value.value.replace(/\n\s+/g, " ");
if (value.extra && value.extra.raw) {
delete value.extra.raw;
}
}
return value;
}
return {
name: "transform-jsx-spread",
visitor: {
JSXOpeningElement(path, state) {
const useSpread = state.opts.useSpread === true;
const hasSpread = path.node.attributes.some(attr =>
t.isJSXSpreadAttribute(attr)
);
if (!hasSpread || path.node.attributes.length === 1) return;
if (useSpread) {
path.node.attributes = [
t.jsxSpreadAttribute(
t.objectExpression(
path.node.attributes.map(convertAttributeSpread)
)
),
];
} else {
path.node.attributes = [
t.jsxSpreadAttribute(convertAttributesAssign(path.node.attributes)),
];
}
},
},
};
};