@atlaskit/eslint-plugin-design-system 4.9.0 → 4.11.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @atlaskit/eslint-plugin-design-system
2
2
 
3
+ ## 4.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`268f92124e2`](https://bitbucket.org/atlassian/atlassian-frontend/commits/268f92124e2) - Bolster isException logic to support descendants of excepted functions and to be case-agnostic
8
+
9
+ ## 4.10.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [`d76851b2f42`](https://bitbucket.org/atlassian/atlassian-frontend/commits/d76851b2f42) - Improved NaN handling and output
14
+ - [`0544fe823d1`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0544fe823d1) - Updates to account for nested unary selectors.
15
+ - [`1ed3db0c9be`](https://bitbucket.org/atlassian/atlassian-frontend/commits/1ed3db0c9be) - Improvements to lint rule and accounting for edge cases
16
+
17
+ ## 4.10.0
18
+
19
+ ### Minor Changes
20
+
21
+ - [`bb808f9a186`](https://bitbucket.org/atlassian/atlassian-frontend/commits/bb808f9a186) - Add exceptions option to ensure-design-token-usage rule
22
+
3
23
  ## 4.9.0
4
24
 
5
25
  ### Minor Changes
@@ -7,6 +7,8 @@ exports.default = void 0;
7
7
 
8
8
  var _eslintCodemodUtils = require("eslint-codemod-utils");
9
9
 
10
+ var _getIsException = require("../utils/get-is-exception");
11
+
10
12
  var _isColor = require("../utils/is-color");
11
13
 
12
14
  var _isElevation = require("../utils/is-elevation");
@@ -58,13 +60,14 @@ var rule = {
58
60
  },
59
61
  create: function create(context) {
60
62
  var config = context.options[0] || defaultConfig;
63
+ var isException = (0, _getIsException.getIsException)(config.exceptions);
61
64
  return {
62
65
  'TemplateLiteral > Identifier': function TemplateLiteralIdentifier(node) {
63
66
  if (!(0, _isNode.isDecendantOfStyleBlock)(node)) {
64
67
  return;
65
68
  }
66
69
 
67
- if (node.type === 'Identifier' && (0, _isColor.isLegacyNamedColor)(node.name)) {
70
+ if (node.type === 'Identifier' && (0, _isColor.isLegacyNamedColor)(node.name) && !isException(node)) {
68
71
  context.report({
69
72
  messageId: 'hardCodedColor',
70
73
  node: node,
@@ -74,22 +77,24 @@ var rule = {
74
77
  }
75
78
  },
76
79
  Identifier: function Identifier(node) {
77
- if ((0, _isNode.isDecendantOfGlobalToken)(node) || (0, _isNode.isDecendantOfType)(node, 'ImportDeclaration') || (0, _isNode.isPropertyKey)(node) || (0, _isNode.isVariableName)(node)) {
80
+ if (isException(node) || (0, _isNode.isDecendantOfGlobalToken)(node) || (0, _isNode.isDecendantOfType)(node, 'ImportDeclaration') || (0, _isNode.isPropertyKey)(node) || (0, _isNode.isVariableName)(node)) {
78
81
  return;
79
82
  }
80
83
 
81
- var isNodeHardCodedColor = (0, _isColor.isHardCodedColor)(node.name);
82
-
83
- if ((0, _isColor.isLegacyColor)(node.name) || isNodeHardCodedColor) {
84
- if (node.parent.type === 'MemberExpression' && node.parent.object.type === 'Identifier') {
85
- // Object members as named colors, like obj.ivory, should be valid,
86
- // and hexes and color functions cannot be property names anyway.
87
- if (!isNodeHardCodedColor) {
88
- context.report({
89
- messageId: 'hardCodedColor',
90
- node: node,
91
- suggest: getTokenSuggestion(node.parent, "".concat(node.parent.object.name, ".").concat(node.name), config)
92
- });
84
+ var isNodeLegacyColor = (0, _isColor.isLegacyColor)(node.name);
85
+
86
+ if (isNodeLegacyColor || (0, _isColor.isHardCodedColor)(node.name)) {
87
+ if (node.parent.type === 'MemberExpression') {
88
+ if (node.parent.object.type === 'Identifier') {
89
+ // Object members as named colors, like obj.ivory, should be valid,
90
+ // and hexes and color functions cannot be property names anyway.
91
+ if (isNodeLegacyColor) {
92
+ context.report({
93
+ messageId: 'hardCodedColor',
94
+ node: node,
95
+ suggest: getTokenSuggestion(node.parent, "".concat(node.parent.object.name, ".").concat(node.name), config)
96
+ });
97
+ }
93
98
  }
94
99
 
95
100
  return;
@@ -150,11 +155,7 @@ var rule = {
150
155
  });
151
156
  },
152
157
  'ObjectExpression > Property > Literal': function ObjectExpressionPropertyLiteral(node) {
153
- if (node.type !== 'Literal') {
154
- return;
155
- }
156
-
157
- if (typeof node.value !== 'string') {
158
+ if (node.type !== 'Literal' || typeof node.value !== 'string') {
158
159
  return;
159
160
  }
160
161
 
@@ -162,7 +163,7 @@ var rule = {
162
163
  return;
163
164
  }
164
165
 
165
- if ((0, _isColor.isHardCodedColor)(node.value) || (0, _isColor.includesHardCodedColor)(node.value)) {
166
+ if (((0, _isColor.isHardCodedColor)(node.value) || (0, _isColor.includesHardCodedColor)(node.value)) && !isException(node)) {
166
167
  context.report({
167
168
  messageId: 'hardCodedColor',
168
169
  node: node,
@@ -180,7 +181,7 @@ var rule = {
180
181
  return;
181
182
  }
182
183
 
183
- if (!(0, _isColor.isLegacyNamedColor)(node.callee.name) || (0, _isNode.isDecendantOfGlobalToken)(node)) {
184
+ if (!(0, _isColor.isLegacyNamedColor)(node.callee.name) || (0, _isNode.isDecendantOfGlobalToken)(node) || isException(node)) {
184
185
  return;
185
186
  }
186
187
 
@@ -199,13 +200,21 @@ var rule = {
199
200
  return;
200
201
  }
201
202
 
202
- if (node.value.type === 'Literal' && ((0, _isColor.isHardCodedColor)(node.value.value) || (0, _isColor.includesHardCodedColor)(node.value.value))) {
203
- context.report({
204
- messageId: 'hardCodedColor',
205
- node: node,
206
- suggest: getTokenSuggestion(node.value, node.value.value, config)
207
- });
208
- return;
203
+ if (node.value.type === 'Literal') {
204
+ if (isException(node)) {
205
+ return;
206
+ }
207
+
208
+ var literalValue = node.value.value;
209
+
210
+ if ((0, _isColor.isHardCodedColor)(literalValue) || (0, _isColor.includesHardCodedColor)(literalValue)) {
211
+ context.report({
212
+ messageId: 'hardCodedColor',
213
+ node: node,
214
+ suggest: getTokenSuggestion(node.value, literalValue, config)
215
+ });
216
+ return;
217
+ }
209
218
  }
210
219
  }
211
220
  };
@@ -13,6 +13,12 @@ var _eslintCodemodUtils = require("eslint-codemod-utils");
13
13
 
14
14
  var _utils = require("./utils");
15
15
 
16
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
17
+
18
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
19
+
20
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
21
+
16
22
  var rule = {
17
23
  meta: {
18
24
  type: 'problem',
@@ -33,7 +39,7 @@ var rule = {
33
39
  return;
34
40
  }
35
41
  /**
36
- * We do this in case we the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration
42
+ * We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration
37
43
  */
38
44
 
39
45
 
@@ -64,26 +70,36 @@ var rule = {
64
70
  return;
65
71
  }
66
72
 
73
+ if (node.value.type === 'Literal' && !(0, _utils.isValidSpacingValue)(node.value.value, fontSize)) {
74
+ context.report({
75
+ node: node,
76
+ messageId: 'noRawSpacingValues',
77
+ data: {
78
+ payload: "NaN:".concat(node.value.value)
79
+ }
80
+ });
81
+ return;
82
+ }
83
+
67
84
  var value = (0, _utils.getValue)(node.value, context);
68
85
 
69
- if (value) {
86
+ if (value && (0, _utils.isValidSpacingValue)(value, fontSize)) {
70
87
  var values = typeof value === 'number' || typeof value === 'string' ? [value] : value;
71
- values.forEach(function (value) {
88
+ values.forEach(function (val) {
72
89
  context.report({
73
90
  node: node,
74
91
  messageId: 'noRawSpacingValues',
75
92
  data: {
76
- payload: "".concat(node.key.name, ":").concat((0, _utils.emToPixels)(value, fontSize))
93
+ payload: "".concat(node.key.name, ":").concat((0, _utils.emToPixels)(val, fontSize))
77
94
  }
78
95
  });
79
96
  });
80
- return;
81
97
  } else {
82
98
  context.report({
83
99
  node: node,
84
100
  messageId: 'noRawSpacingValues',
85
101
  data: {
86
- payload: "".concat(node.key.name, ":NaN")
102
+ payload: "NaN:".concat(value)
87
103
  }
88
104
  });
89
105
  }
@@ -106,7 +122,9 @@ var rule = {
106
122
  * Adapted from ensure-design-token-usage
107
123
  */
108
124
 
109
- var cssProperties = combinedString.replace(/\n/g, '').split(/;|{|}/).map(function (el) {
125
+ var cssProperties = combinedString.split('\n').filter(function (line) {
126
+ return !line.trim().startsWith('@');
127
+ }).join('\n').replace(/\n/g, '').split(/;|{|}/).map(function (el) {
110
128
  return el.trim() || '';
111
129
  });
112
130
  cssProperties.map(function (style) {
@@ -115,14 +133,41 @@ var rule = {
115
133
  property = _style$split2[0],
116
134
  value = _style$split2[1];
117
135
 
136
+ property = (0, _utils.convertHyphenatedNameToCamelCase)(property);
137
+
118
138
  if ((0, _utils.isSpacingProperty)(property)) {
119
- context.report({
120
- node: node,
121
- messageId: 'noRawSpacingValues',
122
- data: {
123
- payload: "".concat(property, ":").concat((0, _utils.removePixelSuffix)(value.trim()))
139
+ if ((0, _utils.isValidSpacingValue)(value)) {
140
+ var values = (0, _utils.getValueFromShorthand)(value);
141
+
142
+ var _iterator = _createForOfIteratorHelper(values),
143
+ _step;
144
+
145
+ try {
146
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
147
+ var val = _step.value;
148
+ // could be array of values e.g. padding: 8px 12px 3px
149
+ context.report({
150
+ node: node,
151
+ messageId: 'noRawSpacingValues',
152
+ data: {
153
+ payload: "".concat(property, ":").concat(val)
154
+ }
155
+ });
156
+ }
157
+ } catch (err) {
158
+ _iterator.e(err);
159
+ } finally {
160
+ _iterator.f();
124
161
  }
125
- });
162
+ } else {
163
+ context.report({
164
+ node: node,
165
+ messageId: 'noRawSpacingValues',
166
+ data: {
167
+ payload: "NaN:".concat(value)
168
+ }
169
+ });
170
+ }
126
171
  }
127
172
 
128
173
  return;
@@ -3,13 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.emToPixels = void 0;
6
+ exports.emToPixels = exports.convertHyphenatedNameToCamelCase = void 0;
7
7
  exports.findIdentifierInParentScope = findIdentifierInParentScope;
8
- exports.removePixelSuffix = exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = void 0;
8
+ exports.removePixelSuffix = exports.isValidSpacingValue = exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = void 0;
9
9
 
10
10
  var _eslintCodemodUtils = require("eslint-codemod-utils");
11
11
 
12
- var properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height'];
12
+ var properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height', 'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
13
13
 
14
14
  function findIdentifierInParentScope(_ref) {
15
15
  var scope = _ref.scope,
@@ -123,6 +123,10 @@ var getValueFromIdentifier = function getValueFromIdentifier(node, context) {
123
123
 
124
124
  var definition = variable.defs[0];
125
125
 
126
+ if ((0, _eslintCodemodUtils.isNodeOfType)(definition.node, 'ImportSpecifier') && (0, _eslintCodemodUtils.isNodeOfType)(definition.node.parent, 'ImportDeclaration') && definition.node.parent.source.value === '@atlassian/jira-common-legacy-do-not-add-anything-new/src/styles') {
127
+ return definition.node.imported.name === 'gridSize' ? 8 : null;
128
+ }
129
+
126
130
  if (!(0, _eslintCodemodUtils.isNodeOfType)(definition.node, 'VariableDeclarator')) {
127
131
  return null;
128
132
  }
@@ -146,7 +150,7 @@ var getValueFromUnaryExpression = function getValueFromUnaryExpression(node, con
146
150
  } // eslint-disable-next-line no-eval
147
151
 
148
152
 
149
- return eval("".concat(node.operator).concat(value));
153
+ return eval("".concat(node.operator, "(").concat(value, ")"));
150
154
  };
151
155
  /**
152
156
  * @example
@@ -198,9 +202,9 @@ var emToPixels = function emToPixels(value, fontSize) {
198
202
 
199
203
  if (match && typeof fontSize === 'number') {
200
204
  return Number(match[1]) * fontSize;
205
+ } else {
206
+ return null;
201
207
  }
202
-
203
- return 'NaN';
204
208
  }
205
209
 
206
210
  return value;
@@ -220,4 +224,37 @@ var removePixelSuffix = function removePixelSuffix(value) {
220
224
  return Number(isString ? value.replace('px', '') : value);
221
225
  };
222
226
 
223
- exports.removePixelSuffix = removePixelSuffix;
227
+ exports.removePixelSuffix = removePixelSuffix;
228
+ var invalidSpacingUnitRegex = /(%$)|(\d+rem$)|(^calc)|(vw$)|(vh$)/;
229
+
230
+ var isValidSpacingValue = function isValidSpacingValue(value, fontSize) {
231
+ if (typeof value === 'string') {
232
+ if (invalidSpacingUnitRegex.test(value)) {
233
+ return false;
234
+ }
235
+ } else if (Array.isArray(value)) {
236
+ // could be array due to shorthand
237
+ for (var val in value) {
238
+ if (invalidSpacingUnitRegex.test(val)) {
239
+ return false;
240
+ }
241
+ }
242
+ }
243
+
244
+ if (emRegex.test(value) && typeof fontSize !== 'number') {
245
+ return false;
246
+ }
247
+
248
+ return true;
249
+ }; // convert line-height to lineHeight
250
+
251
+
252
+ exports.isValidSpacingValue = isValidSpacingValue;
253
+
254
+ var convertHyphenatedNameToCamelCase = function convertHyphenatedNameToCamelCase(prop) {
255
+ return prop.replace(/-./g, function (m) {
256
+ return m[1].toUpperCase();
257
+ });
258
+ };
259
+
260
+ exports.convertHyphenatedNameToCamelCase = convertHyphenatedNameToCamelCase;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getIsException = void 0;
7
+
8
+ var getNodeValue = function getNodeValue(node) {
9
+ var _node$value;
10
+
11
+ switch (node.type) {
12
+ case 'Identifier':
13
+ return node.name;
14
+
15
+ case 'Literal':
16
+ return typeof node.value === 'string' ? node.value : null;
17
+
18
+ case 'CallExpression':
19
+ return node.callee.type === 'Identifier' ? node.callee.name : null;
20
+ // @ts-expect-error
21
+
22
+ case 'JSXAttribute':
23
+ // @ts-expect-error
24
+ return ((_node$value = node.value) === null || _node$value === void 0 ? void 0 : _node$value.type) === 'Literal' ? node.value.value : null;
25
+
26
+ default:
27
+ return null;
28
+ }
29
+ };
30
+
31
+ var getIsException = function getIsException(exceptions) {
32
+ if (!(exceptions !== null && exceptions !== void 0 && exceptions.length)) {
33
+ return function () {
34
+ return false;
35
+ };
36
+ }
37
+
38
+ var exceptionsSet = new Set(exceptions.map(function (x) {
39
+ return x.toLowerCase();
40
+ }));
41
+
42
+ var isException = function isException(node) {
43
+ var value = getNodeValue(node);
44
+
45
+ if (value) {
46
+ var splitValues = value.split(/[-_\s]+/);
47
+
48
+ if (splitValues.some(function (v) {
49
+ return exceptionsSet.has(v.toLowerCase());
50
+ })) {
51
+ return true;
52
+ }
53
+ }
54
+
55
+ if (node.parent) {
56
+ return isException(node.parent);
57
+ }
58
+
59
+ return false;
60
+ };
61
+
62
+ return isException;
63
+ };
64
+
65
+ exports.getIsException = getIsException;
@@ -4,29 +4,26 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.isLegacyNamedColor = exports.isLegacyColor = exports.isHardCodedColor = exports.includesHardCodedColor = void 0;
7
- var namedColors = ['black', 'silver', 'gray', 'white', 'maroon', 'red', 'purple', 'fuchsia', 'green', 'lime', 'olive', 'yellow', 'navy', 'blue', 'teal', 'aqua', 'orange', 'aliceblue', 'antiquewhite', 'aquamarine', 'azure', 'beige', 'bisque', 'blanchedalmond', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'limegreen', 'linen', 'magenta', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'oldlace', 'olivedrab', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'whitesmoke', 'yellowgreen', 'rebeccapurple'];
8
- var legacyColors = ['R50', 'R75', 'R100', 'R200', 'R300', 'R400', 'R500', 'Y50', 'Y75', 'Y100', 'Y200', 'Y300', 'Y400', 'Y500', 'G50', 'G75', 'G100', 'G200', 'G300', 'G400', 'G500', 'B50', 'B75', 'B100', 'B200', 'B300', 'B400', 'B500', 'P50', 'P75', 'P100', 'P200', 'P300', 'P400', 'P500', 'T50', 'T75', 'T100', 'T200', 'T300', 'T400', 'T500', 'N0', 'N10', 'N20', 'N30', 'N40', 'N50', 'N60', 'N70', 'N80', 'N90', 'N100', 'N200', 'N300', 'N400', 'N500', 'N600', 'N700', 'N800', 'N900', 'N10A', 'N20A', 'N30A', 'N40A', 'N50A', 'N60A', 'N70A', 'N80A', 'N90A', 'N100A', 'N200A', 'N300A', 'N400A', 'N500A', 'N600A', 'N700A', 'N800A', 'DN900', 'DN800', 'DN700', 'DN600', 'DN500', 'DN400', 'DN300', 'DN200', 'DN100', 'DN90', 'DN80', 'DN70', 'DN60', 'DN50', 'DN40', 'DN30', 'DN20', 'DN10', 'DN0', 'DN800A', 'DN700A', 'DN600A', 'DN500A', 'DN400A', 'DN300A', 'DN200A', 'DN100A', 'DN90A', 'DN80A', 'DN70A', 'DN60A', 'DN50A', 'DN40A', 'DN30A', 'DN20A', 'DN10A'];
9
- var legacyColorMixins = ['background', 'backgroundActive', 'backgroundHover', 'backgroundOnLayer', 'text', 'textHover', 'textActive', 'subtleText', 'placeholderText', 'heading', 'subtleHeading', 'codeBlock', 'link', 'linkHover', 'linkActive', 'linkOutline', 'primary', 'blue', 'teal', 'purple', 'red', 'yellow', 'green', 'skeleton'];
7
+ var namedColors = new Set(['black', 'silver', 'gray', 'white', 'maroon', 'red', 'purple', 'fuchsia', 'green', 'lime', 'olive', 'yellow', 'navy', 'blue', 'teal', 'aqua', 'orange', 'aliceblue', 'antiquewhite', 'aquamarine', 'azure', 'beige', 'bisque', 'blanchedalmond', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'limegreen', 'linen', 'magenta', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'oldlace', 'olivedrab', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'whitesmoke', 'yellowgreen', 'rebeccapurple']);
8
+ var legacyColors = new Set(['R50', 'R75', 'R100', 'R200', 'R300', 'R400', 'R500', 'Y50', 'Y75', 'Y100', 'Y200', 'Y300', 'Y400', 'Y500', 'G50', 'G75', 'G100', 'G200', 'G300', 'G400', 'G500', 'B50', 'B75', 'B100', 'B200', 'B300', 'B400', 'B500', 'P50', 'P75', 'P100', 'P200', 'P300', 'P400', 'P500', 'T50', 'T75', 'T100', 'T200', 'T300', 'T400', 'T500', 'N0', 'N10', 'N20', 'N30', 'N40', 'N50', 'N60', 'N70', 'N80', 'N90', 'N100', 'N200', 'N300', 'N400', 'N500', 'N600', 'N700', 'N800', 'N900', 'N10A', 'N20A', 'N30A', 'N40A', 'N50A', 'N60A', 'N70A', 'N80A', 'N90A', 'N100A', 'N200A', 'N300A', 'N400A', 'N500A', 'N600A', 'N700A', 'N800A', 'DN900', 'DN800', 'DN700', 'DN600', 'DN500', 'DN400', 'DN300', 'DN200', 'DN100', 'DN90', 'DN80', 'DN70', 'DN60', 'DN50', 'DN40', 'DN30', 'DN20', 'DN10', 'DN0', 'DN800A', 'DN700A', 'DN600A', 'DN500A', 'DN400A', 'DN300A', 'DN200A', 'DN100A', 'DN90A', 'DN80A', 'DN70A', 'DN60A', 'DN50A', 'DN40A', 'DN30A', 'DN20A', 'DN10A', // Legacy Trello colors:
9
+ 'AtlassianBlue50', 'AtlassianBlue200', 'AtlassianBlue300', 'AtlassianBlue400', 'TrelloBlue25', 'TrelloBlue50', 'TrelloBlue100', 'TrelloBlue200', 'TrelloBlue300', 'TrelloBlue400', 'TrelloBlue500', 'TrelloBlue600', 'TrelloBlue700', 'TrelloBlue800', 'TrelloBlue900', 'Green50', 'Green100', 'Green200', 'Green300', 'Green400', 'Green500', 'Green600', 'Green700', 'Green800', 'Green900', 'Orange50', 'Orange100', 'Orange200', 'Orange300', 'Orange400', 'Orange500', 'Orange600', 'Orange700', 'Orange800', 'Orange900', 'Red50', 'Red100', 'Red200', 'Red300', 'Red400', 'Red500', 'Red600', 'Red700', 'Red800', 'Red900', 'Yellow50', 'Yellow100', 'Yellow200', 'Yellow300', 'Yellow400', 'Yellow500', 'Yellow600', 'Yellow700', 'Yellow800', 'Yellow900', 'Purple50', 'Purple100', 'Purple200', 'Purple300', 'Purple400', 'Purple500', 'Purple600', 'Purple700', 'Purple800', 'Purple900', 'VioletMbgAlert', 'Pink50', 'Pink100', 'Pink200', 'Pink300', 'Pink400', 'Pink500', 'Pink600', 'Pink700', 'Pink800', 'Pink900', 'Sky25', 'Sky50', 'Sky100', 'Sky200', 'Sky300', 'Sky400', 'Sky500', 'Sky600', 'Sky700', 'Sky800', 'Sky900', 'Lime50', 'Lime100', 'Lime200', 'Lime300', 'Lime400', 'Lime500', 'Lime600', 'Lime700', 'Lime800', 'Lime900', 'BusinessBlue50', 'BusinessBlue100', 'BusinessBlue200', 'BusinessBlue300', 'BusinessBlue400', 'BusinessBlue500', 'BusinessBlue600', 'BusinessBlue700', 'BusinessBlue800', 'BusinessBlue900', 'Opacity1', 'Opacity2', 'Opacity3', 'Opacity4', 'Opacity5', 'Opacity6', 'Opacity7', 'Opacity8', 'Opacity9', 'OpacityDark1', 'OpacityDark2', 'OpacityDark3', 'OpacityDark4', 'OpacityDark5', 'OpacityDark6', 'OpacityDark7', 'OpacityDark8', 'OpacityDark9', 'Black']);
10
+ var legacyColorMixins = new Set(['background', 'backgroundActive', 'backgroundHover', 'backgroundOnLayer', 'text', 'textHover', 'textActive', 'subtleText', 'placeholderText', 'heading', 'subtleHeading', 'codeBlock', 'link', 'linkHover', 'linkActive', 'linkOutline', 'primary', 'blue', 'teal', 'purple', 'red', 'yellow', 'green', 'skeleton']);
10
11
 
11
12
  var includesWholeWord = function includesWholeWord(value, options) {
12
13
  var values = value.replace(/[^a-zA-Z ]/g, ' ').trim().split(/(?:,|\.| )+/);
13
- var result = false;
14
- options.forEach(function (el) {
15
- if (values.includes(el)) {
16
- result = true;
17
- }
14
+ return values.some(function (value) {
15
+ return options.has(value);
18
16
  });
19
- return result;
20
17
  };
21
18
 
22
19
  var isLegacyColor = function isLegacyColor(value) {
23
- return legacyColors.includes(value);
20
+ return legacyColors.has(value);
24
21
  };
25
22
 
26
23
  exports.isLegacyColor = isLegacyColor;
27
24
 
28
25
  var isLegacyNamedColor = function isLegacyNamedColor(value) {
29
- return legacyColorMixins.includes(value);
26
+ return legacyColorMixins.has(value);
30
27
  };
31
28
 
32
29
  exports.isLegacyNamedColor = isLegacyNamedColor;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-design-system",
3
- "version": "4.9.0",
3
+ "version": "4.11.0",
4
4
  "sideEffects": false
5
5
  }
@@ -1,4 +1,5 @@
1
1
  import { isNodeOfType } from 'eslint-codemod-utils';
2
+ import { getIsException } from '../utils/get-is-exception';
2
3
  import { includesHardCodedColor, isHardCodedColor, isLegacyColor, isLegacyNamedColor } from '../utils/is-color';
3
4
  import { isLegacyElevation } from '../utils/is-elevation';
4
5
  import { isChildOfType, isDecendantOfGlobalToken, isDecendantOfStyleBlock, isDecendantOfStyleJsxAttribute, isDecendantOfType, isPropertyKey, isVariableName } from '../utils/is-node';
@@ -49,13 +50,14 @@ token('color.background.blanket');
49
50
 
50
51
  create(context) {
51
52
  const config = context.options[0] || defaultConfig;
53
+ const isException = getIsException(config.exceptions);
52
54
  return {
53
55
  'TemplateLiteral > Identifier': node => {
54
56
  if (!isDecendantOfStyleBlock(node)) {
55
57
  return;
56
58
  }
57
59
 
58
- if (node.type === 'Identifier' && isLegacyNamedColor(node.name)) {
60
+ if (node.type === 'Identifier' && isLegacyNamedColor(node.name) && !isException(node)) {
59
61
  context.report({
60
62
  messageId: 'hardCodedColor',
61
63
  node,
@@ -66,22 +68,24 @@ token('color.background.blanket');
66
68
  },
67
69
 
68
70
  Identifier(node) {
69
- if (isDecendantOfGlobalToken(node) || isDecendantOfType(node, 'ImportDeclaration') || isPropertyKey(node) || isVariableName(node)) {
71
+ if (isException(node) || isDecendantOfGlobalToken(node) || isDecendantOfType(node, 'ImportDeclaration') || isPropertyKey(node) || isVariableName(node)) {
70
72
  return;
71
73
  }
72
74
 
73
- const isNodeHardCodedColor = isHardCodedColor(node.name);
74
-
75
- if (isLegacyColor(node.name) || isNodeHardCodedColor) {
76
- if (node.parent.type === 'MemberExpression' && node.parent.object.type === 'Identifier') {
77
- // Object members as named colors, like obj.ivory, should be valid,
78
- // and hexes and color functions cannot be property names anyway.
79
- if (!isNodeHardCodedColor) {
80
- context.report({
81
- messageId: 'hardCodedColor',
82
- node,
83
- suggest: getTokenSuggestion(node.parent, `${node.parent.object.name}.${node.name}`, config)
84
- });
75
+ const isNodeLegacyColor = isLegacyColor(node.name);
76
+
77
+ if (isNodeLegacyColor || isHardCodedColor(node.name)) {
78
+ if (node.parent.type === 'MemberExpression') {
79
+ if (node.parent.object.type === 'Identifier') {
80
+ // Object members as named colors, like obj.ivory, should be valid,
81
+ // and hexes and color functions cannot be property names anyway.
82
+ if (isNodeLegacyColor) {
83
+ context.report({
84
+ messageId: 'hardCodedColor',
85
+ node,
86
+ suggest: getTokenSuggestion(node.parent, `${node.parent.object.name}.${node.name}`, config)
87
+ });
88
+ }
85
89
  }
86
90
 
87
91
  return;
@@ -147,11 +151,7 @@ ${' '.repeat(getNodeColumn(node) - 2)}box-shadow: \${token('${elevation.shadow}'
147
151
  });
148
152
  },
149
153
  'ObjectExpression > Property > Literal': node => {
150
- if (node.type !== 'Literal') {
151
- return;
152
- }
153
-
154
- if (typeof node.value !== 'string') {
154
+ if (node.type !== 'Literal' || typeof node.value !== 'string') {
155
155
  return;
156
156
  }
157
157
 
@@ -159,7 +159,7 @@ ${' '.repeat(getNodeColumn(node) - 2)}box-shadow: \${token('${elevation.shadow}'
159
159
  return;
160
160
  }
161
161
 
162
- if (isHardCodedColor(node.value) || includesHardCodedColor(node.value)) {
162
+ if ((isHardCodedColor(node.value) || includesHardCodedColor(node.value)) && !isException(node)) {
163
163
  context.report({
164
164
  messageId: 'hardCodedColor',
165
165
  node,
@@ -178,7 +178,7 @@ ${' '.repeat(getNodeColumn(node) - 2)}box-shadow: \${token('${elevation.shadow}'
178
178
  return;
179
179
  }
180
180
 
181
- if (!isLegacyNamedColor(node.callee.name) || isDecendantOfGlobalToken(node)) {
181
+ if (!isLegacyNamedColor(node.callee.name) || isDecendantOfGlobalToken(node) || isException(node)) {
182
182
  return;
183
183
  }
184
184
 
@@ -198,13 +198,21 @@ ${' '.repeat(getNodeColumn(node) - 2)}box-shadow: \${token('${elevation.shadow}'
198
198
  return;
199
199
  }
200
200
 
201
- if (node.value.type === 'Literal' && (isHardCodedColor(node.value.value) || includesHardCodedColor(node.value.value))) {
202
- context.report({
203
- messageId: 'hardCodedColor',
204
- node,
205
- suggest: getTokenSuggestion(node.value, node.value.value, config)
206
- });
207
- return;
201
+ if (node.value.type === 'Literal') {
202
+ if (isException(node)) {
203
+ return;
204
+ }
205
+
206
+ const literalValue = node.value.value;
207
+
208
+ if (isHardCodedColor(literalValue) || includesHardCodedColor(literalValue)) {
209
+ context.report({
210
+ messageId: 'hardCodedColor',
211
+ node,
212
+ suggest: getTokenSuggestion(node.value, literalValue, config)
213
+ });
214
+ return;
215
+ }
208
216
  }
209
217
  }
210
218