@atlaskit/eslint-plugin-design-system 10.15.0 → 10.17.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 (31) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -0
  3. package/dist/cjs/presets/all.codegen.js +2 -1
  4. package/dist/cjs/rules/ensure-icon-color/index.js +57 -0
  5. package/dist/cjs/rules/index.codegen.js +3 -1
  6. package/dist/cjs/rules/no-legacy-icons/checks.js +272 -84
  7. package/dist/cjs/rules/no-legacy-icons/helpers.js +214 -14
  8. package/dist/cjs/rules/no-legacy-icons/index.js +4 -0
  9. package/dist/es2019/presets/all.codegen.js +2 -1
  10. package/dist/es2019/rules/ensure-icon-color/index.js +50 -0
  11. package/dist/es2019/rules/index.codegen.js +3 -1
  12. package/dist/es2019/rules/no-legacy-icons/checks.js +190 -24
  13. package/dist/es2019/rules/no-legacy-icons/helpers.js +220 -6
  14. package/dist/es2019/rules/no-legacy-icons/index.js +4 -0
  15. package/dist/esm/presets/all.codegen.js +2 -1
  16. package/dist/esm/rules/ensure-icon-color/index.js +52 -0
  17. package/dist/esm/rules/index.codegen.js +3 -1
  18. package/dist/esm/rules/no-legacy-icons/checks.js +273 -85
  19. package/dist/esm/rules/no-legacy-icons/helpers.js +214 -14
  20. package/dist/esm/rules/no-legacy-icons/index.js +4 -0
  21. package/dist/types/index.codegen.d.ts +1 -0
  22. package/dist/types/presets/all.codegen.d.ts +2 -1
  23. package/dist/types/rules/ensure-icon-color/index.d.ts +3 -0
  24. package/dist/types/rules/index.codegen.d.ts +1 -0
  25. package/dist/types/rules/no-legacy-icons/helpers.d.ts +88 -3
  26. package/dist/types-ts4.5/index.codegen.d.ts +1 -0
  27. package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -1
  28. package/dist/types-ts4.5/rules/ensure-icon-color/index.d.ts +3 -0
  29. package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -0
  30. package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +88 -3
  31. package/package.json +4 -4
@@ -5,7 +5,7 @@ var _typeof = require("@babel/runtime/helpers/typeof");
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.locToString = exports.isSize = exports.isInRangeList = exports.getUpcomingIcons = exports.getMigrationMapObject = exports.getLiteralStringValue = exports.createHelpers = exports.createGuidance = exports.createCantMigrateSpreadPropsError = exports.createCantMigrateSizeUnknown = exports.createCantMigrateReExportError = exports.createCantMigrateIdentifierMapOrArrayError = exports.createCantMigrateIdentifierError = exports.createCantMigrateFunctionUnknownError = exports.createCantMigrateColorError = exports.createCantFindSuitableReplacementError = exports.createAutoMigrationError = exports.canMigrateColor = exports.canAutoMigrateNewIconBasedOnSize = exports.addToListOfRanges = void 0;
8
+ exports.locToString = exports.isSize = exports.isInsideNewButton = exports.isInsideLegacyButton = exports.isInRangeList = exports.getUpcomingIcons = exports.getNewIconNameAndImportPath = exports.getMigrationMapObject = exports.getLiteralStringValue = exports.createPropFixes = exports.createImportFix = exports.createHelpers = exports.createGuidance = exports.createCantMigrateSpreadPropsError = exports.createCantMigrateSizeUnknown = exports.createCantMigrateReExportError = exports.createCantMigrateIdentifierMapOrArrayError = exports.createCantMigrateIdentifierError = exports.createCantMigrateFunctionUnknownError = exports.createCantMigrateColorError = exports.createCantFindSuitableReplacementError = exports.createAutoMigrationError = exports.checkIfNewIconExist = exports.canMigrateColor = exports.canAutoMigrateNewIconBasedOnSize = exports.addToListOfRanges = void 0;
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
10
  var _eslintCodemodUtils = require("eslint-codemod-utils");
11
11
  var _UNSAFE_migrationMap = _interopRequireWildcard(require("@atlaskit/icon/UNSAFE_migration-map"));
@@ -63,12 +63,33 @@ var canAutoMigrateNewIconBasedOnSize = exports.canAutoMigrateNewIconBasedOnSize
63
63
  return ['swap', 'swap-slight-visual-change', 'swap-visual-change', 'swap-size-shift-utility'].includes(guidance || '');
64
64
  };
65
65
 
66
+ /**
67
+ *
68
+ * @param iconPackage string
69
+ * @returns object of new icon name and import path
70
+ */
71
+ var getNewIconNameAndImportPath = exports.getNewIconNameAndImportPath = function getNewIconNameAndImportPath(iconPackage, shouldUseMigrationPath) {
72
+ var legacyIconName = getIconKey(iconPackage);
73
+ var migrationMapObject = getMigrationMapObject(iconPackage);
74
+ if (!migrationMapObject || !migrationMapObject.newIcon) {
75
+ return {};
76
+ }
77
+ var newIcon = migrationMapObject.newIcon;
78
+ var migrationPath = newIcon.name === legacyIconName ? "".concat(newIcon.package, "/").concat(newIcon.type, "/migration/").concat(newIcon.name) : "".concat(newIcon.package, "/").concat(newIcon.type, "/migration/").concat(newIcon.name, "--").concat(legacyIconName.replaceAll('/', '-'));
79
+ return {
80
+ iconName: newIcon.name,
81
+ importPath: shouldUseMigrationPath ? migrationPath : "".concat(newIcon.package, "/").concat(newIcon.type, "/").concat(newIcon.name)
82
+ };
83
+ };
84
+
66
85
  /**
67
86
  * Creates the written guidance for migrating a legacy icon to a new icon
68
87
  */
69
- var createGuidance = exports.createGuidance = function createGuidance(iconPackage) {
70
- var insideNewButton = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
71
- var size = arguments.length > 2 ? arguments[2] : undefined;
88
+ var createGuidance = exports.createGuidance = function createGuidance(_ref) {
89
+ var iconPackage = _ref.iconPackage,
90
+ insideNewButton = _ref.insideNewButton,
91
+ size = _ref.size,
92
+ shouldUseMigrationPath = _ref.shouldUseMigrationPath;
72
93
  var migrationMapObject = getMigrationMapObject(iconPackage);
73
94
  var upcomingIcon = getUpcomingIcons(iconPackage);
74
95
  if (upcomingIcon) {
@@ -100,21 +121,24 @@ var createGuidance = exports.createGuidance = function createGuidance(iconPackag
100
121
  if (!newIcon) {
101
122
  return 'No equivalent icon in new set. An option is to contribute a custom icon into icon-labs package instead.\n';
102
123
  }
124
+ var _getNewIconNameAndImp = getNewIconNameAndImportPath(iconPackage, shouldUseMigrationPath),
125
+ iconName = _getNewIconNameAndImp.iconName,
126
+ importPath = _getNewIconNameAndImp.importPath;
103
127
  var buttonGuidanceStr = "Please set 'spacing' property of the new icon to 'none', to ensure appropriate spacing inside `@atlaskit/button`.\n";
104
128
  var _guidance = '';
105
129
  if (size) {
106
130
  if (migrationMapObject.sizeGuidance[size] && canAutoMigrateNewIconBasedOnSize(migrationMapObject.sizeGuidance[size])) {
107
- _guidance += "Fix: Use ".concat(newIcon.name, " from ").concat(newIcon.package, "/").concat(newIcon.type, "/").concat(newIcon.name, " instead.");
131
+ _guidance += "Fix: Use ".concat(iconName, " from ").concat(importPath, " instead.");
108
132
  } else {
109
133
  _guidance += "No equivalent icon for this size, ".concat(size, ", in new set.");
110
134
  }
111
135
  _guidance += "".concat(Object.keys(_UNSAFE_migrationMap.migrationOutcomeDescriptionMap).includes(migrationMapObject.sizeGuidance[size]) ? " Please: ".concat(_UNSAFE_migrationMap.migrationOutcomeDescriptionMap[migrationMapObject.sizeGuidance[size]]) : ' No migration size advice given.', "\n");
112
136
  } else {
113
- _guidance = "Use ".concat(newIcon.name, " from ").concat(newIcon.package, "/").concat(newIcon.type, "/").concat(newIcon.name, " instead.\nMigration suggestions, depending on the legacy icon size:\n");
114
- Object.entries(migrationMapObject.sizeGuidance).forEach(function (_ref) {
115
- var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
116
- size = _ref2[0],
117
- value = _ref2[1];
137
+ _guidance = "Use ".concat(iconName, " from ").concat(importPath, " instead.\nMigration suggestions, depending on the legacy icon size:\n");
138
+ Object.entries(migrationMapObject.sizeGuidance).forEach(function (_ref2) {
139
+ var _ref3 = (0, _slicedToArray2.default)(_ref2, 2),
140
+ size = _ref3[0],
141
+ value = _ref3[1];
118
142
  _guidance += "\t- ".concat(size, ": ");
119
143
  if (!Object.keys(_UNSAFE_migrationMap.migrationOutcomeDescriptionMap).includes(value)) {
120
144
  _guidance += 'No migration advice given.\n';
@@ -244,13 +268,22 @@ var createCantMigrateSizeUnknown = exports.createCantMigrateSizeUnknown = functi
244
268
  };
245
269
  pushManualError(locToString(node), errors, myError, importSource, iconName);
246
270
  };
247
- var createAutoMigrationError = exports.createAutoMigrationError = function createAutoMigrationError(node, importSource, iconName, errors) {
271
+ var createAutoMigrationError = exports.createAutoMigrationError = function createAutoMigrationError(_ref4) {
272
+ var node = _ref4.node,
273
+ importSource = _ref4.importSource,
274
+ iconName = _ref4.iconName,
275
+ errors = _ref4.errors,
276
+ shouldAddSpaciousSpacing = _ref4.shouldAddSpaciousSpacing,
277
+ insideNewButton = _ref4.insideNewButton;
248
278
  var myError = {
249
279
  node: node,
250
280
  messageId: 'noLegacyIconsAutoMigration',
251
281
  data: {
252
282
  importSource: importSource,
253
- iconName: iconName
283
+ iconName: iconName,
284
+ spacing: shouldAddSpaciousSpacing ? 'spacious' : '',
285
+ // value type need to be a string in Rule.ReportDescriptor
286
+ insideNewButton: String(insideNewButton)
254
287
  }
255
288
  };
256
289
  errors[locToString(node)] = myError;
@@ -314,9 +347,9 @@ var createHelpers = exports.createHelpers = function createHelpers(context) {
314
347
  * Extracts the primaryColor value from a JSXAttribute
315
348
  */
316
349
  getPrimaryColor: function getPrimaryColor(attr) {
317
- var _ref3, _getLiteralStringValu;
350
+ var _ref5, _getLiteralStringValu;
318
351
  var value = attr.value;
319
- return (_ref3 = (_getLiteralStringValu = getLiteralStringValue(value)) !== null && _getLiteralStringValu !== void 0 ? _getLiteralStringValu : getTokenCallValue(value)) !== null && _ref3 !== void 0 ? _ref3 : null;
352
+ return (_ref5 = (_getLiteralStringValu = getLiteralStringValue(value)) !== null && _getLiteralStringValu !== void 0 ? _getLiteralStringValu : getTokenCallValue(value)) !== null && _ref5 !== void 0 ? _ref5 : null;
320
353
  },
321
354
  getTokenCallValue: getTokenCallValue,
322
355
  getConfigFlag: getConfigFlag
@@ -339,4 +372,171 @@ var isInRangeList = exports.isInRangeList = function isInRangeList(node, sortedL
339
372
  return range[0] >= currRange.start && range[1] <= currRange.end;
340
373
  });
341
374
  return !!found;
375
+ };
376
+
377
+ /**
378
+ *
379
+ * @param node Icon JSXelement
380
+ * @param newButtonImports list of new button import specifiers
381
+ * @returns if Icon is inside a new button
382
+ */
383
+ var isInsideNewButton = exports.isInsideNewButton = function isInsideNewButton(node, newButtonImports) {
384
+ var _node$parent, _node$parent2;
385
+ var insideNewButton = false;
386
+ if (node.parent && (0, _eslintCodemodUtils.isNodeOfType)(node.parent, 'ArrowFunctionExpression') && (_node$parent = node.parent) !== null && _node$parent !== void 0 && (_node$parent = _node$parent.parent) !== null && _node$parent !== void 0 && _node$parent.parent && (0, _eslintCodemodUtils.isNodeOfType)(node.parent.parent.parent, 'JSXAttribute') && (0, _eslintCodemodUtils.isNodeOfType)(node.parent.parent.parent.name, 'JSXIdentifier') && (_node$parent2 = node.parent) !== null && _node$parent2 !== void 0 && (_node$parent2 = _node$parent2.parent) !== null && _node$parent2 !== void 0 && (_node$parent2 = _node$parent2.parent) !== null && _node$parent2 !== void 0 && _node$parent2.parent && (0, _eslintCodemodUtils.isNodeOfType)(node.parent.parent.parent.parent, 'JSXOpeningElement') && (0, _eslintCodemodUtils.isNodeOfType)(node.parent.parent.parent.parent.name, 'JSXIdentifier') && newButtonImports.has(node.parent.parent.parent.parent.name.name)) {
387
+ insideNewButton = true;
388
+ }
389
+ return insideNewButton;
390
+ };
391
+
392
+ /**
393
+ *
394
+ * @param node Icon JSXelement
395
+ * @param newButtonImports list of legacy button import specifiers
396
+ * @returns if Icon is inside a legacy button
397
+ */
398
+ var isInsideLegacyButton = exports.isInsideLegacyButton = function isInsideLegacyButton(node, legacyButtonImports) {
399
+ var _node$parent3, _node$parent4, _node$parent5, _node$parent6;
400
+ var insideLegacyButton = false;
401
+ if (node.parent && (0, _eslintCodemodUtils.isNodeOfType)(node.parent, 'JSXExpressionContainer') && (_node$parent3 = node.parent) !== null && _node$parent3 !== void 0 && _node$parent3.parent && (0, _eslintCodemodUtils.isNodeOfType)(node.parent.parent, 'JSXAttribute') && (node.parent.parent.name.name === 'iconBefore' || node.parent.parent.name.name === 'iconAfter') && (0, _eslintCodemodUtils.isNodeOfType)((_node$parent4 = node.parent) === null || _node$parent4 === void 0 || (_node$parent4 = _node$parent4.parent) === null || _node$parent4 === void 0 ? void 0 : _node$parent4.parent, 'JSXOpeningElement') && (0, _eslintCodemodUtils.isNodeOfType)((_node$parent5 = node.parent) === null || _node$parent5 === void 0 || (_node$parent5 = _node$parent5.parent) === null || _node$parent5 === void 0 ? void 0 : _node$parent5.parent.name, 'JSXIdentifier') && legacyButtonImports.has((_node$parent6 = node.parent) === null || _node$parent6 === void 0 || (_node$parent6 = _node$parent6.parent) === null || _node$parent6 === void 0 ? void 0 : _node$parent6.parent.name.name)) {
402
+ insideLegacyButton = true;
403
+ }
404
+ return insideLegacyButton;
405
+ };
406
+ var findProp = function findProp(attributes, propName) {
407
+ return attributes.find(function (attr) {
408
+ return attr.type === 'JSXAttribute' && attr.name.name === propName;
409
+ });
410
+ };
411
+
412
+ /**
413
+ *
414
+ * Creates a list of fixers to update the icon import path
415
+ * @param metadata Metadata including the import source and spacing
416
+ * @param fixer The original fix function
417
+ * @param legacyImportNode The import declaration node to replace
418
+ * @param shouldUseMigrationPath The eslint rule config, whether to use migration entrypoint or not
419
+ * @param migrationImportNode The migration import declaration node to replace, only present if shouldUseMigrationPath is false
420
+ * @returns A list of fixers to migrate the icon
421
+ */
422
+ var createImportFix = exports.createImportFix = function createImportFix(_ref6) {
423
+ var fixer = _ref6.fixer,
424
+ legacyImportNode = _ref6.legacyImportNode,
425
+ metadata = _ref6.metadata,
426
+ shouldUseMigrationPath = _ref6.shouldUseMigrationPath,
427
+ migrationImportNode = _ref6.migrationImportNode;
428
+ var fixes = [];
429
+ var importSource = metadata.importSource;
430
+ var importPath = migrationImportNode ? importSource.replace('/migration', '').split('--')[0] : getNewIconNameAndImportPath(importSource, shouldUseMigrationPath).importPath;
431
+
432
+ // replace old icon import with icon import
433
+ if (legacyImportNode && importPath) {
434
+ fixes.push(fixer.replaceText(legacyImportNode.source, "'".concat((0, _eslintCodemodUtils.literal)(importPath), "'")));
435
+ }
436
+ if (migrationImportNode && !shouldUseMigrationPath && importPath) {
437
+ fixes.push(fixer.replaceText(migrationImportNode.source, "'".concat((0, _eslintCodemodUtils.literal)(importPath), "'")));
438
+ }
439
+ return fixes;
440
+ };
441
+
442
+ /**
443
+ * Creates a list of fixers to update the icon props
444
+ * @param node The Icon element to migrate
445
+ * @param metadata Metadata including the import source and spacing
446
+ * @param fixer The original fix function
447
+ * @param legacyImportNode The import declaration node to replace
448
+ * @param shouldUseMigrationPath The eslint rule config, whether to use migration entrypoint or not
449
+ * @param migrationImportNode The migration import declaration node to replace, only present if shouldUseMigrationPath is false
450
+ * @returns A list of fixers to migrate the icon
451
+ */
452
+ var createPropFixes = exports.createPropFixes = function createPropFixes(_ref7) {
453
+ var node = _ref7.node,
454
+ fixer = _ref7.fixer,
455
+ legacyImportNode = _ref7.legacyImportNode,
456
+ metadata = _ref7.metadata,
457
+ shouldUseMigrationPath = _ref7.shouldUseMigrationPath,
458
+ migrationImportNode = _ref7.migrationImportNode;
459
+ var fixes = [];
460
+ var importSource = metadata.importSource,
461
+ spacing = metadata.spacing,
462
+ insideNewButton = metadata.insideNewButton;
463
+ if (shouldUseMigrationPath && !legacyImportNode) {
464
+ return fixes;
465
+ }
466
+ var importPath = migrationImportNode ? importSource.replace('/migration', '').split('--')[0] : getNewIconNameAndImportPath(importSource, shouldUseMigrationPath).importPath;
467
+ var iconType = importPath !== null && importPath !== void 0 && importPath.startsWith('@atlaskit/icon/core') ? 'core' : 'utility';
468
+ if (node.type === 'JSXElement') {
469
+ var openingElement = node.openingElement;
470
+ var attributes = openingElement.attributes;
471
+
472
+ // replace primaryColor prop with color
473
+ var primaryColor = findProp(attributes, 'primaryColor');
474
+ if (primaryColor && primaryColor.type === 'JSXAttribute') {
475
+ fixes.push(fixer.replaceText(primaryColor.name, 'color'));
476
+ }
477
+
478
+ // add color="currentColor" if
479
+ // 1. primaryColor prop is not set
480
+ // 2. icon is not imported from migration entrypoint
481
+ // 3. icon element is not inside a new button
482
+ if (legacyImportNode && !primaryColor && !migrationImportNode &&
483
+ // value type need to be a string in Rule.ReportDescriptor
484
+ insideNewButton !== 'true') {
485
+ fixes.push(fixer.insertTextAfter(openingElement.name, " color=\"currentColor\""));
486
+ }
487
+
488
+ // rename or remove size prop based on shouldUseMigrationPath,
489
+ // add spacing="spacious" if
490
+ // 1. it's in error metadata, which means size is medium
491
+ // 2. no existing spacing prop
492
+ // 3. iconType is "core"
493
+ // 4. icon is not imported from migration entrypoint
494
+ var sizeProp = findProp(attributes, 'size');
495
+ var spacingProp = findProp(attributes, 'spacing');
496
+ if (spacing && !spacingProp && iconType === 'core' && !migrationImportNode) {
497
+ fixes.push(fixer.insertTextAfter(sizeProp || openingElement.name, " spacing=\"".concat(spacing, "\"")));
498
+ }
499
+ if (sizeProp && sizeProp.type === 'JSXAttribute') {
500
+ fixes.push(shouldUseMigrationPath ?
501
+ // replace size prop with LEGACY_size,
502
+ fixer.replaceText(sizeProp.name, 'LEGACY_size') :
503
+ // remove size prop if shouldUseMigrationPath is false
504
+ fixer.remove(sizeProp));
505
+ }
506
+
507
+ // rename or remove secondaryColor prop based on shouldUseMigrationPath
508
+ var secondaryColorProp = findProp(attributes, 'secondaryColor');
509
+ if (secondaryColorProp && secondaryColorProp.type === 'JSXAttribute') {
510
+ fixes.push(shouldUseMigrationPath ?
511
+ // replace secondaryColor prop with LEGACY_secondaryColor
512
+ fixer.replaceText(secondaryColorProp.name, 'LEGACY_secondaryColor') :
513
+ // remove secondaryColor prop if shouldUseMigrationPath is false
514
+ fixer.remove(secondaryColorProp));
515
+ }
516
+
517
+ // remove LEGACY props
518
+ if (!shouldUseMigrationPath) {
519
+ ['LEGACY_size', 'LEGACY_margin', 'LEGACY_fallbackIcon', 'LEGACY_secondaryColor'].forEach(function (propName) {
520
+ var legacyProp = findProp(attributes, propName);
521
+ if (legacyProp && legacyProp.type === 'JSXAttribute') {
522
+ fixes.push(fixer.remove(legacyProp));
523
+ }
524
+ });
525
+ }
526
+ }
527
+ return fixes;
528
+ };
529
+
530
+ /**
531
+ * Check if the new icon exists in the migration map
532
+ */
533
+ var checkIfNewIconExist = exports.checkIfNewIconExist = function checkIfNewIconExist(error) {
534
+ var _error$data;
535
+ if (!((_error$data = error.data) !== null && _error$data !== void 0 && _error$data.importSource)) {
536
+ return false;
537
+ }
538
+ var iconKey = getIconKey(error.data.importSource);
539
+ var _ref8 = _UNSAFE_migrationMap.default[iconKey] || {},
540
+ newIcon = _ref8.newIcon;
541
+ return Boolean(newIcon);
342
542
  };
@@ -11,6 +11,7 @@ var _helpers = require("./helpers");
11
11
  var rule = (0, _createRule.createLintRule)({
12
12
  meta: {
13
13
  name: 'no-legacy-icons',
14
+ fixable: 'code',
14
15
  type: 'problem',
15
16
  docs: {
16
17
  description: 'Enforces no legacy icons are used.',
@@ -28,6 +29,9 @@ var rule = (0, _createRule.createLintRule)({
28
29
  },
29
30
  quiet: {
30
31
  type: 'boolean'
32
+ },
33
+ shouldUseMigrationPath: {
34
+ type: 'boolean'
31
35
  }
32
36
  },
33
37
  additionalProperties: false
@@ -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::b6947ac630ea512fe3f4e3f44abb6783>>
3
+ * @codegen <<SignedSource::16613cb3962ed68af0bffd70eef5f5e2>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  export default {
@@ -9,6 +9,7 @@ export default {
9
9
  '@atlaskit/design-system/consistent-css-prop-usage': 'error',
10
10
  '@atlaskit/design-system/ensure-design-token-usage': 'error',
11
11
  '@atlaskit/design-system/ensure-design-token-usage/preview': 'warn',
12
+ '@atlaskit/design-system/ensure-icon-color': 'error',
12
13
  '@atlaskit/design-system/icon-label': 'warn',
13
14
  '@atlaskit/design-system/no-banned-imports': 'error',
14
15
  '@atlaskit/design-system/no-css-tagged-template-expression': 'error',
@@ -0,0 +1,50 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+
3
+ import { isNodeOfType } from 'eslint-codemod-utils';
4
+ import { createIsFromImportSourceFor } from '../no-custom-icons/checks/is-from-import-source';
5
+ import { createLintRule } from '../utils/create-rule';
6
+ import { errorBoundary } from '../utils/error-boundary';
7
+
8
+ /**
9
+ * Returns if the node is a JSXElement with a prop that matches the given name.
10
+ */
11
+ function hasProp(node, propName) {
12
+ return isNodeOfType(node.openingElement, 'JSXOpeningElement') && node.openingElement.attributes.some(a => a.type === 'JSXAttribute' && a.name.name === propName);
13
+ }
14
+ const rule = createLintRule({
15
+ meta: {
16
+ name: 'ensure-icon-color',
17
+ docs: {
18
+ description: 'Enforces that upcoming icon components have a color prop set, to enable a migration of the default value.',
19
+ recommended: false,
20
+ severity: 'error'
21
+ },
22
+ messages: {
23
+ missingColorProp: 'The default value of the `color` prop is about to change. To assist in the migration, the color prop must be set on new icons from `@atlaskit/icon/(core|utility)`.'
24
+ }
25
+ },
26
+ create(context) {
27
+ /**
28
+ * Contains a map of imported icon components from any atlaskit icon package.
29
+ */
30
+ const isNewIcon = createIsFromImportSourceFor(/^@(atlaskit\/icon|atlassian\/icon-lab)\/(core|utility)\/*/);
31
+ return errorBoundary({
32
+ JSXElement(node) {
33
+ var _isNewIcon$getImportS;
34
+ if (!isNewIcon(node) || hasProp(node, 'color')) {
35
+ return;
36
+ }
37
+ const importSource = (_isNewIcon$getImportS = isNewIcon.getImportSource(node)) !== null && _isNewIcon$getImportS !== void 0 ? _isNewIcon$getImportS : '';
38
+ context.report({
39
+ node: node.openingElement,
40
+ messageId: 'missingColorProp',
41
+ data: {
42
+ importSource
43
+ }
44
+ });
45
+ },
46
+ ImportDeclaration: isNewIcon.importDeclarationHook
47
+ });
48
+ }
49
+ });
50
+ export default rule;
@@ -1,11 +1,12 @@
1
1
  /**
2
2
  * THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
3
- * @codegen <<SignedSource::402e6eb5433560b1032e5ed926bb5564>>
3
+ * @codegen <<SignedSource::c2a140a3f690737dd938e746ef8fb9d5>>
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
+ import ensureIconColor from './ensure-icon-color';
9
10
  import iconLabel from './icon-label';
10
11
  import noBannedImports from './no-banned-imports';
11
12
  import noCssTaggedTemplateExpression from './no-css-tagged-template-expression';
@@ -48,6 +49,7 @@ export default {
48
49
  'consistent-css-prop-usage': consistentCssPropUsage,
49
50
  'ensure-design-token-usage': ensureDesignTokenUsage,
50
51
  'ensure-design-token-usage/preview': ensureDesignTokenUsagePreview,
52
+ 'ensure-icon-color': ensureIconColor,
51
53
  'icon-label': iconLabel,
52
54
  'no-banned-imports': noBannedImports,
53
55
  'no-css-tagged-template-expression': noCssTaggedTemplateExpression,