@mui/codemod 6.0.0-alpha.5 → 6.0.0-alpha.6

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.
@@ -0,0 +1,472 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = migrateToVariants;
8
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
+ const MAX_DEPTH = 20;
10
+ /**
11
+ *
12
+ * @param {import('jscodeshift').API['j']} j
13
+ * @param {any[]} styles
14
+ */
15
+ function migrateToVariants(j, styles) {
16
+ function createBuildStyle(key, upperBuildStyle, applyStylesMode) {
17
+ if (applyStylesMode) {
18
+ upperBuildStyle = styleExpression => j.objectExpression([j.spreadElement(j.callExpression(j.memberExpression(j.identifier('theme'), j.identifier('applyStyles')), [j.stringLiteral(applyStylesMode), styleExpression]))]);
19
+ }
20
+ return function buildStyle(styleExpression) {
21
+ if (key) {
22
+ if (key.type === 'Identifier' || key.type === 'StringLiteral') {
23
+ return upperBuildStyle(j.objectExpression([j.objectProperty(key, styleExpression)]));
24
+ }
25
+ if (key.type === 'TemplateLiteral' || key.type === 'CallExpression') {
26
+ return upperBuildStyle(j.objectExpression([(0, _extends2.default)({}, j.objectProperty(key, styleExpression), {
27
+ computed: true
28
+ })]));
29
+ }
30
+ }
31
+ return upperBuildStyle ? upperBuildStyle(styleExpression) : styleExpression;
32
+ };
33
+ }
34
+
35
+ /**
36
+ *
37
+ * @param {import('ast-types').namedTypes.MemberExpression | import('ast-types').namedTypes.Identifier} node
38
+ */
39
+ function getIdentifierKey(node) {
40
+ if (node.type === 'MemberExpression') {
41
+ return node.property;
42
+ }
43
+ return node;
44
+ }
45
+
46
+ /**
47
+ *
48
+ * @param {import('ast-types').namedTypes.UnaryExpression | import('ast-types').namedTypes.MemberExpression | import('ast-types').namedTypes.Identifier} node
49
+ */
50
+ function getObjectKey(node) {
51
+ let tempNode = (0, _extends2.default)({}, node);
52
+ while (tempNode.type === 'UnaryExpression') {
53
+ tempNode = tempNode.argument;
54
+ }
55
+ while (tempNode.type === 'MemberExpression') {
56
+ tempNode = tempNode.object;
57
+ }
58
+ return tempNode;
59
+ }
60
+
61
+ /**
62
+ *
63
+ * @param {import('ast-types').namedTypes.ObjectExpression} objectExpression
64
+ * @param {import('ast-types').namedTypes.BinaryExpression} addtional
65
+ */
66
+ function objectToArrowFunction(objectExpression, addtional) {
67
+ const paramKeys = new Set();
68
+ let left;
69
+ objectExpression.properties.forEach((prop, index) => {
70
+ paramKeys.add(prop.key.name);
71
+ const result = j.binaryExpression('===', prop.key, prop.value);
72
+ if (index === 0) {
73
+ left = result;
74
+ } else {
75
+ left = j.logicalExpression('&&', left, result);
76
+ }
77
+ });
78
+ if (addtional) {
79
+ paramKeys.add(getObjectKey(addtional.left).name);
80
+ }
81
+ return buildArrowFunctionAST(paramKeys, addtional ? j.logicalExpression('&&', left, addtional) : left);
82
+ }
83
+
84
+ /**
85
+ *
86
+ * @param {import('ast-types').namedTypes.Identifier | import('ast-types').namedTypes.BinaryExpression | import('ast-types').namedTypes.UnaryExpression | import('ast-types').namedTypes.MemberExpression} node
87
+ */
88
+ function inverseBinaryExpression(node) {
89
+ if (node.type === 'Identifier' || node.type === 'MemberExpression') {
90
+ return j.unaryExpression('!', node);
91
+ }
92
+ if (node.operator === '===') {
93
+ return (0, _extends2.default)({}, node, {
94
+ operator: '!=='
95
+ });
96
+ }
97
+ if (node.operator === '!==') {
98
+ return (0, _extends2.default)({}, node, {
99
+ operator: '==='
100
+ });
101
+ }
102
+ if (node.operator === '!') {
103
+ var _node$argument;
104
+ if (((_node$argument = node.argument) == null ? void 0 : _node$argument.operator) === '!') {
105
+ return node.argument;
106
+ }
107
+ return j.unaryExpression('!', node);
108
+ }
109
+ return node;
110
+ }
111
+
112
+ /**
113
+ *
114
+ * @param {import('ast-types').namedTypes.ObjectExpression} node
115
+ */
116
+ function removeProperty(parentNode, child) {
117
+ if (parentNode) {
118
+ if (parentNode.type === 'ObjectExpression') {
119
+ parentNode.properties = parentNode.properties.filter(prop => prop !== child && prop.value !== child);
120
+ }
121
+ }
122
+ }
123
+ function buildObjectAST(jsObject) {
124
+ const result = j.objectExpression([]);
125
+ Object.entries(jsObject).forEach(([key, value]) => {
126
+ result.properties.push(j.objectProperty(j.identifier(key), value));
127
+ });
128
+ return result;
129
+ }
130
+ function buildArrowFunctionAST(params, body) {
131
+ return j.arrowFunctionExpression([j.objectPattern([...params].map(k => (0, _extends2.default)({}, j.objectProperty(j.identifier(k), j.identifier(k)), {
132
+ shorthand: true
133
+ })))], body);
134
+ }
135
+
136
+ /**
137
+ *
138
+ * @param {{ properties: any[] }} node
139
+ * @param {Record<string, any[] | import('ast-types').namedTypes.ObjectExpression>} modeStyles
140
+ */
141
+ function appendPaletteModeStyles(node, modeStyles) {
142
+ Object.entries(modeStyles).forEach(([mode, objectStyles]) => {
143
+ node.properties.push(j.spreadElement(j.callExpression(j.memberExpression(j.identifier('theme'), j.identifier('applyStyles')), [j.stringLiteral(mode), Array.isArray(objectStyles) ? j.objectExpression(objectStyles) : objectStyles])));
144
+ });
145
+ }
146
+
147
+ /**
148
+ *
149
+ * @param {import('ast-types').namedTypes.LogicalExpression | import('ast-types').namedTypes.BinaryExpression | import('ast-types').namedTypes.UnaryExpression | import('ast-types').namedTypes.MemberExpression} node
150
+ */
151
+ function buildProps(node) {
152
+ const properties = [];
153
+ const variables = new Set();
154
+ let isAllEqual = true;
155
+ let tempNode = (0, _extends2.default)({}, node);
156
+ function assignProperties(_node) {
157
+ if (_node.type === 'BinaryExpression') {
158
+ variables.add(getObjectKey(_node.left).name);
159
+ if (_node.operator === '===') {
160
+ properties.push(j.objectProperty(getIdentifierKey(_node.left), _node.right));
161
+ } else {
162
+ isAllEqual = false;
163
+ }
164
+ }
165
+ if (_node.type === 'MemberExpression' || _node.type === 'Identifier') {
166
+ isAllEqual = false;
167
+ variables.add(getObjectKey(_node).name);
168
+ }
169
+ if (_node.type === 'UnaryExpression') {
170
+ isAllEqual = false;
171
+ if (_node.argument.type === 'UnaryExpression') {
172
+ // handle `!!variable`
173
+ variables.add(getObjectKey(_node.argument.argument).name);
174
+ } else {
175
+ // handle `!variable`
176
+ variables.add(getObjectKey(_node.argument).name);
177
+ }
178
+ }
179
+ }
180
+ let counter = 0;
181
+ if (tempNode.type !== 'LogicalExpression') {
182
+ assignProperties(tempNode);
183
+ } else {
184
+ while (tempNode.type === 'LogicalExpression' && counter < MAX_DEPTH) {
185
+ counter += 1;
186
+ if (tempNode.operator !== '&&') {
187
+ isAllEqual = false;
188
+ }
189
+ assignProperties(tempNode.right);
190
+ if (tempNode.left.type !== 'LogicalExpression') {
191
+ assignProperties(tempNode.left);
192
+ break;
193
+ }
194
+ tempNode = (0, _extends2.default)({}, tempNode.left);
195
+ }
196
+ }
197
+ if (!isAllEqual) {
198
+ return buildArrowFunctionAST(variables, node);
199
+ }
200
+ return j.objectExpression(properties);
201
+ }
202
+ function mergeProps(parentProps, currentProps) {
203
+ if (parentProps.type === 'ObjectExpression' && currentProps.type === 'ObjectExpression') {
204
+ return j.objectExpression([...parentProps.properties, ...currentProps.properties]);
205
+ }
206
+ const parentArrow = parentProps.type === 'ObjectExpression' ? objectToArrowFunction(parentProps) : parentProps;
207
+ const currentArrow = currentProps.type === 'ObjectExpression' ? objectToArrowFunction(currentProps) : currentProps;
208
+ const variables = new Set();
209
+ [...parentArrow.params[0].properties, ...currentArrow.params[0].properties].forEach(param => {
210
+ variables.add(param.key.name);
211
+ });
212
+ return buildArrowFunctionAST(variables, j.logicalExpression('&&', parentArrow.body, currentArrow.body));
213
+ }
214
+ function isThemePaletteMode(node) {
215
+ return node.type === 'MemberExpression' && node.object.type === 'MemberExpression' && node.object.object.name === 'theme' && node.object.property.name === 'palette' && node.property.name === 'mode';
216
+ }
217
+
218
+ // 2. Find logical spread expressions to convert to variants
219
+ styles.forEach(style => {
220
+ const parameters = new Set();
221
+ style.params.forEach(param => {
222
+ if (param.type === 'ObjectPattern') {
223
+ param.properties.forEach(prop => {
224
+ parameters.add(prop.key.name);
225
+ });
226
+ }
227
+ });
228
+ const variants = [];
229
+ if (style.body.type === 'LogicalExpression') {
230
+ if (style.params[0] && style.params[0].type === 'ObjectPattern' && style.params[0].properties.some(prop => prop.key.name !== 'theme')) {
231
+ // case: ({ theme, ownerState }) => ownerState.variant === 'regular' && theme.mixins.toolbar
232
+ style.body = j.objectExpression([j.objectProperty(j.identifier('variants'), j.arrayExpression([j.objectExpression([j.objectProperty(j.identifier('props'), buildProps(style.body.left)), j.objectProperty(j.identifier('style'), style.body.right)])]))]);
233
+ }
234
+ } else if (style.body.type === 'ConditionalExpression') {
235
+ // skip ConditionalExpression
236
+ } else {
237
+ let objectExpression = style.body;
238
+ let counter = 0;
239
+ while (objectExpression.type !== 'ObjectExpression' && counter < MAX_DEPTH) {
240
+ counter += 1;
241
+ if (objectExpression.type === 'BlockStatement') {
242
+ objectExpression = objectExpression.body.find(item => item.type === 'ReturnStatement').argument;
243
+ }
244
+ }
245
+ recurseObjectExpression({
246
+ node: objectExpression,
247
+ buildStyle: createBuildStyle()
248
+ });
249
+ if (variants.length) {
250
+ objectExpression.properties.push(j.objectProperty(j.identifier('variants'), j.arrayExpression(variants.filter(variant => {
251
+ const props = variant.properties.find(prop => prop.key.name === 'props');
252
+ const styleVal = variant.properties.find(prop => prop.key.name === 'style');
253
+ return props && styleVal && (!styleVal.value.properties || styleVal.value.properties.length > 0) && (props.value.type === 'ArrowFunctionExpression' || props.value.properties.length > 0);
254
+ }))));
255
+ }
256
+ }
257
+ function recurseObjectExpression(data) {
258
+ if (data.node.type === 'ObjectExpression') {
259
+ const modeStyles = {}; // to collect styles from `theme.palette.mode === '...'`
260
+ data.node.properties.forEach(prop => {
261
+ if (prop.type === 'ObjectProperty') {
262
+ recurseObjectExpression((0, _extends2.default)({}, data, {
263
+ node: prop.value,
264
+ parentNode: data.node,
265
+ key: prop.key,
266
+ buildStyle: createBuildStyle(prop.key, data.buildStyle),
267
+ replaceValue: newValue => {
268
+ prop.value = newValue;
269
+ },
270
+ modeStyles
271
+ }));
272
+ } else {
273
+ recurseObjectExpression((0, _extends2.default)({}, data, {
274
+ node: prop,
275
+ parentNode: data.node,
276
+ buildStyle: createBuildStyle(prop.key, data.buildStyle)
277
+ }));
278
+ }
279
+ });
280
+ appendPaletteModeStyles(data.node, modeStyles);
281
+ }
282
+ if (data.node.type === 'SpreadElement') {
283
+ if (data.node.argument.type === 'LogicalExpression') {
284
+ var _getObjectKey, _getObjectKey2;
285
+ const paramName = data.node.argument.left.type === 'BinaryExpression' ? (_getObjectKey = getObjectKey(data.node.argument.left.left)) == null ? void 0 : _getObjectKey.name : (_getObjectKey2 = getObjectKey(data.node.argument.left)) == null ? void 0 : _getObjectKey2.name;
286
+ if (paramName === 'theme' && data.node.argument.left.right.type === 'StringLiteral') {
287
+ if (data.node.argument.right.type === 'ObjectExpression') {
288
+ const mode = data.node.argument.left.right.value;
289
+ data.node.argument.right.properties.forEach(prop => {
290
+ if (prop.type === 'ObjectProperty') {
291
+ recurseObjectExpression((0, _extends2.default)({}, data, {
292
+ node: prop.value,
293
+ parentNode: data.node.argument.right,
294
+ key: prop.key,
295
+ buildStyle: createBuildStyle(prop.key, data.buildStyle, mode),
296
+ replaceValue: newValue => {
297
+ prop.value = newValue;
298
+ }
299
+ }));
300
+ } else {
301
+ recurseObjectExpression((0, _extends2.default)({}, data, {
302
+ node: prop,
303
+ parentNode: data.node.argument.right,
304
+ buildStyle: createBuildStyle(prop.key, data.buildStyle, mode)
305
+ }));
306
+ }
307
+ });
308
+ appendPaletteModeStyles(data.parentNode, {
309
+ [mode]: data.node.argument.right
310
+ });
311
+ }
312
+ removeProperty(data.parentNode, data.node);
313
+ return;
314
+ }
315
+ if (paramName && !parameters.has(paramName)) {
316
+ return;
317
+ }
318
+ const scopeProps = buildProps(data.node.argument.left);
319
+ const variant = {
320
+ props: data.props ? mergeProps(data.props, scopeProps) : scopeProps,
321
+ style: data.node.argument.right
322
+ };
323
+ const lastLength = variants.push({}); // preserve the order of the recursive calls
324
+
325
+ const modeStyles = {}; // to collect styles from `theme.palette.mode === '...'`
326
+ if (variant.style.type === 'ObjectExpression') {
327
+ variant.style.properties.forEach(prop => {
328
+ if (prop.type === 'ObjectProperty') {
329
+ recurseObjectExpression((0, _extends2.default)({}, data, {
330
+ node: prop.value,
331
+ parentNode: variant.style,
332
+ props: variant.props,
333
+ key: prop.key,
334
+ buildStyle: createBuildStyle(prop.key, data.buildStyle),
335
+ replaceValue: newValue => {
336
+ prop.value = newValue;
337
+ },
338
+ modeStyles
339
+ }));
340
+ } else {
341
+ recurseObjectExpression((0, _extends2.default)({}, data, {
342
+ node: prop,
343
+ parentNode: variant.style,
344
+ props: variant.props,
345
+ buildStyle: createBuildStyle(prop.key, data.buildStyle)
346
+ }));
347
+ }
348
+ });
349
+ }
350
+ appendPaletteModeStyles(variant.style, modeStyles);
351
+ variant.style = data.buildStyle(variant.style);
352
+ variants[lastLength - 1] = buildObjectAST(variant);
353
+ removeProperty(data.parentNode, data.node);
354
+ }
355
+ if (data.node.argument.type === 'ConditionalExpression') {
356
+ recurseObjectExpression((0, _extends2.default)({}, data, {
357
+ node: data.node.argument,
358
+ parentNode: data.node
359
+ }));
360
+ removeProperty(data.parentNode, data.node);
361
+ }
362
+ }
363
+ if (data.node.type === 'ConditionalExpression') {
364
+ if (data.node.test.type === 'BinaryExpression' || data.node.test.type === 'UnaryExpression' || data.node.test.type === 'Identifier' || data.node.test.type === 'MemberExpression') {
365
+ var _getObjectKey3, _data$parentNode2, _data$node$test;
366
+ let leftName = (_getObjectKey3 = getObjectKey(data.node.test)) == null ? void 0 : _getObjectKey3.name;
367
+ if (data.node.test.left) {
368
+ var _getObjectKey4;
369
+ leftName = (_getObjectKey4 = getObjectKey(data.node.test.left)) == null ? void 0 : _getObjectKey4.name;
370
+ }
371
+ if (data.node.test.argument) {
372
+ var _getObjectKey5;
373
+ leftName = (_getObjectKey5 = getObjectKey(data.node.test.argument)) == null ? void 0 : _getObjectKey5.name;
374
+ }
375
+ if (parameters.has(leftName) && leftName !== 'theme') {
376
+ var _data$parentNode;
377
+ let props = buildProps(data.node.test);
378
+ if (data.props) {
379
+ props = mergeProps(data.props, props);
380
+ }
381
+ const styleVal = data.buildStyle(data.node.consequent);
382
+ const variant = {
383
+ props,
384
+ style: styleVal
385
+ };
386
+ variants.push(buildObjectAST(variant));
387
+
388
+ // create another variant with inverted condition
389
+ let props2 = buildProps(inverseBinaryExpression(data.node.test));
390
+ if (data.props) {
391
+ props2 = mergeProps(data.props, props2);
392
+ }
393
+ const styleVal2 = data.buildStyle(data.node.alternate);
394
+ const variant2 = {
395
+ props: props2,
396
+ style: styleVal2
397
+ };
398
+ variants.push(buildObjectAST(variant2));
399
+ if (((_data$parentNode = data.parentNode) == null ? void 0 : _data$parentNode.type) === 'ObjectExpression') {
400
+ removeProperty(data.parentNode, data.node);
401
+ }
402
+ }
403
+ if (leftName === 'theme' && ((_data$parentNode2 = data.parentNode) == null ? void 0 : _data$parentNode2.type) === 'ObjectExpression' && ((_data$node$test = data.node.test) == null ? void 0 : _data$node$test.type) === 'BinaryExpression' && isThemePaletteMode(data.node.test.left)) {
404
+ if (data.node.consequent.type !== 'ObjectExpression' && data.node.alternate.type !== 'ObjectExpression') {
405
+ var _data$replaceValue;
406
+ if (data.modeStyles) {
407
+ if (!data.modeStyles[data.node.test.right.value]) {
408
+ data.modeStyles[data.node.test.right.value] = [];
409
+ }
410
+ data.modeStyles[data.node.test.right.value].push(j.objectProperty(data.key, data.node.consequent));
411
+ }
412
+ (_data$replaceValue = data.replaceValue) == null || _data$replaceValue.call(data, data.node.alternate);
413
+ }
414
+ }
415
+ }
416
+ }
417
+ if (data.node.type === 'TemplateLiteral') {
418
+ var _data$parentNode3;
419
+ if (((_data$parentNode3 = data.parentNode) == null ? void 0 : _data$parentNode3.type) === 'ObjectExpression') {
420
+ const modeStyles = {};
421
+ data.node.expressions.forEach((expression, index) => {
422
+ recurseObjectExpression((0, _extends2.default)({}, data, {
423
+ node: expression,
424
+ parentNode: data.parentNode,
425
+ buildStyle: createBuildStyle(data.key, data.buildStyle),
426
+ replaceValue: newValue => {
427
+ data.node.expressions[index] = newValue;
428
+ },
429
+ modeStyles
430
+ }));
431
+ });
432
+ if (data.modeStyles) {
433
+ Object.entries(modeStyles).forEach(([mode, objectStyles]) => {
434
+ const clonedNode = (0, _extends2.default)({}, data.node, {
435
+ expressions: data.node.expressions.map(expression => (0, _extends2.default)({}, expression))
436
+ });
437
+ clonedNode.expressions = objectStyles.map(item => item.value);
438
+ if (!data.modeStyles[mode]) {
439
+ data.modeStyles[mode] = [];
440
+ }
441
+ data.modeStyles[mode].push(j.objectProperty(data.key, clonedNode));
442
+ });
443
+ }
444
+ }
445
+ }
446
+ if (data.key && data.key.type === 'Identifier' && data.node.type === 'MemberExpression' && data.node.object.type === 'ObjectExpression' && parameters.has(getObjectKey(data.node.property).name)) {
447
+ data.node.object.properties.forEach(prop => {
448
+ variants.push(buildObjectAST({
449
+ props: j.objectExpression([j.objectProperty(getIdentifierKey(data.node.property), j.stringLiteral(prop.key.name))]),
450
+ style: data.buildStyle(prop.value)
451
+ }));
452
+ });
453
+ removeProperty(data.parentNode, data.node);
454
+ }
455
+ }
456
+ style.params.forEach(param => {
457
+ if (param.type === 'ObjectPattern') {
458
+ param.properties = param.properties.filter(prop => prop.key.name === 'theme');
459
+ }
460
+ });
461
+ if (style.body.type === 'ObjectExpression') {
462
+ // Remove empty `...theme.applyStyles('...', {})`
463
+ style.body.properties = style.body.properties.filter(prop => {
464
+ var _prop$argument, _prop$argument2, _prop$argument3;
465
+ if (((_prop$argument = prop.argument) == null || (_prop$argument = _prop$argument.callee) == null || (_prop$argument = _prop$argument.object) == null ? void 0 : _prop$argument.name) === 'theme' && typeof ((_prop$argument2 = prop.argument) == null || (_prop$argument2 = _prop$argument2.arguments[0]) == null ? void 0 : _prop$argument2.value) === 'string' && !((_prop$argument3 = prop.argument) != null && (_prop$argument3 = _prop$argument3.arguments) != null && (_prop$argument3 = _prop$argument3[1]) != null && (_prop$argument3 = _prop$argument3.properties) != null && _prop$argument3.length)) {
466
+ return false;
467
+ }
468
+ return true;
469
+ });
470
+ }
471
+ });
472
+ }