Skip to content

Commit

Permalink
Merge branch 'master' into fix-footer-conteiner-size
Browse files Browse the repository at this point in the history
  • Loading branch information
cherniavskii committed Oct 11, 2024
2 parents 7cd1987 + ca0a847 commit ea13e10
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 166 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default function CoreV5WithCoreV4() {
return (
<iframe
title="codesandbox"
src="https://codesandbox.io/embed/mui-core-v5-with-mui-core-v4-1pmwj?hidenavigation=1&fontsize=14&view=preview"
src="https://codesandbox.io/embed/https-mui-com-x-migration-migration-data-grid-v4-24ltxx?hidenavigation=1&fontsize=14&view=preview"
style={{
width: '100%',
height: 520,
Expand Down
176 changes: 176 additions & 0 deletions packages/x-codemod/src/util/renameImports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import type {
ASTPath,
Collection,
ImportDeclaration,
ImportSpecifier,
JSCodeshift,
} from 'jscodeshift';

interface ImportConfig {
oldEndpoint?: string;
newEndpoint?: string;
skipRoot?: boolean;
importsMapping: Record<string, string>;
}

interface RenameImportsParameters {
j: JSCodeshift;
root: Collection<any>;
packageNames: string[];
imports: ImportConfig[];
}

const getPathStrFromPath = (path: ASTPath<ImportDeclaration> | ASTPath<ImportSpecifier>) => {
let cleanPath: ASTPath<ImportDeclaration>;
if (path.get('type').value === 'ImportDeclaration') {
cleanPath = path as ASTPath<ImportDeclaration>;
} else {
cleanPath = path.parentPath.parentPath as ASTPath<ImportDeclaration>;
}

return cleanPath.node.source.value?.toString() ?? '';
};

const getRelativeEndpointFromPathStr = (pathStr: string, packageNames: string[]) => {
return pathStr.replace(new RegExp(`^(${packageNames.join('|')})/`), '');
};

const getMatchingNestedImport = (
path: ASTPath<ImportSpecifier> | ASTPath<ImportDeclaration>,
parameters: RenameImportsParameters,
) => {
const pathStr = getPathStrFromPath(path);
const relativeEndpoint = getRelativeEndpointFromPathStr(pathStr, parameters.packageNames);
return parameters.imports.find((importConfig) => importConfig.oldEndpoint === relativeEndpoint);
};

const getMatchingRootImport = (
path: ASTPath<ImportSpecifier>,
parameters: RenameImportsParameters,
) => {
return parameters.imports.find((importConfig) => {
return (
!importConfig.skipRoot && importConfig.importsMapping.hasOwnProperty(path.node.imported.name)
);
});
};

export function renameImports(parameters: RenameImportsParameters) {
const { j, root } = parameters;

const renamedIdentifiersMap: Record<string, string> = {};

const importDeclarations = root
// Find all the import declarations (import { ... } from '...')
.find(j.ImportDeclaration);

// Rename the nested imports specifiers
// - import { A } from '@mui/x-date-pickers/A'
// + import { B } from '@mui/x-date-pickers/A'
const nestedImportRegExp = new RegExp(`^(${parameters.packageNames.join('|')})/(.*)$`);
importDeclarations
// Filter out the declarations that are not nested endpoints of the matching packages or that don't have any update to apply
.filter((path) => {
const pathStr = getPathStrFromPath(path);
if (!pathStr.match(nestedImportRegExp)) {
return false;
}

return !!getMatchingNestedImport(path, parameters);
})
// Find all the import specifiers (extract A in import { A } from '...')
.find(j.ImportSpecifier)
// Filter out the specifiers that don't need to be updated
.filter((path) => {
return getMatchingNestedImport(path, parameters)!.importsMapping.hasOwnProperty(
path.node.imported.name,
);
})
// Rename the import specifiers
.replaceWith((path) => {
const newName = getMatchingNestedImport(path, parameters)!.importsMapping[
path.node.imported.name
];

// If the import is alias, we keep the alias and don't rename the variable usage
const hasAlias = path.node.local?.name !== path.node.imported.name;
if (hasAlias) {
return j.importSpecifier(j.identifier(newName), j.identifier(path.node.local!.name));
}

renamedIdentifiersMap[path.node.imported.name] = newName;
return j.importSpecifier(j.identifier(newName));
});

// Rename the root imports specifiers
// - import { A } from '@mui/x-date-pickers'
// + import { B } from '@mui/x-date-pickers'
const rootImportRegExp = new RegExp(`^(${parameters.packageNames.join('|')})$`);
importDeclarations
// Filter out the declarations that are not root endpoint of the matching packages
.filter((path) => {
const pathStr = getPathStrFromPath(path);
return !!pathStr.match(rootImportRegExp);
})
.find(j.ImportSpecifier)
.filter((path) => {
return !!getMatchingRootImport(path, parameters);
})
// Rename the import specifiers
.replaceWith((path) => {
const newName = getMatchingRootImport(path, parameters)!.importsMapping[
path.node.imported.name
];

// If the import is alias, we keep the alias and don't rename the variable usage
const hasAlias = path.node.local?.name !== path.node.imported.name;
if (hasAlias) {
return j.importSpecifier(j.identifier(newName), j.identifier(path.node.local!.name));
}

renamedIdentifiersMap[path.node.imported.name] = newName;
return j.importSpecifier(j.identifier(newName));
});

// Rename the nested import declarations
// - import { B } from '@mui/x-date-pickers/A'
// + import { B } from '@mui/x-date-pickers/B'
importDeclarations
// Filter out the declarations that are not nested endpoints of the matching packages or that don't have any update to apply
.filter((path) => {
const pathStr = getPathStrFromPath(path);
if (!pathStr.match(nestedImportRegExp)) {
return false;
}

return !!getMatchingNestedImport(path, parameters)?.newEndpoint;
})
.replaceWith((path) => {
const pathStr = getPathStrFromPath(path);
const oldEndpoint = getRelativeEndpointFromPathStr(pathStr, parameters.packageNames);
const newEndpoint = getMatchingNestedImport(path, parameters)!.newEndpoint;
const newPathStr = pathStr.replace(oldEndpoint, newEndpoint!);

return j.importDeclaration(
// Copy over the existing import specifiers
path.node.specifiers,
// Replace the source with our new source
j.stringLiteral(newPathStr),
);
});

// Rename the import usage
// - <A />
// + <B />
root
.find(j.Identifier)
.filter((path) => {
return renamedIdentifiersMap.hasOwnProperty(path.node.name);
})
.replaceWith((path) => {
const newName = renamedIdentifiersMap[path.node.name];
return j.identifier(newName);
});

return root;
}
156 changes: 70 additions & 86 deletions packages/x-codemod/src/v6.0.0/pickers/view-components-rename/index.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,6 @@
import { ASTPath, ImportDeclaration } from 'jscodeshift';
import type { JsCodeShiftAPI, JsCodeShiftFileInfo } from '../../../types';
import { renameImports } from '../../../util/renameImports';

const SUB_PACKAGES = {
CalendarPicker: 'DateCalendar',
CalendarPickerSkeleton: 'DayCalendarSkeleton',
MonthPicker: 'MonthCalendar',
YearPicker: 'YearCalendar',
ClockPicker: 'TimeClock',
};

const VARIABLES = {
// Date Calendar
CalendarPicker: 'DateCalendar',
CalendarPickerProps: 'DateCalendarProps',
CalendarPickerSlotsComponent: 'DateCalendarSlotsComponent',
CalendarPickerSlotsComponentsProps: 'DateCalendarSlotsComponentsProps',
CalendarPickerClasses: 'DateCalendarClasses',
CalendarPickerClassKey: 'DateCalendarClassKey',
calendarPickerClasses: 'dateCalendarClasses',
getCalendarPickerUtilityClass: 'getDateCalendarUtilityClass',

// Month Calendar
MonthPicker: 'MonthCalendar',
MonthPickerProps: 'MonthCalendarProps',
MonthPickerClasses: 'MonthCalendarClasses',
MonthPickerClassKey: 'MonthCalendarClassKey',
monthPickerClasses: 'monthCalendarClasses',
getMonthPickerUtilityClass: 'getMonthCalendarUtilityClass',

YearPicker: 'YearCalendar',
YearPickerProps: 'YearCalendarProps',
YearPickerClasses: 'YearCalendarClasses',
YearPickerClassKey: 'YearCalendarClassKey',
yearPickerClasses: 'yearCalendarClasses',
getYearPickerUtilityClass: 'getYearCalendarUtilityClass',

ClockPicker: 'TimeClock',
ClockPickerProps: 'TimeClockProps',
ClockPickerClasses: 'TimeClockClasses',
ClockPickerClassKey: 'TimeClockClassKey',
clockPickerClasses: 'timeClockClasses',
getClockPickerUtilityClass: 'getTimeClockUtilityClass',

CalendarPickerSkeleton: 'DayCalendarSkeleton',
CalendarPickerSkeletonProps: 'DayCalendarSkeletonProps',
CalendarPickerSkeletonClasses: 'DayCalendarSkeletonClasses',
CalendarPickerSkeletonClassKey: 'DayCalendarSkeletonClassKey',
calendarPickerSkeletonClasses: 'dayCalendarSkeletonClasses',
getCalendarPickerSkeletonUtilityClass: 'getDayCalendarSkeletonUtilityClass',
};

const PACKAGE_REGEXP = /@mui\/x-date-pickers(-pro|)(\/(.*)|)/;

const matchImport = (path: ASTPath<ImportDeclaration>) =>
(path.node.source.value?.toString() ?? '').match(PACKAGE_REGEXP);
export default function transformer(file: JsCodeShiftFileInfo, api: JsCodeShiftAPI, options: any) {
const j = api.jscodeshift;
const root = j(file.source);
Expand All @@ -63,38 +10,75 @@ export default function transformer(file: JsCodeShiftFileInfo, api: JsCodeShiftA
trailingComma: true,
};

const matchingImports = root.find(j.ImportDeclaration).filter((path) => !!matchImport(path));

// Rename the import specifiers
// - import { MonthPicker } from '@mui/x-date-pickers/MonthPicker'
// + import { MonthCalendar } from '@mui/x-date-pickers/MonthPicker'
matchingImports
.find(j.ImportSpecifier)
.filter((path) => VARIABLES.hasOwnProperty(path.node.imported.name))
.replaceWith((path) => j.importSpecifier(j.identifier(VARIABLES[path.node.imported.name])));

// Rename the nested import declarations
// - import {} from '@mui/x-date-pickers/MonthPicker'
// + import {} from '@mui/x-date-pickers/MonthCalendar'
matchingImports
.filter((path) => SUB_PACKAGES.hasOwnProperty(matchImport(path)?.[3] ?? ''))
.replaceWith((path) => {
const subPackage = matchImport(path)![3];
const importPath = path.node.source.value?.toString() ?? '';

return j.importDeclaration(
path.node.specifiers, // copy over the existing import specifiers
j.stringLiteral(importPath.replace(subPackage, SUB_PACKAGES[subPackage])), // Replace the source with our new source
);
});

// Rename the import usage
// - <CalendarPicker />
// + <DateCalendar />
root
.find(j.Identifier)
.filter((path) => VARIABLES.hasOwnProperty(path.node.name))
.replaceWith((path) => j.identifier(VARIABLES[path.node.name]));
renameImports({
j,
root,
packageNames: ['@mui/x-date-pickers', '@mui/x-date-pickers-pro'],
imports: [
{
oldEndpoint: 'CalendarPicker',
newEndpoint: 'DateCalendar',
importsMapping: {
CalendarPicker: 'DateCalendar',
CalendarPickerProps: 'DateCalendarProps',
CalendarPickerSlotsComponent: 'DateCalendarSlotsComponent',
CalendarPickerSlotsComponentsProps: 'DateCalendarSlotsComponentsProps',
CalendarPickerClasses: 'DateCalendarClasses',
CalendarPickerClassKey: 'DateCalendarClassKey',
calendarPickerClasses: 'dateCalendarClasses',
getCalendarPickerUtilityClass: 'getDateCalendarUtilityClass',
},
},
{
oldEndpoint: 'MonthPicker',
newEndpoint: 'MonthCalendar',
importsMapping: {
MonthPicker: 'MonthCalendar',
MonthPickerProps: 'MonthCalendarProps',
MonthPickerClasses: 'MonthCalendarClasses',
MonthPickerClassKey: 'MonthCalendarClassKey',
monthPickerClasses: 'monthCalendarClasses',
getMonthPickerUtilityClass: 'getMonthCalendarUtilityClass',
},
},
{
oldEndpoint: 'YearPicker',
newEndpoint: 'YearCalendar',
importsMapping: {
YearPicker: 'YearCalendar',
YearPickerProps: 'YearCalendarProps',
YearPickerClasses: 'YearCalendarClasses',
YearPickerClassKey: 'YearCalendarClassKey',
yearPickerClasses: 'yearCalendarClasses',
getYearPickerUtilityClass: 'getYearCalendarUtilityClass',
},
},
{
oldEndpoint: 'ClockPicker',
newEndpoint: 'TimeClock',
importsMapping: {
ClockPicker: 'TimeClock',
ClockPickerProps: 'TimeClockProps',
ClockPickerClasses: 'TimeClockClasses',
ClockPickerClassKey: 'TimeClockClassKey',
clockPickerClasses: 'timeClockClasses',
getClockPickerUtilityClass: 'getTimeClockUtilityClass',
},
},
{
oldEndpoint: 'CalendarPickerSkeleton',
newEndpoint: 'DayCalendarSkeleton',
importsMapping: {
CalendarPickerSkeleton: 'DayCalendarSkeleton',
CalendarPickerSkeletonProps: 'DayCalendarSkeletonProps',
CalendarPickerSkeletonClasses: 'DayCalendarSkeletonClasses',
CalendarPickerSkeletonClassKey: 'DayCalendarSkeletonClassKey',
calendarPickerSkeletonClasses: 'dayCalendarSkeletonClasses',
getCalendarPickerSkeletonUtilityClass: 'getDayCalendarSkeletonUtilityClass',
},
},
],
});

return root.toSource(printOptions);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('v6.0.0/pickers', () => {
const actualPath = `./actual-${testFile}.spec.tsx`;
const expectedPath = `./expected-${testFile}.spec.tsx`;

describe(`Community package (${testFile.replace(/-/g, ' ')})`, () => {
describe(`Package (${testFile.replace(/-/g, ' ')})`, () => {
it('transforms imports as needed', () => {
const actual = transform(
{ source: read(actualPath) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TreeItem } from '@mui/x-tree-view/TreeItem';
function App() {
getTreeViewUtilityClass('root');

// prettier-ignore
return (
<TreeView>
<TreeItem nodeId="1" label="Item 1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ import {
SimpleTreeViewClassKey,
simpleTreeViewClasses,
getSimpleTreeViewUtilityClass,
} from '@mui/x-tree-view/TreeView';
} from '@mui/x-tree-view/SimpleTreeView';
import { TreeItem } from '@mui/x-tree-view/TreeItem';

function App() {
getSimpleTreeViewUtilityClass('root');

// prettier-ignore
return (
<SimpleTreeView>
(<SimpleTreeView>
<TreeItem nodeId="1" label="Item 1" />
</SimpleTreeView>
</SimpleTreeView>)
);
}
Loading

0 comments on commit ea13e10

Please sign in to comment.