@atlaskit/eslint-plugin-design-system 4.15.4 → 4.15.6

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,17 @@
1
1
  # @atlaskit/eslint-plugin-design-system
2
2
 
3
+ ## 4.15.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [`6a43a780a85`](https://bitbucket.org/atlassian/atlassian-frontend/commits/6a43a780a85) - Enhance token replacement capabilities of ensure-design-tokens-usage-spacing rule in tagged template literal strings
8
+
9
+ ## 4.15.5
10
+
11
+ ### Patch Changes
12
+
13
+ - [`dda18b361da`](https://bitbucket.org/atlassian/atlassian-frontend/commits/dda18b361da) - Bump version of `eslint-codemod-utils`.
14
+
3
15
  ## 4.15.4
4
16
 
5
17
  ### Patch Changes
@@ -8,91 +8,10 @@ exports.default = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
10
  var _eslintCodemodUtils = require("eslint-codemod-utils");
11
- var _tokensRaw = require("@atlaskit/tokens/tokens-raw");
12
11
  var _isNode = require("../utils/is-node");
13
12
  var _utils = require("./utils");
14
13
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
15
14
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
16
- /**
17
- * Currently we have a wide range of experimental spacing tokens that we are testing.
18
- * We only want transforms to apply to the stable scale values, not the rest.
19
- * This could be removed in the future.
20
- */
21
- var onlyScaleTokens = _tokensRaw.spacing.filter(function (token) {
22
- return token.name.startsWith('space.');
23
- });
24
- var spacingValueToToken = Object.fromEntries(onlyScaleTokens.map(function (token) {
25
- return [token.attributes['pixelValue'], token.name];
26
- }));
27
- var typographyValueToToken = Object.fromEntries(_tokensRaw.typography.map(function (currentToken) {
28
- // Group tokens by property name (e.g. fontSize, fontFamily, lineHeight)
29
- // This allows us to look up values specific to a property
30
- // (so as not to mix tokens with overlapping values e.g. font size and line height both have tokens for 16px)
31
- var tokenGroup = currentToken.attributes.group;
32
- return [tokenGroup, Object.fromEntries(_tokensRaw.typography.map(function (token) {
33
- return token.attributes.group === tokenGroup ? [token.value.replaceAll("\"", "'"), token.name] : [];
34
- }).filter(function (token) {
35
- return token.length;
36
- }))];
37
- }));
38
-
39
- /**
40
- * Returns a token node for a given value including fallbacks.
41
- * @param propertyName camelCase CSS property
42
- * @param value string representing pixel value, or font family, or number representing font weight
43
- * @example
44
- * ```
45
- * propertyName: padding, value: '8px' => token('space.100', '8px')
46
- * propertyName: fontWeight, value: 400 => token('font.weight.regular', '400')
47
- * ```
48
- */
49
- function getTokenNodeForValue(propertyName, value) {
50
- var token = (0, _utils.isTypographyProperty)(propertyName) ? typographyValueToToken[propertyName][value] : spacingValueToToken[value];
51
- var fallbackValue = propertyName === 'fontFamily' ? "\"".concat(value, "\"") : "'".concat(value, "'");
52
- return (0, _eslintCodemodUtils.callExpression)({
53
- callee: (0, _eslintCodemodUtils.identifier)({
54
- name: 'token'
55
- }),
56
- arguments: [(0, _eslintCodemodUtils.literal)({
57
- value: "'".concat(token !== null && token !== void 0 ? token : '', "'")
58
- }), (0, _eslintCodemodUtils.literal)(fallbackValue)],
59
- optional: false
60
- });
61
- }
62
-
63
- /**
64
- * Returns a boolean that signals wether the current property is revelant under the current configuration
65
- * @param propertyName camelCase CSS property
66
- * @param targetOptions Array containing the types of properties that should be included in the rule
67
- * @example
68
- * ```
69
- * propertyName: padding, targetOptions: ['spacing']
70
- * propertyName: fontWeight, targetOptions: ['spacing', 'typography']
71
- * ```
72
- */
73
- function shouldAnalyzeProperty(propertyName, targetOptions) {
74
- if ((0, _utils.isSpacingProperty)(propertyName) && targetOptions.includes('spacing')) {
75
- return true;
76
- }
77
- if ((0, _utils.isTypographyProperty)(propertyName) && targetOptions.includes('typography')) {
78
- return true;
79
- }
80
- return false;
81
- }
82
- /**
83
- * Attempts to remove all non-essential words & characters from a style block.
84
- * Including selectors and queries
85
- * Adapted from ensure-design-token-usage
86
- * @param styleString string of css properties
87
- */
88
- function splitCssProperties(styleString) {
89
- return styleString.split('\n').filter(function (line) {
90
- return !line.trim().startsWith('@');
91
- }).join('\n').replace(/\n/g, '').split(/;|(?<!\$){|(?<!\${.+?)}/) // don't split on template literal expressions i.e. `${...}`
92
- .map(function (el) {
93
- return el.trim() || '';
94
- }).filter(Boolean);
95
- }
96
15
  var rule = {
97
16
  meta: {
98
17
  type: 'problem',
@@ -102,7 +21,8 @@ var rule = {
102
21
  recommended: true
103
22
  },
104
23
  messages: {
105
- noRawSpacingValues: 'The use of spacing primitives or tokens is preferred over the direct application of spacing properties.\n\n@meta <<{{payload}}>>'
24
+ noRawSpacingValues: 'The use of spacing primitives or tokens is preferred over the direct application of spacing properties.\n\n@meta <<{{payload}}>>',
25
+ autofixesPossible: 'Automated corrections available for spacing values. Apply autofix to replace values with appropriate tokens'
106
26
  }
107
27
  },
108
28
  create: function create(context) {
@@ -146,7 +66,7 @@ var rule = {
146
66
  if (!(0, _eslintCodemodUtils.isNodeOfType)(node.key, 'Identifier')) {
147
67
  return;
148
68
  }
149
- if (!shouldAnalyzeProperty(node.key.name, targetCategories)) {
69
+ if (!(0, _utils.shouldAnalyzeProperty)(node.key.name, targetCategories)) {
150
70
  return;
151
71
  }
152
72
  if ((0, _isNode.isDecendantOfGlobalToken)(node.value)) {
@@ -195,16 +115,16 @@ var rule = {
195
115
  },
196
116
  fix: function fix(fixer) {
197
117
  var _node$loc;
198
- if (!shouldAnalyzeProperty(propertyName, targetCategories)) {
118
+ if (!(0, _utils.shouldAnalyzeProperty)(propertyName, targetCategories)) {
199
119
  return null;
200
120
  }
201
121
  var pixelValueString = "".concat(pixelValue, "px");
202
122
  var lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
203
- var tokenName = (0, _utils.isTypographyProperty)(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
123
+ var tokenName = (0, _utils.isTypographyProperty)(propertyName) ? _utils.typographyValueToToken[propertyName][lookupValue] : _utils.spacingValueToToken[lookupValue];
204
124
  if (!tokenName) {
205
125
  return null;
206
126
  }
207
- var replacementValue = getTokenNodeForValue(propertyName, lookupValue);
127
+ var replacementValue = (0, _utils.getTokenNodeForValue)(propertyName, lookupValue);
208
128
  return [fixer.insertTextBefore(node, "// TODO Delete this comment after verifying spacing token -> previous value `".concat((0, _eslintCodemodUtils.node)(node.value), "`\n").concat(' '.padStart(((_node$loc = node.loc) === null || _node$loc === void 0 ? void 0 : _node$loc.start.column) || 0))), fixer.replaceText(node, (0, _eslintCodemodUtils.property)(_objectSpread(_objectSpread({}, node), {}, {
209
129
  value: replacementValue
210
130
  })).toString())];
@@ -237,7 +157,7 @@ var rule = {
237
157
  return fixer.replaceText(node.value, "`".concat(values.map(function (value) {
238
158
  var pixelValue = (0, _utils.emToPixels)(value, fontSize);
239
159
  var pixelValueString = "".concat(pixelValue, "px");
240
- return "${".concat(getTokenNodeForValue(propertyName, pixelValueString), "}");
160
+ return "${".concat((0, _utils.getTokenNodeForValue)(propertyName, pixelValueString), "}");
241
161
  }).join(' '), "`"));
242
162
  } : undefined
243
163
  });
@@ -253,96 +173,115 @@ var rule = {
253
173
  return;
254
174
  }
255
175
  var parentNode = (0, _utils.findParentNodeForLine)(node);
256
- var combinedString = node.quasi.quasis.map(function (q, i) {
257
- return "".concat(q.value.raw).concat(node.quasi.expressions[i] ? (0, _utils.getValue)(node.quasi.expressions[i], context) : '');
258
- }).join('');
259
- var rawString = node.quasi.quasis.map(function (q, i) {
260
- return "".concat(q.value.raw).concat(node.quasi.expressions[i] ? "${".concat((0, _utils.getRawExpression)(node.quasi.expressions[i], context), "}") : '');
261
- }).join('');
262
- var cssProperties = splitCssProperties(combinedString);
263
- var unalteredCssProperties = splitCssProperties(rawString);
264
-
265
- // Get font size
266
- var fontSizeNode = cssProperties.find(function (style) {
267
- var _style$split = style.split(':'),
268
- _style$split2 = (0, _slicedToArray2.default)(_style$split, 2),
269
- rawProperty = _style$split2[0],
270
- value = _style$split2[1];
271
- return /font-size/.test(rawProperty) ? value : null;
272
- });
273
- var fontSize = (0, _utils.getValueFromShorthand)(fontSizeNode)[0];
274
- cssProperties.forEach(function (style, currentPropIndex) {
275
- var _style$split3 = style.split(':'),
276
- _style$split4 = (0, _slicedToArray2.default)(_style$split3, 2),
277
- rawProperty = _style$split4[0],
278
- value = _style$split4[1];
279
- var propertyName = (0, _utils.convertHyphenatedNameToCamelCase)(rawProperty);
280
- if (!shouldAnalyzeProperty(propertyName, targetCategories)) {
281
- return;
176
+ var processedCssLines = (0, _utils.processCssNode)(node, context);
177
+ var globalFontSize = (0, _utils.getFontSizeValueInScope)(processedCssLines);
178
+ var textForSource = context.getSourceCode().getText(node.quasi);
179
+ var allReplacedValues = [];
180
+ var completeSource = processedCssLines.reduce(function (currentSource, _ref) {
181
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
182
+ resolvedCssLine = _ref2[0],
183
+ originalCssLine = _ref2[1];
184
+ var _resolvedCssLine$spli = resolvedCssLine.split(':'),
185
+ _resolvedCssLine$spli2 = (0, _slicedToArray2.default)(_resolvedCssLine$spli, 2),
186
+ originalProperty = _resolvedCssLine$spli2[0],
187
+ resolvedCssValues = _resolvedCssLine$spli2[1];
188
+ var _originalCssLine$spli = originalCssLine.split(':'),
189
+ _originalCssLine$spli2 = (0, _slicedToArray2.default)(_originalCssLine$spli, 2),
190
+ _ = _originalCssLine$spli2[0],
191
+ originalCssValues = _originalCssLine$spli2[1];
192
+ var propertyName = (0, _utils.convertHyphenatedNameToCamelCase)(originalProperty);
193
+ var isFontFamily = /fontFamily/.test(propertyName);
194
+ var replacedValuesPerProperty = [originalProperty];
195
+ if (!(0, _utils.shouldAnalyzeProperty)(propertyName, targetCategories) || !resolvedCssValues || !(0, _utils.isValidSpacingValue)(resolvedCssValues, globalFontSize)) {
196
+ // in all of these cases no changes should be made to the current property
197
+ return currentSource;
282
198
  }
283
199
 
284
- // value is either NaN or it can't be resolved eg, em, 100% etc...
285
- if (!(0, _utils.isValidSpacingValue)(value, fontSize)) {
286
- return context.report({
287
- node: node,
288
- messageId: 'noRawSpacingValues',
289
- data: {
290
- payload: "NaN:".concat(value)
291
- }
292
- });
293
- }
294
- var values = (0, _utils.getValueFromShorthand)(value);
295
- values.forEach(function (val, index) {
296
- if (!val && val !== 0 || !shouldAnalyzeProperty(propertyName, targetCategories)) {
297
- return;
200
+ // gets the values from the associated property, numeric values or NaN
201
+ var processedNumericValues = (0, _utils.getValueFromShorthand)(resolvedCssValues);
202
+ var processedValues = (0, _utils.splitShorthandValues)(resolvedCssValues);
203
+ // only splits shorthand values but it does not transform NaNs so tokens are preserved
204
+ var originalValues = (0, _utils.splitShorthandValues)(originalCssValues);
205
+
206
+ // reconstructing the string
207
+ // should replace what it can and preserve the raw value for everything else
208
+
209
+ var replacementValue = processedNumericValues
210
+ // put together resolved value and original value on a tuple
211
+ .map(function (value, index) {
212
+ return [
213
+ // if emToPX conversion fails we'll default to original value
214
+ (0, _utils.emToPixels)(value, globalFontSize) || value, processedValues[index], originalValues[index]];
215
+ }).map(function (_ref3) {
216
+ var _ref4 = (0, _slicedToArray2.default)(_ref3, 3),
217
+ numericOrNanValue = _ref4[0],
218
+ pxValue = _ref4[1],
219
+ originalValue = _ref4[2];
220
+ if ((0, _utils.isTokenValueString)(originalValue)) {
221
+ // if the value is already valid, nothing to report or replace
222
+ return originalValue;
223
+ }
224
+ if (isNaN(numericOrNanValue) && !isFontFamily) {
225
+ // this can be either a weird expression or a fontsize declaration
226
+
227
+ // we can't replace a NaN but we can alert what the offending value is
228
+ context.report({
229
+ node: node,
230
+ messageId: 'noRawSpacingValues',
231
+ data: {
232
+ payload: "".concat(propertyName, ":").concat(originalValue)
233
+ }
234
+ });
235
+ return originalValue;
298
236
  }
299
- var isFontFamily = /fontFamily/.test(propertyName);
300
- var pixelValue = isFontFamily ? val : (0, _utils.emToPixels)(val, fontSize);
237
+
238
+ // value is numeric or fontFamily, and needs replacing we'll report first
301
239
  context.report({
302
240
  node: node,
303
241
  messageId: 'noRawSpacingValues',
304
242
  data: {
305
- payload: "".concat(propertyName, ":").concat(pixelValue)
306
- },
307
- fix: index === 0 ? function (fixer) {
308
- var allResolvableValues = values.every(function (value) {
309
- return !Number.isNaN((0, _utils.emToPixels)(value, fontSize));
310
- });
311
- if (!allResolvableValues) {
312
- return null;
313
- }
314
- var replacementValue = values.map(function (value) {
315
- var propertyValue = typeof value === 'string' ? value.trim() : value;
316
- var pixelValue = isFontFamily ? propertyValue : (0, _utils.emToPixels)(propertyValue, fontSize);
317
- var pixelValueString = "".concat(pixelValue, "px");
318
- var lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
319
- var tokenName = (0, _utils.isTypographyProperty)(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
320
- if (!tokenName) {
321
- return pixelValueString;
322
- }
323
- var replacementTokenValue = getTokenNodeForValue(propertyName, lookupValue);
243
+ payload: "".concat(propertyName, ":").concat(numericOrNanValue)
244
+ }
245
+ });
324
246
 
325
- // ${token('...', '...')}
326
- var replacementSubValue = '${' + replacementTokenValue.toString() + '}';
327
- return replacementSubValue;
328
- }).join(' ');
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 replacementToken = (0, _utils.getTokenReplacement)(propertyName, numericOrNanValue);
249
+ if (!replacementToken) {
250
+ return originalValue;
251
+ }
252
+ replacedValuesPerProperty.push(isFontFamily ? numericOrNanValue.trim() : pxValue);
253
+ return replacementToken;
254
+ }).join(' ');
255
+ if (replacedValuesPerProperty.length > 1) {
256
+ // first value is the property name, so it will always have at least 1
257
+ allReplacedValues.push(replacedValuesPerProperty);
258
+ }
329
259
 
330
- // get original source
331
- var textForSource = context.getSourceCode().getText(node.quasi);
260
+ // replace property:val with new property:val
261
+ var replacedCssLine = currentSource.replace(originalCssLine, // padding: ${gridSize()}px;
262
+ "".concat(originalProperty, ": ").concat(replacementValue));
263
+ if (!replacedCssLine) {
264
+ return currentSource;
265
+ }
266
+ return replacedCssLine;
267
+ }, textForSource);
268
+ if (completeSource !== textForSource) {
269
+ // means we found some replacement values, well give the option to fix them
332
270
 
333
- // find `<property>: ...;` in original
334
- var styleString = unalteredCssProperties[currentPropIndex];
335
- // replace property:val with new property:val
336
- var replacement = textForSource.replace(styleString, // padding: ${gridSize()}px;
337
- "".concat(rawProperty, ": ").concat(replacementValue));
338
- if (!replacement) {
339
- return [];
340
- }
341
- return [fixer.insertTextBefore(parentNode, "// TODO Delete this comment after verifying spacing token -> previous value `".concat(value.trim(), "`\n")), fixer.replaceText(node.quasi, replacement)];
342
- } : undefined
343
- });
271
+ var replacementComments = "".concat(allReplacedValues.map(function (replacedProperties) {
272
+ var _replacedProperties = (0, _slicedToArray2.default)(replacedProperties, 1),
273
+ propertyName = _replacedProperties[0];
274
+ var replacedValues = replacedProperties.slice(1).join(' ');
275
+ return "// TODO Delete this comment after verifying spacing token -> previous value `".concat(propertyName, ": ").concat(replacedValues, "`");
276
+ }).join('\n'), "\n");
277
+ context.report({
278
+ node: node,
279
+ messageId: 'autofixesPossible',
280
+ fix: function fix(fixer) {
281
+ return [fixer.insertTextBefore(parentNode, replacementComments), fixer.replaceText(node.quasi, completeSource)];
282
+ }
344
283
  });
345
- });
284
+ }
346
285
  }
347
286
  };
348
287
  }
@@ -6,11 +6,50 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.emToPixels = exports.convertHyphenatedNameToCamelCase = void 0;
8
8
  exports.findIdentifierInParentScope = findIdentifierInParentScope;
9
- exports.removePixelSuffix = exports.isValidSpacingValue = exports.isTypographyProperty = exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = exports.getRawExpression = exports.findParentNodeForLine = void 0;
9
+ exports.findParentNodeForLine = void 0;
10
+ exports.getFontSizeValueInScope = getFontSizeValueInScope;
11
+ exports.getRawExpression = void 0;
12
+ exports.getTokenNodeForValue = getTokenNodeForValue;
13
+ exports.getTokenReplacement = getTokenReplacement;
14
+ exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = void 0;
15
+ exports.isTokenValueString = isTokenValueString;
16
+ exports.onlyScaleTokens = exports.isValidSpacingValue = exports.isTypographyProperty = void 0;
17
+ exports.processCssNode = processCssNode;
18
+ exports.removePixelSuffix = void 0;
19
+ exports.shouldAnalyzeProperty = shouldAnalyzeProperty;
20
+ exports.spacingValueToToken = void 0;
21
+ exports.splitCssProperties = splitCssProperties;
22
+ exports.typographyValueToToken = exports.splitShorthandValues = void 0;
10
23
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
11
24
  var _eslintCodemodUtils = require("eslint-codemod-utils");
25
+ var _tokensRaw = require("@atlaskit/tokens/tokens-raw");
12
26
  var typographyProperties = ['fontSize', 'fontWeight', 'fontFamily', 'lineHeight'];
13
27
  var properties = ['padding', 'paddingBlock', 'paddingInline', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingInline', 'paddingInlineStart', 'paddingInlineEnd', 'paddingBlock', 'paddingBlockStart', 'paddingBlockEnd', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'marginInline', 'marginInlineStart', 'marginInlineEnd', 'marginBlock', 'marginBlockStart', 'marginBlockEnd', 'margin', 'gap', 'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
28
+ /**
29
+ * Currently we have a wide range of experimental spacing tokens that we are testing.
30
+ * We only want transforms to apply to the stable scale values, not the rest.
31
+ * This could be removed in the future.
32
+ */
33
+ var onlyScaleTokens = _tokensRaw.spacing.filter(function (token) {
34
+ return token.name.startsWith('space.');
35
+ });
36
+ exports.onlyScaleTokens = onlyScaleTokens;
37
+ var spacingValueToToken = Object.fromEntries(onlyScaleTokens.map(function (token) {
38
+ return [token.attributes['pixelValue'], token.name];
39
+ }));
40
+ exports.spacingValueToToken = spacingValueToToken;
41
+ var typographyValueToToken = Object.fromEntries(_tokensRaw.typography.map(function (currentToken) {
42
+ // Group tokens by property name (e.g. fontSize, fontFamily, lineHeight)
43
+ // This allows us to look up values specific to a property
44
+ // (so as not to mix tokens with overlapping values e.g. font size and line height both have tokens for 16px)
45
+ var tokenGroup = currentToken.attributes.group;
46
+ return [tokenGroup, Object.fromEntries(_tokensRaw.typography.map(function (token) {
47
+ return token.attributes.group === tokenGroup ? [token.value.replaceAll("\"", "'"), token.name] : [];
48
+ }).filter(function (token) {
49
+ return token.length;
50
+ }))];
51
+ }));
52
+ exports.typographyValueToToken = typographyValueToToken;
14
53
  function findIdentifierInParentScope(_ref) {
15
54
  var scope = _ref.scope,
16
55
  identifierName = _ref.identifierName;
@@ -34,6 +73,11 @@ var isTypographyProperty = function isTypographyProperty(propertyName) {
34
73
  return typographyProperties.includes(propertyName);
35
74
  };
36
75
  exports.isTypographyProperty = isTypographyProperty;
76
+ var splitShorthandValues = function splitShorthandValues(str) {
77
+ // Regex accomplishes split str by whitespace but ignore spaces in between ${}
78
+ return str.split(/(\${[^}]*}\S*)|\s+/g).filter(Boolean);
79
+ };
80
+ exports.splitShorthandValues = splitShorthandValues;
37
81
  var getValueFromShorthand = function getValueFromShorthand(str) {
38
82
  var valueString = String(str);
39
83
  var fontFamily = /(sans-serif$)|(monospace$)/;
@@ -41,9 +85,7 @@ var getValueFromShorthand = function getValueFromShorthand(str) {
41
85
  return [valueString];
42
86
  }
43
87
  // If we want to filter out NaN just add .filter(Boolean)
44
- return String(str).trim().split(' ').filter(function (val) {
45
- return val !== '';
46
- }).map(removePixelSuffix);
88
+ return splitShorthandValues(String(str).trim()).map(removePixelSuffix);
47
89
  };
48
90
  exports.getValueFromShorthand = getValueFromShorthand;
49
91
  var isGridSize = function isGridSize(node) {
@@ -129,7 +171,7 @@ var getRawExpression = function getRawExpression(node, context) {
129
171
  if (!(
130
172
  // if not one of our recognized types or doesn't have a range prop, early return
131
173
 
132
- (0, _eslintCodemodUtils.isNodeOfType)(node, 'Literal') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'Identifier') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'BinaryExpression') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'UnaryExpression') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'TemplateLiteral') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression')) || !Array.isArray(node.range)) {
174
+ (0, _eslintCodemodUtils.isNodeOfType)(node, 'Literal') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'Identifier') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'BinaryExpression') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'UnaryExpression') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'TemplateLiteral') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') || (0, _eslintCodemodUtils.isNodeOfType)(node, 'ArrowFunctionExpression')) || !Array.isArray(node.range)) {
133
175
  return null;
134
176
  }
135
177
  var _node$range = (0, _slicedToArray2.default)(node.range, 2),
@@ -142,6 +184,9 @@ var getValueFromIdentifier = function getValueFromIdentifier(node, context) {
142
184
  if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'Identifier')) {
143
185
  return null;
144
186
  }
187
+ if (node.name === 'gridSize') {
188
+ return 8;
189
+ }
145
190
  var scope = context.getScope();
146
191
  var variable = findIdentifierInParentScope({
147
192
  scope: scope,
@@ -286,4 +331,145 @@ var findParentNodeForLine = function findParentNodeForLine(node) {
286
331
  return findParentNodeForLine(node.parent);
287
332
  }
288
333
  };
289
- exports.findParentNodeForLine = findParentNodeForLine;
334
+
335
+ /**
336
+ * Returns a boolean that signals wether the current property is revelant under the current configuration
337
+ * @param propertyName camelCase CSS property
338
+ * @param targetOptions Array containing the types of properties that should be included in the rule
339
+ * @example
340
+ * ```
341
+ * propertyName: padding, targetOptions: ['spacing']
342
+ * propertyName: fontWeight, targetOptions: ['spacing', 'typography']
343
+ * ```
344
+ */
345
+ exports.findParentNodeForLine = findParentNodeForLine;
346
+ function shouldAnalyzeProperty(propertyName, targetOptions) {
347
+ if (isSpacingProperty(propertyName) && targetOptions.includes('spacing')) {
348
+ return true;
349
+ }
350
+ if (isTypographyProperty(propertyName) && targetOptions.includes('typography')) {
351
+ return true;
352
+ }
353
+ return false;
354
+ }
355
+
356
+ /**
357
+ * Returns an array of tuples representing a processed css within `TaggedTemplateExpression` node.
358
+ * each element of the array is a tuple `[string, string]`,
359
+ * where the first element is the processed css line with computed values
360
+ * and the second element of the tuple is the original css line from source
361
+ * @param node TaggedTemplateExpression node
362
+ * @param context Rule.RuleContext
363
+ * @example
364
+ * ```
365
+ * `[['padding: 8', 'padding: ${gridSize()}'], ['margin: 6', 'margin: 6px' ]]`
366
+ * ```
367
+ */
368
+ function processCssNode(node, context) {
369
+ var combinedString = node.quasi.quasis.map(function (q, i) {
370
+ return "".concat(q.value.raw).concat(node.quasi.expressions[i] ? getValue(node.quasi.expressions[i], context) : '');
371
+ }).join('');
372
+ var rawString = node.quasi.quasis.map(function (q, i) {
373
+ return "".concat(q.value.raw).concat(node.quasi.expressions[i] ? "${".concat(getRawExpression(node.quasi.expressions[i], context), "}") : '');
374
+ }).join('');
375
+ var cssProperties = splitCssProperties(combinedString);
376
+ var unalteredCssProperties = splitCssProperties(rawString);
377
+ return cssProperties.map(function (cssProperty, index) {
378
+ return [cssProperty, unalteredCssProperties[index]];
379
+ });
380
+ }
381
+
382
+ /**
383
+ * Returns a token node for a given value including fallbacks.
384
+ * @param propertyName camelCase CSS property
385
+ * @param value string representing pixel value, or font family, or number representing font weight
386
+ * @example
387
+ * ```
388
+ * propertyName: padding, value: '8px' => token('space.100', '8px')
389
+ * propertyName: fontWeight, value: 400 => token('font.weight.regular', '400')
390
+ * ```
391
+ */
392
+ function getTokenNodeForValue(propertyName, value) {
393
+ var token = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][value] : spacingValueToToken[value];
394
+ var fallbackValue = propertyName === 'fontFamily' ? {
395
+ value: "".concat(value),
396
+ raw: "\"".concat(value, "\"")
397
+ } : "".concat(value);
398
+ return (0, _eslintCodemodUtils.callExpression)({
399
+ callee: (0, _eslintCodemodUtils.identifier)({
400
+ name: 'token'
401
+ }),
402
+ arguments: [(0, _eslintCodemodUtils.literal)({
403
+ value: "'".concat(token !== null && token !== void 0 ? token : '', "'")
404
+ }), (0, _eslintCodemodUtils.literal)(fallbackValue)],
405
+ optional: false
406
+ });
407
+ }
408
+ function getFontSizeValueInScope(cssProperties) {
409
+ var fontSizeNode = cssProperties.find(function (_ref2) {
410
+ var _ref3 = (0, _slicedToArray2.default)(_ref2, 1),
411
+ style = _ref3[0];
412
+ var _style$split = style.split(':'),
413
+ _style$split2 = (0, _slicedToArray2.default)(_style$split, 2),
414
+ rawProperty = _style$split2[0],
415
+ value = _style$split2[1];
416
+ return /font-size/.test(rawProperty) ? value : null;
417
+ });
418
+ if (!fontSizeNode) {
419
+ return undefined;
420
+ }
421
+ var _fontSizeNode$0$split = fontSizeNode[0].split(':'),
422
+ _fontSizeNode$0$split2 = (0, _slicedToArray2.default)(_fontSizeNode$0$split, 2),
423
+ _ = _fontSizeNode$0$split2[0],
424
+ fontSizeValue = _fontSizeNode$0$split2[1];
425
+ if (!fontSizeValue) {
426
+ return undefined;
427
+ }
428
+ return getValueFromShorthand(fontSizeValue)[0];
429
+ }
430
+
431
+ /**
432
+ * Attempts to remove all non-essential words & characters from a style block.
433
+ * Including selectors and queries
434
+ * Adapted from ensure-design-token-usage
435
+ * @param styleString string of css properties
436
+ */
437
+ function splitCssProperties(styleString) {
438
+ return styleString.split('\n').filter(function (line) {
439
+ return !line.trim().startsWith('@');
440
+ }).join('\n').replace(/\n/g, '').split(/;|(?<!\$){|(?<!\${.+?)}/) // don't split on template literal expressions i.e. `${...}`
441
+ .map(function (el) {
442
+ return el.trim() || '';
443
+ }).filter(Boolean);
444
+ }
445
+
446
+ /**
447
+ * returns wether the current string is a token value
448
+ * @param originalVaue string representing a css property value e.g 1em, 12px
449
+ */
450
+ function isTokenValueString(originalValue) {
451
+ return originalValue.startsWith('${token(') && originalValue.endsWith('}');
452
+ }
453
+
454
+ /**
455
+ * Returns a string with token expression corresponding to input parameters
456
+ * if no token found for the pair the function returns undefined
457
+ * @param propertyName string camelCased css property
458
+ * @param value the computed value e.g '8px' -> '8'
459
+ */
460
+ function getTokenReplacement(propertyName, value) {
461
+ var isFontWeightOrFamily = /fontWeight|fontFamily/.test(propertyName);
462
+ var propertyValue = typeof value === 'string' ? value.trim() : value;
463
+ var pixelValue = propertyValue;
464
+ var pixelValueString = "".concat(propertyValue, "px");
465
+ var lookupValue = isFontWeightOrFamily ? pixelValue : pixelValueString;
466
+ var tokenName = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
467
+ if (!tokenName) {
468
+ return undefined;
469
+ }
470
+ var replacementTokenValue = getTokenNodeForValue(propertyName, lookupValue);
471
+
472
+ // ${token('...', '...')}
473
+ var replacementSubValue = '${' + replacementTokenValue.toString() + '}';
474
+ return replacementSubValue;
475
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-design-system",
3
- "version": "4.15.4",
3
+ "version": "4.15.6",
4
4
  "sideEffects": false
5
5
  }