@atlaskit/eslint-plugin-design-system 10.12.3 → 10.12.5

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.
@@ -1,5 +1,5 @@
1
1
  import { isNodeOfType } from 'eslint-codemod-utils';
2
- import { canAutoMigrateNewIconBasedOnSize, canMigrateColor, createAutoMigrationError, createCantFindSuitableReplacementError, createCantMigrateColorError, createCantMigrateFunctionUnknownError, createCantMigrateIdentifierError, createCantMigrateReExportError, createCantMigrateSizeUnknown, createCantMigrateSpreadPropsError, createGuidance, createHelpers, getMigrationMapObject, isSize, locToString } from './helpers';
2
+ import { addToListOfRanges, canAutoMigrateNewIconBasedOnSize, canMigrateColor, createAutoMigrationError, createCantFindSuitableReplacementError, createCantMigrateColorError, createCantMigrateFunctionUnknownError, createCantMigrateIdentifierError, createCantMigrateIdentifierMapOrArrayError, createCantMigrateReExportError, createCantMigrateSizeUnknown, createCantMigrateSpreadPropsError, createGuidance, createHelpers, getMigrationMapObject, getUpcomingIcons, isInRangeList, isSize, locToString } from './helpers';
3
3
  export const createChecks = context => {
4
4
  //create global variables to be shared by the checks
5
5
  const {
@@ -17,6 +17,9 @@ export const createChecks = context => {
17
17
  const shouldErrorForAutoMigration = getConfigFlag('shouldErrorForAutoMigration', true);
18
18
  const isQuietMode = getConfigFlag('quiet', false);
19
19
 
20
+ // Sorted list of ranges
21
+ let errorRanges = [];
22
+
20
23
  /**
21
24
  * Adds the legacy Icon and new button imports to the correct global arrays to be used by the other checks
22
25
  * @param node The import node found by ESLint
@@ -56,8 +59,8 @@ export const createChecks = context => {
56
59
  if (isNodeOfType(node, 'VariableDeclaration')) {
57
60
  const isExported = node.parent && isNodeOfType(node.parent, 'ExportNamedDeclaration');
58
61
  for (const decl of node.declarations) {
59
- 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')) {
60
- if (decl.init.name in legacyIconImports) {
62
+ if (isNodeOfType(decl, 'VariableDeclarator') && Object.keys(decl).includes('init') && Object.keys(decl).includes('id') && decl.init && decl.id && 'name' in decl.id && decl.id.name && isNodeOfType(decl.init, 'Identifier')) {
63
+ if (Object.keys(legacyIconImports).includes(decl.init.name)) {
61
64
  legacyIconImports[decl.id.name] = {
62
65
  packageName: legacyIconImports[decl.init.name].packageName,
63
66
  exported: legacyIconImports[decl.init.name].exported || isExported
@@ -77,16 +80,17 @@ export const createChecks = context => {
77
80
  const checkExportDefaultDeclaration = node => {
78
81
  let exportName = '';
79
82
  let packageName = '';
80
- if ('declaration' in node && node.declaration && isNodeOfType(node.declaration, 'Identifier') && node.declaration.name in legacyIconImports) {
83
+ if (Object.keys(node).includes('declaration') && node.declaration && isNodeOfType(node.declaration, 'Identifier') && Object.keys(legacyIconImports).includes(node.declaration.name)) {
81
84
  packageName = legacyIconImports[node.declaration.name].packageName;
82
85
  exportName = 'Default export';
83
- } else if ('declaration' in node && node.declaration && isNodeOfType(node.declaration, 'AssignmentExpression') && isNodeOfType(node.declaration.left, 'Identifier') && isNodeOfType(node.declaration.right, 'Identifier') && node.declaration.right.name in legacyIconImports) {
86
+ } else if (Object.keys(node).includes('declaration') && node.declaration && isNodeOfType(node.declaration, 'AssignmentExpression') && isNodeOfType(node.declaration.left, 'Identifier') && isNodeOfType(node.declaration.right, 'Identifier') && Object.keys(legacyIconImports).includes(node.declaration.right.name)) {
84
87
  packageName = legacyIconImports[node.declaration.right.name].packageName;
85
88
  exportName = node.declaration.left.name;
86
89
  } else {
87
90
  return;
88
91
  }
89
92
  createCantMigrateReExportError(node, packageName, exportName, errorsManual);
93
+ addToListOfRanges(node, errorRanges);
90
94
  guidance[locToString(node)] = createGuidance(packageName);
91
95
  };
92
96
 
@@ -96,19 +100,21 @@ export const createChecks = context => {
96
100
  */
97
101
  const checkExportNamedVariables = node => {
98
102
  // export {default as AddIcon} from '@atlaskit/icon/glyph/add';
99
- if (node.source && isNodeOfType(node.source, 'Literal') && 'value' in node.source) {
103
+ if (node.source && isNodeOfType(node.source, 'Literal') && Object.keys(node.source).includes('value')) {
100
104
  const moduleSource = node.source.value;
101
105
  if (typeof moduleSource === 'string' && ['@atlaskit/icon/glyph/', '@atlaskit/icon-object/glyph/'].find(val => moduleSource.startsWith(val)) && node.specifiers.length) {
102
106
  for (const spec of node.specifiers) {
103
107
  createCantMigrateReExportError(spec, moduleSource, spec.exported.name, errorsManual);
108
+ addToListOfRanges(spec, errorRanges);
104
109
  guidance[locToString(spec)] = createGuidance(moduleSource);
105
110
  }
106
111
  }
107
112
  } else if (node.declaration && isNodeOfType(node.declaration, 'VariableDeclaration')) {
108
113
  // export const Icon = AddIcon;
109
114
  for (const decl of node.declaration.declarations) {
110
- if (isNodeOfType(decl, 'VariableDeclarator') && 'init' in decl && decl.init && isNodeOfType(decl.init, 'Identifier') && decl.init.name in legacyIconImports) {
115
+ if (isNodeOfType(decl, 'VariableDeclarator') && Object.keys(decl).includes('init') && decl.init && isNodeOfType(decl.init, 'Identifier') && Object.keys(legacyIconImports).includes(decl.init.name)) {
111
116
  createCantMigrateReExportError(node, legacyIconImports[decl.init.name].packageName, decl.init.name, errorsManual);
117
+ addToListOfRanges(node, errorRanges);
112
118
  guidance[locToString(node)] = createGuidance(legacyIconImports[decl.init.name].packageName);
113
119
  }
114
120
  }
@@ -120,13 +126,14 @@ export const createChecks = context => {
120
126
  * export { AddIcon, CrossIcon as default }
121
127
  */
122
128
  for (const spec of node.specifiers) {
123
- if (spec.local.name in legacyIconImports) {
129
+ if (Object.keys(legacyIconImports).includes(spec.local.name)) {
124
130
  //update legacy imports to be exported
125
131
  legacyIconImports[spec.local.name] = {
126
132
  packageName: legacyIconImports[spec.local.name].packageName,
127
133
  exported: true
128
134
  };
129
135
  createCantMigrateReExportError(spec, legacyIconImports[spec.local.name].packageName, spec.exported.name, errorsManual);
136
+ addToListOfRanges(spec, errorRanges);
130
137
  guidance[locToString(spec)] = createGuidance(legacyIconImports[spec.local.name].packageName);
131
138
  }
132
139
  }
@@ -141,8 +148,9 @@ export const createChecks = context => {
141
148
  if (!isNodeOfType(node, 'Identifier')) {
142
149
  return;
143
150
  }
144
- if (node.name && node.name in legacyIconImports && legacyIconImports[node.name].packageName) {
145
- createCantMigrateIdentifierError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
151
+ if (node.name && Object.keys(legacyIconImports).includes(node.name) && legacyIconImports[node.name].packageName) {
152
+ createCantMigrateIdentifierMapOrArrayError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
153
+ addToListOfRanges(node, errorRanges);
146
154
  guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName);
147
155
  }
148
156
  };
@@ -161,24 +169,44 @@ export const createChecks = context => {
161
169
  if (!isNodeOfType(node.parent, 'JSXExpressionContainer') || !isNodeOfType(node.parent.parent, 'JSXAttribute') || !isNodeOfType(node.parent.parent.parent, 'JSXOpeningElement')) {
162
170
  return;
163
171
  }
164
- if (node.name in legacyIconImports && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') && node.parent.parent.name.name !== 'LEGACY_fallbackIcon') {
172
+ if (Object.keys(legacyIconImports).includes(node.name) && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') && node.parent.parent.name.name !== 'LEGACY_fallbackIcon') {
165
173
  var _migrationMapObject$s;
166
174
  const migrationMapObject = getMigrationMapObject(legacyIconImports[node.name].packageName);
175
+ const upcomingIcon = getUpcomingIcons(legacyIconImports[node.name].packageName);
167
176
  const newIcon = migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.newIcon;
168
- const isNewIconMigratable = canAutoMigrateNewIconBasedOnSize(migrationMapObject === null || migrationMapObject === void 0 ? void 0 : (_migrationMapObject$s = migrationMapObject.sizeGuidance) === null || _migrationMapObject$s === void 0 ? void 0 : _migrationMapObject$s.medium);
177
+ const isNewIconMigratable = canAutoMigrateNewIconBasedOnSize(upcomingIcon ? upcomingIcon.sizeGuidance.medium : migrationMapObject === null || migrationMapObject === void 0 ? void 0 : (_migrationMapObject$s = migrationMapObject.sizeGuidance) === null || _migrationMapObject$s === void 0 ? void 0 : _migrationMapObject$s.medium);
169
178
  const isInNewButton = isNodeOfType(node.parent.parent.parent.name, 'JSXIdentifier') && newButtonImports.has(node.parent.parent.parent.name.name);
170
- if (newIcon && isInNewButton && isNewIconMigratable) {
179
+ if (newIcon && isInNewButton && isNewIconMigratable || upcomingIcon && isInNewButton && isNewIconMigratable) {
171
180
  createAutoMigrationError(node, legacyIconImports[node.name].packageName, node.name, errorsAuto);
181
+ addToListOfRanges(node, errorRanges);
172
182
  guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName, isInNewButton, 'medium');
173
- } else if (!newIcon || !isNewIconMigratable) {
183
+ } else if (!newIcon && !upcomingIcon || !isNewIconMigratable) {
174
184
  createCantFindSuitableReplacementError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
185
+ addToListOfRanges(node, errorRanges);
175
186
  guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName, isInNewButton);
176
187
  } else if (!isInNewButton) {
177
188
  createCantMigrateFunctionUnknownError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
189
+ addToListOfRanges(node, errorRanges);
178
190
  guidance[locToString(node)] = createGuidance(legacyIconImports[node.name].packageName, isInNewButton);
179
191
  }
180
192
  }
181
193
  };
194
+ const checkIconReference = node => {
195
+ //check the reference to see if it's a legacy icon, if not exit early
196
+ if (!Object.keys(legacyIconImports).includes(node.name)) {
197
+ return;
198
+ }
199
+ //if this is an import statement then exit early
200
+ if (node.parent && (isNodeOfType(node.parent, 'ImportSpecifier') || isNodeOfType(node.parent, 'ImportDefaultSpecifier'))) {
201
+ return;
202
+ }
203
+ //if in Fallback prop, do not error
204
+ if (node.parent && node.parent.parent && isNodeOfType(node.parent.parent, 'JSXAttribute') && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') && node.parent.parent.name.name === 'LEGACY_fallbackIcon') {
205
+ return;
206
+ }
207
+ // manually error
208
+ createCantMigrateIdentifierError(node, legacyIconImports[node.name].packageName, node.name, errorsManual);
209
+ };
182
210
 
183
211
  /**
184
212
  * Checks if a legacy icon is being rendered and stores the errors in the global array
@@ -196,8 +224,8 @@ export const createChecks = context => {
196
224
  }
197
225
  const name = node.openingElement.name.name;
198
226
  // Legacy icons rendered as JSX elements
199
- if (name in legacyIconImports) {
200
- var _node$parent2, _node$parent2$parent, _node$parent3, _node$parent3$parent, _node$parent3$parent$, _size;
227
+ if (Object.keys(legacyIconImports).includes(name)) {
228
+ var _node$parent2, _node$parent2$parent, _node$parent3, _node$parent3$parent, _node$parent3$parent$, _size, _size2;
201
229
  // Determine if inside a new button - if so:
202
230
  // - Assume spread props are safe - still error if props explicitly set to unmigratable values
203
231
  let insideNewButton = false;
@@ -268,13 +296,15 @@ export const createChecks = context => {
268
296
  hasManualMigration = true;
269
297
  }
270
298
  const migrationMapObject = getMigrationMapObject(legacyIconImports[name].packageName);
299
+ const upcomingIcon = getUpcomingIcons(legacyIconImports[name].packageName);
271
300
  const newIcon = migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.newIcon;
272
- const isNewIconMigratable = canAutoMigrateNewIconBasedOnSize(migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.sizeGuidance[(_size = size) !== null && _size !== void 0 ? _size : 'medium']);
273
- if (!hasManualMigration && newIcon && isNewIconMigratable) {
301
+ const isNewIconMigratable = canAutoMigrateNewIconBasedOnSize(upcomingIcon ? upcomingIcon.sizeGuidance[(_size = size) !== null && _size !== void 0 ? _size : 'medium'] : migrationMapObject === null || migrationMapObject === void 0 ? void 0 : migrationMapObject.sizeGuidance[(_size2 = size) !== null && _size2 !== void 0 ? _size2 : 'medium']);
302
+ if (!hasManualMigration && (newIcon || upcomingIcon) && isNewIconMigratable) {
274
303
  createAutoMigrationError(node, legacyIconImports[name].packageName, name, errorsAuto);
275
- } else if ((!newIcon || !isNewIconMigratable) && size) {
276
- createCantFindSuitableReplacementError(node, legacyIconImports[name].packageName, name, errorsManual, migrationMapObject ? true : false);
304
+ } else if ((!newIcon && !upcomingIcon || !isNewIconMigratable) && size) {
305
+ createCantFindSuitableReplacementError(node, legacyIconImports[name].packageName, name, errorsManual, upcomingIcon ? true : migrationMapObject ? true : false);
277
306
  }
307
+ addToListOfRanges(node, errorRanges);
278
308
  guidance[locToString(node)] = createGuidance(legacyIconImports[name].packageName, insideNewButton, size && isSize(size) ? size : undefined);
279
309
  }
280
310
  };
@@ -284,10 +314,11 @@ export const createChecks = context => {
284
314
  * @param node The function call node found by ESLint
285
315
  */
286
316
  const checkCallExpression = node => {
287
- if ('arguments' in node && node.arguments.length) {
317
+ if (Object.keys(node).includes('arguments') && node.arguments.length) {
288
318
  for (const arg of node.arguments) {
289
- if (isNodeOfType(arg, 'Identifier') && arg.name in legacyIconImports && legacyIconImports[arg.name].packageName) {
319
+ if (isNodeOfType(arg, 'Identifier') && Object.keys(legacyIconImports).includes(arg.name) && legacyIconImports[arg.name].packageName) {
290
320
  createCantMigrateFunctionUnknownError(node, legacyIconImports[arg.name].packageName, arg.name, errorsManual);
321
+ addToListOfRanges(node, errorRanges);
291
322
  guidance[locToString(node)] = createGuidance(legacyIconImports[arg.name].packageName);
292
323
  }
293
324
  }
@@ -301,20 +332,29 @@ export const createChecks = context => {
301
332
  if (shouldErrorForManualMigration) {
302
333
  for (const [key, errorList] of Object.entries(errorsManual)) {
303
334
  const node = 'node' in errorList.errors[0] ? errorList.errors[0].node : null;
335
+ const cantMigrateIdentifierError = errorList.errors.find(x => 'messageId' in x && x.messageId === 'cantMigrateIdentifier');
304
336
  if (node) {
305
- const guidanceMessage = key in guidance ? guidance[key] : '';
306
- context.report({
307
- node,
308
- messageId: 'noLegacyIconsManualMigration',
309
- data: {
310
- iconName: errorList.iconName,
311
- importSource: errorList.importSource,
312
- guidance: isQuietMode ? guidanceMessage : `${guidanceMessage}For more information see the below errors.\n`
313
- }
314
- });
315
- if (!isQuietMode) {
316
- for (const error of errorList.errors) {
317
- context.report(error);
337
+ let isInRange = false;
338
+ if (cantMigrateIdentifierError && isInRangeList(node, errorRanges)) {
339
+ isInRange = true;
340
+ }
341
+ if (isInRange && errorList.errors.length - 1 > 0 || !isInRange && errorList.errors.length > 0) {
342
+ const guidanceMessage = Object.keys(guidance).includes(key) ? guidance[key] : '';
343
+ context.report({
344
+ node,
345
+ messageId: 'noLegacyIconsManualMigration',
346
+ data: {
347
+ iconName: errorList.iconName,
348
+ importSource: errorList.importSource,
349
+ guidance: isQuietMode ? guidanceMessage : `${guidanceMessage}For more information see the below errors.\n`
350
+ }
351
+ });
352
+ if (!isQuietMode) {
353
+ for (const error of errorList.errors) {
354
+ if ('messageId' in error && (error.messageId !== 'cantMigrateIdentifier' || error.messageId === 'cantMigrateIdentifier' && !isInRange)) {
355
+ context.report(error);
356
+ }
357
+ }
318
358
  }
319
359
  }
320
360
  }
@@ -324,14 +364,17 @@ export const createChecks = context => {
324
364
  for (const [key, error] of Object.entries(errorsAuto)) {
325
365
  // If there's a manual error that exists for this same component,
326
366
  // don't throw the auto error
327
- if (key in errorsManual) {
328
- delete errorsAuto[key];
329
- continue;
367
+ if (Object.keys(errorsManual).includes(key)) {
368
+ const cantMigrateIdentifierError = errorsManual[key].errors.find(x => 'messageId' in x && x.messageId === 'cantMigrateIdentifier');
369
+ if (!cantMigrateIdentifierError || cantMigrateIdentifierError && errorsManual[key].errors.length > 1) {
370
+ delete errorsAuto[key];
371
+ continue;
372
+ }
330
373
  }
331
374
  const node = 'node' in error ? error.node : null;
332
375
  if (node) {
333
- const guidanceMessage = key in guidance ? guidance[key] : '';
334
- if ('data' in error && error.data) {
376
+ const guidanceMessage = Object.keys(guidance).includes(key) ? guidance[key] : '';
377
+ if (Object.keys(error).includes('data') && error.data) {
335
378
  error.data.guidance = guidanceMessage;
336
379
  }
337
380
  context.report(error);
@@ -348,6 +391,7 @@ export const createChecks = context => {
348
391
  checkIconAsProp,
349
392
  checkJSXElement,
350
393
  checkCallExpression,
351
- throwErrors
394
+ throwErrors,
395
+ checkIconReference
352
396
  };
353
397
  };
@@ -1,6 +1,7 @@
1
1
  import { isNodeOfType } from 'eslint-codemod-utils';
2
2
  import baseMigrationMap, { migrationOutcomeDescriptionMap } from '@atlaskit/icon/UNSAFE_migration-map';
3
3
  import { getImportName } from '../utils/get-import-name';
4
+ import { upcomingIcons } from './upcoming-icons';
4
5
  const sizes = ['small', 'medium', 'large', 'xlarge'];
5
6
  export const isSize = size => sizes.includes(size);
6
7
 
@@ -11,11 +12,26 @@ export const isSize = size => sizes.includes(size);
11
12
  */
12
13
  export const getMigrationMapObject = iconPackage => {
13
14
  const key = getIconKey(iconPackage);
14
- if (key in baseMigrationMap) {
15
+ if (Object.keys(baseMigrationMap).includes(key)) {
15
16
  return baseMigrationMap[key];
16
17
  }
17
18
  return null;
18
19
  };
20
+ export const getUpcomingIcons = iconPackage => {
21
+ const key = getIconKey(iconPackage);
22
+ if (upcomingIcons.includes(key)) {
23
+ const retval = {
24
+ sizeGuidance: {
25
+ small: 'swap',
26
+ medium: 'swap',
27
+ large: 'icon-tile',
28
+ xlarge: 'icon-tile'
29
+ }
30
+ };
31
+ return retval;
32
+ }
33
+ return null;
34
+ };
19
35
 
20
36
  /**
21
37
  * Returns the key of a legacy icon
@@ -39,7 +55,29 @@ export const canAutoMigrateNewIconBasedOnSize = guidance => {
39
55
  */
40
56
  export const createGuidance = (iconPackage, insideNewButton = false, size) => {
41
57
  const migrationMapObject = getMigrationMapObject(iconPackage);
42
- if (migrationMapObject) {
58
+ const upcomingIcon = getUpcomingIcons(iconPackage);
59
+ if (upcomingIcon) {
60
+ let guidance = '';
61
+ if (size) {
62
+ if (upcomingIcon.sizeGuidance[size] && canAutoMigrateNewIconBasedOnSize(upcomingIcon.sizeGuidance[size])) {
63
+ guidance += `Fix: An upcoming icon release is planned to migrate this legacy icon.`;
64
+ } else {
65
+ guidance += `No equivalent icon for this size, ${size}, in the current or upcoming set of icons.`;
66
+ }
67
+ guidance += `${Object.keys(migrationOutcomeDescriptionMap).includes(upcomingIcon.sizeGuidance[size]) ? ` Once the upcoming icons are released, please: ${migrationOutcomeDescriptionMap[upcomingIcon.sizeGuidance[size]]}` : ' No migration size advice given.'}\n`;
68
+ } else {
69
+ guidance = `Please wait for the upcoming icons released, as it will contain an alternative for this legacy icon.\nMigration suggestions, depending on the legacy icon size:\n`;
70
+ for (const [size, value] of Object.entries(upcomingIcon.sizeGuidance)) {
71
+ guidance += `\t- ${size}: `;
72
+ if (!Object.keys(migrationOutcomeDescriptionMap).includes(value)) {
73
+ guidance += 'No migration advice given.\n';
74
+ } else {
75
+ guidance += `${migrationOutcomeDescriptionMap[value]}.\n`;
76
+ }
77
+ }
78
+ }
79
+ return guidance;
80
+ } else if (migrationMapObject) {
43
81
  const newIcon = migrationMapObject.newIcon;
44
82
  if (!newIcon) {
45
83
  return 'No equivalent icon in new set. An option is to contribute a custom icon into icon-labs package instead.\n';
@@ -52,12 +90,12 @@ export const createGuidance = (iconPackage, insideNewButton = false, size) => {
52
90
  } else {
53
91
  guidance += `No equivalent icon for this size, ${size}, in new set.`;
54
92
  }
55
- guidance += `${migrationMapObject.sizeGuidance[size] in migrationOutcomeDescriptionMap ? ` Please: ${migrationOutcomeDescriptionMap[migrationMapObject.sizeGuidance[size]]}` : ' No migration size advice given.'}\n`;
93
+ guidance += `${Object.keys(migrationOutcomeDescriptionMap).includes(migrationMapObject.sizeGuidance[size]) ? ` Please: ${migrationOutcomeDescriptionMap[migrationMapObject.sizeGuidance[size]]}` : ' No migration size advice given.'}\n`;
56
94
  } else {
57
95
  guidance = `Use ${newIcon.name} from ${newIcon.package}/${newIcon.type}/${newIcon.name} instead.\nMigration suggestions, depending on the legacy icon size:\n`;
58
96
  Object.entries(migrationMapObject.sizeGuidance).forEach(([size, value]) => {
59
97
  guidance += `\t- ${size}: `;
60
- if (!(value in migrationOutcomeDescriptionMap)) {
98
+ if (!Object.keys(migrationOutcomeDescriptionMap).includes(value)) {
61
99
  guidance += 'No migration advice given.\n';
62
100
  } else {
63
101
  guidance += `${migrationOutcomeDescriptionMap[value]}.\n`;
@@ -96,8 +134,11 @@ export const canMigrateColor = color => {
96
134
  }
97
135
  };
98
136
  export const locToString = node => {
99
- var _node$loc, _node$loc2, _node$loc3, _node$loc4;
100
- 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}`;
137
+ if (node.range && node.range.length >= 2) {
138
+ return `${node.range[0]}:${node.range[1]}`;
139
+ } else {
140
+ return '';
141
+ }
101
142
  };
102
143
  export const createCantMigrateReExportError = (node, packageName, exportName, errors) => {
103
144
  const myError = {
@@ -110,10 +151,10 @@ export const createCantMigrateReExportError = (node, packageName, exportName, er
110
151
  };
111
152
  pushManualError(locToString(node), errors, myError, packageName, exportName);
112
153
  };
113
- export const createCantMigrateIdentifierError = (node, packageName, exportName, errors) => {
154
+ export const createCantMigrateIdentifierMapOrArrayError = (node, packageName, exportName, errors) => {
114
155
  const myError = {
115
156
  node,
116
- messageId: 'cantMigrateIdentifier',
157
+ messageId: 'cantMigrateIdentifierMapOrArray',
117
158
  data: {
118
159
  packageName,
119
160
  exportName
@@ -121,6 +162,17 @@ export const createCantMigrateIdentifierError = (node, packageName, exportName,
121
162
  };
122
163
  pushManualError(locToString(node), errors, myError, packageName, exportName);
123
164
  };
165
+ export const createCantMigrateIdentifierError = (node, packageName, exportName, errors) => {
166
+ const myError = {
167
+ node,
168
+ messageId: 'cantMigrateIdentifier',
169
+ data: {
170
+ iconSource: packageName,
171
+ iconName: exportName
172
+ }
173
+ };
174
+ pushManualError(locToString(node), errors, myError, packageName, exportName);
175
+ };
124
176
  export const createCantFindSuitableReplacementError = (node, importSource, iconName, errors, sizeIssue) => {
125
177
  const myError = {
126
178
  node,
@@ -183,7 +235,7 @@ export const createAutoMigrationError = (node, importSource, iconName, errors) =
183
235
  errors[locToString(node)] = myError;
184
236
  };
185
237
  const pushManualError = (key, errors, myError, importSource, iconName) => {
186
- if (key in errors) {
238
+ if (Object.keys(errors).includes(key)) {
187
239
  errors[key].errors.push(myError);
188
240
  } else {
189
241
  errors[key] = {
@@ -231,7 +283,7 @@ export const createHelpers = context => {
231
283
  * @returns defaultValue if the configuration flag is not set, the defaultValue of the configuration flag otherwise
232
284
  */
233
285
  const getConfigFlag = (key, defaultValue) => {
234
- if (context.options.length > 0 && context.options[0] && key in context.options[0]) {
286
+ if (context.options.length > 0 && context.options[0] && Object.keys(context.options[0]).includes(key)) {
235
287
  return context.options[0][key] === !defaultValue ? !defaultValue : defaultValue;
236
288
  }
237
289
  return defaultValue;
@@ -250,4 +302,22 @@ export const createHelpers = context => {
250
302
  getTokenCallValue,
251
303
  getConfigFlag
252
304
  };
305
+ };
306
+ export const addToListOfRanges = (node, sortedListOfRangesForErrors) => {
307
+ if (node.range && node.range.length >= 2) {
308
+ sortedListOfRangesForErrors.push({
309
+ start: node.range[0],
310
+ end: node.range[1]
311
+ });
312
+ }
313
+ };
314
+ export const isInRangeList = (node, sortedListOfRangesForErrors) => {
315
+ const {
316
+ range
317
+ } = node;
318
+ if (!range || range.length < 2) {
319
+ return false;
320
+ }
321
+ const found = sortedListOfRangesForErrors.find(currRange => range[0] >= currRange.start && range[1] <= currRange.end);
322
+ return !!found;
253
323
  };
@@ -35,8 +35,8 @@ const rule = createLintRule({
35
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
36
  cantMigrateSizeUnknown: `This usage of Icon sets the size via a variable or function that can't be determined.`,
37
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.`
38
+ cantMigrateIdentifierMapOrArray: `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
+ cantMigrateIdentifier: `This is a legacy icon, {{iconName}} from {{iconSource}}, being referenced. Please manually migrate.`
40
40
  }
41
41
  },
42
42
  create(context) {
@@ -53,7 +53,8 @@ const rule = createLintRule({
53
53
  checkIconAsProp,
54
54
  checkJSXElement,
55
55
  checkCallExpression,
56
- throwErrors
56
+ throwErrors,
57
+ checkIconReference
57
58
  } = createChecks(context);
58
59
  return errorBoundary({
59
60
  // Track imports of relevant components
@@ -70,6 +71,7 @@ const rule = createLintRule({
70
71
  JSXElement: checkJSXElement,
71
72
  // Icons called as an argument of a function (i.e. icon={DefaultIcon(AddIcon)})
72
73
  CallExpression: checkCallExpression,
74
+ Identifier: checkIconReference,
73
75
  'Program:exit': throwErrors
74
76
  }, failSilently);
75
77
  }
@@ -0,0 +1 @@
1
+ export const upcomingIcons = ['app-switcher', 'check-circle-outline', 'export', 'file', 'flag-filled', 'lightbulb-filled', 'lock-filled', 'menu-expand', 'menu', 'notification-direct', 'notification', 'people-group', 'people', 'refresh', 'switcher', 'editor/align-image-center', 'editor/align-image-left', 'editor/align-image-right', 'editor/background-color', 'editor/bold', 'editor/indent', 'editor/italic', 'editor/horizontal-rule', 'editor-layout-three-equal', 'editor-layout-three-with-sidebars', 'editor/layout-two-equal', 'editor/layout-two-left-sidebars', 'editor/layout-two-right-sidebar', 'editor/media-center', 'editor/media-full-width', 'editor/media-wide', 'editor/number-list', 'emoji/activity', 'editor/file', 'emoji/flags', 'emoji/food', 'emoji/nature', 'emoji/people', 'emoji/productivity', 'emoji/travel', 'bitbucket/repos'];