@lmc-eu/spirit-codemods
Version:
Codemods scripts for Spirit Design System packages
120 lines (106 loc) • 4 kB
text/typescript
import { API, FileInfo, JSXAttribute } from 'jscodeshift';
const transform = (fileInfo: FileInfo, api: API) => {
const j = api.jscodeshift;
const root = j(fileInfo.source);
root
.find(j.ImportDeclaration, {
source: {
value: (value: string) => /^@lmc-eu\/spirit-web-react(\/.*)?$/.test(value),
},
})
.forEach((path) => {
if (path.node.specifiers) {
path.node.specifiers = path.node.specifiers.map((specifier) => {
if ('imported' in specifier && specifier.imported.name === 'GridSpan') {
return j.importSpecifier(j.identifier('GridItem'));
}
return specifier;
});
}
});
root
.find(j.JSXOpeningElement, {
name: {
type: 'JSXIdentifier',
name: 'GridSpan',
},
})
.forEach((path) => {
if (path.node.name.type === 'JSXIdentifier') {
path.node.name.name = 'GridItem';
}
const attributesMap: { [key: string]: JSXAttribute | undefined } = {};
const columnStartValues: { [key: string]: number } = {};
const columnEndValues: { [key: string]: string } = {};
path.node.attributes?.forEach((attr) => {
if (
attr.type === 'JSXAttribute' &&
(attr.name.name === 'over' || attr.name.name === 'tablet' || attr.name.name === 'desktop') &&
attr.value?.type === 'JSXExpressionContainer'
) {
let overValue = 0;
if (attr.value.expression.type === 'NumericLiteral') {
overValue = attr.value.expression.value;
}
const columnStartValue = 1 + (12 - overValue) / 2;
const breakpoint = attr.name.name === 'over' ? 'mobile' : attr.name.name;
columnStartValues[breakpoint] = columnStartValue;
columnEndValues[breakpoint] = `span ${overValue}`;
} else if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
attributesMap[attr.name.name] = attr;
}
});
if (Object.keys(columnStartValues).length === 1 && columnStartValues.mobile) {
attributesMap.columnStart = j.jsxAttribute(
j.jsxIdentifier('columnStart'),
j.jsxExpressionContainer(j.numericLiteral(columnStartValues.mobile)),
);
} else {
attributesMap.columnStart = j.jsxAttribute(
j.jsxIdentifier('columnStart'),
j.jsxExpressionContainer(
j.objectExpression(
Object.entries(columnStartValues).map(([key, value]) =>
j.objectProperty(j.identifier(key), j.numericLiteral(value)),
),
),
),
);
}
if (Object.keys(columnEndValues).length === 1 && columnEndValues.mobile) {
attributesMap.columnEnd = j.jsxAttribute(j.jsxIdentifier('columnEnd'), j.stringLiteral(columnEndValues.mobile));
} else {
attributesMap.columnEnd = j.jsxAttribute(
j.jsxIdentifier('columnEnd'),
j.jsxExpressionContainer(
j.objectExpression(
Object.entries(columnEndValues).map(([key, value]) =>
j.objectProperty(j.identifier(key), j.stringLiteral(value)),
),
),
),
);
}
path.node.attributes = Object.values(attributesMap).filter(Boolean) as JSXAttribute[];
});
root
.find(j.JSXClosingElement, {
name: {
type: 'JSXIdentifier',
name: 'GridSpan',
},
})
.forEach((path) => {
if (path.node.name.type === 'JSXIdentifier') {
path.node.name.name = 'GridItem';
}
});
let source = root.toSource({ trailingComma: true });
// Post-process the generated code to replace double quotes with single quotes in columnEnd object values
// jscodeshift doesn't support this transformation natively
source = source.replace(/columnEnd={{([^}]+)}}/g, (match) => {
return match.replace(/"([^"]+)"/g, "'$1'");
});
return source;
};
export default transform;