@atlaskit/codemod-cli 0.17.2 → 0.17.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.
- package/CHANGELOG.md +6 -0
- package/dist/cjs/main.js +1 -1
- package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +69 -44
- package/dist/cjs/presets/migrate-to-new-buttons/utils/constants.js +9 -2
- package/dist/cjs/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +32 -13
- package/dist/cjs/presets/migrate-to-new-buttons/utils/has-unsupported-props.js +12 -0
- package/dist/cjs/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +14 -0
- package/dist/cjs/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.js +41 -0
- package/dist/cjs/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.js +15 -0
- package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +59 -32
- package/dist/es2019/presets/migrate-to-new-buttons/utils/constants.js +8 -1
- package/dist/es2019/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +30 -13
- package/dist/es2019/presets/migrate-to-new-buttons/utils/has-unsupported-props.js +2 -0
- package/dist/es2019/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +4 -0
- package/dist/es2019/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.js +27 -0
- package/dist/es2019/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.js +9 -0
- package/dist/esm/main.js +1 -1
- package/dist/esm/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js +70 -45
- package/dist/esm/presets/migrate-to-new-buttons/utils/constants.js +8 -1
- package/dist/esm/presets/migrate-to-new-buttons/utils/generate-new-button-element.js +32 -13
- package/dist/esm/presets/migrate-to-new-buttons/utils/has-unsupported-props.js +6 -0
- package/dist/esm/presets/migrate-to-new-buttons/utils/if-variant-already-imported.js +8 -0
- package/dist/esm/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.js +35 -0
- package/dist/esm/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.js +9 -0
- package/dist/types/presets/migrate-to-new-buttons/utils/constants.d.ts +7 -0
- package/dist/types/presets/migrate-to-new-buttons/utils/generate-new-button-element.d.ts +3 -1
- package/dist/types/presets/migrate-to-new-buttons/utils/has-unsupported-props.d.ts +2 -0
- package/dist/types/presets/migrate-to-new-buttons/utils/if-variant-already-imported.d.ts +2 -0
- package/dist/types/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.d.ts +3 -0
- package/dist/types/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.d.ts +2 -0
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/constants.d.ts +7 -0
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/generate-new-button-element.d.ts +3 -1
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/has-unsupported-props.d.ts +2 -0
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/if-variant-already-imported.d.ts +2 -0
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/migrate-fit-container-icon-button.d.ts +3 -0
- package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @atlaskit/codemod-cli
|
|
2
2
|
|
|
3
|
+
## 0.17.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#57531](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/57531) [`18f167967f89`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/18f167967f89) - Handle button migrations with unsupported props.
|
|
8
|
+
|
|
3
9
|
## 0.17.2
|
|
4
10
|
|
|
5
11
|
### Patch 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.17.
|
|
308
|
+
_process$env$_PACKAGE = "0.17.3", _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) {
|
package/dist/cjs/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js
CHANGED
|
@@ -7,6 +7,10 @@ exports.default = void 0;
|
|
|
7
7
|
var _codemodUtils = require("@atlaskit/codemod-utils");
|
|
8
8
|
var _constants = require("../utils/constants");
|
|
9
9
|
var _generateNewButtonElement = require("../utils/generate-new-button-element");
|
|
10
|
+
var _hasUnsupportedProps = require("../utils/has-unsupported-props");
|
|
11
|
+
var _ifVariantAlreadyImported = require("../utils/if-variant-already-imported");
|
|
12
|
+
var _renameDefaultButtonToLegacyButton = require("../utils/rename-default-button-to-legacy-button");
|
|
13
|
+
var _migrateFitContainerIconButton = require("../utils/migrate-fit-container-icon-button");
|
|
10
14
|
var transformer = function transformer(file, api, options) {
|
|
11
15
|
var j = api.jscodeshift;
|
|
12
16
|
var fileSource = j(file.source);
|
|
@@ -23,33 +27,17 @@ var transformer = function transformer(file, api, options) {
|
|
|
23
27
|
return fileSource.toSource();
|
|
24
28
|
}
|
|
25
29
|
var specifierIdentifier = defaultButtonImport.get(0).node.local.name;
|
|
26
|
-
var
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
var hasCustomComponent = attributes.filter(function (attribute) {
|
|
30
|
-
return attribute.node.name.name === 'component';
|
|
31
|
-
}).length > 0;
|
|
32
|
-
var hasCssProp = attributes.filter(function (attribute) {
|
|
33
|
-
return attribute.node.name.name === 'css';
|
|
34
|
-
}).length > 0;
|
|
35
|
-
if (hasCustomComponent || hasCssProp) {
|
|
36
|
-
return fileSource.toSource(_constants.PRINT_SETTINGS);
|
|
37
|
-
}
|
|
38
|
-
var checkIfVariantAlreadyImported = function checkIfVariantAlreadyImported(variant) {
|
|
39
|
-
return fileSource.find(j.ImportDeclaration).filter(function (path) {
|
|
40
|
-
return path.node.source.value === _constants.NEW_BUTTON_ENTRY_POINT;
|
|
41
|
-
}).find(j.ImportSpecifier).filter(function (path) {
|
|
42
|
-
return path.node.imported.name === variant;
|
|
43
|
-
}).length > 0;
|
|
44
|
-
};
|
|
45
|
-
var hasLinkIconButton = checkIfVariantAlreadyImported(_constants.NEW_BUTTON_VARIANTS.linkIcon.import);
|
|
46
|
-
var hasLinkButton = checkIfVariantAlreadyImported(_constants.NEW_BUTTON_VARIANTS.link.import);
|
|
47
|
-
var hasIconButton = checkIfVariantAlreadyImported(_constants.NEW_BUTTON_VARIANTS.icon.import);
|
|
30
|
+
var hasLinkIconButton = (0, _ifVariantAlreadyImported.checkIfVariantAlreadyImported)(_constants.NEW_BUTTON_VARIANTS.linkIcon.import, fileSource, j);
|
|
31
|
+
var hasLinkButton = (0, _ifVariantAlreadyImported.checkIfVariantAlreadyImported)(_constants.NEW_BUTTON_VARIANTS.link.import, fileSource, j);
|
|
32
|
+
var hasIconButton = (0, _ifVariantAlreadyImported.checkIfVariantAlreadyImported)(_constants.NEW_BUTTON_VARIANTS.icon.import, fileSource, j);
|
|
48
33
|
var allButtons = fileSource.find(j.JSXElement).filter(function (path) {
|
|
49
34
|
return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier;
|
|
50
35
|
});
|
|
51
|
-
allButtons.
|
|
52
|
-
|
|
36
|
+
var buttonsWithoutUnsupportedProps = allButtons.filter(function (path) {
|
|
37
|
+
return !(0, _hasUnsupportedProps.ifHasUnsupportedProps)(path.value.openingElement.attributes);
|
|
38
|
+
});
|
|
39
|
+
buttonsWithoutUnsupportedProps.forEach(function (element) {
|
|
40
|
+
var _element$value$childr;
|
|
53
41
|
var attributes = element.value.openingElement.attributes;
|
|
54
42
|
if (!attributes) {
|
|
55
43
|
return;
|
|
@@ -59,18 +47,21 @@ var transformer = function transformer(file, api, options) {
|
|
|
59
47
|
});
|
|
60
48
|
var hasHref = buttonAttributes.includes('href');
|
|
61
49
|
var hasIcon = buttonAttributes.includes('iconBefore') || buttonAttributes.includes('iconAfter');
|
|
62
|
-
var
|
|
50
|
+
var hasNoChildren = ((_element$value$childr = element.value.children) === null || _element$value$childr === void 0 ? void 0 : _element$value$childr.length) === 0;
|
|
51
|
+
var isFitContainerIconButton = hasIcon && hasNoChildren && buttonAttributes.includes('shouldFitContainer');
|
|
52
|
+
var isLinkIconButton = hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
|
|
63
53
|
var isLinkButton = hasHref && !isLinkIconButton;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
var isIconButton = !hasHref && hasIcon && ((_element$value$childr2 = element.value.children) === null || _element$value$childr2 === void 0 ? void 0 : _element$value$childr2.length) === 0;
|
|
67
|
-
var isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && hasIcon;
|
|
68
|
-
|
|
69
|
-
// TODO: add checks for unsupported icon props except label and size, e.g. primaryColor, testId, or spread props
|
|
70
|
-
// and don't migrate these buttons.
|
|
54
|
+
var isIconButton = !hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
|
|
55
|
+
var isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && !isFitContainerIconButton && hasIcon;
|
|
71
56
|
if (isDefaultButtonWithAnIcon) {
|
|
72
57
|
(0, _generateNewButtonElement.moveSizeAndLabelAttributes)(element.value, j);
|
|
73
58
|
}
|
|
59
|
+
if (isFitContainerIconButton) {
|
|
60
|
+
var migratedToIconButton = (0, _migrateFitContainerIconButton.migrateFitContainerIconButton)(element, j);
|
|
61
|
+
if (migratedToIconButton) {
|
|
62
|
+
isIconButton = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
74
65
|
if (isLinkIconButton) {
|
|
75
66
|
hasLinkIconButton = true;
|
|
76
67
|
j(element).replaceWith((0, _generateNewButtonElement.generateNewElement)(_constants.NEW_BUTTON_VARIANTS.linkIcon.as, element.value, j));
|
|
@@ -83,32 +74,66 @@ var transformer = function transformer(file, api, options) {
|
|
|
83
74
|
hasLinkButton = true;
|
|
84
75
|
j(element).replaceWith((0, _generateNewButtonElement.generateNewElement)(_constants.NEW_BUTTON_VARIANTS.link.as, element.value, j));
|
|
85
76
|
}
|
|
77
|
+
if (!hasHref && attributes.find(function (node) {
|
|
78
|
+
var _node$value, _node$name, _node$value2, _node$value3;
|
|
79
|
+
return node.type === 'JSXAttribute' && ((_node$value = node.value) === null || _node$value === void 0 ? void 0 : _node$value.type) === 'Literal' && (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');
|
|
80
|
+
})) {
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
(0, _codemodUtils.addCommentBefore)(j, [element], _constants.linkButtonMissingHrefComment);
|
|
83
|
+
}
|
|
86
84
|
});
|
|
87
85
|
var specifiers = [];
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
if (hasLinkIconButton) {
|
|
95
|
-
specifiers.push(j.importSpecifier(j.identifier(_constants.NEW_BUTTON_VARIANTS.linkIcon.import), j.identifier(_constants.NEW_BUTTON_VARIANTS.linkIcon.as)));
|
|
96
|
-
}
|
|
86
|
+
[hasLinkButton ? 'link' : null, hasIconButton ? 'icon' : null, hasLinkIconButton ? 'linkIcon' : null].forEach(function (variant) {
|
|
87
|
+
if (variant) {
|
|
88
|
+
specifiers.push(j.importSpecifier(j.identifier(_constants.NEW_BUTTON_VARIANTS[variant].import), j.identifier(_constants.NEW_BUTTON_VARIANTS[variant].as)));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
97
91
|
var oldButtonImport = fileSource.find(j.ImportDeclaration).filter(function (path) {
|
|
98
92
|
return path.node.source.value === _constants.NEW_BUTTON_ENTRY_POINT || path.node.source.value === _constants.entryPointsMapping.Button;
|
|
99
93
|
});
|
|
100
94
|
var remainingDefaultButtons = fileSource.find(j.JSXElement).filter(function (path) {
|
|
101
|
-
return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier;
|
|
95
|
+
return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier && !(0, _hasUnsupportedProps.ifHasUnsupportedProps)(path.value.openingElement.attributes);
|
|
102
96
|
}).length > 0 || fileSource.find(j.CallExpression).filter(function (path) {
|
|
103
97
|
return path.node.arguments.map(function (argument) {
|
|
104
98
|
return argument.type === 'Identifier' && (argument === null || argument === void 0 ? void 0 : argument.name);
|
|
105
99
|
}).includes(specifierIdentifier);
|
|
106
100
|
}).length > 0;
|
|
101
|
+
if (remainingDefaultButtons) {
|
|
102
|
+
specifiers.push(j.importSpecifier(j.identifier(_constants.NEW_BUTTON_VARIANTS.default.import), j.identifier(specifierIdentifier)));
|
|
103
|
+
}
|
|
104
|
+
var buttonsWithUnsupportedProps = allButtons.filter(function (path) {
|
|
105
|
+
return (0, _hasUnsupportedProps.ifHasUnsupportedProps)(path.value.openingElement.attributes);
|
|
106
|
+
});
|
|
107
|
+
if (buttonsWithUnsupportedProps.length) {
|
|
108
|
+
// add comment to all buttons with unsupported props: "component", "style", "css"
|
|
109
|
+
buttonsWithUnsupportedProps.forEach(function (element) {
|
|
110
|
+
var _element$value$openin;
|
|
111
|
+
var attribute = (_element$value$openin = element.value.openingElement.attributes) === null || _element$value$openin === void 0 ? void 0 : _element$value$openin.find(function (node) {
|
|
112
|
+
return node.type === 'JSXAttribute' && typeof node.name.name === 'string' && _constants.unsupportedProps.includes(node.name.name);
|
|
113
|
+
});
|
|
114
|
+
if (attribute) {
|
|
115
|
+
(0, _codemodUtils.addCommentBefore)(j, j(attribute), _constants.buttonPropsNoLongerSupportedComment, 'line');
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// rename all buttons with unsupported props to LegacyButton if default new button is imported
|
|
120
|
+
if (specifiers.find(function (specifier) {
|
|
121
|
+
return specifier.imported.name === _constants.NEW_BUTTON_VARIANTS.default.import;
|
|
122
|
+
})) {
|
|
123
|
+
(0, _renameDefaultButtonToLegacyButton.renameDefaultButtonToLegacyButtonImport)(oldButtonImport, buttonsWithUnsupportedProps, j);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
107
126
|
if (specifiers.length || remainingDefaultButtons) {
|
|
108
|
-
|
|
109
|
-
|
|
127
|
+
// split the type imports into a separate import
|
|
128
|
+
var typeSpecifier = buttonImports.find(j.ImportSpecifier).filter(function (path) {
|
|
129
|
+
return path.node.imported.name === _constants.ButtonPropsTypeName;
|
|
130
|
+
});
|
|
131
|
+
if (typeSpecifier.length > 0) {
|
|
132
|
+
oldButtonImport.insertBefore(j.importDeclaration([j.importSpecifier(j.identifier(_constants.ButtonPropsTypeName), j.identifier(typeSpecifier.get(0).node.local.name))], j.stringLiteral(_constants.entryPointsMapping.Button), 'type'));
|
|
110
133
|
}
|
|
111
134
|
oldButtonImport.replaceWith(j.importDeclaration(specifiers, j.stringLiteral(_constants.NEW_BUTTON_ENTRY_POINT)));
|
|
135
|
+
|
|
136
|
+
// add eslint-disable-next-line @atlaskit/design-system/no-banned-imports comment if unsafe import is allowed in custom options
|
|
112
137
|
if (_constants.NEW_BUTTON_ENTRY_POINT.includes('unsafe') && (options === null || options === void 0 ? void 0 : options.allowUnsafeImport) === true) {
|
|
113
138
|
(0, _codemodUtils.addCommentBefore)(j, fileSource.find(j.ImportDeclaration).filter(function (path) {
|
|
114
139
|
return path.node.source.value === _constants.NEW_BUTTON_ENTRY_POINT;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.eslintDisableComment = exports.entryPointsMapping = 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.iconPropsNoLongerSupportedComment = exports.eslintDisableComment = exports.entryPointsMapping = exports.buttonPropsNoLongerSupportedComment = exports.PRINT_SETTINGS = exports.NEW_BUTTON_VARIANTS = exports.NEW_BUTTON_ENTRY_POINT = exports.ButtonPropsTypeName = exports.BUTTON_TYPES = void 0;
|
|
7
7
|
var PRINT_SETTINGS = exports.PRINT_SETTINGS = {
|
|
8
8
|
quote: 'single'
|
|
9
9
|
};
|
|
@@ -33,4 +33,11 @@ var entryPointsMapping = exports.entryPointsMapping = {
|
|
|
33
33
|
CustomThemeButton: '@atlaskit/button/custom-theme-button'
|
|
34
34
|
};
|
|
35
35
|
var BUTTON_TYPES = exports.BUTTON_TYPES = ['Appearance', 'Spacing', 'BaseOwnProps', 'BaseProps', 'ButtonProps', 'LoadingButtonProps', 'LoadingButtonOwnProps', 'ThemeTokens', 'ThemeProps', 'InteractionState', 'CustomThemeButtonProps', 'CustomThemeButtonOwnProps'];
|
|
36
|
-
var eslintDisableComment = exports.eslintDisableComment = 'eslint-disable-next-line @atlaskit/design-system/no-banned-imports';
|
|
36
|
+
var eslintDisableComment = exports.eslintDisableComment = 'eslint-disable-next-line @atlaskit/design-system/no-banned-imports';
|
|
37
|
+
var ButtonPropsTypeName = exports.ButtonPropsTypeName = 'ButtonProps';
|
|
38
|
+
var unsupportedProps = exports.unsupportedProps = ['component', 'css', 'style'];
|
|
39
|
+
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.";
|
|
40
|
+
var iconPropsNoLongerSupportedComment = exports.iconPropsNoLongerSupportedComment = "\"glyph\", \"primaryColor\", \"secondaryColor\" and \"testId\" are no longer supported in button icons, please refactor the code and/or revisit the UI.";
|
|
41
|
+
var buttonPropsNoLongerSupportedComment = exports.buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
|
|
42
|
+
var migrateFitContainerButtonToDefaultButtonComment = exports.migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
|
|
43
|
+
var migrateFitContainerButtonToIconButtonComment = exports.migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
|
|
@@ -3,26 +3,45 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.moveSizeAndLabelAttributes = exports.generateNewElement = void 0;
|
|
6
|
+
exports.moveSizeAndLabelAttributes = exports.getIconElement = exports.getIconAttributes = exports.generateNewElement = void 0;
|
|
7
|
+
var _codemodUtils = require("@atlaskit/codemod-utils");
|
|
7
8
|
var _constants = require("../utils/constants");
|
|
8
|
-
var
|
|
9
|
+
var getIconAttributes = exports.getIconAttributes = function getIconAttributes(attributes) {
|
|
9
10
|
var iconAttr = attributes === null || attributes === void 0 ? void 0 : attributes.filter(function (attribute) {
|
|
10
11
|
return attribute.type === 'JSXAttribute' && (attribute.name.name === 'iconBefore' || attribute.name.name === 'iconAfter');
|
|
11
12
|
});
|
|
12
|
-
if (
|
|
13
|
-
return iconAttr
|
|
13
|
+
if (iconAttr !== null && iconAttr !== void 0 && iconAttr.length) {
|
|
14
|
+
return iconAttr;
|
|
14
15
|
}
|
|
15
16
|
return null;
|
|
16
17
|
};
|
|
17
|
-
var
|
|
18
|
+
var getIconElement = exports.getIconElement = function getIconElement(iconAttr) {
|
|
18
19
|
var _iconAttr$value;
|
|
20
|
+
if (iconAttr && ((_iconAttr$value = iconAttr.value) === null || _iconAttr$value === void 0 ? void 0 : _iconAttr$value.type) === 'JSXExpressionContainer' && iconAttr.value.expression.type === 'JSXElement') {
|
|
21
|
+
return iconAttr.value.expression;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
};
|
|
25
|
+
var moveSizeAndLabelAttributes = exports.moveSizeAndLabelAttributes = function moveSizeAndLabelAttributes(element, j) {
|
|
19
26
|
var iconRenamed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
20
27
|
var attributes = element.openingElement.attributes;
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
var
|
|
28
|
+
var iconAttrs = attributes && getIconAttributes(attributes);
|
|
29
|
+
iconAttrs === null || iconAttrs === void 0 || iconAttrs.forEach(function (iconAttr) {
|
|
30
|
+
var _iconAttr$value2;
|
|
31
|
+
var iconElement = getIconElement(iconAttr);
|
|
32
|
+
if (!iconElement) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
24
35
|
var iconJSXElementAttributes = iconElement.openingElement.attributes;
|
|
36
|
+
// add inlined comment to the icon if it has any attributes other than label and size
|
|
25
37
|
if (Array.isArray(iconJSXElementAttributes)) {
|
|
38
|
+
var ifIconAttributeEitherLabelOrSize = iconJSXElementAttributes === null || iconJSXElementAttributes === void 0 ? void 0 : iconJSXElementAttributes.every(function (attribute) {
|
|
39
|
+
return attribute.type === 'JSXAttribute' && typeof attribute.name.name === 'string' && (attribute.name.name === 'size' || attribute.name.name === 'label');
|
|
40
|
+
});
|
|
41
|
+
if (!ifIconAttributeEitherLabelOrSize) {
|
|
42
|
+
(0, _codemodUtils.addCommentBefore)(j, j(iconAttr), _constants.iconPropsNoLongerSupportedComment, 'line');
|
|
43
|
+
}
|
|
44
|
+
|
|
26
45
|
// move label and size attributes from icon to the root Button prop
|
|
27
46
|
var labelAttribute = iconJSXElementAttributes.find(function (attribute) {
|
|
28
47
|
return attribute.type === 'JSXAttribute' && attribute.name.name === 'label';
|
|
@@ -40,20 +59,20 @@ var moveSizeAndLabelAttributes = exports.moveSizeAndLabelAttributes = function m
|
|
|
40
59
|
}
|
|
41
60
|
|
|
42
61
|
// replace JSXElement with identifier {<MoreIcon />} => {MoreIcon}
|
|
43
|
-
if (iconElement.openingElement.name.type === 'JSXIdentifier') {
|
|
62
|
+
if (iconElement.openingElement.name.type === 'JSXIdentifier' && ((_iconAttr$value2 = iconAttr.value) === null || _iconAttr$value2 === void 0 ? void 0 : _iconAttr$value2.type) === 'JSXExpressionContainer') {
|
|
44
63
|
iconAttr.value.expression = j.identifier(iconElement.openingElement.name.name);
|
|
45
64
|
}
|
|
46
|
-
}
|
|
65
|
+
});
|
|
47
66
|
};
|
|
48
67
|
var generateNewElement = exports.generateNewElement = function generateNewElement(variant, element, j) {
|
|
49
68
|
var attributes = element.openingElement.attributes;
|
|
50
|
-
var
|
|
69
|
+
var iconAttrs = attributes && getIconAttributes(attributes);
|
|
51
70
|
var isIconOrLinkIcon = variant === _constants.NEW_BUTTON_VARIANTS.icon.as || variant === _constants.NEW_BUTTON_VARIANTS.linkIcon.as;
|
|
52
|
-
if (isIconOrLinkIcon &&
|
|
71
|
+
if (isIconOrLinkIcon && iconAttrs !== null && iconAttrs !== void 0 && iconAttrs.length) {
|
|
53
72
|
moveSizeAndLabelAttributes(element, j, true);
|
|
54
73
|
|
|
55
74
|
// rename iconBefore/iconAfter to icon
|
|
56
|
-
|
|
75
|
+
iconAttrs[0].name.name = 'icon';
|
|
57
76
|
}
|
|
58
77
|
return j.jsxElement(
|
|
59
78
|
// self closing if it's an icon button or icon link button
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ifHasUnsupportedProps = void 0;
|
|
7
|
+
var _constants = require("./constants");
|
|
8
|
+
var ifHasUnsupportedProps = exports.ifHasUnsupportedProps = function ifHasUnsupportedProps(attributes) {
|
|
9
|
+
return Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(function (node) {
|
|
10
|
+
return node.type === 'JSXAttribute' && _constants.unsupportedProps.includes(String(node.name.name));
|
|
11
|
+
})));
|
|
12
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.checkIfVariantAlreadyImported = void 0;
|
|
7
|
+
var _constants = require("./constants");
|
|
8
|
+
var checkIfVariantAlreadyImported = exports.checkIfVariantAlreadyImported = function checkIfVariantAlreadyImported(variant, fileSource, j) {
|
|
9
|
+
return fileSource.find(j.ImportDeclaration).filter(function (path) {
|
|
10
|
+
return path.node.source.value === _constants.NEW_BUTTON_ENTRY_POINT;
|
|
11
|
+
}).find(j.ImportSpecifier).filter(function (path) {
|
|
12
|
+
return path.node.imported.name === variant;
|
|
13
|
+
}).length > 0;
|
|
14
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.migrateFitContainerIconButton = void 0;
|
|
7
|
+
var _codemodUtils = require("@atlaskit/codemod-utils");
|
|
8
|
+
var _generateNewButtonElement = require("../utils/generate-new-button-element");
|
|
9
|
+
var _constants = require("./constants");
|
|
10
|
+
var migrateFitContainerIconButton = exports.migrateFitContainerIconButton = function migrateFitContainerIconButton(element, j) {
|
|
11
|
+
var _iconElement$openingE, _labelAttribute$value;
|
|
12
|
+
var attributes = element.value.openingElement.attributes;
|
|
13
|
+
var iconAttrs = attributes && (0, _generateNewButtonElement.getIconAttributes)(attributes);
|
|
14
|
+
var iconElement = iconAttrs && iconAttrs[0] && (0, _generateNewButtonElement.getIconElement)(iconAttrs[0]);
|
|
15
|
+
var labelAttribute = iconElement && Array.isArray(iconElement.openingElement.attributes) && ((_iconElement$openingE = iconElement.openingElement) === null || _iconElement$openingE === void 0 ? void 0 : _iconElement$openingE.attributes.find(function (path) {
|
|
16
|
+
return path.type === 'JSXAttribute' && (path.name.name === 'label' || path.name.name === 'aria-label' || path.name.name === 'aria-labelledby');
|
|
17
|
+
}));
|
|
18
|
+
var migratedToIconButton;
|
|
19
|
+
if (labelAttribute && labelAttribute.type === 'JSXAttribute' && ((_labelAttribute$value = labelAttribute.value) === null || _labelAttribute$value === void 0 ? void 0 : _labelAttribute$value.type) === 'Literal' && typeof labelAttribute.value.value === 'string') {
|
|
20
|
+
migratedToIconButton = false;
|
|
21
|
+
var label = labelAttribute.value.value;
|
|
22
|
+
var formattedLabel = "".concat(label.charAt(0).toUpperCase()).concat(label.slice(1)).split('-').join(' ');
|
|
23
|
+
j(element).find(j.JSXAttribute).filter(function (path) {
|
|
24
|
+
return path.node.name.name === 'iconBefore' || path.node.name.name === 'iconAfter';
|
|
25
|
+
}).remove();
|
|
26
|
+
var newButton = j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier(_constants.NEW_BUTTON_VARIANTS.default.as), attributes), j.jsxClosingElement(j.jsxIdentifier(_constants.NEW_BUTTON_VARIANTS.default.as)), [j.jsxText(formattedLabel)]);
|
|
27
|
+
j(element).replaceWith(newButton);
|
|
28
|
+
(0, _codemodUtils.addCommentBefore)(j, j(newButton).find(j.JSXAttribute).filter(function (path) {
|
|
29
|
+
return path.node.name.name === 'shouldFitContainer';
|
|
30
|
+
}), _constants.migrateFitContainerButtonToDefaultButtonComment, 'line');
|
|
31
|
+
} else {
|
|
32
|
+
migratedToIconButton = true;
|
|
33
|
+
(0, _codemodUtils.addCommentBefore)(j, j(element).find(j.JSXAttribute).filter(function (path) {
|
|
34
|
+
return path.node.name.name === 'iconBefore' || path.node.name.name === 'iconAfter';
|
|
35
|
+
}), _constants.migrateFitContainerButtonToIconButtonComment, 'line');
|
|
36
|
+
j(element).find(j.JSXAttribute).filter(function (path) {
|
|
37
|
+
return path.node.name.name === 'shouldFitContainer';
|
|
38
|
+
}).remove();
|
|
39
|
+
}
|
|
40
|
+
return migratedToIconButton;
|
|
41
|
+
};
|
package/dist/cjs/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.renameDefaultButtonToLegacyButtonImport = void 0;
|
|
7
|
+
var _constants = require("../utils/constants");
|
|
8
|
+
var renameDefaultButtonToLegacyButtonImport = exports.renameDefaultButtonToLegacyButtonImport = function renameDefaultButtonToLegacyButtonImport(oldButtonImport, oldButtonElements, j) {
|
|
9
|
+
oldButtonImport.insertBefore(j.importDeclaration([j.importDefaultSpecifier(j.identifier('LegacyButton'))], j.stringLiteral(_constants.entryPointsMapping.Button)));
|
|
10
|
+
oldButtonElements.forEach(function (element) {
|
|
11
|
+
var _element$value$childr, _element$value$childr2;
|
|
12
|
+
var legacyElement = j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier('LegacyButton'), 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('LegacyButton')), element.value.children);
|
|
13
|
+
j(element).replaceWith(legacyElement);
|
|
14
|
+
});
|
|
15
|
+
};
|
package/dist/es2019/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { addCommentBefore } from '@atlaskit/codemod-utils';
|
|
2
|
-
import { PRINT_SETTINGS, NEW_BUTTON_VARIANTS, entryPointsMapping, NEW_BUTTON_ENTRY_POINT, eslintDisableComment } from '../utils/constants';
|
|
2
|
+
import { PRINT_SETTINGS, NEW_BUTTON_VARIANTS, entryPointsMapping, NEW_BUTTON_ENTRY_POINT, eslintDisableComment, ButtonPropsTypeName, linkButtonMissingHrefComment, buttonPropsNoLongerSupportedComment, unsupportedProps } from '../utils/constants';
|
|
3
3
|
import { generateNewElement, moveSizeAndLabelAttributes } from '../utils/generate-new-button-element';
|
|
4
|
+
import { ifHasUnsupportedProps } from '../utils/has-unsupported-props';
|
|
5
|
+
import { checkIfVariantAlreadyImported } from '../utils/if-variant-already-imported';
|
|
6
|
+
import { renameDefaultButtonToLegacyButtonImport } from '../utils/rename-default-button-to-legacy-button';
|
|
7
|
+
import { migrateFitContainerIconButton } from '../utils/migrate-fit-container-icon-button';
|
|
4
8
|
const transformer = (file, api, options) => {
|
|
5
9
|
const j = api.jscodeshift;
|
|
6
10
|
const fileSource = j(file.source);
|
|
@@ -13,19 +17,13 @@ const transformer = (file, api, options) => {
|
|
|
13
17
|
return fileSource.toSource();
|
|
14
18
|
}
|
|
15
19
|
const specifierIdentifier = defaultButtonImport.get(0).node.local.name;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (hasCustomComponent || hasCssProp) {
|
|
20
|
-
return fileSource.toSource(PRINT_SETTINGS);
|
|
21
|
-
}
|
|
22
|
-
const checkIfVariantAlreadyImported = variant => 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;
|
|
23
|
-
let hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon.import);
|
|
24
|
-
let hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link.import);
|
|
25
|
-
let hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon.import);
|
|
20
|
+
let hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon.import, fileSource, j);
|
|
21
|
+
let hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link.import, fileSource, j);
|
|
22
|
+
let hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon.import, fileSource, j);
|
|
26
23
|
const allButtons = fileSource.find(j.JSXElement).filter(path => path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier);
|
|
27
|
-
allButtons.
|
|
28
|
-
|
|
24
|
+
const buttonsWithoutUnsupportedProps = allButtons.filter(path => !ifHasUnsupportedProps(path.value.openingElement.attributes));
|
|
25
|
+
buttonsWithoutUnsupportedProps.forEach(element => {
|
|
26
|
+
var _element$value$childr;
|
|
29
27
|
const {
|
|
30
28
|
attributes
|
|
31
29
|
} = element.value.openingElement;
|
|
@@ -35,18 +33,21 @@ const transformer = (file, api, options) => {
|
|
|
35
33
|
const buttonAttributes = attributes.map(node => node.type === 'JSXAttribute' && node.name.name);
|
|
36
34
|
const hasHref = buttonAttributes.includes('href');
|
|
37
35
|
const hasIcon = buttonAttributes.includes('iconBefore') || buttonAttributes.includes('iconAfter');
|
|
38
|
-
const
|
|
36
|
+
const hasNoChildren = ((_element$value$childr = element.value.children) === null || _element$value$childr === void 0 ? void 0 : _element$value$childr.length) === 0;
|
|
37
|
+
const isFitContainerIconButton = hasIcon && hasNoChildren && buttonAttributes.includes('shouldFitContainer');
|
|
38
|
+
const isLinkIconButton = hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
|
|
39
39
|
const isLinkButton = hasHref && !isLinkIconButton;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const isIconButton = !hasHref && hasIcon && ((_element$value$childr2 = element.value.children) === null || _element$value$childr2 === void 0 ? void 0 : _element$value$childr2.length) === 0;
|
|
43
|
-
const isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && hasIcon;
|
|
44
|
-
|
|
45
|
-
// TODO: add checks for unsupported icon props except label and size, e.g. primaryColor, testId, or spread props
|
|
46
|
-
// and don't migrate these buttons.
|
|
40
|
+
let isIconButton = !hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
|
|
41
|
+
const isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && !isFitContainerIconButton && hasIcon;
|
|
47
42
|
if (isDefaultButtonWithAnIcon) {
|
|
48
43
|
moveSizeAndLabelAttributes(element.value, j);
|
|
49
44
|
}
|
|
45
|
+
if (isFitContainerIconButton) {
|
|
46
|
+
const migratedToIconButton = migrateFitContainerIconButton(element, j);
|
|
47
|
+
if (migratedToIconButton) {
|
|
48
|
+
isIconButton = true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
50
51
|
if (isLinkIconButton) {
|
|
51
52
|
hasLinkIconButton = true;
|
|
52
53
|
j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.linkIcon.as, element.value, j));
|
|
@@ -59,24 +60,50 @@ const transformer = (file, api, options) => {
|
|
|
59
60
|
hasLinkButton = true;
|
|
60
61
|
j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.link.as, element.value, j));
|
|
61
62
|
}
|
|
63
|
+
if (!hasHref && attributes.find(node => {
|
|
64
|
+
var _node$value, _node$name, _node$value2, _node$value3;
|
|
65
|
+
return node.type === 'JSXAttribute' && ((_node$value = node.value) === null || _node$value === void 0 ? void 0 : _node$value.type) === 'Literal' && (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');
|
|
66
|
+
})) {
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
addCommentBefore(j, [element], linkButtonMissingHrefComment);
|
|
69
|
+
}
|
|
62
70
|
});
|
|
63
71
|
const specifiers = [];
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
[hasLinkButton ? 'link' : null, hasIconButton ? 'icon' : null, hasLinkIconButton ? 'linkIcon' : null].forEach(variant => {
|
|
73
|
+
if (variant) {
|
|
74
|
+
specifiers.push(j.importSpecifier(j.identifier(NEW_BUTTON_VARIANTS[variant].import), j.identifier(NEW_BUTTON_VARIANTS[variant].as)));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
const oldButtonImport = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === NEW_BUTTON_ENTRY_POINT || path.node.source.value === entryPointsMapping.Button);
|
|
78
|
+
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;
|
|
79
|
+
if (remainingDefaultButtons) {
|
|
80
|
+
specifiers.push(j.importSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default.import), j.identifier(specifierIdentifier)));
|
|
69
81
|
}
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
const buttonsWithUnsupportedProps = allButtons.filter(path => ifHasUnsupportedProps(path.value.openingElement.attributes));
|
|
83
|
+
if (buttonsWithUnsupportedProps.length) {
|
|
84
|
+
// add comment to all buttons with unsupported props: "component", "style", "css"
|
|
85
|
+
buttonsWithUnsupportedProps.forEach(element => {
|
|
86
|
+
var _element$value$openin;
|
|
87
|
+
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));
|
|
88
|
+
if (attribute) {
|
|
89
|
+
addCommentBefore(j, j(attribute), buttonPropsNoLongerSupportedComment, 'line');
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// rename all buttons with unsupported props to LegacyButton if default new button is imported
|
|
94
|
+
if (specifiers.find(specifier => specifier.imported.name === NEW_BUTTON_VARIANTS.default.import)) {
|
|
95
|
+
renameDefaultButtonToLegacyButtonImport(oldButtonImport, buttonsWithUnsupportedProps, j);
|
|
96
|
+
}
|
|
72
97
|
}
|
|
73
|
-
const oldButtonImport = fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === NEW_BUTTON_ENTRY_POINT || path.node.source.value === entryPointsMapping.Button);
|
|
74
|
-
const remainingDefaultButtons = fileSource.find(j.JSXElement).filter(path => path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier).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;
|
|
75
98
|
if (specifiers.length || remainingDefaultButtons) {
|
|
76
|
-
|
|
77
|
-
|
|
99
|
+
// split the type imports into a separate import
|
|
100
|
+
const typeSpecifier = buttonImports.find(j.ImportSpecifier).filter(path => path.node.imported.name === ButtonPropsTypeName);
|
|
101
|
+
if (typeSpecifier.length > 0) {
|
|
102
|
+
oldButtonImport.insertBefore(j.importDeclaration([j.importSpecifier(j.identifier(ButtonPropsTypeName), j.identifier(typeSpecifier.get(0).node.local.name))], j.stringLiteral(entryPointsMapping.Button), 'type'));
|
|
78
103
|
}
|
|
79
104
|
oldButtonImport.replaceWith(j.importDeclaration(specifiers, j.stringLiteral(NEW_BUTTON_ENTRY_POINT)));
|
|
105
|
+
|
|
106
|
+
// add eslint-disable-next-line @atlaskit/design-system/no-banned-imports comment if unsafe import is allowed in custom options
|
|
80
107
|
if (NEW_BUTTON_ENTRY_POINT.includes('unsafe') && (options === null || options === void 0 ? void 0 : options.allowUnsafeImport) === true) {
|
|
81
108
|
addCommentBefore(j, fileSource.find(j.ImportDeclaration).filter(path => path.node.source.value === NEW_BUTTON_ENTRY_POINT), eslintDisableComment, 'line', '');
|
|
82
109
|
}
|
|
@@ -27,4 +27,11 @@ export const entryPointsMapping = {
|
|
|
27
27
|
CustomThemeButton: '@atlaskit/button/custom-theme-button'
|
|
28
28
|
};
|
|
29
29
|
export const BUTTON_TYPES = ['Appearance', 'Spacing', 'BaseOwnProps', 'BaseProps', 'ButtonProps', 'LoadingButtonProps', 'LoadingButtonOwnProps', 'ThemeTokens', 'ThemeProps', 'InteractionState', 'CustomThemeButtonProps', 'CustomThemeButtonOwnProps'];
|
|
30
|
-
export const eslintDisableComment = 'eslint-disable-next-line @atlaskit/design-system/no-banned-imports';
|
|
30
|
+
export const eslintDisableComment = 'eslint-disable-next-line @atlaskit/design-system/no-banned-imports';
|
|
31
|
+
export const ButtonPropsTypeName = 'ButtonProps';
|
|
32
|
+
export const unsupportedProps = ['component', 'css', 'style'];
|
|
33
|
+
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.`;
|
|
34
|
+
export const iconPropsNoLongerSupportedComment = `"glyph", "primaryColor", "secondaryColor" and "testId" are no longer supported in button icons, please refactor the code and/or revisit the UI.`;
|
|
35
|
+
export const buttonPropsNoLongerSupportedComment = `Buttons with "component", "css" or "style" prop can't be automatically migrated with codemods. Please migrate it manually.`;
|
|
36
|
+
export const migrateFitContainerButtonToDefaultButtonComment = `Migrated to a default button with text which is from the icon label.`;
|
|
37
|
+
export const migrateFitContainerButtonToIconButtonComment = `"shouldFitContainer" is not available in icon buttons, please consider using a default button with text.`;
|
|
@@ -1,21 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { addCommentBefore } from '@atlaskit/codemod-utils';
|
|
2
|
+
import { NEW_BUTTON_VARIANTS, iconPropsNoLongerSupportedComment } from '../utils/constants';
|
|
3
|
+
export const getIconAttributes = attributes => {
|
|
3
4
|
const iconAttr = attributes === null || attributes === void 0 ? void 0 : attributes.filter(attribute => attribute.type === 'JSXAttribute' && (attribute.name.name === 'iconBefore' || attribute.name.name === 'iconAfter'));
|
|
4
|
-
if (
|
|
5
|
-
return iconAttr
|
|
5
|
+
if (iconAttr !== null && iconAttr !== void 0 && iconAttr.length) {
|
|
6
|
+
return iconAttr;
|
|
6
7
|
}
|
|
7
8
|
return null;
|
|
8
9
|
};
|
|
9
|
-
export const
|
|
10
|
+
export const getIconElement = iconAttr => {
|
|
10
11
|
var _iconAttr$value;
|
|
12
|
+
if (iconAttr && ((_iconAttr$value = iconAttr.value) === null || _iconAttr$value === void 0 ? void 0 : _iconAttr$value.type) === 'JSXExpressionContainer' && iconAttr.value.expression.type === 'JSXElement') {
|
|
13
|
+
return iconAttr.value.expression;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
export const moveSizeAndLabelAttributes = (element, j, iconRenamed = false) => {
|
|
11
18
|
const {
|
|
12
19
|
attributes
|
|
13
20
|
} = element.openingElement;
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
const iconAttrs = attributes && getIconAttributes(attributes);
|
|
22
|
+
iconAttrs === null || iconAttrs === void 0 ? void 0 : iconAttrs.forEach(iconAttr => {
|
|
23
|
+
var _iconAttr$value2;
|
|
24
|
+
const iconElement = getIconElement(iconAttr);
|
|
25
|
+
if (!iconElement) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
17
28
|
const iconJSXElementAttributes = iconElement.openingElement.attributes;
|
|
29
|
+
// add inlined comment to the icon if it has any attributes other than label and size
|
|
18
30
|
if (Array.isArray(iconJSXElementAttributes)) {
|
|
31
|
+
const ifIconAttributeEitherLabelOrSize = iconJSXElementAttributes === null || iconJSXElementAttributes === void 0 ? void 0 : iconJSXElementAttributes.every(attribute => attribute.type === 'JSXAttribute' && typeof attribute.name.name === 'string' && (attribute.name.name === 'size' || attribute.name.name === 'label'));
|
|
32
|
+
if (!ifIconAttributeEitherLabelOrSize) {
|
|
33
|
+
addCommentBefore(j, j(iconAttr), iconPropsNoLongerSupportedComment, 'line');
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
// move label and size attributes from icon to the root Button prop
|
|
20
37
|
const labelAttribute = iconJSXElementAttributes.find(attribute => attribute.type === 'JSXAttribute' && attribute.name.name === 'label');
|
|
21
38
|
if (labelAttribute && labelAttribute.type === 'JSXAttribute' && iconRenamed) {
|
|
@@ -29,22 +46,22 @@ export const moveSizeAndLabelAttributes = (element, j, iconRenamed = false) => {
|
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
// replace JSXElement with identifier {<MoreIcon />} => {MoreIcon}
|
|
32
|
-
if (iconElement.openingElement.name.type === 'JSXIdentifier') {
|
|
49
|
+
if (iconElement.openingElement.name.type === 'JSXIdentifier' && ((_iconAttr$value2 = iconAttr.value) === null || _iconAttr$value2 === void 0 ? void 0 : _iconAttr$value2.type) === 'JSXExpressionContainer') {
|
|
33
50
|
iconAttr.value.expression = j.identifier(iconElement.openingElement.name.name);
|
|
34
51
|
}
|
|
35
|
-
}
|
|
52
|
+
});
|
|
36
53
|
};
|
|
37
54
|
export const generateNewElement = (variant, element, j) => {
|
|
38
55
|
const {
|
|
39
56
|
attributes
|
|
40
57
|
} = element.openingElement;
|
|
41
|
-
const
|
|
58
|
+
const iconAttrs = attributes && getIconAttributes(attributes);
|
|
42
59
|
const isIconOrLinkIcon = variant === NEW_BUTTON_VARIANTS.icon.as || variant === NEW_BUTTON_VARIANTS.linkIcon.as;
|
|
43
|
-
if (isIconOrLinkIcon &&
|
|
60
|
+
if (isIconOrLinkIcon && iconAttrs !== null && iconAttrs !== void 0 && iconAttrs.length) {
|
|
44
61
|
moveSizeAndLabelAttributes(element, j, true);
|
|
45
62
|
|
|
46
63
|
// rename iconBefore/iconAfter to icon
|
|
47
|
-
|
|
64
|
+
iconAttrs[0].name.name = 'icon';
|
|
48
65
|
}
|
|
49
66
|
return j.jsxElement(
|
|
50
67
|
// self closing if it's an icon button or icon link button
|
|
@@ -0,0 +1,2 @@
|
|
|
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)))));
|
|
@@ -0,0 +1,4 @@
|
|
|
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;
|
|
4
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { addCommentBefore } from '@atlaskit/codemod-utils';
|
|
2
|
+
import { getIconAttributes, getIconElement } from '../utils/generate-new-button-element';
|
|
3
|
+
import { NEW_BUTTON_VARIANTS, migrateFitContainerButtonToDefaultButtonComment, migrateFitContainerButtonToIconButtonComment } from './constants';
|
|
4
|
+
export const migrateFitContainerIconButton = (element, j) => {
|
|
5
|
+
var _iconElement$openingE, _labelAttribute$value;
|
|
6
|
+
const {
|
|
7
|
+
attributes
|
|
8
|
+
} = element.value.openingElement;
|
|
9
|
+
const iconAttrs = attributes && getIconAttributes(attributes);
|
|
10
|
+
const iconElement = iconAttrs && iconAttrs[0] && getIconElement(iconAttrs[0]);
|
|
11
|
+
const labelAttribute = iconElement && Array.isArray(iconElement.openingElement.attributes) && ((_iconElement$openingE = iconElement.openingElement) === null || _iconElement$openingE === void 0 ? void 0 : _iconElement$openingE.attributes.find(path => path.type === 'JSXAttribute' && (path.name.name === 'label' || path.name.name === 'aria-label' || path.name.name === 'aria-labelledby')));
|
|
12
|
+
let migratedToIconButton;
|
|
13
|
+
if (labelAttribute && labelAttribute.type === 'JSXAttribute' && ((_labelAttribute$value = labelAttribute.value) === null || _labelAttribute$value === void 0 ? void 0 : _labelAttribute$value.type) === 'Literal' && typeof labelAttribute.value.value === 'string') {
|
|
14
|
+
migratedToIconButton = false;
|
|
15
|
+
const label = labelAttribute.value.value;
|
|
16
|
+
const formattedLabel = `${label.charAt(0).toUpperCase()}${label.slice(1)}`.split('-').join(' ');
|
|
17
|
+
j(element).find(j.JSXAttribute).filter(path => path.node.name.name === 'iconBefore' || path.node.name.name === 'iconAfter').remove();
|
|
18
|
+
const newButton = j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier(NEW_BUTTON_VARIANTS.default.as), attributes), j.jsxClosingElement(j.jsxIdentifier(NEW_BUTTON_VARIANTS.default.as)), [j.jsxText(formattedLabel)]);
|
|
19
|
+
j(element).replaceWith(newButton);
|
|
20
|
+
addCommentBefore(j, j(newButton).find(j.JSXAttribute).filter(path => path.node.name.name === 'shouldFitContainer'), migrateFitContainerButtonToDefaultButtonComment, 'line');
|
|
21
|
+
} else {
|
|
22
|
+
migratedToIconButton = true;
|
|
23
|
+
addCommentBefore(j, j(element).find(j.JSXAttribute).filter(path => path.node.name.name === 'iconBefore' || path.node.name.name === 'iconAfter'), migrateFitContainerButtonToIconButtonComment, 'line');
|
|
24
|
+
j(element).find(j.JSXAttribute).filter(path => path.node.name.name === 'shouldFitContainer').remove();
|
|
25
|
+
}
|
|
26
|
+
return migratedToIconButton;
|
|
27
|
+
};
|
package/dist/es2019/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { entryPointsMapping } from '../utils/constants';
|
|
2
|
+
export const renameDefaultButtonToLegacyButtonImport = (oldButtonImport, oldButtonElements, j) => {
|
|
3
|
+
oldButtonImport.insertBefore(j.importDeclaration([j.importDefaultSpecifier(j.identifier('LegacyButton'))], j.stringLiteral(entryPointsMapping.Button)));
|
|
4
|
+
oldButtonElements.forEach(element => {
|
|
5
|
+
var _element$value$childr, _element$value$childr2;
|
|
6
|
+
const legacyElement = j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier('LegacyButton'), 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('LegacyButton')), element.value.children);
|
|
7
|
+
j(element).replaceWith(legacyElement);
|
|
8
|
+
});
|
|
9
|
+
};
|
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.17.
|
|
301
|
+
_process$env$_PACKAGE = "0.17.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) {
|
package/dist/esm/presets/migrate-to-new-buttons/codemods/next-migrate-to-new-button-variants.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { addCommentBefore } from '@atlaskit/codemod-utils';
|
|
2
|
-
import { PRINT_SETTINGS, NEW_BUTTON_VARIANTS, entryPointsMapping, NEW_BUTTON_ENTRY_POINT, eslintDisableComment } from '../utils/constants';
|
|
2
|
+
import { PRINT_SETTINGS, NEW_BUTTON_VARIANTS, entryPointsMapping, NEW_BUTTON_ENTRY_POINT, eslintDisableComment, ButtonPropsTypeName, linkButtonMissingHrefComment, buttonPropsNoLongerSupportedComment, unsupportedProps } from '../utils/constants';
|
|
3
3
|
import { generateNewElement, moveSizeAndLabelAttributes } from '../utils/generate-new-button-element';
|
|
4
|
+
import { ifHasUnsupportedProps } from '../utils/has-unsupported-props';
|
|
5
|
+
import { checkIfVariantAlreadyImported } from '../utils/if-variant-already-imported';
|
|
6
|
+
import { renameDefaultButtonToLegacyButtonImport } from '../utils/rename-default-button-to-legacy-button';
|
|
7
|
+
import { migrateFitContainerIconButton } from '../utils/migrate-fit-container-icon-button';
|
|
4
8
|
var transformer = function transformer(file, api, options) {
|
|
5
9
|
var j = api.jscodeshift;
|
|
6
10
|
var fileSource = j(file.source);
|
|
@@ -17,33 +21,17 @@ var transformer = function transformer(file, api, options) {
|
|
|
17
21
|
return fileSource.toSource();
|
|
18
22
|
}
|
|
19
23
|
var specifierIdentifier = defaultButtonImport.get(0).node.local.name;
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
var hasCustomComponent = attributes.filter(function (attribute) {
|
|
24
|
-
return attribute.node.name.name === 'component';
|
|
25
|
-
}).length > 0;
|
|
26
|
-
var hasCssProp = attributes.filter(function (attribute) {
|
|
27
|
-
return attribute.node.name.name === 'css';
|
|
28
|
-
}).length > 0;
|
|
29
|
-
if (hasCustomComponent || hasCssProp) {
|
|
30
|
-
return fileSource.toSource(PRINT_SETTINGS);
|
|
31
|
-
}
|
|
32
|
-
var checkIfVariantAlreadyImported = function checkIfVariantAlreadyImported(variant) {
|
|
33
|
-
return fileSource.find(j.ImportDeclaration).filter(function (path) {
|
|
34
|
-
return path.node.source.value === NEW_BUTTON_ENTRY_POINT;
|
|
35
|
-
}).find(j.ImportSpecifier).filter(function (path) {
|
|
36
|
-
return path.node.imported.name === variant;
|
|
37
|
-
}).length > 0;
|
|
38
|
-
};
|
|
39
|
-
var hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon.import);
|
|
40
|
-
var hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link.import);
|
|
41
|
-
var hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon.import);
|
|
24
|
+
var hasLinkIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.linkIcon.import, fileSource, j);
|
|
25
|
+
var hasLinkButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.link.import, fileSource, j);
|
|
26
|
+
var hasIconButton = checkIfVariantAlreadyImported(NEW_BUTTON_VARIANTS.icon.import, fileSource, j);
|
|
42
27
|
var allButtons = fileSource.find(j.JSXElement).filter(function (path) {
|
|
43
28
|
return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier;
|
|
44
29
|
});
|
|
45
|
-
allButtons.
|
|
46
|
-
|
|
30
|
+
var buttonsWithoutUnsupportedProps = allButtons.filter(function (path) {
|
|
31
|
+
return !ifHasUnsupportedProps(path.value.openingElement.attributes);
|
|
32
|
+
});
|
|
33
|
+
buttonsWithoutUnsupportedProps.forEach(function (element) {
|
|
34
|
+
var _element$value$childr;
|
|
47
35
|
var attributes = element.value.openingElement.attributes;
|
|
48
36
|
if (!attributes) {
|
|
49
37
|
return;
|
|
@@ -53,18 +41,21 @@ var transformer = function transformer(file, api, options) {
|
|
|
53
41
|
});
|
|
54
42
|
var hasHref = buttonAttributes.includes('href');
|
|
55
43
|
var hasIcon = buttonAttributes.includes('iconBefore') || buttonAttributes.includes('iconAfter');
|
|
56
|
-
var
|
|
44
|
+
var hasNoChildren = ((_element$value$childr = element.value.children) === null || _element$value$childr === void 0 ? void 0 : _element$value$childr.length) === 0;
|
|
45
|
+
var isFitContainerIconButton = hasIcon && hasNoChildren && buttonAttributes.includes('shouldFitContainer');
|
|
46
|
+
var isLinkIconButton = hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
|
|
57
47
|
var isLinkButton = hasHref && !isLinkIconButton;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
var isIconButton = !hasHref && hasIcon && ((_element$value$childr2 = element.value.children) === null || _element$value$childr2 === void 0 ? void 0 : _element$value$childr2.length) === 0;
|
|
61
|
-
var isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && hasIcon;
|
|
62
|
-
|
|
63
|
-
// TODO: add checks for unsupported icon props except label and size, e.g. primaryColor, testId, or spread props
|
|
64
|
-
// and don't migrate these buttons.
|
|
48
|
+
var isIconButton = !hasHref && hasIcon && hasNoChildren && !isFitContainerIconButton;
|
|
49
|
+
var isDefaultButtonWithAnIcon = !isLinkIconButton && !isIconButton && !isFitContainerIconButton && hasIcon;
|
|
65
50
|
if (isDefaultButtonWithAnIcon) {
|
|
66
51
|
moveSizeAndLabelAttributes(element.value, j);
|
|
67
52
|
}
|
|
53
|
+
if (isFitContainerIconButton) {
|
|
54
|
+
var migratedToIconButton = migrateFitContainerIconButton(element, j);
|
|
55
|
+
if (migratedToIconButton) {
|
|
56
|
+
isIconButton = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
68
59
|
if (isLinkIconButton) {
|
|
69
60
|
hasLinkIconButton = true;
|
|
70
61
|
j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.linkIcon.as, element.value, j));
|
|
@@ -77,32 +68,66 @@ var transformer = function transformer(file, api, options) {
|
|
|
77
68
|
hasLinkButton = true;
|
|
78
69
|
j(element).replaceWith(generateNewElement(NEW_BUTTON_VARIANTS.link.as, element.value, j));
|
|
79
70
|
}
|
|
71
|
+
if (!hasHref && attributes.find(function (node) {
|
|
72
|
+
var _node$value, _node$name, _node$value2, _node$value3;
|
|
73
|
+
return node.type === 'JSXAttribute' && ((_node$value = node.value) === null || _node$value === void 0 ? void 0 : _node$value.type) === 'Literal' && (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');
|
|
74
|
+
})) {
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
addCommentBefore(j, [element], linkButtonMissingHrefComment);
|
|
77
|
+
}
|
|
80
78
|
});
|
|
81
79
|
var specifiers = [];
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
if (hasLinkIconButton) {
|
|
89
|
-
specifiers.push(j.importSpecifier(j.identifier(NEW_BUTTON_VARIANTS.linkIcon.import), j.identifier(NEW_BUTTON_VARIANTS.linkIcon.as)));
|
|
90
|
-
}
|
|
80
|
+
[hasLinkButton ? 'link' : null, hasIconButton ? 'icon' : null, hasLinkIconButton ? 'linkIcon' : null].forEach(function (variant) {
|
|
81
|
+
if (variant) {
|
|
82
|
+
specifiers.push(j.importSpecifier(j.identifier(NEW_BUTTON_VARIANTS[variant].import), j.identifier(NEW_BUTTON_VARIANTS[variant].as)));
|
|
83
|
+
}
|
|
84
|
+
});
|
|
91
85
|
var oldButtonImport = fileSource.find(j.ImportDeclaration).filter(function (path) {
|
|
92
86
|
return path.node.source.value === NEW_BUTTON_ENTRY_POINT || path.node.source.value === entryPointsMapping.Button;
|
|
93
87
|
});
|
|
94
88
|
var remainingDefaultButtons = fileSource.find(j.JSXElement).filter(function (path) {
|
|
95
|
-
return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier;
|
|
89
|
+
return path.value.openingElement.name.type === 'JSXIdentifier' && path.value.openingElement.name.name === specifierIdentifier && !ifHasUnsupportedProps(path.value.openingElement.attributes);
|
|
96
90
|
}).length > 0 || fileSource.find(j.CallExpression).filter(function (path) {
|
|
97
91
|
return path.node.arguments.map(function (argument) {
|
|
98
92
|
return argument.type === 'Identifier' && (argument === null || argument === void 0 ? void 0 : argument.name);
|
|
99
93
|
}).includes(specifierIdentifier);
|
|
100
94
|
}).length > 0;
|
|
95
|
+
if (remainingDefaultButtons) {
|
|
96
|
+
specifiers.push(j.importSpecifier(j.identifier(NEW_BUTTON_VARIANTS.default.import), j.identifier(specifierIdentifier)));
|
|
97
|
+
}
|
|
98
|
+
var buttonsWithUnsupportedProps = allButtons.filter(function (path) {
|
|
99
|
+
return ifHasUnsupportedProps(path.value.openingElement.attributes);
|
|
100
|
+
});
|
|
101
|
+
if (buttonsWithUnsupportedProps.length) {
|
|
102
|
+
// add comment to all buttons with unsupported props: "component", "style", "css"
|
|
103
|
+
buttonsWithUnsupportedProps.forEach(function (element) {
|
|
104
|
+
var _element$value$openin;
|
|
105
|
+
var attribute = (_element$value$openin = element.value.openingElement.attributes) === null || _element$value$openin === void 0 ? void 0 : _element$value$openin.find(function (node) {
|
|
106
|
+
return node.type === 'JSXAttribute' && typeof node.name.name === 'string' && unsupportedProps.includes(node.name.name);
|
|
107
|
+
});
|
|
108
|
+
if (attribute) {
|
|
109
|
+
addCommentBefore(j, j(attribute), buttonPropsNoLongerSupportedComment, 'line');
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// rename all buttons with unsupported props to LegacyButton if default new button is imported
|
|
114
|
+
if (specifiers.find(function (specifier) {
|
|
115
|
+
return specifier.imported.name === NEW_BUTTON_VARIANTS.default.import;
|
|
116
|
+
})) {
|
|
117
|
+
renameDefaultButtonToLegacyButtonImport(oldButtonImport, buttonsWithUnsupportedProps, j);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
101
120
|
if (specifiers.length || remainingDefaultButtons) {
|
|
102
|
-
|
|
103
|
-
|
|
121
|
+
// split the type imports into a separate import
|
|
122
|
+
var typeSpecifier = buttonImports.find(j.ImportSpecifier).filter(function (path) {
|
|
123
|
+
return path.node.imported.name === ButtonPropsTypeName;
|
|
124
|
+
});
|
|
125
|
+
if (typeSpecifier.length > 0) {
|
|
126
|
+
oldButtonImport.insertBefore(j.importDeclaration([j.importSpecifier(j.identifier(ButtonPropsTypeName), j.identifier(typeSpecifier.get(0).node.local.name))], j.stringLiteral(entryPointsMapping.Button), 'type'));
|
|
104
127
|
}
|
|
105
128
|
oldButtonImport.replaceWith(j.importDeclaration(specifiers, j.stringLiteral(NEW_BUTTON_ENTRY_POINT)));
|
|
129
|
+
|
|
130
|
+
// add eslint-disable-next-line @atlaskit/design-system/no-banned-imports comment if unsafe import is allowed in custom options
|
|
106
131
|
if (NEW_BUTTON_ENTRY_POINT.includes('unsafe') && (options === null || options === void 0 ? void 0 : options.allowUnsafeImport) === true) {
|
|
107
132
|
addCommentBefore(j, fileSource.find(j.ImportDeclaration).filter(function (path) {
|
|
108
133
|
return path.node.source.value === NEW_BUTTON_ENTRY_POINT;
|
|
@@ -27,4 +27,11 @@ export var entryPointsMapping = {
|
|
|
27
27
|
CustomThemeButton: '@atlaskit/button/custom-theme-button'
|
|
28
28
|
};
|
|
29
29
|
export var BUTTON_TYPES = ['Appearance', 'Spacing', 'BaseOwnProps', 'BaseProps', 'ButtonProps', 'LoadingButtonProps', 'LoadingButtonOwnProps', 'ThemeTokens', 'ThemeProps', 'InteractionState', 'CustomThemeButtonProps', 'CustomThemeButtonOwnProps'];
|
|
30
|
-
export var eslintDisableComment = 'eslint-disable-next-line @atlaskit/design-system/no-banned-imports';
|
|
30
|
+
export var eslintDisableComment = 'eslint-disable-next-line @atlaskit/design-system/no-banned-imports';
|
|
31
|
+
export var ButtonPropsTypeName = 'ButtonProps';
|
|
32
|
+
export var unsupportedProps = ['component', 'css', 'style'];
|
|
33
|
+
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.";
|
|
34
|
+
export var iconPropsNoLongerSupportedComment = "\"glyph\", \"primaryColor\", \"secondaryColor\" and \"testId\" are no longer supported in button icons, please refactor the code and/or revisit the UI.";
|
|
35
|
+
export var buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
|
|
36
|
+
export var migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
|
|
37
|
+
export var migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
|
|
@@ -1,22 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { addCommentBefore } from '@atlaskit/codemod-utils';
|
|
2
|
+
import { NEW_BUTTON_VARIANTS, iconPropsNoLongerSupportedComment } from '../utils/constants';
|
|
3
|
+
export var getIconAttributes = function getIconAttributes(attributes) {
|
|
3
4
|
var iconAttr = attributes === null || attributes === void 0 ? void 0 : attributes.filter(function (attribute) {
|
|
4
5
|
return attribute.type === 'JSXAttribute' && (attribute.name.name === 'iconBefore' || attribute.name.name === 'iconAfter');
|
|
5
6
|
});
|
|
6
|
-
if (
|
|
7
|
-
return iconAttr
|
|
7
|
+
if (iconAttr !== null && iconAttr !== void 0 && iconAttr.length) {
|
|
8
|
+
return iconAttr;
|
|
8
9
|
}
|
|
9
10
|
return null;
|
|
10
11
|
};
|
|
11
|
-
export var
|
|
12
|
+
export var getIconElement = function getIconElement(iconAttr) {
|
|
12
13
|
var _iconAttr$value;
|
|
14
|
+
if (iconAttr && ((_iconAttr$value = iconAttr.value) === null || _iconAttr$value === void 0 ? void 0 : _iconAttr$value.type) === 'JSXExpressionContainer' && iconAttr.value.expression.type === 'JSXElement') {
|
|
15
|
+
return iconAttr.value.expression;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
export var moveSizeAndLabelAttributes = function moveSizeAndLabelAttributes(element, j) {
|
|
13
20
|
var iconRenamed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
14
21
|
var attributes = element.openingElement.attributes;
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
var
|
|
22
|
+
var iconAttrs = attributes && getIconAttributes(attributes);
|
|
23
|
+
iconAttrs === null || iconAttrs === void 0 || iconAttrs.forEach(function (iconAttr) {
|
|
24
|
+
var _iconAttr$value2;
|
|
25
|
+
var iconElement = getIconElement(iconAttr);
|
|
26
|
+
if (!iconElement) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
18
29
|
var iconJSXElementAttributes = iconElement.openingElement.attributes;
|
|
30
|
+
// add inlined comment to the icon if it has any attributes other than label and size
|
|
19
31
|
if (Array.isArray(iconJSXElementAttributes)) {
|
|
32
|
+
var ifIconAttributeEitherLabelOrSize = iconJSXElementAttributes === null || iconJSXElementAttributes === void 0 ? void 0 : iconJSXElementAttributes.every(function (attribute) {
|
|
33
|
+
return attribute.type === 'JSXAttribute' && typeof attribute.name.name === 'string' && (attribute.name.name === 'size' || attribute.name.name === 'label');
|
|
34
|
+
});
|
|
35
|
+
if (!ifIconAttributeEitherLabelOrSize) {
|
|
36
|
+
addCommentBefore(j, j(iconAttr), iconPropsNoLongerSupportedComment, 'line');
|
|
37
|
+
}
|
|
38
|
+
|
|
20
39
|
// move label and size attributes from icon to the root Button prop
|
|
21
40
|
var labelAttribute = iconJSXElementAttributes.find(function (attribute) {
|
|
22
41
|
return attribute.type === 'JSXAttribute' && attribute.name.name === 'label';
|
|
@@ -34,20 +53,20 @@ export var moveSizeAndLabelAttributes = function moveSizeAndLabelAttributes(elem
|
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
// replace JSXElement with identifier {<MoreIcon />} => {MoreIcon}
|
|
37
|
-
if (iconElement.openingElement.name.type === 'JSXIdentifier') {
|
|
56
|
+
if (iconElement.openingElement.name.type === 'JSXIdentifier' && ((_iconAttr$value2 = iconAttr.value) === null || _iconAttr$value2 === void 0 ? void 0 : _iconAttr$value2.type) === 'JSXExpressionContainer') {
|
|
38
57
|
iconAttr.value.expression = j.identifier(iconElement.openingElement.name.name);
|
|
39
58
|
}
|
|
40
|
-
}
|
|
59
|
+
});
|
|
41
60
|
};
|
|
42
61
|
export var generateNewElement = function generateNewElement(variant, element, j) {
|
|
43
62
|
var attributes = element.openingElement.attributes;
|
|
44
|
-
var
|
|
63
|
+
var iconAttrs = attributes && getIconAttributes(attributes);
|
|
45
64
|
var isIconOrLinkIcon = variant === NEW_BUTTON_VARIANTS.icon.as || variant === NEW_BUTTON_VARIANTS.linkIcon.as;
|
|
46
|
-
if (isIconOrLinkIcon &&
|
|
65
|
+
if (isIconOrLinkIcon && iconAttrs !== null && iconAttrs !== void 0 && iconAttrs.length) {
|
|
47
66
|
moveSizeAndLabelAttributes(element, j, true);
|
|
48
67
|
|
|
49
68
|
// rename iconBefore/iconAfter to icon
|
|
50
|
-
|
|
69
|
+
iconAttrs[0].name.name = 'icon';
|
|
51
70
|
}
|
|
52
71
|
return j.jsxElement(
|
|
53
72
|
// self closing if it's an icon button or icon link button
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { unsupportedProps } from './constants';
|
|
2
|
+
export var ifHasUnsupportedProps = function ifHasUnsupportedProps(attributes) {
|
|
3
|
+
return Boolean(attributes && (attributes === null || attributes === void 0 ? void 0 : attributes.some(function (node) {
|
|
4
|
+
return node.type === 'JSXAttribute' && unsupportedProps.includes(String(node.name.name));
|
|
5
|
+
})));
|
|
6
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
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) {
|
|
6
|
+
return path.node.imported.name === variant;
|
|
7
|
+
}).length > 0;
|
|
8
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { addCommentBefore } from '@atlaskit/codemod-utils';
|
|
2
|
+
import { getIconAttributes, getIconElement } from '../utils/generate-new-button-element';
|
|
3
|
+
import { NEW_BUTTON_VARIANTS, migrateFitContainerButtonToDefaultButtonComment, migrateFitContainerButtonToIconButtonComment } from './constants';
|
|
4
|
+
export var migrateFitContainerIconButton = function migrateFitContainerIconButton(element, j) {
|
|
5
|
+
var _iconElement$openingE, _labelAttribute$value;
|
|
6
|
+
var attributes = element.value.openingElement.attributes;
|
|
7
|
+
var iconAttrs = attributes && getIconAttributes(attributes);
|
|
8
|
+
var iconElement = iconAttrs && iconAttrs[0] && getIconElement(iconAttrs[0]);
|
|
9
|
+
var labelAttribute = iconElement && Array.isArray(iconElement.openingElement.attributes) && ((_iconElement$openingE = iconElement.openingElement) === null || _iconElement$openingE === void 0 ? void 0 : _iconElement$openingE.attributes.find(function (path) {
|
|
10
|
+
return path.type === 'JSXAttribute' && (path.name.name === 'label' || path.name.name === 'aria-label' || path.name.name === 'aria-labelledby');
|
|
11
|
+
}));
|
|
12
|
+
var migratedToIconButton;
|
|
13
|
+
if (labelAttribute && labelAttribute.type === 'JSXAttribute' && ((_labelAttribute$value = labelAttribute.value) === null || _labelAttribute$value === void 0 ? void 0 : _labelAttribute$value.type) === 'Literal' && typeof labelAttribute.value.value === 'string') {
|
|
14
|
+
migratedToIconButton = false;
|
|
15
|
+
var label = labelAttribute.value.value;
|
|
16
|
+
var formattedLabel = "".concat(label.charAt(0).toUpperCase()).concat(label.slice(1)).split('-').join(' ');
|
|
17
|
+
j(element).find(j.JSXAttribute).filter(function (path) {
|
|
18
|
+
return path.node.name.name === 'iconBefore' || path.node.name.name === 'iconAfter';
|
|
19
|
+
}).remove();
|
|
20
|
+
var newButton = j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier(NEW_BUTTON_VARIANTS.default.as), attributes), j.jsxClosingElement(j.jsxIdentifier(NEW_BUTTON_VARIANTS.default.as)), [j.jsxText(formattedLabel)]);
|
|
21
|
+
j(element).replaceWith(newButton);
|
|
22
|
+
addCommentBefore(j, j(newButton).find(j.JSXAttribute).filter(function (path) {
|
|
23
|
+
return path.node.name.name === 'shouldFitContainer';
|
|
24
|
+
}), migrateFitContainerButtonToDefaultButtonComment, 'line');
|
|
25
|
+
} else {
|
|
26
|
+
migratedToIconButton = true;
|
|
27
|
+
addCommentBefore(j, j(element).find(j.JSXAttribute).filter(function (path) {
|
|
28
|
+
return path.node.name.name === 'iconBefore' || path.node.name.name === 'iconAfter';
|
|
29
|
+
}), migrateFitContainerButtonToIconButtonComment, 'line');
|
|
30
|
+
j(element).find(j.JSXAttribute).filter(function (path) {
|
|
31
|
+
return path.node.name.name === 'shouldFitContainer';
|
|
32
|
+
}).remove();
|
|
33
|
+
}
|
|
34
|
+
return migratedToIconButton;
|
|
35
|
+
};
|
package/dist/esm/presets/migrate-to-new-buttons/utils/rename-default-button-to-legacy-button.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { entryPointsMapping } from '../utils/constants';
|
|
2
|
+
export var renameDefaultButtonToLegacyButtonImport = function renameDefaultButtonToLegacyButtonImport(oldButtonImport, oldButtonElements, j) {
|
|
3
|
+
oldButtonImport.insertBefore(j.importDeclaration([j.importDefaultSpecifier(j.identifier('LegacyButton'))], j.stringLiteral(entryPointsMapping.Button)));
|
|
4
|
+
oldButtonElements.forEach(function (element) {
|
|
5
|
+
var _element$value$childr, _element$value$childr2;
|
|
6
|
+
var legacyElement = j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier('LegacyButton'), 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('LegacyButton')), element.value.children);
|
|
7
|
+
j(element).replaceWith(legacyElement);
|
|
8
|
+
});
|
|
9
|
+
};
|
|
@@ -13,3 +13,10 @@ export declare const entryPointsMapping: {
|
|
|
13
13
|
};
|
|
14
14
|
export declare const BUTTON_TYPES: string[];
|
|
15
15
|
export declare const eslintDisableComment = "eslint-disable-next-line @atlaskit/design-system/no-banned-imports";
|
|
16
|
+
export declare const ButtonPropsTypeName = "ButtonProps";
|
|
17
|
+
export declare const unsupportedProps: string[];
|
|
18
|
+
export declare 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.";
|
|
19
|
+
export declare const iconPropsNoLongerSupportedComment = "\"glyph\", \"primaryColor\", \"secondaryColor\" and \"testId\" are no longer supported in button icons, please refactor the code and/or revisit the UI.";
|
|
20
|
+
export declare const buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
|
|
21
|
+
export declare const migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
|
|
22
|
+
export declare const migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { API, JSXElement } from 'jscodeshift';
|
|
1
|
+
import type { API, JSXElement, JSXAttribute, JSXSpreadAttribute } from 'jscodeshift';
|
|
2
2
|
import { NEW_BUTTON_VARIANTS } from '../utils/constants';
|
|
3
|
+
export declare const getIconAttributes: (attributes: (JSXAttribute | JSXSpreadAttribute)[]) => JSXAttribute[] | null;
|
|
4
|
+
export declare const getIconElement: (iconAttr: JSXAttribute) => JSXElement | null;
|
|
3
5
|
export declare const moveSizeAndLabelAttributes: (element: JSXElement, j: API['jscodeshift'], iconRenamed?: boolean) => void;
|
|
4
6
|
export declare const generateNewElement: (variant: (typeof NEW_BUTTON_VARIANTS)[keyof typeof NEW_BUTTON_VARIANTS]['as'], element: JSXElement, j: API['jscodeshift']) => JSXElement;
|
|
@@ -13,3 +13,10 @@ export declare const entryPointsMapping: {
|
|
|
13
13
|
};
|
|
14
14
|
export declare const BUTTON_TYPES: string[];
|
|
15
15
|
export declare const eslintDisableComment = "eslint-disable-next-line @atlaskit/design-system/no-banned-imports";
|
|
16
|
+
export declare const ButtonPropsTypeName = "ButtonProps";
|
|
17
|
+
export declare const unsupportedProps: string[];
|
|
18
|
+
export declare 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.";
|
|
19
|
+
export declare const iconPropsNoLongerSupportedComment = "\"glyph\", \"primaryColor\", \"secondaryColor\" and \"testId\" are no longer supported in button icons, please refactor the code and/or revisit the UI.";
|
|
20
|
+
export declare const buttonPropsNoLongerSupportedComment = "Buttons with \"component\", \"css\" or \"style\" prop can't be automatically migrated with codemods. Please migrate it manually.";
|
|
21
|
+
export declare const migrateFitContainerButtonToDefaultButtonComment = "Migrated to a default button with text which is from the icon label.";
|
|
22
|
+
export declare const migrateFitContainerButtonToIconButtonComment = "\"shouldFitContainer\" is not available in icon buttons, please consider using a default button with text.";
|
package/dist/types-ts4.5/presets/migrate-to-new-buttons/utils/generate-new-button-element.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { API, JSXElement } from 'jscodeshift';
|
|
1
|
+
import type { API, JSXElement, JSXAttribute, JSXSpreadAttribute } from 'jscodeshift';
|
|
2
2
|
import { NEW_BUTTON_VARIANTS } from '../utils/constants';
|
|
3
|
+
export declare const getIconAttributes: (attributes: (JSXAttribute | JSXSpreadAttribute)[]) => JSXAttribute[] | null;
|
|
4
|
+
export declare const getIconElement: (iconAttr: JSXAttribute) => JSXElement | null;
|
|
3
5
|
export declare const moveSizeAndLabelAttributes: (element: JSXElement, j: API['jscodeshift'], iconRenamed?: boolean) => void;
|
|
4
6
|
export declare const generateNewElement: (variant: (typeof NEW_BUTTON_VARIANTS)[keyof typeof NEW_BUTTON_VARIANTS]['as'], element: JSXElement, j: API['jscodeshift']) => JSXElement;
|
package/package.json
CHANGED