@atlaskit/eslint-plugin-design-system 10.8.0 → 10.8.2

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 (76) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -0
  3. package/constellation/index/usage.mdx +1 -0
  4. package/constellation/use-latest-xcss-syntax-typography/usage.mdx +34 -0
  5. package/dist/cjs/ast-nodes/object-entry.js +2 -1
  6. package/dist/cjs/presets/all.codegen.js +2 -1
  7. package/dist/cjs/presets/recommended.codegen.js +2 -1
  8. package/dist/cjs/rules/ensure-design-token-usage/index.js +1 -1
  9. package/dist/cjs/rules/index.codegen.js +3 -1
  10. package/dist/cjs/rules/no-legacy-icons/checks.js +484 -0
  11. package/dist/cjs/rules/no-legacy-icons/helpers.js +289 -0
  12. package/dist/cjs/rules/no-legacy-icons/index.js +111 -131
  13. package/dist/cjs/rules/no-legacy-icons/migration-map-temp.js +4090 -0
  14. package/dist/cjs/rules/use-latest-xcss-syntax-typography/index.js +40 -0
  15. package/dist/cjs/rules/use-latest-xcss-syntax-typography/linters/banned-property/index.js +18 -0
  16. package/dist/cjs/rules/use-latest-xcss-syntax-typography/linters/index.js +12 -0
  17. package/dist/cjs/rules/use-tokens-typography/index.js +1 -1
  18. package/dist/es2019/ast-nodes/object-entry.js +2 -1
  19. package/dist/es2019/presets/all.codegen.js +2 -1
  20. package/dist/es2019/presets/recommended.codegen.js +2 -1
  21. package/dist/es2019/rules/ensure-design-token-usage/index.js +1 -1
  22. package/dist/es2019/rules/index.codegen.js +3 -1
  23. package/dist/es2019/rules/no-legacy-icons/checks.js +388 -0
  24. package/dist/es2019/rules/no-legacy-icons/helpers.js +275 -0
  25. package/dist/es2019/rules/no-legacy-icons/index.js +96 -97
  26. package/dist/es2019/rules/no-legacy-icons/migration-map-temp.js +4082 -0
  27. package/dist/es2019/rules/use-latest-xcss-syntax-typography/index.js +30 -0
  28. package/dist/es2019/rules/use-latest-xcss-syntax-typography/linters/banned-property/index.js +13 -0
  29. package/dist/es2019/rules/use-latest-xcss-syntax-typography/linters/index.js +1 -0
  30. package/dist/es2019/rules/use-tokens-typography/index.js +1 -1
  31. package/dist/esm/ast-nodes/object-entry.js +2 -1
  32. package/dist/esm/presets/all.codegen.js +2 -1
  33. package/dist/esm/presets/recommended.codegen.js +2 -1
  34. package/dist/esm/rules/ensure-design-token-usage/index.js +1 -1
  35. package/dist/esm/rules/index.codegen.js +3 -1
  36. package/dist/esm/rules/no-legacy-icons/checks.js +477 -0
  37. package/dist/esm/rules/no-legacy-icons/helpers.js +279 -0
  38. package/dist/esm/rules/no-legacy-icons/index.js +111 -131
  39. package/dist/esm/rules/no-legacy-icons/migration-map-temp.js +4084 -0
  40. package/dist/esm/rules/use-latest-xcss-syntax-typography/index.js +34 -0
  41. package/dist/esm/rules/use-latest-xcss-syntax-typography/linters/banned-property/index.js +12 -0
  42. package/dist/esm/rules/use-latest-xcss-syntax-typography/linters/index.js +1 -0
  43. package/dist/esm/rules/use-tokens-typography/index.js +1 -1
  44. package/dist/types/index.codegen.d.ts +2 -0
  45. package/dist/types/presets/all.codegen.d.ts +2 -1
  46. package/dist/types/presets/recommended.codegen.d.ts +2 -1
  47. package/dist/types/rules/index.codegen.d.ts +1 -0
  48. package/dist/types/rules/no-legacy-icons/checks.d.ts +13 -0
  49. package/dist/types/rules/no-legacy-icons/helpers.d.ts +82 -0
  50. package/dist/types/rules/no-legacy-icons/index.d.ts +2 -1
  51. package/dist/types/rules/no-legacy-icons/migration-map-temp.d.ts +22 -0
  52. package/dist/types/rules/use-latest-xcss-syntax-typography/index.d.ts +4 -0
  53. package/dist/types/rules/use-latest-xcss-syntax-typography/linters/banned-property/index.d.ts +6 -0
  54. package/dist/types/rules/use-latest-xcss-syntax-typography/linters/index.d.ts +1 -0
  55. package/dist/{types-ts4.5/rules/use-tokens-typography → types/rules/utils}/error-boundary.d.ts +5 -1
  56. package/dist/types-ts4.5/index.codegen.d.ts +2 -0
  57. package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -1
  58. package/dist/types-ts4.5/presets/recommended.codegen.d.ts +2 -1
  59. package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -0
  60. package/dist/types-ts4.5/rules/no-legacy-icons/checks.d.ts +13 -0
  61. package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +82 -0
  62. package/dist/types-ts4.5/rules/no-legacy-icons/index.d.ts +2 -1
  63. package/dist/types-ts4.5/rules/no-legacy-icons/migration-map-temp.d.ts +27 -0
  64. package/dist/types-ts4.5/rules/use-latest-xcss-syntax-typography/index.d.ts +4 -0
  65. package/dist/types-ts4.5/rules/use-latest-xcss-syntax-typography/linters/banned-property/index.d.ts +6 -0
  66. package/dist/types-ts4.5/rules/use-latest-xcss-syntax-typography/linters/index.d.ts +1 -0
  67. package/dist/types-ts4.5/rules/{ensure-design-token-usage → utils}/error-boundary.d.ts +5 -1
  68. package/package.json +2 -2
  69. package/dist/cjs/rules/use-tokens-typography/error-boundary.js +0 -24
  70. package/dist/es2019/rules/use-tokens-typography/error-boundary.js +0 -19
  71. package/dist/esm/rules/use-tokens-typography/error-boundary.js +0 -18
  72. package/dist/types/rules/ensure-design-token-usage/error-boundary.d.ts +0 -11
  73. package/dist/types/rules/use-tokens-typography/error-boundary.d.ts +0 -11
  74. /package/dist/cjs/rules/{ensure-design-token-usage → utils}/error-boundary.js +0 -0
  75. /package/dist/es2019/rules/{ensure-design-token-usage → utils}/error-boundary.js +0 -0
  76. /package/dist/esm/rules/{ensure-design-token-usage → utils}/error-boundary.js +0 -0
@@ -0,0 +1,275 @@
1
+ import { isNodeOfType } from 'eslint-codemod-utils';
2
+ import { getImportName } from '../utils/get-import-name';
3
+ import migrationMap, { outcomeDescriptionMap } from './migration-map-temp';
4
+ /**
5
+ * Returns the migration map object for a legacy icon or null if not found
6
+ * @param iconPackage The name of the legacy icon package
7
+ * @returns The migration map object for the legacy icon or null if not found
8
+ */
9
+ export const getMigrationMapObject = iconPackage => {
10
+ const key = getIconKey(iconPackage);
11
+ if (key in migrationMap) {
12
+ return migrationMap[key];
13
+ }
14
+ return null;
15
+ };
16
+
17
+ /**
18
+ * Returns the key of a legacy icon
19
+ * @param iconPackage The name of the legacy icon package
20
+ * @returns The unique identifier for the icon (the part after "@atlaskit/icon/glyph")
21
+ */
22
+ export const getIconKey = iconPackage => {
23
+ const key = iconPackage.replace(/^@atlaskit\/icon\/glyph\//, '');
24
+ return key;
25
+ };
26
+
27
+ /**
28
+ * Checks if a new icon can be auto-migrated based on guidance from the migration map
29
+ */
30
+ export const canAutoMigrateNewIconBasedOnSize = guidance => {
31
+ return ['swap', 'swap-slight-visual-change', 'swap-visual-change', 'swap-size-shift-utility'].includes(guidance || '');
32
+ };
33
+
34
+ /**
35
+ * Creates the written guidance for migrating a legacy icon to a new icon
36
+ */
37
+ export const createGuidance = (iconPackage, size) => {
38
+ const migrationMapObject = getMigrationMapObject(iconPackage);
39
+ if (migrationMapObject) {
40
+ const newIcon = migrationMapObject.newIcon;
41
+ if (!newIcon) {
42
+ return 'No equivalent icon in new set. An option is to contribute a custom icon into icon-labs package instead.\n';
43
+ }
44
+ if (size) {
45
+ let guidance = `Fix: Use ${newIcon.name} from @atlaskit/${newIcon.library}/${newIcon.type}/${newIcon.name} instead.`;
46
+ if (migrationMapObject.sizeGuidance[size] in outcomeDescriptionMap) {
47
+ guidance += ` Please: ${outcomeDescriptionMap[migrationMapObject.sizeGuidance[size]]}\n`;
48
+ } else {
49
+ guidance += ' No migration advice given.\n';
50
+ }
51
+ return guidance;
52
+ } else {
53
+ let guidance = `Use ${newIcon.name} from @atlaskit/${newIcon.library}/${newIcon.type}/${newIcon.name} instead.\nMigration suggestions, depending on the legacy icon size:\n`;
54
+ for (const [size, value] of Object.entries(migrationMapObject.sizeGuidance)) {
55
+ guidance += `\t- ${size}: `;
56
+ if (!(value in outcomeDescriptionMap)) {
57
+ guidance += 'No migration advice given.\n';
58
+ } else {
59
+ guidance += `${outcomeDescriptionMap[value]}\n`;
60
+ }
61
+ guidance;
62
+ }
63
+ return guidance;
64
+ }
65
+ } else {
66
+ return 'Migration suggestions not found\n';
67
+ }
68
+ };
69
+
70
+ /**
71
+ * Checks if the color can be migrated
72
+ * @param color String representing the color to check
73
+ * @returns True if the color can be migrated, false otherwise
74
+ */
75
+ export const canMigrateColor = color => {
76
+ if (color.match(/^color\.text$/)) {
77
+ return true;
78
+ } else if (color.match(/^color\.icon/)) {
79
+ return true;
80
+ } else if (color.match(/^color\.link/)) {
81
+ return true;
82
+ } else if (color === 'currentColor') {
83
+ return true;
84
+ } else {
85
+ return false;
86
+ }
87
+ };
88
+ export const locToString = node => {
89
+ var _node$loc, _node$loc2, _node$loc3, _node$loc4;
90
+ return `${(_node$loc = node.loc) === null || _node$loc === void 0 ? void 0 : _node$loc.start.line}:${(_node$loc2 = node.loc) === null || _node$loc2 === void 0 ? void 0 : _node$loc2.start.column}:${(_node$loc3 = node.loc) === null || _node$loc3 === void 0 ? void 0 : _node$loc3.end.line}:${(_node$loc4 = node.loc) === null || _node$loc4 === void 0 ? void 0 : _node$loc4.end.column}`;
91
+ };
92
+ export const createCantMigrateReExportError = (node, packageName, exportName, errors) => {
93
+ const myError = {
94
+ node,
95
+ messageId: 'cantMigrateReExport',
96
+ data: {
97
+ packageName,
98
+ exportName
99
+ }
100
+ };
101
+ pushManualError(locToString(node), errors, myError, packageName, exportName);
102
+ };
103
+ export const createCantMigrateIdentifierError = (node, packageName, exportName, errors) => {
104
+ const myError = {
105
+ node,
106
+ messageId: 'cantMigrateIdentifier',
107
+ data: {
108
+ packageName,
109
+ exportName
110
+ }
111
+ };
112
+ pushManualError(locToString(node), errors, myError, packageName, exportName);
113
+ };
114
+ export const findUNSAFEProp = (iconAttr, button) => {
115
+ let UNSAFE_size = null;
116
+ const propName = iconAttr.name.name === 'iconAfter' || iconAttr.name.name === 'iconBefore' || iconAttr.name.name === 'icon' ? iconAttr.name.name : null;
117
+ const buttonAttributes = button.attributes;
118
+ const UNSAFE_propName = propName === 'icon' ? `UNSAFE_size` : propName ? `UNSAFE_${propName}_size` : null;
119
+ const UNSAFE_size_index = buttonAttributes.findIndex(x => UNSAFE_propName && 'name' in x && x.name && x.name.name === UNSAFE_propName);
120
+ let unsafeAttribute = UNSAFE_size_index !== -1 ? buttonAttributes[UNSAFE_size_index] : null;
121
+ if (unsafeAttribute && isNodeOfType(unsafeAttribute, 'JSXAttribute') && unsafeAttribute.value && isNodeOfType(unsafeAttribute.value, 'Literal') && unsafeAttribute.value.value && ['small', 'large', 'xlarge'].includes(unsafeAttribute.value.value)) {
122
+ UNSAFE_size = unsafeAttribute.value.value;
123
+ } else if (unsafeAttribute && isNodeOfType(unsafeAttribute, 'JSXAttribute') && unsafeAttribute.value && isNodeOfType(unsafeAttribute.value, 'JSXExpressionContainer') && isNodeOfType(unsafeAttribute.value.expression, 'Literal') && ['small', 'large', 'xlarge'].includes(unsafeAttribute.value.expression.value)) {
124
+ UNSAFE_size = unsafeAttribute.value.expression.value;
125
+ }
126
+ return {
127
+ UNSAFE_size,
128
+ UNSAFE_propName
129
+ };
130
+ };
131
+ export const createCantMigrateUnsafeProp = (node, propName, value, packageName, iconName, errors) => {
132
+ const myError = {
133
+ node,
134
+ messageId: 'cantMigrateUnsafeProp',
135
+ data: {
136
+ propName,
137
+ value
138
+ }
139
+ };
140
+ pushManualError(locToString(node), errors, myError, packageName, iconName);
141
+ };
142
+ export const createCantFindSuitableReplacementError = (node, importSource, iconName, errors) => {
143
+ const myError = {
144
+ node,
145
+ messageId: 'cantFindSuitableReplacement',
146
+ data: {
147
+ importSource,
148
+ iconName
149
+ }
150
+ };
151
+ pushManualError(locToString(node), errors, myError, importSource, iconName);
152
+ };
153
+ export const createCantMigrateFunctionUnknownError = (node, importSource, iconName, errors) => {
154
+ const myError = {
155
+ node,
156
+ messageId: 'cantMigrateFunctionUnknown',
157
+ data: {
158
+ importSource,
159
+ iconName
160
+ }
161
+ };
162
+ pushManualError(locToString(node), errors, myError, importSource, iconName);
163
+ };
164
+ export const createCantMigrateColorError = (node, colorValue, errors, importSource, iconName) => {
165
+ const myError = {
166
+ node,
167
+ messageId: 'cantMigrateColor',
168
+ data: {
169
+ colorValue
170
+ }
171
+ };
172
+ pushManualError(locToString(node), errors, myError, importSource, iconName);
173
+ };
174
+ export const createCantMigrateSpreadPropsError = (node, missingProps, errors, importSource, iconName) => {
175
+ const myError = {
176
+ node,
177
+ messageId: 'cantMigrateSpreadProps',
178
+ data: {
179
+ missingProps: missingProps.join(', ')
180
+ }
181
+ };
182
+ pushManualError(locToString(node), errors, myError, importSource, iconName);
183
+ };
184
+ export const createCantMigrateSizeUnknown = (node, errors, importSource, iconName) => {
185
+ const myError = {
186
+ node,
187
+ messageId: 'cantMigrateSizeUnknown'
188
+ };
189
+ pushManualError(locToString(node), errors, myError, importSource, iconName);
190
+ };
191
+ export const createAutoMigrationError = (node, importSource, iconName, newIcon, oldIconName, errors) => {
192
+ const migrationKey = newIcon.name === oldIconName ? newIcon.name : `${newIcon.name}--${oldIconName}`;
193
+ const newMigrationIconPackage = `@atlaskit/${newIcon.library}/${newIcon.type}/migration/${migrationKey}`;
194
+ const myError = {
195
+ node,
196
+ messageId: 'noLegacyIconsAutoMigration',
197
+ data: {
198
+ importSource,
199
+ iconName,
200
+ newIcon: newIcon.name,
201
+ //TODO: provide size guidance
202
+ newPackage: newMigrationIconPackage
203
+ }
204
+ };
205
+ errors[locToString(node)] = myError;
206
+ };
207
+ const pushManualError = (key, errors, myError, importSource, iconName) => {
208
+ if (key in errors) {
209
+ errors[key].errors.push(myError);
210
+ } else {
211
+ errors[key] = {
212
+ errors: [myError],
213
+ importSource,
214
+ iconName
215
+ };
216
+ }
217
+ };
218
+ export const getLiteralStringValue = value => {
219
+ if (!value) {
220
+ return;
221
+ }
222
+
223
+ // propName="value"
224
+ if (isNodeOfType(value, 'Literal') && typeof value.value === 'string') {
225
+ return value.value;
226
+ }
227
+
228
+ // propName={"value"}
229
+ if (isNodeOfType(value, 'JSXExpressionContainer') && isNodeOfType(value.expression, 'Literal') && typeof value.expression.value === 'string') {
230
+ return value.expression.value;
231
+ }
232
+ return;
233
+ };
234
+ export const createHelpers = context => {
235
+ /**
236
+ * Extracts the token name of a token() call from a JSXExpressionContainer
237
+ * @param value The JSXExpressionContainer to extract the token call from
238
+ * @returns The value of the token call, or null if it could not be extracted
239
+ */
240
+ const getTokenCallValue = value => {
241
+ const tokenName = getImportName(context.sourceCode.getScope(value), '@atlaskit/tokens', 'token');
242
+ if (tokenName && isNodeOfType(value, 'JSXExpressionContainer') && isNodeOfType(value.expression, 'CallExpression') && 'name' in value.expression.callee && value.expression.callee.name === tokenName) {
243
+ // propName={token("color...."}
244
+ return getLiteralStringValue(value.expression.arguments[0]);
245
+ }
246
+ return;
247
+ };
248
+
249
+ /**
250
+ * Gets the value of a boolean configuration flag
251
+ * @param key the key of the configuration flag
252
+ * @param defaultValue The default value of the configuration flag
253
+ * @returns defaultValue if the configuration flag is not set, the defaultValue of the configuration flag otherwise
254
+ */
255
+ const getConfigFlag = (key, defaultValue) => {
256
+ if (context.options.length > 0 && context.options[0] && key in context.options[0]) {
257
+ return context.options[0][key] === !defaultValue ? !defaultValue : defaultValue;
258
+ }
259
+ return defaultValue;
260
+ };
261
+ return {
262
+ /**
263
+ * Extracts the primaryColor value from a JSXAttribute
264
+ */
265
+ getPrimaryColor(attr) {
266
+ var _ref, _getLiteralStringValu;
267
+ const {
268
+ value
269
+ } = attr;
270
+ return (_ref = (_getLiteralStringValu = getLiteralStringValue(value)) !== null && _getLiteralStringValu !== void 0 ? _getLiteralStringValu : getTokenCallValue(value)) !== null && _ref !== void 0 ? _ref : null;
271
+ },
272
+ getTokenCallValue,
273
+ getConfigFlag
274
+ };
275
+ };
@@ -1,5 +1,7 @@
1
- import { isNodeOfType } from 'eslint-codemod-utils';
2
1
  import { createLintRule } from '../utils/create-rule';
2
+ import { errorBoundary } from '../utils/error-boundary';
3
+ import { createChecks } from './checks';
4
+ import { createHelpers } from './helpers';
3
5
  const rule = createLintRule({
4
6
  meta: {
5
7
  name: 'no-legacy-icons',
@@ -9,123 +11,120 @@ const rule = createLintRule({
9
11
  recommended: false,
10
12
  severity: 'warn'
11
13
  },
14
+ schema: [{
15
+ type: 'object',
16
+ properties: {
17
+ shouldErrorForManualMigration: {
18
+ type: 'boolean'
19
+ },
20
+ shouldErrorForAutoMigration: {
21
+ type: 'boolean'
22
+ },
23
+ quiet: {
24
+ type: 'boolean'
25
+ }
26
+ },
27
+ additionalProperties: false
28
+ }],
12
29
  messages: {
13
- noLegacyIcons: `Legacy icon '{{iconName}}', is being rendered from import '{{importSource}}'. Migrate to an icon from '@atlaskit/icon/(core|utility)', or '@atlaskit/icon-labs/(core|utility)'.
14
- Learn more in our [code migration guide](https://hello.atlassian.net/wiki/spaces/DST/pages/3748692796/New+ADS+iconography+-+Code+migration+guide).`
30
+ noLegacyIconsAutoMigration: `Auto Migration:\nLegacy icon '{{iconName}}' from '{{importSource}}' detected.\nAutomatic migration is possible to '{{newIcon}}' from '{{newPackage}}.\nAtlassians: See https://go.atlassian.com/icon-migration-guide for details.'`,
31
+ noLegacyIconsManualMigration: `Manual Migration:\nLegacy icon '{{iconName}}' from '{{importSource}}' detected.\nAutomatic migration not possible.{{quietModeGuidance}}.\nAtlassians: See https://go.atlassian.com/icon-migration-guide for details.`,
32
+ cantFindSuitableReplacement: `No suitable replacement found for '{{iconName}}' from '{{importSource}}' at the size listed. Please manually migrate this icon.`,
33
+ cantMigrateReExport: `'{{exportName}}' is a re-export of icon from '{{packageName}}' and cannot be automatically migrated. Please utilize the export from icons directly.`,
34
+ cantMigrateColor: `Primary Color prop has {{colorValue}} which cannot be automatically migrated to color prop in the new Icon API. Please use either an appropriate color.icon, color.link token, or currentColor (as a last resort).`,
35
+ cantMigrateSpreadProps: `This usage of Icon uses spread props in a way that can't be automatically migrated. Please explicitly define the following props after spread: '{{missingProps}}' `,
36
+ cantMigrateSizeUnknown: `This usage of Icon sets the size via a variable or function that can't be determined.`,
37
+ cantMigrateFunctionUnknown: `'{{iconName}}' from legacy '{{importSource}}' is used in unknown function/component. Please manually migrate this icon.`,
38
+ cantMigrateIdentifier: `This icon is passed to other components via a map or array, in a way that can't be automatically migrated. Please manually migrate wherever this expression is used and use the icon components directly.`,
39
+ cantMigrateUnsafeProp: `Property '{{propName}}' with value of '{{value}}' is unable to be auto-migrated to the new button. Please manually migrate this icon.`,
40
+ guidance: `Guidance:\n'{{guidance}}'`
15
41
  }
16
42
  },
17
43
  create(context) {
18
- const legacyIconImports = {};
44
+ const {
45
+ getConfigFlag
46
+ } = createHelpers(context);
47
+ const failSilently = getConfigFlag('failSilently', false);
48
+ const {
49
+ checkImportDeclarations,
50
+ checkVariableDeclarations,
51
+ checkExportDefaultDeclaration,
52
+ checkExportNamedVariables,
53
+ checkArrayOrMap,
54
+ checkIconAsProp,
55
+ checkJSXElement,
56
+ checkCallExpression,
57
+ throwErrors
58
+ } = createChecks(context);
19
59
  return {
60
+ // Track imports of relevant components
20
61
  ImportDeclaration(node) {
21
- const moduleSource = node.source.value;
22
- if (typeof moduleSource === 'string' && ['@atlaskit/icon/glyph/', '@atlaskit/icon-object/glyph/'].find(val => moduleSource.startsWith(val)) && node.specifiers.length) {
23
- const defaultImport = node.specifiers.find(spec => spec.type === 'ImportDefaultSpecifier');
24
- if (!defaultImport) {
25
- return;
62
+ errorBoundary(() => checkImportDeclarations(node), {
63
+ config: {
64
+ failSilently
26
65
  }
27
- const defaultImportName = defaultImport.local.name;
28
- legacyIconImports[defaultImportName] = moduleSource;
29
- }
66
+ });
30
67
  },
68
+ // Keep track of the relevant variable declarations and renames
31
69
  VariableDeclaration(node) {
32
- if (isNodeOfType(node, 'VariableDeclaration')) {
33
- for (const decl of node.declarations) {
34
- if (isNodeOfType(decl, 'VariableDeclarator') && 'init' in decl && 'id' in decl && decl.init && decl.id && 'name' in decl.id && decl.id.name && isNodeOfType(decl.init, 'Identifier') && decl.init.name in legacyIconImports) {
35
- legacyIconImports[decl.id.name] = legacyIconImports[decl.init.name];
36
- }
70
+ errorBoundary(() => checkVariableDeclarations(node), {
71
+ config: {
72
+ failSilently
37
73
  }
38
- }
74
+ });
39
75
  },
76
+ // Case: default re-exports. Can't be auto-migrated
40
77
  ExportDefaultDeclaration(node) {
41
- if ('declaration' in node && node.declaration && isNodeOfType(node.declaration, 'Identifier') && node.declaration.name in legacyIconImports) {
42
- context.report({
43
- node,
44
- messageId: 'noLegacyIcons',
45
- data: {
46
- importSource: legacyIconImports[node.declaration.name],
47
- iconName: node.declaration.name
48
- }
49
- });
50
- }
78
+ errorBoundary(() => checkExportDefaultDeclaration(node), {
79
+ config: {
80
+ failSilently
81
+ }
82
+ });
51
83
  },
52
84
  ExportNamedDeclaration(node) {
53
- if ('source' in node && node.source && isNodeOfType(node.source, 'Literal') && 'value' in node.source) {
54
- const moduleSource = node.source.value;
55
- if (typeof moduleSource === 'string' && ['@atlaskit/icon/glyph/', '@atlaskit/icon-object/glyph/'].find(val => moduleSource.startsWith(val)) && node.specifiers.length) {
56
- context.report({
57
- node,
58
- messageId: 'noLegacyIcons',
59
- data: {
60
- importSource: moduleSource,
61
- iconName: node.specifiers[0].exported.name
62
- }
63
- });
85
+ errorBoundary(() => checkExportNamedVariables(node), {
86
+ config: {
87
+ failSilently
64
88
  }
65
- } else if ('declaration' in node && node.declaration && isNodeOfType(node.declaration, 'VariableDeclaration')) {
66
- for (const decl of node.declaration.declarations) {
67
- if (isNodeOfType(decl, 'VariableDeclarator') && 'init' in decl && decl.init && isNodeOfType(decl.init, 'Identifier') && decl.init.name in legacyIconImports) {
68
- context.report({
69
- node,
70
- messageId: 'noLegacyIcons',
71
- data: {
72
- importSource: legacyIconImports[decl.init.name],
73
- iconName: decl.init.name
74
- }
75
- });
76
- }
89
+ });
90
+ },
91
+ // Legacy icons found in arrays/objects
92
+ 'ObjectExpression > Property > Identifier, ArrayExpression > Identifier ': node => {
93
+ errorBoundary(() => checkArrayOrMap(node), {
94
+ config: {
95
+ failSilently
77
96
  }
78
- }
97
+ });
79
98
  },
80
- JSXAttribute(node) {
81
- if (!isNodeOfType(node.value, 'JSXExpressionContainer')) {
82
- return;
83
- }
84
- if (isNodeOfType(node.value.expression, 'Identifier') && node.value.expression.name in legacyIconImports && isNodeOfType(node.name, 'JSXIdentifier') && !node.name.name.startsWith('LEGACY_')) {
85
- context.report({
86
- node,
87
- messageId: 'noLegacyIcons',
88
- data: {
89
- importSource: legacyIconImports[node.value.expression.name],
90
- iconName: node.value.expression.name
91
- }
92
- });
93
- }
99
+ // Legacy icons passed in via props, as JSX identifier (i.e. icon={AddIcon})
100
+ 'JSXOpeningElement > JSXAttribute > JSXExpressionContainer > Identifier': node => {
101
+ errorBoundary(() => checkIconAsProp(node), {
102
+ config: {
103
+ failSilently
104
+ }
105
+ });
94
106
  },
95
107
  JSXElement(node) {
96
- if (!isNodeOfType(node, 'JSXElement')) {
97
- return;
98
- }
99
- if (!isNodeOfType(node.openingElement.name, 'JSXIdentifier')) {
100
- return;
101
- }
102
- const name = node.openingElement.name.name;
103
- if (name in legacyIconImports) {
104
- context.report({
105
- node,
106
- messageId: 'noLegacyIcons',
107
- data: {
108
- importSource: legacyIconImports[name],
109
- iconName: name
110
- }
111
- });
112
- }
108
+ errorBoundary(() => checkJSXElement(node), {
109
+ config: {
110
+ failSilently
111
+ }
112
+ });
113
113
  },
114
- CallExpression(node) {
115
- if ('arguments' in node && node.arguments.length) {
116
- for (const arg of node.arguments) {
117
- if (isNodeOfType(arg, 'Identifier') && arg.name in legacyIconImports) {
118
- context.report({
119
- node: arg,
120
- messageId: 'noLegacyIcons',
121
- data: {
122
- importSource: legacyIconImports[arg.name],
123
- iconName: arg.name
124
- }
125
- });
126
- }
114
+ // Icons called as an argument of a function (i.e. icon={DefaultIcon(AddIcon)})
115
+ CallExpression: node => {
116
+ errorBoundary(() => checkCallExpression(node), {
117
+ config: {
118
+ failSilently
127
119
  }
128
- }
120
+ });
121
+ },
122
+ 'Program:exit': () => {
123
+ errorBoundary(() => throwErrors(), {
124
+ config: {
125
+ failSilently
126
+ }
127
+ });
129
128
  }
130
129
  };
131
130
  }