export default declare(api => { api.assertVersion(7); return { name: "transform-react-jsx-compat", manipulateOptions(opts, parserOpts) { parserOpts.plugins.push("jsx"); }, visitor: helper({ pre(state) { state.callee = state.tagExpr; }, post(state) { if (t.react.isCompatTag(state.tagName)) { state.call = t.callExpression( t.memberExpression( t.memberExpression(t.identifier("React"), t.identifier("DOM")), state.tagExpr, t.isLiteral(state.tagExpr), ), state.args, ); } }, compat: true, }), }; });
export default declare(api => { api.assertVersion(7); 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 }) ); } const visitor = helper({ filter(node) { return ( // Regular JSX nodes have an `openingElement`. JSX fragments, however, don't have an // `openingElement` which causes `node.openingElement.attributes` to throw. node.openingElement && !hasRefOrSpread(node.openingElement.attributes) ); }, pre(state) { const tagName = state.tagName; const args = state.args; if (t.react.isCompatTag(tagName)) { args.push(t.stringLiteral(tagName)); } else { args.push(state.tagExpr); } }, post(state, pass) { state.callee = pass.addHelper("jsx"); // NOTE: The arguments passed to the "jsx" helper are: // (element, props, key, ...children) or (element, props) // The argument generated by the helper are: // (element, { ...props, key }, ...children) const props = state.args[1]; let hasKey = false; if (t.isObjectExpression(props)) { const keyIndex = props.properties.findIndex(prop => t.isIdentifier(prop.key, { name: "key" }), ); if (keyIndex > -1) { state.args.splice(2, 0, props.properties[keyIndex].value); props.properties.splice(keyIndex, 1); hasKey = true; } } else if (t.isNullLiteral(props)) { state.args.splice(1, 1, t.objectExpression([])); } if (!hasKey && state.args.length > 2) { state.args.splice(2, 0, t.unaryExpression("void", t.numericLiteral(0))); } }, }); return { name: "transform-react-inline-elements", visitor, }; });
export default function(api, options) { const THROW_IF_NAMESPACE = options.throwIfNamespace === undefined ? true : !!options.throwIfNamespace; const PRAGMA_DEFAULT = options.pragma || "React.createElement"; const PRAGMA_FRAG_DEFAULT = options.pragmaFrag || "React.Fragment"; const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/; const JSX_FRAG_ANNOTATION_REGEX = /\*?\s*@jsxFrag\s+([^\s]+)/; // returns a closure that returns an identifier or memberExpression node // based on the given id const createIdentifierParser = (id: string) => () => { return id .split(".") .map(name => t.identifier(name)) .reduce((object, property) => t.memberExpression(object, property)); }; const visitor = helper({ pre(state) { const tagName = state.tagName; const args = state.args; if (t.react.isCompatTag(tagName)) { args.push(t.stringLiteral(tagName)); } else { args.push(state.tagExpr); } }, post(state, pass) { state.callee = pass.get("jsxIdentifier")(); }, throwIfNamespace: THROW_IF_NAMESPACE, }); visitor.Program = { enter(path, state) { const { file } = state; let pragma = PRAGMA_DEFAULT; let pragmaFrag = PRAGMA_FRAG_DEFAULT; let pragmaSet = !!options.pragma; let pragmaFragSet = !!options.pragmaFrag; for (const comment of (file.ast.comments: Array<Object>)) { const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value); if (jsxMatches) { pragma = jsxMatches[1]; pragmaSet = true; } const jsxFragMatches = JSX_FRAG_ANNOTATION_REGEX.exec(comment.value); if (jsxFragMatches) { pragmaFrag = jsxFragMatches[1]; pragmaFragSet = true; } } state.set("jsxIdentifier", createIdentifierParser(pragma)); state.set("jsxFragIdentifier", createIdentifierParser(pragmaFrag)); state.set("usedFragment", false); state.set("pragmaSet", pragmaSet); state.set("pragmaFragSet", pragmaFragSet); }, exit(path, state) { if ( state.get("pragmaSet") && state.get("usedFragment") && !state.get("pragmaFragSet") ) { throw new Error( "transform-react-jsx: pragma has been set but " + "pragmafrag has not been set", ); } }, }; visitor.JSXAttribute = function(path) { if (t.isJSXElement(path.node.value)) { path.node.value = t.jsxExpressionContainer(path.node.value); } }; return { inherits: jsx, visitor, }; }