@atlaskit/eslint-plugin-design-system 10.21.0 → 10.22.1
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 +16 -0
- package/README.md +1 -1
- package/dist/cjs/rules/ensure-design-token-usage/color.js +1 -1
- package/dist/cjs/rules/no-html-anchor/index.js +1 -0
- package/dist/cjs/rules/no-html-anchor/node-types/jsx-element/index.js +126 -4
- package/dist/cjs/rules/no-legacy-icons/checks.js +18 -6
- package/dist/cjs/rules/no-legacy-icons/helpers.js +4 -7
- package/dist/es2019/rules/ensure-design-token-usage/color.js +1 -1
- package/dist/es2019/rules/no-html-anchor/index.js +1 -0
- package/dist/es2019/rules/no-html-anchor/node-types/jsx-element/index.js +97 -2
- package/dist/es2019/rules/no-legacy-icons/checks.js +18 -6
- package/dist/es2019/rules/no-legacy-icons/helpers.js +3 -6
- package/dist/esm/rules/ensure-design-token-usage/color.js +1 -1
- package/dist/esm/rules/no-html-anchor/index.js +1 -0
- package/dist/esm/rules/no-html-anchor/node-types/jsx-element/index.js +126 -2
- package/dist/esm/rules/no-legacy-icons/checks.js +18 -6
- package/dist/esm/rules/no-legacy-icons/helpers.js +4 -7
- package/dist/types/rules/no-legacy-icons/helpers.d.ts +2 -2
- package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +2 -2
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-design-system
|
|
2
2
|
|
|
3
|
+
## 10.22.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#153007](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/153007)
|
|
8
|
+
[`89e8b9b297149`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/89e8b9b297149) -
|
|
9
|
+
Update `ensure-design-token-usage` rule to avoid false positive with Icon Tile component
|
|
10
|
+
|
|
11
|
+
## 10.22.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [#147366](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/147366)
|
|
16
|
+
[`7f5bab6a1ebd1`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/7f5bab6a1ebd1) -
|
|
17
|
+
Add fixes for html anchors in the no-html-anchor rule
|
|
18
|
+
|
|
3
19
|
## 10.21.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ module.exports = {
|
|
|
65
65
|
| <a href="./src/rules/no-empty-styled-expression/README.md">no-empty-styled-expression</a> | Forbids any styled expression to be used when passing empty arguments to styled.div() (or other JSX elements). | | | |
|
|
66
66
|
| <a href="./src/rules/no-exported-css/README.md">no-exported-css</a> | Forbid exporting `css` function calls. Exporting `css` function calls can result in unexpected behaviour at runtime, and is not statically analysable. | | | |
|
|
67
67
|
| <a href="./src/rules/no-exported-keyframes/README.md">no-exported-keyframes</a> | Forbid exporting `keyframes` function calls. Exporting `css` function calls can result in unexpected behaviour at runtime, and is not statically analysable. | | | |
|
|
68
|
-
| <a href="./src/rules/no-html-anchor/README.md">no-html-anchor</a> | Discourage direct usage of HTML anchor elements in favor of Atlassian Design System link components. | Yes | |
|
|
68
|
+
| <a href="./src/rules/no-html-anchor/README.md">no-html-anchor</a> | Discourage direct usage of HTML anchor elements in favor of Atlassian Design System link components. | Yes | | Yes |
|
|
69
69
|
| <a href="./src/rules/no-html-button/README.md">no-html-button</a> | Discourage direct usage of HTML button elements in favor of Atlassian Design System button components. | Yes | | |
|
|
70
70
|
| <a href="./src/rules/no-invalid-css-map/README.md">no-invalid-css-map</a> | Checks the validity of a CSS map created through cssMap. This is intended to be used alongside TypeScript's type-checking. | Yes | | |
|
|
71
71
|
| <a href="./src/rules/no-keyframes-tagged-template-expression/README.md">no-keyframes-tagged-template-expression</a> | Disallows any `keyframe` tagged template expressions that originate from Emotion, Styled Components or Compiled | | Yes | |
|
|
@@ -148,7 +148,7 @@ var lintJSXLiteralForColor = exports.lintJSXLiteralForColor = function lintJSXLi
|
|
|
148
148
|
if ((0, _isNode.isDecendantOfPrimitive)(node.parent, context)) {
|
|
149
149
|
return;
|
|
150
150
|
}
|
|
151
|
-
if (['alt', 'src', 'label', 'key'].includes(node.parent.name.name)) {
|
|
151
|
+
if (['alt', 'src', 'label', 'key', 'appearance'].includes(node.parent.name.name)) {
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
154
|
var isException = (0, _getIsException.getIsException)(config.exceptions);
|
|
@@ -10,6 +10,7 @@ var rule = (0, _createRule.createLintRule)({
|
|
|
10
10
|
meta: {
|
|
11
11
|
name: 'no-html-anchor',
|
|
12
12
|
type: 'suggestion',
|
|
13
|
+
hasSuggestions: true,
|
|
13
14
|
docs: {
|
|
14
15
|
description: 'Discourage direct usage of HTML anchor elements in favor of Atlassian Design System link components.',
|
|
15
16
|
recommended: true,
|
|
@@ -9,20 +9,142 @@ var ast = _interopRequireWildcard(require("../../../../ast-nodes"));
|
|
|
9
9
|
var _supported = require("../supported");
|
|
10
10
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
11
11
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
13
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
14
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } /* eslint-disable @repo/internal/react/require-jsdoc */
|
|
15
|
+
function isImportDeclaration(node) {
|
|
16
|
+
return node.type === 'ImportDeclaration';
|
|
17
|
+
}
|
|
14
18
|
var JSXElement = exports.JSXElement = {
|
|
15
19
|
lint: function lint(node, _ref) {
|
|
16
20
|
var context = _ref.context;
|
|
17
21
|
if (!(0, _supported.isSupportedForLint)(node)) {
|
|
18
22
|
return;
|
|
19
23
|
}
|
|
24
|
+
var nodeName = ast.JSXElement.getName(node);
|
|
25
|
+
var sourceCode = context.getSourceCode();
|
|
26
|
+
var importDeclarations = sourceCode.ast.body.filter(isImportDeclaration);
|
|
27
|
+
var existingLinkName = null;
|
|
28
|
+
var existingLinkButtonName = null;
|
|
29
|
+
var usedNames = new Set();
|
|
30
|
+
|
|
31
|
+
// Check for existing imports
|
|
32
|
+
var _iterator = _createForOfIteratorHelper(importDeclarations),
|
|
33
|
+
_step;
|
|
34
|
+
try {
|
|
35
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
36
|
+
var declaration = _step.value;
|
|
37
|
+
var _iterator2 = _createForOfIteratorHelper(declaration.specifiers),
|
|
38
|
+
_step2;
|
|
39
|
+
try {
|
|
40
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
41
|
+
var specifier = _step2.value;
|
|
42
|
+
usedNames.add(specifier.local.name);
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
_iterator2.e(err);
|
|
46
|
+
} finally {
|
|
47
|
+
_iterator2.f();
|
|
48
|
+
}
|
|
49
|
+
if (declaration.source.value === '@atlaskit/link') {
|
|
50
|
+
var defaultSpecifier = declaration.specifiers.find(function (specifier) {
|
|
51
|
+
return specifier.type === 'ImportDefaultSpecifier';
|
|
52
|
+
});
|
|
53
|
+
if (defaultSpecifier) {
|
|
54
|
+
existingLinkName = defaultSpecifier.local.name;
|
|
55
|
+
}
|
|
56
|
+
} else if (declaration.source.value === '@atlaskit/button/new') {
|
|
57
|
+
var namedSpecifier = declaration.specifiers.find(function (specifier) {
|
|
58
|
+
return specifier.type === 'ImportSpecifier' && specifier.imported.name === 'LinkButton';
|
|
59
|
+
});
|
|
60
|
+
if (namedSpecifier) {
|
|
61
|
+
existingLinkButtonName = namedSpecifier.local.name;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
_iterator.e(err);
|
|
67
|
+
} finally {
|
|
68
|
+
_iterator.f();
|
|
69
|
+
}
|
|
70
|
+
var generateUniqueName = function generateUniqueName(baseName) {
|
|
71
|
+
var index = 1;
|
|
72
|
+
var newName = baseName;
|
|
73
|
+
while (usedNames.has(newName)) {
|
|
74
|
+
newName = "".concat(baseName).concat(index);
|
|
75
|
+
index++;
|
|
76
|
+
}
|
|
77
|
+
return newName;
|
|
78
|
+
};
|
|
79
|
+
var linkName = existingLinkName || generateUniqueName('Link');
|
|
80
|
+
var linkButtonName = existingLinkButtonName || generateUniqueName('LinkButton');
|
|
20
81
|
context.report({
|
|
21
82
|
node: node.openingElement,
|
|
22
83
|
messageId: 'noHtmlAnchor',
|
|
23
84
|
data: {
|
|
24
|
-
name:
|
|
25
|
-
}
|
|
85
|
+
name: nodeName
|
|
86
|
+
},
|
|
87
|
+
suggest: [{
|
|
88
|
+
desc: 'Replace with Link component from @atlaskit/link',
|
|
89
|
+
fix: function fix(fixer) {
|
|
90
|
+
var _node$closingElement;
|
|
91
|
+
var openingTagRange = node.openingElement.range;
|
|
92
|
+
var closingTagRange = (_node$closingElement = node.closingElement) === null || _node$closingElement === void 0 ? void 0 : _node$closingElement.range;
|
|
93
|
+
var attributesText = node.openingElement.attributes.map(function (attr) {
|
|
94
|
+
return sourceCode.getText(attr);
|
|
95
|
+
}).join(' ');
|
|
96
|
+
var fixers = [];
|
|
97
|
+
|
|
98
|
+
// Replace <a> with <Link> and retain attributes
|
|
99
|
+
if (openingTagRange) {
|
|
100
|
+
if (node.openingElement.selfClosing) {
|
|
101
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkName).concat(attributesText ? " ".concat(attributesText) : '', " /")));
|
|
102
|
+
} else {
|
|
103
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkName).concat(attributesText ? " ".concat(attributesText) : '')));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
107
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], linkName));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Add import if not present
|
|
111
|
+
if (!existingLinkName) {
|
|
112
|
+
var importStatement = "import ".concat(linkName, " from '@atlaskit/link';\n");
|
|
113
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
114
|
+
}
|
|
115
|
+
return fixers;
|
|
116
|
+
}
|
|
117
|
+
}, {
|
|
118
|
+
desc: 'Replace with LinkButton component from @atlaskit/button/new',
|
|
119
|
+
fix: function fix(fixer) {
|
|
120
|
+
var _node$closingElement2;
|
|
121
|
+
var openingTagRange = node.openingElement.range;
|
|
122
|
+
var closingTagRange = (_node$closingElement2 = node.closingElement) === null || _node$closingElement2 === void 0 ? void 0 : _node$closingElement2.range;
|
|
123
|
+
var attributesText = node.openingElement.attributes.map(function (attr) {
|
|
124
|
+
return sourceCode.getText(attr);
|
|
125
|
+
}).join(' ');
|
|
126
|
+
var fixers = [];
|
|
127
|
+
|
|
128
|
+
// Replace <a> with <LinkButton> and retain attributes
|
|
129
|
+
if (openingTagRange) {
|
|
130
|
+
if (node.openingElement.selfClosing) {
|
|
131
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkButtonName).concat(attributesText ? " ".concat(attributesText) : '', " /")));
|
|
132
|
+
} else {
|
|
133
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkButtonName).concat(attributesText ? " ".concat(attributesText) : '')));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
137
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], linkButtonName));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Add import if not present
|
|
141
|
+
if (!existingLinkButtonName) {
|
|
142
|
+
var importStatement = "import { ".concat(linkButtonName, " } from '@atlaskit/button/new';\n");
|
|
143
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
144
|
+
}
|
|
145
|
+
return fixers;
|
|
146
|
+
}
|
|
147
|
+
}]
|
|
26
148
|
});
|
|
27
149
|
}
|
|
28
150
|
};
|
|
@@ -392,14 +392,14 @@ var createChecks = exports.createChecks = function createChecks(context) {
|
|
|
392
392
|
importSource: migrationIconImports[name].packageName,
|
|
393
393
|
iconName: name,
|
|
394
394
|
errors: errorsAuto,
|
|
395
|
-
shouldAddSpaciousSpacing:
|
|
395
|
+
spacing: shouldAddSpaciousSpacing ? 'spacious' : undefined,
|
|
396
396
|
insideNewButton: insideNewButton
|
|
397
397
|
});
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
// Legacy icons rendered as JSX elements
|
|
401
401
|
if (Object.keys(legacyIconImports).includes(name)) {
|
|
402
|
-
var _size, _size2
|
|
402
|
+
var _size, _size2;
|
|
403
403
|
// Determine if inside a new button - if so:
|
|
404
404
|
// - Assume spread props are safe - still error if props explicitly set to unmigratable values
|
|
405
405
|
var _insideNewButton = (0, _helpers.isInsideNewButton)(node, newButtonImports);
|
|
@@ -488,20 +488,32 @@ var createChecks = exports.createChecks = function createChecks(context) {
|
|
|
488
488
|
var newIcon = migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.newIcon;
|
|
489
489
|
var isNewIconMigratable = (0, _helpers.canAutoMigrateNewIconBasedOnSize)(upcomingIcon ? upcomingIcon.sizeGuidance[(_size = size) !== null && _size !== void 0 ? _size : 'medium'] : migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.sizeGuidance[(_size2 = size) !== null && _size2 !== void 0 ? _size2 : 'medium']);
|
|
490
490
|
|
|
491
|
-
// Add
|
|
492
|
-
// 1. size is medium, or not set (default is medium)
|
|
491
|
+
// Add spacing if:
|
|
492
|
+
// 1. size is medium for core/utility icons or small for utility icons, or not set (default is medium for core and small for utility icons)
|
|
493
493
|
// 2. not inside a new or legacy button
|
|
494
494
|
var _sizeProp = node.openingElement.attributes.find(function (attribute) {
|
|
495
495
|
return attribute.type === 'JSXAttribute' && (attribute.name.name === 'size' || attribute.name.name === 'LEGACY_size');
|
|
496
496
|
});
|
|
497
|
-
var
|
|
497
|
+
var spacing;
|
|
498
|
+
if (!_insideNewButton && !insideLegacyButton) {
|
|
499
|
+
var _sizeProp$value2;
|
|
500
|
+
if (_sizeProp && _sizeProp.type === 'JSXAttribute' && ((_sizeProp$value2 = _sizeProp.value) === null || _sizeProp$value2 === void 0 ? void 0 : _sizeProp$value2.type) === 'Literal') {
|
|
501
|
+
if (_sizeProp.value.value === 'medium') {
|
|
502
|
+
spacing = 'spacious';
|
|
503
|
+
} else if (_sizeProp.value.value === 'small' && (newIcon === null || newIcon === void 0 ? void 0 : newIcon.type) === 'utility') {
|
|
504
|
+
spacing = 'compact';
|
|
505
|
+
}
|
|
506
|
+
} else if (!_sizeProp) {
|
|
507
|
+
spacing = 'spacious';
|
|
508
|
+
}
|
|
509
|
+
}
|
|
498
510
|
if (!hasManualMigration && (newIcon || upcomingIcon) && isNewIconMigratable) {
|
|
499
511
|
(0, _helpers.createAutoMigrationError)({
|
|
500
512
|
node: node,
|
|
501
513
|
importSource: legacyIconImports[name].packageName,
|
|
502
514
|
iconName: name,
|
|
503
515
|
errors: errorsAuto,
|
|
504
|
-
|
|
516
|
+
spacing: spacing,
|
|
505
517
|
insideNewButton: _insideNewButton
|
|
506
518
|
});
|
|
507
519
|
} else if ((!newIcon && !upcomingIcon || !isNewIconMigratable) && size) {
|
|
@@ -279,7 +279,7 @@ var createAutoMigrationError = exports.createAutoMigrationError = function creat
|
|
|
279
279
|
importSource = _ref4.importSource,
|
|
280
280
|
iconName = _ref4.iconName,
|
|
281
281
|
errors = _ref4.errors,
|
|
282
|
-
|
|
282
|
+
spacing = _ref4.spacing,
|
|
283
283
|
insideNewButton = _ref4.insideNewButton;
|
|
284
284
|
var myError = {
|
|
285
285
|
node: node,
|
|
@@ -287,7 +287,7 @@ var createAutoMigrationError = exports.createAutoMigrationError = function creat
|
|
|
287
287
|
data: {
|
|
288
288
|
importSource: importSource,
|
|
289
289
|
iconName: iconName,
|
|
290
|
-
spacing:
|
|
290
|
+
spacing: spacing !== null && spacing !== void 0 ? spacing : '',
|
|
291
291
|
// value type need to be a string in Rule.ReportDescriptor
|
|
292
292
|
insideNewButton: String(insideNewButton)
|
|
293
293
|
}
|
|
@@ -480,14 +480,11 @@ var createPropFixes = function createPropFixes(_ref7) {
|
|
|
480
480
|
migrationImportNode = _ref7.migrationImportNode,
|
|
481
481
|
newIconName = _ref7.newIconName;
|
|
482
482
|
var fixes = [];
|
|
483
|
-
var
|
|
484
|
-
spacing = metadata.spacing,
|
|
483
|
+
var spacing = metadata.spacing,
|
|
485
484
|
insideNewButton = metadata.insideNewButton;
|
|
486
485
|
if (shouldUseMigrationPath && !legacyImportNode) {
|
|
487
486
|
return fixes;
|
|
488
487
|
}
|
|
489
|
-
var importPath = migrationImportNode ? importSource.replace('/migration', '').split('--')[0] : getNewIconNameAndImportPath(importSource, shouldUseMigrationPath).importPath;
|
|
490
|
-
var iconType = importPath !== null && importPath !== void 0 && importPath.startsWith('@atlaskit/icon/core') ? 'core' : 'utility';
|
|
491
488
|
if (node.type === 'JSXElement') {
|
|
492
489
|
var openingElement = node.openingElement;
|
|
493
490
|
if (newIconName) {
|
|
@@ -519,7 +516,7 @@ var createPropFixes = function createPropFixes(_ref7) {
|
|
|
519
516
|
// 4. icon is not imported from migration entrypoint
|
|
520
517
|
var sizeProp = findProp(attributes, 'size');
|
|
521
518
|
var spacingProp = findProp(attributes, 'spacing');
|
|
522
|
-
if (spacing && !spacingProp &&
|
|
519
|
+
if (spacing && !spacingProp && !migrationImportNode) {
|
|
523
520
|
fixes.push(fixer.insertTextAfter(sizeProp || openingElement.name, " spacing=\"".concat(spacing, "\"")));
|
|
524
521
|
}
|
|
525
522
|
if (sizeProp && sizeProp.type === 'JSXAttribute') {
|
|
@@ -143,7 +143,7 @@ export const lintJSXLiteralForColor = (node, context, config) => {
|
|
|
143
143
|
if (isDecendantOfPrimitive(node.parent, context)) {
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
|
-
if (['alt', 'src', 'label', 'key'].includes(node.parent.name.name)) {
|
|
146
|
+
if (['alt', 'src', 'label', 'key', 'appearance'].includes(node.parent.name.name)) {
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
149
|
const isException = getIsException(config.exceptions);
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import * as ast from '../../../../ast-nodes';
|
|
4
4
|
import { isSupportedForLint } from '../supported';
|
|
5
|
+
function isImportDeclaration(node) {
|
|
6
|
+
return node.type === 'ImportDeclaration';
|
|
7
|
+
}
|
|
5
8
|
export const JSXElement = {
|
|
6
9
|
lint(node, {
|
|
7
10
|
context
|
|
@@ -9,12 +12,104 @@ export const JSXElement = {
|
|
|
9
12
|
if (!isSupportedForLint(node)) {
|
|
10
13
|
return;
|
|
11
14
|
}
|
|
15
|
+
const nodeName = ast.JSXElement.getName(node);
|
|
16
|
+
const sourceCode = context.getSourceCode();
|
|
17
|
+
const importDeclarations = sourceCode.ast.body.filter(isImportDeclaration);
|
|
18
|
+
let existingLinkName = null;
|
|
19
|
+
let existingLinkButtonName = null;
|
|
20
|
+
const usedNames = new Set();
|
|
21
|
+
|
|
22
|
+
// Check for existing imports
|
|
23
|
+
for (const declaration of importDeclarations) {
|
|
24
|
+
for (const specifier of declaration.specifiers) {
|
|
25
|
+
usedNames.add(specifier.local.name);
|
|
26
|
+
}
|
|
27
|
+
if (declaration.source.value === '@atlaskit/link') {
|
|
28
|
+
const defaultSpecifier = declaration.specifiers.find(specifier => specifier.type === 'ImportDefaultSpecifier');
|
|
29
|
+
if (defaultSpecifier) {
|
|
30
|
+
existingLinkName = defaultSpecifier.local.name;
|
|
31
|
+
}
|
|
32
|
+
} else if (declaration.source.value === '@atlaskit/button/new') {
|
|
33
|
+
const namedSpecifier = declaration.specifiers.find(specifier => specifier.type === 'ImportSpecifier' && specifier.imported.name === 'LinkButton');
|
|
34
|
+
if (namedSpecifier) {
|
|
35
|
+
existingLinkButtonName = namedSpecifier.local.name;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const generateUniqueName = baseName => {
|
|
40
|
+
let index = 1;
|
|
41
|
+
let newName = baseName;
|
|
42
|
+
while (usedNames.has(newName)) {
|
|
43
|
+
newName = `${baseName}${index}`;
|
|
44
|
+
index++;
|
|
45
|
+
}
|
|
46
|
+
return newName;
|
|
47
|
+
};
|
|
48
|
+
const linkName = existingLinkName || generateUniqueName('Link');
|
|
49
|
+
const linkButtonName = existingLinkButtonName || generateUniqueName('LinkButton');
|
|
12
50
|
context.report({
|
|
13
51
|
node: node.openingElement,
|
|
14
52
|
messageId: 'noHtmlAnchor',
|
|
15
53
|
data: {
|
|
16
|
-
name:
|
|
17
|
-
}
|
|
54
|
+
name: nodeName
|
|
55
|
+
},
|
|
56
|
+
suggest: [{
|
|
57
|
+
desc: 'Replace with Link component from @atlaskit/link',
|
|
58
|
+
fix(fixer) {
|
|
59
|
+
var _node$closingElement;
|
|
60
|
+
const openingTagRange = node.openingElement.range;
|
|
61
|
+
const closingTagRange = (_node$closingElement = node.closingElement) === null || _node$closingElement === void 0 ? void 0 : _node$closingElement.range;
|
|
62
|
+
const attributesText = node.openingElement.attributes.map(attr => sourceCode.getText(attr)).join(' ');
|
|
63
|
+
const fixers = [];
|
|
64
|
+
|
|
65
|
+
// Replace <a> with <Link> and retain attributes
|
|
66
|
+
if (openingTagRange) {
|
|
67
|
+
if (node.openingElement.selfClosing) {
|
|
68
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], `${linkName}${attributesText ? ` ${attributesText}` : ''} /`));
|
|
69
|
+
} else {
|
|
70
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], `${linkName}${attributesText ? ` ${attributesText}` : ''}`));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
74
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], linkName));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Add import if not present
|
|
78
|
+
if (!existingLinkName) {
|
|
79
|
+
const importStatement = `import ${linkName} from '@atlaskit/link';\n`;
|
|
80
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
81
|
+
}
|
|
82
|
+
return fixers;
|
|
83
|
+
}
|
|
84
|
+
}, {
|
|
85
|
+
desc: 'Replace with LinkButton component from @atlaskit/button/new',
|
|
86
|
+
fix(fixer) {
|
|
87
|
+
var _node$closingElement2;
|
|
88
|
+
const openingTagRange = node.openingElement.range;
|
|
89
|
+
const closingTagRange = (_node$closingElement2 = node.closingElement) === null || _node$closingElement2 === void 0 ? void 0 : _node$closingElement2.range;
|
|
90
|
+
const attributesText = node.openingElement.attributes.map(attr => sourceCode.getText(attr)).join(' ');
|
|
91
|
+
const fixers = [];
|
|
92
|
+
|
|
93
|
+
// Replace <a> with <LinkButton> and retain attributes
|
|
94
|
+
if (openingTagRange) {
|
|
95
|
+
if (node.openingElement.selfClosing) {
|
|
96
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], `${linkButtonName}${attributesText ? ` ${attributesText}` : ''} /`));
|
|
97
|
+
} else {
|
|
98
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], `${linkButtonName}${attributesText ? ` ${attributesText}` : ''}`));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
102
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], linkButtonName));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Add import if not present
|
|
106
|
+
if (!existingLinkButtonName) {
|
|
107
|
+
const importStatement = `import { ${linkButtonName} } from '@atlaskit/button/new';\n`;
|
|
108
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
109
|
+
}
|
|
110
|
+
return fixers;
|
|
111
|
+
}
|
|
112
|
+
}]
|
|
18
113
|
});
|
|
19
114
|
}
|
|
20
115
|
};
|
|
@@ -315,14 +315,14 @@ export const createChecks = context => {
|
|
|
315
315
|
importSource: migrationIconImports[name].packageName,
|
|
316
316
|
iconName: name,
|
|
317
317
|
errors: errorsAuto,
|
|
318
|
-
shouldAddSpaciousSpacing,
|
|
318
|
+
spacing: shouldAddSpaciousSpacing ? 'spacious' : undefined,
|
|
319
319
|
insideNewButton
|
|
320
320
|
});
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
// Legacy icons rendered as JSX elements
|
|
324
324
|
if (Object.keys(legacyIconImports).includes(name)) {
|
|
325
|
-
var _size, _size2
|
|
325
|
+
var _size, _size2;
|
|
326
326
|
// Determine if inside a new button - if so:
|
|
327
327
|
// - Assume spread props are safe - still error if props explicitly set to unmigratable values
|
|
328
328
|
const insideNewButton = isInsideNewButton(node, newButtonImports);
|
|
@@ -398,18 +398,30 @@ export const createChecks = context => {
|
|
|
398
398
|
const newIcon = migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.newIcon;
|
|
399
399
|
const isNewIconMigratable = canAutoMigrateNewIconBasedOnSize(upcomingIcon ? upcomingIcon.sizeGuidance[(_size = size) !== null && _size !== void 0 ? _size : 'medium'] : migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.sizeGuidance[(_size2 = size) !== null && _size2 !== void 0 ? _size2 : 'medium']);
|
|
400
400
|
|
|
401
|
-
// Add
|
|
402
|
-
// 1. size is medium, or not set (default is medium)
|
|
401
|
+
// Add spacing if:
|
|
402
|
+
// 1. size is medium for core/utility icons or small for utility icons, or not set (default is medium for core and small for utility icons)
|
|
403
403
|
// 2. not inside a new or legacy button
|
|
404
404
|
const sizeProp = node.openingElement.attributes.find(attribute => attribute.type === 'JSXAttribute' && (attribute.name.name === 'size' || attribute.name.name === 'LEGACY_size'));
|
|
405
|
-
|
|
405
|
+
let spacing;
|
|
406
|
+
if (!insideNewButton && !insideLegacyButton) {
|
|
407
|
+
var _sizeProp$value2;
|
|
408
|
+
if (sizeProp && sizeProp.type === 'JSXAttribute' && ((_sizeProp$value2 = sizeProp.value) === null || _sizeProp$value2 === void 0 ? void 0 : _sizeProp$value2.type) === 'Literal') {
|
|
409
|
+
if (sizeProp.value.value === 'medium') {
|
|
410
|
+
spacing = 'spacious';
|
|
411
|
+
} else if (sizeProp.value.value === 'small' && (newIcon === null || newIcon === void 0 ? void 0 : newIcon.type) === 'utility') {
|
|
412
|
+
spacing = 'compact';
|
|
413
|
+
}
|
|
414
|
+
} else if (!sizeProp) {
|
|
415
|
+
spacing = 'spacious';
|
|
416
|
+
}
|
|
417
|
+
}
|
|
406
418
|
if (!hasManualMigration && (newIcon || upcomingIcon) && isNewIconMigratable) {
|
|
407
419
|
createAutoMigrationError({
|
|
408
420
|
node,
|
|
409
421
|
importSource: legacyIconImports[name].packageName,
|
|
410
422
|
iconName: name,
|
|
411
423
|
errors: errorsAuto,
|
|
412
|
-
|
|
424
|
+
spacing,
|
|
413
425
|
insideNewButton
|
|
414
426
|
});
|
|
415
427
|
} else if ((!newIcon && !upcomingIcon || !isNewIconMigratable) && size) {
|
|
@@ -257,7 +257,7 @@ export const createAutoMigrationError = ({
|
|
|
257
257
|
importSource,
|
|
258
258
|
iconName,
|
|
259
259
|
errors,
|
|
260
|
-
|
|
260
|
+
spacing,
|
|
261
261
|
insideNewButton
|
|
262
262
|
}) => {
|
|
263
263
|
const myError = {
|
|
@@ -266,7 +266,7 @@ export const createAutoMigrationError = ({
|
|
|
266
266
|
data: {
|
|
267
267
|
importSource,
|
|
268
268
|
iconName,
|
|
269
|
-
spacing:
|
|
269
|
+
spacing: spacing !== null && spacing !== void 0 ? spacing : '',
|
|
270
270
|
// value type need to be a string in Rule.ReportDescriptor
|
|
271
271
|
insideNewButton: String(insideNewButton)
|
|
272
272
|
}
|
|
@@ -462,15 +462,12 @@ const createPropFixes = ({
|
|
|
462
462
|
}) => {
|
|
463
463
|
const fixes = [];
|
|
464
464
|
const {
|
|
465
|
-
importSource,
|
|
466
465
|
spacing,
|
|
467
466
|
insideNewButton
|
|
468
467
|
} = metadata;
|
|
469
468
|
if (shouldUseMigrationPath && !legacyImportNode) {
|
|
470
469
|
return fixes;
|
|
471
470
|
}
|
|
472
|
-
const importPath = migrationImportNode ? importSource.replace('/migration', '').split('--')[0] : getNewIconNameAndImportPath(importSource, shouldUseMigrationPath).importPath;
|
|
473
|
-
const iconType = importPath !== null && importPath !== void 0 && importPath.startsWith('@atlaskit/icon/core') ? 'core' : 'utility';
|
|
474
471
|
if (node.type === 'JSXElement') {
|
|
475
472
|
const {
|
|
476
473
|
openingElement
|
|
@@ -506,7 +503,7 @@ const createPropFixes = ({
|
|
|
506
503
|
// 4. icon is not imported from migration entrypoint
|
|
507
504
|
const sizeProp = findProp(attributes, 'size');
|
|
508
505
|
const spacingProp = findProp(attributes, 'spacing');
|
|
509
|
-
if (spacing && !spacingProp &&
|
|
506
|
+
if (spacing && !spacingProp && !migrationImportNode) {
|
|
510
507
|
fixes.push(fixer.insertTextAfter(sizeProp || openingElement.name, ` spacing="${spacing}"`));
|
|
511
508
|
}
|
|
512
509
|
if (sizeProp && sizeProp.type === 'JSXAttribute') {
|
|
@@ -142,7 +142,7 @@ export var lintJSXLiteralForColor = function lintJSXLiteralForColor(node, contex
|
|
|
142
142
|
if (isDecendantOfPrimitive(node.parent, context)) {
|
|
143
143
|
return;
|
|
144
144
|
}
|
|
145
|
-
if (['alt', 'src', 'label', 'key'].includes(node.parent.name.name)) {
|
|
145
|
+
if (['alt', 'src', 'label', 'key', 'appearance'].includes(node.parent.name.name)) {
|
|
146
146
|
return;
|
|
147
147
|
}
|
|
148
148
|
var isException = getIsException(config.exceptions);
|
|
@@ -1,19 +1,143 @@
|
|
|
1
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
2
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
3
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
1
4
|
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
5
|
|
|
3
6
|
import * as ast from '../../../../ast-nodes';
|
|
4
7
|
import { isSupportedForLint } from '../supported';
|
|
8
|
+
function isImportDeclaration(node) {
|
|
9
|
+
return node.type === 'ImportDeclaration';
|
|
10
|
+
}
|
|
5
11
|
export var JSXElement = {
|
|
6
12
|
lint: function lint(node, _ref) {
|
|
7
13
|
var context = _ref.context;
|
|
8
14
|
if (!isSupportedForLint(node)) {
|
|
9
15
|
return;
|
|
10
16
|
}
|
|
17
|
+
var nodeName = ast.JSXElement.getName(node);
|
|
18
|
+
var sourceCode = context.getSourceCode();
|
|
19
|
+
var importDeclarations = sourceCode.ast.body.filter(isImportDeclaration);
|
|
20
|
+
var existingLinkName = null;
|
|
21
|
+
var existingLinkButtonName = null;
|
|
22
|
+
var usedNames = new Set();
|
|
23
|
+
|
|
24
|
+
// Check for existing imports
|
|
25
|
+
var _iterator = _createForOfIteratorHelper(importDeclarations),
|
|
26
|
+
_step;
|
|
27
|
+
try {
|
|
28
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
29
|
+
var declaration = _step.value;
|
|
30
|
+
var _iterator2 = _createForOfIteratorHelper(declaration.specifiers),
|
|
31
|
+
_step2;
|
|
32
|
+
try {
|
|
33
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
34
|
+
var specifier = _step2.value;
|
|
35
|
+
usedNames.add(specifier.local.name);
|
|
36
|
+
}
|
|
37
|
+
} catch (err) {
|
|
38
|
+
_iterator2.e(err);
|
|
39
|
+
} finally {
|
|
40
|
+
_iterator2.f();
|
|
41
|
+
}
|
|
42
|
+
if (declaration.source.value === '@atlaskit/link') {
|
|
43
|
+
var defaultSpecifier = declaration.specifiers.find(function (specifier) {
|
|
44
|
+
return specifier.type === 'ImportDefaultSpecifier';
|
|
45
|
+
});
|
|
46
|
+
if (defaultSpecifier) {
|
|
47
|
+
existingLinkName = defaultSpecifier.local.name;
|
|
48
|
+
}
|
|
49
|
+
} else if (declaration.source.value === '@atlaskit/button/new') {
|
|
50
|
+
var namedSpecifier = declaration.specifiers.find(function (specifier) {
|
|
51
|
+
return specifier.type === 'ImportSpecifier' && specifier.imported.name === 'LinkButton';
|
|
52
|
+
});
|
|
53
|
+
if (namedSpecifier) {
|
|
54
|
+
existingLinkButtonName = namedSpecifier.local.name;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
_iterator.e(err);
|
|
60
|
+
} finally {
|
|
61
|
+
_iterator.f();
|
|
62
|
+
}
|
|
63
|
+
var generateUniqueName = function generateUniqueName(baseName) {
|
|
64
|
+
var index = 1;
|
|
65
|
+
var newName = baseName;
|
|
66
|
+
while (usedNames.has(newName)) {
|
|
67
|
+
newName = "".concat(baseName).concat(index);
|
|
68
|
+
index++;
|
|
69
|
+
}
|
|
70
|
+
return newName;
|
|
71
|
+
};
|
|
72
|
+
var linkName = existingLinkName || generateUniqueName('Link');
|
|
73
|
+
var linkButtonName = existingLinkButtonName || generateUniqueName('LinkButton');
|
|
11
74
|
context.report({
|
|
12
75
|
node: node.openingElement,
|
|
13
76
|
messageId: 'noHtmlAnchor',
|
|
14
77
|
data: {
|
|
15
|
-
name:
|
|
16
|
-
}
|
|
78
|
+
name: nodeName
|
|
79
|
+
},
|
|
80
|
+
suggest: [{
|
|
81
|
+
desc: 'Replace with Link component from @atlaskit/link',
|
|
82
|
+
fix: function fix(fixer) {
|
|
83
|
+
var _node$closingElement;
|
|
84
|
+
var openingTagRange = node.openingElement.range;
|
|
85
|
+
var closingTagRange = (_node$closingElement = node.closingElement) === null || _node$closingElement === void 0 ? void 0 : _node$closingElement.range;
|
|
86
|
+
var attributesText = node.openingElement.attributes.map(function (attr) {
|
|
87
|
+
return sourceCode.getText(attr);
|
|
88
|
+
}).join(' ');
|
|
89
|
+
var fixers = [];
|
|
90
|
+
|
|
91
|
+
// Replace <a> with <Link> and retain attributes
|
|
92
|
+
if (openingTagRange) {
|
|
93
|
+
if (node.openingElement.selfClosing) {
|
|
94
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkName).concat(attributesText ? " ".concat(attributesText) : '', " /")));
|
|
95
|
+
} else {
|
|
96
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkName).concat(attributesText ? " ".concat(attributesText) : '')));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
100
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], linkName));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Add import if not present
|
|
104
|
+
if (!existingLinkName) {
|
|
105
|
+
var importStatement = "import ".concat(linkName, " from '@atlaskit/link';\n");
|
|
106
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
107
|
+
}
|
|
108
|
+
return fixers;
|
|
109
|
+
}
|
|
110
|
+
}, {
|
|
111
|
+
desc: 'Replace with LinkButton component from @atlaskit/button/new',
|
|
112
|
+
fix: function fix(fixer) {
|
|
113
|
+
var _node$closingElement2;
|
|
114
|
+
var openingTagRange = node.openingElement.range;
|
|
115
|
+
var closingTagRange = (_node$closingElement2 = node.closingElement) === null || _node$closingElement2 === void 0 ? void 0 : _node$closingElement2.range;
|
|
116
|
+
var attributesText = node.openingElement.attributes.map(function (attr) {
|
|
117
|
+
return sourceCode.getText(attr);
|
|
118
|
+
}).join(' ');
|
|
119
|
+
var fixers = [];
|
|
120
|
+
|
|
121
|
+
// Replace <a> with <LinkButton> and retain attributes
|
|
122
|
+
if (openingTagRange) {
|
|
123
|
+
if (node.openingElement.selfClosing) {
|
|
124
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkButtonName).concat(attributesText ? " ".concat(attributesText) : '', " /")));
|
|
125
|
+
} else {
|
|
126
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(linkButtonName).concat(attributesText ? " ".concat(attributesText) : '')));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
130
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], linkButtonName));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Add import if not present
|
|
134
|
+
if (!existingLinkButtonName) {
|
|
135
|
+
var importStatement = "import { ".concat(linkButtonName, " } from '@atlaskit/button/new';\n");
|
|
136
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
137
|
+
}
|
|
138
|
+
return fixers;
|
|
139
|
+
}
|
|
140
|
+
}]
|
|
17
141
|
});
|
|
18
142
|
}
|
|
19
143
|
};
|
|
@@ -386,14 +386,14 @@ export var createChecks = function createChecks(context) {
|
|
|
386
386
|
importSource: migrationIconImports[name].packageName,
|
|
387
387
|
iconName: name,
|
|
388
388
|
errors: errorsAuto,
|
|
389
|
-
shouldAddSpaciousSpacing:
|
|
389
|
+
spacing: shouldAddSpaciousSpacing ? 'spacious' : undefined,
|
|
390
390
|
insideNewButton: insideNewButton
|
|
391
391
|
});
|
|
392
392
|
}
|
|
393
393
|
|
|
394
394
|
// Legacy icons rendered as JSX elements
|
|
395
395
|
if (Object.keys(legacyIconImports).includes(name)) {
|
|
396
|
-
var _size, _size2
|
|
396
|
+
var _size, _size2;
|
|
397
397
|
// Determine if inside a new button - if so:
|
|
398
398
|
// - Assume spread props are safe - still error if props explicitly set to unmigratable values
|
|
399
399
|
var _insideNewButton = isInsideNewButton(node, newButtonImports);
|
|
@@ -482,20 +482,32 @@ export var createChecks = function createChecks(context) {
|
|
|
482
482
|
var newIcon = migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.newIcon;
|
|
483
483
|
var isNewIconMigratable = canAutoMigrateNewIconBasedOnSize(upcomingIcon ? upcomingIcon.sizeGuidance[(_size = size) !== null && _size !== void 0 ? _size : 'medium'] : migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.sizeGuidance[(_size2 = size) !== null && _size2 !== void 0 ? _size2 : 'medium']);
|
|
484
484
|
|
|
485
|
-
// Add
|
|
486
|
-
// 1. size is medium, or not set (default is medium)
|
|
485
|
+
// Add spacing if:
|
|
486
|
+
// 1. size is medium for core/utility icons or small for utility icons, or not set (default is medium for core and small for utility icons)
|
|
487
487
|
// 2. not inside a new or legacy button
|
|
488
488
|
var _sizeProp = node.openingElement.attributes.find(function (attribute) {
|
|
489
489
|
return attribute.type === 'JSXAttribute' && (attribute.name.name === 'size' || attribute.name.name === 'LEGACY_size');
|
|
490
490
|
});
|
|
491
|
-
var
|
|
491
|
+
var spacing;
|
|
492
|
+
if (!_insideNewButton && !insideLegacyButton) {
|
|
493
|
+
var _sizeProp$value2;
|
|
494
|
+
if (_sizeProp && _sizeProp.type === 'JSXAttribute' && ((_sizeProp$value2 = _sizeProp.value) === null || _sizeProp$value2 === void 0 ? void 0 : _sizeProp$value2.type) === 'Literal') {
|
|
495
|
+
if (_sizeProp.value.value === 'medium') {
|
|
496
|
+
spacing = 'spacious';
|
|
497
|
+
} else if (_sizeProp.value.value === 'small' && (newIcon === null || newIcon === void 0 ? void 0 : newIcon.type) === 'utility') {
|
|
498
|
+
spacing = 'compact';
|
|
499
|
+
}
|
|
500
|
+
} else if (!_sizeProp) {
|
|
501
|
+
spacing = 'spacious';
|
|
502
|
+
}
|
|
503
|
+
}
|
|
492
504
|
if (!hasManualMigration && (newIcon || upcomingIcon) && isNewIconMigratable) {
|
|
493
505
|
createAutoMigrationError({
|
|
494
506
|
node: node,
|
|
495
507
|
importSource: legacyIconImports[name].packageName,
|
|
496
508
|
iconName: name,
|
|
497
509
|
errors: errorsAuto,
|
|
498
|
-
|
|
510
|
+
spacing: spacing,
|
|
499
511
|
insideNewButton: _insideNewButton
|
|
500
512
|
});
|
|
501
513
|
} else if ((!newIcon && !upcomingIcon || !isNewIconMigratable) && size) {
|
|
@@ -269,7 +269,7 @@ export var createAutoMigrationError = function createAutoMigrationError(_ref4) {
|
|
|
269
269
|
importSource = _ref4.importSource,
|
|
270
270
|
iconName = _ref4.iconName,
|
|
271
271
|
errors = _ref4.errors,
|
|
272
|
-
|
|
272
|
+
spacing = _ref4.spacing,
|
|
273
273
|
insideNewButton = _ref4.insideNewButton;
|
|
274
274
|
var myError = {
|
|
275
275
|
node: node,
|
|
@@ -277,7 +277,7 @@ export var createAutoMigrationError = function createAutoMigrationError(_ref4) {
|
|
|
277
277
|
data: {
|
|
278
278
|
importSource: importSource,
|
|
279
279
|
iconName: iconName,
|
|
280
|
-
spacing:
|
|
280
|
+
spacing: spacing !== null && spacing !== void 0 ? spacing : '',
|
|
281
281
|
// value type need to be a string in Rule.ReportDescriptor
|
|
282
282
|
insideNewButton: String(insideNewButton)
|
|
283
283
|
}
|
|
@@ -470,14 +470,11 @@ var createPropFixes = function createPropFixes(_ref7) {
|
|
|
470
470
|
migrationImportNode = _ref7.migrationImportNode,
|
|
471
471
|
newIconName = _ref7.newIconName;
|
|
472
472
|
var fixes = [];
|
|
473
|
-
var
|
|
474
|
-
spacing = metadata.spacing,
|
|
473
|
+
var spacing = metadata.spacing,
|
|
475
474
|
insideNewButton = metadata.insideNewButton;
|
|
476
475
|
if (shouldUseMigrationPath && !legacyImportNode) {
|
|
477
476
|
return fixes;
|
|
478
477
|
}
|
|
479
|
-
var importPath = migrationImportNode ? importSource.replace('/migration', '').split('--')[0] : getNewIconNameAndImportPath(importSource, shouldUseMigrationPath).importPath;
|
|
480
|
-
var iconType = importPath !== null && importPath !== void 0 && importPath.startsWith('@atlaskit/icon/core') ? 'core' : 'utility';
|
|
481
478
|
if (node.type === 'JSXElement') {
|
|
482
479
|
var openingElement = node.openingElement;
|
|
483
480
|
if (newIconName) {
|
|
@@ -509,7 +506,7 @@ var createPropFixes = function createPropFixes(_ref7) {
|
|
|
509
506
|
// 4. icon is not imported from migration entrypoint
|
|
510
507
|
var sizeProp = findProp(attributes, 'size');
|
|
511
508
|
var spacingProp = findProp(attributes, 'spacing');
|
|
512
|
-
if (spacing && !spacingProp &&
|
|
509
|
+
if (spacing && !spacingProp && !migrationImportNode) {
|
|
513
510
|
fixes.push(fixer.insertTextAfter(sizeProp || openingElement.name, " spacing=\"".concat(spacing, "\"")));
|
|
514
511
|
}
|
|
515
512
|
if (sizeProp && sizeProp.type === 'JSXAttribute') {
|
|
@@ -87,12 +87,12 @@ export declare const createCantMigrateFunctionUnknownError: (node: Node, importS
|
|
|
87
87
|
export declare const createCantMigrateColorError: (node: Node, colorValue: string, errors: ErrorListManual, importSource: string, iconName: string) => void;
|
|
88
88
|
export declare const createCantMigrateSpreadPropsError: (node: Node, missingProps: string[], errors: ErrorListManual, importSource: string, iconName: string) => void;
|
|
89
89
|
export declare const createCantMigrateSizeUnknown: (node: Node, errors: ErrorListManual, importSource: string, iconName: string) => void;
|
|
90
|
-
export declare const createAutoMigrationError: ({ node, importSource, iconName, errors,
|
|
90
|
+
export declare const createAutoMigrationError: ({ node, importSource, iconName, errors, spacing, insideNewButton, }: {
|
|
91
91
|
node: Node;
|
|
92
92
|
importSource: string;
|
|
93
93
|
iconName: string;
|
|
94
94
|
errors: ErrorListAuto;
|
|
95
|
-
|
|
95
|
+
spacing?: string | undefined;
|
|
96
96
|
insideNewButton?: boolean | undefined;
|
|
97
97
|
}) => void;
|
|
98
98
|
export declare const createHelpers: (context: Rule.RuleContext) => {
|
|
@@ -92,12 +92,12 @@ export declare const createCantMigrateFunctionUnknownError: (node: Node, importS
|
|
|
92
92
|
export declare const createCantMigrateColorError: (node: Node, colorValue: string, errors: ErrorListManual, importSource: string, iconName: string) => void;
|
|
93
93
|
export declare const createCantMigrateSpreadPropsError: (node: Node, missingProps: string[], errors: ErrorListManual, importSource: string, iconName: string) => void;
|
|
94
94
|
export declare const createCantMigrateSizeUnknown: (node: Node, errors: ErrorListManual, importSource: string, iconName: string) => void;
|
|
95
|
-
export declare const createAutoMigrationError: ({ node, importSource, iconName, errors,
|
|
95
|
+
export declare const createAutoMigrationError: ({ node, importSource, iconName, errors, spacing, insideNewButton, }: {
|
|
96
96
|
node: Node;
|
|
97
97
|
importSource: string;
|
|
98
98
|
iconName: string;
|
|
99
99
|
errors: ErrorListAuto;
|
|
100
|
-
|
|
100
|
+
spacing?: string | undefined;
|
|
101
101
|
insideNewButton?: boolean | undefined;
|
|
102
102
|
}) => void;
|
|
103
103
|
export declare const createHelpers: (context: Rule.RuleContext) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/eslint-plugin-design-system",
|
|
3
3
|
"description": "The essential plugin for use with the Atlassian Design System.",
|
|
4
|
-
"version": "10.
|
|
4
|
+
"version": "10.22.1",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"publishConfig": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@atlaskit/eslint-utils": "^1.7.0",
|
|
44
|
-
"@atlaskit/icon": "^22.
|
|
44
|
+
"@atlaskit/icon": "^22.22.0",
|
|
45
45
|
"@atlaskit/tokens": "*",
|
|
46
46
|
"@babel/runtime": "^7.0.0",
|
|
47
47
|
"@typescript-eslint/utils": "^5.48.1",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@af/formatting": "*",
|
|
57
|
-
"@atlaskit/ds-lib": "^
|
|
58
|
-
"@atlaskit/theme": "^13.
|
|
57
|
+
"@atlaskit/ds-lib": "^3.1.0",
|
|
58
|
+
"@atlaskit/theme": "^13.1.0",
|
|
59
59
|
"@atlassian/codegen": "*",
|
|
60
60
|
"@atlassian/eslint-utils": "^0.5.0",
|
|
61
61
|
"@atlassian/ts-loader": "*",
|