@atlaskit/codemod-cli 0.24.1 → 0.24.3

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +335 -320
  2. package/dist/cjs/main.js +1 -1
  3. package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +126 -50
  4. package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-split-imports.js +25 -9
  5. package/dist/cjs/presets/migrate-to-new-buttons/utils/constants.js +16 -3
  6. package/dist/cjs/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +14 -5
  7. package/dist/cjs/presets/migrate-to-new-buttons/utils/get-default-imports.js +14 -0
  8. package/dist/cjs/presets/migrate-to-new-buttons/utils/get-specifier-names.js +14 -0
  9. package/dist/cjs/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +15 -7
  10. package/dist/cjs/presets/migrate-to-new-buttons/utils/rename-elements.js +18 -0
  11. package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +119 -46
  12. package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-split-imports.js +25 -9
  13. package/dist/es2019/presets/migrate-to-new-buttons/utils/constants.js +16 -2
  14. package/dist/es2019/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +12 -5
  15. package/dist/es2019/presets/migrate-to-new-buttons/utils/get-default-imports.js +6 -0
  16. package/dist/es2019/presets/migrate-to-new-buttons/utils/get-specifier-names.js +6 -0
  17. package/dist/es2019/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +9 -3
  18. package/dist/es2019/presets/migrate-to-new-buttons/utils/rename-elements.js +12 -0
  19. package/dist/esm/main.js +1 -1
  20. package/dist/esm/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +126 -51
  21. package/dist/esm/presets/migrate-to-new-buttons/codemods/next-split-imports.js +25 -9
  22. package/dist/esm/presets/migrate-to-new-buttons/utils/constants.js +15 -2
  23. package/dist/esm/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +14 -5
  24. package/dist/esm/presets/migrate-to-new-buttons/utils/get-default-imports.js +8 -0
  25. package/dist/esm/presets/migrate-to-new-buttons/utils/get-specifier-names.js +8 -0
  26. package/dist/esm/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +14 -6
  27. package/dist/esm/presets/migrate-to-new-buttons/utils/rename-elements.js +12 -0
  28. package/dist/types/main.d.ts +1 -1
  29. package/dist/types/presets/migrate-to-new-buttons/utils/constants.d.ts +11 -1
  30. package/dist/types/presets/migrate-to-new-buttons/utils/get-default-imports.d.ts +5 -0
  31. package/dist/types/presets/migrate-to-new-buttons/utils/get-specifier-names.d.ts +5 -0
  32. package/dist/types/presets/migrate-to-new-buttons/utils/if-variant-already-imported.d.ts +2 -1
  33. package/dist/types/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.d.ts +1 -1
  34. package/dist/types/presets/migrate-to-new-buttons/utils/rename-elements.d.ts +2 -0
  35. package/dist/types/presets/styled-to-emotion/styled-to-emotion.d.ts +1 -1
  36. package/dist/types/presets/theme-remove-deprecated-mixins/theme-remove-deprecated-mixins.d.ts +1 -1
  37. package/dist/types/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.d.ts +1 -1
  38. package/dist/types/sinceRef.d.ts +1 -1
  39. package/dist/types/transforms.d.ts +2 -2
  40. package/dist/types/types.d.ts +1 -1
  41. package/dist/types-ts4.5/main.d.ts +1 -1
  42. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/constants.d.ts +11 -1
  43. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/get-default-imports.d.ts +5 -0
  44. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/get-specifier-names.d.ts +5 -0
  45. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/if-variant-already-imported.d.ts +2 -1
  46. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.d.ts +1 -1
  47. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/rename-elements.d.ts +2 -0
  48. package/dist/types-ts4.5/presets/styled-to-emotion/styled-to-emotion.d.ts +1 -1
  49. package/dist/types-ts4.5/presets/theme-remove-deprecated-mixins/theme-remove-deprecated-mixins.d.ts +1 -1
  50. package/dist/types-ts4.5/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.d.ts +1 -1
  51. package/dist/types-ts4.5/sinceRef.d.ts +1 -1
  52. package/dist/types-ts4.5/transforms.d.ts +2 -2
  53. package/dist/types-ts4.5/types.d.ts +1 -1
  54. package/package.json +3 -5
@@ -1,6 +1,9 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import { addCommentBefore } from '@atlaskit/codemod-utils';
2
3
  import { getDefaultImportSpecifierName } from '@hypermod/utils';
3
- import { PRINT_SETTINGS, NEW_BUTTON_VARIANTS, entryPointsMapping, NEW_BUTTON_ENTRY_POINT, linkButtonMissingHrefComment, buttonPropsNoLongerSupportedComment, unsupportedProps } from '../utils/constants';
4
+ import { PRINT_SETTINGS, OLD_BUTTON_VARIANTS, NEW_BUTTON_VARIANTS, entryPointsMapping, OLD_BUTTON_ENTRY_POINT, NEW_BUTTON_ENTRY_POINT, linkButtonMissingHrefComment, buttonPropsNoLongerSupportedComment, unsupportedProps, loadingButtonComment } from '../utils/constants';
5
+ import getDefaultImports from '../utils/get-default-imports';
6
+ import getSpecifierNames from '../utils/get-specifier-names';
4
7
  import { generateNewElement, handleIconAttributes } from '../utils/generate-new-button-element';
5
8
  import { ifHasUnsupportedProps } from '../utils/has-unsupported-props';
6
9
  import { checkIfVariantAlreadyImported } from '../utils/if-variant-already-imported';
@@ -12,30 +15,44 @@ var transformer = function transformer(file, api) {
12
15
  var j = api.jscodeshift;
13
16
  var fileSource = j(file.source);
14
17
  addCommentForCustomThemeButtons(fileSource, j);
15
- var buttonImports = fileSource.find(j.ImportDeclaration).filter(function (path) {
16
- return path.node.source.value === entryPointsMapping.Button || path.node.source.value === entryPointsMapping.LoadingButton || path.node.source.value === NEW_BUTTON_ENTRY_POINT;
18
+
19
+ // Find old buttons
20
+ var oldButtonImports = fileSource.find(j.ImportDeclaration).filter(function (path) {
21
+ return path.node.source.value === entryPointsMapping.Button || path.node.source.value === entryPointsMapping.LoadingButton || path.node.source.value === OLD_BUTTON_ENTRY_POINT;
17
22
  });
18
- if (!buttonImports.length) {
23
+ if (!oldButtonImports.length) {
19
24
  return fileSource.toSource();
20
25
  }
21
- var defaultButtonImport = buttonImports.find(j.Specifier).filter(function (path) {
22
- return path.node.type === 'ImportDefaultSpecifier';
26
+ var oldDefaultDefaultImports = getDefaultImports(oldButtonImports, j);
27
+ var oldDefaultImportSpecifiers = getSpecifierNames(oldDefaultDefaultImports);
28
+
29
+ // Find new buttons
30
+ var newButtonImports = fileSource.find(j.ImportDeclaration).filter(function (path) {
31
+ return path.node.source.value === NEW_BUTTON_ENTRY_POINT;
23
32
  });
24
- if (defaultButtonImport.length === 0) {
25
- return fileSource.toSource();
26
- }
27
- var specifierIdentifier = defaultButtonImport.get(0).node.local.name;
28
- var hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon, fileSource, j);
29
- var hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link, fileSource, j);
30
- var hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon, fileSource, j);
31
- var allButtons = fileSource.find(j.JSXElement).filter(function (path) {
32
- return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier;
33
+ var newDefaultDefaultImports = getDefaultImports(newButtonImports, j);
34
+ var newDefaultImportSpecifiers = getSpecifierNames(newDefaultDefaultImports);
35
+ var loadingButtonDirectImportName = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping.LoadingButton);
36
+
37
+ /**
38
+ * Which variants should be in this file?
39
+ *
40
+ * Any variants enabled here will be added to the final import statement.
41
+ * Initial values check if the variant is already imported in the file.
42
+ */
43
+ var hasVariant = {
44
+ defaultButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.default, NEW_BUTTON_ENTRY_POINT, fileSource, j, true),
45
+ linkButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link, NEW_BUTTON_ENTRY_POINT, fileSource, j),
46
+ iconButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon, NEW_BUTTON_ENTRY_POINT, fileSource, j),
47
+ linkIconButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon, NEW_BUTTON_ENTRY_POINT, fileSource, j)
48
+ };
49
+ var oldButtonElements = fileSource.find(j.JSXElement).filter(function (path) {
50
+ return path.value.openingElement.name.type === 'JSXIdentifier' && ((oldDefaultImportSpecifiers === null || oldDefaultImportSpecifiers === void 0 ? void 0 : oldDefaultImportSpecifiers.includes(path.value.openingElement.name.name)) || Object.values(OLD_BUTTON_VARIANTS).includes(path.value.openingElement.name.name));
33
51
  });
34
- var buttonsWithoutUnsupportedProps = allButtons.filter(function (path) {
52
+ var oldButtonsWithoutUnsupportedProps = oldButtonElements.filter(function (path) {
35
53
  return !ifHasUnsupportedProps(path.value.openingElement.attributes);
36
54
  });
37
- var loadingButtonImportName = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping.LoadingButton);
38
- buttonsWithoutUnsupportedProps.forEach(function (element) {
55
+ oldButtonsWithoutUnsupportedProps.forEach(function (element) {
39
56
  var _element$value$childr;
40
57
  var attributes = element.value.openingElement.attributes;
41
58
  if (!attributes) {
@@ -51,9 +68,14 @@ var transformer = function transformer(file, api) {
51
68
  var isLinkIconButton = hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
52
69
  var isLinkButton = hasHref && !isLinkIconButton;
53
70
  var isIconButton = !hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
54
- var isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && !isFitContainerIconButton && hasIcon;
55
- var isLoadingButton = element.value.openingElement.name.type === 'JSXIdentifier' && element.value.openingElement.name.name === loadingButtonImportName;
56
- if (isDefaultButtonWithAnIcon) {
71
+ var isDefaultButton = !isLinkButton && !isLinkIconButton && !isIconButton && !isFitContainerIconButton;
72
+ var isDefaultVariantWithAnIcon = !isLinkIconButton && !isIconButton && !isFitContainerIconButton && hasIcon;
73
+ var isLoadingButton = element.value.openingElement.name.type === 'JSXIdentifier' && element.value.openingElement.name.name === loadingButtonDirectImportName;
74
+ var linkAppearanceAttribute = attributes.find(function (node) {
75
+ var _node$value, _node$name, _node$value2, _node$value3;
76
+ return node.type === 'JSXAttribute' && ((_node$value = node.value) === null || _node$value === void 0 ? void 0 : _node$value.type) === 'StringLiteral' && (node === null || node === void 0 || (_node$name = node.name) === null || _node$name === void 0 ? void 0 : _node$name.name) === 'appearance' && ((node === null || node === void 0 || (_node$value2 = node.value) === null || _node$value2 === void 0 ? void 0 : _node$value2.value) === 'link' || (node === null || node === void 0 || (_node$value3 = node.value) === null || _node$value3 === void 0 ? void 0 : _node$value3.value) === 'subtle-link');
77
+ });
78
+ if (isDefaultVariantWithAnIcon) {
57
79
  handleIconAttributes(element.value, j);
58
80
  }
59
81
  if (isFitContainerIconButton) {
@@ -62,73 +84,86 @@ var transformer = function transformer(file, api) {
62
84
  isIconButton = true;
63
85
  }
64
86
  }
65
- if (isLinkIconButton) {
66
- hasLinkIconButton = true;
87
+ if (isLinkIconButton && !isLoadingButton) {
88
+ hasVariant.linkIconButton = true;
67
89
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.linkIcon, element.value, j));
68
90
  }
69
- if (isIconButton) {
70
- hasIconButton = true;
91
+ if (isIconButton && !isLoadingButton) {
92
+ hasVariant.iconButton = true;
71
93
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.icon, element.value, j));
72
94
  }
73
- if (isLinkButton) {
74
- hasLinkButton = true;
95
+ if (isLinkButton && !isLoadingButton) {
96
+ hasVariant.linkButton = true;
75
97
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.link, element.value, j));
76
98
  }
77
- if (isLoadingButton) {
78
- j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.default, element.value, j));
99
+ if (isDefaultButton && !isLoadingButton) {
100
+ hasVariant.defaultButton = true;
101
+ j(element).replaceWith(generateNewElement(newDefaultImportSpecifiers !== null && newDefaultImportSpecifiers !== void 0 && newDefaultImportSpecifiers.length ?
102
+ // If new button already has a default import, use that incase it's aliased
103
+ newDefaultImportSpecifiers[0] : NEW_BUTTON_VARIANTS.default, element.value, j));
79
104
  }
80
- var linkAppearanceAttribute = attributes.find(function (node) {
81
- var _node$value, _node$name, _node$value2, _node$value3;
82
- return node.type === 'JSXAttribute' && ((_node$value = node.value) === null || _node$value === void 0 ? void 0 : _node$value.type) === 'StringLiteral' && (node === null || node === void 0 || (_node$name = node.name) === null || _node$name === void 0 ? void 0 : _node$name.name) === 'appearance' && ((node === null || node === void 0 || (_node$value2 = node.value) === null || _node$value2 === void 0 ? void 0 : _node$value2.value) === 'link' || (node === null || node === void 0 || (_node$value3 = node.value) === null || _node$value3 === void 0 ? void 0 : _node$value3.value) === 'subtle-link');
83
- });
84
- if (!hasHref && linkAppearanceAttribute) {
105
+ if (isLoadingButton) {
106
+ var newElement = generateNewElement(NEW_BUTTON_VARIANTS[isIconButton || isLinkIconButton ? 'icon' : 'default'], element.value, j);
107
+ if (isIconButton || isLinkIconButton) {
108
+ hasVariant.iconButton = true;
109
+ } else {
110
+ hasVariant.defaultButton = true;
111
+ }
112
+ j(element).replaceWith(newElement);
113
+ if (hasHref || linkAppearanceAttribute) {
114
+ addCommentBefore(j, j(newElement), loadingButtonComment({
115
+ hasHref: hasHref,
116
+ hasLinkAppearance: Boolean(linkAppearanceAttribute)
117
+ }), 'block');
118
+ }
119
+ } else if (!hasHref && linkAppearanceAttribute) {
85
120
  addCommentBefore(j, j(linkAppearanceAttribute), linkButtonMissingHrefComment, 'line');
86
121
  }
87
122
  });
88
123
 
89
124
  // modify import declarations
90
125
  var specifiers = [];
91
- [hasLinkButton ? 'link' : null, hasIconButton ? 'icon' : null, hasLinkIconButton ? 'linkIcon' : null].forEach(function (variant) {
126
+ [hasVariant.linkButton ? 'link' : null, hasVariant.iconButton ? 'icon' : null, hasVariant.linkIconButton ? 'linkIcon' : null].forEach(function (variant) {
92
127
  if (variant) {
93
128
  specifiers.push(j.importSpecifier(j.identifier(NEW_BUTTON_VARIANTS[variant])));
94
129
  }
95
130
  });
96
- var oldButtonImport = fileSource.find(j.ImportDeclaration).filter(function (path) {
97
- return path.node.source.value === NEW_BUTTON_ENTRY_POINT || path.node.source.value === entryPointsMapping.Button || path.node.source.value === entryPointsMapping.LoadingButton;
98
- });
99
131
  var remainingDefaultButtons = fileSource.find(j.JSXElement).filter(function (path) {
100
- return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier && !ifHasUnsupportedProps(path.value.openingElement.attributes);
132
+ return path.value.openingElement.name.type === 'JSXIdentifier' && Boolean(oldDefaultImportSpecifiers === null || oldDefaultImportSpecifiers === void 0 ? void 0 : oldDefaultImportSpecifiers.includes(path.value.openingElement.name.name)) && !ifHasUnsupportedProps(path.value.openingElement.attributes);
101
133
  }).length > 0 || fileSource.find(j.CallExpression).filter(function (path) {
102
134
  return path.node.arguments.map(function (argument) {
103
135
  return argument.type === 'Identifier' && (argument === null || argument === void 0 ? void 0 : argument.name);
104
- }).includes(specifierIdentifier);
136
+ }).some(function (name) {
137
+ return name && (oldDefaultImportSpecifiers === null || oldDefaultImportSpecifiers === void 0 ? void 0 : oldDefaultImportSpecifiers.includes(name));
138
+ });
105
139
  }).length > 0;
106
140
 
107
141
  // Loading buttons map back to default imports
108
- if (specifierIdentifier === loadingButtonImportName) {
142
+ if (loadingButtonDirectImportName && oldDefaultImportSpecifiers !== null && oldDefaultImportSpecifiers !== void 0 && oldDefaultImportSpecifiers.includes(loadingButtonDirectImportName)) {
109
143
  fileSource
110
144
  // rename LoadingButton to Button in all call expressions i.e. render(LoadingButton), find(LoadingButton)
111
145
  .find(j.CallExpression).find(j.Identifier).forEach(function (path) {
112
- if (path.node.name === loadingButtonImportName) {
146
+ if (path.node.name === loadingButtonDirectImportName) {
113
147
  path.node.name = NEW_BUTTON_VARIANTS.default;
114
148
  }
115
149
  });
116
- specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
117
150
  }
118
- if (!specifiers.find(function (specifier) {
151
+
152
+ // Only add the Button import if we found a default button, not icon only
153
+ if (hasVariant.defaultButton || !specifiers.find(function (specifier) {
119
154
  return specifier.type === 'ImportDefaultSpecifier';
120
155
  }) && remainingDefaultButtons) {
121
156
  specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
122
157
  }
123
158
 
124
159
  // update import path for types imports
125
- specifiers = importTypesFromNewEntryPoint(buttonImports, specifiers, j, fileSource);
126
- var buttonsWithUnsupportedProps = allButtons.filter(function (path) {
160
+ specifiers = importTypesFromNewEntryPoint(oldButtonImports, specifiers, j, fileSource);
161
+ var oldButtonsWithUnsupportedProps = oldButtonElements.filter(function (path) {
127
162
  return ifHasUnsupportedProps(path.value.openingElement.attributes);
128
163
  });
129
- if (buttonsWithUnsupportedProps.length) {
164
+ if (oldButtonsWithUnsupportedProps.length) {
130
165
  // add comment to all buttons with unsupported props: "component", "style", "css"
131
- buttonsWithUnsupportedProps.forEach(function (element) {
166
+ oldButtonsWithUnsupportedProps.forEach(function (element) {
132
167
  var _element$value$openin;
133
168
  var attribute = (_element$value$openin = element.value.openingElement.attributes) === null || _element$value$openin === void 0 ? void 0 : _element$value$openin.find(function (node) {
134
169
  return node.type === 'JSXAttribute' && typeof node.name.name === 'string' && unsupportedProps.includes(node.name.name);
@@ -142,16 +177,56 @@ var transformer = function transformer(file, api) {
142
177
  if (specifiers.find(function (specifier) {
143
178
  return specifier.type === 'ImportDefaultSpecifier';
144
179
  })) {
145
- renameDefaultButtonToLegacyButtonImport(oldButtonImport, buttonsWithUnsupportedProps, j);
180
+ renameDefaultButtonToLegacyButtonImport(oldButtonImports, oldButtonsWithUnsupportedProps, j);
146
181
  }
147
182
  }
148
183
  if (specifiers.length) {
184
+ var existingNewButtonImports = fileSource.find(j.ImportDeclaration).filter(function (path) {
185
+ return path.node.source.value === NEW_BUTTON_ENTRY_POINT;
186
+ });
149
187
  var newButtonImport = j.importDeclaration(specifiers, j.stringLiteral(NEW_BUTTON_ENTRY_POINT));
150
- oldButtonImport.forEach(function (path) {
188
+ oldButtonImports.forEach(function (path) {
151
189
  var _path$node;
152
190
  newButtonImport.comments = path !== null && path !== void 0 && (_path$node = path.node) !== null && _path$node !== void 0 && _path$node.comments ? path.node.comments : undefined;
153
191
  });
154
- oldButtonImport.replaceWith(newButtonImport);
192
+ if (existingNewButtonImports.length) {
193
+ existingNewButtonImports.forEach(function (path) {
194
+ // Merge specifiers from existing new button import with added specifiers
195
+ var mergedSpecifiers = [].concat(_toConsumableArray(specifiers.filter(function (specifier) {
196
+ var _path$node$specifiers;
197
+ if (specifier.type !== 'ImportDefaultSpecifier') {
198
+ return true;
199
+ }
200
+
201
+ // Ensure we don't add a duplicate default specifier if one is already imported
202
+ return !((_path$node$specifiers = path.node.specifiers) !== null && _path$node$specifiers !== void 0 && _path$node$specifiers.find(function (s) {
203
+ return s.type === 'ImportDefaultSpecifier';
204
+ }));
205
+ })), _toConsumableArray(path.node.specifiers ? path.node.specifiers : [])) // Filter duplicates
206
+ .filter(function (specifier) {
207
+ if (specifier.type === 'ImportDefaultSpecifier') {
208
+ return true;
209
+ }
210
+ var isAlreadyImported = specifiers.find(function (s) {
211
+ var _specifier$local;
212
+ return s.type === 'ImportSpecifier' && s.imported.name === ((_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name);
213
+ });
214
+ return !isAlreadyImported;
215
+ });
216
+ newButtonImport = j.importDeclaration(mergedSpecifiers, j.stringLiteral(NEW_BUTTON_ENTRY_POINT));
217
+ });
218
+ oldButtonImports.remove();
219
+ existingNewButtonImports.replaceWith(newButtonImport);
220
+ } else {
221
+ oldButtonImports.replaceWith(function (_, index) {
222
+ // Only replace the first import
223
+ if (index === 0) {
224
+ return newButtonImport;
225
+ }
226
+ // Remove the rest
227
+ return null;
228
+ });
229
+ }
155
230
  }
156
231
 
157
232
  // remove empty import declarations
@@ -1,5 +1,7 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  import { PRINT_SETTINGS, entryPointsMapping, BUTTON_TYPES, NEW_BUTTON_ENTRY_POINT } from '../utils/constants';
3
+ import renameElements from '../utils/rename-elements';
4
+ import { getDefaultImportSpecifierName } from '@hypermod/utils';
3
5
  var transformer = function transformer(file, api) {
4
6
  var j = api.jscodeshift;
5
7
  var fileSource = j(file.source);
@@ -16,6 +18,8 @@ var transformer = function transformer(file, api) {
16
18
  var _node$node = node.node,
17
19
  specifiers = _node$node.specifiers,
18
20
  source = _node$node.source;
21
+
22
+ // Return early if the import is not a named import
19
23
  if ([].concat(_toConsumableArray(Object.values(entryPointsMapping)), [NEW_BUTTON_ENTRY_POINT, '@atlaskit/button/types']).includes(source.value)) {
20
24
  return fileSource.toSource(PRINT_SETTINGS);
21
25
  }
@@ -23,16 +27,22 @@ var transformer = function transformer(file, api) {
23
27
  return specifier.type === 'ImportDefaultSpecifier';
24
28
  });
25
29
  if (defaultSpecifier && defaultSpecifier.local) {
26
- var defaultButtonImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(defaultSpecifier.local.name))], j.stringLiteral(entryPointsMapping.Button));
27
- j(node).insertAfter(defaultButtonImport);
30
+ var existingSpecifier = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping.Button);
31
+ if (existingSpecifier) {
32
+ var _defaultSpecifier$loc;
33
+ renameElements((_defaultSpecifier$loc = defaultSpecifier.local) === null || _defaultSpecifier$loc === void 0 ? void 0 : _defaultSpecifier$loc.name, existingSpecifier, fileSource, j);
34
+ } else {
35
+ var newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(defaultSpecifier.local.name))], j.stringLiteral(entryPointsMapping.Button));
36
+ j(node).insertAfter(newImport);
37
+ }
28
38
  }
29
- var valueSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(function (specifier) {
39
+ var namedSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(function (specifier) {
30
40
  return specifier.type === 'ImportSpecifier';
31
41
  });
32
- var newTypeSpecifier = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(function (specifier) {
42
+ var newTypeSpecifier = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(function (specifier) {
33
43
  return specifier.type === 'ImportSpecifier' && (specifier.imported.name === 'Appearance' || specifier.imported.name === 'Spacing');
34
44
  });
35
- var otherTypeSpecifiers = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(function (specifier) {
45
+ var otherTypeSpecifiers = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(function (specifier) {
36
46
  return BUTTON_TYPES.includes(specifier.imported.name);
37
47
  });
38
48
  if (newTypeSpecifier !== null && newTypeSpecifier !== void 0 && newTypeSpecifier.length) {
@@ -43,11 +53,17 @@ var transformer = function transformer(file, api) {
43
53
  var _typeImport = j.importDeclaration(otherTypeSpecifiers, j.stringLiteral('@atlaskit/button'));
44
54
  j(node).insertAfter(_typeImport);
45
55
  }
46
- if (valueSpecifiers !== null && valueSpecifiers !== void 0 && valueSpecifiers.length) {
47
- valueSpecifiers.forEach(function (specifier) {
56
+ if (namedSpecifiers !== null && namedSpecifiers !== void 0 && namedSpecifiers.length) {
57
+ namedSpecifiers.forEach(function (specifier) {
48
58
  if (specifier.local && specifier.type === 'ImportSpecifier' && specifier.local.name && entryPointsMapping[specifier.imported.name]) {
49
- var newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(specifier.local.name))], j.stringLiteral(entryPointsMapping[specifier.imported.name]));
50
- j(node).insertAfter(newImport);
59
+ var _existingSpecifier = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping[specifier.imported.name]);
60
+ if (_existingSpecifier) {
61
+ var _specifier$local;
62
+ renameElements((_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name, _existingSpecifier, fileSource, j);
63
+ } else {
64
+ var _newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(specifier.local.name))], j.stringLiteral(entryPointsMapping[specifier.imported.name]));
65
+ j(node).insertAfter(_newImport);
66
+ }
51
67
  }
52
68
  });
53
69
  }
@@ -1,13 +1,21 @@
1
1
  export var PRINT_SETTINGS = {
2
2
  quote: 'single'
3
3
  };
4
+
5
+ /** NEW button **/
6
+ export var NEW_BUTTON_ENTRY_POINT = '@atlaskit/button/new';
4
7
  export var NEW_BUTTON_VARIANTS = {
5
8
  default: 'Button',
6
9
  link: 'LinkButton',
7
10
  icon: 'IconButton',
8
11
  linkIcon: 'LinkIconButton'
9
12
  };
10
- export var NEW_BUTTON_ENTRY_POINT = '@atlaskit/button/new';
13
+
14
+ /** OLD button **/
15
+ export var OLD_BUTTON_ENTRY_POINT = '@atlaskit/button';
16
+ export var OLD_BUTTON_VARIANTS = {
17
+ loading: 'LoadingButton'
18
+ };
11
19
  export var entryPointsMapping = {
12
20
  Button: '@atlaskit/button/standard-button',
13
21
  LoadingButton: '@atlaskit/button/loading-button',
@@ -25,4 +33,9 @@ export var linkButtonMissingHrefComment = "\"link\" and \"subtle-link\" appearan
25
33
  export var buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
26
34
  export var migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
27
35
  export var migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
28
- export var customThemeButtonComment = "CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.";
36
+ export var customThemeButtonComment = "CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.";
37
+ export var loadingButtonComment = function loadingButtonComment(_ref) {
38
+ var hasLinkAppearance = _ref.hasLinkAppearance,
39
+ hasHref = _ref.hasHref;
40
+ return "This should be migrated to a new Button with a `isLoading` prop. ".concat(hasLinkAppearance ? "\"link\" and \"subtle-link\" appearances are not available for new loading buttons.\"" : '').concat(hasHref ? "The `href` attribute it not compatible with new loading buttons, because links should not need loading states." : '', " Please reconsider the design or change the appearance of the button.");
41
+ };
@@ -51,7 +51,10 @@ export var handleIconAttributes = function handleIconAttributes(element, j) {
51
51
  var buttonAlreadyHasLabelProp = buttonAttributes === null || buttonAttributes === void 0 ? void 0 : buttonAttributes.find(function (buttonAttribute) {
52
52
  return buttonAttribute.type === 'JSXAttribute' && buttonAttribute.name.name === 'label';
53
53
  });
54
- if (!buttonAlreadyHasLabelProp) {
54
+ var buttonAlreadyHasAriaLabelProp = buttonAttributes === null || buttonAttributes === void 0 ? void 0 : buttonAttributes.find(function (buttonAttribute) {
55
+ return buttonAttribute.type === 'JSXAttribute' && buttonAttribute.name.name === 'aria-label';
56
+ });
57
+ if (!buttonAlreadyHasLabelProp && !buttonAlreadyHasAriaLabelProp) {
55
58
  var labelAttribute = iconAttributes.find(function (attribute) {
56
59
  return attribute.type === 'JSXAttribute' && attribute.name.name === 'label';
57
60
  });
@@ -117,12 +120,18 @@ export var generateNewElement = function generateNewElement(variant, element, j)
117
120
  return attribute.type === 'JSXAttribute' && attribute.name.name === 'label';
118
121
  }));
119
122
  if (hasNoLabelProp && attributes) {
120
- attributes.push(j.jsxAttribute(j.jsxIdentifier('label'), ariaLabelAttr.get().node.value));
123
+ attributes.unshift(j.jsxAttribute.from({
124
+ name: j.jsxIdentifier('label'),
125
+ value: j.literal(ariaLabelAttr.get().value.value.value)
126
+ }));
121
127
  }
122
128
  ariaLabelAttr.remove();
123
129
  }
124
130
  }
125
- return j.jsxElement(
126
- // self closing if it's an icon button or icon link button
127
- j.jsxOpeningElement(j.jsxIdentifier(variant), attributes, isIconOrLinkIcon), isIconOrLinkIcon ? null : j.jsxClosingElement(j.jsxIdentifier(variant)), element.children);
131
+ return j.jsxElement.from({
132
+ openingElement: j.jsxOpeningElement(j.jsxIdentifier(variant), attributes, isIconOrLinkIcon),
133
+ // self closing if it's an icon button or icon link button
134
+ closingElement: isIconOrLinkIcon ? null : j.jsxClosingElement(j.jsxIdentifier(variant)),
135
+ children: element.children
136
+ });
128
137
  };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns default import specifiers from the given import declarations.
3
+ */
4
+ export default function getDefaultImports(importDeclarations, j) {
5
+ return importDeclarations.find(j.Specifier).filter(function (path) {
6
+ return path.node.type === 'ImportDefaultSpecifier';
7
+ });
8
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns a list of specifier names from the given specifiers.
3
+ */
4
+ export default function getSpecifierNames(specifiers) {
5
+ return specifiers.length ? specifiers.paths().map(function (path) {
6
+ return path.get().value.local.name;
7
+ }) : undefined;
8
+ }
@@ -1,8 +1,16 @@
1
- import { NEW_BUTTON_ENTRY_POINT } from './constants';
2
- export var checkIfVariantAlreadyImported = function checkIfVariantAlreadyImported(variant, fileSource, j) {
3
- return fileSource.find(j.ImportDeclaration).filter(function (path) {
4
- return path.node.source.value === NEW_BUTTON_ENTRY_POINT;
5
- }).find(j.ImportSpecifier).filter(function (path) {
1
+ export var findVariantAlreadyImported = function findVariantAlreadyImported(variant, entryPoint, fileSource, j) {
2
+ var isDefaultSpecifier = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
3
+ var imports = fileSource.find(j.ImportDeclaration).filter(function (path) {
4
+ return path.node.source.value === entryPoint;
5
+ });
6
+ if (isDefaultSpecifier) {
7
+ return imports.find(j.ImportDefaultSpecifier);
8
+ }
9
+ return imports.find(j.ImportSpecifier).filter(function (path) {
6
10
  return path.node.imported.name === variant;
7
- }).length > 0;
11
+ });
12
+ };
13
+ export var checkIfVariantAlreadyImported = function checkIfVariantAlreadyImported(variant, entryPoint, fileSource, j) {
14
+ var isDefaultSpecifier = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
15
+ return findVariantAlreadyImported(variant, entryPoint, fileSource, j, isDefaultSpecifier).length > 0;
8
16
  };
@@ -0,0 +1,12 @@
1
+ export default function renameElements(elementName, newElementName, fileSource, j) {
2
+ var oldElements = fileSource.find(j.JSXElement).filter(function (path) {
3
+ return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === elementName;
4
+ });
5
+
6
+ // Rename elements to match existing import name
7
+ oldElements.forEach(function (element) {
8
+ var _element$value$childr, _element$value$childr2;
9
+ var newElement = j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier(newElementName), element.value.openingElement.attributes, ((_element$value$childr = element.value.children) === null || _element$value$childr === void 0 ? void 0 : _element$value$childr.length) === 0), ((_element$value$childr2 = element.value.children) === null || _element$value$childr2 === void 0 ? void 0 : _element$value$childr2.length) === 0 ? null : j.jsxClosingElement(j.jsxIdentifier(newElementName)), element.value.children);
10
+ j(element).replaceWith(newElement);
11
+ });
12
+ }
@@ -1,4 +1,4 @@
1
- import { Flags, Default } from './types';
1
+ import { type Flags, type Default } from './types';
2
2
  declare const defaultFlags: {
3
3
  parser: "babel";
4
4
  extensions: string;
@@ -1,10 +1,16 @@
1
1
  export declare const PRINT_SETTINGS: {
2
2
  quote: "single";
3
3
  };
4
+ /** NEW button **/
5
+ export declare const NEW_BUTTON_ENTRY_POINT = "@atlaskit/button/new";
4
6
  export declare const NEW_BUTTON_VARIANTS: {
5
7
  [key: string]: string;
6
8
  };
7
- export declare const NEW_BUTTON_ENTRY_POINT = "@atlaskit/button/new";
9
+ /** OLD button **/
10
+ export declare const OLD_BUTTON_ENTRY_POINT = "@atlaskit/button";
11
+ export declare const OLD_BUTTON_VARIANTS: {
12
+ [key: string]: string;
13
+ };
8
14
  export declare const entryPointsMapping: {
9
15
  [key: string]: string;
10
16
  };
@@ -16,3 +22,7 @@ export declare const buttonPropsNoLongerSupportedComment = "Buttons with \"compo
16
22
  export declare const migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
17
23
  export declare const migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
18
24
  export declare const customThemeButtonComment = "CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.";
25
+ export declare const loadingButtonComment: ({ hasLinkAppearance, hasHref, }: {
26
+ hasLinkAppearance: boolean;
27
+ hasHref: boolean;
28
+ }) => string;
@@ -0,0 +1,5 @@
1
+ import { type API, type Collection, type ImportDeclaration, type Specifier } from 'jscodeshift';
2
+ /**
3
+ * Returns default import specifiers from the given import declarations.
4
+ */
5
+ export default function getDefaultImports(importDeclarations: Collection<ImportDeclaration>, j: API['jscodeshift']): Collection<Specifier>;
@@ -0,0 +1,5 @@
1
+ import { type Collection, type Specifier } from 'jscodeshift';
2
+ /**
3
+ * Returns a list of specifier names from the given specifiers.
4
+ */
5
+ export default function getSpecifierNames(specifiers: Collection<Specifier>): string[] | undefined;
@@ -1,2 +1,3 @@
1
1
  import type { API, Collection } from 'jscodeshift';
2
- export declare const checkIfVariantAlreadyImported: (variant: string, fileSource: Collection<any>, j: API['jscodeshift']) => boolean;
2
+ export declare const findVariantAlreadyImported: (variant: string, entryPoint: string, fileSource: Collection<any>, j: API['jscodeshift'], isDefaultSpecifier?: boolean) => Collection<any>;
3
+ export declare const checkIfVariantAlreadyImported: (variant: string, entryPoint: string, fileSource: Collection<any>, j: API['jscodeshift'], isDefaultSpecifier?: boolean) => boolean;
@@ -1,3 +1,3 @@
1
1
  import type { API, ASTPath } from 'jscodeshift';
2
- import { JSXElement } from 'jscodeshift';
2
+ import { type JSXElement } from 'jscodeshift';
3
3
  export declare const migrateFitContainerIconButton: (element: ASTPath<JSXElement>, j: API['jscodeshift']) => boolean;
@@ -0,0 +1,2 @@
1
+ import type { API, Collection } from 'jscodeshift';
2
+ export default function renameElements(elementName: string, newElementName: string, fileSource: Collection<any>, j: API['jscodeshift']): void;
@@ -1,4 +1,4 @@
1
- import { FileInfo, API, Options } from 'jscodeshift';
1
+ import type { FileInfo, API, Options } from 'jscodeshift';
2
2
  /**
3
3
  * Converts all imports of `styled-components` to `@emotion/styled`
4
4
  */
@@ -1,2 +1,2 @@
1
- import { API, FileInfo } from 'jscodeshift';
1
+ import type { API, FileInfo } from 'jscodeshift';
2
2
  export default function transformer(file: FileInfo, api: API): string;
@@ -1,2 +1,2 @@
1
- import { FileInfo, API } from 'jscodeshift';
1
+ import { type FileInfo, type API } from 'jscodeshift';
2
2
  export default function transformer(file: FileInfo, api: API): string;
@@ -1,4 +1,4 @@
1
- import { ParsedPkg } from './types';
1
+ import { type ParsedPkg } from './types';
2
2
  /** Returns packages that have been upgraded in package.json since ref. The version refers to their previous
3
3
  * version
4
4
  */
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- import path, { ParsedPath } from 'path';
3
- import { ParsedPkg } from './types';
2
+ import path, { type ParsedPath } from 'path';
3
+ import { type ParsedPkg } from './types';
4
4
  export declare const hasTransform: (transformPath: string) => boolean;
5
5
  /** Retrieves transforms for `packages` if provided, otherwise all transforms including presets */
6
6
  export declare const getTransforms: (packages?: ParsedPkg[]) => ParsedPath[];
@@ -1,4 +1,4 @@
1
- import { FileInfo, API, Options } from 'jscodeshift';
1
+ import { type FileInfo, type API, type Options } from 'jscodeshift';
2
2
  export type Transform = (fileInfo: FileInfo, { jscodeshift }: API, options: Options) => string;
3
3
  export type CliFlags = {
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { Flags, Default } from './types';
1
+ import { type Flags, type Default } from './types';
2
2
  declare const defaultFlags: {
3
3
  parser: "babel";
4
4
  extensions: string;
@@ -1,10 +1,16 @@
1
1
  export declare const PRINT_SETTINGS: {
2
2
  quote: "single";
3
3
  };
4
+ /** NEW button **/
5
+ export declare const NEW_BUTTON_ENTRY_POINT = "@atlaskit/button/new";
4
6
  export declare const NEW_BUTTON_VARIANTS: {
5
7
  [key: string]: string;
6
8
  };
7
- export declare const NEW_BUTTON_ENTRY_POINT = "@atlaskit/button/new";
9
+ /** OLD button **/
10
+ export declare const OLD_BUTTON_ENTRY_POINT = "@atlaskit/button";
11
+ export declare const OLD_BUTTON_VARIANTS: {
12
+ [key: string]: string;
13
+ };
8
14
  export declare const entryPointsMapping: {
9
15
  [key: string]: string;
10
16
  };
@@ -16,3 +22,7 @@ export declare const buttonPropsNoLongerSupportedComment = "Buttons with \"compo
16
22
  export declare const migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
17
23
  export declare const migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
18
24
  export declare const customThemeButtonComment = "CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.";
25
+ export declare const loadingButtonComment: ({ hasLinkAppearance, hasHref, }: {
26
+ hasLinkAppearance: boolean;
27
+ hasHref: boolean;
28
+ }) => string;
@@ -0,0 +1,5 @@
1
+ import { type API, type Collection, type ImportDeclaration, type Specifier } from 'jscodeshift';
2
+ /**
3
+ * Returns default import specifiers from the given import declarations.
4
+ */
5
+ export default function getDefaultImports(importDeclarations: Collection<ImportDeclaration>, j: API['jscodeshift']): Collection<Specifier>;
@@ -0,0 +1,5 @@
1
+ import { type Collection, type Specifier } from 'jscodeshift';
2
+ /**
3
+ * Returns a list of specifier names from the given specifiers.
4
+ */
5
+ export default function getSpecifierNames(specifiers: Collection<Specifier>): string[] | undefined;