@availity/mui-codemod 0.1.0-alpha.0
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/CHANGELOG.md +10 -0
- package/README.md +27 -0
- package/jest.config.js +7 -0
- package/jsconfig.json +5 -0
- package/package.json +47 -0
- package/project.json +26 -0
- package/src/codemod.js +194 -0
- package/src/lib/v1.0.0/grid-v2-props/grid-v2-props.js +217 -0
- package/src/lib/v1.0.0/grid-v2-props/grid-v2-props.test.js +23 -0
- package/src/lib/v1.0.0/grid-v2-props/test-cases/actual.js +36 -0
- package/src/lib/v1.0.0/grid-v2-props/test-cases/custom-breakpoints.actual.js +9 -0
- package/src/lib/v1.0.0/grid-v2-props/test-cases/custom-breakpoints.expected.js +19 -0
- package/src/lib/v1.0.0/grid-v2-props/test-cases/expected.js +69 -0
- package/src/lib/v1.0.0/system-props/removeSystemProps.js +300 -0
- package/src/lib/v1.0.0/system-props/removeSystemProps.test.js +34 -0
- package/src/lib/v1.0.0/system-props/test-cases/system-props.actual.js +47 -0
- package/src/lib/v1.0.0/system-props/test-cases/system-props.expected.js +93 -0
- package/src/testUtils/index.js +49 -0
- package/src/utils.js +117 -0
- package/tsconfig.spec.json +10 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
|
+
|
|
5
|
+
## 0.1.0-alpha.0 (2025-02-24)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **mui-codemod:** add MUI v6 codemods for element users ([3be1a1b](https://github.com/Availity/element/commit/3be1a1ba2dab07968d26361bf4965b96fae682b5))
|
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @availity/mui-codemod
|
|
2
|
+
|
|
3
|
+
> Availity MUI v1 Codemods to be used when migrating from @availity/element v0 to v1.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@availity/mui-codemod)
|
|
6
|
+
[](https://www.npmjs.com/package/@availity/mui-codemod)
|
|
7
|
+
[](https://github.com/Availity/element/blob/main/packages/mui-codemod/package.json)
|
|
8
|
+
|
|
9
|
+
## Documentation
|
|
10
|
+
|
|
11
|
+
This package extends the MUI v6 Codemods: [MUI Codemod Docs](https://mui.com/material-ui/migration/upgrade-to-v6/)
|
|
12
|
+
|
|
13
|
+
Availity standards for design and usage can be found in the [Availity Design Guide](https://zeroheight.com/2e36e50c7)
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Migrate Grid props
|
|
18
|
+
|
|
19
|
+
`npx @availity/mui-codemod@latest v1.0.0/grid-v2-props <path/to/folder>`
|
|
20
|
+
|
|
21
|
+
### Migrate sx props
|
|
22
|
+
|
|
23
|
+
`npx @availity/mui-codemod@latest v1.0.0/sx-props <path/to/folder>`
|
|
24
|
+
|
|
25
|
+
### Migrate system props
|
|
26
|
+
|
|
27
|
+
`npx @availity/mui-codemod@latest v1.0.0/system-props <path/to/folder>`
|
package/jest.config.js
ADDED
package/jsconfig.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@availity/mui-codemod",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "Availity MUI v1 Codemods - part of the @availity/element design system",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"typescript",
|
|
8
|
+
"availity",
|
|
9
|
+
"mui"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://availity.github.io/element/?path=/docs/components-codemod-introduction--docs",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Availity/element/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/Availity/element.git",
|
|
18
|
+
"directory": "packages/codemod"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Availity Developers <AVOSS@availity.com>",
|
|
22
|
+
"bin": "./src/codemod.js",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup src/codemod.js --format esm,cjs --dts",
|
|
28
|
+
"dev": "tsup src/codemod.js --format esm,cjs --watch --dts",
|
|
29
|
+
"clean": "rm -rf dist",
|
|
30
|
+
"clean:nm": "rm -rf node_modules",
|
|
31
|
+
"publish": "yarn npm publish --tolerate-republish --access public",
|
|
32
|
+
"publish:canary": "yarn npm publish --access public --tag canary"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"tsup": "^8.3.6",
|
|
36
|
+
"typescript": "^5.4.5"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@types/jscodeshift": "^0.12.0",
|
|
43
|
+
"jscodeshift": "^17.1.2",
|
|
44
|
+
"postcss-cli": "^11.0.0",
|
|
45
|
+
"yargs": "^17.7.2"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mui-codemod",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/codemod/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"targets": {
|
|
8
|
+
"test": {
|
|
9
|
+
"executor": "@nx/jest:jest",
|
|
10
|
+
"outputs": ["{workspaceRoot}/coverage/codemod"],
|
|
11
|
+
"options": {
|
|
12
|
+
"jestConfig": "packages/codemod/jest.config.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"version": {
|
|
16
|
+
"executor": "@jscutlery/semver:version",
|
|
17
|
+
"options": {
|
|
18
|
+
"preset": "conventional",
|
|
19
|
+
"commitMessageFormat": "chore({projectName}): release version ${version} [skip ci]",
|
|
20
|
+
"tagPrefix": "@availity/{projectName}@",
|
|
21
|
+
"trackDeps": true,
|
|
22
|
+
"skipCommitTypes": ["docs"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/codemod.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const childProcess = require('child_process');
|
|
4
|
+
const { promises: fs } = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const yargs = require('yargs');
|
|
7
|
+
const jscodeshiftPackage = require('jscodeshift/package.json');
|
|
8
|
+
const postcssCliPackage = require('postcss-cli/package.json');
|
|
9
|
+
|
|
10
|
+
const jscodeshiftDirectory = path.dirname(require.resolve('jscodeshift'));
|
|
11
|
+
const jscodeshiftExecutable = path.join(jscodeshiftDirectory, jscodeshiftPackage.bin.jscodeshift);
|
|
12
|
+
|
|
13
|
+
const postcssCliDirectory = path.dirname(require.resolve('postcss-cli'));
|
|
14
|
+
const postcssExecutable = path.join(postcssCliDirectory, postcssCliPackage.bin.postcss);
|
|
15
|
+
|
|
16
|
+
async function runJscodeshiftTransform(transform, files, flags, codemodFlags) {
|
|
17
|
+
const paths = [
|
|
18
|
+
path.resolve(__dirname, './src', `${transform}/index.js`),
|
|
19
|
+
path.resolve(__dirname, './src', `${transform}.js`),
|
|
20
|
+
path.resolve(__dirname, './node', `${transform}/index.js`),
|
|
21
|
+
path.resolve(__dirname, './node', `${transform}.js`),
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
let transformerPath;
|
|
25
|
+
let error;
|
|
26
|
+
for (const item of paths) {
|
|
27
|
+
try {
|
|
28
|
+
await fs.stat(item);
|
|
29
|
+
error = undefined;
|
|
30
|
+
transformerPath = item;
|
|
31
|
+
break;
|
|
32
|
+
} catch (srcPathError) {
|
|
33
|
+
error = srcPathError;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (error) {
|
|
39
|
+
if (error?.code === 'ENOENT') {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Transform '${transform}' not found. Check out ${path.resolve(__dirname, './README.md for a list of available codemods.')}`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const args = [
|
|
48
|
+
jscodeshiftExecutable,
|
|
49
|
+
'--transform',
|
|
50
|
+
transformerPath,
|
|
51
|
+
...codemodFlags,
|
|
52
|
+
'--extensions',
|
|
53
|
+
'js,ts,jsx,tsx,json',
|
|
54
|
+
'--parser',
|
|
55
|
+
flags.parser || 'tsx',
|
|
56
|
+
'--ignore-pattern',
|
|
57
|
+
'**/node_modules/**',
|
|
58
|
+
'--ignore-pattern',
|
|
59
|
+
'**/*.css'
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
if (flags.dry) {
|
|
63
|
+
args.push('--dry');
|
|
64
|
+
}
|
|
65
|
+
if (flags.print) {
|
|
66
|
+
args.push('--print');
|
|
67
|
+
}
|
|
68
|
+
if (flags.jscodeshift) {
|
|
69
|
+
args.push(flags.jscodeshift);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
args.push(...files);
|
|
73
|
+
|
|
74
|
+
console.log(`Executing command: jscodeshift ${args.join(' ')}`);
|
|
75
|
+
const jscodeshiftProcess = childProcess.spawnSync('node', args, { stdio: 'inherit' });
|
|
76
|
+
|
|
77
|
+
if (jscodeshiftProcess.error) {
|
|
78
|
+
throw jscodeshiftProcess.error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const parseCssFilePaths = async (files) => {
|
|
83
|
+
const cssFiles = await Promise.all(files.map(async (filePath) => {
|
|
84
|
+
const stat = await fs.stat(filePath);
|
|
85
|
+
if (stat.isDirectory()) {
|
|
86
|
+
return `${filePath}/**/*.css`;
|
|
87
|
+
}
|
|
88
|
+
if (filePath.endsWith('.css')) {
|
|
89
|
+
return filePath;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return null;
|
|
93
|
+
}),);
|
|
94
|
+
|
|
95
|
+
return cssFiles.filter(Boolean);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function runPostcssTransform(transform, files) {
|
|
99
|
+
const paths = [
|
|
100
|
+
path.resolve(__dirname, './src', `${transform}/postcss.config.js`),
|
|
101
|
+
path.resolve(__dirname, './node', `${transform}/postcss.config.js`),
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
let configPath;
|
|
105
|
+
let error;
|
|
106
|
+
for (const item of paths) {
|
|
107
|
+
try {
|
|
108
|
+
await fs.stat(item);
|
|
109
|
+
error = undefined;
|
|
110
|
+
configPath = item;
|
|
111
|
+
break;
|
|
112
|
+
} catch (srcPathError) {
|
|
113
|
+
error = srcPathError;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (error) {
|
|
119
|
+
if (error?.code !== 'ENOENT') {
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
const cssPaths = await parseCssFilePaths(files);
|
|
124
|
+
|
|
125
|
+
if (cssPaths.length > 0) {
|
|
126
|
+
const args = [
|
|
127
|
+
postcssExecutable,
|
|
128
|
+
...cssPaths,
|
|
129
|
+
'--config',
|
|
130
|
+
configPath,
|
|
131
|
+
'--replace',
|
|
132
|
+
'--verbose',
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
console.log(`Executing command: postcss ${args.join(' ')}`);
|
|
136
|
+
const postCssProcess = childProcess.spawnSync('node', args, { stdio: 'inherit' });
|
|
137
|
+
|
|
138
|
+
if (postCssProcess.error) {
|
|
139
|
+
throw postCssProcess.error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function run(argv) {
|
|
146
|
+
const { codemod, paths, ...flags } = argv;
|
|
147
|
+
const files = paths.map((filePath) => path.resolve(filePath));
|
|
148
|
+
|
|
149
|
+
runJscodeshiftTransform(codemod, files, flags, argv._);
|
|
150
|
+
runPostcssTransform(codemod, files);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
yargs.command({
|
|
154
|
+
command: '$0 <codemod> <paths...>',
|
|
155
|
+
describe: 'Applies a `@mui/codemod` to the specified paths',
|
|
156
|
+
builder: (command) => {
|
|
157
|
+
return command
|
|
158
|
+
.positional('codemod', {
|
|
159
|
+
description: 'The name of the codemod',
|
|
160
|
+
type: 'string'
|
|
161
|
+
})
|
|
162
|
+
.positional('paths', {
|
|
163
|
+
array: true,
|
|
164
|
+
description: 'Paths forwarded to `jscodeshift`',
|
|
165
|
+
type: 'string',
|
|
166
|
+
})
|
|
167
|
+
.option('dry', {
|
|
168
|
+
description: 'dry run (no changes are made to files)',
|
|
169
|
+
default: false,
|
|
170
|
+
type: 'boolean'
|
|
171
|
+
})
|
|
172
|
+
.option('parser', {
|
|
173
|
+
description: 'which parser for jscodeshift to use',
|
|
174
|
+
default: 'tsx',
|
|
175
|
+
type: 'string'
|
|
176
|
+
})
|
|
177
|
+
.option('print', {
|
|
178
|
+
description: 'print transformed files to stdout, useful for development',
|
|
179
|
+
default: false,
|
|
180
|
+
type: 'boolean'
|
|
181
|
+
})
|
|
182
|
+
.option('jscodeshift', {
|
|
183
|
+
description: '(Advanced) Pass options directly to jscodeshift',
|
|
184
|
+
default: false,
|
|
185
|
+
type: 'string'
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
handler: run,
|
|
189
|
+
})
|
|
190
|
+
.scriptName('npx @availity/mui-codemod')
|
|
191
|
+
.example('$0 v4.0.0/theme-spacing-api src')
|
|
192
|
+
.example('$0 v5.0.0/component-rename-prop src -- --component=Grid --from=prop --to=newProp')
|
|
193
|
+
.help()
|
|
194
|
+
.parse();
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
const possibleDefaultImports = ['@availity/element', '@availity/mui-layout'];
|
|
2
|
+
const possibleNamedImports = {
|
|
3
|
+
'@availity/element': 'Grid',
|
|
4
|
+
'@availity/mui-layout': 'Grid',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const defaultBreakpoints = ['xs', 'sm', 'md', 'lg', 'xl'];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('jscodeshift').FileInfo} file
|
|
11
|
+
* @param {import('jscodeshift').API} api
|
|
12
|
+
*/
|
|
13
|
+
export default function gridV2Props(file, api, options) {
|
|
14
|
+
if (file.path?.endsWith('.json') || file.path?.endsWith('.d.ts')) {
|
|
15
|
+
return file.source;
|
|
16
|
+
}
|
|
17
|
+
const j = api.jscodeshift;
|
|
18
|
+
const root = j(file.source);
|
|
19
|
+
const breakpoints = options.muiBreakpoints?.split(',') || defaultBreakpoints;
|
|
20
|
+
const printOptions = options.printOptions;
|
|
21
|
+
|
|
22
|
+
const gridLocalNames = [];
|
|
23
|
+
|
|
24
|
+
root
|
|
25
|
+
.find(j.ImportDeclaration, (decl) => possibleDefaultImports.includes(decl.source.value))
|
|
26
|
+
.forEach((decl) => {
|
|
27
|
+
decl.node.specifiers.forEach((spec) => {
|
|
28
|
+
if (spec.type === 'ImportDefaultSpecifier') {
|
|
29
|
+
gridLocalNames.push(spec.local.name);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
root
|
|
35
|
+
.find(j.ImportDeclaration, (decl) =>
|
|
36
|
+
Object.keys(possibleNamedImports).includes(decl.source.value),
|
|
37
|
+
)
|
|
38
|
+
.forEach((decl) => {
|
|
39
|
+
decl.node.specifiers.forEach((spec) => {
|
|
40
|
+
if (spec.type === 'ImportSpecifier') {
|
|
41
|
+
if (possibleNamedImports[decl.node.source.value] === spec.imported.name) {
|
|
42
|
+
gridLocalNames.push(spec.local.name);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
root
|
|
49
|
+
.find(j.JSXElement, {
|
|
50
|
+
openingElement: {
|
|
51
|
+
name: {
|
|
52
|
+
name: (name) => gridLocalNames.includes(name),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
.forEach((el) => {
|
|
57
|
+
const size = j.objectExpression([]);
|
|
58
|
+
|
|
59
|
+
const spreadProps = [];
|
|
60
|
+
const attributesToPrune = [];
|
|
61
|
+
|
|
62
|
+
el.node.openingElement.attributes.forEach((attr) => {
|
|
63
|
+
if (attr.type === 'JSXSpreadAttribute') {
|
|
64
|
+
spreadProps.push(attr);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const breakpointNodes = j(el)
|
|
69
|
+
.find(j.JSXAttribute)
|
|
70
|
+
.filter(
|
|
71
|
+
(path) =>
|
|
72
|
+
path.parent.parent.node === el.node && breakpoints.includes(path.node.name.name),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
breakpointNodes.nodes().forEach((node) => {
|
|
76
|
+
const breakpoint = node.name.name;
|
|
77
|
+
const nodeValue = node.value;
|
|
78
|
+
let value;
|
|
79
|
+
|
|
80
|
+
if (nodeValue === null) {
|
|
81
|
+
value = j.stringLiteral('grow');
|
|
82
|
+
} else if (nodeValue.type === 'JSXExpressionContainer') {
|
|
83
|
+
if (nodeValue.expression.value === true) {
|
|
84
|
+
value = j.stringLiteral('grow');
|
|
85
|
+
} else {
|
|
86
|
+
value = nodeValue.expression;
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
value = nodeValue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
size.properties.push(j.property('init', j.identifier(breakpoint), value));
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
spreadProps.forEach((spreadProp) => {
|
|
96
|
+
const spreadPropArgument = spreadProp.argument;
|
|
97
|
+
if (spreadPropArgument.type === 'ObjectExpression') {
|
|
98
|
+
const propertiesToPrune = [];
|
|
99
|
+
spreadPropArgument.properties.forEach((property) => {
|
|
100
|
+
if (breakpoints.includes(property.key.name)) {
|
|
101
|
+
size.properties.push(j.property('init', property.key, property.value));
|
|
102
|
+
propertiesToPrune.push(property.key.name);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
spreadPropArgument.properties = spreadPropArgument.properties.filter(
|
|
106
|
+
(prop) => !propertiesToPrune.includes(prop.key.name),
|
|
107
|
+
);
|
|
108
|
+
if (spreadPropArgument.properties.length === 0) {
|
|
109
|
+
attributesToPrune.push(spreadProp);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (size.properties.length) {
|
|
115
|
+
let sizePropValue = size;
|
|
116
|
+
if (size.properties.length === 1 && size.properties[0].key.name === 'xs') {
|
|
117
|
+
sizePropValue = size.properties[0].value;
|
|
118
|
+
}
|
|
119
|
+
if (sizePropValue.type !== 'StringLiteral') {
|
|
120
|
+
sizePropValue = j.jsxExpressionContainer(sizePropValue);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
el.node.openingElement.attributes.push(
|
|
124
|
+
j.jsxAttribute(j.jsxIdentifier('size'), sizePropValue),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
el.node.openingElement.attributes = el.node.openingElement.attributes.filter(
|
|
129
|
+
(attr) => !breakpoints.includes(attr?.name?.name),
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const offset = j.objectExpression([]);
|
|
133
|
+
|
|
134
|
+
const offsetNodes = j(el)
|
|
135
|
+
.find(j.JSXAttribute)
|
|
136
|
+
.filter(
|
|
137
|
+
(path) =>
|
|
138
|
+
path.parent.parent.node === el.node &&
|
|
139
|
+
path.node.name.name.endsWith('Offset') &&
|
|
140
|
+
breakpoints.includes(path.node.name.name.replace('Offset', '')),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
offsetNodes.nodes().forEach((node) => {
|
|
144
|
+
const breakpoint = node.name.name.replace('Offset', '');
|
|
145
|
+
const value =
|
|
146
|
+
node.value.type === 'JSXExpressionContainer' ? node.value.expression : node.value;
|
|
147
|
+
|
|
148
|
+
offset.properties.push(j.property('init', j.identifier(breakpoint), value));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
spreadProps.forEach((spreadProp) => {
|
|
152
|
+
const spreadPropArgument = spreadProp.argument;
|
|
153
|
+
if (spreadPropArgument.type === 'ObjectExpression') {
|
|
154
|
+
const propertiesToPrune = [];
|
|
155
|
+
spreadPropArgument.properties.forEach((property) => {
|
|
156
|
+
const breakpoint = property.key.name.replace('Offset', '');
|
|
157
|
+
if (property.key.name.endsWith('Offset') && breakpoints.includes(breakpoint)) {
|
|
158
|
+
offset.properties.push(j.property('init', j.identifier(breakpoint), property.value));
|
|
159
|
+
propertiesToPrune.push(property.key.name);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
spreadPropArgument.properties = spreadPropArgument.properties.filter(
|
|
163
|
+
(prop) => !propertiesToPrune.includes(prop.key.name),
|
|
164
|
+
);
|
|
165
|
+
if (spreadPropArgument.properties.length === 0) {
|
|
166
|
+
attributesToPrune.push(spreadProp);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (offset.properties.length) {
|
|
172
|
+
let offsetPropValue = offset;
|
|
173
|
+
|
|
174
|
+
if (offset.properties.length === 1 && offset.properties[0].key.name === 'xs') {
|
|
175
|
+
offsetPropValue = offset.properties[0].value;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (offsetPropValue.type !== 'StringLiteral') {
|
|
179
|
+
offsetPropValue = j.jsxExpressionContainer(offsetPropValue);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
el.node.openingElement.attributes.push(
|
|
183
|
+
j.jsxAttribute(j.jsxIdentifier('offset'), offsetPropValue),
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
el.node.openingElement.attributes = el.node.openingElement.attributes.filter(
|
|
188
|
+
(attr) => !breakpoints.includes(attr?.name?.name.replace('Offset', '')),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
el.node.openingElement.attributes = el.node.openingElement.attributes.filter(
|
|
192
|
+
(attr) => !attributesToPrune.includes(attr),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const itemProp = el.node.openingElement.attributes.find(
|
|
196
|
+
(attr) => attr.type === 'JSXAttribute' && attr.name.name === 'item',
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
if (itemProp) {
|
|
200
|
+
el.node.openingElement.attributes = el.node.openingElement.attributes.filter(
|
|
201
|
+
(attr) => attr.type === 'JSXAttribute' && attr.name.name !== 'item',
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const zeroMinWidthProp = el.node.openingElement.attributes.find(
|
|
206
|
+
(attr) => attr.type === 'JSXAttribute' && attr.name.name === 'zeroMinWidth',
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
if (zeroMinWidthProp) {
|
|
210
|
+
el.node.openingElement.attributes = el.node.openingElement.attributes.filter(
|
|
211
|
+
(attr) => attr.type === 'JSXAttribute' && attr.name.name !== 'zeroMinWidth',
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
return root.toSource(printOptions);
|
|
217
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describeJscodeshiftTransform } from "../../../testUtils";
|
|
2
|
+
import transform from './grid-v2-props';
|
|
3
|
+
|
|
4
|
+
describe('@availity/codemod', () => {
|
|
5
|
+
describe('deprecations', () => {
|
|
6
|
+
describeJscodeshiftTransform({
|
|
7
|
+
transform,
|
|
8
|
+
transformName: 'grid-props',
|
|
9
|
+
dirname: __dirname,
|
|
10
|
+
testCases: [
|
|
11
|
+
{
|
|
12
|
+
actual: '/test-cases/actual.js',
|
|
13
|
+
expected: '/test-cases/expected.js'
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
actual: '/test-cases/custom-breakpoints.actual.js',
|
|
17
|
+
expected: '/test-cases/custom-breakpoints.expected.js',
|
|
18
|
+
options: { muiBreakpoints: 'customXs,customSm,customMd'}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @nx/enforce-module-boundaries */
|
|
2
|
+
import { Grid as GridA } from '@availity/element';
|
|
3
|
+
import { Grid as GridB } from '@availity/mui-layout';
|
|
4
|
+
|
|
5
|
+
// Transforms on all the possible imports
|
|
6
|
+
<GridA xs={2} />;
|
|
7
|
+
<GridB xs={2} />;
|
|
8
|
+
|
|
9
|
+
<GridA item />;
|
|
10
|
+
<GridA item={true} />;
|
|
11
|
+
<GridA item={false} />;
|
|
12
|
+
|
|
13
|
+
<GridA zeroMinWidth />;
|
|
14
|
+
<GridA zeroMinWidth={true} />;
|
|
15
|
+
<GridA zeroMinWidth={false} />;
|
|
16
|
+
|
|
17
|
+
// Transforms responsive sizes
|
|
18
|
+
<GridA xs={2} sm={4} md={6} lg={8} xl={10} />;
|
|
19
|
+
|
|
20
|
+
// Transforms all the possible size values
|
|
21
|
+
<GridA xs sm="auto" md={2} lg={true} xl={false} />;
|
|
22
|
+
|
|
23
|
+
// Doesn't add jsx object expression for single string values
|
|
24
|
+
<GridA xs="auto" />;
|
|
25
|
+
|
|
26
|
+
// Transforms offset
|
|
27
|
+
<GridA xsOffset={2} />;
|
|
28
|
+
|
|
29
|
+
// Transforms responsive offset
|
|
30
|
+
<GridA xsOffset={2} smOffset={4} mdOffset={6} lgOffset={8} xlOffset={10} />;
|
|
31
|
+
|
|
32
|
+
// Transforms all the possible offset values
|
|
33
|
+
<GridA xsOffset={2} smOffset="auto" />;
|
|
34
|
+
|
|
35
|
+
// Transforms spread props
|
|
36
|
+
<GridA {...{ xs: 2, sm: 4, xsOffset: 0, smOffset: 2 }} />;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Grid } from '@availity/mui-layout';
|
|
2
|
+
|
|
3
|
+
<>
|
|
4
|
+
// Transforms custom breakpoints
|
|
5
|
+
<Grid
|
|
6
|
+
size={{
|
|
7
|
+
customXs: 2,
|
|
8
|
+
customSm: 4,
|
|
9
|
+
customMd: 6
|
|
10
|
+
}} />
|
|
11
|
+
|
|
12
|
+
// Transforms custom breakpoints offset
|
|
13
|
+
<Grid
|
|
14
|
+
offset={{
|
|
15
|
+
customXs: 2,
|
|
16
|
+
customSm: 4,
|
|
17
|
+
customMd: 6
|
|
18
|
+
}} />
|
|
19
|
+
</>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* eslint-disable @nx/enforce-module-boundaries */
|
|
2
|
+
import { Grid as GridA } from '@availity/element';
|
|
3
|
+
import { Grid as GridB } from '@availity/mui-layout';
|
|
4
|
+
|
|
5
|
+
// Transforms on all the possible imports
|
|
6
|
+
<GridA size={2} />;
|
|
7
|
+
<GridB size={2} />;
|
|
8
|
+
|
|
9
|
+
<GridA />;
|
|
10
|
+
<GridA />;
|
|
11
|
+
<GridA />;
|
|
12
|
+
|
|
13
|
+
<GridA />;
|
|
14
|
+
<GridA />;
|
|
15
|
+
<GridA />;
|
|
16
|
+
|
|
17
|
+
// Transforms responsive sizes
|
|
18
|
+
<GridA
|
|
19
|
+
size={{
|
|
20
|
+
xs: 2,
|
|
21
|
+
sm: 4,
|
|
22
|
+
md: 6,
|
|
23
|
+
lg: 8,
|
|
24
|
+
xl: 10
|
|
25
|
+
}} />;
|
|
26
|
+
|
|
27
|
+
// Transforms all the possible size values
|
|
28
|
+
<GridA
|
|
29
|
+
size={{
|
|
30
|
+
xs: "grow",
|
|
31
|
+
sm: "auto",
|
|
32
|
+
md: 2,
|
|
33
|
+
lg: "grow",
|
|
34
|
+
xl: false
|
|
35
|
+
}} />;
|
|
36
|
+
|
|
37
|
+
// Doesn't add jsx object expression for single string values
|
|
38
|
+
<GridA size="auto" />;
|
|
39
|
+
|
|
40
|
+
// Transforms offset
|
|
41
|
+
<GridA offset={2} />;
|
|
42
|
+
|
|
43
|
+
// Transforms responsive offset
|
|
44
|
+
<GridA
|
|
45
|
+
offset={{
|
|
46
|
+
xs: 2,
|
|
47
|
+
sm: 4,
|
|
48
|
+
md: 6,
|
|
49
|
+
lg: 8,
|
|
50
|
+
xl: 10
|
|
51
|
+
}} />;
|
|
52
|
+
|
|
53
|
+
// Transforms all the possible offset values
|
|
54
|
+
<GridA
|
|
55
|
+
offset={{
|
|
56
|
+
xs: 2,
|
|
57
|
+
sm: "auto"
|
|
58
|
+
}} />;
|
|
59
|
+
|
|
60
|
+
// Transforms spread props
|
|
61
|
+
<GridA
|
|
62
|
+
size={{
|
|
63
|
+
xs: 2,
|
|
64
|
+
sm: 4
|
|
65
|
+
}}
|
|
66
|
+
offset={{
|
|
67
|
+
xs: 0,
|
|
68
|
+
sm: 2
|
|
69
|
+
}} />;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// from `packages/mui-system/src/styleFunctionSx/defaultSxConfig.js`
|
|
2
|
+
const defaultSxConfig = {
|
|
3
|
+
// borders
|
|
4
|
+
border: {},
|
|
5
|
+
borderTop: {},
|
|
6
|
+
borderRight: {},
|
|
7
|
+
borderBottom: {},
|
|
8
|
+
borderLeft: {},
|
|
9
|
+
borderColor: {},
|
|
10
|
+
borderTopColor: {},
|
|
11
|
+
borderRightColor: {},
|
|
12
|
+
borderBottomColor: {},
|
|
13
|
+
borderLeftColor: {},
|
|
14
|
+
outline: {},
|
|
15
|
+
outlineColor: {},
|
|
16
|
+
borderRadius: {},
|
|
17
|
+
color: {},
|
|
18
|
+
bgcolor: {},
|
|
19
|
+
backgroundColor: {},
|
|
20
|
+
p: {},
|
|
21
|
+
pt: {},
|
|
22
|
+
pr: {},
|
|
23
|
+
pb: {},
|
|
24
|
+
pl: {},
|
|
25
|
+
px: {},
|
|
26
|
+
py: {},
|
|
27
|
+
padding: {},
|
|
28
|
+
paddingTop: {},
|
|
29
|
+
paddingRight: {},
|
|
30
|
+
paddingBottom: {},
|
|
31
|
+
paddingLeft: {},
|
|
32
|
+
paddingX: {},
|
|
33
|
+
paddingY: {},
|
|
34
|
+
paddingInline: {},
|
|
35
|
+
paddingInlineStart: {},
|
|
36
|
+
paddingInlineEnd: {},
|
|
37
|
+
paddingBlock: {},
|
|
38
|
+
paddingBlockStart: {},
|
|
39
|
+
paddingBlockEnd: {},
|
|
40
|
+
|
|
41
|
+
m: {},
|
|
42
|
+
mt: {},
|
|
43
|
+
mr: {},
|
|
44
|
+
mb: {},
|
|
45
|
+
ml: {},
|
|
46
|
+
mx: {},
|
|
47
|
+
my: {},
|
|
48
|
+
margin: {},
|
|
49
|
+
marginTop: {},
|
|
50
|
+
marginRight: {},
|
|
51
|
+
marginBottom: {},
|
|
52
|
+
marginLeft: {},
|
|
53
|
+
marginX: {},
|
|
54
|
+
marginY: {},
|
|
55
|
+
marginInline: {},
|
|
56
|
+
marginInlineStart: {},
|
|
57
|
+
marginInlineEnd: {},
|
|
58
|
+
marginBlock: {},
|
|
59
|
+
marginBlockStart: {},
|
|
60
|
+
marginBlockEnd: {},
|
|
61
|
+
|
|
62
|
+
// display
|
|
63
|
+
displayPrint: {},
|
|
64
|
+
display: {},
|
|
65
|
+
overflow: {},
|
|
66
|
+
textOverflow: {},
|
|
67
|
+
visibility: {},
|
|
68
|
+
whiteSpace: {},
|
|
69
|
+
|
|
70
|
+
// flexbox
|
|
71
|
+
flexBasis: {},
|
|
72
|
+
flexDirection: {},
|
|
73
|
+
flexWrap: {},
|
|
74
|
+
justifyContent: {},
|
|
75
|
+
alignItems: {},
|
|
76
|
+
alignContent: {},
|
|
77
|
+
order: {},
|
|
78
|
+
flex: {},
|
|
79
|
+
flexGrow: {},
|
|
80
|
+
flexShrink: {},
|
|
81
|
+
alignSelf: {},
|
|
82
|
+
justifyItems: {},
|
|
83
|
+
justifySelf: {},
|
|
84
|
+
|
|
85
|
+
// grid
|
|
86
|
+
gap: {},
|
|
87
|
+
rowGap: {},
|
|
88
|
+
columnGap: {},
|
|
89
|
+
gridColumn: {},
|
|
90
|
+
gridRow: {},
|
|
91
|
+
gridAutoFlow: {},
|
|
92
|
+
gridAutoColumns: {},
|
|
93
|
+
gridAutoRows: {},
|
|
94
|
+
gridTemplateColumns: {},
|
|
95
|
+
gridTemplateRows: {},
|
|
96
|
+
gridTemplateAreas: {},
|
|
97
|
+
gridArea: {},
|
|
98
|
+
|
|
99
|
+
// positions
|
|
100
|
+
position: {},
|
|
101
|
+
zIndex: {},
|
|
102
|
+
top: {},
|
|
103
|
+
right: {},
|
|
104
|
+
bottom: {},
|
|
105
|
+
left: {},
|
|
106
|
+
|
|
107
|
+
// shadows
|
|
108
|
+
boxShadow: {},
|
|
109
|
+
|
|
110
|
+
// sizing
|
|
111
|
+
width: {},
|
|
112
|
+
maxWidth: {},
|
|
113
|
+
minWidth: {},
|
|
114
|
+
height: {},
|
|
115
|
+
maxHeight: {},
|
|
116
|
+
minHeight: {},
|
|
117
|
+
boxSizing: {},
|
|
118
|
+
|
|
119
|
+
// typography
|
|
120
|
+
font: {},
|
|
121
|
+
fontFamily: {},
|
|
122
|
+
fontSize: {},
|
|
123
|
+
fontStyle: {},
|
|
124
|
+
fontWeight: {},
|
|
125
|
+
letterSpacing: {},
|
|
126
|
+
textTransform: {},
|
|
127
|
+
lineHeight: {},
|
|
128
|
+
textAlign: {},
|
|
129
|
+
typography: {},
|
|
130
|
+
};
|
|
131
|
+
const systemProps = Object.keys(defaultSxConfig);
|
|
132
|
+
const components = ['Box', 'Stack', 'Typography', 'Link', 'Grid'];
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @param {import('jscodeshift').FileInfo} file
|
|
136
|
+
* @param {import('jscodeshift').API} api
|
|
137
|
+
*/
|
|
138
|
+
export default function removeSystemProps(file, api, options) {
|
|
139
|
+
if (file.path?.endsWith('.json') || file.path?.endsWith('.d.ts')) {
|
|
140
|
+
return file.source;
|
|
141
|
+
}
|
|
142
|
+
const j = api.jscodeshift;
|
|
143
|
+
const root = j(file.source);
|
|
144
|
+
const printOptions = options.printOptions;
|
|
145
|
+
|
|
146
|
+
const deprecatedElements = [];
|
|
147
|
+
const customReplacement = {
|
|
148
|
+
Typography: {
|
|
149
|
+
matcher: (key, val) =>
|
|
150
|
+
key !== 'color' ||
|
|
151
|
+
(val.value?.includes('.') && val.value !== 'inherit') ||
|
|
152
|
+
val.value === 'divider' ||
|
|
153
|
+
val.value.startsWith('#') ||
|
|
154
|
+
val.value.match(/\(.*\)/),
|
|
155
|
+
},
|
|
156
|
+
Link: {
|
|
157
|
+
matcher: (key) => key !== 'color',
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
const elementReplacement = {};
|
|
161
|
+
|
|
162
|
+
root
|
|
163
|
+
.find(j.ImportDeclaration, (decl) => {
|
|
164
|
+
const { source: {value} } = decl;
|
|
165
|
+
return value.includes('@availity/element') || value.includes('@availity/mui')
|
|
166
|
+
})
|
|
167
|
+
.forEach((decl) => {
|
|
168
|
+
decl.node.specifiers.forEach((spec) => {
|
|
169
|
+
if (spec.type === 'ImportSpecifier') {
|
|
170
|
+
const name = spec.imported.name;
|
|
171
|
+
if (components.includes(name)) {
|
|
172
|
+
deprecatedElements.push(spec.local.name);
|
|
173
|
+
if (customReplacement[name]) {
|
|
174
|
+
elementReplacement[spec.local.name] = customReplacement[name];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (spec.type === 'ImportDefaultSpecifier') {
|
|
179
|
+
const name = decl.node.source.value.split('/').pop();
|
|
180
|
+
if (components.includes(name)) {
|
|
181
|
+
deprecatedElements.push(spec.local.name);
|
|
182
|
+
if (customReplacement[name]) {
|
|
183
|
+
elementReplacement[spec.local.name] = customReplacement[name];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
root
|
|
191
|
+
.find(j.JSXElement, {
|
|
192
|
+
openingElement: {
|
|
193
|
+
name: {
|
|
194
|
+
name: (name) => {
|
|
195
|
+
return deprecatedElements.includes(name);
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
.forEach((el) => {
|
|
201
|
+
const sx = j.objectExpression([]);
|
|
202
|
+
const elementName = el.value?.openingElement?.name?.name;
|
|
203
|
+
|
|
204
|
+
const sxNodes = j(el)
|
|
205
|
+
.find(j.JSXAttribute)
|
|
206
|
+
.filter((path) => path.parent.parent.node === el.node && path.node.name.name === 'sx');
|
|
207
|
+
|
|
208
|
+
const sxNodesArray = sxNodes.nodes() || [];
|
|
209
|
+
const existingSxValue = sxNodesArray[0]?.value?.expression;
|
|
210
|
+
|
|
211
|
+
let spreadElement = null;
|
|
212
|
+
el.node.openingElement.attributes.forEach((attr) => {
|
|
213
|
+
if (attr.type === 'JSXSpreadAttribute') {
|
|
214
|
+
spreadElement = attr;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const attrToPrune = ['sx'];
|
|
219
|
+
el.node.openingElement.attributes.forEach((attr) => {
|
|
220
|
+
if (
|
|
221
|
+
attr.type === 'JSXSpreadAttribute' ||
|
|
222
|
+
!attr.value ||
|
|
223
|
+
!systemProps.includes(attr?.name?.name)
|
|
224
|
+
) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const key = attr?.name?.name;
|
|
228
|
+
const literal = attr?.value;
|
|
229
|
+
const val = literal.type === 'JSXExpressionContainer' ? literal.expression : literal;
|
|
230
|
+
const shouldPrune =
|
|
231
|
+
!elementReplacement[elementName] || elementReplacement[elementName].matcher(key, val);
|
|
232
|
+
if (key && val) {
|
|
233
|
+
if (shouldPrune) {
|
|
234
|
+
sx.properties.push(j.property('init', j.identifier(key), val));
|
|
235
|
+
attrToPrune.push(key);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
if (sx.properties.length) {
|
|
241
|
+
el.node.openingElement.attributes = el.node.openingElement.attributes.filter(
|
|
242
|
+
(attr) => attr.type !== 'JSXAttribute' || !attrToPrune.includes(attr?.name?.name),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
let finalSx;
|
|
246
|
+
if (!existingSxValue) {
|
|
247
|
+
finalSx = sx;
|
|
248
|
+
} else if (existingSxValue?.type === 'ObjectExpression') {
|
|
249
|
+
sx.properties.push(...existingSxValue.properties);
|
|
250
|
+
finalSx = sx;
|
|
251
|
+
} else if (existingSxValue?.type === 'ArrayExpression') {
|
|
252
|
+
existingSxValue.elements = [sx, ...existingSxValue.elements];
|
|
253
|
+
finalSx = existingSxValue;
|
|
254
|
+
} else {
|
|
255
|
+
finalSx = j.arrayExpression([
|
|
256
|
+
sx,
|
|
257
|
+
existingSxValue.type === 'Identifier'
|
|
258
|
+
? j.spreadElement(
|
|
259
|
+
j.conditionalExpression(
|
|
260
|
+
j.callExpression(
|
|
261
|
+
j.memberExpression(j.identifier('Array'), j.identifier('isArray')),
|
|
262
|
+
[existingSxValue],
|
|
263
|
+
),
|
|
264
|
+
existingSxValue,
|
|
265
|
+
j.arrayExpression([existingSxValue]),
|
|
266
|
+
),
|
|
267
|
+
)
|
|
268
|
+
: existingSxValue,
|
|
269
|
+
]);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (spreadElement && spreadElement.argument.type === 'Identifier') {
|
|
273
|
+
if (finalSx.type === 'ObjectExpression') {
|
|
274
|
+
const propSx = j.memberExpression(spreadElement.argument, j.identifier('sx'));
|
|
275
|
+
finalSx = j.arrayExpression([
|
|
276
|
+
finalSx,
|
|
277
|
+
j.spreadElement(
|
|
278
|
+
j.conditionalExpression(
|
|
279
|
+
j.callExpression(
|
|
280
|
+
j.memberExpression(j.identifier('Array'), j.identifier('isArray')),
|
|
281
|
+
[propSx],
|
|
282
|
+
),
|
|
283
|
+
propSx,
|
|
284
|
+
j.arrayExpression([propSx]),
|
|
285
|
+
),
|
|
286
|
+
),
|
|
287
|
+
]);
|
|
288
|
+
} else if (finalSx.type === 'ArrayExpression') {
|
|
289
|
+
finalSx.elements.push(j.memberExpression(spreadElement.argument, j.identifier('sx')));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
el.node.openingElement.attributes.push(
|
|
294
|
+
j.jsxAttribute(j.jsxIdentifier('sx'), j.jsxExpressionContainer(finalSx)),
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
return root.toSource(printOptions);
|
|
300
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { jscodeshift } from '../../../testUtils';
|
|
3
|
+
import transform from './removeSystemProps';
|
|
4
|
+
import {readFile} from '../../../utils';
|
|
5
|
+
|
|
6
|
+
function read(fileName) {
|
|
7
|
+
return readFile(path.join(__dirname, fileName));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe('@mui/codemod', () => {
|
|
11
|
+
describe('v6.0.0 - removeSystemProps', () => {
|
|
12
|
+
it('transforms props as needed', () => {
|
|
13
|
+
const actual = transform(
|
|
14
|
+
{ source: read('./test-cases/system-props.actual.js') },
|
|
15
|
+
{ jscodeshift },
|
|
16
|
+
{},
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const expected = read('./test-cases/system-props.expected.js');
|
|
20
|
+
expect(actual).toBe(expected);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should be idempotent', () => {
|
|
24
|
+
const actual = transform(
|
|
25
|
+
{ source: read('./test-cases/system-props.expected.js') },
|
|
26
|
+
{ jscodeshift },
|
|
27
|
+
{},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const expected = read('./test-cases/system-props.expected.js');
|
|
31
|
+
expect(actual).toBe(expected);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
// eslint-disable-next-line @nx/enforce-module-boundaries
|
|
3
|
+
import { Box as Boxxx, Grid as Griddd } from '@availity/element';
|
|
4
|
+
import { Typography } from '@availity/mui-typography';
|
|
5
|
+
import { Typography as Typographyyy } from '@availity/mui-typography';
|
|
6
|
+
import { Stack as Stackkk } from '@availity/mui-layout';
|
|
7
|
+
|
|
8
|
+
<Boxxx typography="body1" />;
|
|
9
|
+
<Boxxx color="palette.main" sx={{ display: 'block' }} />;
|
|
10
|
+
|
|
11
|
+
<Griddd container flexDirection={`column`} />;
|
|
12
|
+
|
|
13
|
+
const sx = { display: 'flex' };
|
|
14
|
+
const ml = 2;
|
|
15
|
+
<Typography color="#fff" mb={5} />;
|
|
16
|
+
<Typography color="hsl(200 30% 30%)" mb={5} />;
|
|
17
|
+
<Typographyyy variant="body1" color="primary.main" ml={ml} sx={sx} />;
|
|
18
|
+
<Typographyyy variant="body1" color="divider" ml={ml} sx={sx} />;
|
|
19
|
+
<Typographyyy variant="body1" color="inherit" ml={ml} sx={sx} />;
|
|
20
|
+
<Typographyyy
|
|
21
|
+
fontSize="xl4"
|
|
22
|
+
lineHeight={1}
|
|
23
|
+
startDecorator={
|
|
24
|
+
<Typographyyy fontSize="lg" textColor="text.secondary">
|
|
25
|
+
$
|
|
26
|
+
</Typographyyy>
|
|
27
|
+
}
|
|
28
|
+
sx={{ alignItems: 'flex-start' }}
|
|
29
|
+
>
|
|
30
|
+
25
|
|
31
|
+
</Typographyyy>;
|
|
32
|
+
function Copyright(props) {
|
|
33
|
+
return (
|
|
34
|
+
<Typographyyy variant="body2" color="text.secondary" align="center" {...props}>
|
|
35
|
+
{'Copyright © '}
|
|
36
|
+
<Link color="inherit" href="https://mui.com/">
|
|
37
|
+
Your Website
|
|
38
|
+
</Link>{' '}
|
|
39
|
+
{new Date().getFullYear()}
|
|
40
|
+
{'.'}
|
|
41
|
+
</Typographyyy>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
<Stackkk flex="1" sx={[...(Array.isArray(sx) ? sx : [sx])]} />;
|
|
46
|
+
|
|
47
|
+
<Boxxx typography="body1" sx={foo.bar ? { opacity: 0 } : sx} />;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
// eslint-disable-next-line @nx/enforce-module-boundaries
|
|
3
|
+
import { Box as Boxxx, Grid as Griddd } from '@availity/element';
|
|
4
|
+
import { Typography } from '@availity/mui-typography';
|
|
5
|
+
import { Typography as Typographyyy } from '@availity/mui-typography';
|
|
6
|
+
import { Stack as Stackkk } from '@availity/mui-layout';
|
|
7
|
+
|
|
8
|
+
<Boxxx sx={{
|
|
9
|
+
typography: "body1"
|
|
10
|
+
}} />;
|
|
11
|
+
<Boxxx
|
|
12
|
+
sx={{
|
|
13
|
+
color: "palette.main",
|
|
14
|
+
display: 'block'
|
|
15
|
+
}} />;
|
|
16
|
+
|
|
17
|
+
<Griddd container sx={{
|
|
18
|
+
flexDirection: `column`
|
|
19
|
+
}} />;
|
|
20
|
+
|
|
21
|
+
const sx = { display: 'flex' };
|
|
22
|
+
const ml = 2;
|
|
23
|
+
<Typography
|
|
24
|
+
sx={{
|
|
25
|
+
color: "#fff",
|
|
26
|
+
mb: 5
|
|
27
|
+
}} />;
|
|
28
|
+
<Typography
|
|
29
|
+
sx={{
|
|
30
|
+
color: "hsl(200 30% 30%)",
|
|
31
|
+
mb: 5
|
|
32
|
+
}} />;
|
|
33
|
+
<Typographyyy
|
|
34
|
+
variant="body1"
|
|
35
|
+
sx={[{
|
|
36
|
+
color: "primary.main",
|
|
37
|
+
ml: ml
|
|
38
|
+
}, ...(Array.isArray(sx) ? sx : [sx])]} />;
|
|
39
|
+
<Typographyyy
|
|
40
|
+
variant="body1"
|
|
41
|
+
sx={[{
|
|
42
|
+
color: "divider",
|
|
43
|
+
ml: ml
|
|
44
|
+
}, ...(Array.isArray(sx) ? sx : [sx])]} />;
|
|
45
|
+
<Typographyyy
|
|
46
|
+
variant="body1"
|
|
47
|
+
color="inherit"
|
|
48
|
+
sx={[{
|
|
49
|
+
ml: ml
|
|
50
|
+
}, ...(Array.isArray(sx) ? sx : [sx])]} />;
|
|
51
|
+
<Typographyyy
|
|
52
|
+
startDecorator={
|
|
53
|
+
<Typographyyy textColor="text.secondary" sx={{
|
|
54
|
+
fontSize: "lg"
|
|
55
|
+
}}>
|
|
56
|
+
$
|
|
57
|
+
</Typographyyy>
|
|
58
|
+
}
|
|
59
|
+
sx={{
|
|
60
|
+
fontSize: "xl4",
|
|
61
|
+
lineHeight: 1,
|
|
62
|
+
alignItems: 'flex-start'
|
|
63
|
+
}}>
|
|
64
|
+
25
|
|
65
|
+
</Typographyyy>;
|
|
66
|
+
function Copyright(props) {
|
|
67
|
+
return (
|
|
68
|
+
(<Typographyyy
|
|
69
|
+
variant="body2"
|
|
70
|
+
align="center"
|
|
71
|
+
{...props}
|
|
72
|
+
sx={[{
|
|
73
|
+
color: "text.secondary"
|
|
74
|
+
}, ...(Array.isArray(props.sx) ? props.sx : [props.sx])]}>
|
|
75
|
+
{'Copyright © '}
|
|
76
|
+
<Link color="inherit" href="https://mui.com/">
|
|
77
|
+
Your Website
|
|
78
|
+
</Link>{' '}
|
|
79
|
+
{new Date().getFullYear()}
|
|
80
|
+
{'.'}
|
|
81
|
+
</Typographyyy>)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
<Stackkk
|
|
86
|
+
sx={[{
|
|
87
|
+
flex: "1"
|
|
88
|
+
}, ...(Array.isArray(sx) ? sx : [sx])]} />;
|
|
89
|
+
|
|
90
|
+
<Boxxx
|
|
91
|
+
sx={[{
|
|
92
|
+
typography: "body1"
|
|
93
|
+
}, foo.bar ? { opacity: 0 } : sx]} />;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
import j from 'jscodeshift';
|
|
3
|
+
import { EOL } from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { readFile } from '../utils';
|
|
6
|
+
|
|
7
|
+
export const jscodeshift = j.withParser('tsx');
|
|
8
|
+
|
|
9
|
+
function read(dirname, fileName) {
|
|
10
|
+
return readFile(path.join(dirname, fileName));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function describeJscodeshiftTransform({ transformName, transform, testCases, dirname }) {
|
|
14
|
+
describe(transformName, () => {
|
|
15
|
+
testCases.forEach((testCase) => {
|
|
16
|
+
it('transforms as needed', () => {
|
|
17
|
+
const actual = transform(
|
|
18
|
+
{ source: read(dirname, testCase.actual) },
|
|
19
|
+
{ jscodeshift },
|
|
20
|
+
{
|
|
21
|
+
...testCase.options, printOptions: {
|
|
22
|
+
...testCase.options?.printOptions,
|
|
23
|
+
lineTerminator: EOL
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const expected = read(dirname, testCase.expected);
|
|
28
|
+
expect(actual).toBe(expected);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should be idempotent', () => {
|
|
32
|
+
const actual = transform(
|
|
33
|
+
{ source: read(dirname, testCase.expected) },
|
|
34
|
+
{ jscodeshift },
|
|
35
|
+
{
|
|
36
|
+
...testCase.options,
|
|
37
|
+
printOptions: {
|
|
38
|
+
...testCase.options?.printOptions,
|
|
39
|
+
lineTerminator: EOL,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const expected = read(dirname, testCase.expected);
|
|
45
|
+
expect(actual).toBe(expected);
|
|
46
|
+
});
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
}
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { EOL } from 'os';
|
|
3
|
+
|
|
4
|
+
export function readFile(filePath) {
|
|
5
|
+
const fileContents = fs.readFileSync(filePath, 'utf8').toString();
|
|
6
|
+
|
|
7
|
+
if (EOL !== '\n') {
|
|
8
|
+
return fileContents.replace(/\n/g, EOL);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return fileContents;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const getCreateBuildStyle = (j) =>
|
|
15
|
+
function createBuildStyle(key, upperBuildStyle, applyStylesMode) {
|
|
16
|
+
if (applyStylesMode) {
|
|
17
|
+
upperBuildStyle = (styleExpression) =>
|
|
18
|
+
j.objectExpression([
|
|
19
|
+
j.spreadElement(
|
|
20
|
+
j.callExpression(
|
|
21
|
+
j.memberExpression(j.identifier('theme'), j.identifier('applyStyles')),
|
|
22
|
+
[j.stringLiteral(applyStylesMode), styleExpression],
|
|
23
|
+
),
|
|
24
|
+
),
|
|
25
|
+
]);
|
|
26
|
+
}
|
|
27
|
+
return function buildStyle(styleExpression) {
|
|
28
|
+
if (key) {
|
|
29
|
+
if (key.type === 'Identifier' || key.type === 'StringLiteral') {
|
|
30
|
+
return upperBuildStyle(j.objectExpression([j.objectProperty(key, styleExpression)]));
|
|
31
|
+
}
|
|
32
|
+
if (key.type === 'TemplateLiteral' || key.type === 'CallExpression') {
|
|
33
|
+
return upperBuildStyle(
|
|
34
|
+
j.objectExpression([
|
|
35
|
+
{
|
|
36
|
+
...j.objectProperty(key, styleExpression),
|
|
37
|
+
computed: true,
|
|
38
|
+
},
|
|
39
|
+
]),
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return upperBuildStyle ? upperBuildStyle(styleExpression) : styleExpression;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const getAppendPaletteModeStyles = (j) => function appendPaletteModeStyles(node, modeStyles) {
|
|
48
|
+
Object.entries(modeStyles).forEach(([mode, objectStyles]) => {
|
|
49
|
+
node.properties.push(
|
|
50
|
+
j.spreadElement(
|
|
51
|
+
j.callExpression(j.memberExpression(j.identifier('theme'), j.identifier('applyStyles')), [
|
|
52
|
+
j.stringLiteral(mode),
|
|
53
|
+
Array.isArray(objectStyles) ? j.objectExpression(objectStyles) : objectStyles,
|
|
54
|
+
]),
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const getBuildArrowFunctionAST = (j) => function buildArrowFunctionAST(params, body) {
|
|
61
|
+
const destructured = [...params].every((param) => typeof param === 'string');
|
|
62
|
+
return j.arrowFunctionExpression(
|
|
63
|
+
destructured ? [
|
|
64
|
+
j.objectPattern(
|
|
65
|
+
[...params].map((k) => ({
|
|
66
|
+
...j.objectProperty(j.identifier(k), j.identifier(k)),
|
|
67
|
+
shorthand: true,
|
|
68
|
+
})),
|
|
69
|
+
),
|
|
70
|
+
]
|
|
71
|
+
: params,
|
|
72
|
+
body,
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export function getReturnExpression(node) {
|
|
77
|
+
let body = node.body;
|
|
78
|
+
if (body === 'BlockStatement') {
|
|
79
|
+
body = body.body;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (Array.isArray(body)) {
|
|
83
|
+
return body.find((statement) => statement.type === 'ReturnStatement')?.argument;
|
|
84
|
+
}
|
|
85
|
+
return body;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function getObjectKey(node) {
|
|
89
|
+
let tempNode = { ...node };
|
|
90
|
+
while (tempNode.type === 'UnaryExpression') {
|
|
91
|
+
tempNode = tempNode.argument;
|
|
92
|
+
}
|
|
93
|
+
while (tempNode.type === 'MemberExpression' || tempNode.type === 'OptionMemberExpression') {
|
|
94
|
+
tempNode = tempNode.object;
|
|
95
|
+
}
|
|
96
|
+
return tempNode;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function removeProperty(parentNode, child) {
|
|
100
|
+
if (parentNode) {
|
|
101
|
+
if (parentNode.type === 'ObjectExpression') {
|
|
102
|
+
parentNode.properties = parentNode.properties.filter(
|
|
103
|
+
(prop) => prop !== child && prop.value !== child,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function isThemePaletteMode(node) {
|
|
110
|
+
return (
|
|
111
|
+
node?.type === 'MemberExpression' &&
|
|
112
|
+
node.object.type === 'MemberExpression' &&
|
|
113
|
+
node.object.object.name === 'theme' &&
|
|
114
|
+
node.object.property.name === 'palette' &&
|
|
115
|
+
node.property.name === 'mode'
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./jsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"types": ["jest", "node", "@testing-library/jest-dom"],
|
|
7
|
+
"allowJs": true
|
|
8
|
+
},
|
|
9
|
+
"include": ["**/*.test.js", "**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"]
|
|
10
|
+
}
|