@atlaskit/codemod-cli 0.24.0 → 0.24.2

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 (29) hide show
  1. package/CHANGELOG.md +16 -0
  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 +10 -2
  4. package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-remove-unsafe-size.js +13 -6
  5. package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-split-imports.js +7 -5
  6. package/dist/cjs/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.js +33 -0
  7. package/dist/cjs/presets/migrate-to-new-buttons/utils/constants.js +3 -2
  8. package/dist/cjs/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +14 -5
  9. package/dist/cjs/presets/migrate-to-new-buttons/utils/has-unsupported-props.js +26 -1
  10. package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +10 -2
  11. package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-remove-unsafe-size.js +11 -6
  12. package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-split-imports.js +7 -5
  13. package/dist/es2019/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.js +23 -0
  14. package/dist/es2019/presets/migrate-to-new-buttons/utils/constants.js +2 -1
  15. package/dist/es2019/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +12 -5
  16. package/dist/es2019/presets/migrate-to-new-buttons/utils/has-unsupported-props.js +24 -1
  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 +10 -2
  19. package/dist/esm/presets/migrate-to-new-buttons/codemods/next-remove-unsafe-size.js +13 -6
  20. package/dist/esm/presets/migrate-to-new-buttons/codemods/next-split-imports.js +7 -5
  21. package/dist/esm/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.js +27 -0
  22. package/dist/esm/presets/migrate-to-new-buttons/utils/constants.js +2 -1
  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/has-unsupported-props.js +26 -1
  25. package/dist/types/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.d.ts +2 -0
  26. package/dist/types/presets/migrate-to-new-buttons/utils/constants.d.ts +1 -0
  27. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/add-comment-for-custom-theme-buttons.d.ts +2 -0
  28. package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/constants.d.ts +1 -0
  29. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/codemod-cli
2
2
 
3
+ ## 0.24.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#102800](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/102800)
8
+ [`868e9aebf5af`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/868e9aebf5af) -
9
+ Fix icon buttons with loading being converted to default buttons
10
+
11
+ ## 0.24.1
12
+
13
+ ### Patch Changes
14
+
15
+ - [#100948](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/100948)
16
+ [`28061857f2cd`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/28061857f2cd) -
17
+ Prevent migration of buttons where icon component might be wrapped.
18
+
3
19
  ## 0.24.0
4
20
 
5
21
  ### Minor Changes
package/dist/cjs/main.js CHANGED
@@ -305,7 +305,7 @@ function _main() {
305
305
  case 4:
306
306
  _yield$parseArgs = _context5.sent;
307
307
  packages = _yield$parseArgs.packages;
308
- _process$env$_PACKAGE = "0.24.0", _PACKAGE_VERSION_ = _process$env$_PACKAGE === void 0 ? '0.0.0-dev' : _process$env$_PACKAGE;
308
+ _process$env$_PACKAGE = "0.24.2", _PACKAGE_VERSION_ = _process$env$_PACKAGE === void 0 ? '0.0.0-dev' : _process$env$_PACKAGE;
309
309
  logger.log(_chalk.default.bgBlue(_chalk.default.black("\uD83D\uDCDA Atlassian-Frontend codemod library @ ".concat(_PACKAGE_VERSION_, " \uD83D\uDCDA"))));
310
310
  if (packages && packages.length > 0) {
311
311
  logger.log(_chalk.default.gray("Searching for codemods for newer versions of the following packages: ".concat(packages.map(function (pkg) {
@@ -13,9 +13,11 @@ var _ifVariantAlreadyImported = require("../utils/if-variant-already-imported");
13
13
  var _renameDefaultButtonToLegacyButton = require("../utils/rename-default-button-to-legacy-button");
14
14
  var _migrateFitContainerIconButton = require("../utils/migrate-fit-container-icon-button");
15
15
  var _importTypesFromNewEntryPoint = require("../utils/import-types-from-new-entry-point");
16
+ var _addCommentForCustomThemeButtons = require("../utils/add-comment-for-custom-theme-buttons");
16
17
  var transformer = function transformer(file, api) {
17
18
  var j = api.jscodeshift;
18
19
  var fileSource = j(file.source);
20
+ (0, _addCommentForCustomThemeButtons.addCommentForCustomThemeButtons)(fileSource, j);
19
21
  var buttonImports = fileSource.find(j.ImportDeclaration).filter(function (path) {
20
22
  return path.node.source.value === _constants.entryPointsMapping.Button || path.node.source.value === _constants.entryPointsMapping.LoadingButton || path.node.source.value === _constants.NEW_BUTTON_ENTRY_POINT;
21
23
  });
@@ -32,6 +34,7 @@ var transformer = function transformer(file, api) {
32
34
  var hasLinkIconButton = (0, _ifVariantAlreadyImported.checkIfVariantAlreadyImported)(_constants.NEW_BUTTON_VARIANTS.linkIcon, fileSource, j);
33
35
  var hasLinkButton = (0, _ifVariantAlreadyImported.checkIfVariantAlreadyImported)(_constants.NEW_BUTTON_VARIANTS.link, fileSource, j);
34
36
  var hasIconButton = (0, _ifVariantAlreadyImported.checkIfVariantAlreadyImported)(_constants.NEW_BUTTON_VARIANTS.icon, fileSource, j);
37
+ var hasDefaultLoadingButton = false;
35
38
  var allButtons = fileSource.find(j.JSXElement).filter(function (path) {
36
39
  return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier;
37
40
  });
@@ -78,7 +81,8 @@ var transformer = function transformer(file, api) {
78
81
  hasLinkButton = true;
79
82
  j(element).replaceWith((0, _generateNewButtonElement.generateNewElement)(_constants.NEW_BUTTON_VARIANTS.link, element.value, j));
80
83
  }
81
- if (isLoadingButton) {
84
+ if (isLoadingButton && !isIconButton) {
85
+ hasDefaultLoadingButton = true;
82
86
  j(element).replaceWith((0, _generateNewButtonElement.generateNewElement)(_constants.NEW_BUTTON_VARIANTS.default, element.value, j));
83
87
  }
84
88
  var linkAppearanceAttribute = attributes.find(function (node) {
@@ -117,7 +121,11 @@ var transformer = function transformer(file, api) {
117
121
  path.node.name = _constants.NEW_BUTTON_VARIANTS.default;
118
122
  }
119
123
  });
120
- specifiers.push(j.importDefaultSpecifier(j.identifier(_constants.NEW_BUTTON_VARIANTS.default)));
124
+
125
+ // Only add the Button import if we found a default button, not icon only
126
+ if (hasDefaultLoadingButton) {
127
+ specifiers.push(j.importDefaultSpecifier(j.identifier(_constants.NEW_BUTTON_VARIANTS.default)));
128
+ }
121
129
  }
122
130
  if (!specifiers.find(function (specifier) {
123
131
  return specifier.type === 'ImportDefaultSpecifier';
@@ -62,17 +62,27 @@ function _default(file, api) {
62
62
 
63
63
  // Check if render prop or bounded API
64
64
  iconAttributes.forEach(function (iconAttribute) {
65
- var _newButtonJXSElement$2, _iconAttribute$value;
65
+ var _newButtonJXSElement$2, _iconAttribute$value, _iconAttribute$value$;
66
66
  var unsafeSizeAttribute = (_newButtonJXSElement$2 = newButtonJXSElement.value.openingElement.attributes) === null || _newButtonJXSElement$2 === void 0 ? void 0 : _newButtonJXSElement$2.find(function (attribute) {
67
67
  return attribute.type === 'JSXAttribute' && attribute.name.name === unsafeSizeProp;
68
68
  });
69
69
  if (iconAttribute.type !== 'JSXAttribute' || ((_iconAttribute$value = iconAttribute.value) === null || _iconAttribute$value === void 0 ? void 0 : _iconAttribute$value.type) !== 'JSXExpressionContainer' || !unsafeSizeAttribute || unsafeSizeAttribute.type !== 'JSXAttribute') {
70
70
  return;
71
71
  }
72
+ var safeSizeAttribute = j.jsxAttribute.from({
73
+ name: j.jsxIdentifier('size'),
74
+ value: unsafeSizeAttribute.value
75
+ });
72
76
  switch (iconAttribute.value.expression.type) {
73
77
  // We have a render prop, move the UNSAFE prop to the render prop
74
78
  case 'ArrowFunctionExpression':
75
- // TODO: we have an existing render prop, move size to there
79
+ // Prefer existing size on icon over UNSAFE size on button
80
+ if (iconAttribute.value.expression.body.type === 'JSXElement' && !((_iconAttribute$value$ = iconAttribute.value.expression.body.openingElement.attributes) !== null && _iconAttribute$value$ !== void 0 && _iconAttribute$value$.some(function (attribute) {
81
+ return attribute.type === 'JSXAttribute' && attribute.name.name === 'size';
82
+ }))) {
83
+ var _iconAttribute$value$2;
84
+ (_iconAttribute$value$2 = iconAttribute.value.expression.body.openingElement.attributes) === null || _iconAttribute$value$2 === void 0 || _iconAttribute$value$2.push(safeSizeAttribute);
85
+ }
76
86
  break;
77
87
 
78
88
  // We have a bounded API, move to render prop
@@ -88,10 +98,7 @@ function _default(file, api) {
88
98
  selfClosing: true,
89
99
  attributes: [j.jsxSpreadAttribute.from({
90
100
  argument: j.identifier('iconProps')
91
- }), j.jsxAttribute.from({
92
- name: j.jsxIdentifier('size'),
93
- value: unsafeSizeAttribute.value
94
- })]
101
+ }), safeSizeAttribute]
95
102
  })
96
103
  })
97
104
  }));
@@ -23,6 +23,8 @@ var transformer = function transformer(file, api) {
23
23
  var _node$node = node.node,
24
24
  specifiers = _node$node.specifiers,
25
25
  source = _node$node.source;
26
+
27
+ // Return early if the import is not a named import
26
28
  if ([].concat((0, _toConsumableArray2.default)(Object.values(_constants.entryPointsMapping)), [_constants.NEW_BUTTON_ENTRY_POINT, '@atlaskit/button/types']).includes(source.value)) {
27
29
  return fileSource.toSource(_constants.PRINT_SETTINGS);
28
30
  }
@@ -33,13 +35,13 @@ var transformer = function transformer(file, api) {
33
35
  var defaultButtonImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(defaultSpecifier.local.name))], j.stringLiteral(_constants.entryPointsMapping.Button));
34
36
  j(node).insertAfter(defaultButtonImport);
35
37
  }
36
- var valueSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(function (specifier) {
38
+ var namedSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(function (specifier) {
37
39
  return specifier.type === 'ImportSpecifier';
38
40
  });
39
- var newTypeSpecifier = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(function (specifier) {
41
+ var newTypeSpecifier = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(function (specifier) {
40
42
  return specifier.type === 'ImportSpecifier' && (specifier.imported.name === 'Appearance' || specifier.imported.name === 'Spacing');
41
43
  });
42
- var otherTypeSpecifiers = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(function (specifier) {
44
+ var otherTypeSpecifiers = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(function (specifier) {
43
45
  return _constants.BUTTON_TYPES.includes(specifier.imported.name);
44
46
  });
45
47
  if (newTypeSpecifier !== null && newTypeSpecifier !== void 0 && newTypeSpecifier.length) {
@@ -50,8 +52,8 @@ var transformer = function transformer(file, api) {
50
52
  var _typeImport = j.importDeclaration(otherTypeSpecifiers, j.stringLiteral('@atlaskit/button'));
51
53
  j(node).insertAfter(_typeImport);
52
54
  }
53
- if (valueSpecifiers !== null && valueSpecifiers !== void 0 && valueSpecifiers.length) {
54
- valueSpecifiers.forEach(function (specifier) {
55
+ if (namedSpecifiers !== null && namedSpecifiers !== void 0 && namedSpecifiers.length) {
56
+ namedSpecifiers.forEach(function (specifier) {
55
57
  if (specifier.local && specifier.type === 'ImportSpecifier' && specifier.local.name && _constants.entryPointsMapping[specifier.imported.name]) {
56
58
  var newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(specifier.local.name))], j.stringLiteral(_constants.entryPointsMapping[specifier.imported.name]));
57
59
  j(node).insertAfter(newImport);
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.addCommentForCustomThemeButtons = void 0;
7
+ var _codemodUtils = require("@atlaskit/codemod-utils");
8
+ var _constants = require("./constants");
9
+ var addCommentForCustomThemeButtons = exports.addCommentForCustomThemeButtons = function addCommentForCustomThemeButtons(fileSource, j) {
10
+ var _fileSource$find$filt;
11
+ var customThemeButtonImportName;
12
+ (_fileSource$find$filt = fileSource.find(j.ImportDeclaration).filter(function (path) {
13
+ return path.node.source.value === _constants.entryPointsMapping.CustomThemeButton;
14
+ })) === null || _fileSource$find$filt === void 0 || _fileSource$find$filt.forEach(function (path) {
15
+ var _path$node$specifiers;
16
+ (_path$node$specifiers = path.node.specifiers) === null || _path$node$specifiers === void 0 || _path$node$specifiers.forEach(function (specifier) {
17
+ if (specifier.type === 'ImportDefaultSpecifier') {
18
+ var _specifier$local;
19
+ customThemeButtonImportName = (_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name;
20
+ }
21
+ });
22
+ });
23
+ if (!customThemeButtonImportName) {
24
+ return;
25
+ }
26
+ var customThemeButtonElement = fileSource.find(j.JSXElement).filter(function (path) {
27
+ return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === customThemeButtonImportName;
28
+ });
29
+ if (!customThemeButtonElement.length) {
30
+ return;
31
+ }
32
+ (0, _codemodUtils.addCommentBefore)(j, j(customThemeButtonElement.get(0).node.openingElement), _constants.customThemeButtonComment, 'line');
33
+ };
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.unsupportedProps = exports.migrateFitContainerButtonToIconButtonComment = exports.migrateFitContainerButtonToDefaultButtonComment = exports.linkButtonMissingHrefComment = exports.entryPointsMapping = exports.buttonPropsNoLongerSupportedComment = exports.UNSAFE_SIZE_PROPS_MAP = exports.PRINT_SETTINGS = exports.NEW_BUTTON_VARIANTS = exports.NEW_BUTTON_ENTRY_POINT = exports.BUTTON_TYPES = void 0;
6
+ exports.unsupportedProps = exports.migrateFitContainerButtonToIconButtonComment = exports.migrateFitContainerButtonToDefaultButtonComment = exports.linkButtonMissingHrefComment = exports.entryPointsMapping = exports.customThemeButtonComment = exports.buttonPropsNoLongerSupportedComment = exports.UNSAFE_SIZE_PROPS_MAP = exports.PRINT_SETTINGS = exports.NEW_BUTTON_VARIANTS = exports.NEW_BUTTON_ENTRY_POINT = exports.BUTTON_TYPES = void 0;
7
7
  var PRINT_SETTINGS = exports.PRINT_SETTINGS = {
8
8
  quote: 'single'
9
9
  };
@@ -30,4 +30,5 @@ var unsupportedProps = exports.unsupportedProps = ['component', 'css', 'style'];
30
30
  var linkButtonMissingHrefComment = exports.linkButtonMissingHrefComment = "\"link\" and \"subtle-link\" appearances are only available in LinkButton, please either provide a href prop then migrate to LinkButton, or remove the appearance from the default button.";
31
31
  var buttonPropsNoLongerSupportedComment = exports.buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
32
32
  var migrateFitContainerButtonToDefaultButtonComment = exports.migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
33
- var migrateFitContainerButtonToIconButtonComment = exports.migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
33
+ var migrateFitContainerButtonToIconButtonComment = exports.migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
34
+ var customThemeButtonComment = exports.customThemeButtonComment = "CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.";
@@ -57,7 +57,10 @@ var handleIconAttributes = exports.handleIconAttributes = function handleIconAtt
57
57
  var buttonAlreadyHasLabelProp = buttonAttributes === null || buttonAttributes === void 0 ? void 0 : buttonAttributes.find(function (buttonAttribute) {
58
58
  return buttonAttribute.type === 'JSXAttribute' && buttonAttribute.name.name === 'label';
59
59
  });
60
- if (!buttonAlreadyHasLabelProp) {
60
+ var buttonAlreadyHasAriaLabelProp = buttonAttributes === null || buttonAttributes === void 0 ? void 0 : buttonAttributes.find(function (buttonAttribute) {
61
+ return buttonAttribute.type === 'JSXAttribute' && buttonAttribute.name.name === 'aria-label';
62
+ });
63
+ if (!buttonAlreadyHasLabelProp && !buttonAlreadyHasAriaLabelProp) {
61
64
  var labelAttribute = iconAttributes.find(function (attribute) {
62
65
  return attribute.type === 'JSXAttribute' && attribute.name.name === 'label';
63
66
  });
@@ -123,12 +126,18 @@ var generateNewElement = exports.generateNewElement = function generateNewElemen
123
126
  return attribute.type === 'JSXAttribute' && attribute.name.name === 'label';
124
127
  }));
125
128
  if (hasNoLabelProp && attributes) {
126
- attributes.push(j.jsxAttribute(j.jsxIdentifier('label'), ariaLabelAttr.get().node.value));
129
+ attributes.unshift(j.jsxAttribute.from({
130
+ name: j.jsxIdentifier('label'),
131
+ value: j.literal(ariaLabelAttr.get().value.value.value)
132
+ }));
127
133
  }
128
134
  ariaLabelAttr.remove();
129
135
  }
130
136
  }
131
- return j.jsxElement(
132
- // self closing if it's an icon button or icon link button
133
- j.jsxOpeningElement(j.jsxIdentifier(variant), attributes, isIconOrLinkIcon), isIconOrLinkIcon ? null : j.jsxClosingElement(j.jsxIdentifier(variant)), element.children);
137
+ return j.jsxElement.from({
138
+ openingElement: j.jsxOpeningElement(j.jsxIdentifier(variant), attributes, isIconOrLinkIcon),
139
+ // self closing if it's an icon button or icon link button
140
+ closingElement: isIconOrLinkIcon ? null : j.jsxClosingElement(j.jsxIdentifier(variant)),
141
+ children: element.children
142
+ });
134
143
  };
@@ -6,7 +6,32 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.ifHasUnsupportedProps = void 0;
7
7
  var _constants = require("./constants");
8
8
  var ifHasUnsupportedProps = exports.ifHasUnsupportedProps = function ifHasUnsupportedProps(attributes) {
9
- return Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(function (node) {
9
+ var hasUnsupportedProps = Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(function (node) {
10
10
  return node.type === 'JSXAttribute' && _constants.unsupportedProps.includes(String(node.name.name));
11
11
  })));
12
+ var hasUnmigratableIcon = function hasUnmigratableIcon() {
13
+ var oldIconProps = ['iconBefore', 'iconAfter'];
14
+ var hasUnmigratableIcon = false;
15
+ if (!(attributes !== null && attributes !== void 0 && attributes.some(function (attribute) {
16
+ return attribute.type === 'JSXAttribute' && attribute.name.type === 'JSXIdentifier' && oldIconProps.includes(attribute.name.name);
17
+ }))) {
18
+ return hasUnmigratableIcon;
19
+ }
20
+ oldIconProps.forEach(function (oldIconProp) {
21
+ var _iconAttribute$value;
22
+ var iconAttribute = attributes.find(function (attribute) {
23
+ return attribute.type === 'JSXAttribute' && attribute.name.name === oldIconProp;
24
+ });
25
+ if (!iconAttribute) {
26
+ return;
27
+ }
28
+
29
+ // check to see if the element is self closing, otherwise assume it's not an icon (may contain wrapper)
30
+ if (iconAttribute.type === 'JSXAttribute' && ((_iconAttribute$value = iconAttribute.value) === null || _iconAttribute$value === void 0 ? void 0 : _iconAttribute$value.type) === 'JSXExpressionContainer' && iconAttribute.value.expression.type === 'JSXElement' && !iconAttribute.value.expression.openingElement.selfClosing) {
31
+ hasUnmigratableIcon = true;
32
+ }
33
+ });
34
+ return hasUnmigratableIcon;
35
+ };
36
+ return hasUnsupportedProps || hasUnmigratableIcon();
12
37
  };
@@ -7,9 +7,11 @@ import { checkIfVariantAlreadyImported } from '../utils/if-variant-already-impor
7
7
  import { renameDefaultButtonToLegacyButtonImport } from '../utils/rename-default-button-to-legacy-button';
8
8
  import { migrateFitContainerIconButton } from '../utils/migrate-fit-container-icon-button';
9
9
  import { importTypesFromNewEntryPoint } from '../utils/import-types-from-new-entry-point';
10
+ import { addCommentForCustomThemeButtons } from '../utils/add-comment-for-custom-theme-buttons';
10
11
  const transformer = (file, api) => {
11
12
  const j = api.jscodeshift;
12
13
  const fileSource = j(file.source);
14
+ addCommentForCustomThemeButtons(fileSource, j);
13
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);
14
16
  if (!buttonImports.length) {
15
17
  return fileSource.toSource();
@@ -22,6 +24,7 @@ const transformer = (file, api) => {
22
24
  let hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon, fileSource, j);
23
25
  let hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link, fileSource, j);
24
26
  let hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon, fileSource, j);
27
+ let hasDefaultLoadingButton = false;
25
28
  const allButtons = fileSource.find(j.JSXElement).filter(path => path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier);
26
29
  const buttonsWithoutUnsupportedProps = allButtons.filter(path => !ifHasUnsupportedProps(path.value.openingElement.attributes));
27
30
  const loadingButtonImportName = getDefaultImportSpecifierName(j, fileSource, entryPointsMapping.LoadingButton);
@@ -64,7 +67,8 @@ const transformer = (file, api) => {
64
67
  hasLinkButton = true;
65
68
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.link, element.value, j));
66
69
  }
67
- if (isLoadingButton) {
70
+ if (isLoadingButton && !isIconButton) {
71
+ hasDefaultLoadingButton = true;
68
72
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.default, element.value, j));
69
73
  }
70
74
  const linkAppearanceAttribute = attributes.find(node => {
@@ -95,7 +99,11 @@ const transformer = (file, api) => {
95
99
  path.node.name = NEW_BUTTON_VARIANTS.default;
96
100
  }
97
101
  });
98
- specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
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
+ }
99
107
  }
100
108
  if (!specifiers.find(specifier => specifier.type === 'ImportDefaultSpecifier') && remainingDefaultButtons) {
101
109
  specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
@@ -46,15 +46,23 @@ export default function (file, api) {
46
46
 
47
47
  // Check if render prop or bounded API
48
48
  iconAttributes.forEach(iconAttribute => {
49
- var _newButtonJXSElement$2, _iconAttribute$value;
49
+ var _newButtonJXSElement$2, _iconAttribute$value, _iconAttribute$value$;
50
50
  const unsafeSizeAttribute = (_newButtonJXSElement$2 = newButtonJXSElement.value.openingElement.attributes) === null || _newButtonJXSElement$2 === void 0 ? void 0 : _newButtonJXSElement$2.find(attribute => attribute.type === 'JSXAttribute' && attribute.name.name === unsafeSizeProp);
51
51
  if (iconAttribute.type !== 'JSXAttribute' || ((_iconAttribute$value = iconAttribute.value) === null || _iconAttribute$value === void 0 ? void 0 : _iconAttribute$value.type) !== 'JSXExpressionContainer' || !unsafeSizeAttribute || unsafeSizeAttribute.type !== 'JSXAttribute') {
52
52
  return;
53
53
  }
54
+ const safeSizeAttribute = j.jsxAttribute.from({
55
+ name: j.jsxIdentifier('size'),
56
+ value: unsafeSizeAttribute.value
57
+ });
54
58
  switch (iconAttribute.value.expression.type) {
55
59
  // We have a render prop, move the UNSAFE prop to the render prop
56
60
  case 'ArrowFunctionExpression':
57
- // TODO: we have an existing render prop, move size to there
61
+ // Prefer existing size on icon over UNSAFE size on button
62
+ if (iconAttribute.value.expression.body.type === 'JSXElement' && !((_iconAttribute$value$ = iconAttribute.value.expression.body.openingElement.attributes) !== null && _iconAttribute$value$ !== void 0 && _iconAttribute$value$.some(attribute => attribute.type === 'JSXAttribute' && attribute.name.name === 'size'))) {
63
+ var _iconAttribute$value$2;
64
+ (_iconAttribute$value$2 = iconAttribute.value.expression.body.openingElement.attributes) === null || _iconAttribute$value$2 === void 0 ? void 0 : _iconAttribute$value$2.push(safeSizeAttribute);
65
+ }
58
66
  break;
59
67
 
60
68
  // We have a bounded API, move to render prop
@@ -70,10 +78,7 @@ export default function (file, api) {
70
78
  selfClosing: true,
71
79
  attributes: [j.jsxSpreadAttribute.from({
72
80
  argument: j.identifier('iconProps')
73
- }), j.jsxAttribute.from({
74
- name: j.jsxIdentifier('size'),
75
- value: unsafeSizeAttribute.value
76
- })]
81
+ }), safeSizeAttribute]
77
82
  })
78
83
  })
79
84
  }));
@@ -14,6 +14,8 @@ const transformer = (file, api) => {
14
14
  specifiers,
15
15
  source
16
16
  } = node.node;
17
+
18
+ // Return early if the import is not a named import
17
19
  if ([...Object.values(entryPointsMapping), NEW_BUTTON_ENTRY_POINT, '@atlaskit/button/types'].includes(source.value)) {
18
20
  return fileSource.toSource(PRINT_SETTINGS);
19
21
  }
@@ -22,9 +24,9 @@ const transformer = (file, api) => {
22
24
  const defaultButtonImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(defaultSpecifier.local.name))], j.stringLiteral(entryPointsMapping.Button));
23
25
  j(node).insertAfter(defaultButtonImport);
24
26
  }
25
- const valueSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(specifier => specifier.type === 'ImportSpecifier');
26
- const newTypeSpecifier = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(specifier => specifier.type === 'ImportSpecifier' && (specifier.imported.name === 'Appearance' || specifier.imported.name === 'Spacing'));
27
- const otherTypeSpecifiers = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(specifier => BUTTON_TYPES.includes(specifier.imported.name));
27
+ const namedSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(specifier => specifier.type === 'ImportSpecifier');
28
+ const newTypeSpecifier = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(specifier => specifier.type === 'ImportSpecifier' && (specifier.imported.name === 'Appearance' || specifier.imported.name === 'Spacing'));
29
+ const otherTypeSpecifiers = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(specifier => BUTTON_TYPES.includes(specifier.imported.name));
28
30
  if (newTypeSpecifier !== null && newTypeSpecifier !== void 0 && newTypeSpecifier.length) {
29
31
  const typeImport = j.importDeclaration(newTypeSpecifier, j.stringLiteral('@atlaskit/button/types'));
30
32
  j(node).insertAfter(typeImport);
@@ -33,8 +35,8 @@ const transformer = (file, api) => {
33
35
  const typeImport = j.importDeclaration(otherTypeSpecifiers, j.stringLiteral('@atlaskit/button'));
34
36
  j(node).insertAfter(typeImport);
35
37
  }
36
- if (valueSpecifiers !== null && valueSpecifiers !== void 0 && valueSpecifiers.length) {
37
- valueSpecifiers.forEach(specifier => {
38
+ if (namedSpecifiers !== null && namedSpecifiers !== void 0 && namedSpecifiers.length) {
39
+ namedSpecifiers.forEach(specifier => {
38
40
  if (specifier.local && specifier.type === 'ImportSpecifier' && specifier.local.name && entryPointsMapping[specifier.imported.name]) {
39
41
  const newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(specifier.local.name))], j.stringLiteral(entryPointsMapping[specifier.imported.name]));
40
42
  j(node).insertAfter(newImport);
@@ -0,0 +1,23 @@
1
+ import { addCommentBefore } from '@atlaskit/codemod-utils';
2
+ import { entryPointsMapping, customThemeButtonComment } from './constants';
3
+ export const addCommentForCustomThemeButtons = (fileSource, j) => {
4
+ var _fileSource$find$filt;
5
+ let customThemeButtonImportName;
6
+ (_fileSource$find$filt = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === entryPointsMapping.CustomThemeButton)) === null || _fileSource$find$filt === void 0 ? void 0 : _fileSource$find$filt.forEach(path => {
7
+ var _path$node$specifiers;
8
+ (_path$node$specifiers = path.node.specifiers) === null || _path$node$specifiers === void 0 ? void 0 : _path$node$specifiers.forEach(specifier => {
9
+ if (specifier.type === 'ImportDefaultSpecifier') {
10
+ var _specifier$local;
11
+ customThemeButtonImportName = (_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name;
12
+ }
13
+ });
14
+ });
15
+ if (!customThemeButtonImportName) {
16
+ return;
17
+ }
18
+ const customThemeButtonElement = fileSource.find(j.JSXElement).filter(path => path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === customThemeButtonImportName);
19
+ if (!customThemeButtonElement.length) {
20
+ return;
21
+ }
22
+ addCommentBefore(j, j(customThemeButtonElement.get(0).node.openingElement), customThemeButtonComment, 'line');
23
+ };
@@ -24,4 +24,5 @@ export const unsupportedProps = ['component', 'css', 'style'];
24
24
  export const linkButtonMissingHrefComment = `"link" and "subtle-link" appearances are only available in LinkButton, please either provide a href prop then migrate to LinkButton, or remove the appearance from the default button.`;
25
25
  export const buttonPropsNoLongerSupportedComment = `Buttons with "component", "css" or "style" prop can't be automatically migrated with codemods. Please migrate it manually.`;
26
26
  export const migrateFitContainerButtonToDefaultButtonComment = `Migrated to a default button with text which is from the icon label.`;
27
- export const migrateFitContainerButtonToIconButtonComment = `"shouldFitContainer" is not available in icon buttons, please consider using a default button with text.`;
27
+ 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.`;
@@ -48,7 +48,8 @@ export const handleIconAttributes = (element, j, iconRenamed = false) => {
48
48
  // takes precedence over icon label.
49
49
 
50
50
  const buttonAlreadyHasLabelProp = buttonAttributes === null || buttonAttributes === void 0 ? void 0 : buttonAttributes.find(buttonAttribute => buttonAttribute.type === 'JSXAttribute' && buttonAttribute.name.name === 'label');
51
- if (!buttonAlreadyHasLabelProp) {
51
+ const buttonAlreadyHasAriaLabelProp = buttonAttributes === null || buttonAttributes === void 0 ? void 0 : buttonAttributes.find(buttonAttribute => buttonAttribute.type === 'JSXAttribute' && buttonAttribute.name.name === 'aria-label');
52
+ if (!buttonAlreadyHasLabelProp && !buttonAlreadyHasAriaLabelProp) {
52
53
  const labelAttribute = iconAttributes.find(attribute => attribute.type === 'JSXAttribute' && attribute.name.name === 'label');
53
54
  if (labelAttribute && labelAttribute.type === 'JSXAttribute' && iconRenamed) {
54
55
  buttonAttributes === null || buttonAttributes === void 0 ? void 0 : buttonAttributes.unshift(labelAttribute);
@@ -108,12 +109,18 @@ export const generateNewElement = (variant, element, j) => {
108
109
  if (ariaLabelAttr.length) {
109
110
  const hasNoLabelProp = !(attributes !== null && attributes !== void 0 && attributes.find(attribute => attribute.type === 'JSXAttribute' && attribute.name.name === 'label'));
110
111
  if (hasNoLabelProp && attributes) {
111
- attributes.push(j.jsxAttribute(j.jsxIdentifier('label'), ariaLabelAttr.get().node.value));
112
+ attributes.unshift(j.jsxAttribute.from({
113
+ name: j.jsxIdentifier('label'),
114
+ value: j.literal(ariaLabelAttr.get().value.value.value)
115
+ }));
112
116
  }
113
117
  ariaLabelAttr.remove();
114
118
  }
115
119
  }
116
- return j.jsxElement(
117
- // self closing if it's an icon button or icon link button
118
- j.jsxOpeningElement(j.jsxIdentifier(variant), attributes, isIconOrLinkIcon), isIconOrLinkIcon ? null : j.jsxClosingElement(j.jsxIdentifier(variant)), element.children);
120
+ return j.jsxElement.from({
121
+ openingElement: j.jsxOpeningElement(j.jsxIdentifier(variant), attributes, isIconOrLinkIcon),
122
+ // self closing if it's an icon button or icon link button
123
+ closingElement: isIconOrLinkIcon ? null : j.jsxClosingElement(j.jsxIdentifier(variant)),
124
+ children: element.children
125
+ });
119
126
  };
@@ -1,2 +1,25 @@
1
1
  import { unsupportedProps } from './constants';
2
- export const ifHasUnsupportedProps = attributes => Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(node => node.type === 'JSXAttribute' && unsupportedProps.includes(String(node.name.name)))));
2
+ export const ifHasUnsupportedProps = attributes => {
3
+ let hasUnsupportedProps = Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(node => node.type === 'JSXAttribute' && unsupportedProps.includes(String(node.name.name)))));
4
+ const hasUnmigratableIcon = () => {
5
+ const oldIconProps = ['iconBefore', 'iconAfter'];
6
+ let hasUnmigratableIcon = false;
7
+ if (!(attributes !== null && attributes !== void 0 && attributes.some(attribute => attribute.type === 'JSXAttribute' && attribute.name.type === 'JSXIdentifier' && oldIconProps.includes(attribute.name.name)))) {
8
+ return hasUnmigratableIcon;
9
+ }
10
+ oldIconProps.forEach(oldIconProp => {
11
+ var _iconAttribute$value;
12
+ const iconAttribute = attributes.find(attribute => attribute.type === 'JSXAttribute' && attribute.name.name === oldIconProp);
13
+ if (!iconAttribute) {
14
+ return;
15
+ }
16
+
17
+ // check to see if the element is self closing, otherwise assume it's not an icon (may contain wrapper)
18
+ if (iconAttribute.type === 'JSXAttribute' && ((_iconAttribute$value = iconAttribute.value) === null || _iconAttribute$value === void 0 ? void 0 : _iconAttribute$value.type) === 'JSXExpressionContainer' && iconAttribute.value.expression.type === 'JSXElement' && !iconAttribute.value.expression.openingElement.selfClosing) {
19
+ hasUnmigratableIcon = true;
20
+ }
21
+ });
22
+ return hasUnmigratableIcon;
23
+ };
24
+ return hasUnsupportedProps || hasUnmigratableIcon();
25
+ };
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.0", _PACKAGE_VERSION_ = _process$env$_PACKAGE === void 0 ? '0.0.0-dev' : _process$env$_PACKAGE;
301
+ _process$env$_PACKAGE = "0.24.2", _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) {
@@ -7,9 +7,11 @@ import { checkIfVariantAlreadyImported } from '../utils/if-variant-already-impor
7
7
  import { renameDefaultButtonToLegacyButtonImport } from '../utils/rename-default-button-to-legacy-button';
8
8
  import { migrateFitContainerIconButton } from '../utils/migrate-fit-container-icon-button';
9
9
  import { importTypesFromNewEntryPoint } from '../utils/import-types-from-new-entry-point';
10
+ import { addCommentForCustomThemeButtons } from '../utils/add-comment-for-custom-theme-buttons';
10
11
  var transformer = function transformer(file, api) {
11
12
  var j = api.jscodeshift;
12
13
  var fileSource = j(file.source);
14
+ addCommentForCustomThemeButtons(fileSource, j);
13
15
  var buttonImports = fileSource.find(j.ImportDeclaration).filter(function (path) {
14
16
  return path.node.source.value === entryPointsMapping.Button || path.node.source.value === entryPointsMapping.LoadingButton || path.node.source.value === NEW_BUTTON_ENTRY_POINT;
15
17
  });
@@ -26,6 +28,7 @@ var transformer = function transformer(file, api) {
26
28
  var hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon, fileSource, j);
27
29
  var hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link, fileSource, j);
28
30
  var hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon, fileSource, j);
31
+ var hasDefaultLoadingButton = false;
29
32
  var allButtons = fileSource.find(j.JSXElement).filter(function (path) {
30
33
  return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier;
31
34
  });
@@ -72,7 +75,8 @@ var transformer = function transformer(file, api) {
72
75
  hasLinkButton = true;
73
76
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.link, element.value, j));
74
77
  }
75
- if (isLoadingButton) {
78
+ if (isLoadingButton && !isIconButton) {
79
+ hasDefaultLoadingButton = true;
76
80
  j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.default, element.value, j));
77
81
  }
78
82
  var linkAppearanceAttribute = attributes.find(function (node) {
@@ -111,7 +115,11 @@ var transformer = function transformer(file, api) {
111
115
  path.node.name = NEW_BUTTON_VARIANTS.default;
112
116
  }
113
117
  });
114
- specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
118
+
119
+ // Only add the Button import if we found a default button, not icon only
120
+ if (hasDefaultLoadingButton) {
121
+ specifiers.push(j.importDefaultSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default)));
122
+ }
115
123
  }
116
124
  if (!specifiers.find(function (specifier) {
117
125
  return specifier.type === 'ImportDefaultSpecifier';
@@ -56,17 +56,27 @@ export default function (file, api) {
56
56
 
57
57
  // Check if render prop or bounded API
58
58
  iconAttributes.forEach(function (iconAttribute) {
59
- var _newButtonJXSElement$2, _iconAttribute$value;
59
+ var _newButtonJXSElement$2, _iconAttribute$value, _iconAttribute$value$;
60
60
  var unsafeSizeAttribute = (_newButtonJXSElement$2 = newButtonJXSElement.value.openingElement.attributes) === null || _newButtonJXSElement$2 === void 0 ? void 0 : _newButtonJXSElement$2.find(function (attribute) {
61
61
  return attribute.type === 'JSXAttribute' && attribute.name.name === unsafeSizeProp;
62
62
  });
63
63
  if (iconAttribute.type !== 'JSXAttribute' || ((_iconAttribute$value = iconAttribute.value) === null || _iconAttribute$value === void 0 ? void 0 : _iconAttribute$value.type) !== 'JSXExpressionContainer' || !unsafeSizeAttribute || unsafeSizeAttribute.type !== 'JSXAttribute') {
64
64
  return;
65
65
  }
66
+ var safeSizeAttribute = j.jsxAttribute.from({
67
+ name: j.jsxIdentifier('size'),
68
+ value: unsafeSizeAttribute.value
69
+ });
66
70
  switch (iconAttribute.value.expression.type) {
67
71
  // We have a render prop, move the UNSAFE prop to the render prop
68
72
  case 'ArrowFunctionExpression':
69
- // TODO: we have an existing render prop, move size to there
73
+ // Prefer existing size on icon over UNSAFE size on button
74
+ if (iconAttribute.value.expression.body.type === 'JSXElement' && !((_iconAttribute$value$ = iconAttribute.value.expression.body.openingElement.attributes) !== null && _iconAttribute$value$ !== void 0 && _iconAttribute$value$.some(function (attribute) {
75
+ return attribute.type === 'JSXAttribute' && attribute.name.name === 'size';
76
+ }))) {
77
+ var _iconAttribute$value$2;
78
+ (_iconAttribute$value$2 = iconAttribute.value.expression.body.openingElement.attributes) === null || _iconAttribute$value$2 === void 0 || _iconAttribute$value$2.push(safeSizeAttribute);
79
+ }
70
80
  break;
71
81
 
72
82
  // We have a bounded API, move to render prop
@@ -82,10 +92,7 @@ export default function (file, api) {
82
92
  selfClosing: true,
83
93
  attributes: [j.jsxSpreadAttribute.from({
84
94
  argument: j.identifier('iconProps')
85
- }), j.jsxAttribute.from({
86
- name: j.jsxIdentifier('size'),
87
- value: unsafeSizeAttribute.value
88
- })]
95
+ }), safeSizeAttribute]
89
96
  })
90
97
  })
91
98
  }));
@@ -16,6 +16,8 @@ var transformer = function transformer(file, api) {
16
16
  var _node$node = node.node,
17
17
  specifiers = _node$node.specifiers,
18
18
  source = _node$node.source;
19
+
20
+ // Return early if the import is not a named import
19
21
  if ([].concat(_toConsumableArray(Object.values(entryPointsMapping)), [NEW_BUTTON_ENTRY_POINT, '@atlaskit/button/types']).includes(source.value)) {
20
22
  return fileSource.toSource(PRINT_SETTINGS);
21
23
  }
@@ -26,13 +28,13 @@ var transformer = function transformer(file, api) {
26
28
  var defaultButtonImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(defaultSpecifier.local.name))], j.stringLiteral(entryPointsMapping.Button));
27
29
  j(node).insertAfter(defaultButtonImport);
28
30
  }
29
- var valueSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(function (specifier) {
31
+ var namedSpecifiers = specifiers === null || specifiers === void 0 ? void 0 : specifiers.filter(function (specifier) {
30
32
  return specifier.type === 'ImportSpecifier';
31
33
  });
32
- var newTypeSpecifier = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(function (specifier) {
34
+ var newTypeSpecifier = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(function (specifier) {
33
35
  return specifier.type === 'ImportSpecifier' && (specifier.imported.name === 'Appearance' || specifier.imported.name === 'Spacing');
34
36
  });
35
- var otherTypeSpecifiers = valueSpecifiers === null || valueSpecifiers === void 0 ? void 0 : valueSpecifiers.filter(function (specifier) {
37
+ var otherTypeSpecifiers = namedSpecifiers === null || namedSpecifiers === void 0 ? void 0 : namedSpecifiers.filter(function (specifier) {
36
38
  return BUTTON_TYPES.includes(specifier.imported.name);
37
39
  });
38
40
  if (newTypeSpecifier !== null && newTypeSpecifier !== void 0 && newTypeSpecifier.length) {
@@ -43,8 +45,8 @@ var transformer = function transformer(file, api) {
43
45
  var _typeImport = j.importDeclaration(otherTypeSpecifiers, j.stringLiteral('@atlaskit/button'));
44
46
  j(node).insertAfter(_typeImport);
45
47
  }
46
- if (valueSpecifiers !== null && valueSpecifiers !== void 0 && valueSpecifiers.length) {
47
- valueSpecifiers.forEach(function (specifier) {
48
+ if (namedSpecifiers !== null && namedSpecifiers !== void 0 && namedSpecifiers.length) {
49
+ namedSpecifiers.forEach(function (specifier) {
48
50
  if (specifier.local && specifier.type === 'ImportSpecifier' && specifier.local.name && entryPointsMapping[specifier.imported.name]) {
49
51
  var newImport = j.importDeclaration([j.importDefaultSpecifier(j.identifier(specifier.local.name))], j.stringLiteral(entryPointsMapping[specifier.imported.name]));
50
52
  j(node).insertAfter(newImport);
@@ -0,0 +1,27 @@
1
+ import { addCommentBefore } from '@atlaskit/codemod-utils';
2
+ import { entryPointsMapping, customThemeButtonComment } from './constants';
3
+ export var addCommentForCustomThemeButtons = function addCommentForCustomThemeButtons(fileSource, j) {
4
+ var _fileSource$find$filt;
5
+ var customThemeButtonImportName;
6
+ (_fileSource$find$filt = fileSource.find(j.ImportDeclaration).filter(function (path) {
7
+ return path.node.source.value === entryPointsMapping.CustomThemeButton;
8
+ })) === null || _fileSource$find$filt === void 0 || _fileSource$find$filt.forEach(function (path) {
9
+ var _path$node$specifiers;
10
+ (_path$node$specifiers = path.node.specifiers) === null || _path$node$specifiers === void 0 || _path$node$specifiers.forEach(function (specifier) {
11
+ if (specifier.type === 'ImportDefaultSpecifier') {
12
+ var _specifier$local;
13
+ customThemeButtonImportName = (_specifier$local = specifier.local) === null || _specifier$local === void 0 ? void 0 : _specifier$local.name;
14
+ }
15
+ });
16
+ });
17
+ if (!customThemeButtonImportName) {
18
+ return;
19
+ }
20
+ var customThemeButtonElement = fileSource.find(j.JSXElement).filter(function (path) {
21
+ return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === customThemeButtonImportName;
22
+ });
23
+ if (!customThemeButtonElement.length) {
24
+ return;
25
+ }
26
+ addCommentBefore(j, j(customThemeButtonElement.get(0).node.openingElement), customThemeButtonComment, 'line');
27
+ };
@@ -24,4 +24,5 @@ export var unsupportedProps = ['component', 'css', 'style'];
24
24
  export var linkButtonMissingHrefComment = "\"link\" and \"subtle-link\" appearances are only available in LinkButton, please either provide a href prop then migrate to LinkButton, or remove the appearance from the default button.";
25
25
  export var buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
26
26
  export var migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
27
- export var migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
27
+ 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.";
@@ -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
  };
@@ -1,6 +1,31 @@
1
1
  import { unsupportedProps } from './constants';
2
2
  export var ifHasUnsupportedProps = function ifHasUnsupportedProps(attributes) {
3
- return Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(function (node) {
3
+ var hasUnsupportedProps = Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(function (node) {
4
4
  return node.type === 'JSXAttribute' && unsupportedProps.includes(String(node.name.name));
5
5
  })));
6
+ var hasUnmigratableIcon = function hasUnmigratableIcon() {
7
+ var oldIconProps = ['iconBefore', 'iconAfter'];
8
+ var hasUnmigratableIcon = false;
9
+ if (!(attributes !== null && attributes !== void 0 && attributes.some(function (attribute) {
10
+ return attribute.type === 'JSXAttribute' && attribute.name.type === 'JSXIdentifier' && oldIconProps.includes(attribute.name.name);
11
+ }))) {
12
+ return hasUnmigratableIcon;
13
+ }
14
+ oldIconProps.forEach(function (oldIconProp) {
15
+ var _iconAttribute$value;
16
+ var iconAttribute = attributes.find(function (attribute) {
17
+ return attribute.type === 'JSXAttribute' && attribute.name.name === oldIconProp;
18
+ });
19
+ if (!iconAttribute) {
20
+ return;
21
+ }
22
+
23
+ // check to see if the element is self closing, otherwise assume it's not an icon (may contain wrapper)
24
+ if (iconAttribute.type === 'JSXAttribute' && ((_iconAttribute$value = iconAttribute.value) === null || _iconAttribute$value === void 0 ? void 0 : _iconAttribute$value.type) === 'JSXExpressionContainer' && iconAttribute.value.expression.type === 'JSXElement' && !iconAttribute.value.expression.openingElement.selfClosing) {
25
+ hasUnmigratableIcon = true;
26
+ }
27
+ });
28
+ return hasUnmigratableIcon;
29
+ };
30
+ return hasUnsupportedProps || hasUnmigratableIcon();
6
31
  };
@@ -0,0 +1,2 @@
1
+ import type { API, Collection } from 'jscodeshift';
2
+ export declare const addCommentForCustomThemeButtons: (fileSource: Collection<any>, j: API['jscodeshift']) => void;
@@ -15,3 +15,4 @@ export declare const linkButtonMissingHrefComment = "\"link\" and \"subtle-link\
15
15
  export declare const buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
16
16
  export declare const migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
17
17
  export declare const migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
18
+ export declare const customThemeButtonComment = "CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.";
@@ -0,0 +1,2 @@
1
+ import type { API, Collection } from 'jscodeshift';
2
+ export declare const addCommentForCustomThemeButtons: (fileSource: Collection<any>, j: API['jscodeshift']) => void;
@@ -15,3 +15,4 @@ export declare const linkButtonMissingHrefComment = "\"link\" and \"subtle-link\
15
15
  export declare const buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
16
16
  export declare const migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
17
17
  export declare const migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
18
+ export declare const customThemeButtonComment = "CustomThemeButton will be deprecated. Please consider migrating to Pressable or Anchor Primitives with custom styles.";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/codemod-cli",
3
- "version": "0.24.0",
3
+ "version": "0.24.2",
4
4
  "description": "A cli for distributing codemods for atlassian-frontend components and services",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -40,7 +40,7 @@
40
40
  "bin": "./bin/codemod-cli.js",
41
41
  "dependencies": {
42
42
  "@atlaskit/codemod-utils": "^4.2.0",
43
- "@atlaskit/tokens": "^1.48.0",
43
+ "@atlaskit/tokens": "^1.49.0",
44
44
  "@babel/runtime": "^7.0.0",
45
45
  "@codeshift/utils": "^0.2.4",
46
46
  "@hypermod/utils": "^0.4.2",