1// Based on https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-transform-react-native-svg 2 3const elementToComponent = { 4 a: 'A', 5 article: 'Article', 6 b: 'B', 7 br: 'BR', 8 caption: 'Caption', 9 code: 'Code', 10 footer: 'Footer', 11 h1: 'H1', 12 h2: 'H2', 13 pre: 'Pre', 14 h3: 'H3', 15 h4: 'H4', 16 h5: 'H5', 17 h6: 'H6', 18 header: 'Header', 19 time: 'Time', 20 hr: 'HR', 21 i: 'I', 22 mark: 'Mark', 23 del: 'Del', 24 em: 'EM', 25 li: 'LI', 26 main: 'Main', 27 nav: 'Nav', 28 p: 'P', 29 s: 'S', 30 section: 'Section', 31 table: 'Table', 32 tbody: 'TBody', 33 td: 'TD', 34 th: 'TH', 35 thead: 'THead', 36 tr: 'TR', 37 ul: 'UL', 38 strong: 'Strong', 39 aside: 'Aside', 40 tfoot: 'TFoot', 41}; 42 43module.exports = ({ types: t }, { expo }) => { 44 function replaceElement(path, state) { 45 const { name } = path.node.openingElement.name; 46 47 // Replace element with @expo/html-elements 48 const component = elementToComponent[name]; 49 50 if (!component) { 51 return; 52 } 53 const prefixedComponent = component; 54 const openingElementName = path.get('openingElement.name'); 55 openingElementName.replaceWith(t.jsxIdentifier(prefixedComponent)); 56 if (path.has('closingElement')) { 57 const closingElementName = path.get('closingElement.name'); 58 closingElementName.replaceWith(t.jsxIdentifier(prefixedComponent)); 59 } 60 state.replacedComponents.add(prefixedComponent); 61 } 62 63 const htmlElementVisitor = { 64 JSXElement(path, state) { 65 replaceElement(path, state); 66 path.traverse(jsxElementVisitor, state); 67 }, 68 }; 69 70 const jsxElementVisitor = { 71 JSXElement(path, state) { 72 replaceElement(path, state); 73 }, 74 }; 75 76 const importDeclarationVisitor = { 77 ImportDeclaration(path, state) { 78 if (path.get('source').isStringLiteral({ value: '@expo/html-elements' })) { 79 state.replacedComponents.forEach(component => { 80 if ( 81 path 82 .get('specifiers') 83 .some(specifier => specifier.get('local').isIdentifier({ name: component })) 84 ) { 85 return; 86 } 87 path.pushContainer( 88 'specifiers', 89 t.importSpecifier(t.identifier(component), t.identifier(component)) 90 ); 91 }); 92 } 93 }, 94 }; 95 96 return { 97 name: 'Rewrite React DOM to universal Expo elements', 98 visitor: { 99 Program(path, state) { 100 state.replacedComponents = new Set(); 101 state.unsupportedComponents = new Set(); 102 103 path.traverse(htmlElementVisitor, state); 104 path.traverse(importDeclarationVisitor, state); 105 }, 106 }, 107 }; 108}; 109