From 6b824804346727c7e5c7069890fab0670ff51865 Mon Sep 17 00:00:00 2001 From: saurabhdaware Date: Mon, 2 Dec 2024 10:48:58 +0530 Subject: [PATCH] feat: add codemod --- .../__tests__/migrate-motion-tokens.test.ts | 130 ++++++++++++++++++ .../transformers/index.ts | 1 + .../transformers/migrate-motion.ts | 20 +++ .../transformers/motionTokenMapping.json | 11 ++ 4 files changed, 162 insertions(+) create mode 100644 packages/blade/codemods/migrate-motion-tokens/transformers/__tests__/migrate-motion-tokens.test.ts create mode 100644 packages/blade/codemods/migrate-motion-tokens/transformers/index.ts create mode 100644 packages/blade/codemods/migrate-motion-tokens/transformers/migrate-motion.ts create mode 100644 packages/blade/codemods/migrate-motion-tokens/transformers/motionTokenMapping.json diff --git a/packages/blade/codemods/migrate-motion-tokens/transformers/__tests__/migrate-motion-tokens.test.ts b/packages/blade/codemods/migrate-motion-tokens/transformers/__tests__/migrate-motion-tokens.test.ts new file mode 100644 index 00000000000..f340b31d418 --- /dev/null +++ b/packages/blade/codemods/migrate-motion-tokens/transformers/__tests__/migrate-motion-tokens.test.ts @@ -0,0 +1,130 @@ +import { applyTransform } from '@hypermod/utils'; +import transformer from '..'; + +it('should update token for dashboard sidebar example', async () => { + const result = await applyTransform( + transformer, + ` + export const SidebarContainer = styled.div( + ({ theme, isRTUXHomepage, isVisible, isMobile }) => \` + display: flex; + flex-direction: column; + position: fixed; + top: 0; + bottom: 0; + background-color: \${ + isRTUXHomepage + ? isMobile + ? theme.colors.surface.background.cloud.subtle + : 'transparent' + : '#2e3345' + }; + transform: translate(-100%,0); + transition: transform \${makeMotionTime(theme.motion.delay.short)} \${ + theme.motion.easing.standard.effective + }; + \`); + `, + { parser: 'tsx' }, + ); + + expect(result).toMatchInlineSnapshot(` + "export const SidebarContainer = styled.div( + ({ theme, isRTUXHomepage, isVisible, isMobile }) => \` + display: flex; + flex-direction: column; + position: fixed; + top: 0; + bottom: 0; + background-color: \${ + isRTUXHomepage + ? isMobile + ? theme.colors.surface.background.cloud.subtle + : 'transparent' + : '#2e3345' + }; + transform: translate(-100%,0); + transition: transform \${makeMotionTime(theme.motion.delay.short)} \${ + theme.motion.easing.standard + }; + \`);" + `); +}); + +it('should update token when used as prop', async () => { + const result = await applyTransform( + transformer, + ` + function App() { + const { theme } = useTheme(); + + return + } + `, + { parser: 'tsx' }, + ); + + expect(result).toMatchInlineSnapshot(` + "function App() { + const { theme } = useTheme(); + + return + }" + `); +}); + +it('should update token as used in X payroll', async () => { + const result = await applyTransform( + transformer, + ` + export const AnimatedContainer = styled.div<{ delay?: number }>(({ theme, delay = 0 }) => { + return css\` + animation: \${entry} \${makeMotionTime(theme.motion.duration['2xgentle'])} + \${theme.motion.easing.entrance.revealing} forwards; + animation-delay: \${delay}ms; + opacity: 0; + \`; + }); + `, + { parser: 'tsx' }, + ); + + expect(result).toMatchInlineSnapshot(` + "export const AnimatedContainer = styled.div<{ delay?: number }>(({ theme, delay = 0 }) => { + return css\` + animation: \${entry} \${makeMotionTime(theme.motion.duration['2xgentle'])} + \${theme.motion.easing.entrance} forwards; + animation-delay: \${delay}ms; + opacity: 0; + \`; + });" + `); +}); + +it('should update token when variable name is not "theme"', async () => { + const result = await applyTransform( + transformer, + ` + export const AnimatedContainer = styled.div<{ delay?: number }>(({ theme, delay = 0 }) => { + return css\` + animation: \${entry} \${makeMotionTime(paymentTheme.motion.duration['2xgentle'])} + \${paymentTheme.motion.easing.exit.effective} forwards; + animation-delay: \${delay}ms; + opacity: 0; + \`; + }); + `, + { parser: 'tsx' }, + ); + + expect(result).toMatchInlineSnapshot(` + "export const AnimatedContainer = styled.div<{ delay?: number }>(({ theme, delay = 0 }) => { + return css\` + animation: \${entry} \${makeMotionTime(paymentTheme.motion.duration['2xgentle'])} + \${paymentTheme.motion.easing.exit} forwards; + animation-delay: \${delay}ms; + opacity: 0; + \`; + });" + `); +}); diff --git a/packages/blade/codemods/migrate-motion-tokens/transformers/index.ts b/packages/blade/codemods/migrate-motion-tokens/transformers/index.ts new file mode 100644 index 00000000000..9b1c9ad219d --- /dev/null +++ b/packages/blade/codemods/migrate-motion-tokens/transformers/index.ts @@ -0,0 +1 @@ +export { default } from './migrate-motion'; diff --git a/packages/blade/codemods/migrate-motion-tokens/transformers/migrate-motion.ts b/packages/blade/codemods/migrate-motion-tokens/transformers/migrate-motion.ts new file mode 100644 index 00000000000..f5af2c98792 --- /dev/null +++ b/packages/blade/codemods/migrate-motion-tokens/transformers/migrate-motion.ts @@ -0,0 +1,20 @@ +import type { FileInfo } from 'jscodeshift'; +import * as tokenMapping from './motionTokenMapping.json'; + +export default function transformer(file: FileInfo) { + // Fairly simple usecases of motion tokens in razorpay files so this works. + // .replace has also worked well during rebranding + const newSource = file.source.replace(/motion\.easing\.[\w\.]+/g, (matchingToken) => { + const match = Object.entries(tokenMapping).find( + ([oldToken, _newToken]) => oldToken === matchingToken, + ); + + if (match) { + return match[1]; + } + + return matchingToken; + }); + + return newSource; +} diff --git a/packages/blade/codemods/migrate-motion-tokens/transformers/motionTokenMapping.json b/packages/blade/codemods/migrate-motion-tokens/transformers/motionTokenMapping.json new file mode 100644 index 00000000000..4dfa25cb259 --- /dev/null +++ b/packages/blade/codemods/migrate-motion-tokens/transformers/motionTokenMapping.json @@ -0,0 +1,11 @@ +{ + "motion.easing.entrance.effective": "motion.easing.entrance", + "motion.easing.standard.effective": "motion.easing.standard", + "motion.easing.exit.effective": "motion.easing.exit", + "motion.easing.entrance.revealing": "motion.easing.entrance", + "motion.easing.standard.revealing": "motion.easing.emphasized", + "motion.easing.exit.revealing": "motion.easing.exit", + "motion.easing.entrance.attentive": "motion.easing.overshoot", + "motion.easing.exit.attentive": "motion.easing.exit", + "motion.easing.standard.wary": "motion.easing.shake" +}