@mui/x-codemod 6.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/codemod.js +80 -0
- package/package.json +51 -0
- package/util/propsToObject.js +54 -0
- package/util/readFile.js +16 -0
- package/util/renameClassKey.js +29 -0
- package/util/renameProps.js +19 -0
- package/v6.0.0/component-rename-prop/index.js +20 -0
- package/v6.0.0/localization-provider-rename-locale/index.js +20 -0
- package/v6.0.0/preset-safe/index.js +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @mui/x-codemod
|
|
2
|
+
|
|
3
|
+
> Codemod scripts for MUI X
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@mui/x-codemod)
|
|
6
|
+
[](https://www.npmjs.com/package/@mui/x-codemod)
|
|
7
|
+
|
|
8
|
+
This repository contains a collection of codemod scripts based for use with
|
|
9
|
+
[jscodeshift](https://github.com/facebook/jscodeshift) that help update MUI X APIs.
|
|
10
|
+
|
|
11
|
+
## Setup & run
|
|
12
|
+
|
|
13
|
+
<!-- #default-branch-switch -->
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx @mui/x-codemod <codemod> <paths...>
|
|
17
|
+
|
|
18
|
+
Applies a `@mui/x-codemod` to the specified paths
|
|
19
|
+
|
|
20
|
+
Positionals:
|
|
21
|
+
codemod The name of the codemod [string]
|
|
22
|
+
paths Paths forwarded to `jscodeshift` [string]
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--version Show version number [boolean]
|
|
26
|
+
--help Show help [boolean]
|
|
27
|
+
--parser which parser for jscodeshift to use.
|
|
28
|
+
[string] [default: 'tsx']
|
|
29
|
+
--jscodeshift Pass options directly to jscodeshift [array]
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
npx @mui/x-codemod v6.0.0/preset-safe src
|
|
33
|
+
npx @mui/x-codemod v6.0.0/component-rename-prop src --
|
|
34
|
+
--component=DataGrid --from=prop --to=newProp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `jscodeshift` options
|
|
38
|
+
|
|
39
|
+
To pass more options directly to jscodeshift, use `--jscodeshift=...`. For example:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
// single option
|
|
43
|
+
npx @mui/x-codemod --jscodeshift=--run-in-band
|
|
44
|
+
// multiple options
|
|
45
|
+
npx @mui/x-codemod --jscodeshift=--cpus=1 --jscodeshift=--print --jscodeshift=--dry --jscodeshift=--verbose=2
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
See all available options [here](https://github.com/facebook/jscodeshift#usage-cli).
|
|
49
|
+
|
|
50
|
+
### `Recast` Options
|
|
51
|
+
|
|
52
|
+
Options to [recast](https://github.com/benjamn/recast)'s printer can be provided
|
|
53
|
+
through jscodeshift's `printOptions` command line argument
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
npx @mui/x-codemod <transform> <path> --jscodeshift="--printOptions='{\"quote\":\"double\"}'"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Included scripts
|
|
60
|
+
|
|
61
|
+
### v6.0.0
|
|
62
|
+
|
|
63
|
+
#### 🚀 `preset-safe`
|
|
64
|
+
|
|
65
|
+
A combination of all important transformers for migrating v5 to v6. ⚠️ This codemod should be run only once.
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npx @mui/x-codemod v6.0.0/preset-safe <path|folder>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The list includes these transformers
|
|
72
|
+
|
|
73
|
+
- [`localization-provider-rename-locale`](#localization-provider-rename-locale)
|
|
74
|
+
|
|
75
|
+
#### `localization-provider-rename-locale`
|
|
76
|
+
|
|
77
|
+
Renames `locale` into `adapterLocale` (or `LocalizationProvider`)
|
|
78
|
+
|
|
79
|
+
```diff
|
|
80
|
+
<LocalizationProvider
|
|
81
|
+
dateAdapter={AdapterDayjs}
|
|
82
|
+
- locale="fr"
|
|
83
|
+
+ adapterLocale="fr"
|
|
84
|
+
>
|
|
85
|
+
{children}
|
|
86
|
+
</LocalizationProvider
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
npx @mui/x-codemod v6.0.0/localization-provider-rename-locale <path>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
You can find more details about this breaking change in [the migration guide](https://next.mui.com/x/migration/migration-pickers-v5/#rename-the-locale-prop-on-localizationprovider).
|
package/codemod.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
5
|
+
var _child_process = _interopRequireDefault(require("child_process"));
|
|
6
|
+
var _fs = require("fs");
|
|
7
|
+
var _path = _interopRequireDefault(require("path"));
|
|
8
|
+
var _yargs = _interopRequireDefault(require("yargs"));
|
|
9
|
+
const jscodeshiftPackage = require('jscodeshift/package.json');
|
|
10
|
+
const jscodeshiftDirectory = _path.default.dirname(require.resolve('jscodeshift'));
|
|
11
|
+
const jscodeshiftExecutable = _path.default.join(jscodeshiftDirectory, jscodeshiftPackage.bin.jscodeshift);
|
|
12
|
+
async function runTransform(transform, files, flags, codemodFlags) {
|
|
13
|
+
const transformerSrcPath = _path.default.resolve(__dirname, './src', transform);
|
|
14
|
+
const transformerBuildPath = _path.default.resolve(__dirname, transform);
|
|
15
|
+
let transformerPath;
|
|
16
|
+
try {
|
|
17
|
+
await _fs.promises.stat(transformerSrcPath);
|
|
18
|
+
transformerPath = transformerSrcPath;
|
|
19
|
+
} catch (srcPathError) {
|
|
20
|
+
try {
|
|
21
|
+
await _fs.promises.stat(transformerBuildPath);
|
|
22
|
+
transformerPath = transformerBuildPath;
|
|
23
|
+
} catch (buildPathError) {
|
|
24
|
+
if (buildPathError.code === 'ENOENT') {
|
|
25
|
+
throw new Error(`Transform '${transform}' not found. Check out ${_path.default.resolve(__dirname, './README.md for a list of available codemods.')}`);
|
|
26
|
+
}
|
|
27
|
+
throw buildPathError;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const args = [
|
|
31
|
+
// can't directly spawn `jscodeshiftExecutable` due to https://github.com/facebook/jscodeshift/issues/424
|
|
32
|
+
jscodeshiftExecutable, '--transform', transformerPath, ...codemodFlags, '--extensions', 'js,ts,jsx,tsx', '--parser', flags.parser || 'tsx', '--ignore-pattern', '**/node_modules/**', ...flags.jscodeshift];
|
|
33
|
+
args.push(...files);
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line no-console -- debug information
|
|
36
|
+
console.log(`Executing command: jscodeshift ${args.join(' ')}`);
|
|
37
|
+
const jscodeshiftProcess = _child_process.default.spawnSync('node', args, {
|
|
38
|
+
stdio: 'inherit'
|
|
39
|
+
});
|
|
40
|
+
if (jscodeshiftProcess.error) {
|
|
41
|
+
throw jscodeshiftProcess.error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function run(argv) {
|
|
45
|
+
const {
|
|
46
|
+
codemod,
|
|
47
|
+
paths,
|
|
48
|
+
_: other,
|
|
49
|
+
jscodeshift,
|
|
50
|
+
parser
|
|
51
|
+
} = argv;
|
|
52
|
+
return runTransform(codemod, paths.map(filePath => _path.default.resolve(filePath)), {
|
|
53
|
+
jscodeshift,
|
|
54
|
+
parser
|
|
55
|
+
}, other || []);
|
|
56
|
+
}
|
|
57
|
+
_yargs.default.command({
|
|
58
|
+
command: '$0 <codemod> <paths...>',
|
|
59
|
+
describe: 'Applies a `@mui/x-codemod` to the specified paths',
|
|
60
|
+
// @ts-expect-error
|
|
61
|
+
builder: command => {
|
|
62
|
+
return command.positional('codemod', {
|
|
63
|
+
description: 'The name of the codemod',
|
|
64
|
+
type: 'string'
|
|
65
|
+
}).positional('paths', {
|
|
66
|
+
array: true,
|
|
67
|
+
description: 'Paths forwarded to `jscodeshift`',
|
|
68
|
+
type: 'string'
|
|
69
|
+
}).option('parser', {
|
|
70
|
+
description: 'which parser for jscodeshift to use',
|
|
71
|
+
default: 'tsx',
|
|
72
|
+
type: 'string'
|
|
73
|
+
}).option('jscodeshift', {
|
|
74
|
+
description: '(Advanced) Pass options directly to jscodeshift',
|
|
75
|
+
default: [],
|
|
76
|
+
type: 'array'
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
handler: run
|
|
80
|
+
}).scriptName('npx @mui/x-codemod').example('$0 v6.0.0/localization-provider-rename-locale src', 'Run "localization-provider-rename-locale" codemod on "src" path').example('$0 v6.0.0/component-rename-prop src -- --component=DataGrid --from=prop --to=newProp', 'Run "component-rename-prop" codemod in "src" path on "DataGrid" component with custom "from" and "to" arguments').help().parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mui/x-codemod",
|
|
3
|
+
"version": "6.0.0-alpha.9",
|
|
4
|
+
"bin": "./codemod.js",
|
|
5
|
+
"private": false,
|
|
6
|
+
"author": "MUI Team",
|
|
7
|
+
"description": "Codemod scripts for MUI X.",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"react",
|
|
10
|
+
"react-component",
|
|
11
|
+
"mui",
|
|
12
|
+
"codemod",
|
|
13
|
+
"jscodeshift"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/x-codemod/**/*.test.ts'",
|
|
17
|
+
"typescript": "tsc -p tsconfig.json",
|
|
18
|
+
"prebuild": "rimraf build",
|
|
19
|
+
"copy-files": "cpy README.md build && cpy package.json build",
|
|
20
|
+
"build": "node ../../scripts/build.mjs node --ignore 'src/types.ts' && yarn copy-files"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/mui/mui-x.git",
|
|
25
|
+
"directory": "packages/x-codemod"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"homepage": "https://github.com/mui/mui-x/tree/next/packages/x-codemod",
|
|
29
|
+
"funding": {
|
|
30
|
+
"type": "opencollective",
|
|
31
|
+
"url": "https://opencollective.com/mui"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@babel/core": "^7.20.2",
|
|
35
|
+
"@babel/runtime": "^7.20.1",
|
|
36
|
+
"@babel/traverse": "^7.20.1",
|
|
37
|
+
"jscodeshift": "0.13.1",
|
|
38
|
+
"jscodeshift-add-imports": "^1.0.10",
|
|
39
|
+
"yargs": "^17.6.2"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/jscodeshift": "^0.11.5"
|
|
43
|
+
},
|
|
44
|
+
"sideEffects": false,
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=14.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = propsToObject;
|
|
7
|
+
function propsToObject({
|
|
8
|
+
j,
|
|
9
|
+
root,
|
|
10
|
+
componentName,
|
|
11
|
+
aliasName,
|
|
12
|
+
propName,
|
|
13
|
+
props
|
|
14
|
+
}) {
|
|
15
|
+
function buildObject(node, value) {
|
|
16
|
+
const shorthand = node.value.expression && node.value.expression.name === node.name.name;
|
|
17
|
+
const property = j.objectProperty(j.identifier(node.name.name), node.value.expression ? node.value.expression : node.value);
|
|
18
|
+
property.shorthand = shorthand;
|
|
19
|
+
value.push(property);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
const result = aliasName ? root.find(j.JSXElement, {
|
|
23
|
+
openingElement: {
|
|
24
|
+
name: {
|
|
25
|
+
property: {
|
|
26
|
+
name: componentName
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}) : root.findJSXElements(componentName);
|
|
31
|
+
return result.forEach(path => {
|
|
32
|
+
// @ts-expect-error
|
|
33
|
+
if (!aliasName || aliasName && path.node.openingElement.name.object.name === aliasName) {
|
|
34
|
+
let propValue = [];
|
|
35
|
+
const attributes = path.node.openingElement.attributes;
|
|
36
|
+
attributes?.forEach((node, index) => {
|
|
37
|
+
// Only transform whitelisted props
|
|
38
|
+
if (node.type === 'JSXAttribute' && props.includes(node.name.name)) {
|
|
39
|
+
propValue = buildObject(node, propValue);
|
|
40
|
+
delete attributes[index];
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
if (propValue.length > 0) {
|
|
44
|
+
const propNameAttr = attributes?.find(attr => attr.type === 'JSXAttribute' && attr.name.name === propName);
|
|
45
|
+
if (propNameAttr && propNameAttr.type === 'JSXAttribute') {
|
|
46
|
+
// @ts-expect-error
|
|
47
|
+
(propNameAttr.value.expression?.properties || []).push(...j.objectExpression(propValue).properties);
|
|
48
|
+
} else {
|
|
49
|
+
attributes?.push(j.jsxAttribute(j.jsxIdentifier(propName), j.jsxExpressionContainer(j.objectExpression(propValue))));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
package/util/readFile.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = readFile;
|
|
8
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
9
|
+
var _os = require("os");
|
|
10
|
+
function readFile(filePath) {
|
|
11
|
+
const fileContents = _fs.default.readFileSync(filePath, 'utf8').toString();
|
|
12
|
+
if (_os.EOL !== '\n') {
|
|
13
|
+
return fileContents.replace(/\n/g, _os.EOL);
|
|
14
|
+
}
|
|
15
|
+
return fileContents;
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = renameClassKey;
|
|
7
|
+
function renameClassKey({
|
|
8
|
+
root,
|
|
9
|
+
componentName,
|
|
10
|
+
classes,
|
|
11
|
+
printOptions
|
|
12
|
+
}) {
|
|
13
|
+
const source = root.findJSXElements(componentName).forEach(path => {
|
|
14
|
+
path.node.openingElement.attributes?.forEach(node => {
|
|
15
|
+
if (node.type === 'JSXAttribute' && node.name.name === 'classes') {
|
|
16
|
+
// @ts-expect-error
|
|
17
|
+
node.value?.expression?.properties?.forEach(subNode => {
|
|
18
|
+
if (Object.keys(classes).includes(subNode.key.name)) {
|
|
19
|
+
subNode.key.name = classes[subNode.key.name];
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}).toSource(printOptions);
|
|
25
|
+
return Object.entries(classes).reduce((result, [currentKey, newKey]) => {
|
|
26
|
+
const regex = new RegExp(`.Mui${componentName}-${currentKey}`, 'gm');
|
|
27
|
+
return result.replace(regex, `.Mui${componentName}-${newKey}`);
|
|
28
|
+
}, source);
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = renameProps;
|
|
7
|
+
function renameProps({
|
|
8
|
+
root,
|
|
9
|
+
componentName,
|
|
10
|
+
props
|
|
11
|
+
}) {
|
|
12
|
+
return root.findJSXElements(componentName).forEach(path => {
|
|
13
|
+
path.node.openingElement.attributes?.forEach(node => {
|
|
14
|
+
if (node.type === 'JSXAttribute' && Object.keys(props).includes(node.name.name)) {
|
|
15
|
+
node.name.name = props[node.name.name];
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = transformer;
|
|
8
|
+
var _renameProps = _interopRequireDefault(require("../../util/renameProps"));
|
|
9
|
+
function transformer(file, api, options) {
|
|
10
|
+
const j = api.jscodeshift;
|
|
11
|
+
const root = j(file.source);
|
|
12
|
+
const printOptions = options.printOptions;
|
|
13
|
+
return (0, _renameProps.default)({
|
|
14
|
+
root,
|
|
15
|
+
componentName: options.component,
|
|
16
|
+
props: {
|
|
17
|
+
[options.from]: options.to
|
|
18
|
+
}
|
|
19
|
+
}).toSource(printOptions);
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = transformer;
|
|
8
|
+
var _renameProps = _interopRequireDefault(require("../../util/renameProps"));
|
|
9
|
+
function transformer(file, api, options) {
|
|
10
|
+
const j = api.jscodeshift;
|
|
11
|
+
const root = j(file.source);
|
|
12
|
+
const printOptions = options.printOptions;
|
|
13
|
+
return (0, _renameProps.default)({
|
|
14
|
+
root,
|
|
15
|
+
componentName: 'LocalizationProvider',
|
|
16
|
+
props: {
|
|
17
|
+
locale: 'adapterLocale'
|
|
18
|
+
}
|
|
19
|
+
}).toSource(printOptions);
|
|
20
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = transformer;
|
|
8
|
+
var _localizationProviderRenameLocale = _interopRequireDefault(require("../localization-provider-rename-locale"));
|
|
9
|
+
function transformer(file, api, options) {
|
|
10
|
+
file.source = (0, _localizationProviderRenameLocale.default)(file, api, options);
|
|
11
|
+
return file.source;
|
|
12
|
+
}
|