@atlaskit/eslint-plugin-design-system 13.12.0 → 13.13.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +2 -0
  3. package/dist/cjs/presets/all-flat.codegen.js +3 -1
  4. package/dist/cjs/presets/all.codegen.js +3 -1
  5. package/dist/cjs/presets/recommended-flat.codegen.js +3 -1
  6. package/dist/cjs/presets/recommended.codegen.js +3 -1
  7. package/dist/cjs/rules/index.codegen.js +5 -1
  8. package/dist/cjs/rules/no-html-text-input/index.js +34 -0
  9. package/dist/cjs/rules/no-html-text-input/node-types/index.js +12 -0
  10. package/dist/cjs/rules/no-html-text-input/node-types/jsx-element/index.js +115 -0
  11. package/dist/cjs/rules/no-html-text-input/node-types/supported.js +91 -0
  12. package/dist/cjs/rules/no-html-textarea/index.js +40 -0
  13. package/dist/cjs/rules/no-html-textarea/node-types/index.js +19 -0
  14. package/dist/cjs/rules/no-html-textarea/node-types/jsx-element/index.js +112 -0
  15. package/dist/cjs/rules/no-html-textarea/node-types/styled-component/index.js +42 -0
  16. package/dist/cjs/rules/no-html-textarea/node-types/supported.js +66 -0
  17. package/dist/es2019/presets/all-flat.codegen.js +3 -1
  18. package/dist/es2019/presets/all.codegen.js +3 -1
  19. package/dist/es2019/presets/recommended-flat.codegen.js +3 -1
  20. package/dist/es2019/presets/recommended.codegen.js +3 -1
  21. package/dist/es2019/rules/index.codegen.js +5 -1
  22. package/dist/es2019/rules/no-html-text-input/index.js +28 -0
  23. package/dist/es2019/rules/no-html-text-input/node-types/index.js +1 -0
  24. package/dist/es2019/rules/no-html-text-input/node-types/jsx-element/index.js +80 -0
  25. package/dist/es2019/rules/no-html-text-input/node-types/supported.js +79 -0
  26. package/dist/es2019/rules/no-html-textarea/index.js +34 -0
  27. package/dist/es2019/rules/no-html-textarea/node-types/index.js +2 -0
  28. package/dist/es2019/rules/no-html-textarea/node-types/jsx-element/index.js +79 -0
  29. package/dist/es2019/rules/no-html-textarea/node-types/styled-component/index.js +37 -0
  30. package/dist/es2019/rules/no-html-textarea/node-types/supported.js +56 -0
  31. package/dist/esm/presets/all-flat.codegen.js +3 -1
  32. package/dist/esm/presets/all.codegen.js +3 -1
  33. package/dist/esm/presets/recommended-flat.codegen.js +3 -1
  34. package/dist/esm/presets/recommended.codegen.js +3 -1
  35. package/dist/esm/rules/index.codegen.js +5 -1
  36. package/dist/esm/rules/no-html-text-input/index.js +28 -0
  37. package/dist/esm/rules/no-html-text-input/node-types/index.js +1 -0
  38. package/dist/esm/rules/no-html-text-input/node-types/jsx-element/index.js +106 -0
  39. package/dist/esm/rules/no-html-text-input/node-types/supported.js +82 -0
  40. package/dist/esm/rules/no-html-textarea/index.js +34 -0
  41. package/dist/esm/rules/no-html-textarea/node-types/index.js +2 -0
  42. package/dist/esm/rules/no-html-textarea/node-types/jsx-element/index.js +103 -0
  43. package/dist/esm/rules/no-html-textarea/node-types/styled-component/index.js +36 -0
  44. package/dist/esm/rules/no-html-textarea/node-types/supported.js +57 -0
  45. package/dist/types/index.codegen.d.ts +18 -0
  46. package/dist/types/presets/all-flat.codegen.d.ts +2 -0
  47. package/dist/types/presets/all.codegen.d.ts +2 -0
  48. package/dist/types/presets/recommended-flat.codegen.d.ts +2 -0
  49. package/dist/types/presets/recommended.codegen.d.ts +2 -0
  50. package/dist/types/rules/index.codegen.d.ts +2 -0
  51. package/dist/types/rules/no-html-text-input/index.d.ts +3 -0
  52. package/dist/types/rules/no-html-text-input/node-types/index.d.ts +1 -0
  53. package/dist/types/rules/no-html-text-input/node-types/jsx-element/index.d.ts +8 -0
  54. package/dist/types/rules/no-html-text-input/node-types/supported.d.ts +7 -0
  55. package/dist/types/rules/no-html-textarea/index.d.ts +3 -0
  56. package/dist/types/rules/no-html-textarea/node-types/index.d.ts +2 -0
  57. package/dist/types/rules/no-html-textarea/node-types/jsx-element/index.d.ts +8 -0
  58. package/dist/types/rules/no-html-textarea/node-types/styled-component/index.d.ts +8 -0
  59. package/dist/types/rules/no-html-textarea/node-types/supported.d.ts +7 -0
  60. package/dist/types-ts4.5/index.codegen.d.ts +18 -0
  61. package/dist/types-ts4.5/presets/all-flat.codegen.d.ts +2 -0
  62. package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -0
  63. package/dist/types-ts4.5/presets/recommended-flat.codegen.d.ts +2 -0
  64. package/dist/types-ts4.5/presets/recommended.codegen.d.ts +2 -0
  65. package/dist/types-ts4.5/rules/index.codegen.d.ts +2 -0
  66. package/dist/types-ts4.5/rules/no-html-text-input/index.d.ts +3 -0
  67. package/dist/types-ts4.5/rules/no-html-text-input/node-types/index.d.ts +1 -0
  68. package/dist/types-ts4.5/rules/no-html-text-input/node-types/jsx-element/index.d.ts +8 -0
  69. package/dist/types-ts4.5/rules/no-html-text-input/node-types/supported.d.ts +7 -0
  70. package/dist/types-ts4.5/rules/no-html-textarea/index.d.ts +3 -0
  71. package/dist/types-ts4.5/rules/no-html-textarea/node-types/index.d.ts +2 -0
  72. package/dist/types-ts4.5/rules/no-html-textarea/node-types/jsx-element/index.d.ts +8 -0
  73. package/dist/types-ts4.5/rules/no-html-textarea/node-types/styled-component/index.d.ts +8 -0
  74. package/dist/types-ts4.5/rules/no-html-textarea/node-types/supported.d.ts +7 -0
  75. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @atlaskit/eslint-plugin-design-system
2
2
 
3
+ ## 13.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#147266](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/147266)
8
+ [`b5c2728320969`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b5c2728320969) -
9
+ Add rule to encourage use of DS textarea component.
10
+ - [#147256](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/147256)
11
+ [`df8b0619d7ebf`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/df8b0619d7ebf) -
12
+ Add rule to encourage use of DS textfield component.
13
+
3
14
  ## 13.12.0
4
15
 
5
16
  ### Minor Changes
package/README.md CHANGED
@@ -75,6 +75,8 @@ module.exports = {
75
75
  | <a href="./src/rules/no-html-radio/README.md">no-html-radio</a> | Discourage direct usage of HTML radio elements in favor of the Atlassian Design System radio component. | Yes | | Yes |
76
76
  | <a href="./src/rules/no-html-range/README.md">no-html-range</a> | Discourage direct usage of HTML range elements in favor of the Atlassian Design System range component. | Yes | | Yes |
77
77
  | <a href="./src/rules/no-html-select/README.md">no-html-select</a> | Discourage direct usage of HTML select elements in favor of the Atlassian Design System select component. | Yes | | Yes |
78
+ | <a href="./src/rules/no-html-text-input/README.md">no-html-text-input</a> | Discourage direct usage of HTML text input elements in favor of the Atlassian Design System textfield component. | Yes | | Yes |
79
+ | <a href="./src/rules/no-html-textarea/README.md">no-html-textarea</a> | Discourage direct usage of HTML textarea elements in favor of the Atlassian Design System textarea component. | Yes | | Yes |
78
80
  | <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 | | |
79
81
  | <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 | |
80
82
  | <a href="./src/rules/no-legacy-icons/README.md">no-legacy-icons</a> | Enforces no legacy icons are used. | | Yes | Yes |
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  /**
8
8
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
9
- * @codegen <<SignedSource::1602f6349577ef6ff9950bcc26efd668>>
9
+ * @codegen <<SignedSource::70743df3608ca82213ea54b79fedd264>>
10
10
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
11
11
  */
12
12
  var _default = exports.default = {
@@ -36,6 +36,8 @@ var _default = exports.default = {
36
36
  '@atlaskit/design-system/no-html-radio': 'warn',
37
37
  '@atlaskit/design-system/no-html-range': 'warn',
38
38
  '@atlaskit/design-system/no-html-select': 'warn',
39
+ '@atlaskit/design-system/no-html-text-input': 'warn',
40
+ '@atlaskit/design-system/no-html-textarea': 'warn',
39
41
  '@atlaskit/design-system/no-invalid-css-map': ['error', {
40
42
  allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
41
43
  }],
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  /**
8
8
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
9
- * @codegen <<SignedSource::5d725e14bffb8d9a0fef48552880717c>>
9
+ * @codegen <<SignedSource::a0aebeced02b3d5507a0aa23fe8ff1b2>>
10
10
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
11
11
  */
12
12
  var _default = exports.default = {
@@ -35,6 +35,8 @@ var _default = exports.default = {
35
35
  '@atlaskit/design-system/no-html-radio': 'warn',
36
36
  '@atlaskit/design-system/no-html-range': 'warn',
37
37
  '@atlaskit/design-system/no-html-select': 'warn',
38
+ '@atlaskit/design-system/no-html-text-input': 'warn',
39
+ '@atlaskit/design-system/no-html-textarea': 'warn',
38
40
  '@atlaskit/design-system/no-invalid-css-map': ['error', {
39
41
  allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
40
42
  }],
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  /**
8
8
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
9
- * @codegen <<SignedSource::6dd8cd1a75ab5e45935592d62f64875e>>
9
+ * @codegen <<SignedSource::af96131434aa77c7882ceb200e4e2cf1>>
10
10
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
11
11
  */
12
12
  var _default = exports.default = {
@@ -31,6 +31,8 @@ var _default = exports.default = {
31
31
  '@atlaskit/design-system/no-html-radio': 'warn',
32
32
  '@atlaskit/design-system/no-html-range': 'warn',
33
33
  '@atlaskit/design-system/no-html-select': 'warn',
34
+ '@atlaskit/design-system/no-html-text-input': 'warn',
35
+ '@atlaskit/design-system/no-html-textarea': 'warn',
34
36
  '@atlaskit/design-system/no-invalid-css-map': ['error', {
35
37
  allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
36
38
  }],
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  /**
8
8
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
9
- * @codegen <<SignedSource::fc8d439406a5af0011226104bfcb66b5>>
9
+ * @codegen <<SignedSource::4bb65ab8e5c1cad968c6e74d7179e58b>>
10
10
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
11
11
  */
12
12
  var _default = exports.default = {
@@ -30,6 +30,8 @@ var _default = exports.default = {
30
30
  '@atlaskit/design-system/no-html-radio': 'warn',
31
31
  '@atlaskit/design-system/no-html-range': 'warn',
32
32
  '@atlaskit/design-system/no-html-select': 'warn',
33
+ '@atlaskit/design-system/no-html-text-input': 'warn',
34
+ '@atlaskit/design-system/no-html-textarea': 'warn',
33
35
  '@atlaskit/design-system/no-invalid-css-map': ['error', {
34
36
  allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
35
37
  }],
@@ -31,6 +31,8 @@ var _noHtmlImage = _interopRequireDefault(require("./no-html-image"));
31
31
  var _noHtmlRadio = _interopRequireDefault(require("./no-html-radio"));
32
32
  var _noHtmlRange = _interopRequireDefault(require("./no-html-range"));
33
33
  var _noHtmlSelect = _interopRequireDefault(require("./no-html-select"));
34
+ var _noHtmlTextInput = _interopRequireDefault(require("./no-html-text-input"));
35
+ var _noHtmlTextarea = _interopRequireDefault(require("./no-html-textarea"));
34
36
  var _noInvalidCssMap = _interopRequireDefault(require("./no-invalid-css-map"));
35
37
  var _noKeyframesTaggedTemplateExpression = _interopRequireDefault(require("./no-keyframes-tagged-template-expression"));
36
38
  var _noLegacyIcons = _interopRequireDefault(require("./no-legacy-icons"));
@@ -65,7 +67,7 @@ var _useTokensTypography = _interopRequireDefault(require("./use-tokens-typograp
65
67
  var _useVisuallyHidden = _interopRequireDefault(require("./use-visually-hidden"));
66
68
  /**
67
69
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
68
- * @codegen <<SignedSource::c2467b3710c61a46d8227d23aaa8b5cf>>
70
+ * @codegen <<SignedSource::be1696f2cf03313e918f93d6414aafd3>>
69
71
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
70
72
  */
71
73
 
@@ -96,6 +98,8 @@ var rules = exports.rules = {
96
98
  'no-html-radio': _noHtmlRadio.default,
97
99
  'no-html-range': _noHtmlRange.default,
98
100
  'no-html-select': _noHtmlSelect.default,
101
+ 'no-html-text-input': _noHtmlTextInput.default,
102
+ 'no-html-textarea': _noHtmlTextarea.default,
99
103
  'no-invalid-css-map': _noInvalidCssMap.default,
100
104
  'no-keyframes-tagged-template-expression': _noKeyframesTaggedTemplateExpression.default,
101
105
  'no-legacy-icons': _noLegacyIcons.default,
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _createRule = require("../utils/create-rule");
8
+ var _nodeTypes = require("./node-types");
9
+ var rule = (0, _createRule.createLintRule)({
10
+ meta: {
11
+ name: 'no-html-text-input',
12
+ type: 'suggestion',
13
+ hasSuggestions: true,
14
+ docs: {
15
+ description: 'Discourage direct usage of HTML text input elements in favor of the Atlassian Design System textfield component.',
16
+ recommended: true,
17
+ severity: 'warn'
18
+ },
19
+ messages: {
20
+ noHtmlTextInput: "This <{{ name }}> should be replaced with a textfield component from the Atlassian Design System. ADS components include event tracking, ensure accessible implementations, and provide access to ADS styling features like design tokens."
21
+ }
22
+ },
23
+ create: function create(context) {
24
+ return {
25
+ // transforms <input type="range" css={...}> usages
26
+ JSXElement: function JSXElement(node) {
27
+ _nodeTypes.JSXElement.lint(node, {
28
+ context: context
29
+ });
30
+ }
31
+ };
32
+ }
33
+ });
34
+ var _default = exports.default = rule;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "JSXElement", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _jsxElement.JSXElement;
10
+ }
11
+ });
12
+ var _jsxElement = require("./jsx-element");
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+
3
+ var _typeof = require("@babel/runtime/helpers/typeof");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.JSXElement = void 0;
8
+ var _eslintCodemodUtils = require("eslint-codemod-utils");
9
+ var _contextCompat = require("@atlaskit/eslint-utils/context-compat");
10
+ var ast = _interopRequireWildcard(require("../../../../ast-nodes"));
11
+ var _supported = require("../supported");
12
+ 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); }
13
+ 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; }
14
+ 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; } } }; }
15
+ 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; } }
16
+ 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; }
17
+ function isImportDeclaration(node) {
18
+ return node.type === 'ImportDeclaration';
19
+ }
20
+ var JSXElement = exports.JSXElement = {
21
+ lint: function lint(node, _ref) {
22
+ var context = _ref.context;
23
+ if (!(0, _supported.isSupportedForLint)(node)) {
24
+ return;
25
+ }
26
+ var nodeName = ast.JSXElement.getName(node);
27
+ var sourceCode = (0, _contextCompat.getSourceCode)(context);
28
+ var importDeclarations = sourceCode.ast.body.filter(isImportDeclaration);
29
+ var existingTextfieldName = null;
30
+ var usedNames = new Set();
31
+
32
+ // Check for existing imports
33
+ var _iterator = _createForOfIteratorHelper(importDeclarations),
34
+ _step;
35
+ try {
36
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
37
+ var declaration = _step.value;
38
+ var _iterator2 = _createForOfIteratorHelper(declaration.specifiers),
39
+ _step2;
40
+ try {
41
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
42
+ var specifier = _step2.value;
43
+ usedNames.add(specifier.local.name);
44
+ }
45
+ } catch (err) {
46
+ _iterator2.e(err);
47
+ } finally {
48
+ _iterator2.f();
49
+ }
50
+ if (declaration.source.value === '@atlaskit/textfield') {
51
+ var defaultSpecifier = declaration.specifiers.find(function (specifier) {
52
+ return specifier.type === 'ImportDefaultSpecifier';
53
+ });
54
+ if (defaultSpecifier) {
55
+ existingTextfieldName = defaultSpecifier.local.name;
56
+ }
57
+ }
58
+ }
59
+ } catch (err) {
60
+ _iterator.e(err);
61
+ } finally {
62
+ _iterator.f();
63
+ }
64
+ var generateUniqueName = function generateUniqueName(baseName) {
65
+ var index = 1;
66
+ var newName = baseName;
67
+ while (usedNames.has(newName)) {
68
+ newName = "".concat(baseName).concat(index);
69
+ index++;
70
+ }
71
+ return newName;
72
+ };
73
+ var textfieldName = existingTextfieldName || generateUniqueName('Textfield');
74
+ context.report({
75
+ node: node.openingElement,
76
+ messageId: 'noHtmlTextInput',
77
+ data: {
78
+ name: nodeName
79
+ },
80
+ suggest: [{
81
+ desc: 'Replace with Textfield component from @atlaskit/textfield',
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.filter(function (attr) {
87
+ return !(0, _eslintCodemodUtils.isNodeOfType)(attr, 'JSXAttribute') || attr.name.name !== 'type';
88
+ }).map(function (attr) {
89
+ return sourceCode.getText(attr);
90
+ }).join(' ');
91
+ var fixers = [];
92
+
93
+ // Replace <img> with <textfield> and retain attributes
94
+ if (openingTagRange) {
95
+ if (node.openingElement.selfClosing) {
96
+ fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(textfieldName).concat(attributesText ? " ".concat(attributesText) : '', " /")));
97
+ } else {
98
+ fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(textfieldName).concat(attributesText ? " ".concat(attributesText) : '')));
99
+ }
100
+ }
101
+ if (closingTagRange && !node.openingElement.selfClosing) {
102
+ fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], textfieldName));
103
+ }
104
+
105
+ // Add import if not present
106
+ if (!existingTextfieldName) {
107
+ var importStatement = "import ".concat(textfieldName, " from '@atlaskit/textfield';\n");
108
+ fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
109
+ }
110
+ return fixers;
111
+ }
112
+ }]
113
+ });
114
+ }
115
+ };
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+
3
+ var _typeof = require("@babel/runtime/helpers/typeof");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.isSupportedForLint = isSupportedForLint;
8
+ var _eslintCodemodUtils = require("eslint-codemod-utils");
9
+ var ast = _interopRequireWildcard(require("../../../ast-nodes"));
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
+ 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
+ var supportedElements = [{
13
+ name: 'input',
14
+ attributes: [{
15
+ name: 'type',
16
+ values: ['text'],
17
+ canBeUndefined: true
18
+ }]
19
+ }];
20
+
21
+ /**
22
+ * Determines if the given JSX element is a supported element to lint with this rule.
23
+ */
24
+ function isSupportedForLint(jsxNode, elementName) {
25
+ if (!(0, _eslintCodemodUtils.isNodeOfType)(jsxNode, 'JSXElement')) {
26
+ return false;
27
+ }
28
+
29
+ // Allow passing in the element name because the jsxNode doesn't
30
+ // represent the element name with styled components
31
+ var elName = elementName || ast.JSXElement.getName(jsxNode);
32
+ if (!elName) {
33
+ return false;
34
+ }
35
+
36
+ // Only check native HTML elements, not components
37
+ if (elName[0] !== elName[0].toLowerCase()) {
38
+ return false;
39
+ }
40
+ var supportedElement = supportedElements.find(function (_ref) {
41
+ var name = _ref.name;
42
+ return name === elName;
43
+ });
44
+ if (!supportedElement) {
45
+ supportedElement = supportedElements.find(function (_ref2) {
46
+ var name = _ref2.name;
47
+ return name === '*';
48
+ });
49
+ }
50
+ if (!supportedElement) {
51
+ return false;
52
+ }
53
+
54
+ // Check if the element has any attributes that are not supported
55
+ var attributes = ast.JSXElement.getAttributes(jsxNode);
56
+ if (supportedElement.attributes &&
57
+ // If not every attribute resolves to `true`
58
+ !supportedElement.attributes.every(function (_ref3) {
59
+ var name = _ref3.name,
60
+ values = _ref3.values,
61
+ canBeUndefined = _ref3.canBeUndefined;
62
+ // If it can be an undefined prop
63
+ if (canBeUndefined) {
64
+ // Search attributes for `name`
65
+ var foundAttribute = attributes.find(function (attr) {
66
+ return (0, _eslintCodemodUtils.isNodeOfType)(attr, 'JSXAttribute') && attr.name.name === name;
67
+ });
68
+ // If we didn't find that attribute, then it should be linted
69
+ if (!foundAttribute) {
70
+ return true;
71
+ }
72
+ }
73
+
74
+ // If we did find the attribute with a matching name, then check if one of
75
+ // it's values matches
76
+ return attributes.some(function (attribute) {
77
+ // Don't lint spreads
78
+ if (attribute.type === 'JSXSpreadAttribute') {
79
+ return false;
80
+ }
81
+ var isMatchingName = attribute.name.name === name;
82
+ var isMatchingValues = values && attribute.value && attribute.value.type === 'Literal' && typeof attribute.value.value === 'string' && (values === null || values === void 0 ? void 0 : values.includes(attribute.value.value));
83
+
84
+ // If one of our values match the attribute's value, lint it
85
+ return isMatchingName && isMatchingValues;
86
+ });
87
+ })) {
88
+ return false;
89
+ }
90
+ return true;
91
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _createRule = require("../utils/create-rule");
8
+ var _nodeTypes = require("./node-types");
9
+ var rule = (0, _createRule.createLintRule)({
10
+ meta: {
11
+ name: 'no-html-textarea',
12
+ type: 'suggestion',
13
+ hasSuggestions: true,
14
+ docs: {
15
+ description: 'Discourage direct usage of HTML textarea elements in favor of the Atlassian Design System textarea component.',
16
+ recommended: true,
17
+ severity: 'warn'
18
+ },
19
+ messages: {
20
+ noHtmlTextarea: "This <{{ name }}> should be replaced with a textarea component from the Atlassian Design System. ADS components include event tracking, ensure accessible implementations, and provide access to ADS styling features like design tokens."
21
+ }
22
+ },
23
+ create: function create(context) {
24
+ return {
25
+ // transforms styled.<textarea>(...) usages
26
+ CallExpression: function CallExpression(node) {
27
+ _nodeTypes.StyledComponent.lint(node, {
28
+ context: context
29
+ });
30
+ },
31
+ // transforms <textarea css={...}> usages
32
+ JSXElement: function JSXElement(node) {
33
+ _nodeTypes.JSXElement.lint(node, {
34
+ context: context
35
+ });
36
+ }
37
+ };
38
+ }
39
+ });
40
+ var _default = exports.default = rule;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "JSXElement", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _jsxElement.JSXElement;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "StyledComponent", {
13
+ enumerable: true,
14
+ get: function get() {
15
+ return _styledComponent.StyledComponent;
16
+ }
17
+ });
18
+ var _styledComponent = require("./styled-component");
19
+ var _jsxElement = require("./jsx-element");
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+
3
+ var _typeof = require("@babel/runtime/helpers/typeof");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.JSXElement = void 0;
8
+ var _contextCompat = require("@atlaskit/eslint-utils/context-compat");
9
+ var ast = _interopRequireWildcard(require("../../../../ast-nodes"));
10
+ var _supported = require("../supported");
11
+ 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); }
12
+ 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; }
13
+ 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; } } }; }
14
+ 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; } }
15
+ 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; }
16
+ function isImportDeclaration(node) {
17
+ return node.type === 'ImportDeclaration';
18
+ }
19
+ var JSXElement = exports.JSXElement = {
20
+ lint: function lint(node, _ref) {
21
+ var context = _ref.context;
22
+ if (!(0, _supported.isSupportedForLint)(node)) {
23
+ return;
24
+ }
25
+ var nodeName = ast.JSXElement.getName(node);
26
+ var sourceCode = (0, _contextCompat.getSourceCode)(context);
27
+ var importDeclarations = sourceCode.ast.body.filter(isImportDeclaration);
28
+ var existingTextareaName = 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/textarea') {
50
+ var defaultSpecifier = declaration.specifiers.find(function (specifier) {
51
+ return specifier.type === 'ImportDefaultSpecifier';
52
+ });
53
+ if (defaultSpecifier) {
54
+ existingTextareaName = defaultSpecifier.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 textareaName = existingTextareaName || generateUniqueName('Textarea');
73
+ context.report({
74
+ node: node.openingElement,
75
+ messageId: 'noHtmlTextarea',
76
+ data: {
77
+ name: nodeName
78
+ },
79
+ suggest: [{
80
+ desc: 'Replace with Textarea component from @atlaskit/textarea',
81
+ fix: function fix(fixer) {
82
+ var _node$closingElement;
83
+ var openingTagRange = node.openingElement.range;
84
+ var closingTagRange = (_node$closingElement = node.closingElement) === null || _node$closingElement === void 0 ? void 0 : _node$closingElement.range;
85
+ var attributesText = node.openingElement.attributes.map(function (attr) {
86
+ return sourceCode.getText(attr);
87
+ }).join(' ');
88
+ var fixers = [];
89
+
90
+ // Replace <textarea> with <Textarea> and retain attributes
91
+ if (openingTagRange) {
92
+ if (node.openingElement.selfClosing) {
93
+ fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(textareaName).concat(attributesText ? " ".concat(attributesText) : '', " /")));
94
+ } else {
95
+ fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(textareaName).concat(attributesText ? " ".concat(attributesText) : '')));
96
+ }
97
+ }
98
+ if (closingTagRange && !node.openingElement.selfClosing) {
99
+ fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], textareaName));
100
+ }
101
+
102
+ // Add import if not present
103
+ if (!existingTextareaName) {
104
+ var importStatement = "import ".concat(textareaName, " from '@atlaskit/textarea';\n");
105
+ fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
106
+ }
107
+ return fixers;
108
+ }
109
+ }]
110
+ });
111
+ }
112
+ };
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StyledComponent = void 0;
7
+ var _eslintCodemodUtils = require("eslint-codemod-utils");
8
+ var _contextCompat = require("@atlaskit/eslint-utils/context-compat");
9
+ var _getJsxElementByName2 = require("../../../utils/get-jsx-element-by-name");
10
+ var _getStyledComponentCall = require("../../../utils/get-styled-component-call");
11
+ var _supported = require("../supported");
12
+ /* eslint-disable @repo/internal/react/require-jsdoc */
13
+
14
+ var StyledComponent = exports.StyledComponent = {
15
+ lint: function lint(node, _ref) {
16
+ var _getJsxElementByName;
17
+ var context = _ref.context;
18
+ if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee, 'MemberExpression') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee.object, 'Identifier') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee.property, 'Identifier')) {
19
+ return;
20
+ }
21
+ var styles = (0, _getStyledComponentCall.getStyledComponentCall)(node);
22
+ var elementName = node.callee.property.name;
23
+ if (!styles || !(0, _eslintCodemodUtils.isNodeOfType)(styles.id, 'Identifier')) {
24
+ return;
25
+ }
26
+ var jsxElement = (_getJsxElementByName = (0, _getJsxElementByName2.getJsxElementByName)(styles.id.name, (0, _contextCompat.getScope)(context, node))) === null || _getJsxElementByName === void 0 ? void 0 : _getJsxElementByName.parent;
27
+ if (!jsxElement) {
28
+ // If there's no JSX element, we can't determine if it's being used as an textarea or not
29
+ return;
30
+ }
31
+ if (jsxElement && !(0, _supported.isSupportedForLint)(jsxElement, elementName)) {
32
+ return;
33
+ }
34
+ context.report({
35
+ node: styles,
36
+ messageId: 'noHtmlTextarea',
37
+ data: {
38
+ name: node.callee.property.name
39
+ }
40
+ });
41
+ }
42
+ };