@atlaskit/eslint-plugin-design-system 10.21.0 → 10.22.0

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/eslint-plugin-design-system
2
2
 
3
+ ## 10.22.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#147366](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/147366)
8
+ [`7f5bab6a1ebd1`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/7f5bab6a1ebd1) -
9
+ Add fixes for html anchors in the no-html-anchor rule
10
+
3
11
  ## 10.21.0
4
12
 
5
13
  ### 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 | |
@@ -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
- /* eslint-disable @repo/internal/react/require-jsdoc */
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: ast.JSXElement.getName(node)
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
  };
@@ -4,6 +4,7 @@ const rule = createLintRule({
4
4
  meta: {
5
5
  name: 'no-html-anchor',
6
6
  type: 'suggestion',
7
+ hasSuggestions: true,
7
8
  docs: {
8
9
  description: 'Discourage direct usage of HTML anchor elements in favor of Atlassian Design System link components.',
9
10
  recommended: true,
@@ -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: ast.JSXElement.getName(node)
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
  };
@@ -4,6 +4,7 @@ var rule = createLintRule({
4
4
  meta: {
5
5
  name: 'no-html-anchor',
6
6
  type: 'suggestion',
7
+ hasSuggestions: true,
7
8
  docs: {
8
9
  description: 'Discourage direct usage of HTML anchor elements in favor of Atlassian Design System link components.',
9
10
  recommended: true,
@@ -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: ast.JSXElement.getName(node)
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
  };
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.21.0",
4
+ "version": "10.22.0",
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.18.0",
44
+ "@atlaskit/icon": "^22.20.0",
45
45
  "@atlaskit/tokens": "*",
46
46
  "@babel/runtime": "^7.0.0",
47
47
  "@typescript-eslint/utils": "^5.48.1",
@@ -54,7 +54,7 @@
54
54
  },
55
55
  "devDependencies": {
56
56
  "@af/formatting": "*",
57
- "@atlaskit/ds-lib": "^2.5.0",
57
+ "@atlaskit/ds-lib": "^2.6.0",
58
58
  "@atlaskit/theme": "^13.0.0",
59
59
  "@atlassian/codegen": "*",
60
60
  "@atlassian/eslint-utils": "^0.5.0",