@atlaskit/codemod-cli 0.24.2 → 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 (51) hide show
  1. package/CHANGELOG.md +330 -323
  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 -56
  4. package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-split-imports.js +18 -4
  5. package/dist/cjs/presets/migrate-to-new-buttons/utils/constants.js +16 -3
  6. package/dist/cjs/presets/migrate-to-new-buttons/utils/get-default-imports.js +14 -0
  7. package/dist/cjs/presets/migrate-to-new-buttons/utils/get-specifier-names.js +14 -0
  8. package/dist/cjs/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +15 -7
  9. package/dist/cjs/presets/migrate-to-new-buttons/utils/rename-elements.js +18 -0
  10. package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +119 -52
  11. package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-split-imports.js +18 -4
  12. package/dist/es2019/presets/migrate-to-new-buttons/utils/constants.js +16 -2
  13. package/dist/es2019/presets/migrate-to-new-buttons/utils/get-default-imports.js +6 -0
  14. package/dist/es2019/presets/migrate-to-new-buttons/utils/get-specifier-names.js +6 -0
  15. package/dist/es2019/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +9 -3
  16. package/dist/es2019/presets/migrate-to-new-buttons/utils/rename-elements.js +12 -0
  17. package/dist/esm/main.js +1 -1
  18. package/dist/esm/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +126 -57
  19. package/dist/esm/presets/migrate-to-new-buttons/codemods/next-split-imports.js +18 -4
  20. package/dist/esm/presets/migrate-to-new-buttons/utils/constants.js +15 -2
  21. package/dist/esm/presets/migrate-to-new-buttons/utils/get-default-imports.js +8 -0
  22. package/dist/esm/presets/migrate-to-new-buttons/utils/get-specifier-names.js +8 -0
  23. package/dist/esm/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +14 -6
  24. package/dist/esm/presets/migrate-to-new-buttons/utils/rename-elements.js +12 -0
  25. package/dist/types/main.d.ts +1 -1
  26. package/dist/types/presets/migrate-to-new-buttons/utils/constants.d.ts +11 -1
  27. package/dist/types/presets/migrate-to-new-buttons/utils/get-default-imports.d.ts +5 -0
  28. package/dist/types/presets/migrate-to-new-buttons/utils/get-specifier-names.d.ts +5 -0
  29. package/dist/types/presets/migrate-to-new-buttons/utils/if-variant-already-imported.d.ts +2 -1
  30. package/dist/types/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.d.ts +1 -1
  31. package/dist/types/presets/migrate-to-new-buttons/utils/rename-elements.d.ts +2 -0
  32. package/dist/types/presets/styled-to-emotion/styled-to-emotion.d.ts +1 -1
  33. package/dist/types/presets/theme-remove-deprecated-mixins/theme-remove-deprecated-mixins.d.ts +1 -1
  34. package/dist/types/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.d.ts +1 -1
  35. package/dist/types/sinceRef.d.ts +1 -1
  36. package/dist/types/transforms.d.ts +2 -2
  37. package/dist/types/types.d.ts +1 -1
  38. package/dist/types-ts4.5/main.d.ts +1 -1
  39. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/constants.d.ts +11 -1
  40. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/get-default-imports.d.ts +5 -0
  41. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/get-specifier-names.d.ts +5 -0
  42. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/if-variant-already-imported.d.ts +2 -1
  43. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.d.ts +1 -1
  44. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/rename-elements.d.ts +2 -0
  45. package/dist/types-ts4.5/presets/styled-to-emotion/styled-to-emotion.d.ts +1 -1
  46. package/dist/types-ts4.5/presets/theme-remove-deprecated-mixins/theme-remove-deprecated-mixins.d.ts +1 -1
  47. package/dist/types-ts4.5/presets/upgrade-pragmatic-drag-and-drop-to-stable/upgrade-pragmatic-drag-and-drop-to-stable.d.ts +1 -1
  48. package/dist/types-ts4.5/sinceRef.d.ts +1 -1
  49. package/dist/types-ts4.5/transforms.d.ts +2 -2
  50. package/dist/types-ts4.5/types.d.ts +1 -1
  51. package/package.json +2 -4
@@ -1,6 +1,8 @@
1
1
  import { addCommentBefore } from '@atlaskit/codemod-utils';
2
2
  import { getDefaultImportSpecifierName } from '@hypermod/utils';
3
- import { PRINT_SETTINGS, NEW_BUTTON_VARIANTS, entryPointsMapping, NEW_BUTTON_ENTRY_POINT, linkButtonMissingHrefComment, buttonPropsNoLongerSupportedComment, unsupportedProps } from '../utils/constants';
3
+ 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';
4
+ import getDefaultImports from '../utils/get-default-imports';
5
+ import getSpecifierNames from '../utils/get-specifier-names';
4
6
  import { generateNewElement, handleIconAttributes } from '../utils/generate-new-button-element';
5
7
  import { ifHasUnsupportedProps } from '../utils/has-unsupported-props';
6
8
  import { checkIfVariantAlreadyImported } from '../utils/if-variant-already-imported';
@@ -12,23 +14,38 @@ const transformer = (file, api) => {
12
14
  const j = api.jscodeshift;
13
15
  const fileSource = j(file.source);
14
16
  addCommentForCustomThemeButtons(fileSource, j);
15
- const buttonImports = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === entryPointsMapping.Button || path.node.source.value === entryPointsMapping.LoadingButton || path.node.source.value === NEW_BUTTON_ENTRY_POINT);
16
- if (!buttonImports.length) {
17
- return fileSource.toSource();
18
- }
19
- const defaultButtonImport = buttonImports.find(j.Specifier).filter(path => path.node.type === 'ImportDefaultSpecifier');
20
- if (defaultButtonImport.length === 0) {
17
+
18
+ // Find old buttons
19
+ const oldButtonImports = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === entryPointsMapping.Button || path.node.source.value === entryPointsMapping.LoadingButton || path.node.source.value === OLD_BUTTON_ENTRY_POINT);
20
+ if (!oldButtonImports.length) {
21
21
  return fileSource.toSource();
22
22
  }
23
- const specifierIdentifier = defaultButtonImport.get(0).node.local.name;
24
- let hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon, fileSource, j);
25
- let hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link, fileSource, j);
26
- let hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon, fileSource, j);
27
- let hasDefaultLoadingButton = false;
28
- const allButtons = fileSource.find(j.JSXElement).filter(path => path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier);
29
- const buttonsWithoutUnsupportedProps = allButtons.filter(path => !ifHasUnsupportedProps(path.value.openingElement.attributes));
30
- const loadingButtonImportName = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping.LoadingButton);
31
- buttonsWithoutUnsupportedProps.forEach(element => {
23
+ const oldDefaultDefaultImports = getDefaultImports(oldButtonImports, j);
24
+ const oldDefaultImportSpecifiers = getSpecifierNames(oldDefaultDefaultImports);
25
+
26
+ // Find new buttons
27
+ const newButtonImports = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === NEW_BUTTON_ENTRY_POINT);
28
+ const newDefaultDefaultImports = getDefaultImports(newButtonImports, j);
29
+ const newDefaultImportSpecifiers = getSpecifierNames(newDefaultDefaultImports);
30
+ const loadingButtonDirectImportName = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping.LoadingButton);
31
+
32
+ /**
33
+ * Which variants should be in this file?
34
+ *
35
+ * Any variants enabled here will be added to the final import statement.
36
+ * Initial values check if the variant is already imported in the file.
37
+ */
38
+ let hasVariant = {
39
+ defaultButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.default, NEW_BUTTON_ENTRY_POINT, fileSource, j, true),
40
+ linkButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link, NEW_BUTTON_ENTRY_POINT, fileSource, j),
41
+ iconButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon, NEW_BUTTON_ENTRY_POINT, fileSource, j),
42
+ linkIconButton: checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon, NEW_BUTTON_ENTRY_POINT, fileSource, j)
43
+ };
44
+ const oldButtonElements = fileSource.find(j.JSXElement).filter(path => {
45
+ 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));
46
+ });
47
+ const oldButtonsWithoutUnsupportedProps = oldButtonElements.filter(path => !ifHasUnsupportedProps(path.value.openingElement.attributes));
48
+ oldButtonsWithoutUnsupportedProps.forEach(element => {
32
49
  var _element$value$childr;
33
50
  const {
34
51
  attributes
@@ -44,9 +61,14 @@ const transformer = (file, api) => {
44
61
  const isLinkIconButton = hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
45
62
  const isLinkButton = hasHref && !isLinkIconButton;
46
63
  let isIconButton = !hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
47
- const isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && !isFitContainerIconButton && hasIcon;
48
- const isLoadingButton = element.value.openingElement.name.type === 'JSXIdentifier' && element.value.openingElement.name.name === loadingButtonImportName;
49
- if (isDefaultButtonWithAnIcon) {
64
+ const isDefaultButton = !isLinkButton && !isLinkIconButton && !isIconButton && !isFitContainerIconButton;
65
+ const isDefaultVariantWithAnIcon = !isLinkIconButton && !isIconButton && !isFitContainerIconButton && hasIcon;
66
+ const isLoadingButton = element.value.openingElement.name.type === 'JSXIdentifier' && element.value.openingElement.name.name === loadingButtonDirectImportName;
67
+ const linkAppearanceAttribute = attributes.find(node => {
68
+ var _node$value, _node$name, _node$value2, _node$value3;
69
+ return node.type === 'JSXAttribute' && ((_node$value = node.value) === null || _node$value === void 0 ? void 0 : _node$value.type) === 'StringLiteral' && (node === null || node === void 0 ? void 0 : (_node$name = node.name) === null || _node$name === void 0 ? void 0 : _node$name.name) === 'appearance' && ((node === null || node === void 0 ? void 0 : (_node$value2 = node.value) === null || _node$value2 === void 0 ? void 0 : _node$value2.value) === 'link' || (node === null || node === void 0 ? void 0 : (_node$value3 = node.value) === null || _node$value3 === void 0 ? void 0 : _node$value3.value) === 'subtle-link');
70
+ });
71
+ if (isDefaultVariantWithAnIcon) {
50
72
  handleIconAttributes(element.value, j);
51
73
  }
52
74
  if (isFitContainerIconButton) {
@@ -55,66 +77,74 @@ const transformer = (file, api) => {
55
77
  isIconButton = true;
56
78
  }
57
79
  }
58
- if (isLinkIconButton) {
59
- hasLinkIconButton = true;
80
+ if (isLinkIconButton && !isLoadingButton) {
81
+ hasVariant.linkIconButton = true;
60
82
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.linkIcon, element.value, j));
61
83
  }
62
- if (isIconButton) {
63
- hasIconButton = true;
84
+ if (isIconButton && !isLoadingButton) {
85
+ hasVariant.iconButton = true;
64
86
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.icon, element.value, j));
65
87
  }
66
- if (isLinkButton) {
67
- hasLinkButton = true;
88
+ if (isLinkButton && !isLoadingButton) {
89
+ hasVariant.linkButton = true;
68
90
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.link, element.value, j));
69
91
  }
70
- if (isLoadingButton && !isIconButton) {
71
- hasDefaultLoadingButton = true;
72
- j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.default, element.value, j));
92
+ if (isDefaultButton && !isLoadingButton) {
93
+ hasVariant.defaultButton = true;
94
+ j(element).replaceWith(generateNewElement(newDefaultImportSpecifiers !== null && newDefaultImportSpecifiers !== void 0 && newDefaultImportSpecifiers.length ?
95
+ // If new button already has a default import, use that incase it's aliased
96
+ newDefaultImportSpecifiers[0] : NEW_BUTTON_VARIANTS.default, element.value, j));
73
97
  }
74
- const linkAppearanceAttribute = attributes.find(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 ? void 0 : (_node$name = node.name) === null || _node$name === void 0 ? void 0 : _node$name.name) === 'appearance' && ((node === null || node === void 0 ? void 0 : (_node$value2 = node.value) === null || _node$value2 === void 0 ? void 0 : _node$value2.value) === 'link' || (node === null || node === void 0 ? void 0 : (_node$value3 = node.value) === null || _node$value3 === void 0 ? void 0 : _node$value3.value) === 'subtle-link');
77
- });
78
- if (!hasHref && linkAppearanceAttribute) {
98
+ if (isLoadingButton) {
99
+ const newElement = generateNewElement(NEW_BUTTON_VARIANTS[isIconButton || isLinkIconButton ? 'icon' : 'default'], element.value, j);
100
+ if (isIconButton || isLinkIconButton) {
101
+ hasVariant.iconButton = true;
102
+ } else {
103
+ hasVariant.defaultButton = true;
104
+ }
105
+ j(element).replaceWith(newElement);
106
+ if (hasHref || linkAppearanceAttribute) {
107
+ addCommentBefore(j, j(newElement), loadingButtonComment({
108
+ hasHref,
109
+ hasLinkAppearance: Boolean(linkAppearanceAttribute)
110
+ }), 'block');
111
+ }
112
+ } else if (!hasHref && linkAppearanceAttribute) {
79
113
  addCommentBefore(j, j(linkAppearanceAttribute), linkButtonMissingHrefComment, 'line');
80
114
  }
81
115
  });
82
116
 
83
117
  // modify import declarations
84
118
  let specifiers = [];
85
- [hasLinkButton ? 'link' : null, hasIconButton ? 'icon' : null, hasLinkIconButton ? 'linkIcon' : null].forEach(variant => {
119
+ [hasVariant.linkButton ? 'link' : null, hasVariant.iconButton ? 'icon' : null, hasVariant.linkIconButton ? 'linkIcon' : null].forEach(variant => {
86
120
  if (variant) {
87
121
  specifiers.push(j.importSpecifier(j.identifier(NEW_BUTTON_VARIANTS[variant])));
88
122
  }
89
123
  });
90
- const oldButtonImport = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === NEW_BUTTON_ENTRY_POINT || path.node.source.value === entryPointsMapping.Button || path.node.source.value === entryPointsMapping.LoadingButton);
91
- const remainingDefaultButtons = fileSource.find(j.JSXElement).filter(path => path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier && !ifHasUnsupportedProps(path.value.openingElement.attributes)).length > 0 || fileSource.find(j.CallExpression).filter(path => path.node.arguments.map(argument => argument.type === 'Identifier' && (argument === null || argument === void 0 ? void 0 : argument.name)).includes(specifierIdentifier)).length > 0;
124
+ const remainingDefaultButtons = fileSource.find(j.JSXElement).filter(path => 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)).length > 0 || fileSource.find(j.CallExpression).filter(path => path.node.arguments.map(argument => argument.type === 'Identifier' && (argument === null || argument === void 0 ? void 0 : argument.name)).some(name => name && (oldDefaultImportSpecifiers === null || oldDefaultImportSpecifiers === void 0 ? void 0 : oldDefaultImportSpecifiers.includes(name)))).length > 0;
92
125
 
93
126
  // Loading buttons map back to default imports
94
- if (specifierIdentifier === loadingButtonImportName) {
127
+ if (loadingButtonDirectImportName && oldDefaultImportSpecifiers !== null && oldDefaultImportSpecifiers !== void 0 && oldDefaultImportSpecifiers.includes(loadingButtonDirectImportName)) {
95
128
  fileSource
96
129
  // rename LoadingButton to Button in all call expressions i.e. render(LoadingButton), find(LoadingButton)
97
130
  .find(j.CallExpression).find(j.Identifier).forEach(path => {
98
- if (path.node.name === loadingButtonImportName) {
131
+ if (path.node.name === loadingButtonDirectImportName) {
99
132
  path.node.name = NEW_BUTTON_VARIANTS.default;
100
133
  }
101
134
  });
102
-
103
- // Only add the Button import if we found a default button, not icon only
104
- if (hasDefaultLoadingButton) {
105
- specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
106
- }
107
135
  }
108
- if (!specifiers.find(specifier => specifier.type === 'ImportDefaultSpecifier') && remainingDefaultButtons) {
136
+
137
+ // Only add the Button import if we found a default button, not icon only
138
+ if (hasVariant.defaultButton || !specifiers.find(specifier => specifier.type === 'ImportDefaultSpecifier') && remainingDefaultButtons) {
109
139
  specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
110
140
  }
111
141
 
112
142
  // update import path for types imports
113
- specifiers = importTypesFromNewEntryPoint(buttonImports, specifiers, j, fileSource);
114
- const buttonsWithUnsupportedProps = allButtons.filter(path => ifHasUnsupportedProps(path.value.openingElement.attributes));
115
- if (buttonsWithUnsupportedProps.length) {
143
+ specifiers = importTypesFromNewEntryPoint(oldButtonImports, specifiers, j, fileSource);
144
+ const oldButtonsWithUnsupportedProps = oldButtonElements.filter(path => ifHasUnsupportedProps(path.value.openingElement.attributes));
145
+ if (oldButtonsWithUnsupportedProps.length) {
116
146
  // add comment to all buttons with unsupported props: "component", "style", "css"
117
- buttonsWithUnsupportedProps.forEach(element => {
147
+ oldButtonsWithUnsupportedProps.forEach(element => {
118
148
  var _element$value$openin;
119
149
  const attribute = (_element$value$openin = element.value.openingElement.attributes) === null || _element$value$openin === void 0 ? void 0 : _element$value$openin.find(node => node.type === 'JSXAttribute' && typeof node.name.name === 'string' && unsupportedProps.includes(node.name.name));
120
150
  if (attribute) {
@@ -124,16 +154,53 @@ const transformer = (file, api) => {
124
154
 
125
155
  // rename all buttons with unsupported props to LegacyButton if default new button is imported
126
156
  if (specifiers.find(specifier => specifier.type === 'ImportDefaultSpecifier')) {
127
- renameDefaultButtonToLegacyButtonImport(oldButtonImport, buttonsWithUnsupportedProps, j);
157
+ renameDefaultButtonToLegacyButtonImport(oldButtonImports, oldButtonsWithUnsupportedProps, j);
128
158
  }
129
159
  }
130
160
  if (specifiers.length) {
131
- const newButtonImport = j.importDeclaration(specifiers, j.stringLiteral(NEW_BUTTON_ENTRY_POINT));
132
- oldButtonImport.forEach(path => {
161
+ const existingNewButtonImports = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === NEW_BUTTON_ENTRY_POINT);
162
+ let newButtonImport = j.importDeclaration(specifiers, j.stringLiteral(NEW_BUTTON_ENTRY_POINT));
163
+ oldButtonImports.forEach(path => {
133
164
  var _path$node;
134
165
  newButtonImport.comments = path !== null && path !== void 0 && (_path$node = path.node) !== null && _path$node !== void 0 && _path$node.comments ? path.node.comments : undefined;
135
166
  });
136
- oldButtonImport.replaceWith(newButtonImport);
167
+ if (existingNewButtonImports.length) {
168
+ existingNewButtonImports.forEach(path => {
169
+ // Merge specifiers from existing new button import with added specifiers
170
+ const mergedSpecifiers = [...specifiers.filter(specifier => {
171
+ var _path$node$specifiers;
172
+ if (specifier.type !== 'ImportDefaultSpecifier') {
173
+ return true;
174
+ }
175
+
176
+ // Ensure we don't add a duplicate default specifier if one is already imported
177
+ return !((_path$node$specifiers = path.node.specifiers) !== null && _path$node$specifiers !== void 0 && _path$node$specifiers.find(s => s.type === 'ImportDefaultSpecifier'));
178
+ }), ...(path.node.specifiers ? path.node.specifiers : [])]
179
+ // Filter duplicates
180
+ .filter(specifier => {
181
+ if (specifier.type === 'ImportDefaultSpecifier') {
182
+ return true;
183
+ }
184
+ const isAlreadyImported = specifiers.find(s => {
185
+ var _specifier$local;
186
+ return s.type === 'ImportSpecifier' && s.imported.name === ((_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name);
187
+ });
188
+ return !isAlreadyImported;
189
+ });
190
+ newButtonImport = j.importDeclaration(mergedSpecifiers, j.stringLiteral(NEW_BUTTON_ENTRY_POINT));
191
+ });
192
+ oldButtonImports.remove();
193
+ existingNewButtonImports.replaceWith(newButtonImport);
194
+ } else {
195
+ oldButtonImports.replaceWith((_, index) => {
196
+ // Only replace the first import
197
+ if (index === 0) {
198
+ return newButtonImport;
199
+ }
200
+ // Remove the rest
201
+ return null;
202
+ });
203
+ }
137
204
  }
138
205
 
139
206
  // remove empty import declarations
@@ -1,4 +1,6 @@
1
1
  import { PRINT_SETTINGS, entryPointsMapping, BUTTON_TYPES, NEW_BUTTON_ENTRY_POINT } from '../utils/constants';
2
+ import renameElements from '../utils/rename-elements';
3
+ import { getDefaultImportSpecifierName } from '@hypermod/utils';
2
4
  const transformer = (file, api) => {
3
5
  const j = api.jscodeshift;
4
6
  const fileSource = j(file.source);
@@ -21,8 +23,14 @@ const transformer = (file, api) => {
21
23
  }
22
24
  const defaultSpecifier = specifiers === null || specifiers === void 0 ? void 0 : specifiers.find(specifier => specifier.type === 'ImportDefaultSpecifier');
23
25
  if (defaultSpecifier && defaultSpecifier.local) {
24
- const defaultButtonImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(defaultSpecifier.local.name))], j.stringLiteral(entryPointsMapping.Button));
25
- j(node).insertAfter(defaultButtonImport);
26
+ const existingSpecifier = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping.Button);
27
+ if (existingSpecifier) {
28
+ var _defaultSpecifier$loc;
29
+ renameElements((_defaultSpecifier$loc = defaultSpecifier.local) === null || _defaultSpecifier$loc === void 0 ? void 0 : _defaultSpecifier$loc.name, existingSpecifier, fileSource, j);
30
+ } else {
31
+ const newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(defaultSpecifier.local.name))], j.stringLiteral(entryPointsMapping.Button));
32
+ j(node).insertAfter(newImport);
33
+ }
26
34
  }
27
35
  const namedSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(specifier => specifier.type === 'ImportSpecifier');
28
36
  const newTypeSpecifier = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(specifier => specifier.type === 'ImportSpecifier' && (specifier.imported.name === 'Appearance' || specifier.imported.name === 'Spacing'));
@@ -38,8 +46,14 @@ const transformer = (file, api) => {
38
46
  if (namedSpecifiers !== null && namedSpecifiers !== void 0 && namedSpecifiers.length) {
39
47
  namedSpecifiers.forEach(specifier => {
40
48
  if (specifier.local && specifier.type === 'ImportSpecifier' && specifier.local.name && entryPointsMapping[specifier.imported.name]) {
41
- const newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(specifier.local.name))], j.stringLiteral(entryPointsMapping[specifier.imported.name]));
42
- j(node).insertAfter(newImport);
49
+ const existingSpecifier = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping[specifier.imported.name]);
50
+ if (existingSpecifier) {
51
+ var _specifier$local;
52
+ renameElements((_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name, existingSpecifier, fileSource, j);
53
+ } else {
54
+ const newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(specifier.local.name))], j.stringLiteral(entryPointsMapping[specifier.imported.name]));
55
+ j(node).insertAfter(newImport);
56
+ }
43
57
  }
44
58
  });
45
59
  }
@@ -1,13 +1,21 @@
1
1
  export const PRINT_SETTINGS = {
2
2
  quote: 'single'
3
3
  };
4
+
5
+ /** NEW button **/
6
+ export const NEW_BUTTON_ENTRY_POINT = '@atlaskit/button/new';
4
7
  export const NEW_BUTTON_VARIANTS = {
5
8
  default: 'Button',
6
9
  link: 'LinkButton',
7
10
  icon: 'IconButton',
8
11
  linkIcon: 'LinkIconButton'
9
12
  };
10
- export const NEW_BUTTON_ENTRY_POINT = '@atlaskit/button/new';
13
+
14
+ /** OLD button **/
15
+ export const OLD_BUTTON_ENTRY_POINT = '@atlaskit/button';
16
+ export const OLD_BUTTON_VARIANTS = {
17
+ loading: 'LoadingButton'
18
+ };
11
19
  export const entryPointsMapping = {
12
20
  Button: '@atlaskit/button/standard-button',
13
21
  LoadingButton: '@atlaskit/button/loading-button',
@@ -25,4 +33,10 @@ export const linkButtonMissingHrefComment = `"link" and "subtle-link" appearance
25
33
  export const buttonPropsNoLongerSupportedComment = `Buttons with "component", "css" or "style" prop can't be automatically migrated with codemods. Please migrate it manually.`;
26
34
  export const migrateFitContainerButtonToDefaultButtonComment = `Migrated to a default button with text which is from the icon label.`;
27
35
  export const migrateFitContainerButtonToIconButtonComment = `"shouldFitContainer" is not available in icon buttons, please consider using a default button with text.`;
28
- export const customThemeButtonComment = `CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.`;
36
+ export const customThemeButtonComment = `CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.`;
37
+ export const loadingButtonComment = ({
38
+ hasLinkAppearance,
39
+ hasHref
40
+ }) => {
41
+ return `This should be migrated to a new Button with a \`isLoading\` prop. ${hasLinkAppearance ? `"link" and "subtle-link" appearances are not available for new loading buttons."` : ''}${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.`;
42
+ };
@@ -0,0 +1,6 @@
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(path => path.node.type === 'ImportDefaultSpecifier');
6
+ }
@@ -0,0 +1,6 @@
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(path => path.get().value.local.name) : undefined;
6
+ }
@@ -1,4 +1,10 @@
1
- import { NEW_BUTTON_ENTRY_POINT } from './constants';
2
- export const checkIfVariantAlreadyImported = (variant, fileSource, j) => {
3
- return fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === NEW_BUTTON_ENTRY_POINT).find(j.ImportSpecifier).filter(path => path.node.imported.name === variant).length > 0;
1
+ export const findVariantAlreadyImported = (variant, entryPoint, fileSource, j, isDefaultSpecifier = false) => {
2
+ const imports = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === entryPoint);
3
+ if (isDefaultSpecifier) {
4
+ return imports.find(j.ImportDefaultSpecifier);
5
+ }
6
+ return imports.find(j.ImportSpecifier).filter(path => path.node.imported.name === variant);
7
+ };
8
+ export const checkIfVariantAlreadyImported = (variant, entryPoint, fileSource, j, isDefaultSpecifier = false) => {
9
+ return findVariantAlreadyImported(variant, entryPoint, fileSource, j, isDefaultSpecifier).length > 0;
4
10
  };
@@ -0,0 +1,12 @@
1
+ export default function renameElements(elementName, newElementName, fileSource, j) {
2
+ const oldElements = fileSource.find(j.JSXElement).filter(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(element => {
8
+ var _element$value$childr, _element$value$childr2;
9
+ const 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
+ }
package/dist/esm/main.js CHANGED
@@ -298,7 +298,7 @@ function _main() {
298
298
  case 4:
299
299
  _yield$parseArgs = _context5.sent;
300
300
  packages = _yield$parseArgs.packages;
301
- _process$env$_PACKAGE = "0.24.2", _PACKAGE_VERSION_ = _process$env$_PACKAGE === void 0 ? '0.0.0-dev' : _process$env$_PACKAGE;
301
+ _process$env$_PACKAGE = "0.24.3", _PACKAGE_VERSION_ = _process$env$_PACKAGE === void 0 ? '0.0.0-dev' : _process$env$_PACKAGE;
302
302
  logger.log(chalk.bgBlue(chalk.black("\uD83D\uDCDA Atlassian-Frontend codemod library @ ".concat(_PACKAGE_VERSION_, " \uD83D\uDCDA"))));
303
303
  if (packages && packages.length > 0) {
304
304
  logger.log(chalk.gray("Searching for codemods for newer versions of the following packages: ".concat(packages.map(function (pkg) {