Skip to content

Commit

Permalink
[codemod] Support more cases for sx-prop transformation (#42527)
Browse files Browse the repository at this point in the history
  • Loading branch information
siriwatknp authored Jun 5, 2024
1 parent f414d42 commit 44934b2
Show file tree
Hide file tree
Showing 6 changed files with 404 additions and 18 deletions.
100 changes: 82 additions & 18 deletions packages/mui-codemod/src/v6.0.0/sx-prop/sx-v6.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ export default function sxV6(file, api, options) {
}
}

function rootThemeCallback(data) {
if (data.root.type === 'ObjectExpression') {
data.replaceRoot?.(buildArrowFunctionAST([j.identifier('theme')], data.root));
} else if (data.root.type === 'ArrayExpression') {
data.root.elements.forEach((item, index) => {
if (item === data.node) {
data.root.elements[index] = buildArrowFunctionAST([j.identifier('theme')], data.root);
}
});
}
}

/**
*
* @param {{ node: import('jscodeshift').Expression }} data
Expand All @@ -165,10 +177,64 @@ export default function sxV6(file, api, options) {
if (data.node.type === 'ArrowFunctionExpression') {
const returnExpression = getReturnExpression(data.node);
if (returnExpression) {
recurseObjectExpression({
...data,
node: returnExpression,
});
if (
returnExpression.type === 'MemberExpression' &&
returnExpression.property?.type === 'ConditionalExpression'
) {
recurseObjectExpression({
...data,
node: j.conditionalExpression(
returnExpression.property.test,
{ ...returnExpression, property: returnExpression.property.consequent },
{ ...returnExpression, property: returnExpression.property.alternate },
),
});
} else if (returnExpression.type === 'TemplateLiteral') {
const firstExpression = returnExpression.expressions[0];
if (firstExpression?.type === 'ConditionalExpression') {
recurseObjectExpression({
...data,
node: j.conditionalExpression(
firstExpression.test,
{
...returnExpression,
expressions: [
firstExpression.consequent,
...(returnExpression.expressions || []).slice(1),
],
},
{
...returnExpression,
expressions: [
firstExpression.alternate,
...(returnExpression.expressions || []).slice(1),
],
},
),
});
} else {
recurseObjectExpression({
...data,
node: returnExpression,
});
}
} else if (
(returnExpression.type === 'CallExpression' &&
getObjectKey(returnExpression.callee)?.name === 'theme') ||
(returnExpression.type === 'MemberExpression' &&
getObjectKey(returnExpression)?.name === 'theme') ||
(returnExpression.type === 'BinaryExpression' &&
(getObjectKey(returnExpression.left)?.name === 'theme' ||
getObjectKey(returnExpression.right)?.name === 'theme'))
) {
data.replaceValue?.(returnExpression);
rootThemeCallback(data);
} else {
recurseObjectExpression({
...data,
node: returnExpression,
});
}
}
}
if (data.node.type === 'ObjectExpression') {
Expand Down Expand Up @@ -319,19 +385,7 @@ export default function sxV6(file, api, options) {
);
}
data.replaceValue?.(replaceUndefined(data.node.alternate));

if (data.root.type === 'ObjectExpression') {
data.replaceRoot?.(buildArrowFunctionAST([j.identifier('theme')], data.root));
} else if (data.root.type === 'ArrayExpression') {
data.root.elements.forEach((item, index) => {
if (item === data.node) {
data.root.elements[index] = buildArrowFunctionAST(
[j.identifier('theme')],
data.root,
);
}
});
}
rootThemeCallback(data);
} else {
wrapSxInArray(
j.conditionalExpression(
Expand Down Expand Up @@ -392,6 +446,16 @@ export default function sxV6(file, api, options) {
}
}
}
if (
data.node.expressions?.some(
(expression) =>
getObjectKey(expression)?.name === 'theme' ||
(expression.type === 'CallExpression' &&
getObjectKey(expression.callee)?.name === 'theme'),
)
) {
rootThemeCallback(data);
}
}
}
});
Expand All @@ -414,7 +478,7 @@ export default function sxV6(file, api, options) {
}
lines.push(line);
}
if (line.includes('sx=')) {
if (line.includes('sx=') && !line.match(/sx=\{\{[^}]+\}\}/)) {
isInStyled = true;
spaceMatch = line.match(/^\s+/);
}
Expand Down
24 changes: 24 additions & 0 deletions packages/mui-codemod/src/v6.0.0/sx-prop/sx-v6.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,29 @@ describe('@mui/codemod', () => {
expect(actual).to.equal(expected, 'The transformed version should be correct');
});
});

describe('should not delete line breaks', () => {
it('transforms props as needed', () => {
const actual = transform(
{ source: read('./test-cases/sx-line-break.actual.js') },
{ jscodeshift },
{},
);

const expected = read('./test-cases/sx-line-break.expected.js');
expect(actual).to.equal(expected, 'The transformed version should be correct');
});

it('should be idempotent', () => {
const actual = transform(
{ source: read('./test-cases/sx-line-break.expected.js') },
{ jscodeshift },
{},
);

const expected = read('./test-cases/sx-line-break.expected.js');
expect(actual).to.equal(expected, 'The transformed version should be correct');
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as React from 'react';
import AppBar from '@mui/material/AppBar';
import Stack from '@mui/material/Stack';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import MenuIcon from '@mui/icons-material/Menu';
import { ThemeProvider, createTheme } from '@mui/material/styles';

function appBarLabel(label) {
return (
<Toolbar>
<IconButton edge="start" color="inherit" aria-label="menu" sx={{ mr: 2 }}>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
{label}
</Typography>
</Toolbar>
);
}

const darkTheme = createTheme({
palette: {
mode: 'dark',
primary: {
main: '#1976d2',
},
},
});

export default function EnableColorOnDarkAppBar() {
return (
<Stack spacing={2} sx={{ flexGrow: 1 }}>
<ThemeProvider theme={darkTheme}>
<AppBar position="static" color="primary" enableColorOnDark>
{appBarLabel('enableColorOnDark')}
</AppBar>
<AppBar position="static" color="primary">
{appBarLabel('default')}
</AppBar>
</ThemeProvider>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as React from 'react';
import AppBar from '@mui/material/AppBar';
import Stack from '@mui/material/Stack';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import MenuIcon from '@mui/icons-material/Menu';
import { ThemeProvider, createTheme } from '@mui/material/styles';

function appBarLabel(label) {
return (
<Toolbar>
<IconButton edge="start" color="inherit" aria-label="menu" sx={{ mr: 2 }}>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
{label}
</Typography>
</Toolbar>
);
}

const darkTheme = createTheme({
palette: {
mode: 'dark',
primary: {
main: '#1976d2',
},
},
});

export default function EnableColorOnDarkAppBar() {
return (
<Stack spacing={2} sx={{ flexGrow: 1 }}>
<ThemeProvider theme={darkTheme}>
<AppBar position="static" color="primary" enableColorOnDark>
{appBarLabel('enableColorOnDark')}
</AppBar>
<AppBar position="static" color="primary">
{appBarLabel('default')}
</AppBar>
</ThemeProvider>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
function FacebookCircularProgress(props) {
return (
<Box sx={{ position: 'relative' }}>
<CircularProgress
variant="determinate"
sx={{
color: (theme) => theme.palette.grey[theme.palette.mode === 'light' ? 200 : 800],
}}
size={40}
thickness={4}
{...props}
value={100}
/>
<CircularProgress
variant="indeterminate"
disableShrink
sx={{
color: (theme) => (theme.palette.mode === 'light' ? '#1a90ff' : '#308fe8'),
animationDuration: '550ms',
position: 'absolute',
left: 0,
[`& .${circularProgressClasses.circle}`]: {
strokeLinecap: 'round',
},
}}
size={40}
thickness={4}
{...props}
/>
</Box>
);
}

<Paper
elevation={0}
sx={{
display: 'flex',
border: (theme) => `1px solid ${theme.palette.divider}`,
flexWrap: 'wrap',
}}
></Paper>;

<Divider
sx={{ border: (theme) => `1px solid ${theme.palette.mode === 'dark' ? '#fff' : '#000'}` }}
/>;

<Typography
component="span"
variant="subtitle1"
color="inherit"
sx={{
position: 'relative',
p: 4,
pt: 2,
pb: (theme) => `calc(${theme.spacing(1)} + 6px)`,
}}
>
{image.title}
<ImageMarked className="MuiImageMarked-root" />
</Typography>;

<Autocomplete
sx={{
display: 'inline-block',
'& input': {
width: 200,
bgcolor: 'background.paper',
color: (theme) => theme.palette.getContrastText(theme.palette.background.paper),
},
}}
id="custom-input-demo"
options={options}
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<input type="text" {...params.inputProps} />
</div>
)}
/>;

<Box
sx={{
position: 'relative',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: (theme) => theme.shadows[5],
p: 4,
}}
></Box>;

<Backdrop
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
open={open}
onClick={handleClose}
>
<CircularProgress color="inherit" />
</Backdrop>;
Loading

0 comments on commit 44934b2

Please sign in to comment.