@atlaskit/eslint-plugin-design-system 4.1.0 → 4.2.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/index.js +10 -2
  3. package/dist/cjs/rules/no-deprecated-apis/index.js +91 -0
  4. package/dist/cjs/rules/no-deprecated-imports/index.js +45 -33
  5. package/dist/cjs/rules/no-deprecated-imports/paths.js +43 -15
  6. package/dist/cjs/rules/use-visually-hidden/constants.js +12 -0
  7. package/dist/cjs/rules/use-visually-hidden/fix-jsx.js +39 -0
  8. package/dist/cjs/rules/use-visually-hidden/fix-vanilla.js +35 -0
  9. package/dist/cjs/rules/use-visually-hidden/index.js +194 -0
  10. package/dist/cjs/rules/use-visually-hidden/utils.js +91 -0
  11. package/dist/cjs/rules/utils/get-import-node-by-source.js +23 -0
  12. package/dist/cjs/rules/utils/is-node.js +36 -5
  13. package/dist/cjs/rules/utils/remove-named-import.js +29 -0
  14. package/dist/cjs/version.json +1 -1
  15. package/dist/es2019/index.js +8 -2
  16. package/dist/es2019/rules/no-deprecated-apis/index.js +72 -0
  17. package/dist/es2019/rules/no-deprecated-imports/index.js +45 -32
  18. package/dist/es2019/rules/no-deprecated-imports/paths.js +41 -14
  19. package/dist/es2019/rules/use-visually-hidden/constants.js +3 -0
  20. package/dist/es2019/rules/use-visually-hidden/fix-jsx.js +24 -0
  21. package/dist/es2019/rules/use-visually-hidden/fix-vanilla.js +21 -0
  22. package/dist/es2019/rules/use-visually-hidden/index.js +169 -0
  23. package/dist/es2019/rules/use-visually-hidden/utils.js +62 -0
  24. package/dist/es2019/rules/utils/get-import-node-by-source.js +10 -0
  25. package/dist/es2019/rules/utils/is-node.js +22 -4
  26. package/dist/es2019/rules/utils/remove-named-import.js +16 -0
  27. package/dist/es2019/version.json +1 -1
  28. package/dist/esm/index.js +8 -2
  29. package/dist/esm/rules/no-deprecated-apis/index.js +81 -0
  30. package/dist/esm/rules/no-deprecated-imports/index.js +45 -32
  31. package/dist/esm/rules/no-deprecated-imports/paths.js +41 -14
  32. package/dist/esm/rules/use-visually-hidden/constants.js +3 -0
  33. package/dist/esm/rules/use-visually-hidden/fix-jsx.js +26 -0
  34. package/dist/esm/rules/use-visually-hidden/fix-vanilla.js +23 -0
  35. package/dist/esm/rules/use-visually-hidden/index.js +180 -0
  36. package/dist/esm/rules/use-visually-hidden/utils.js +74 -0
  37. package/dist/esm/rules/utils/get-import-node-by-source.js +14 -0
  38. package/dist/esm/rules/utils/is-node.js +25 -3
  39. package/dist/esm/rules/utils/remove-named-import.js +20 -0
  40. package/dist/esm/version.json +1 -1
  41. package/dist/types/index.d.ts +4 -0
  42. package/dist/types/rules/no-deprecated-apis/index.d.ts +3 -0
  43. package/dist/types/rules/no-deprecated-imports/paths.d.ts +33 -14
  44. package/dist/types/rules/use-visually-hidden/constants.d.ts +3 -0
  45. package/dist/types/rules/use-visually-hidden/fix-jsx.d.ts +3 -0
  46. package/dist/types/rules/use-visually-hidden/fix-vanilla.d.ts +3 -0
  47. package/dist/types/rules/use-visually-hidden/index.d.ts +3 -0
  48. package/dist/types/rules/use-visually-hidden/utils.d.ts +35 -0
  49. package/dist/types/rules/utils/get-import-node-by-source.d.ts +8 -0
  50. package/dist/types/rules/utils/is-node.d.ts +7 -0
  51. package/dist/types/rules/utils/remove-named-import.d.ts +8 -0
  52. package/package.json +6 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @atlaskit/eslint-plugin-design-system
2
2
 
3
+ ## 4.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`63a22b17621`](https://bitbucket.org/atlassian/atlassian-frontend/commits/63a22b17621) - Fixes a bug where use of qualified type annotations would throw an error.
8
+
9
+ ## 4.2.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`afc248d2ded`](https://bitbucket.org/atlassian/atlassian-frontend/commits/afc248d2ded) - Adds a new rule, `use-visually-hidden` to complement the `@atlaskit/visually-hidden` component.
14
+ - [`0c0a8b5dff4`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0c0a8b5dff4) - Adds an additional rule 'no-deprecated-api-usage'. This rule targets APIs/props in the Design System that we intend to remove completely. This rule should be used by all product repos as it will provide an early warning of expected deprecations.
15
+ - [`93d6f8856f2`](https://bitbucket.org/atlassian/atlassian-frontend/commits/93d6f8856f2) - @atlaskit/icon-priority has been deprecated due to low usage. It will be deleted after 21 April 2022. If you rely on these icons, @atlaskit/icon-priority will still be available as a deprecated package on NPM, but we recommend self-hosting and managing.
16
+
17
+ ## 4.1.1
18
+
19
+ ### Patch Changes
20
+
21
+ - [`19d72473dfb`](https://bitbucket.org/atlassian/atlassian-frontend/commits/19d72473dfb) - The no-unsafe-design-token-usage eslint rule now respects the new token naming conventions when auto-fixing by correctly formatting token ids.
22
+ - Updated dependencies
23
+
3
24
  ## 4.1.0
4
25
 
5
26
  ### Minor Changes
package/dist/cjs/index.js CHANGED
@@ -9,24 +9,32 @@ exports.rules = exports.configs = void 0;
9
9
 
10
10
  var _ensureDesignTokenUsage = _interopRequireDefault(require("./rules/ensure-design-token-usage"));
11
11
 
12
+ var _noDeprecatedApis = _interopRequireDefault(require("./rules/no-deprecated-apis"));
13
+
12
14
  var _noDeprecatedDesignTokenUsage = _interopRequireDefault(require("./rules/no-deprecated-design-token-usage"));
13
15
 
14
16
  var _noDeprecatedImports = _interopRequireDefault(require("./rules/no-deprecated-imports"));
15
17
 
16
18
  var _noUnsafeDesignTokenUsage = _interopRequireDefault(require("./rules/no-unsafe-design-token-usage"));
17
19
 
20
+ var _useVisuallyHidden = _interopRequireDefault(require("./rules/use-visually-hidden"));
21
+
18
22
  var rules = {
19
23
  'ensure-design-token-usage': _ensureDesignTokenUsage.default,
20
24
  'no-unsafe-design-token-usage': _noUnsafeDesignTokenUsage.default,
21
25
  'no-deprecated-design-token-usage': _noDeprecatedDesignTokenUsage.default,
22
- 'no-deprecated-imports': _noDeprecatedImports.default
26
+ 'no-deprecated-imports': _noDeprecatedImports.default,
27
+ 'no-deprecated-apis': _noDeprecatedApis.default,
28
+ 'use-visually-hidden': _useVisuallyHidden.default
23
29
  };
24
30
  exports.rules = rules;
25
31
  var configs = {
26
32
  recommended: {
27
33
  plugins: ['@atlaskit/design-system'],
28
34
  rules: {
29
- '@atlaskit/design-system/no-deprecated-imports': 'error'
35
+ '@atlaskit/design-system/no-deprecated-imports': 'error',
36
+ '@atlaskit/design-system/use-visually-hidden': 'error',
37
+ '@atlaskit/design-system/no-deprecated-apis': 'warn'
30
38
  }
31
39
  }
32
40
  };
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _getImportNodeBySource = require("../utils/get-import-node-by-source");
9
+
10
+ var _isNode = require("../utils/is-node");
11
+
12
+ // eslint-disable-next-line import/no-unresolved
13
+ var unsafeOverridesConfig = {
14
+ cssFn: ['@atlaskit/menu', '@atlaskit/side-navigation'],
15
+ overrides: ['@atlaskit/drawer', '@atlaskit/menu', '@atlaskit/side-navigation']
16
+ };
17
+ var unsafeOverrides = ['cssFn', 'overrides'];
18
+ var rule = {
19
+ meta: {
20
+ type: 'suggestion',
21
+ docs: {
22
+ description: 'Disallow specified APIs that have been marked as deprecated and/or discouraged.',
23
+ recommended: true
24
+ },
25
+ messages: {
26
+ noDeprecatedApis: "The prop \"{{propName}}\" has been deprecated. It will be removed in the next major release."
27
+ }
28
+ },
29
+ create: function create(context) {
30
+ return {
31
+ // find JSX atribute - find name of attribute - get source and find relevant identifiers.
32
+ JSXAttribute: function (_JSXAttribute) {
33
+ function JSXAttribute(_x) {
34
+ return _JSXAttribute.apply(this, arguments);
35
+ }
36
+
37
+ JSXAttribute.toString = function () {
38
+ return _JSXAttribute.toString();
39
+ };
40
+
41
+ return JSXAttribute;
42
+ }(function (node) {
43
+ var _node$name, _closesetJSXElement$n;
44
+
45
+ if (!unsafeOverrides.includes(node === null || node === void 0 ? void 0 : (_node$name = node.name) === null || _node$name === void 0 ? void 0 : _node$name.name)) {
46
+ return;
47
+ }
48
+
49
+ var source = context.getSourceCode();
50
+ var bannedApi = node.name.name; // traverse the tree to the nearest JSX Element and get its name
51
+
52
+ var closesetJSXElement = (0, _isNode.getClosestNodeOfType)(node, 'JSXOpeningElement'); // @ts-ignore
53
+
54
+ var jsxElementName = closesetJSXElement === null || closesetJSXElement === void 0 ? void 0 : (_closesetJSXElement$n = closesetJSXElement.name) === null || _closesetJSXElement$n === void 0 ? void 0 : _closesetJSXElement$n.name;
55
+
56
+ if (!jsxElementName) {
57
+ return;
58
+ } // find an import for the path of the banned api
59
+
60
+
61
+ unsafeOverridesConfig[bannedApi].forEach(function (path) {
62
+ var importNode = (0, _getImportNodeBySource.getImportedNodeBySource)(source, path);
63
+
64
+ if (!importNode) {
65
+ return;
66
+ } // find an import that matches our JSX element
67
+
68
+
69
+ var hasTargetNode = importNode.specifiers.some(function (node) {
70
+ return node.local.name === jsxElementName;
71
+ });
72
+
73
+ if (!hasTargetNode) {
74
+ return;
75
+ } // if we're here the import exists and there is a valid lint error.
76
+
77
+
78
+ context.report({
79
+ node: node,
80
+ messageId: 'noDeprecatedApis',
81
+ data: {
82
+ propName: bannedApi
83
+ }
84
+ });
85
+ });
86
+ })
87
+ };
88
+ }
89
+ };
90
+ var _default = rule;
91
+ exports.default = _default;
@@ -31,18 +31,24 @@ var rule = {
31
31
  }
32
32
  },
33
33
  create: function create(context) {
34
- var sourceCode = context.getSourceCode();
35
-
36
34
  var restrictedPathMessages = _paths.restrictedPaths.reduce(function (memo, importSource) {
37
35
  if (typeof importSource === 'string') {
38
36
  memo[importSource] = {
39
37
  message: ''
40
38
  };
41
39
  } else {
42
- memo[importSource.name] = {
43
- message: importSource.message // importNames: importSource.importNames
40
+ if ('message' in importSource) {
41
+ memo[importSource.path] = {
42
+ message: importSource.message
43
+ };
44
+ }
44
45
 
45
- };
46
+ if ('imports' in importSource) {
47
+ memo[importSource.path] = {
48
+ // @ts-ignore
49
+ imports: importSource.imports
50
+ };
51
+ }
46
52
  }
47
53
 
48
54
  return memo;
@@ -50,27 +56,46 @@ var rule = {
50
56
  /**
51
57
  * Report a restricted path.
52
58
  * @param {string} importSource path of the import
53
- * @param {Map<string,Object[]>} importNames Map of import names that are being imported
54
59
  * @param {node} node representing the restricted path reference
60
+ * @param {Map<string,Rule.Node>} importNames Map of import names that are being imported
55
61
  * @returns {void}
56
62
  * @private
57
63
  */
58
64
 
59
65
 
60
- function checkRestrictedPathAndReport(importSource, importNames, node) {
66
+ function checkRestrictedPathAndReport(importSource, node, importNames) {
61
67
  if (!Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) {
62
68
  return;
63
69
  }
64
70
 
65
- var customMessage = restrictedPathMessages[importSource].message;
66
- context.report({
67
- node: node,
68
- messageId: customMessage ? 'pathWithCustomMessage' : 'path',
69
- data: {
70
- importSource: importSource,
71
- customMessage: customMessage
72
- }
73
- });
71
+ var config = restrictedPathMessages[importSource]; // The message will only exist if the import is completely banned,
72
+ // eg a deprecated package
73
+
74
+ if ('message' in config) {
75
+ context.report({
76
+ node: node,
77
+ messageId: config.message ? 'pathWithCustomMessage' : 'path',
78
+ data: {
79
+ importSource: importSource,
80
+ customMessage: config.message
81
+ }
82
+ });
83
+ } // if there are specific named exports that are banned,
84
+ // iterate through and check if they're being imported
85
+
86
+
87
+ if ('imports' in config) {
88
+ var _config$imports;
89
+
90
+ (_config$imports = config.imports) === null || _config$imports === void 0 ? void 0 : _config$imports.forEach(function (restrictedImport) {
91
+ if (importNames.has(restrictedImport.importName)) {
92
+ context.report({
93
+ node: importNames.get(restrictedImport.importName),
94
+ message: restrictedImport.message
95
+ });
96
+ }
97
+ });
98
+ }
74
99
  }
75
100
  /**
76
101
  * Checks a node to see if any problems should be reported.
@@ -84,12 +109,7 @@ var rule = {
84
109
  var importSource = node.source.value.trim();
85
110
  var importNames = new Map();
86
111
 
87
- if (node.type === 'ExportAllDeclaration') {
88
- var starToken = sourceCode.getFirstToken(node, 1);
89
- importNames.set('*', [{
90
- loc: starToken === null || starToken === void 0 ? void 0 : starToken.loc
91
- }]);
92
- } else if ('specifiers' in node) {
112
+ if ('specifiers' in node) {
93
113
  // @ts-ignore
94
114
  var _iterator = _createForOfIteratorHelper(node.specifiers),
95
115
  _step;
@@ -98,9 +118,6 @@ var rule = {
98
118
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
99
119
  var specifier = _step.value;
100
120
  var name = void 0;
101
- var specifierData = {
102
- loc: specifier.loc
103
- };
104
121
 
105
122
  if (specifier.type === 'ImportDefaultSpecifier') {
106
123
  name = 'default';
@@ -113,11 +130,7 @@ var rule = {
113
130
  }
114
131
 
115
132
  if (name) {
116
- if (importNames.has(name)) {
117
- importNames.get(name).push(specifierData);
118
- } else {
119
- importNames.set(name, [specifierData]);
120
- }
133
+ importNames.set(name, specifier);
121
134
  }
122
135
  }
123
136
  } catch (err) {
@@ -127,7 +140,7 @@ var rule = {
127
140
  }
128
141
  }
129
142
 
130
- checkRestrictedPathAndReport(importSource, importNames, node);
143
+ checkRestrictedPathAndReport(importSource, node, importNames);
131
144
  };
132
145
 
133
146
  return {
@@ -136,8 +149,7 @@ var rule = {
136
149
  if (node.source) {
137
150
  checkNode(node);
138
151
  }
139
- },
140
- ExportAllDeclaration: checkNode
152
+ }
141
153
  };
142
154
  }
143
155
  };
@@ -3,48 +3,76 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.restrictedPaths = void 0;
6
+ exports.restrictedPaths = exports.namedThemeExports = void 0;
7
+ var namedThemeExports = [{
8
+ importName: 'assistive',
9
+ message: 'The assistive mixin is deprecated. Please use `@atlaskit/visually-hidden` instead.'
10
+ }, {
11
+ importName: 'visuallyHidden',
12
+ message: 'The visuallyHidden mixin is deprecated. Please use `@atlaskit/visually-hidden` instead.'
13
+ }, {
14
+ importName: 'focusRing',
15
+ message: 'The focusRing mixin is deprecated. Please use `@atlaskit/visually-hidden` instead.'
16
+ }];
17
+ exports.namedThemeExports = namedThemeExports;
7
18
  var restrictedPaths = [{
8
- name: '@atlaskit/navigation-next',
19
+ path: '@atlaskit/navigation-next',
9
20
  message: "navigation-next is deprecated. Please use '@atlaskit/atlassian-navigation' instead."
10
21
  }, {
11
- name: '@atlaskit/field-base',
22
+ path: '@atlaskit/field-base',
12
23
  message: "field-base is deprecated. Please use the '@atlaskit/form' package instead."
13
24
  }, {
14
- name: '@atlaskit/field-radio-group',
25
+ path: '@atlaskit/field-radio-group',
15
26
  message: "field-radio-group is deprecated. Please use '@atlaskit/radio' instead, and check the migration guide."
16
27
  }, {
17
- name: '@atlaskit/field-range',
28
+ path: '@atlaskit/field-range',
18
29
  message: "field-range is deprecated. Please use '@atlaskit/range' instead."
19
30
  }, {
20
- name: '@atlaskit/field-text',
31
+ path: '@atlaskit/field-text',
21
32
  message: "field-text is deprecated. Please use '@atlaskit/textfield' instead."
22
33
  }, {
23
- name: '@atlaskit/field-text-area',
34
+ path: '@atlaskit/field-text-area',
24
35
  message: "field-text-area is deprecated. Please use '@atlaskit/textarea' instead."
25
36
  }, {
26
- name: '@atlaskit/navigation',
37
+ path: '@atlaskit/navigation',
27
38
  message: "navigation is deprecated. Please use '@atlaskit/atlassian-navigation' instead."
28
39
  }, {
29
- name: '@atlaskit/global-navigation',
40
+ path: '@atlaskit/global-navigation',
30
41
  message: "global-navigation is deprecated. Please use '@atlaskit/atlassian-navigation' for the horizontal nav bar, '@atlaskit/side-navigation' for the side nav, and '@atlaskit/page-layout' to layout your application."
31
42
  }, {
32
- name: '@atlaskit/input',
43
+ path: '@atlaskit/input',
33
44
  message: 'input is deprecated. This was an internal component and should not be used directly.'
34
45
  }, {
35
- name: '@atlaskit/layer',
46
+ path: '@atlaskit/layer',
36
47
  message: 'layer is deprecated. This was an internal component and should not be used directly.'
37
48
  }, {
38
- name: '@atlaskit/single-select',
49
+ path: '@atlaskit/single-select',
39
50
  message: "single-select is deprecated. Please use '@atlaskit/select' instead."
40
51
  }, {
41
- name: '@atlaskit/multi-select',
52
+ path: '@atlaskit/multi-select',
42
53
  message: "multi-select is deprecated. Please use '@atlaskit/select' instead."
43
54
  }, {
44
- name: '@atlaskit/droplist',
55
+ path: '@atlaskit/droplist',
45
56
  message: "droplist is deprecated. For the pop-up behaviour please use '@atlaskit/popup' and for common menu components please use '@atlaskit/menu'."
46
57
  }, {
47
- name: '@atlaskit/item',
58
+ path: '@atlaskit/item',
48
59
  message: "item is deprecated. Please use '@atlaskit/menu' instead."
60
+ }, // TODO uncomment me when we formally deprecate typography
61
+ // {
62
+ // path: '@atlaskit/theme/typography',
63
+ // message: 'The typography mixins are deprecated. Please use `@atlaskit/heading` instead.',
64
+ // },
65
+ {
66
+ path: '@atlaskit/theme/constants',
67
+ imports: namedThemeExports
68
+ }, {
69
+ path: '@atlaskit/theme',
70
+ imports: namedThemeExports // .concat(
71
+ // { importName: 'typography', message: 'The typography mixins are deprecated. Please use `@atlaskit/heading` instead.',}
72
+ // )
73
+
74
+ }, {
75
+ path: '@atlaskit/icon-priority',
76
+ message: "icon-priority is deprecated due to limited usage in Cloud products. It will be deleted after 21 April 2022."
49
77
  }];
50
78
  exports.restrictedPaths = restrictedPaths;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.VISUALLY_HIDDEN_SOURCE = exports.VISUALLY_HIDDEN_IMPORT = exports.IMPORT_NAME = void 0;
7
+ var IMPORT_NAME = 'AKVisuallyHidden';
8
+ exports.IMPORT_NAME = IMPORT_NAME;
9
+ var VISUALLY_HIDDEN_SOURCE = '@atlaskit/visually-hidden';
10
+ exports.VISUALLY_HIDDEN_SOURCE = VISUALLY_HIDDEN_SOURCE;
11
+ var VISUALLY_HIDDEN_IMPORT = "import ".concat(IMPORT_NAME, " from '").concat(VISUALLY_HIDDEN_SOURCE, "';\n");
12
+ exports.VISUALLY_HIDDEN_IMPORT = VISUALLY_HIDDEN_IMPORT;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _getImportNodeBySource = require("../utils/get-import-node-by-source");
9
+
10
+ var _isNode = require("../utils/is-node");
11
+
12
+ var _constants = require("./constants");
13
+
14
+ var _utils = require("./utils");
15
+
16
+ var _default = function _default(source, node) {
17
+ return function (fixer) {
18
+ var fixes = [];
19
+ var importedNode = (0, _utils.getFirstImport)(source);
20
+ var visuallyHiddenNode = (0, _getImportNodeBySource.getImportedNodeBySource)(source, _constants.VISUALLY_HIDDEN_SOURCE);
21
+
22
+ if (!importedNode) {
23
+ return [];
24
+ }
25
+
26
+ var jsxOpeningElement = (0, _isNode.getClosestNodeOfType)(node, 'JSXOpeningElement');
27
+
28
+ if (visuallyHiddenNode) {
29
+ fixes.push(fixer.replaceText(jsxOpeningElement, visuallyHiddenNode.specifiers[0].local.name));
30
+ } else {
31
+ fixes.push(fixer.insertTextBefore(importedNode, _constants.VISUALLY_HIDDEN_IMPORT));
32
+ fixes.push(fixer.replaceText(jsxOpeningElement, "<".concat(_constants.IMPORT_NAME, " />")));
33
+ }
34
+
35
+ return fixes;
36
+ };
37
+ };
38
+
39
+ exports.default = _default;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _getImportNodeBySource = require("../utils/get-import-node-by-source");
9
+
10
+ var _constants = require("./constants");
11
+
12
+ var _utils = require("./utils");
13
+
14
+ var _default = function _default(source, node) {
15
+ return function (fixer) {
16
+ var fixes = [];
17
+ var importedNode = (0, _utils.getFirstImport)(source);
18
+ var visuallyHiddenNode = (0, _getImportNodeBySource.getImportedNodeBySource)(source, _constants.VISUALLY_HIDDEN_SOURCE);
19
+
20
+ if (!importedNode) {
21
+ return [];
22
+ }
23
+
24
+ if (visuallyHiddenNode) {
25
+ fixes.push(fixer.replaceText(node, visuallyHiddenNode.specifiers[0].local.name));
26
+ } else {
27
+ fixes.push(fixer.insertTextBefore(importedNode, _constants.VISUALLY_HIDDEN_IMPORT));
28
+ fixes.push(fixer.replaceText(node, _constants.IMPORT_NAME));
29
+ }
30
+
31
+ return fixes;
32
+ };
33
+ };
34
+
35
+ exports.default = _default;
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+
10
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
11
+
12
+ var _isNode = require("../utils/is-node");
13
+
14
+ var _fixJsx = _interopRequireDefault(require("./fix-jsx"));
15
+
16
+ var _fixVanilla = _interopRequireDefault(require("./fix-vanilla"));
17
+
18
+ var _utils = require("./utils");
19
+
20
+ /* eslint-disable @atlaskit/design-system/use-visually-hidden */
21
+ var THEME_IMPORT_NAMES = ['visuallyHidden', 'assistive'];
22
+ var rule = {
23
+ meta: {
24
+ type: 'suggestion',
25
+ fixable: 'code',
26
+ docs: {
27
+ description: 'Suggest usage of the `@atlaskit/visually-hidden` component instead of either the `@atlaskit/theme` mixins or just something the user has rolled themselves.',
28
+ recommended: true
29
+ },
30
+ messages: {
31
+ noDeprecatedUsage: 'Using the export `{{local}}` from `{{import}}` as a mixin is discouraged. Please use `@atlaskit/visually-hidden` instead.',
32
+ noDeprecated: 'The export `{{local}}` from `{{import}}` is deprecated. Please use `@atlaskit/visually-hidden` instead.',
33
+ suggestion: 'This CSS closely matches the implementation of a visually hidden element. You should consider using the `@atlaskit/visually-hidden` component instead.'
34
+ }
35
+ },
36
+ create: function create(context) {
37
+ var source = context.getSourceCode();
38
+ return {
39
+ ImportDeclaration: function ImportDeclaration(node) {
40
+ var isThemeNode = node.source.value === '@atlaskit/theme' || node.source.value === '@atlaskit/theme/constants';
41
+
42
+ if (!isThemeNode) {
43
+ return;
44
+ }
45
+
46
+ var visuallyHiddenOrAssistive = node.specifiers.filter(function (specifier) {
47
+ return specifier.type === 'ImportSpecifier';
48
+ }).find(function (specifier) {
49
+ return THEME_IMPORT_NAMES.includes(specifier.imported.name);
50
+ });
51
+
52
+ if (!visuallyHiddenOrAssistive) {
53
+ return;
54
+ }
55
+
56
+ context.getDeclaredVariables(visuallyHiddenOrAssistive).forEach(function (someNode) {
57
+ someNode.references.map(function (innerNode) {
58
+ return innerNode.identifier;
59
+ }).forEach(function (idNode) {
60
+ // @ts-ignore JSX is not typed correctly in eslint
61
+ if ((idNode === null || idNode === void 0 ? void 0 : idNode.parent.type) === 'JSXExpressionContainer') {
62
+ context.report({
63
+ node: idNode.parent,
64
+ messageId: 'noDeprecatedUsage',
65
+ data: {
66
+ import: "".concat(node.source.value),
67
+ local: visuallyHiddenOrAssistive.local.name
68
+ },
69
+ fix: (0, _fixJsx.default)(source, idNode)
70
+ }); // this is either a styled usage OR mixin usage in a styled usage
71
+ } else if (idNode.parent.type === 'CallExpression') {
72
+ if ((0, _isNode.isStyledObjectNode)(idNode.parent) || (0, _isNode.isStyledTemplateNode)(idNode.parent)) {
73
+ context.report({
74
+ node: idNode.parent,
75
+ messageId: 'noDeprecatedUsage',
76
+ data: {
77
+ import: "".concat(node.source.value),
78
+ local: visuallyHiddenOrAssistive.local.name
79
+ },
80
+ fix: (0, _fixVanilla.default)(source, idNode.parent)
81
+ });
82
+ }
83
+
84
+ if (idNode.parent.callee === idNode) {
85
+ context.report({
86
+ node: idNode.parent,
87
+ messageId: 'noDeprecatedUsage',
88
+ data: {
89
+ import: "".concat(node.source.value),
90
+ local: visuallyHiddenOrAssistive.local.name
91
+ },
92
+ fix: (0, _fixVanilla.default)(source, (0, _isNode.getClosestNodeOfType)(idNode.parent, 'TaggedTemplateExpression'))
93
+ });
94
+ }
95
+ }
96
+ });
97
+ });
98
+ return context.report({
99
+ node: visuallyHiddenOrAssistive,
100
+ messageId: 'noDeprecated',
101
+ data: {
102
+ import: "".concat(node.source.value),
103
+ local: visuallyHiddenOrAssistive.local.name
104
+ }
105
+ });
106
+ },
107
+ CallExpression: function CallExpression(node) {
108
+ var _node$arguments$;
109
+
110
+ if (node.type !== 'CallExpression') {
111
+ return;
112
+ }
113
+
114
+ if (!(node.callee.type === 'MemberExpression' || node.callee.type === 'Identifier')) {
115
+ return;
116
+ }
117
+
118
+ var isStyled = (0, _isNode.isStyledObjectNode)(node);
119
+
120
+ if (node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.object.name !== 'styled') {
121
+ return;
122
+ }
123
+
124
+ if (node.callee.type === 'Identifier' && node.callee.name !== 'css') {
125
+ return;
126
+ } // This is an object style (probably)
127
+
128
+
129
+ if (node.arguments && ((_node$arguments$ = node.arguments[0]) === null || _node$arguments$ === void 0 ? void 0 : _node$arguments$.type) === 'ObjectExpression') {
130
+ var matchingScore = (0, _utils.getObjectLikeness)(node.arguments[0]);
131
+
132
+ if (matchingScore > 0.8) {
133
+ return context.report({
134
+ node: node.parent,
135
+ messageId: 'suggestion',
136
+ fix: isStyled ? (0, _fixVanilla.default)(source, node) : undefined
137
+ });
138
+ }
139
+ }
140
+
141
+ return null;
142
+ },
143
+ ObjectExpression: function ObjectExpression(node) {
144
+ if (node.parent.type === 'CallExpression') {
145
+ return;
146
+ }
147
+
148
+ var matchingScore = (0, _utils.getObjectLikeness)(node);
149
+
150
+ if (matchingScore > 0.8) {
151
+ return context.report({
152
+ node: node,
153
+ messageId: 'suggestion'
154
+ });
155
+ }
156
+ },
157
+ 'TaggedTemplateExpression[tag.name="css"],TaggedTemplateExpression[tag.object.name="styled"]': function TaggedTemplateExpressionTagNameCssTaggedTemplateExpressionTagObjectNameStyled(node) {
158
+ if (node.type !== 'TaggedTemplateExpression') {
159
+ return;
160
+ }
161
+
162
+ var templateString = node.quasi.quasis.map(function (q) {
163
+ return q.value.raw;
164
+ }).join('');
165
+ var styleEntries = (0, _utils.makeTemplateLiteralIntoEntries)(templateString);
166
+
167
+ if (!styleEntries) {
168
+ return;
169
+ }
170
+
171
+ var count = (0, _utils.countMatchingKeyValues)(styleEntries.map(function (_ref) {
172
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
173
+ key = _ref2[0],
174
+ value = _ref2[1];
175
+
176
+ return {
177
+ key: key,
178
+ value: value
179
+ };
180
+ }));
181
+
182
+ if (count > 0.8) {
183
+ return context.report({
184
+ node: node,
185
+ messageId: 'suggestion',
186
+ fix: node.tag.type !== 'Identifier' ? (0, _fixVanilla.default)(source, node) : undefined
187
+ });
188
+ }
189
+ }
190
+ };
191
+ }
192
+ };
193
+ var _default = rule;
194
+ exports.default = _default;