@atlaskit/eslint-plugin-design-system 10.9.0 → 10.10.1

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 (101) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -0
  3. package/dist/cjs/presets/all.codegen.js +2 -1
  4. package/dist/cjs/rules/ensure-design-token-usage/index.js +199 -227
  5. package/dist/cjs/rules/index.codegen.js +3 -1
  6. package/dist/cjs/rules/no-custom-icons/checks/has-prop.js +12 -0
  7. package/dist/cjs/rules/no-custom-icons/checks/is-from-import-source.js +42 -0
  8. package/dist/cjs/rules/no-custom-icons/checks/is-imported-jsx-element.js +10 -0
  9. package/dist/cjs/rules/no-custom-icons/index.js +67 -0
  10. package/dist/cjs/rules/no-legacy-icons/checks.js +63 -67
  11. package/dist/cjs/rules/no-legacy-icons/helpers.js +29 -24
  12. package/dist/cjs/rules/no-legacy-icons/index.js +15 -88
  13. package/dist/cjs/rules/use-tokens-typography/index.js +4 -8
  14. package/dist/cjs/rules/utils/error-boundary.js +58 -11
  15. package/dist/es2019/presets/all.codegen.js +2 -1
  16. package/dist/es2019/rules/ensure-design-token-usage/index.js +16 -30
  17. package/dist/es2019/rules/index.codegen.js +3 -1
  18. package/dist/es2019/rules/no-custom-icons/checks/has-prop.js +4 -0
  19. package/dist/es2019/rules/no-custom-icons/checks/is-from-import-source.js +23 -0
  20. package/dist/es2019/rules/no-custom-icons/checks/is-imported-jsx-element.js +4 -0
  21. package/dist/es2019/rules/no-custom-icons/index.js +61 -0
  22. package/dist/es2019/rules/no-legacy-icons/checks.js +20 -33
  23. package/dist/es2019/rules/no-legacy-icons/helpers.js +24 -21
  24. package/dist/es2019/rules/no-legacy-icons/index.js +15 -70
  25. package/dist/es2019/rules/use-tokens-typography/index.js +3 -7
  26. package/dist/es2019/rules/utils/error-boundary.js +55 -11
  27. package/dist/esm/presets/all.codegen.js +2 -1
  28. package/dist/esm/rules/ensure-design-token-usage/index.js +199 -227
  29. package/dist/esm/rules/index.codegen.js +3 -1
  30. package/dist/esm/rules/no-custom-icons/checks/has-prop.js +6 -0
  31. package/dist/esm/rules/no-custom-icons/checks/is-from-import-source.js +36 -0
  32. package/dist/esm/rules/no-custom-icons/checks/is-imported-jsx-element.js +4 -0
  33. package/dist/esm/rules/no-custom-icons/index.js +61 -0
  34. package/dist/esm/rules/no-legacy-icons/checks.js +64 -68
  35. package/dist/esm/rules/no-legacy-icons/helpers.js +28 -23
  36. package/dist/esm/rules/no-legacy-icons/index.js +15 -88
  37. package/dist/esm/rules/use-tokens-typography/index.js +4 -8
  38. package/dist/esm/rules/utils/error-boundary.js +56 -10
  39. package/dist/types/index.codegen.d.ts +1 -0
  40. package/dist/types/presets/all.codegen.d.ts +2 -1
  41. package/dist/types/rules/index.codegen.d.ts +1 -0
  42. package/dist/types/rules/no-custom-icons/checks/has-prop.d.ts +2 -0
  43. package/dist/types/rules/no-custom-icons/checks/is-from-import-source.d.ts +8 -0
  44. package/dist/types/rules/no-custom-icons/checks/is-imported-jsx-element.d.ts +8 -0
  45. package/dist/types/rules/no-custom-icons/index.d.ts +3 -0
  46. package/dist/types/rules/no-legacy-icons/helpers.d.ts +3 -13
  47. package/dist/types/rules/no-legacy-icons/index.d.ts +1 -2
  48. package/dist/types/rules/utils/error-boundary.d.ts +8 -5
  49. package/dist/types-ts4.5/index.codegen.d.ts +1 -0
  50. package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -1
  51. package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -0
  52. package/dist/types-ts4.5/rules/no-custom-icons/checks/has-prop.d.ts +2 -0
  53. package/dist/types-ts4.5/rules/no-custom-icons/checks/is-from-import-source.d.ts +8 -0
  54. package/dist/types-ts4.5/rules/no-custom-icons/checks/is-imported-jsx-element.d.ts +8 -0
  55. package/dist/types-ts4.5/rules/no-custom-icons/index.d.ts +3 -0
  56. package/dist/types-ts4.5/rules/no-legacy-icons/helpers.d.ts +3 -13
  57. package/dist/types-ts4.5/rules/no-legacy-icons/index.d.ts +1 -2
  58. package/dist/types-ts4.5/rules/utils/error-boundary.d.ts +8 -5
  59. package/package.json +2 -2
  60. package/constellation/consistent-css-prop-usage/usage.mdx +0 -210
  61. package/constellation/ensure-design-token-usage/usage.mdx +0 -77
  62. package/constellation/ensure-design-token-usage-preview/usage.mdx +0 -6
  63. package/constellation/icon-label/usage.mdx +0 -41
  64. package/constellation/index/props.mdx +0 -30
  65. package/constellation/index/usage.mdx +0 -56
  66. package/constellation/no-banned-imports/usage.mdx +0 -19
  67. package/constellation/no-css-tagged-template-expression/usage.mdx +0 -71
  68. package/constellation/no-deprecated-apis/usage.mdx +0 -82
  69. package/constellation/no-deprecated-design-token-usage/usage.mdx +0 -30
  70. package/constellation/no-deprecated-imports/usage.mdx +0 -66
  71. package/constellation/no-direct-use-of-web-platform-drag-and-drop/usage.mdx +0 -149
  72. package/constellation/no-empty-styled-expression/usage.mdx +0 -82
  73. package/constellation/no-exported-css/usage.mdx +0 -55
  74. package/constellation/no-exported-keyframes/usage.mdx +0 -55
  75. package/constellation/no-html-anchor/usage.mdx +0 -46
  76. package/constellation/no-html-button/usage.mdx +0 -52
  77. package/constellation/no-invalid-css-map/usage.mdx +0 -210
  78. package/constellation/no-keyframes-tagged-template-expression/usage.mdx +0 -80
  79. package/constellation/no-legacy-icons/usage.mdx +0 -42
  80. package/constellation/no-margin/usage.mdx +0 -21
  81. package/constellation/no-nested-styles/usage.mdx +0 -47
  82. package/constellation/no-physical-properties/usage.mdx +0 -53
  83. package/constellation/no-styled-tagged-template-expression/usage.mdx +0 -135
  84. package/constellation/no-unsafe-design-token-usage/usage.mdx +0 -50
  85. package/constellation/no-unsafe-style-overrides/usage.mdx +0 -52
  86. package/constellation/no-unsupported-drag-and-drop-libraries/usage.mdx +0 -23
  87. package/constellation/prefer-primitives/usage.mdx +0 -32
  88. package/constellation/use-button-group-label/usage.mdx +0 -60
  89. package/constellation/use-drawer-label/usage.mdx +0 -55
  90. package/constellation/use-heading/usage.mdx +0 -31
  91. package/constellation/use-heading-level-in-spotlight-card/usage.mdx +0 -21
  92. package/constellation/use-href-in-link-item/usage.mdx +0 -19
  93. package/constellation/use-latest-xcss-syntax/usage.mdx +0 -33
  94. package/constellation/use-latest-xcss-syntax-typography/usage.mdx +0 -34
  95. package/constellation/use-menu-section-title/usage.mdx +0 -55
  96. package/constellation/use-popup-label/usage.mdx +0 -56
  97. package/constellation/use-primitives/usage.mdx +0 -78
  98. package/constellation/use-primitives-text/usage.mdx +0 -35
  99. package/constellation/use-tokens-space/usage.mdx +0 -34
  100. package/constellation/use-tokens-typography/usage.mdx +0 -55
  101. package/constellation/use-visually-hidden/usage.mdx +0 -35
@@ -29,26 +29,18 @@ var createWithConfig = function createWithConfig(initialConfig) {
29
29
  failSilently: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.failSilently) || defaultConfig.failSilently
30
30
  };
31
31
  var tokenNode = null;
32
- return {
32
+ return errorBoundary({
33
33
  ImportDeclaration: function ImportDeclaration(node) {
34
- return errorBoundary(function () {
35
- if (node.source.value === '@atlaskit/tokens' && config.applyImport) {
36
- tokenNode = node;
37
- }
38
- }, {
39
- config: config
40
- });
34
+ if (node.source.value === '@atlaskit/tokens' && config.applyImport) {
35
+ tokenNode = node;
36
+ }
41
37
  },
42
38
  // For expressions within template literals (e.g. `color: ${red}`) - color only
43
39
  'TemplateLiteral > Identifier': function TemplateLiteralIdentifier(node) {
44
- return errorBoundary(function () {
45
- if (config.domains.includes('color')) {
46
- return lintTemplateIdentifierForColor(node, context, config);
47
- }
48
- return;
49
- }, {
50
- config: config
51
- });
40
+ if (config.domains.includes('color')) {
41
+ return lintTemplateIdentifierForColor(node, context, config);
42
+ }
43
+ return;
52
44
  },
53
45
  // const styles = css({ color: 'red', margin: '4px' }), styled.div({ color: 'red', margin: '4px' })
54
46
  ObjectExpression: function (_ObjectExpression) {
@@ -60,263 +52,243 @@ var createWithConfig = function createWithConfig(initialConfig) {
60
52
  };
61
53
  return ObjectExpression;
62
54
  }(function (parentNode) {
63
- return errorBoundary(function () {
64
- var _context$getScope = context.getScope(),
65
- references = _context$getScope.references;
66
- /**
67
- * NOTE: This rule doesn't have an `importSources` config option,
68
- * so this will just be equal to DEFAULT_IMPORT_SOURCES (which is fine)
69
- */
70
- var importSources = getImportSources(context);
55
+ var _context$getScope = context.getScope(),
56
+ references = _context$getScope.references;
57
+ /**
58
+ * NOTE: This rule doesn't have an `importSources` config option,
59
+ * so this will just be equal to DEFAULT_IMPORT_SOURCES (which is fine)
60
+ */
61
+ var importSources = getImportSources(context);
71
62
 
72
- // To force the correct node type
73
- if (!isNodeOfType(parentNode, 'ObjectExpression')) {
74
- return;
75
- }
63
+ // To force the correct node type
64
+ if (!isNodeOfType(parentNode, 'ObjectExpression')) {
65
+ return;
66
+ }
76
67
 
77
- // Return for nested objects - these get handled automatically so without returning we'd be doubling up
78
- if (parentNode.parent.type === 'Property') {
68
+ // Return for nested objects - these get handled automatically so without returning we'd be doubling up
69
+ if (parentNode.parent.type === 'Property') {
70
+ return;
71
+ }
72
+ if (isDecendantOfXcssBlock(parentNode, references, importSources)) {
73
+ return;
74
+ }
75
+ if (!isDecendantOfStyleBlock(parentNode) && !isDecendantOfType(parentNode, 'JSXExpressionContainer')) {
76
+ return;
77
+ }
78
+ function findObjectStyles(node) {
79
+ if (!isNodeOfType(node, 'Property')) {
79
80
  return;
80
81
  }
81
- if (isDecendantOfXcssBlock(parentNode, references, importSources)) {
82
+ if (isNodeOfType(node.value, 'ObjectExpression')) {
83
+ return node.value.properties.forEach(findObjectStyles);
84
+ }
85
+ if (!isNodeOfType(node.key, 'Identifier') && !isNodeOfType(node.key, 'Literal')) {
82
86
  return;
83
87
  }
84
- if (!isDecendantOfStyleBlock(parentNode) && !isDecendantOfType(parentNode, 'JSXExpressionContainer')) {
88
+ var propertyName = isNodeOfType(node.key, 'Identifier') ? node.key.name : String(node.key.value);
89
+
90
+ // Returns which domains to lint against based on rule's config and current property
91
+ var domains = getDomainsForProperty(propertyName, config.domains);
92
+ if (domains.length === 0 || isDecendantOfGlobalToken(node.value)) {
85
93
  return;
86
94
  }
87
- function findObjectStyles(node) {
88
- if (!isNodeOfType(node, 'Property')) {
89
- return;
90
- }
91
- if (isNodeOfType(node.value, 'ObjectExpression')) {
92
- return node.value.properties.forEach(findObjectStyles);
93
- }
94
- if (!isNodeOfType(node.key, 'Identifier') && !isNodeOfType(node.key, 'Literal')) {
95
- return;
95
+ if (isNodeOfType(node.value, 'TemplateLiteral')) {
96
+ var value = getValueFromTemplateLiteralRaw(node.value, context);
97
+ if (Array.isArray(value) && value.some(isCalc)) {
98
+ return context.report({
99
+ node: node,
100
+ messageId: 'noCalcUsage',
101
+ data: {
102
+ payload: "".concat(propertyName)
103
+ }
104
+ });
96
105
  }
97
- var propertyName = isNodeOfType(node.key, 'Identifier') ? node.key.name : String(node.key.value);
98
-
99
- // Returns which domains to lint against based on rule's config and current property
100
- var domains = getDomainsForProperty(propertyName, config.domains);
101
- if (domains.length === 0 || isDecendantOfGlobalToken(node.value)) {
106
+ if (node.value.expressions.some(isDecendantOfGlobalToken)) {
102
107
  return;
103
108
  }
104
- if (isNodeOfType(node.value, 'TemplateLiteral')) {
105
- var value = getValueFromTemplateLiteralRaw(node.value, context);
106
- if (Array.isArray(value) && value.some(isCalc)) {
107
- return context.report({
108
- node: node,
109
- messageId: 'noCalcUsage',
110
- data: {
111
- payload: "".concat(propertyName)
112
- }
113
- });
114
- }
115
- if (node.value.expressions.some(isDecendantOfGlobalToken)) {
116
- return;
117
- }
118
- }
119
- if (domains.includes('color')) {
120
- return lintObjectForColor(node, context, config);
121
- }
122
- if (domains.includes('spacing') || domains.includes('shape')) {
123
- /**
124
- * We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration.
125
- */
126
- var fontSizeNode = getPropertyNodeFromParent('fontSize', parentNode);
127
- var fontSize = fontSizeNode && getValueForPropertyNode(fontSizeNode, context);
128
- return lintObjectForSpacing(node, context, config, fontSize, tokenNode);
129
- }
130
109
  }
131
- parentNode.properties.forEach(findObjectStyles);
132
- }, {
133
- config: config
134
- });
110
+ if (domains.includes('color')) {
111
+ return lintObjectForColor(node, context, config);
112
+ }
113
+ if (domains.includes('spacing') || domains.includes('shape')) {
114
+ /**
115
+ * We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration.
116
+ */
117
+ var fontSizeNode = getPropertyNodeFromParent('fontSize', parentNode);
118
+ var fontSize = fontSizeNode && getValueForPropertyNode(fontSizeNode, context);
119
+ return lintObjectForSpacing(node, context, config, fontSize, tokenNode);
120
+ }
121
+ }
122
+ parentNode.properties.forEach(findObjectStyles);
135
123
  }),
136
124
  // CSSTemplateLiteral and StyledTemplateLiteral
137
125
  // const cssTemplateLiteral = css`color: red; padding: 12px`;
138
126
  // const styledTemplateLiteral = styled.p`color: red; padding: 8px`;
139
127
  'TaggedTemplateExpression[tag.name="css"],TaggedTemplateExpression[tag.object.name="styled"],TaggedTemplateExpression[tag.callee.name="styled"]': function TaggedTemplateExpressionTagNameCssTaggedTemplateExpressionTagObjectNameStyledTaggedTemplateExpressionTagCalleeNameStyled(node) {
140
- return errorBoundary(function () {
141
- // To force the correct node type
142
- if (!isNodeOfType(node, 'TaggedTemplateExpression')) {
143
- return;
144
- }
145
- var processedCssLines = processCssNode(node, context);
146
- if (!processedCssLines) {
147
- // if we can't get a processed css we bail
148
- return;
128
+ // To force the correct node type
129
+ if (!isNodeOfType(node, 'TaggedTemplateExpression')) {
130
+ return;
131
+ }
132
+ var processedCssLines = processCssNode(node, context);
133
+ if (!processedCssLines) {
134
+ // if we can't get a processed css we bail
135
+ return;
136
+ }
137
+ var globalFontSize = getFontSizeValueInScope(processedCssLines);
138
+ var textForSource = context.getSourceCode().getText(node.quasi);
139
+ var allReplacedValues = [];
140
+ var completeSource = processedCssLines.reduce(function (currentSource, _ref) {
141
+ var _ref2 = _slicedToArray(_ref, 2),
142
+ resolvedCssLine = _ref2[0],
143
+ originalCssLine = _ref2[1];
144
+ var _resolvedCssLine$spli = resolvedCssLine.split(':'),
145
+ _resolvedCssLine$spli2 = _slicedToArray(_resolvedCssLine$spli, 2),
146
+ originalProperty = _resolvedCssLine$spli2[0],
147
+ resolvedCssValues = _resolvedCssLine$spli2[1];
148
+ var _originalCssLine$spli = originalCssLine.split(':'),
149
+ _originalCssLine$spli2 = _slicedToArray(_originalCssLine$spli, 2),
150
+ _ = _originalCssLine$spli2[0],
151
+ originalCssValues = _originalCssLine$spli2[1];
152
+ var propertyName = convertHyphenatedNameToCamelCase(originalProperty);
153
+ var isFontFamily = /fontFamily/.test(propertyName);
154
+ var replacedValuesPerProperty = [originalProperty];
155
+ var domains = getDomainsForProperty(propertyName, config.domains);
156
+ if (domains.length === 0 || !resolvedCssValues) {
157
+ // in both of these cases no changes should be made to the current property
158
+ return currentSource;
149
159
  }
150
- var globalFontSize = getFontSizeValueInScope(processedCssLines);
151
- var textForSource = context.getSourceCode().getText(node.quasi);
152
- var allReplacedValues = [];
153
- var completeSource = processedCssLines.reduce(function (currentSource, _ref) {
154
- var _ref2 = _slicedToArray(_ref, 2),
155
- resolvedCssLine = _ref2[0],
156
- originalCssLine = _ref2[1];
157
- var _resolvedCssLine$spli = resolvedCssLine.split(':'),
158
- _resolvedCssLine$spli2 = _slicedToArray(_resolvedCssLine$spli, 2),
159
- originalProperty = _resolvedCssLine$spli2[0],
160
- resolvedCssValues = _resolvedCssLine$spli2[1];
161
- var _originalCssLine$spli = originalCssLine.split(':'),
162
- _originalCssLine$spli2 = _slicedToArray(_originalCssLine$spli, 2),
163
- _ = _originalCssLine$spli2[0],
164
- originalCssValues = _originalCssLine$spli2[1];
165
- var propertyName = convertHyphenatedNameToCamelCase(originalProperty);
166
- var isFontFamily = /fontFamily/.test(propertyName);
167
- var replacedValuesPerProperty = [originalProperty];
168
- var domains = getDomainsForProperty(propertyName, config.domains);
169
- if (domains.length === 0 || !resolvedCssValues) {
170
- // in both of these cases no changes should be made to the current property
160
+ if (domains.includes('color')) {
161
+ if (includesTokenString(resolvedCssValues.trim())) {
171
162
  return currentSource;
172
163
  }
173
- if (domains.includes('color')) {
174
- if (includesTokenString(resolvedCssValues.trim())) {
175
- return currentSource;
176
- }
177
- if (includesHardCodedColor(resolvedCssValues)) {
178
- context.report({
179
- messageId: 'hardCodedColor',
180
- node: node
181
- });
182
- return currentSource;
183
- }
164
+ if (includesHardCodedColor(resolvedCssValues)) {
165
+ context.report({
166
+ messageId: 'hardCodedColor',
167
+ node: node
168
+ });
169
+ return currentSource;
170
+ }
171
+ }
172
+ if (domains.includes('spacing') || domains.includes('shape')) {
173
+ if (!isValidSpacingValue(resolvedCssValues, globalFontSize)) {
174
+ // no changes should be made to the current property
175
+ return currentSource;
184
176
  }
185
- if (domains.includes('spacing') || domains.includes('shape')) {
186
- if (!isValidSpacingValue(resolvedCssValues, globalFontSize)) {
187
- // no changes should be made to the current property
188
- return currentSource;
189
- }
190
-
191
- // gets the values from the associated property, numeric values or NaN
192
- var processedNumericValues = getValueFromShorthand(resolvedCssValues);
193
- var processedValues = splitShorthandValues(resolvedCssValues);
194
- // only splits shorthand values but it does not transform NaNs so tokens are preserved
195
- var originalValues = splitShorthandValues(originalCssValues);
196
-
197
- // reconstructing the string
198
- // should replace what it can and preserve the raw value for everything else
199
177
 
200
- var replacementValue = processedNumericValues
201
- // put together resolved value and original value on a tuple
202
- .map(function (value, index) {
203
- return [
204
- // if emToPX conversion fails we'll default to original value
205
- emToPixels(value, globalFontSize) || value, processedValues[index], originalValues[index]];
206
- }).map(function (_ref3) {
207
- var _ref4 = _slicedToArray(_ref3, 3),
208
- numericOrNanValue = _ref4[0],
209
- pxValue = _ref4[1],
210
- originalValue = _ref4[2];
211
- if (!originalValue) {
212
- return originalValue;
213
- }
214
- if (isCalc(originalValue)) {
215
- context.report({
216
- node: node,
217
- messageId: 'noCalcUsage',
218
- data: {
219
- payload: "".concat(propertyName)
220
- }
221
- });
222
- return originalValue;
223
- }
224
- if (isTokenValueString(originalValue)) {
225
- // if the value is already valid, nothing to report or replace
226
- return originalValue;
227
- }
178
+ // gets the values from the associated property, numeric values or NaN
179
+ var processedNumericValues = getValueFromShorthand(resolvedCssValues);
180
+ var processedValues = splitShorthandValues(resolvedCssValues);
181
+ // only splits shorthand values but it does not transform NaNs so tokens are preserved
182
+ var originalValues = splitShorthandValues(originalCssValues);
228
183
 
229
- // do not replace 0 or auto with tokens
230
- if (isZero(pxValue) || isAuto(pxValue)) {
231
- return originalValue;
232
- }
233
- if (isNaN(numericOrNanValue) && !isFontFamily) {
234
- // do not report if we have nothing to replace with
235
- return originalValue;
236
- }
184
+ // reconstructing the string
185
+ // should replace what it can and preserve the raw value for everything else
237
186
 
238
- // value is numeric or fontFamily, and needs replacing we'll report first
187
+ var replacementValue = processedNumericValues
188
+ // put together resolved value and original value on a tuple
189
+ .map(function (value, index) {
190
+ return [
191
+ // if emToPX conversion fails we'll default to original value
192
+ emToPixels(value, globalFontSize) || value, processedValues[index], originalValues[index]];
193
+ }).map(function (_ref3) {
194
+ var _ref4 = _slicedToArray(_ref3, 3),
195
+ numericOrNanValue = _ref4[0],
196
+ pxValue = _ref4[1],
197
+ originalValue = _ref4[2];
198
+ if (!originalValue) {
199
+ return originalValue;
200
+ }
201
+ if (isCalc(originalValue)) {
239
202
  context.report({
240
203
  node: node,
241
- messageId: 'noRawSpacingValues',
204
+ messageId: 'noCalcUsage',
242
205
  data: {
243
- payload: "".concat(propertyName, ":").concat(numericOrNanValue)
206
+ payload: "".concat(propertyName)
244
207
  }
245
208
  });
209
+ return originalValue;
210
+ }
211
+ if (isTokenValueString(originalValue)) {
212
+ // if the value is already valid, nothing to report or replace
213
+ return originalValue;
214
+ }
246
215
 
247
- // from here on we know value is numeric or a font family, so it might or might not have a token equivalent
248
- var replacementNode = getTokenReplacement(propertyName, numericOrNanValue);
249
- if (!replacementNode) {
250
- return originalValue;
251
- }
252
- var replacementToken = '${' + replacementNode.toString() + '}';
253
- replacedValuesPerProperty.push(isFontFamily ? numericOrNanValue.trim() : pxValue);
254
- return replacementToken;
255
- }).join(' ');
256
- if (replacedValuesPerProperty.length > 1) {
257
- // first value is the property name, so it will always have at least 1
258
- allReplacedValues.push(replacedValuesPerProperty);
216
+ // do not replace 0 or auto with tokens
217
+ if (isZero(pxValue) || isAuto(pxValue)) {
218
+ return originalValue;
219
+ }
220
+ if (isNaN(numericOrNanValue) && !isFontFamily) {
221
+ // do not report if we have nothing to replace with
222
+ return originalValue;
259
223
  }
260
224
 
261
- // replace property:val with new property:val
262
- var replacedCssLine = currentSource.replace(originalCssLine, // padding: ${gridSize()}px;
263
- "".concat(originalProperty, ": ").concat(replacementValue));
264
- if (!replacedCssLine) {
265
- return currentSource;
225
+ // value is numeric or fontFamily, and needs replacing we'll report first
226
+ context.report({
227
+ node: node,
228
+ messageId: 'noRawSpacingValues',
229
+ data: {
230
+ payload: "".concat(propertyName, ":").concat(numericOrNanValue)
231
+ }
232
+ });
233
+
234
+ // from here on we know value is numeric or a font family, so it might or might not have a token equivalent
235
+ var replacementNode = getTokenReplacement(propertyName, numericOrNanValue);
236
+ if (!replacementNode) {
237
+ return originalValue;
266
238
  }
267
- return replacedCssLine;
239
+ var replacementToken = '${' + replacementNode.toString() + '}';
240
+ replacedValuesPerProperty.push(isFontFamily ? numericOrNanValue.trim() : pxValue);
241
+ return replacementToken;
242
+ }).join(' ');
243
+ if (replacedValuesPerProperty.length > 1) {
244
+ // first value is the property name, so it will always have at least 1
245
+ allReplacedValues.push(replacedValuesPerProperty);
268
246
  }
269
- return currentSource;
270
- }, textForSource);
271
- if (completeSource !== textForSource) {
272
- // means we found some replacement values, we'll give the option to fix them
273
247
 
274
- context.report({
275
- node: node,
276
- messageId: 'autofixesPossible',
277
- fix: function fix(fixer) {
278
- return (!tokenNode && config.applyImport ? [insertTokensImport(fixer)] : []).concat([fixer.replaceText(node.quasi, completeSource)]);
279
- }
280
- });
248
+ // replace property:val with new property:val
249
+ var replacedCssLine = currentSource.replace(originalCssLine, // padding: ${gridSize()}px;
250
+ "".concat(originalProperty, ": ").concat(replacementValue));
251
+ if (!replacedCssLine) {
252
+ return currentSource;
253
+ }
254
+ return replacedCssLine;
281
255
  }
282
- }, {
283
- config: config
284
- });
256
+ return currentSource;
257
+ }, textForSource);
258
+ if (completeSource !== textForSource) {
259
+ // means we found some replacement values, we'll give the option to fix them
260
+
261
+ context.report({
262
+ node: node,
263
+ messageId: 'autofixesPossible',
264
+ fix: function fix(fixer) {
265
+ return (!tokenNode && config.applyImport ? [insertTokensImport(fixer)] : []).concat([fixer.replaceText(node.quasi, completeSource)]);
266
+ }
267
+ });
268
+ }
285
269
  },
286
270
  // For inline JSX styles - literals (e.g. <Test color="red"/>) - color only
287
271
  'JSXAttribute > Literal': function JSXAttributeLiteral(node) {
288
- return errorBoundary(function () {
289
- if (config.domains.includes('color')) {
290
- return lintJSXLiteralForColor(node, context, config);
291
- }
292
- return;
293
- }, {
294
- config: config
295
- });
272
+ if (config.domains.includes('color')) {
273
+ return lintJSXLiteralForColor(node, context, config);
274
+ }
275
+ return;
296
276
  },
297
277
  // For inline JSX styles - members (e.g. <Test color={color.red}/>) - color only
298
278
  'JSXExpressionContainer > MemberExpression': function JSXExpressionContainerMemberExpression(node) {
299
- return errorBoundary(function () {
300
- if (config.domains.includes('color')) {
301
- return lintJSXMemberForColor(node, context, config);
302
- }
303
- return;
304
- }, {
305
- config: config
306
- });
279
+ if (config.domains.includes('color')) {
280
+ return lintJSXMemberForColor(node, context, config);
281
+ }
282
+ return;
307
283
  },
308
284
  // For inline JSX styles - identifiers (e.g. <Test color={red}/>) - color only
309
285
  'JSXExpressionContainer > Identifier': function JSXExpressionContainerIdentifier(node) {
310
- return errorBoundary(function () {
311
- if (config.domains.includes('color')) {
312
- return lintJSXIdentifierForColor(node, context, config);
313
- }
314
- return;
315
- }, {
316
- config: config
317
- });
286
+ if (config.domains.includes('color')) {
287
+ return lintJSXIdentifierForColor(node, context, config);
288
+ }
289
+ return;
318
290
  }
319
- };
291
+ }, config);
320
292
  };
321
293
  };
322
294
  var rule = createLintRule({
@@ -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::b359d356c482db0087ddfce5bd105403>>
3
+ * @codegen <<SignedSource::402e6eb5433560b1032e5ed926bb5564>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  import consistentCssPropUsage from './consistent-css-prop-usage';
@@ -9,6 +9,7 @@ import ensureDesignTokenUsagePreview from './ensure-design-token-usage-preview';
9
9
  import iconLabel from './icon-label';
10
10
  import noBannedImports from './no-banned-imports';
11
11
  import noCssTaggedTemplateExpression from './no-css-tagged-template-expression';
12
+ import noCustomIcons from './no-custom-icons';
12
13
  import noDeprecatedApis from './no-deprecated-apis';
13
14
  import noDeprecatedDesignTokenUsage from './no-deprecated-design-token-usage';
14
15
  import noDeprecatedImports from './no-deprecated-imports';
@@ -50,6 +51,7 @@ export default {
50
51
  'icon-label': iconLabel,
51
52
  'no-banned-imports': noBannedImports,
52
53
  'no-css-tagged-template-expression': noCssTaggedTemplateExpression,
54
+ 'no-custom-icons': noCustomIcons,
53
55
  'no-deprecated-apis': noDeprecatedApis,
54
56
  'no-deprecated-design-token-usage': noDeprecatedDesignTokenUsage,
55
57
  'no-deprecated-imports': noDeprecatedImports,
@@ -0,0 +1,6 @@
1
+ import { isNodeOfType } from 'eslint-codemod-utils';
2
+ export function hasProp(node, propName) {
3
+ return isNodeOfType(node.openingElement, 'JSXOpeningElement') && node.openingElement.attributes.some(function (a) {
4
+ return a.type === 'JSXAttribute' && a.name.name === propName;
5
+ });
6
+ }
@@ -0,0 +1,36 @@
1
+ import { isImportedJSXElement } from './is-imported-jsx-element';
2
+ export function createIsFromImportSourceFor() {
3
+ for (var _len = arguments.length, importSources = new Array(_len), _key = 0; _key < _len; _key++) {
4
+ importSources[_key] = arguments[_key];
5
+ }
6
+ var literalImportSources = importSources.filter(function (s) {
7
+ return typeof s === 'string';
8
+ });
9
+ var matchImportSources = importSources.filter(function (s) {
10
+ return s instanceof RegExp;
11
+ });
12
+ var varImportSourceMap = new Map();
13
+ function isFromImportSource(node) {
14
+ return isImportedJSXElement(node) && varImportSourceMap.has(node.openingElement.name.name);
15
+ }
16
+ isFromImportSource.importDeclarationHook = function (node) {
17
+ var source = node.source.value;
18
+ if (typeof source !== 'string' || !(literalImportSources.includes(source) || matchImportSources.some(function (r) {
19
+ return r.test(source);
20
+ }))) {
21
+ return;
22
+ }
23
+ node.specifiers.filter(function (spec) {
24
+ return ['ImportSpecifier', 'ImportDefaultSpecifier'].includes(spec.type);
25
+ }).forEach(function (spec) {
26
+ return varImportSourceMap.set(spec.local.name, source);
27
+ });
28
+ };
29
+ isFromImportSource.getImportSource = function (node) {
30
+ if (!isFromImportSource(node)) {
31
+ throw new Error('Node is not an imported JSX element');
32
+ }
33
+ return varImportSourceMap.get(node.openingElement.name.name);
34
+ };
35
+ return isFromImportSource;
36
+ }
@@ -0,0 +1,4 @@
1
+ import { isNodeOfType } from 'eslint-codemod-utils';
2
+ export function isImportedJSXElement(node) {
3
+ return isNodeOfType(node, 'JSXElement') && isNodeOfType(node.openingElement.name, 'JSXIdentifier');
4
+ }
@@ -0,0 +1,61 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+
3
+ import { createLintRule } from '../utils/create-rule';
4
+ import { errorBoundary } from '../utils/error-boundary';
5
+ import { hasProp } from './checks/has-prop';
6
+ import { createIsFromImportSourceFor } from './checks/is-from-import-source';
7
+ var rule = createLintRule({
8
+ meta: {
9
+ name: 'no-custom-icons',
10
+ type: 'problem',
11
+ docs: {
12
+ description: 'Enforces custom glyph icons are used.',
13
+ recommended: false,
14
+ severity: 'warn'
15
+ },
16
+ schema: [{
17
+ type: 'object',
18
+ properties: {
19
+ centralLocation: {
20
+ type: 'string'
21
+ },
22
+ failSilently: {
23
+ type: 'boolean'
24
+ }
25
+ },
26
+ additionalProperties: false
27
+ }],
28
+ messages: {
29
+ noCustomIcons: "Custom icons from {{importSource}} are no longer supported. Migrate to an icon from '@atlaskit/(icon-labs|icon/core|icon/utility)'{{locationMessage}}.\n[Migration guide](https://hello.atlassian.net/wiki/spaces/DST/pages/3748692796/New+ADS+iconography+-+Code+migration+guide)."
30
+ }
31
+ },
32
+ create: function create(context) {
33
+ var _context$options$;
34
+ var isIconBase = createIsFromImportSourceFor('@atlaskit/icon', '@atlaskit/icon/base');
35
+ var _ref = (_context$options$ = context.options[0]) !== null && _context$options$ !== void 0 ? _context$options$ : {},
36
+ _ref$centralLocation = _ref.centralLocation,
37
+ centralLocation = _ref$centralLocation === void 0 ? '' : _ref$centralLocation,
38
+ _ref$failSilently = _ref.failSilently,
39
+ failSilently = _ref$failSilently === void 0 ? false : _ref$failSilently;
40
+ var locationMessage = centralLocation ? " or move the icon to '".concat(centralLocation, "'") : '';
41
+ return errorBoundary({
42
+ JSXElement: function JSXElement(node) {
43
+ var _isIconBase$getImport;
44
+ if (!isIconBase(node) || !hasProp(node, 'glyph')) {
45
+ return;
46
+ }
47
+ var importSource = (_isIconBase$getImport = isIconBase.getImportSource(node)) !== null && _isIconBase$getImport !== void 0 ? _isIconBase$getImport : '';
48
+ context.report({
49
+ node: node.openingElement,
50
+ messageId: 'noCustomIcons',
51
+ data: {
52
+ importSource: importSource,
53
+ locationMessage: locationMessage
54
+ }
55
+ });
56
+ },
57
+ ImportDeclaration: isIconBase.importDeclarationHook
58
+ }, failSilently);
59
+ }
60
+ });
61
+ export default rule;