@atlaskit/eslint-plugin-design-system 13.14.2 → 13.16.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 (66) hide show
  1. package/CHANGELOG.md +24 -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 +2 -1
  6. package/dist/cjs/presets/recommended.codegen.js +2 -1
  7. package/dist/cjs/rules/ensure-proper-xcss-usage/index.js +157 -0
  8. package/dist/cjs/rules/index.codegen.js +5 -1
  9. package/dist/cjs/rules/no-legacy-icons/checks.js +22 -5
  10. package/dist/cjs/rules/no-legacy-icons/helpers.js +122 -46
  11. package/dist/cjs/rules/no-utility-icons/checks.js +233 -0
  12. package/dist/cjs/rules/no-utility-icons/index.js +40 -0
  13. package/dist/cjs/rules/utils/get-deprecated-config.js +1 -1
  14. package/dist/es2019/presets/all-flat.codegen.js +3 -1
  15. package/dist/es2019/presets/all.codegen.js +3 -1
  16. package/dist/es2019/presets/recommended-flat.codegen.js +2 -1
  17. package/dist/es2019/presets/recommended.codegen.js +2 -1
  18. package/dist/es2019/rules/ensure-proper-xcss-usage/index.js +149 -0
  19. package/dist/es2019/rules/index.codegen.js +5 -1
  20. package/dist/es2019/rules/no-legacy-icons/checks.js +22 -6
  21. package/dist/es2019/rules/no-legacy-icons/helpers.js +125 -44
  22. package/dist/es2019/rules/no-utility-icons/checks.js +164 -0
  23. package/dist/es2019/rules/no-utility-icons/index.js +35 -0
  24. package/dist/es2019/rules/utils/get-deprecated-config.js +3 -2
  25. package/dist/esm/presets/all-flat.codegen.js +3 -1
  26. package/dist/esm/presets/all.codegen.js +3 -1
  27. package/dist/esm/presets/recommended-flat.codegen.js +2 -1
  28. package/dist/esm/presets/recommended.codegen.js +2 -1
  29. package/dist/esm/rules/ensure-proper-xcss-usage/index.js +151 -0
  30. package/dist/esm/rules/index.codegen.js +5 -1
  31. package/dist/esm/rules/no-legacy-icons/checks.js +22 -5
  32. package/dist/esm/rules/no-legacy-icons/helpers.js +121 -45
  33. package/dist/esm/rules/no-utility-icons/checks.js +226 -0
  34. package/dist/esm/rules/no-utility-icons/index.js +34 -0
  35. package/dist/esm/rules/utils/get-deprecated-config.js +2 -2
  36. package/dist/types/index.codegen.d.ts +14 -0
  37. package/dist/types/presets/all-flat.codegen.d.ts +2 -0
  38. package/dist/types/presets/all.codegen.d.ts +2 -0
  39. package/dist/types/presets/recommended-flat.codegen.d.ts +1 -0
  40. package/dist/types/presets/recommended.codegen.d.ts +1 -0
  41. package/dist/types/rules/ensure-proper-xcss-usage/index.d.ts +3 -0
  42. package/dist/types/rules/index.codegen.d.ts +2 -0
  43. package/dist/types/rules/no-legacy-icons/helpers.d.ts +12 -4
  44. package/dist/types/rules/no-utility-icons/checks.d.ts +10 -0
  45. package/dist/types/rules/no-utility-icons/index.d.ts +3 -0
  46. package/dist/types/rules/use-tokens-typography/transformers/banned-properties.d.ts +1 -1
  47. package/dist/types/rules/use-tokens-typography/transformers/font-family.d.ts +1 -1
  48. package/dist/types/rules/use-tokens-typography/transformers/font-weight.d.ts +1 -1
  49. package/dist/types/rules/use-tokens-typography/transformers/restricted-capitalisation.d.ts +1 -1
  50. package/dist/types/rules/use-tokens-typography/transformers/untokenized-properties.d.ts +1 -1
  51. package/dist/types-ts4.5/index.codegen.d.ts +14 -0
  52. package/dist/types-ts4.5/presets/all-flat.codegen.d.ts +2 -0
  53. package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -0
  54. package/dist/types-ts4.5/presets/recommended-flat.codegen.d.ts +1 -0
  55. package/dist/types-ts4.5/presets/recommended.codegen.d.ts +1 -0
  56. package/dist/types-ts4.5/rules/ensure-proper-xcss-usage/index.d.ts +3 -0
  57. package/dist/types-ts4.5/rules/index.codegen.d.ts +2 -0
  58. package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +12 -4
  59. package/dist/types-ts4.5/rules/no-utility-icons/checks.d.ts +10 -0
  60. package/dist/types-ts4.5/rules/no-utility-icons/index.d.ts +3 -0
  61. package/dist/types-ts4.5/rules/use-tokens-typography/transformers/banned-properties.d.ts +1 -1
  62. package/dist/types-ts4.5/rules/use-tokens-typography/transformers/font-family.d.ts +1 -1
  63. package/dist/types-ts4.5/rules/use-tokens-typography/transformers/font-weight.d.ts +1 -1
  64. package/dist/types-ts4.5/rules/use-tokens-typography/transformers/restricted-capitalisation.d.ts +1 -1
  65. package/dist/types-ts4.5/rules/use-tokens-typography/transformers/untokenized-properties.d.ts +1 -1
  66. package/package.json +4 -4
@@ -0,0 +1,164 @@
1
+ import { isNodeOfType } from 'eslint-codemod-utils';
2
+ const specialCases = {
3
+ '@atlaskit/icon/utility/cross': '@atlaskit/icon/core/close',
4
+ '@atlaskit/icon/utility/migration/cross--editor-close': '@atlaskit/icon/core/migration/close--editor-close'
5
+ };
6
+ const iconPropsinNewButton = ['icon', 'iconBefore', 'iconAfter'];
7
+ export const createChecks = context => {
8
+ const importStatementsUtility = {};
9
+ const importStatementsCore = {};
10
+ const newButtonImports = new Set();
11
+ const errors = {};
12
+ const checkImportDeclarations = node => {
13
+ const moduleSource = node.source.value;
14
+ if (typeof moduleSource !== 'string') {
15
+ return;
16
+ }
17
+ if (moduleSource.startsWith('@atlaskit/icon/utility/')) {
18
+ for (const specifier of node.specifiers) {
19
+ if (specifier.type === 'ImportDefaultSpecifier') {
20
+ importStatementsUtility[specifier.local.name] = node;
21
+ }
22
+ }
23
+ } else if (moduleSource.startsWith('@atlaskit/icon/core/')) {
24
+ for (const specifier of node.specifiers) {
25
+ if (specifier.type === 'ImportDefaultSpecifier') {
26
+ importStatementsCore[moduleSource] = {
27
+ node,
28
+ localName: specifier.local.name
29
+ };
30
+ }
31
+ }
32
+ } else if (moduleSource.startsWith('@atlaskit/button/')) {
33
+ for (const specifier of node.specifiers) {
34
+ newButtonImports.add(specifier.local.name);
35
+ }
36
+ }
37
+ };
38
+ const checkJSXElement = node => {
39
+ if (!(isNodeOfType(node, 'JSXElement') && isNodeOfType(node.openingElement.name, 'JSXIdentifier') && importStatementsUtility.hasOwnProperty(node.openingElement.name.name) && typeof importStatementsUtility[node.openingElement.name.name].source.value === 'string')) {
40
+ return;
41
+ }
42
+ if (!errors.hasOwnProperty(node.openingElement.name.name)) {
43
+ errors[node.openingElement.name.name] = [];
44
+ }
45
+ errors[node.openingElement.name.name].push({
46
+ node,
47
+ messageId: 'noUtilityIconsJSXElement',
48
+ localName: node.openingElement.name.name,
49
+ fixable: true,
50
+ inNewButton: false
51
+ });
52
+ };
53
+
54
+ // Cases: As Props, In Function Calls, In Arrays, In Maps, In Exports
55
+ const checkIconReference = node => {
56
+ //if this is an import statement then exit early
57
+ if (node.parent && (isNodeOfType(node.parent, 'ImportSpecifier') || isNodeOfType(node.parent, 'ImportDefaultSpecifier'))) {
58
+ return;
59
+ }
60
+
61
+ //check the reference to see if it's a utility icon, if not exit early
62
+ if (!importStatementsUtility.hasOwnProperty(node.name)) {
63
+ return;
64
+ }
65
+
66
+ // if it is in new Button then we can fix it
67
+ if (node.parent && node.parent.parent && node.parent.parent.parent && isNodeOfType(node.parent, 'JSXExpressionContainer') && isNodeOfType(node.parent.parent, 'JSXAttribute') && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') && iconPropsinNewButton.includes(node.parent.parent.name.name) && isNodeOfType(node.parent.parent.parent, 'JSXOpeningElement') && isNodeOfType(node.parent.parent.parent.name, 'JSXIdentifier') && newButtonImports.has(node.parent.parent.parent.name.name)) {
68
+ // if it is in new Button then we can fix it
69
+ if (!errors.hasOwnProperty(node.name)) {
70
+ errors[node.name] = [];
71
+ }
72
+ errors[node.name].push({
73
+ node,
74
+ messageId: 'noUtilityIconsReference',
75
+ localName: node.name,
76
+ fixable: true,
77
+ inNewButton: true
78
+ });
79
+ return;
80
+ }
81
+
82
+ // manually error
83
+ if (!errors.hasOwnProperty(node.name)) {
84
+ errors[node.name] = [];
85
+ }
86
+ errors[node.name].push({
87
+ node,
88
+ messageId: 'noUtilityIconsReference',
89
+ localName: node.name,
90
+ fixable: false,
91
+ inNewButton: false
92
+ });
93
+ };
94
+
95
+ /**
96
+ * Throws the relevant errors in the correct order.
97
+ */
98
+ const throwErrors = () => {
99
+ for (const utilityIcon of Object.keys(errors)) {
100
+ const allFixable = errors[utilityIcon].every(x => x.fixable); // Check if ALL errors for a giving import are fixable
101
+ const originalImportNode = importStatementsUtility[utilityIcon];
102
+ const oldImportName = importStatementsUtility[utilityIcon].source.value;
103
+ const newImportName = specialCases.hasOwnProperty(oldImportName) ? specialCases[oldImportName] : oldImportName.replace('@atlaskit/icon/utility/', '@atlaskit/icon/core/');
104
+ const existingImport = importStatementsCore.hasOwnProperty(newImportName) ? importStatementsCore[newImportName].localName : null;
105
+ let replacementImportName = existingImport ? existingImport : allFixable ? utilityIcon : `${utilityIcon}Core`;
106
+ let importFixAdded = false;
107
+ for (const [index, error] of errors[utilityIcon].entries()) {
108
+ if (error.fixable) {
109
+ context.report({
110
+ node: error.node,
111
+ messageId: error.messageId,
112
+ fix: fixer => {
113
+ const fixes = [];
114
+
115
+ // Add a new import statement if it doesn't already exist
116
+ if (!existingImport && !importFixAdded) {
117
+ importFixAdded = true;
118
+ fixes.push(fixer.insertTextBeforeRange([0, 0], `import ${replacementImportName} from '${newImportName}';\n`));
119
+ }
120
+
121
+ // Handle JSX elements differently if they are in a "new Button"
122
+ if (error.inNewButton) {
123
+ // Replace the icon with a function that wraps it with iconProps and size="small"
124
+ const wrappedIcon = `(iconProps) => <${replacementImportName} label="" {...iconProps} size="small" />`;
125
+ fixes.push(fixer.replaceText(error.node, wrappedIcon));
126
+ } else if (isNodeOfType(error.node, 'JSXElement') && isNodeOfType(error.node.openingElement.name, 'JSXIdentifier')) {
127
+ // Replace the JSX element's closing tag with size="small"
128
+ const newOpeningElementText = context.sourceCode.getText(error.node.openingElement).replace(/\s*\/\s*>$/, ` size="small"\/>`).replace(new RegExp('<\s*' + error.node.openingElement.name.name), `<${replacementImportName}`);
129
+ fixes.push(fixer.replaceText(error.node.openingElement, newOpeningElementText));
130
+ }
131
+
132
+ // Handle the first fixable error for import removal if all fixable for this import
133
+ if (index === 0 && allFixable) {
134
+ fixes.push(fixer.remove(originalImportNode));
135
+ }
136
+ return fixes;
137
+ }
138
+ });
139
+ } else {
140
+ // Report non-fixable errors
141
+ context.report({
142
+ node: error.node,
143
+ messageId: error.messageId
144
+ });
145
+ }
146
+ }
147
+ }
148
+
149
+ // If other utility icons are imported but there were no errors for them - (this should only be unused imports but good to have as a backup), report them
150
+ const otherUtilityImportsWithoutErrors = Object.keys(importStatementsUtility).filter(utilityIcon => !errors.hasOwnProperty(utilityIcon));
151
+ for (const utilityIcon of otherUtilityImportsWithoutErrors) {
152
+ context.report({
153
+ node: importStatementsUtility[utilityIcon],
154
+ messageId: 'noUtilityIconsImport'
155
+ });
156
+ }
157
+ };
158
+ return {
159
+ checkImportDeclarations,
160
+ checkJSXElement,
161
+ checkIconReference,
162
+ throwErrors
163
+ };
164
+ };
@@ -0,0 +1,35 @@
1
+ import { createLintRule } from '../utils/create-rule';
2
+ import { createChecks } from './checks';
3
+ const rule = createLintRule({
4
+ meta: {
5
+ name: 'no-utility-icons',
6
+ fixable: 'code',
7
+ hasSuggestions: true,
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Disallow use of deprecated utility icons, in favor of core icons with `size="small"`.',
11
+ recommended: true,
12
+ severity: 'warn'
13
+ },
14
+ messages: {
15
+ noUtilityIconsJSXElement: `Utility icons are deprecated. Please use core icons instead with the size prop set to small.`,
16
+ noUtilityIconsImport: `Utility icons are deprecated. Please do not import them, use core icons instead.`,
17
+ noUtilityIconsReference: `Utility icons are deprecated. To replace them, please use core icons with the size prop set to small instead.`
18
+ }
19
+ },
20
+ create(context) {
21
+ const {
22
+ checkImportDeclarations,
23
+ checkJSXElement,
24
+ checkIconReference,
25
+ throwErrors
26
+ } = createChecks(context);
27
+ return {
28
+ ImportDeclaration: checkImportDeclarations,
29
+ JSXElement: checkJSXElement,
30
+ Identifier: checkIconReference,
31
+ 'Program:exit': throwErrors
32
+ };
33
+ }
34
+ });
35
+ export default rule;
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { deprecatedCore as deprecatedIconLabCore } from '@atlaskit/icon-lab/deprecated-map';
3
+ import { deprecatedCore as deprecatedIconLabCore, deprecatedUtility as deprecatedIconLabUtility } from '@atlaskit/icon-lab/deprecated-map';
4
4
  import { deprecatedCore as deprecatedIconCore, deprecatedUtility as deprecatedIconUtility } from '@atlaskit/icon/deprecated-map';
5
5
  export const getConfig = specifier => {
6
6
  const configPath = path.resolve(__dirname, '..', '..', '..', 'configs', 'deprecated.json');
@@ -12,7 +12,8 @@ export const getConfig = specifier => {
12
12
  ...parsedConfig.imports,
13
13
  ...deprecatedIconCore,
14
14
  ...deprecatedIconUtility,
15
- ...deprecatedIconLabCore
15
+ ...deprecatedIconLabCore,
16
+ ...deprecatedIconLabUtility
16
17
  }
17
18
  };
18
19
  return combinedConfig[specifier];
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
3
- * @codegen <<SignedSource::c6c896451f2be4d48f04068f5bbb85f1>>
3
+ * @codegen <<SignedSource::5ceb45b21744434ca96a850461a3c574>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
 
@@ -12,6 +12,7 @@ export default {
12
12
  '@atlaskit/design-system/ensure-design-token-usage': 'error',
13
13
  '@atlaskit/design-system/ensure-design-token-usage/preview': 'warn',
14
14
  '@atlaskit/design-system/ensure-icon-color': 'error',
15
+ '@atlaskit/design-system/ensure-proper-xcss-usage': 'error',
15
16
  '@atlaskit/design-system/icon-label': 'warn',
16
17
  '@atlaskit/design-system/no-banned-imports': 'error',
17
18
  '@atlaskit/design-system/no-boolean-autofocus-on-modal-dialog': 'warn',
@@ -47,6 +48,7 @@ export default {
47
48
  '@atlaskit/design-system/no-unsafe-design-token-usage': 'error',
48
49
  '@atlaskit/design-system/no-unsafe-style-overrides': 'warn',
49
50
  '@atlaskit/design-system/no-unsupported-drag-and-drop-libraries': 'error',
51
+ '@atlaskit/design-system/no-utility-icons': 'warn',
50
52
  '@atlaskit/design-system/prefer-primitives': 'warn',
51
53
  '@atlaskit/design-system/use-button-group-label': 'warn',
52
54
  '@atlaskit/design-system/use-cx-function-in-xcss': 'error',
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
3
- * @codegen <<SignedSource::d4de619ac262298b2af11f905a02b0dd>>
3
+ * @codegen <<SignedSource::b96d8bb5115de6e0a230feef152a1365>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
 
@@ -11,6 +11,7 @@ export default {
11
11
  '@atlaskit/design-system/ensure-design-token-usage': 'error',
12
12
  '@atlaskit/design-system/ensure-design-token-usage/preview': 'warn',
13
13
  '@atlaskit/design-system/ensure-icon-color': 'error',
14
+ '@atlaskit/design-system/ensure-proper-xcss-usage': 'error',
14
15
  '@atlaskit/design-system/icon-label': 'warn',
15
16
  '@atlaskit/design-system/no-banned-imports': 'error',
16
17
  '@atlaskit/design-system/no-boolean-autofocus-on-modal-dialog': 'warn',
@@ -46,6 +47,7 @@ export default {
46
47
  '@atlaskit/design-system/no-unsafe-design-token-usage': 'error',
47
48
  '@atlaskit/design-system/no-unsafe-style-overrides': 'warn',
48
49
  '@atlaskit/design-system/no-unsupported-drag-and-drop-libraries': 'error',
50
+ '@atlaskit/design-system/no-utility-icons': 'warn',
49
51
  '@atlaskit/design-system/prefer-primitives': 'warn',
50
52
  '@atlaskit/design-system/use-button-group-label': 'warn',
51
53
  '@atlaskit/design-system/use-cx-function-in-xcss': 'error',
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
3
- * @codegen <<SignedSource::af96131434aa77c7882ceb200e4e2cf1>>
3
+ * @codegen <<SignedSource::10f372e16c048db9bfb1bc36cf48421c>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
 
@@ -36,6 +36,7 @@ export default {
36
36
  '@atlaskit/design-system/no-unsafe-design-token-usage': 'error',
37
37
  '@atlaskit/design-system/no-unsafe-style-overrides': 'warn',
38
38
  '@atlaskit/design-system/no-unsupported-drag-and-drop-libraries': 'error',
39
+ '@atlaskit/design-system/no-utility-icons': 'warn',
39
40
  '@atlaskit/design-system/use-button-group-label': 'warn',
40
41
  '@atlaskit/design-system/use-cx-function-in-xcss': 'error',
41
42
  '@atlaskit/design-system/use-datetime-picker-calendar-button': 'warn',
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
3
- * @codegen <<SignedSource::4bb65ab8e5c1cad968c6e74d7179e58b>>
3
+ * @codegen <<SignedSource::608f46f9cc8653226152a8edc34849d6>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
 
@@ -35,6 +35,7 @@ export default {
35
35
  '@atlaskit/design-system/no-unsafe-design-token-usage': 'error',
36
36
  '@atlaskit/design-system/no-unsafe-style-overrides': 'warn',
37
37
  '@atlaskit/design-system/no-unsupported-drag-and-drop-libraries': 'error',
38
+ '@atlaskit/design-system/no-utility-icons': 'warn',
38
39
  '@atlaskit/design-system/use-button-group-label': 'warn',
39
40
  '@atlaskit/design-system/use-cx-function-in-xcss': 'error',
40
41
  '@atlaskit/design-system/use-datetime-picker-calendar-button': 'warn',
@@ -0,0 +1,151 @@
1
+ import { isNodeOfType } from 'eslint-codemod-utils';
2
+ import { createLintRule } from '../utils/create-rule';
3
+ import { errorBoundary } from '../utils/error-boundary';
4
+ var rule = createLintRule({
5
+ meta: {
6
+ name: 'ensure-proper-xcss-usage',
7
+ docs: {
8
+ description: 'Enforces proper xcss usage: migrate from xcss() to cssMap() and use cssMap objects with specific keys.',
9
+ recommended: false,
10
+ severity: 'error'
11
+ },
12
+ messages: {
13
+ missingCssMapKey: 'xcss prop should use a specific key from cssMap (e.g., {{identifier}}.root) instead of the entire cssMap object.',
14
+ noXcssWithCompiled: 'Cannot use `xcss()` function with `@atlaskit/primitives/compiled`. Use `cssMap()` from `@atlaskit/css or `@compiled/react` instead.'
15
+ }
16
+ },
17
+ create: function create(context) {
18
+ var tracker = {
19
+ // Components tracking
20
+ compiledComponents: new Set(),
21
+ // Function tracking
22
+ cssMapFunction: new Set(),
23
+ xcssFunction: new Set(),
24
+ // Variables tracking
25
+ cssMapVariables: new Map(),
26
+ xcssVariables: new Set()
27
+ };
28
+ return errorBoundary({
29
+ // Track all imports in a single handler
30
+ ImportDeclaration: function ImportDeclaration(node) {
31
+ var source = node.source.value;
32
+ node.specifiers.forEach(function (specifier) {
33
+ if (specifier.type !== 'ImportSpecifier') {
34
+ return;
35
+ }
36
+
37
+ // Handle different import sources
38
+ switch (source) {
39
+ case '@atlaskit/primitives/compiled':
40
+ tracker.compiledComponents.add(specifier.imported.name);
41
+ break;
42
+ case '@atlaskit/primitives':
43
+ if (specifier.imported.name === 'xcss') {
44
+ tracker.xcssFunction.add(specifier.local.name);
45
+ }
46
+ break;
47
+ case '@atlaskit/css':
48
+ case '@compiled/react':
49
+ if (specifier.imported.name === 'cssMap') {
50
+ tracker.cssMapFunction.add(specifier.local.name);
51
+ }
52
+ break;
53
+ }
54
+ });
55
+ },
56
+ // Track variable declarations
57
+ VariableDeclarator: function VariableDeclarator(node) {
58
+ if (!node.init || node.init.type !== 'CallExpression' || node.init.callee.type !== 'Identifier' || node.id.type !== 'Identifier') {
59
+ return;
60
+ }
61
+ var calleeName = node.init.callee.name;
62
+ var variableName = node.id.name;
63
+
64
+ // Track cssMap variables and extract their keys
65
+ if (tracker.cssMapFunction.has(calleeName)) {
66
+ var keys = new Set();
67
+
68
+ // Extract keys from the cssMap object argument
69
+ if (node.init.arguments.length > 0 && node.init.arguments[0].type === 'ObjectExpression') {
70
+ node.init.arguments[0].properties.forEach(function (prop) {
71
+ if (prop.type === 'Property' && prop.key.type === 'Identifier') {
72
+ keys.add(prop.key.name);
73
+ }
74
+ });
75
+ }
76
+ tracker.cssMapVariables.set(variableName, keys);
77
+ }
78
+
79
+ // Track xcss variables
80
+ if (tracker.xcssFunction.has(calleeName)) {
81
+ tracker.xcssVariables.add(variableName);
82
+ }
83
+ },
84
+ // Check JSX elements for xcss prop usage
85
+ JSXElement: function JSXElement(node) {
86
+ var _xcssAttribute$value;
87
+ if (!isNodeOfType(node, 'JSXElement')) {
88
+ return;
89
+ }
90
+ var elementName = node.openingElement.name;
91
+ if (elementName.type !== 'JSXIdentifier') {
92
+ return;
93
+ }
94
+ var componentName = elementName.name;
95
+ if (!tracker.compiledComponents.has(componentName)) {
96
+ return;
97
+ }
98
+
99
+ // Find xcss attribute
100
+ var xcssAttribute = node.openingElement.attributes.find(function (attr) {
101
+ return attr.type === 'JSXAttribute' && attr.name.name === 'xcss';
102
+ });
103
+ if ((xcssAttribute === null || xcssAttribute === void 0 || (_xcssAttribute$value = xcssAttribute.value) === null || _xcssAttribute$value === void 0 ? void 0 : _xcssAttribute$value.type) !== 'JSXExpressionContainer') {
104
+ return;
105
+ }
106
+ var expression = xcssAttribute.value.expression;
107
+
108
+ // Check for direct xcss function calls
109
+ if (expression.type === 'CallExpression' && expression.callee.type === 'Identifier' && tracker.xcssFunction.has(expression.callee.name)) {
110
+ context.report({
111
+ node: expression,
112
+ messageId: 'noXcssWithCompiled'
113
+ });
114
+ return;
115
+ }
116
+
117
+ // Check for variables
118
+ if (expression.type === 'Identifier') {
119
+ var identifierName = expression.name;
120
+ if (tracker.xcssVariables.has(identifierName)) {
121
+ context.report({
122
+ node: expression,
123
+ messageId: 'noXcssWithCompiled'
124
+ });
125
+ } else if (tracker.cssMapVariables.has(identifierName)) {
126
+ context.report({
127
+ node: expression,
128
+ messageId: 'missingCssMapKey',
129
+ data: {
130
+ identifier: identifierName
131
+ }
132
+ });
133
+ }
134
+ return;
135
+ }
136
+
137
+ // Check member expressions (e.g., styles.root)
138
+ if (expression.type === 'MemberExpression' && expression.object.type === 'Identifier') {
139
+ var objectName = expression.object.name;
140
+ if (tracker.xcssVariables.has(objectName)) {
141
+ context.report({
142
+ node: expression,
143
+ messageId: 'noXcssWithCompiled'
144
+ });
145
+ }
146
+ }
147
+ }
148
+ });
149
+ }
150
+ });
151
+ export default rule;
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
3
- * @codegen <<SignedSource::d42e0ce93d45d02a5c30dcfdb7110c17>>
3
+ * @codegen <<SignedSource::3de5d5b44aa01faabdb840bc7fb43d04>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  import consistentCssPropUsage from './consistent-css-prop-usage';
7
7
  import ensureDesignTokenUsage from './ensure-design-token-usage';
8
8
  import ensureDesignTokenUsagePreview from './ensure-design-token-usage-preview';
9
9
  import ensureIconColor from './ensure-icon-color';
10
+ import ensureProperXcssUsage from './ensure-proper-xcss-usage';
10
11
  import iconLabel from './icon-label';
11
12
  import noBannedImports from './no-banned-imports';
12
13
  import noBooleanAutofocusOnModalDialog from './no-boolean-autofocus-on-modal-dialog';
@@ -43,6 +44,7 @@ import noStyledTaggedTemplateExpression from './no-styled-tagged-template-expres
43
44
  import noUnsafeDesignTokenUsage from './no-unsafe-design-token-usage';
44
45
  import noUnsafeStyleOverrides from './no-unsafe-style-overrides';
45
46
  import noUnsupportedDragAndDropLibraries from './no-unsupported-drag-and-drop-libraries';
47
+ import noUtilityIcons from './no-utility-icons';
46
48
  import preferPrimitives from './prefer-primitives';
47
49
  import useButtonGroupLabel from './use-button-group-label';
48
50
  import useCxFunctionInXcss from './use-cx-function-in-xcss';
@@ -69,6 +71,7 @@ export var rules = {
69
71
  'ensure-design-token-usage': ensureDesignTokenUsage,
70
72
  'ensure-design-token-usage/preview': ensureDesignTokenUsagePreview,
71
73
  'ensure-icon-color': ensureIconColor,
74
+ 'ensure-proper-xcss-usage': ensureProperXcssUsage,
72
75
  'icon-label': iconLabel,
73
76
  'no-banned-imports': noBannedImports,
74
77
  'no-boolean-autofocus-on-modal-dialog': noBooleanAutofocusOnModalDialog,
@@ -105,6 +108,7 @@ export var rules = {
105
108
  'no-unsafe-design-token-usage': noUnsafeDesignTokenUsage,
106
109
  'no-unsafe-style-overrides': noUnsafeStyleOverrides,
107
110
  'no-unsupported-drag-and-drop-libraries': noUnsupportedDragAndDropLibraries,
111
+ 'no-utility-icons': noUtilityIcons,
108
112
  'prefer-primitives': preferPrimitives,
109
113
  'use-button-group-label': useButtonGroupLabel,
110
114
  'use-cx-function-in-xcss': useCxFunctionInXcss,
@@ -14,6 +14,8 @@ export var createChecks = function createChecks(context) {
14
14
  var legacyButtonImports = new Set();
15
15
  var errorsManual = {};
16
16
  var errorsAuto = {};
17
+ var iconSizesInfo = {}; //Import source key, locations as value
18
+
17
19
  var guidance = {};
18
20
 
19
21
  // Extract parameters
@@ -385,6 +387,7 @@ export var createChecks = function createChecks(context) {
385
387
 
386
388
  // Legacy icons rendered as JSX elements
387
389
  if (Object.keys(legacyIconImports).includes(name)) {
390
+ var _sizeProp$value2;
388
391
  // Determine if inside a new button - if so:
389
392
  // - Assume spread props are safe - still error if props explicitly set to unmigratable values
390
393
  var insideNewButton = isInsideNewButton(node, newButtonImports);
@@ -483,7 +486,7 @@ export var createChecks = function createChecks(context) {
483
486
  var isNewIconMigratable = canAutoMigrateNewIconBasedOnSize(upcomingIcon ? upcomingIcon.sizeGuidance[size !== null && size !== void 0 ? size : 'medium'] : migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.sizeGuidance[size !== null && size !== void 0 ? size : 'medium']);
484
487
 
485
488
  // 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)
489
+ // 1. size is medium for core/utility icons or not set (default is medium for core and small for utility icons)
487
490
  // 2. not inside a new or legacy button (except for icon-only legacy buttons)
488
491
  var sizeProp = node.openingElement.attributes.find(function (attribute) {
489
492
  return attribute.type === 'JSXAttribute' && (attribute.name.name === 'size' || attribute.name.name === 'LEGACY_size');
@@ -494,13 +497,24 @@ export var createChecks = function createChecks(context) {
494
497
  if (sizeProp && sizeProp.type === 'JSXAttribute' && ((_sizeProp$value = sizeProp.value) === null || _sizeProp$value === void 0 ? void 0 : _sizeProp$value.type) === 'Literal') {
495
498
  if (sizeProp.value.value === 'medium') {
496
499
  spacing = 'spacious';
497
- } else if (sizeProp.value.value === 'small' && (newIcon === null || newIcon === void 0 ? void 0 : newIcon.type) === 'utility') {
498
- spacing = 'compact';
499
500
  }
500
501
  } else if (!sizeProp) {
501
502
  spacing = 'spacious';
502
503
  }
503
504
  }
505
+ if (!iconSizesInfo[legacyIconImports[name].packageName]) {
506
+ iconSizesInfo[legacyIconImports[name].packageName] = {
507
+ small: [],
508
+ usageCount: 0
509
+ };
510
+ }
511
+
512
+ // Do not automatically migration if size is small as we cannot determine if a core icon or a scaled down utility icon should be used
513
+ if (sizeProp && sizeProp.type === 'JSXAttribute' && ((_sizeProp$value2 = sizeProp.value) === null || _sizeProp$value2 === void 0 ? void 0 : _sizeProp$value2.type) === 'Literal' && sizeProp.value.value === 'small') {
514
+ iconSizesInfo[legacyIconImports[name].packageName].small.push(locToString(node));
515
+ }
516
+ iconSizesInfo[legacyIconImports[name].packageName].usageCount++;
517
+ var shouldForceSmallIcon = newIcon === null || newIcon === void 0 ? void 0 : newIcon.shouldForceSmallIcon;
504
518
  if (shouldUseSafeMigrationMode && !hasManualMigration && (newIcon !== null && newIcon !== void 0 && newIcon.isMigrationUnsafe || size !== 'medium' || hasSecondaryColorProp)) {
505
519
  createCantFindSuitableReplacementError(node, legacyIconImports[name].packageName, name, errorsManual, upcomingIcon ? true : migrationMapObject ? true : false);
506
520
  } else if (!hasManualMigration && (newIcon || upcomingIcon) && isNewIconMigratable) {
@@ -510,7 +524,8 @@ export var createChecks = function createChecks(context) {
510
524
  iconName: name,
511
525
  errors: errorsAuto,
512
526
  spacing: spacing,
513
- insideNewButton: insideNewButton
527
+ insideNewButton: insideNewButton,
528
+ shouldForceSmallIcon: shouldForceSmallIcon
514
529
  });
515
530
  } else if ((!newIcon && !upcomingIcon || !isNewIconMigratable) && size) {
516
531
  createCantFindSuitableReplacementError(node, legacyIconImports[name].packageName, name, errorsManual, upcomingIcon ? true : migrationMapObject ? true : false);
@@ -520,7 +535,8 @@ export var createChecks = function createChecks(context) {
520
535
  iconPackage: legacyIconImports[name].packageName,
521
536
  insideNewButton: insideNewButton,
522
537
  size: size && isSize(size) ? size : undefined,
523
- shouldUseMigrationPath: shouldUseMigrationPath
538
+ shouldUseMigrationPath: shouldUseMigrationPath,
539
+ shouldForceSmallIcon: shouldForceSmallIcon
524
540
  });
525
541
  }
526
542
  };
@@ -571,6 +587,7 @@ export var createChecks = function createChecks(context) {
571
587
  throwAutoErrors({
572
588
  errorsManual: errorsManual,
573
589
  errorsAuto: errorsAuto,
590
+ iconSizesInfo: iconSizesInfo,
574
591
  legacyIconImports: legacyIconImports,
575
592
  guidance: guidance,
576
593
  migrationIconImports: migrationIconImports,