@mui/codemod
Version:
Codemod scripts for Material UI.
129 lines (124 loc) • 4.09 kB
JavaScript
"use strict";
/* eslint-disable no-eval */
/**
* Update all `theme.spacing.unit` usages to use `theme.spacing()`.
* Find and replace string literal AST nodes to ensure all spacing API usages get updated, regardless
* of any calculation being performed.
* @param {jscodeshift_api_object} j
* @param {jscodeshift_ast_object} root
*/
function transformThemeSpacingApi(j, root) {
const mightContainApi = path => {
return j(path).find(j.MemberExpression, {
object: {
property: {
name: 'spacing'
}
},
property: {
name: 'unit'
}
}).size() > 0;
};
const replaceApi = pathArg => {
pathArg.find(j.MemberExpression, {
object: {
property: {
name: 'spacing'
}
},
property: {
name: 'unit'
}
}).replaceWith(path => {
let param = null;
const themeParam = path.node.object.object.name;
if (j.BinaryExpression.check(path.parent.node)) {
const expression = path.parent.node;
const operation = expression.operator;
// check if it's a variable
if (j.Identifier.check(expression.right)) {
param = expression.right;
} else if (j.Literal.check(expression.right)) {
const value = expression.right.value;
if (operation === '*' || operation === '/') {
param = j.literal(eval(`1 ${operation} ${value}`));
}
}
}
if (param) {
path.parent.replace(j.callExpression(j.memberExpression(j.identifier(themeParam), j.identifier('spacing')), [param]));
return path.node;
}
return j.callExpression(j.memberExpression(j.identifier(themeParam), j.identifier('spacing')), [j.literal(1)]);
});
};
const arrowFunctions = root.find(j.ArrowFunctionExpression).filter(mightContainApi);
const functionDeclarations = root.find(j.FunctionDeclaration).filter(mightContainApi);
replaceApi(arrowFunctions);
replaceApi(functionDeclarations);
}
/**
* Update all `spacing.unit` usages to use `spacing()`.
* Find and replace string literal AST nodes to ensure all spacing API usages get updated, regardless
* of any calculation being performed.
* @param {jscodeshift_api_object} j
* @param {jscodeshift_ast_object} root
*/
function transformThemeSpacingApiDestructured(j, root) {
const mightContainApi = path => {
return j(path).find(j.MemberExpression, {
object: {
name: 'spacing'
},
property: {
name: 'unit'
}
}).size() > 0;
};
const replaceApi = pathArg => {
pathArg.find(j.MemberExpression, {
object: {
name: 'spacing'
},
property: {
name: 'unit'
}
}).replaceWith(path => {
let param = null;
const spacingParam = path.node.object.name;
if (j.BinaryExpression.check(path.parent.node)) {
const expression = path.parent.node;
const operation = expression.operator;
// check if it's a variable
if (j.Identifier.check(expression.right)) {
param = expression.right;
} else if (j.Literal.check(expression.right)) {
const value = expression.right.value;
if (operation === '*' || operation === '/') {
param = j.literal(eval(`1 ${operation} ${value}`));
}
}
}
if (param) {
path.parent.replace(j.callExpression(j.identifier(spacingParam), [param]));
return path.node;
}
return j.callExpression(j.identifier(spacingParam), [j.literal(1)]);
});
};
const arrowFunctions = root.find(j.ArrowFunctionExpression).filter(mightContainApi);
const functionDeclarations = root.find(j.FunctionDeclaration).filter(mightContainApi);
replaceApi(arrowFunctions);
replaceApi(functionDeclarations);
}
module.exports = function transformer(fileInfo, api) {
const j = api.jscodeshift;
const root = j(fileInfo.source);
// transforms
transformThemeSpacingApi(j, root);
transformThemeSpacingApiDestructured(j, root);
return root.toSource({
quote: 'single'
});
};