Skip to content

Instantly share code, notes, and snippets.

@martinschneider01
Created July 26, 2022 13:18
Show Gist options
  • Save martinschneider01/40e0f340cf2ed549a875e8de00475b97 to your computer and use it in GitHub Desktop.
Save martinschneider01/40e0f340cf2ed549a875e8de00475b97 to your computer and use it in GitHub Desktop.
// Codemod to be used with jscodeshift
import {
API,
ASTPath,
CallExpression,
FileInfo,
Identifier,
JSCodeshift,
ObjectExpression,
ObjectProperty,
} from 'jscodeshift';
const requiredPropertiesKeys = ['data', 'number', 'general', 'renderers'] as const;
// Filter function to ensure that we enter the mutation function only if needed
const filterOutSimpleUsages = (p: ASTPath<CallExpression>) => {
const args = p.value.arguments;
// If we only have the translation key, we don't need to refactor this usage
if (args.length === 1) {
return false;
}
// More than 2 arguments is an absolute sign of an old usage
// If second argument is not an object, we need to manually fix this case
if (args.length > 2 || args[1].type !== 'ObjectExpression') {
return true;
}
// If none of the above properties is found in second argument, we can say that this is an old usage
return requiredPropertiesKeys.every(
(requiredPropertyKey) =>
!(args[1] as ObjectExpression).properties.find(
// I needed to do some TS trickery to avoid getting warnings everywhere, sorry for that
(property) => ((property as ObjectProperty).key as Identifier).name === requiredPropertyKey,
),
);
};
// Mutation function, we apply our modification to the AST
const mutatePath = (j: JSCodeshift) => (p: ASTPath<CallExpression>) => {
const objectProperties = requiredPropertiesKeys.reduce((acc, propertyKey, index) => {
const argument = p.value.arguments[index + 1];
if (!argument || argument.type === 'SpreadElement') {
return acc;
}
if ((argument as Identifier).name && (argument as Identifier).name === 'undefined') {
return acc;
}
return [...acc, j.objectProperty(j.identifier(propertyKey), argument)];
}, [] as ObjectProperty[]);
p.value.arguments = [p.value.arguments[0], j.objectExpression(objectProperties)];
return p;
};
module.exports = function (file: FileInfo, api: API) {
const j = api.jscodeshift;
// If we don't find any "Translate" string inside our file, we can assume that it's safe to skip it
const regex = new RegExp('Translate[(]', 'i');
if (!regex.test(file.source)) {
return null;
}
return j(file.source)
.find(j.CallExpression, {
callee: {
type: 'Identifier',
name: 't',
},
})
.filter(filterOutSimpleUsages)
.map(mutatePath(j))
.toSource();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment