@mui/codemod 9.0.0-alpha.0 → 9.0.0-alpha.4
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 +265 -0
- package/README.md +141 -8
- package/codemod.js +68 -124
- package/deprecations/autocomplete-props/autocomplete-props.js +195 -0
- package/deprecations/autocomplete-props/test-cases/actual.js +31 -0
- package/deprecations/autocomplete-props/test-cases/expected.js +31 -0
- package/deprecations/autocomplete-props/test-cases/package.actual.js +11 -0
- package/deprecations/autocomplete-props/test-cases/package.expected.js +11 -0
- package/deprecations/autocomplete-props/test-cases/render-input-package.actual.js +34 -0
- package/deprecations/autocomplete-props/test-cases/render-input-package.expected.js +40 -0
- package/deprecations/autocomplete-props/test-cases/render-input.actual.js +81 -0
- package/deprecations/autocomplete-props/test-cases/render-input.expected.js +92 -0
- package/deprecations/autocomplete-props/test-cases/theme.actual.js +15 -0
- package/deprecations/autocomplete-props/test-cases/theme.expected.js +15 -0
- package/deprecations/circular-progress-classes/circular-progress-classes.js +16 -1
- package/deprecations/circular-progress-classes/postcss-plugin.js +2 -2
- package/deprecations/circular-progress-classes/test-cases/expected.js +4 -4
- package/deprecations/circular-progress-classes/test-cases/package.expected.js +4 -4
- package/deprecations/tabs-props/tabs-props.js +44 -0
- package/deprecations/tabs-props/test-cases/actual.js +11 -0
- package/deprecations/tabs-props/test-cases/expected.js +11 -0
- package/deprecations/tabs-props/test-cases/package.actual.js +6 -0
- package/deprecations/tabs-props/test-cases/package.expected.js +6 -0
- package/deprecations/tabs-props/test-cases/theme.actual.js +10 -0
- package/deprecations/tabs-props/test-cases/theme.expected.js +10 -0
- package/package.json +7 -6
- package/v5.0.0/path-imports.js +0 -5
- package/v5.0.0/top-level-imports.js +1 -5
package/codemod.js
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
2
3
|
|
|
3
4
|
const childProcess = require('child_process');
|
|
4
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
promises: fs
|
|
7
|
+
} = require('fs');
|
|
5
8
|
const path = require('path');
|
|
6
9
|
const yargs = require('yargs');
|
|
7
10
|
const jscodeshiftPackage = require('jscodeshift/package.json');
|
|
8
11
|
const postcssCliPackage = require('postcss-cli/package.json');
|
|
9
|
-
|
|
10
12
|
const jscodeshiftDirectory = path.dirname(require.resolve('jscodeshift'));
|
|
11
13
|
const jscodeshiftExecutable = path.join(jscodeshiftDirectory, jscodeshiftPackage.bin.jscodeshift);
|
|
12
|
-
|
|
13
14
|
const postcssCliDirectory = path.dirname(require.resolve('postcss-cli'));
|
|
14
15
|
const postcssExecutable = path.join(postcssCliDirectory, postcssCliPackage.bin.postcss);
|
|
15
|
-
|
|
16
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, './', `${transform}/index.js`),
|
|
21
|
-
path.resolve(__dirname, './', `${transform}.js`),
|
|
22
|
-
];
|
|
23
|
-
|
|
17
|
+
const paths = [path.resolve(__dirname, './src', `${transform}/index.js`), path.resolve(__dirname, './src', `${transform}.js`), path.resolve(__dirname, './', `${transform}/index.js`), path.resolve(__dirname, './', `${transform}.js`)];
|
|
24
18
|
let transformerPath;
|
|
25
19
|
let error;
|
|
26
20
|
for (const item of paths) {
|
|
@@ -35,35 +29,15 @@ async function runJscodeshiftTransform(transform, files, flags, codemodFlags) {
|
|
|
35
29
|
continue;
|
|
36
30
|
}
|
|
37
31
|
}
|
|
38
|
-
|
|
39
32
|
if (error) {
|
|
40
33
|
if (error?.code === 'ENOENT') {
|
|
41
|
-
throw new Error(
|
|
42
|
-
`Transform '${transform}' not found. Check out ${path.resolve(
|
|
43
|
-
__dirname,
|
|
44
|
-
'./README.md for a list of available codemods.',
|
|
45
|
-
)}`,
|
|
46
|
-
);
|
|
34
|
+
throw new Error(`Transform '${transform}' not found. Check out ${path.resolve(__dirname, './README.md for a list of available codemods.')}`);
|
|
47
35
|
}
|
|
48
36
|
throw error;
|
|
49
37
|
}
|
|
50
|
-
|
|
51
38
|
const args = [
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
'--transform',
|
|
55
|
-
transformerPath,
|
|
56
|
-
...codemodFlags,
|
|
57
|
-
'--extensions',
|
|
58
|
-
'js,ts,jsx,tsx,json',
|
|
59
|
-
'--parser',
|
|
60
|
-
flags.parser || 'tsx',
|
|
61
|
-
'--ignore-pattern',
|
|
62
|
-
'**/node_modules/**',
|
|
63
|
-
'--ignore-pattern',
|
|
64
|
-
'**/*.css',
|
|
65
|
-
];
|
|
66
|
-
|
|
39
|
+
// can't directly spawn `jscodeshiftExecutable` due to https://github.com/facebook/jscodeshift/issues/424
|
|
40
|
+
jscodeshiftExecutable, '--transform', transformerPath, ...codemodFlags, '--extensions', 'js,ts,jsx,tsx,json', '--parser', flags.parser || 'tsx', '--ignore-pattern', '**/node_modules/**', '--ignore-pattern', '**/*.css'];
|
|
67
41
|
if (flags.dry) {
|
|
68
42
|
args.push('--dry');
|
|
69
43
|
}
|
|
@@ -76,43 +50,33 @@ async function runJscodeshiftTransform(transform, files, flags, codemodFlags) {
|
|
|
76
50
|
if (flags.packageName) {
|
|
77
51
|
args.push(`--packageName=${flags.packageName}`);
|
|
78
52
|
}
|
|
79
|
-
|
|
80
53
|
args.push(...files);
|
|
81
54
|
|
|
82
55
|
// eslint-disable-next-line no-console -- debug information
|
|
83
56
|
console.log(`Executing command: jscodeshift ${args.join(' ')}`);
|
|
84
|
-
const jscodeshiftProcess = childProcess.spawnSync('node', args, {
|
|
85
|
-
|
|
57
|
+
const jscodeshiftProcess = childProcess.spawnSync('node', args, {
|
|
58
|
+
stdio: 'inherit'
|
|
59
|
+
});
|
|
86
60
|
if (jscodeshiftProcess.error) {
|
|
87
61
|
throw jscodeshiftProcess.error;
|
|
88
62
|
}
|
|
89
63
|
}
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return null;
|
|
103
|
-
}),
|
|
104
|
-
);
|
|
105
|
-
|
|
64
|
+
const parseCssFilePaths = async files => {
|
|
65
|
+
const cssFiles = await Promise.all(files.map(async filePath => {
|
|
66
|
+
const stat = await fs.stat(filePath);
|
|
67
|
+
if (stat.isDirectory()) {
|
|
68
|
+
return `${filePath}/**/*.css`;
|
|
69
|
+
}
|
|
70
|
+
if (filePath.endsWith('.css')) {
|
|
71
|
+
return filePath;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}));
|
|
106
75
|
return cssFiles.filter(Boolean);
|
|
107
76
|
};
|
|
108
|
-
|
|
109
77
|
async function runPostcssTransform(transform, files) {
|
|
110
78
|
// local postcss plugins are loaded through config files https://github.com/postcss/postcss-load-config/issues/17#issuecomment-253125559
|
|
111
|
-
const paths = [
|
|
112
|
-
path.resolve(__dirname, './src', `${transform}/postcss.config.js`),
|
|
113
|
-
path.resolve(__dirname, './', `${transform}/postcss.config.js`),
|
|
114
|
-
];
|
|
115
|
-
|
|
79
|
+
const paths = [path.resolve(__dirname, './src', `${transform}/postcss.config.js`), path.resolve(__dirname, './', `${transform}/postcss.config.js`)];
|
|
116
80
|
let configPath;
|
|
117
81
|
let error;
|
|
118
82
|
for (const item of paths) {
|
|
@@ -127,7 +91,6 @@ async function runPostcssTransform(transform, files) {
|
|
|
127
91
|
continue;
|
|
128
92
|
}
|
|
129
93
|
}
|
|
130
|
-
|
|
131
94
|
if (error) {
|
|
132
95
|
// don't throw if the file is not found, postcss transform is optional
|
|
133
96
|
if (error?.code !== 'ENOENT') {
|
|
@@ -135,81 +98,62 @@ async function runPostcssTransform(transform, files) {
|
|
|
135
98
|
}
|
|
136
99
|
} else {
|
|
137
100
|
const cssPaths = await parseCssFilePaths(files);
|
|
138
|
-
|
|
139
101
|
if (cssPaths.length > 0) {
|
|
140
|
-
const args = [
|
|
141
|
-
postcssExecutable,
|
|
142
|
-
...cssPaths,
|
|
143
|
-
'--config',
|
|
144
|
-
configPath,
|
|
145
|
-
'--replace',
|
|
146
|
-
'--verbose',
|
|
147
|
-
];
|
|
102
|
+
const args = [postcssExecutable, ...cssPaths, '--config', configPath, '--replace', '--verbose'];
|
|
148
103
|
|
|
149
104
|
// eslint-disable-next-line no-console -- debug information
|
|
150
105
|
console.log(`Executing command: postcss ${args.join(' ')}`);
|
|
151
|
-
const postcssProcess = childProcess.spawnSync('node', args, {
|
|
152
|
-
|
|
106
|
+
const postcssProcess = childProcess.spawnSync('node', args, {
|
|
107
|
+
stdio: 'inherit'
|
|
108
|
+
});
|
|
153
109
|
if (postcssProcess.error) {
|
|
154
110
|
throw postcssProcess.error;
|
|
155
111
|
}
|
|
156
112
|
}
|
|
157
113
|
}
|
|
158
114
|
}
|
|
159
|
-
|
|
160
115
|
function run(argv) {
|
|
161
|
-
const {
|
|
162
|
-
|
|
163
|
-
|
|
116
|
+
const {
|
|
117
|
+
codemod,
|
|
118
|
+
paths,
|
|
119
|
+
...flags
|
|
120
|
+
} = argv;
|
|
121
|
+
const files = paths.map(filePath => path.resolve(filePath));
|
|
164
122
|
runJscodeshiftTransform(codemod, files, flags, argv._);
|
|
165
123
|
runPostcssTransform(codemod, files);
|
|
166
124
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
})
|
|
203
|
-
.option('packageName', {
|
|
204
|
-
description: 'The package name to look for in the import statements',
|
|
205
|
-
default: '@mui/material',
|
|
206
|
-
type: 'string',
|
|
207
|
-
});
|
|
208
|
-
},
|
|
209
|
-
handler: run,
|
|
210
|
-
})
|
|
211
|
-
.scriptName('npx @mui/codemod')
|
|
212
|
-
.example('$0 v4.0.0/theme-spacing-api src')
|
|
213
|
-
.example('$0 v5.0.0/component-rename-prop src -- --component=Grid --from=prop --to=newProp')
|
|
214
|
-
.help()
|
|
215
|
-
.parse();
|
|
125
|
+
yargs.command({
|
|
126
|
+
command: '$0 <codemod> <paths...>',
|
|
127
|
+
describe: 'Applies a `@mui/codemod` to the specified paths',
|
|
128
|
+
builder: command => {
|
|
129
|
+
return command.positional('codemod', {
|
|
130
|
+
description: 'The name of the codemod',
|
|
131
|
+
type: 'string'
|
|
132
|
+
}).positional('paths', {
|
|
133
|
+
array: true,
|
|
134
|
+
description: 'Paths forwarded to `jscodeshift`',
|
|
135
|
+
type: 'string'
|
|
136
|
+
}).option('dry', {
|
|
137
|
+
description: 'dry run (no changes are made to files)',
|
|
138
|
+
default: false,
|
|
139
|
+
type: 'boolean'
|
|
140
|
+
}).option('parser', {
|
|
141
|
+
description: 'which parser for jscodeshift to use',
|
|
142
|
+
default: 'tsx',
|
|
143
|
+
type: 'string'
|
|
144
|
+
}).option('print', {
|
|
145
|
+
description: 'print transformed files to stdout, useful for development',
|
|
146
|
+
default: false,
|
|
147
|
+
type: 'boolean'
|
|
148
|
+
}).option('jscodeshift', {
|
|
149
|
+
description: '(Advanced) Pass options directly to jscodeshift',
|
|
150
|
+
default: false,
|
|
151
|
+
type: 'string'
|
|
152
|
+
}).option('packageName', {
|
|
153
|
+
description: 'The package name to look for in the import statements',
|
|
154
|
+
default: '@mui/material',
|
|
155
|
+
type: 'string'
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
handler: run
|
|
159
|
+
}).scriptName('npx @mui/codemod').example('$0 v4.0.0/theme-spacing-api src').example('$0 v5.0.0/component-rename-prop src -- --component=Grid --from=prop --to=newProp').help().parse();
|
|
@@ -12,6 +12,183 @@ var _findComponentJSX = _interopRequireDefault(require("../../util/findComponent
|
|
|
12
12
|
var _findComponentDefaultProps = _interopRequireDefault(require("../../util/findComponentDefaultProps"));
|
|
13
13
|
var _assignObject = _interopRequireDefault(require("../../util/assignObject"));
|
|
14
14
|
var _appendAttribute = _interopRequireDefault(require("../../util/appendAttribute"));
|
|
15
|
+
function getImportedNames(j, root, packageName, componentName) {
|
|
16
|
+
const importNames = new Set();
|
|
17
|
+
root.find(j.ImportDeclaration).filter(path => path.node.source.value.match(new RegExp(`^${packageName}(/${componentName})?$`))).forEach(path => {
|
|
18
|
+
path.node.specifiers.forEach(specifier => {
|
|
19
|
+
if (specifier.type === 'ImportDefaultSpecifier') {
|
|
20
|
+
importNames.add(specifier.local.name);
|
|
21
|
+
}
|
|
22
|
+
if (specifier.type === 'ImportSpecifier' && specifier.imported.name === componentName) {
|
|
23
|
+
importNames.add(specifier.local.name);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
return importNames;
|
|
28
|
+
}
|
|
29
|
+
function getAttributeIndex(element, attributeName) {
|
|
30
|
+
return element.openingElement.attributes.findIndex(attr => attr.type === 'JSXAttribute' && attr.name.name === attributeName);
|
|
31
|
+
}
|
|
32
|
+
function upsertSlotPropsAttribute(j, element, callback) {
|
|
33
|
+
const slotPropsIndex = getAttributeIndex(element, 'slotProps');
|
|
34
|
+
if (slotPropsIndex === -1) {
|
|
35
|
+
const slotPropsExpression = j.objectExpression([]);
|
|
36
|
+
callback(slotPropsExpression);
|
|
37
|
+
(0, _appendAttribute.default)(j, {
|
|
38
|
+
target: element,
|
|
39
|
+
attributeName: 'slotProps',
|
|
40
|
+
expression: slotPropsExpression
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const slotPropsAttribute = element.openingElement.attributes[slotPropsIndex];
|
|
45
|
+
const slotPropsExpression = slotPropsAttribute.value.expression;
|
|
46
|
+
if (slotPropsExpression.type === 'ObjectExpression') {
|
|
47
|
+
callback(slotPropsExpression);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const nextSlotPropsExpression = j.objectExpression([j.spreadElement(slotPropsExpression)]);
|
|
51
|
+
callback(nextSlotPropsExpression);
|
|
52
|
+
slotPropsAttribute.value.expression = nextSlotPropsExpression;
|
|
53
|
+
}
|
|
54
|
+
function moveJsxPropIntoSlotProps(j, element, propName, slotName) {
|
|
55
|
+
const propIndex = getAttributeIndex(element, propName);
|
|
56
|
+
if (propIndex === -1) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const removedAttribute = element.openingElement.attributes.splice(propIndex, 1)[0];
|
|
60
|
+
const removedValue = removedAttribute.value.type === 'StringLiteral' ? j.literal(removedAttribute.value.value) : removedAttribute.value.expression;
|
|
61
|
+
upsertSlotPropsAttribute(j, element, slotPropsExpression => {
|
|
62
|
+
const existingSlotIndex = slotPropsExpression.properties.findIndex(property => property.type !== 'SpreadElement' && property.key?.name === slotName);
|
|
63
|
+
if (existingSlotIndex === -1) {
|
|
64
|
+
slotPropsExpression.properties.push(j.objectProperty(j.identifier(slotName), removedValue));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const existingSlot = slotPropsExpression.properties[existingSlotIndex].value;
|
|
68
|
+
slotPropsExpression.properties[existingSlotIndex].value = j.objectExpression([j.spreadElement(removedValue), j.spreadElement(existingSlot)]);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function ensureParamsSlotPropsSpread(j, element, paramsName) {
|
|
72
|
+
const hasParamsSpread = element.openingElement.attributes.some(attribute => attribute.type === 'JSXSpreadAttribute' && attribute.argument.type === 'Identifier' && attribute.argument.name === paramsName);
|
|
73
|
+
if (!hasParamsSpread) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
upsertSlotPropsAttribute(j, element, slotPropsExpression => {
|
|
77
|
+
const hasSlotPropsSpread = slotPropsExpression.properties.some(property => property.type === 'SpreadElement' && property.argument.type === 'MemberExpression' && property.argument.object.type === 'Identifier' && property.argument.object.name === paramsName && property.argument.property.type === 'Identifier' && property.argument.property.name === 'slotProps');
|
|
78
|
+
if (!hasSlotPropsSpread) {
|
|
79
|
+
slotPropsExpression.properties.unshift(j.spreadElement(j.memberExpression(j.identifier(paramsName), j.identifier('slotProps'))));
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function replaceRenderInputParamsMembers(j, callbackRoot, paramsName) {
|
|
84
|
+
const slotPropByDeprecatedName = {
|
|
85
|
+
InputProps: 'input',
|
|
86
|
+
inputProps: 'htmlInput',
|
|
87
|
+
InputLabelProps: 'inputLabel'
|
|
88
|
+
};
|
|
89
|
+
callbackRoot.find(j.MemberExpression).filter(path => path.node.object.type === 'Identifier' && path.node.object.name === paramsName && path.node.property.type === 'Identifier' && slotPropByDeprecatedName[path.node.property.name]).replaceWith(path => j.memberExpression(j.memberExpression(j.identifier(paramsName), j.identifier('slotProps')), j.identifier(slotPropByDeprecatedName[path.node.property.name])));
|
|
90
|
+
}
|
|
91
|
+
function transformRenderInput(j, root, options) {
|
|
92
|
+
const packageName = options.packageName || '@mui/material';
|
|
93
|
+
const textFieldNames = getImportedNames(j, root, packageName, 'TextField');
|
|
94
|
+
(0, _findComponentJSX.default)(j, {
|
|
95
|
+
root,
|
|
96
|
+
packageName: options.packageName,
|
|
97
|
+
componentName: 'Autocomplete'
|
|
98
|
+
}, elementPath => {
|
|
99
|
+
const renderInputIndex = getAttributeIndex(elementPath.node, 'renderInput');
|
|
100
|
+
if (renderInputIndex === -1) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const renderInputAttribute = elementPath.node.openingElement.attributes[renderInputIndex];
|
|
104
|
+
const renderInputExpression = renderInputAttribute.value?.expression;
|
|
105
|
+
if (!renderInputExpression || !['ArrowFunctionExpression', 'FunctionExpression'].includes(renderInputExpression.type) || renderInputExpression.params.length === 0 || renderInputExpression.params[0].type !== 'Identifier') {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const paramsName = renderInputExpression.params[0].name;
|
|
109
|
+
const callbackRoot = j(renderInputExpression.body);
|
|
110
|
+
replaceRenderInputParamsMembers(j, callbackRoot, paramsName);
|
|
111
|
+
textFieldNames.forEach(textFieldName => {
|
|
112
|
+
const textFieldElements = [];
|
|
113
|
+
if (renderInputExpression.body.type === 'JSXElement' && renderInputExpression.body.openingElement.name.type === 'JSXIdentifier' && renderInputExpression.body.openingElement.name.name === textFieldName) {
|
|
114
|
+
textFieldElements.push(renderInputExpression.body);
|
|
115
|
+
}
|
|
116
|
+
callbackRoot.find(j.JSXElement).filter(textFieldPath => textFieldPath.node.openingElement.name.type === 'JSXIdentifier' && textFieldPath.node.openingElement.name.name === textFieldName).forEach(textFieldPath => {
|
|
117
|
+
textFieldElements.push(textFieldPath.node);
|
|
118
|
+
});
|
|
119
|
+
textFieldElements.forEach(element => {
|
|
120
|
+
moveJsxPropIntoSlotProps(j, element, 'InputProps', 'input');
|
|
121
|
+
moveJsxPropIntoSlotProps(j, element, 'inputProps', 'htmlInput');
|
|
122
|
+
moveJsxPropIntoSlotProps(j, element, 'InputLabelProps', 'inputLabel');
|
|
123
|
+
moveJsxPropIntoSlotProps(j, element, 'SelectProps', 'select');
|
|
124
|
+
moveJsxPropIntoSlotProps(j, element, 'FormHelperTextProps', 'formHelperText');
|
|
125
|
+
if (getAttributeIndex(element, 'slotProps') !== -1) {
|
|
126
|
+
ensureParamsSlotPropsSpread(j, element, paramsName);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function isNonComputedKey(j, path) {
|
|
133
|
+
const parent = path.parent.node;
|
|
134
|
+
return (j.ObjectProperty.check(parent) || j.Property.check(parent)) && parent.key === path.node && !parent.computed;
|
|
135
|
+
}
|
|
136
|
+
function renameIdentifiersInScope(j, scopePath, oldName, newName) {
|
|
137
|
+
const bindingScope = scopePath.scope.lookup(oldName);
|
|
138
|
+
if (!bindingScope) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
j(bindingScope.path).find(j.Identifier, {
|
|
142
|
+
name: oldName
|
|
143
|
+
}).filter(path => {
|
|
144
|
+
if (isNonComputedKey(j, path)) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
return path.scope.lookup(oldName) === bindingScope;
|
|
148
|
+
}).replaceWith(() => j.identifier(newName));
|
|
149
|
+
}
|
|
150
|
+
function renameRenderTagsCallback(j, callbackPath) {
|
|
151
|
+
const getTagPropsParam = callbackPath.node.params[1];
|
|
152
|
+
if (getTagPropsParam?.type === 'Identifier' && getTagPropsParam.name === 'getTagProps') {
|
|
153
|
+
renameIdentifiersInScope(j, callbackPath, 'getTagProps', 'getItemProps');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function renameRenderTagsProp(j, propertyPath) {
|
|
157
|
+
if (propertyPath.node.key.type === 'Identifier') {
|
|
158
|
+
propertyPath.node.key.name = 'renderValue';
|
|
159
|
+
}
|
|
160
|
+
if (propertyPath.node.value.type === 'ArrowFunctionExpression' || propertyPath.node.value.type === 'FunctionExpression') {
|
|
161
|
+
renameRenderTagsCallback(j, propertyPath.get('value'));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function renameUseAutocompleteReturnMembers(j, root) {
|
|
165
|
+
const renamedMembers = new Map([['getTagProps', 'getItemProps'], ['focusedTag', 'focusedItem']]);
|
|
166
|
+
root.find(j.VariableDeclarator).filter(path => {
|
|
167
|
+
const {
|
|
168
|
+
id,
|
|
169
|
+
init
|
|
170
|
+
} = path.node;
|
|
171
|
+
return id.type === 'ObjectPattern' && init?.type === 'CallExpression' && init.callee.type === 'Identifier' && init.callee.name === 'useAutocomplete';
|
|
172
|
+
}).forEach(path => {
|
|
173
|
+
path.node.id.properties.forEach(property => {
|
|
174
|
+
if (property.type !== 'ObjectProperty' || property.key.type !== 'Identifier') {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const nextName = renamedMembers.get(property.key.name);
|
|
178
|
+
if (!nextName) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const isShorthand = property.shorthand === true;
|
|
182
|
+
const localName = property.value.type === 'Identifier' ? property.value.name : null;
|
|
183
|
+
property.key.name = nextName;
|
|
184
|
+
if (isShorthand && localName) {
|
|
185
|
+
renameIdentifiersInScope(j, path, localName, nextName);
|
|
186
|
+
property.shorthand = true;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
15
192
|
/**
|
|
16
193
|
* @param {import('jscodeshift').FileInfo} file
|
|
17
194
|
* @param {import('jscodeshift').API} api
|
|
@@ -53,6 +230,7 @@ function transformer(file, api, options) {
|
|
|
53
230
|
packageName: options.packageName,
|
|
54
231
|
componentName: 'Autocomplete'
|
|
55
232
|
});
|
|
233
|
+
transformRenderInput(j, root, options);
|
|
56
234
|
|
|
57
235
|
// Move ListboxComponent JSX prop into slotProps.listbox.component
|
|
58
236
|
(0, _findComponentJSX.default)(j, {
|
|
@@ -61,6 +239,15 @@ function transformer(file, api, options) {
|
|
|
61
239
|
componentName: 'Autocomplete'
|
|
62
240
|
}, elementPath => {
|
|
63
241
|
const element = elementPath.node;
|
|
242
|
+
element.openingElement.attributes.forEach((attribute, index) => {
|
|
243
|
+
if (attribute.type !== 'JSXAttribute' || attribute.name.name !== 'renderTags') {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
attribute.name.name = 'renderValue';
|
|
247
|
+
if (attribute.value?.type === 'JSXExpressionContainer' && (attribute.value.expression.type === 'ArrowFunctionExpression' || attribute.value.expression.type === 'FunctionExpression')) {
|
|
248
|
+
renameRenderTagsCallback(j, elementPath.get('openingElement', 'attributes', index, 'value', 'expression'));
|
|
249
|
+
}
|
|
250
|
+
});
|
|
64
251
|
const propIndex = element.openingElement.attributes.findIndex(attr => attr.type === 'JSXAttribute' && attr.name.name === 'ListboxComponent');
|
|
65
252
|
if (propIndex !== -1) {
|
|
66
253
|
const removedValue = element.openingElement.attributes.splice(propIndex, 1)[0].value.expression;
|
|
@@ -127,5 +314,13 @@ function transformer(file, api, options) {
|
|
|
127
314
|
}
|
|
128
315
|
path.prune();
|
|
129
316
|
});
|
|
317
|
+
defaultPropsPathCollection.find(j.ObjectProperty, {
|
|
318
|
+
key: {
|
|
319
|
+
name: 'renderTags'
|
|
320
|
+
}
|
|
321
|
+
}).forEach(path => {
|
|
322
|
+
renameRenderTagsProp(j, path);
|
|
323
|
+
});
|
|
324
|
+
renameUseAutocompleteReturnMembers(j, root);
|
|
130
325
|
return root.toSource(printOptions);
|
|
131
326
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
4
|
var _Autocomplete = _interopRequireDefault(require("@mui/material/Autocomplete"));
|
|
5
5
|
var _material = require("@mui/material");
|
|
6
|
+
var _Chip = _interopRequireDefault(require("@mui/material/Chip"));
|
|
7
|
+
var _useAutocomplete = _interopRequireDefault(require("@mui/material/useAutocomplete"));
|
|
6
8
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
7
9
|
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
|
|
8
10
|
ChipProps: {
|
|
@@ -110,4 +112,33 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
110
112
|
ListboxProps: {
|
|
111
113
|
height: 12
|
|
112
114
|
}
|
|
115
|
+
});
|
|
116
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
|
|
117
|
+
multiple: true,
|
|
118
|
+
options: options,
|
|
119
|
+
renderTags: (value, getTagProps, ownerState) => value.map((option, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
120
|
+
label: option.label,
|
|
121
|
+
"data-focused": ownerState.focused,
|
|
122
|
+
...getTagProps({
|
|
123
|
+
index
|
|
124
|
+
})
|
|
125
|
+
}))
|
|
126
|
+
});
|
|
127
|
+
const {
|
|
128
|
+
getTagProps,
|
|
129
|
+
focusedTag
|
|
130
|
+
} = (0, _useAutocomplete.default)(props);
|
|
131
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
132
|
+
...getTagProps({
|
|
133
|
+
index: focusedTag
|
|
134
|
+
})
|
|
135
|
+
});
|
|
136
|
+
const {
|
|
137
|
+
getTagProps: getAutocompleteTagProps,
|
|
138
|
+
focusedTag: focusedAutocompleteTag
|
|
139
|
+
} = (0, _useAutocomplete.default)(props);
|
|
140
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
141
|
+
...getAutocompleteTagProps({
|
|
142
|
+
index: focusedAutocompleteTag
|
|
143
|
+
})
|
|
113
144
|
});
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
4
|
var _Autocomplete = _interopRequireDefault(require("@mui/material/Autocomplete"));
|
|
5
5
|
var _material = require("@mui/material");
|
|
6
|
+
var _Chip = _interopRequireDefault(require("@mui/material/Chip"));
|
|
7
|
+
var _useAutocomplete = _interopRequireDefault(require("@mui/material/useAutocomplete"));
|
|
6
8
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
7
9
|
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
|
|
8
10
|
slots: {
|
|
@@ -122,4 +124,33 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
122
124
|
ListboxProps: {
|
|
123
125
|
height: 12
|
|
124
126
|
}
|
|
127
|
+
});
|
|
128
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
|
|
129
|
+
multiple: true,
|
|
130
|
+
options: options,
|
|
131
|
+
renderValue: (value, getItemProps, ownerState) => value.map((option, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
132
|
+
label: option.label,
|
|
133
|
+
"data-focused": ownerState.focused,
|
|
134
|
+
...getItemProps({
|
|
135
|
+
index
|
|
136
|
+
})
|
|
137
|
+
}))
|
|
138
|
+
});
|
|
139
|
+
const {
|
|
140
|
+
getItemProps,
|
|
141
|
+
focusedItem
|
|
142
|
+
} = (0, _useAutocomplete.default)(props);
|
|
143
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
144
|
+
...getItemProps({
|
|
145
|
+
index: focusedItem
|
|
146
|
+
})
|
|
147
|
+
});
|
|
148
|
+
const {
|
|
149
|
+
getItemProps: getAutocompleteTagProps,
|
|
150
|
+
focusedItem: focusedAutocompleteTag
|
|
151
|
+
} = (0, _useAutocomplete.default)(props);
|
|
152
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
153
|
+
...getAutocompleteTagProps({
|
|
154
|
+
index: focusedAutocompleteTag
|
|
155
|
+
})
|
|
125
156
|
});
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
4
|
var _Autocomplete = _interopRequireDefault(require("@org/ui/material/Autocomplete"));
|
|
5
5
|
var _material = require("@org/ui/material");
|
|
6
|
+
var _Chip = _interopRequireDefault(require("@org/ui/material/Chip"));
|
|
6
7
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
7
8
|
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
|
|
8
9
|
ChipProps: {
|
|
@@ -110,4 +111,14 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
110
111
|
ListboxProps: {
|
|
111
112
|
height: 12
|
|
112
113
|
}
|
|
114
|
+
});
|
|
115
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Autocomplete, {
|
|
116
|
+
multiple: true,
|
|
117
|
+
options: options,
|
|
118
|
+
renderTags: (value, getTagProps) => value.map((option, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
119
|
+
label: option.label,
|
|
120
|
+
...getTagProps({
|
|
121
|
+
index
|
|
122
|
+
})
|
|
123
|
+
}))
|
|
113
124
|
});
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
4
|
var _Autocomplete = _interopRequireDefault(require("@org/ui/material/Autocomplete"));
|
|
5
5
|
var _material = require("@org/ui/material");
|
|
6
|
+
var _Chip = _interopRequireDefault(require("@org/ui/material/Chip"));
|
|
6
7
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
7
8
|
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
|
|
8
9
|
slots: {
|
|
@@ -122,4 +123,14 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
122
123
|
ListboxProps: {
|
|
123
124
|
height: 12
|
|
124
125
|
}
|
|
126
|
+
});
|
|
127
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Autocomplete, {
|
|
128
|
+
multiple: true,
|
|
129
|
+
options: options,
|
|
130
|
+
renderValue: (value, getItemProps) => value.map((option, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Chip.default, {
|
|
131
|
+
label: option.label,
|
|
132
|
+
...getItemProps({
|
|
133
|
+
index
|
|
134
|
+
})
|
|
135
|
+
}))
|
|
125
136
|
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
+
var _TextField = _interopRequireDefault(require("@org/ui/material/TextField"));
|
|
5
|
+
var _Autocomplete = _interopRequireDefault(require("@org/ui/material/Autocomplete"));
|
|
6
|
+
var _material = require("@org/ui/material");
|
|
7
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
8
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_Autocomplete.default, {
|
|
9
|
+
renderInput: params => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
|
|
10
|
+
...params,
|
|
11
|
+
inputProps: {
|
|
12
|
+
...params.inputProps,
|
|
13
|
+
autoComplete: 'new-password'
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Autocomplete, {
|
|
18
|
+
renderInput: params => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
|
|
19
|
+
...params,
|
|
20
|
+
inputProps: {
|
|
21
|
+
...params.inputProps,
|
|
22
|
+
autoComplete: 'new-password'
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
/*#__PURE__*/(0, _jsxRuntime.jsx)(CustomAutocomplete, {
|
|
27
|
+
renderInput: params => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
|
|
28
|
+
...params,
|
|
29
|
+
inputProps: {
|
|
30
|
+
...params.inputProps,
|
|
31
|
+
autoComplete: 'new-password'
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
});
|