transforms/React-DOM-to-react-dom-factories.js (99 lines of code) (raw):

/** * Copyright 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ 'use strict'; module.exports = function(file, api, options) { const j = api.jscodeshift; const printOptions = options.printOptions || { quote: 'single' }; const root = j(file.source); let hasModifications; const DOMModuleName = 'DOM'; /** * Replaces 'DOM' with 'createElement' in places where we grab 'DOM' out of * 'React' with destructuring. * Note that this only picks up 'DOM' when required from React or * require('react') */ const replaceDestructuredDOMStatement = (j, root) => { let hasModifications = false; //--------- // First update import statments. eg: // import { // DOM, // foo, // } from 'react'; root .find(j.ImportDeclaration) .filter( path => path.node.specifiers.filter( specifier => specifier.imported && specifier.imported.name === DOMModuleName ).length > 0 && path.node.source.value === 'react' ) .forEach(path => { hasModifications = true; // Replace the DOM key with 'createElement' path.node.specifiers = path.node.specifiers.map(specifier => { if (specifier.imported && specifier.imported.name === DOMModuleName) { return j.importSpecifier(j.identifier('createElement')); } else { return specifier; } }); }); //--------- // Next update require statments. // This matches both // const { // Component, // DOM, // } = React; // and // const { // Component, // DOM, // } = require('react'); root .find(j.ObjectPattern) .filter( path => path.parent.node.init && // matches '} = React;' (path.parent.node.init.name === 'React' || // matches "} = require('react');" (path.parent.node.init.type === 'CallExpression' && path.parent.node.init.callee.name === 'require' && path.parent.node.init.arguments[0].value === 'react')) && path.node.properties.some(property => { return property.key.name === DOMModuleName; }) ) .forEach(path => { hasModifications = true; // Replace the DOM key with 'createElement' path.node.properties = path.node.properties.map(property => { if (property.key.name === DOMModuleName) { return j.identifier('createElement'); } else { return property; } }); }); return hasModifications; }; hasModifications = replaceDestructuredDOMStatement(j, root) || hasModifications; if (hasModifications) { // if we 'hasModifications' then we found and replaced a reference to // '{DOM} = React;' or '{DOM} = require('react');' // In this case we need to update 'DOM.<element>' syntax /** * Update cases where DOM.div is being called * eg 'foo = DOM.div('a'...' * replace with 'foo = createElement('div', 'a'...' */ function replaceDOMReferences(j, root) { let hasModifications = false; const isDOMIdentifier = path => path.node.name === DOMModuleName && path.parent.parent.node.type === 'CallExpression'; root .find(j.Identifier) .filter(isDOMIdentifier) .forEach(path => { hasModifications = true; const DOMargs = path.parent.parent.node.arguments; const DOMFactoryPath = path.parent.node.property; const DOMFactoryType = DOMFactoryPath.name; // DOM.div(... -> createElement(... j(path.parent).replaceWith(j.identifier('createElement')); // createElement(... -> createElement('div', ... DOMargs.unshift(j.literal(DOMFactoryType)); }); return hasModifications; } hasModifications = replaceDOMReferences(j, root) || hasModifications; } /** * Update React.DOM references * eg 'foo = React.DOM.div('a'...' * replace with 'foo = React.createElement('div', 'a'...' */ function replaceReactDOMReferences(j, root) { let hasModifications = false; // matches 'React.DOM' const isReactDOMIdentifier = path => path.node.name === DOMModuleName && (path.parent.node.type === 'MemberExpression' && path.parent.node.object.name === 'React'); root .find(j.Identifier) .filter(isReactDOMIdentifier) .forEach(path => { hasModifications = true; const DOMargs = path.parent.parent.parent.node.arguments; const DOMFactoryPath = path.parent.parent.node.property; const DOMFactoryType = DOMFactoryPath.name; // React.DOM.div(... -> React.DOM.createElement(... path.parent.parent.node.property = j.identifier('createElement'); // React.DOM.createElement(... -> React.createElement(... j(path.parent).replaceWith(j.identifier('React')); // React.createElement(... -> React.createElement('div'... DOMargs.unshift(j.literal(DOMFactoryType)); }); return hasModifications; } hasModifications = replaceReactDOMReferences(j, root) || hasModifications; return hasModifications ? root.toSource(printOptions) : null; };