export default function({ types: t }) { function hasRefOrSpread(attrs) { for (let i = 0; i < attrs.length; i++) { const attr = attrs[i]; if (t.isJSXSpreadAttribute(attr)) return true; if (isJSXAttributeOfName(attr, "ref")) return true; } return false; } function isJSXAttributeOfName(attr, name) { return ( t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: name }) ); } function getAttributeValue(attr) { let value = attr.value; if (!value) return t.booleanLiteral(true); if (t.isJSXExpressionContainer(value)) value = value.expression; return value; } return { visitor: { JSXElement(path, file) { const { node } = path; // filter const open = node.openingElement; if (hasRefOrSpread(open.attributes)) return; // init const props = t.objectExpression([]); let key = null; let type = open.name; if (t.isJSXIdentifier(type) && t.react.isCompatTag(type.name)) { type = t.stringLiteral(type.name); } function pushProp(objProps, key, value) { objProps.push(t.objectProperty(key, value)); } // props for (const attr of (open.attributes: Array)) { if (isJSXAttributeOfName(attr, "key")) { key = getAttributeValue(attr); } else { const name = attr.name.name; const propertyKey = t.isValidIdentifier(name) ? t.identifier(name) : t.stringLiteral(name); pushProp(props.properties, propertyKey, getAttributeValue(attr)); } } const args = [type, props]; if (key || node.children.length) { const children = t.react.buildChildren(node); args.push( key || t.unaryExpression("void", t.numericLiteral(0), true), ...children, ); } const el = t.callExpression(file.addHelper("jsx"), args); path.replaceWith(el); }, }, }; }