@atlaskit/eslint-plugin-design-system 4.13.6 → 4.13.8
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 +12 -0
- package/dist/cjs/rules/ensure-design-token-usage-spacing/index.js +57 -24
- package/dist/cjs/rules/ensure-design-token-usage-spacing/utils.js +36 -6
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/rules/ensure-design-token-usage-spacing/index.js +54 -25
- package/dist/es2019/rules/ensure-design-token-usage-spacing/utils.js +27 -4
- package/dist/es2019/version.json +1 -1
- package/dist/esm/rules/ensure-design-token-usage-spacing/index.js +58 -25
- package/dist/esm/rules/ensure-design-token-usage-spacing/utils.js +32 -5
- package/dist/esm/version.json +1 -1
- package/dist/types/rules/ensure-design-token-usage-spacing/utils.d.ts +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-design-system
|
|
2
2
|
|
|
3
|
+
## 4.13.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`f4c5d7db7aa`](https://bitbucket.org/atlassian/atlassian-frontend/commits/f4c5d7db7aa) - Updates fix for `ensure-design-token-usage-spacing` to ensure fixes are not applied erroneously.
|
|
8
|
+
|
|
9
|
+
## 4.13.7
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`41ac6cadd32`](https://bitbucket.org/atlassian/atlassian-frontend/commits/41ac6cadd32) - Adds support to the ensure-design-token-usage-spacing rule for replacing typography values with tokens
|
|
14
|
+
|
|
3
15
|
## 4.13.6
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -15,6 +15,8 @@ var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
|
15
15
|
|
|
16
16
|
var _spacingRaw = _interopRequireDefault(require("@atlaskit/tokens/spacing-raw"));
|
|
17
17
|
|
|
18
|
+
var _typographyRaw = _interopRequireDefault(require("@atlaskit/tokens/typography-raw"));
|
|
19
|
+
|
|
18
20
|
var _isNode = require("../utils/is-node");
|
|
19
21
|
|
|
20
22
|
var _utils = require("./utils");
|
|
@@ -35,22 +37,38 @@ var onlyScaleTokens = _spacingRaw.default.filter(function (token) {
|
|
|
35
37
|
var spacingValueToToken = Object.fromEntries(onlyScaleTokens.map(function (token) {
|
|
36
38
|
return [token.attributes['pixelValue'], token.name];
|
|
37
39
|
}));
|
|
40
|
+
var typographyValueToToken = Object.fromEntries(_typographyRaw.default.map(function (currentToken) {
|
|
41
|
+
// Group tokens by property name (e.g. fontSize, fontFamily, lineHeight)
|
|
42
|
+
// This allows us to look up values specific to a property
|
|
43
|
+
// (so as not to mix tokens with overlapping values e.g. font size and line height both have tokens for 16px)
|
|
44
|
+
var tokenGroup = currentToken.attributes.group;
|
|
45
|
+
return [tokenGroup, Object.fromEntries(_typographyRaw.default.map(function (token) {
|
|
46
|
+
return token.attributes.group === tokenGroup ? [token.value.replaceAll("\"", "'"), token.name] : [];
|
|
47
|
+
}).filter(function (token) {
|
|
48
|
+
return token.length;
|
|
49
|
+
}))];
|
|
50
|
+
}));
|
|
38
51
|
/**
|
|
52
|
+
* Returns a token node for a given value including fallbacks.
|
|
53
|
+
* @param propertyName camelCase CSS property
|
|
54
|
+
* @param value string representing pixel value, or font family, or number representing font weight
|
|
39
55
|
* @example
|
|
40
56
|
* ```
|
|
41
|
-
* '8px' => token('spacing.scale.100', '8px')
|
|
57
|
+
* propertyName: padding, value: '8px' => token('spacing.scale.100', '8px')
|
|
58
|
+
* propertyName: fontWeight, value: 400 => token('font.weight.regular', '400')
|
|
42
59
|
* ```
|
|
43
60
|
*/
|
|
44
61
|
|
|
45
|
-
function
|
|
46
|
-
var token = spacingValueToToken[
|
|
62
|
+
function getTokenNodeForValue(propertyName, value) {
|
|
63
|
+
var token = (0, _utils.isTypographyProperty)(propertyName) ? typographyValueToToken[propertyName][value] : spacingValueToToken[value];
|
|
64
|
+
var fallbackValue = propertyName === 'fontFamily' ? "\"".concat(value, "\"") : "'".concat(value, "'");
|
|
47
65
|
return (0, _eslintCodemodUtils.callExpression)({
|
|
48
66
|
callee: (0, _eslintCodemodUtils.identifier)({
|
|
49
67
|
name: 'token'
|
|
50
68
|
}),
|
|
51
69
|
arguments: [(0, _eslintCodemodUtils.literal)({
|
|
52
70
|
value: "'".concat(token !== null && token !== void 0 ? token : '', "'")
|
|
53
|
-
}), (0, _eslintCodemodUtils.literal)(
|
|
71
|
+
}), (0, _eslintCodemodUtils.literal)(fallbackValue)],
|
|
54
72
|
optional: false
|
|
55
73
|
});
|
|
56
74
|
}
|
|
@@ -92,7 +110,7 @@ var rule = {
|
|
|
92
110
|
|
|
93
111
|
return node.key.name === 'fontSize';
|
|
94
112
|
});
|
|
95
|
-
var fontSizeValue = (0, _utils.getValue)( // @ts-
|
|
113
|
+
var fontSizeValue = (0, _utils.getValue)( // @ts-expect-error
|
|
96
114
|
(0, _eslintCodemodUtils.isNodeOfType)(fontSizeNode, 'Property') && fontSizeNode.value, context);
|
|
97
115
|
var fontSize = Array.isArray(fontSizeValue) ? fontSizeValue[0] : fontSizeValue;
|
|
98
116
|
|
|
@@ -132,6 +150,8 @@ var rule = {
|
|
|
132
150
|
return;
|
|
133
151
|
}
|
|
134
152
|
|
|
153
|
+
var propertyName = node.key.name;
|
|
154
|
+
var isFontFamily = /fontFamily/.test(propertyName);
|
|
135
155
|
var value = (0, _utils.getValue)(node.value, context); // value is either NaN or it can't be resolved eg, em, 100% etc...
|
|
136
156
|
|
|
137
157
|
if (!(value && (0, _utils.isValidSpacingValue)(value, fontSize))) {
|
|
@@ -145,34 +165,37 @@ var rule = {
|
|
|
145
165
|
}
|
|
146
166
|
|
|
147
167
|
var values = Array.isArray(value) ? value : [value]; // value is a single value so we can apply a more robust approach to our fix
|
|
168
|
+
// treat fontFamily as having one value
|
|
148
169
|
|
|
149
|
-
if (values.length === 1) {
|
|
170
|
+
if (values.length === 1 || isFontFamily) {
|
|
150
171
|
var _values = (0, _slicedToArray2.default)(values, 1),
|
|
151
172
|
_value = _values[0];
|
|
152
173
|
|
|
153
|
-
var pixelValue = (0, _utils.emToPixels)(_value, fontSize);
|
|
174
|
+
var pixelValue = isFontFamily ? _value : (0, _utils.emToPixels)(_value, fontSize);
|
|
154
175
|
return context.report({
|
|
155
176
|
node: node,
|
|
156
177
|
messageId: 'noRawSpacingValues',
|
|
157
178
|
data: {
|
|
158
|
-
payload: "".concat(
|
|
179
|
+
payload: "".concat(propertyName, ":").concat(pixelValue)
|
|
159
180
|
},
|
|
160
181
|
fix: function fix(fixer) {
|
|
161
182
|
var _node$loc;
|
|
162
183
|
|
|
163
|
-
if (
|
|
184
|
+
if (!(0, _utils.isSpacingProperty)(propertyName)) {
|
|
164
185
|
return null;
|
|
165
186
|
}
|
|
166
187
|
|
|
167
188
|
var pixelValueString = "".concat(pixelValue, "px");
|
|
168
|
-
var
|
|
189
|
+
var lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
|
|
190
|
+
var tokenName = (0, _utils.isTypographyProperty)(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
|
|
169
191
|
|
|
170
192
|
if (!tokenName) {
|
|
171
193
|
return null;
|
|
172
194
|
}
|
|
173
195
|
|
|
196
|
+
var replacementValue = getTokenNodeForValue(propertyName, lookupValue);
|
|
174
197
|
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), {}, {
|
|
175
|
-
value:
|
|
198
|
+
value: replacementValue
|
|
176
199
|
})).toString())];
|
|
177
200
|
}
|
|
178
201
|
});
|
|
@@ -192,7 +215,7 @@ var rule = {
|
|
|
192
215
|
node: node,
|
|
193
216
|
messageId: 'noRawSpacingValues',
|
|
194
217
|
data: {
|
|
195
|
-
payload: "".concat(
|
|
218
|
+
payload: "".concat(propertyName, ":").concat(pixelValue)
|
|
196
219
|
},
|
|
197
220
|
fix: index === 0 ? function (fixer) {
|
|
198
221
|
var allResolvableValues = values.every(function (value) {
|
|
@@ -206,7 +229,7 @@ var rule = {
|
|
|
206
229
|
return fixer.replaceText(node.value, "`".concat(values.map(function (value) {
|
|
207
230
|
var pixelValue = (0, _utils.emToPixels)(value, fontSize);
|
|
208
231
|
var pixelValueString = "".concat(pixelValue, "px");
|
|
209
|
-
return "${".concat(
|
|
232
|
+
return "${".concat(getTokenNodeForValue(propertyName, pixelValueString), "}");
|
|
210
233
|
}).join(' '), "`"));
|
|
211
234
|
} : undefined
|
|
212
235
|
});
|
|
@@ -255,9 +278,9 @@ var rule = {
|
|
|
255
278
|
rawProperty = _style$split4[0],
|
|
256
279
|
value = _style$split4[1];
|
|
257
280
|
|
|
258
|
-
var
|
|
281
|
+
var propertyName = (0, _utils.convertHyphenatedNameToCamelCase)(rawProperty);
|
|
259
282
|
|
|
260
|
-
if (!(0, _utils.isSpacingProperty)(
|
|
283
|
+
if (!(0, _utils.isSpacingProperty)(propertyName)) {
|
|
261
284
|
return;
|
|
262
285
|
} // value is either NaN or it can't be resolved eg, em, 100% etc...
|
|
263
286
|
|
|
@@ -274,16 +297,17 @@ var rule = {
|
|
|
274
297
|
|
|
275
298
|
var values = (0, _utils.getValueFromShorthand)(value);
|
|
276
299
|
values.forEach(function (val, index) {
|
|
277
|
-
if (!val && val !== 0 ||
|
|
300
|
+
if (!val && val !== 0 || !(0, _utils.isSpacingProperty)(propertyName)) {
|
|
278
301
|
return;
|
|
279
302
|
}
|
|
280
303
|
|
|
281
|
-
var
|
|
304
|
+
var isFontFamily = /fontFamily/.test(propertyName);
|
|
305
|
+
var pixelValue = isFontFamily ? val : (0, _utils.emToPixels)(val, fontSize);
|
|
282
306
|
context.report({
|
|
283
307
|
node: node,
|
|
284
308
|
messageId: 'noRawSpacingValues',
|
|
285
309
|
data: {
|
|
286
|
-
payload: "".concat(
|
|
310
|
+
payload: "".concat(propertyName, ":").concat(pixelValue)
|
|
287
311
|
},
|
|
288
312
|
fix: index === 0 ? function (fixer) {
|
|
289
313
|
var allResolvableValues = values.every(function (value) {
|
|
@@ -295,24 +319,33 @@ var rule = {
|
|
|
295
319
|
}
|
|
296
320
|
|
|
297
321
|
var replacementValue = values.map(function (value) {
|
|
298
|
-
var
|
|
322
|
+
var propertyValue = typeof value === 'string' ? value.trim() : value;
|
|
323
|
+
var pixelValue = isFontFamily ? propertyValue : (0, _utils.emToPixels)(propertyValue, fontSize);
|
|
299
324
|
var pixelValueString = "".concat(pixelValue, "px");
|
|
300
|
-
var
|
|
325
|
+
var lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
|
|
326
|
+
var tokenName = (0, _utils.isTypographyProperty)(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
|
|
301
327
|
|
|
302
328
|
if (!tokenName) {
|
|
303
329
|
return pixelValueString;
|
|
304
|
-
}
|
|
330
|
+
}
|
|
305
331
|
|
|
332
|
+
var replacementTokenValue = getTokenNodeForValue(propertyName, lookupValue); // ${token('...', '...')}
|
|
306
333
|
|
|
307
|
-
var replacementSubValue = '${' +
|
|
334
|
+
var replacementSubValue = '${' + replacementTokenValue.toString() + '}';
|
|
308
335
|
return replacementSubValue;
|
|
309
336
|
}).join(' '); // get original source
|
|
310
337
|
|
|
311
338
|
var textForSource = context.getSourceCode().getText(node.quasi); // find `<property>: ...;` in original
|
|
312
339
|
|
|
313
|
-
var searchRegExp = new RegExp(
|
|
340
|
+
var searchRegExp = new RegExp(style, 'g'); // replace property:val with new property:val
|
|
341
|
+
|
|
342
|
+
var replacement = textForSource.replace(searchRegExp, // padding: ${gridSize()}px;
|
|
343
|
+
"".concat(rawProperty, ": ").concat(replacementValue));
|
|
344
|
+
|
|
345
|
+
if (!replacement) {
|
|
346
|
+
return [];
|
|
347
|
+
}
|
|
314
348
|
|
|
315
|
-
var replacement = textForSource.replace(searchRegExp, "".concat(rawProperty, ": ").concat(replacementValue, ";"));
|
|
316
349
|
return [fixer.insertTextBefore(parentNode, "// TODO Delete this comment after verifying spacing token -> previous value `".concat(value.trim(), "`\n")), fixer.replaceText(node.quasi, replacement)];
|
|
317
350
|
} : undefined
|
|
318
351
|
});
|
|
@@ -5,13 +5,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.emToPixels = exports.convertHyphenatedNameToCamelCase = void 0;
|
|
7
7
|
exports.findIdentifierInParentScope = findIdentifierInParentScope;
|
|
8
|
-
exports.removePixelSuffix = exports.isValidSpacingValue = exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = exports.findParentNodeForLine = void 0;
|
|
8
|
+
exports.removePixelSuffix = exports.isValidSpacingValue = exports.isTypographyProperty = exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = exports.findParentNodeForLine = void 0;
|
|
9
9
|
|
|
10
10
|
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var typographyProperties = ['fontSize', 'fontWeight', 'fontFamily', 'lineHeight'];
|
|
13
|
+
var properties = ['padding', 'paddingBlock', 'paddingInline', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap'].concat(typographyProperties, [// 'width', re-enable later
|
|
13
14
|
// 'height', re-enable later
|
|
14
|
-
'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
|
|
15
|
+
'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap']);
|
|
15
16
|
|
|
16
17
|
function findIdentifierInParentScope(_ref) {
|
|
17
18
|
var scope = _ref.scope,
|
|
@@ -33,14 +34,27 @@ function findIdentifierInParentScope(_ref) {
|
|
|
33
34
|
return null;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
var isSpacingProperty = function isSpacingProperty(
|
|
37
|
-
return properties.includes(
|
|
37
|
+
var isSpacingProperty = function isSpacingProperty(propertyName) {
|
|
38
|
+
return properties.includes(propertyName);
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
exports.isSpacingProperty = isSpacingProperty;
|
|
41
42
|
|
|
43
|
+
var isTypographyProperty = function isTypographyProperty(propertyName) {
|
|
44
|
+
return typographyProperties.includes(propertyName);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
exports.isTypographyProperty = isTypographyProperty;
|
|
48
|
+
|
|
42
49
|
var getValueFromShorthand = function getValueFromShorthand(str) {
|
|
43
|
-
|
|
50
|
+
var valueString = String(str);
|
|
51
|
+
var fontFamily = /(sans-serif$)|(monospace$)/;
|
|
52
|
+
|
|
53
|
+
if (fontFamily.test(valueString)) {
|
|
54
|
+
return [valueString];
|
|
55
|
+
} // If we want to filter out NaN just add .filter(Boolean)
|
|
56
|
+
|
|
57
|
+
|
|
44
58
|
return String(str).trim().split(' ').filter(function (val) {
|
|
45
59
|
return val !== '';
|
|
46
60
|
}).map(removePixelSuffix);
|
|
@@ -60,6 +74,14 @@ var isFontSizeSmall = function isFontSizeSmall(node) {
|
|
|
60
74
|
return (0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') && (0, _eslintCodemodUtils.isNodeOfType)(node.callee, 'Identifier') && node.callee.name === 'fontSizeSmall';
|
|
61
75
|
};
|
|
62
76
|
|
|
77
|
+
var isFontFamily = function isFontFamily(node) {
|
|
78
|
+
return (0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') && (0, _eslintCodemodUtils.isNodeOfType)(node.callee, 'Identifier') && (node.callee.name === 'fontFamily' || node.callee.name === 'getFontFamily');
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
var isCodeFontFamily = function isCodeFontFamily(node) {
|
|
82
|
+
return (0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') && (0, _eslintCodemodUtils.isNodeOfType)(node.callee, 'Identifier') && (node.callee.name === 'codeFontFamily' || node.callee.name === 'getCodeFontFamily');
|
|
83
|
+
};
|
|
84
|
+
|
|
63
85
|
var isToken = function isToken(node) {
|
|
64
86
|
return (0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') && (0, _eslintCodemodUtils.isNodeOfType)(node.callee, 'Identifier') && node.callee.name === 'token';
|
|
65
87
|
};
|
|
@@ -81,6 +103,14 @@ var getValueFromCallExpression = function getValueFromCallExpression(node, conte
|
|
|
81
103
|
return 11;
|
|
82
104
|
}
|
|
83
105
|
|
|
106
|
+
if (isFontFamily(node)) {
|
|
107
|
+
return "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (isCodeFontFamily(node)) {
|
|
111
|
+
return "'SFMono-Medium', 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace";
|
|
112
|
+
}
|
|
113
|
+
|
|
84
114
|
if (isToken(node)) {
|
|
85
115
|
var args = node.arguments;
|
|
86
116
|
var call = "${token(".concat(args.map(function (argNode) {
|
package/dist/cjs/version.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
/* eslint-disable @atlassian/tangerine/import/entry-points */
|
|
1
2
|
import { callExpression, identifier, isNodeOfType, literal, node as nodeFn, property } from 'eslint-codemod-utils';
|
|
2
3
|
import spacingScale from '@atlaskit/tokens/spacing-raw';
|
|
4
|
+
import typographyTokens from '@atlaskit/tokens/typography-raw';
|
|
3
5
|
import { isDecendantOfGlobalToken } from '../utils/is-node';
|
|
4
|
-
import { convertHyphenatedNameToCamelCase, emToPixels, findParentNodeForLine, getValue, getValueFromShorthand, isSpacingProperty, isValidSpacingValue } from './utils';
|
|
6
|
+
import { convertHyphenatedNameToCamelCase, emToPixels, findParentNodeForLine, getValue, getValueFromShorthand, isSpacingProperty, isTypographyProperty, isValidSpacingValue } from './utils';
|
|
5
7
|
/**
|
|
6
8
|
* Currently we have a wide range of experimental spacing tokens that we are testing.
|
|
7
9
|
* We only want transforms to apply to the stable scale values, not the rest.
|
|
@@ -10,22 +12,34 @@ import { convertHyphenatedNameToCamelCase, emToPixels, findParentNodeForLine, ge
|
|
|
10
12
|
|
|
11
13
|
const onlyScaleTokens = spacingScale.filter(token => token.name.startsWith('space.'));
|
|
12
14
|
const spacingValueToToken = Object.fromEntries(onlyScaleTokens.map(token => [token.attributes['pixelValue'], token.name]));
|
|
15
|
+
const typographyValueToToken = Object.fromEntries(typographyTokens.map(currentToken => {
|
|
16
|
+
// Group tokens by property name (e.g. fontSize, fontFamily, lineHeight)
|
|
17
|
+
// This allows us to look up values specific to a property
|
|
18
|
+
// (so as not to mix tokens with overlapping values e.g. font size and line height both have tokens for 16px)
|
|
19
|
+
const tokenGroup = currentToken.attributes.group;
|
|
20
|
+
return [tokenGroup, Object.fromEntries(typographyTokens.map(token => token.attributes.group === tokenGroup ? [token.value.replaceAll(`"`, `'`), token.name] : []).filter(token => token.length))];
|
|
21
|
+
}));
|
|
13
22
|
/**
|
|
23
|
+
* Returns a token node for a given value including fallbacks.
|
|
24
|
+
* @param propertyName camelCase CSS property
|
|
25
|
+
* @param value string representing pixel value, or font family, or number representing font weight
|
|
14
26
|
* @example
|
|
15
27
|
* ```
|
|
16
|
-
* '8px' => token('spacing.scale.100', '8px')
|
|
28
|
+
* propertyName: padding, value: '8px' => token('spacing.scale.100', '8px')
|
|
29
|
+
* propertyName: fontWeight, value: 400 => token('font.weight.regular', '400')
|
|
17
30
|
* ```
|
|
18
31
|
*/
|
|
19
32
|
|
|
20
|
-
function
|
|
21
|
-
const token = spacingValueToToken[
|
|
33
|
+
function getTokenNodeForValue(propertyName, value) {
|
|
34
|
+
const token = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][value] : spacingValueToToken[value];
|
|
35
|
+
const fallbackValue = propertyName === 'fontFamily' ? `"${value}"` : `'${value}'`;
|
|
22
36
|
return callExpression({
|
|
23
37
|
callee: identifier({
|
|
24
38
|
name: 'token'
|
|
25
39
|
}),
|
|
26
40
|
arguments: [literal({
|
|
27
41
|
value: `'${token !== null && token !== void 0 ? token : ''}'`
|
|
28
|
-
}), literal(
|
|
42
|
+
}), literal(fallbackValue)],
|
|
29
43
|
optional: false
|
|
30
44
|
});
|
|
31
45
|
}
|
|
@@ -68,7 +82,7 @@ const rule = {
|
|
|
68
82
|
|
|
69
83
|
return node.key.name === 'fontSize';
|
|
70
84
|
});
|
|
71
|
-
const fontSizeValue = getValue( // @ts-
|
|
85
|
+
const fontSizeValue = getValue( // @ts-expect-error
|
|
72
86
|
isNodeOfType(fontSizeNode, 'Property') && fontSizeNode.value, context);
|
|
73
87
|
const fontSize = Array.isArray(fontSizeValue) ? fontSizeValue[0] : fontSizeValue;
|
|
74
88
|
|
|
@@ -108,6 +122,8 @@ const rule = {
|
|
|
108
122
|
return;
|
|
109
123
|
}
|
|
110
124
|
|
|
125
|
+
const propertyName = node.key.name;
|
|
126
|
+
const isFontFamily = /fontFamily/.test(propertyName);
|
|
111
127
|
const value = getValue(node.value, context); // value is either NaN or it can't be resolved eg, em, 100% etc...
|
|
112
128
|
|
|
113
129
|
if (!(value && isValidSpacingValue(value, fontSize))) {
|
|
@@ -121,32 +137,35 @@ const rule = {
|
|
|
121
137
|
}
|
|
122
138
|
|
|
123
139
|
const values = Array.isArray(value) ? value : [value]; // value is a single value so we can apply a more robust approach to our fix
|
|
140
|
+
// treat fontFamily as having one value
|
|
124
141
|
|
|
125
|
-
if (values.length === 1) {
|
|
142
|
+
if (values.length === 1 || isFontFamily) {
|
|
126
143
|
const [value] = values;
|
|
127
|
-
const pixelValue = emToPixels(value, fontSize);
|
|
144
|
+
const pixelValue = isFontFamily ? value : emToPixels(value, fontSize);
|
|
128
145
|
return context.report({
|
|
129
146
|
node,
|
|
130
147
|
messageId: 'noRawSpacingValues',
|
|
131
148
|
data: {
|
|
132
|
-
payload: `${
|
|
149
|
+
payload: `${propertyName}:${pixelValue}`
|
|
133
150
|
},
|
|
134
151
|
fix: fixer => {
|
|
135
152
|
var _node$loc;
|
|
136
153
|
|
|
137
|
-
if (
|
|
154
|
+
if (!isSpacingProperty(propertyName)) {
|
|
138
155
|
return null;
|
|
139
156
|
}
|
|
140
157
|
|
|
141
158
|
const pixelValueString = `${pixelValue}px`;
|
|
142
|
-
const
|
|
159
|
+
const lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
|
|
160
|
+
const tokenName = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
|
|
143
161
|
|
|
144
162
|
if (!tokenName) {
|
|
145
163
|
return null;
|
|
146
164
|
}
|
|
147
165
|
|
|
166
|
+
const replacementValue = getTokenNodeForValue(propertyName, lookupValue);
|
|
148
167
|
return [fixer.insertTextBefore(node, `// TODO Delete this comment after verifying spacing token -> previous value \`${nodeFn(node.value)}\`\n${' '.padStart(((_node$loc = node.loc) === null || _node$loc === void 0 ? void 0 : _node$loc.start.column) || 0)}`), fixer.replaceText(node, property({ ...node,
|
|
149
|
-
value:
|
|
168
|
+
value: replacementValue
|
|
150
169
|
}).toString())];
|
|
151
170
|
}
|
|
152
171
|
});
|
|
@@ -166,7 +185,7 @@ const rule = {
|
|
|
166
185
|
node,
|
|
167
186
|
messageId: 'noRawSpacingValues',
|
|
168
187
|
data: {
|
|
169
|
-
payload: `${
|
|
188
|
+
payload: `${propertyName}:${pixelValue}`
|
|
170
189
|
},
|
|
171
190
|
fix: index === 0 ? fixer => {
|
|
172
191
|
const allResolvableValues = values.every(value => !Number.isNaN(emToPixels(value, fontSize)));
|
|
@@ -178,7 +197,7 @@ const rule = {
|
|
|
178
197
|
return fixer.replaceText(node.value, `\`${values.map(value => {
|
|
179
198
|
const pixelValue = emToPixels(value, fontSize);
|
|
180
199
|
const pixelValueString = `${pixelValue}px`;
|
|
181
|
-
return `\${${
|
|
200
|
+
return `\${${getTokenNodeForValue(propertyName, pixelValueString)}}`;
|
|
182
201
|
}).join(' ')}\``);
|
|
183
202
|
} : undefined
|
|
184
203
|
});
|
|
@@ -215,9 +234,9 @@ const rule = {
|
|
|
215
234
|
const fontSize = getValueFromShorthand(fontSizeNode)[0];
|
|
216
235
|
cssProperties.forEach(style => {
|
|
217
236
|
const [rawProperty, value] = style.split(':');
|
|
218
|
-
const
|
|
237
|
+
const propertyName = convertHyphenatedNameToCamelCase(rawProperty);
|
|
219
238
|
|
|
220
|
-
if (!isSpacingProperty(
|
|
239
|
+
if (!isSpacingProperty(propertyName)) {
|
|
221
240
|
return;
|
|
222
241
|
} // value is either NaN or it can't be resolved eg, em, 100% etc...
|
|
223
242
|
|
|
@@ -234,16 +253,17 @@ const rule = {
|
|
|
234
253
|
|
|
235
254
|
const values = getValueFromShorthand(value);
|
|
236
255
|
values.forEach((val, index) => {
|
|
237
|
-
if (!val && val !== 0 ||
|
|
256
|
+
if (!val && val !== 0 || !isSpacingProperty(propertyName)) {
|
|
238
257
|
return;
|
|
239
258
|
}
|
|
240
259
|
|
|
241
|
-
const
|
|
260
|
+
const isFontFamily = /fontFamily/.test(propertyName);
|
|
261
|
+
const pixelValue = isFontFamily ? val : emToPixels(val, fontSize);
|
|
242
262
|
context.report({
|
|
243
263
|
node,
|
|
244
264
|
messageId: 'noRawSpacingValues',
|
|
245
265
|
data: {
|
|
246
|
-
payload: `${
|
|
266
|
+
payload: `${propertyName}:${pixelValue}`
|
|
247
267
|
},
|
|
248
268
|
fix: index === 0 ? fixer => {
|
|
249
269
|
const allResolvableValues = values.every(value => !Number.isNaN(emToPixels(value, fontSize)));
|
|
@@ -253,24 +273,33 @@ const rule = {
|
|
|
253
273
|
}
|
|
254
274
|
|
|
255
275
|
const replacementValue = values.map(value => {
|
|
256
|
-
const
|
|
276
|
+
const propertyValue = typeof value === 'string' ? value.trim() : value;
|
|
277
|
+
const pixelValue = isFontFamily ? propertyValue : emToPixels(propertyValue, fontSize);
|
|
257
278
|
const pixelValueString = `${pixelValue}px`;
|
|
258
|
-
const
|
|
279
|
+
const lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
|
|
280
|
+
const tokenName = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
|
|
259
281
|
|
|
260
282
|
if (!tokenName) {
|
|
261
283
|
return pixelValueString;
|
|
262
|
-
}
|
|
284
|
+
}
|
|
263
285
|
|
|
286
|
+
const replacementTokenValue = getTokenNodeForValue(propertyName, lookupValue); // ${token('...', '...')}
|
|
264
287
|
|
|
265
|
-
const replacementSubValue = '${' +
|
|
288
|
+
const replacementSubValue = '${' + replacementTokenValue.toString() + '}';
|
|
266
289
|
return replacementSubValue;
|
|
267
290
|
}).join(' '); // get original source
|
|
268
291
|
|
|
269
292
|
const textForSource = context.getSourceCode().getText(node.quasi); // find `<property>: ...;` in original
|
|
270
293
|
|
|
271
|
-
const searchRegExp = new RegExp(
|
|
294
|
+
const searchRegExp = new RegExp(style, 'g'); // replace property:val with new property:val
|
|
295
|
+
|
|
296
|
+
const replacement = textForSource.replace(searchRegExp, // padding: ${gridSize()}px;
|
|
297
|
+
`${rawProperty}: ${replacementValue}`);
|
|
298
|
+
|
|
299
|
+
if (!replacement) {
|
|
300
|
+
return [];
|
|
301
|
+
}
|
|
272
302
|
|
|
273
|
-
const replacement = textForSource.replace(searchRegExp, `${rawProperty}: ${replacementValue};`);
|
|
274
303
|
return [fixer.insertTextBefore(parentNode, `// TODO Delete this comment after verifying spacing token -> previous value \`${value.trim()}\`\n`), fixer.replaceText(node.quasi, replacement)];
|
|
275
304
|
} : undefined
|
|
276
305
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
-
const
|
|
2
|
+
const typographyProperties = ['fontSize', 'fontWeight', 'fontFamily', 'lineHeight'];
|
|
3
|
+
const properties = ['padding', 'paddingBlock', 'paddingInline', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', ...typographyProperties, // 'width', re-enable later
|
|
3
4
|
// 'height', re-enable later
|
|
4
5
|
'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
|
|
5
6
|
export function findIdentifierInParentScope({
|
|
@@ -20,11 +21,21 @@ export function findIdentifierInParentScope({
|
|
|
20
21
|
|
|
21
22
|
return null;
|
|
22
23
|
}
|
|
23
|
-
export const isSpacingProperty =
|
|
24
|
-
return properties.includes(
|
|
24
|
+
export const isSpacingProperty = propertyName => {
|
|
25
|
+
return properties.includes(propertyName);
|
|
26
|
+
};
|
|
27
|
+
export const isTypographyProperty = propertyName => {
|
|
28
|
+
return typographyProperties.includes(propertyName);
|
|
25
29
|
};
|
|
26
30
|
export const getValueFromShorthand = str => {
|
|
27
|
-
|
|
31
|
+
const valueString = String(str);
|
|
32
|
+
const fontFamily = /(sans-serif$)|(monospace$)/;
|
|
33
|
+
|
|
34
|
+
if (fontFamily.test(valueString)) {
|
|
35
|
+
return [valueString];
|
|
36
|
+
} // If we want to filter out NaN just add .filter(Boolean)
|
|
37
|
+
|
|
38
|
+
|
|
28
39
|
return String(str).trim().split(' ').filter(val => val !== '').map(removePixelSuffix);
|
|
29
40
|
};
|
|
30
41
|
|
|
@@ -34,6 +45,10 @@ const isFontSize = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(
|
|
|
34
45
|
|
|
35
46
|
const isFontSizeSmall = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && node.callee.name === 'fontSizeSmall';
|
|
36
47
|
|
|
48
|
+
const isFontFamily = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && (node.callee.name === 'fontFamily' || node.callee.name === 'getFontFamily');
|
|
49
|
+
|
|
50
|
+
const isCodeFontFamily = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && (node.callee.name === 'codeFontFamily' || node.callee.name === 'getCodeFontFamily');
|
|
51
|
+
|
|
37
52
|
const isToken = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && node.callee.name === 'token';
|
|
38
53
|
|
|
39
54
|
const getValueFromCallExpression = (node, context) => {
|
|
@@ -53,6 +68,14 @@ const getValueFromCallExpression = (node, context) => {
|
|
|
53
68
|
return 11;
|
|
54
69
|
}
|
|
55
70
|
|
|
71
|
+
if (isFontFamily(node)) {
|
|
72
|
+
return `-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (isCodeFontFamily(node)) {
|
|
76
|
+
return `'SFMono-Medium', 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace`;
|
|
77
|
+
}
|
|
78
|
+
|
|
56
79
|
if (isToken(node)) {
|
|
57
80
|
const args = node.arguments;
|
|
58
81
|
const call = `\${token(${args.map(argNode => {
|
package/dist/es2019/version.json
CHANGED
|
@@ -5,10 +5,12 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
|
|
|
5
5
|
|
|
6
6
|
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) { _defineProperty(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; }
|
|
7
7
|
|
|
8
|
+
/* eslint-disable @atlassian/tangerine/import/entry-points */
|
|
8
9
|
import { callExpression, identifier, isNodeOfType, literal, node as nodeFn, property } from 'eslint-codemod-utils';
|
|
9
10
|
import spacingScale from '@atlaskit/tokens/spacing-raw';
|
|
11
|
+
import typographyTokens from '@atlaskit/tokens/typography-raw';
|
|
10
12
|
import { isDecendantOfGlobalToken } from '../utils/is-node';
|
|
11
|
-
import { convertHyphenatedNameToCamelCase, emToPixels, findParentNodeForLine, getValue, getValueFromShorthand, isSpacingProperty, isValidSpacingValue } from './utils';
|
|
13
|
+
import { convertHyphenatedNameToCamelCase, emToPixels, findParentNodeForLine, getValue, getValueFromShorthand, isSpacingProperty, isTypographyProperty, isValidSpacingValue } from './utils';
|
|
12
14
|
/**
|
|
13
15
|
* Currently we have a wide range of experimental spacing tokens that we are testing.
|
|
14
16
|
* We only want transforms to apply to the stable scale values, not the rest.
|
|
@@ -21,22 +23,38 @@ var onlyScaleTokens = spacingScale.filter(function (token) {
|
|
|
21
23
|
var spacingValueToToken = Object.fromEntries(onlyScaleTokens.map(function (token) {
|
|
22
24
|
return [token.attributes['pixelValue'], token.name];
|
|
23
25
|
}));
|
|
26
|
+
var typographyValueToToken = Object.fromEntries(typographyTokens.map(function (currentToken) {
|
|
27
|
+
// Group tokens by property name (e.g. fontSize, fontFamily, lineHeight)
|
|
28
|
+
// This allows us to look up values specific to a property
|
|
29
|
+
// (so as not to mix tokens with overlapping values e.g. font size and line height both have tokens for 16px)
|
|
30
|
+
var tokenGroup = currentToken.attributes.group;
|
|
31
|
+
return [tokenGroup, Object.fromEntries(typographyTokens.map(function (token) {
|
|
32
|
+
return token.attributes.group === tokenGroup ? [token.value.replaceAll("\"", "'"), token.name] : [];
|
|
33
|
+
}).filter(function (token) {
|
|
34
|
+
return token.length;
|
|
35
|
+
}))];
|
|
36
|
+
}));
|
|
24
37
|
/**
|
|
38
|
+
* Returns a token node for a given value including fallbacks.
|
|
39
|
+
* @param propertyName camelCase CSS property
|
|
40
|
+
* @param value string representing pixel value, or font family, or number representing font weight
|
|
25
41
|
* @example
|
|
26
42
|
* ```
|
|
27
|
-
* '8px' => token('spacing.scale.100', '8px')
|
|
43
|
+
* propertyName: padding, value: '8px' => token('spacing.scale.100', '8px')
|
|
44
|
+
* propertyName: fontWeight, value: 400 => token('font.weight.regular', '400')
|
|
28
45
|
* ```
|
|
29
46
|
*/
|
|
30
47
|
|
|
31
|
-
function
|
|
32
|
-
var token = spacingValueToToken[
|
|
48
|
+
function getTokenNodeForValue(propertyName, value) {
|
|
49
|
+
var token = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][value] : spacingValueToToken[value];
|
|
50
|
+
var fallbackValue = propertyName === 'fontFamily' ? "\"".concat(value, "\"") : "'".concat(value, "'");
|
|
33
51
|
return callExpression({
|
|
34
52
|
callee: identifier({
|
|
35
53
|
name: 'token'
|
|
36
54
|
}),
|
|
37
55
|
arguments: [literal({
|
|
38
56
|
value: "'".concat(token !== null && token !== void 0 ? token : '', "'")
|
|
39
|
-
}), literal(
|
|
57
|
+
}), literal(fallbackValue)],
|
|
40
58
|
optional: false
|
|
41
59
|
});
|
|
42
60
|
}
|
|
@@ -78,7 +96,7 @@ var rule = {
|
|
|
78
96
|
|
|
79
97
|
return node.key.name === 'fontSize';
|
|
80
98
|
});
|
|
81
|
-
var fontSizeValue = getValue( // @ts-
|
|
99
|
+
var fontSizeValue = getValue( // @ts-expect-error
|
|
82
100
|
isNodeOfType(fontSizeNode, 'Property') && fontSizeNode.value, context);
|
|
83
101
|
var fontSize = Array.isArray(fontSizeValue) ? fontSizeValue[0] : fontSizeValue;
|
|
84
102
|
|
|
@@ -118,6 +136,8 @@ var rule = {
|
|
|
118
136
|
return;
|
|
119
137
|
}
|
|
120
138
|
|
|
139
|
+
var propertyName = node.key.name;
|
|
140
|
+
var isFontFamily = /fontFamily/.test(propertyName);
|
|
121
141
|
var value = getValue(node.value, context); // value is either NaN or it can't be resolved eg, em, 100% etc...
|
|
122
142
|
|
|
123
143
|
if (!(value && isValidSpacingValue(value, fontSize))) {
|
|
@@ -131,34 +151,37 @@ var rule = {
|
|
|
131
151
|
}
|
|
132
152
|
|
|
133
153
|
var values = Array.isArray(value) ? value : [value]; // value is a single value so we can apply a more robust approach to our fix
|
|
154
|
+
// treat fontFamily as having one value
|
|
134
155
|
|
|
135
|
-
if (values.length === 1) {
|
|
156
|
+
if (values.length === 1 || isFontFamily) {
|
|
136
157
|
var _values = _slicedToArray(values, 1),
|
|
137
158
|
_value = _values[0];
|
|
138
159
|
|
|
139
|
-
var pixelValue = emToPixels(_value, fontSize);
|
|
160
|
+
var pixelValue = isFontFamily ? _value : emToPixels(_value, fontSize);
|
|
140
161
|
return context.report({
|
|
141
162
|
node: node,
|
|
142
163
|
messageId: 'noRawSpacingValues',
|
|
143
164
|
data: {
|
|
144
|
-
payload: "".concat(
|
|
165
|
+
payload: "".concat(propertyName, ":").concat(pixelValue)
|
|
145
166
|
},
|
|
146
167
|
fix: function fix(fixer) {
|
|
147
168
|
var _node$loc;
|
|
148
169
|
|
|
149
|
-
if (
|
|
170
|
+
if (!isSpacingProperty(propertyName)) {
|
|
150
171
|
return null;
|
|
151
172
|
}
|
|
152
173
|
|
|
153
174
|
var pixelValueString = "".concat(pixelValue, "px");
|
|
154
|
-
var
|
|
175
|
+
var lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
|
|
176
|
+
var tokenName = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
|
|
155
177
|
|
|
156
178
|
if (!tokenName) {
|
|
157
179
|
return null;
|
|
158
180
|
}
|
|
159
181
|
|
|
182
|
+
var replacementValue = getTokenNodeForValue(propertyName, lookupValue);
|
|
160
183
|
return [fixer.insertTextBefore(node, "// TODO Delete this comment after verifying spacing token -> previous value `".concat(nodeFn(node.value), "`\n").concat(' '.padStart(((_node$loc = node.loc) === null || _node$loc === void 0 ? void 0 : _node$loc.start.column) || 0))), fixer.replaceText(node, property(_objectSpread(_objectSpread({}, node), {}, {
|
|
161
|
-
value:
|
|
184
|
+
value: replacementValue
|
|
162
185
|
})).toString())];
|
|
163
186
|
}
|
|
164
187
|
});
|
|
@@ -178,7 +201,7 @@ var rule = {
|
|
|
178
201
|
node: node,
|
|
179
202
|
messageId: 'noRawSpacingValues',
|
|
180
203
|
data: {
|
|
181
|
-
payload: "".concat(
|
|
204
|
+
payload: "".concat(propertyName, ":").concat(pixelValue)
|
|
182
205
|
},
|
|
183
206
|
fix: index === 0 ? function (fixer) {
|
|
184
207
|
var allResolvableValues = values.every(function (value) {
|
|
@@ -192,7 +215,7 @@ var rule = {
|
|
|
192
215
|
return fixer.replaceText(node.value, "`".concat(values.map(function (value) {
|
|
193
216
|
var pixelValue = emToPixels(value, fontSize);
|
|
194
217
|
var pixelValueString = "".concat(pixelValue, "px");
|
|
195
|
-
return "${".concat(
|
|
218
|
+
return "${".concat(getTokenNodeForValue(propertyName, pixelValueString), "}");
|
|
196
219
|
}).join(' '), "`"));
|
|
197
220
|
} : undefined
|
|
198
221
|
});
|
|
@@ -241,9 +264,9 @@ var rule = {
|
|
|
241
264
|
rawProperty = _style$split4[0],
|
|
242
265
|
value = _style$split4[1];
|
|
243
266
|
|
|
244
|
-
var
|
|
267
|
+
var propertyName = convertHyphenatedNameToCamelCase(rawProperty);
|
|
245
268
|
|
|
246
|
-
if (!isSpacingProperty(
|
|
269
|
+
if (!isSpacingProperty(propertyName)) {
|
|
247
270
|
return;
|
|
248
271
|
} // value is either NaN or it can't be resolved eg, em, 100% etc...
|
|
249
272
|
|
|
@@ -260,16 +283,17 @@ var rule = {
|
|
|
260
283
|
|
|
261
284
|
var values = getValueFromShorthand(value);
|
|
262
285
|
values.forEach(function (val, index) {
|
|
263
|
-
if (!val && val !== 0 ||
|
|
286
|
+
if (!val && val !== 0 || !isSpacingProperty(propertyName)) {
|
|
264
287
|
return;
|
|
265
288
|
}
|
|
266
289
|
|
|
267
|
-
var
|
|
290
|
+
var isFontFamily = /fontFamily/.test(propertyName);
|
|
291
|
+
var pixelValue = isFontFamily ? val : emToPixels(val, fontSize);
|
|
268
292
|
context.report({
|
|
269
293
|
node: node,
|
|
270
294
|
messageId: 'noRawSpacingValues',
|
|
271
295
|
data: {
|
|
272
|
-
payload: "".concat(
|
|
296
|
+
payload: "".concat(propertyName, ":").concat(pixelValue)
|
|
273
297
|
},
|
|
274
298
|
fix: index === 0 ? function (fixer) {
|
|
275
299
|
var allResolvableValues = values.every(function (value) {
|
|
@@ -281,24 +305,33 @@ var rule = {
|
|
|
281
305
|
}
|
|
282
306
|
|
|
283
307
|
var replacementValue = values.map(function (value) {
|
|
284
|
-
var
|
|
308
|
+
var propertyValue = typeof value === 'string' ? value.trim() : value;
|
|
309
|
+
var pixelValue = isFontFamily ? propertyValue : emToPixels(propertyValue, fontSize);
|
|
285
310
|
var pixelValueString = "".concat(pixelValue, "px");
|
|
286
|
-
var
|
|
311
|
+
var lookupValue = /fontWeight|fontFamily/.test(propertyName) ? pixelValue : pixelValueString;
|
|
312
|
+
var tokenName = isTypographyProperty(propertyName) ? typographyValueToToken[propertyName][lookupValue] : spacingValueToToken[lookupValue];
|
|
287
313
|
|
|
288
314
|
if (!tokenName) {
|
|
289
315
|
return pixelValueString;
|
|
290
|
-
}
|
|
316
|
+
}
|
|
291
317
|
|
|
318
|
+
var replacementTokenValue = getTokenNodeForValue(propertyName, lookupValue); // ${token('...', '...')}
|
|
292
319
|
|
|
293
|
-
var replacementSubValue = '${' +
|
|
320
|
+
var replacementSubValue = '${' + replacementTokenValue.toString() + '}';
|
|
294
321
|
return replacementSubValue;
|
|
295
322
|
}).join(' '); // get original source
|
|
296
323
|
|
|
297
324
|
var textForSource = context.getSourceCode().getText(node.quasi); // find `<property>: ...;` in original
|
|
298
325
|
|
|
299
|
-
var searchRegExp = new RegExp(
|
|
326
|
+
var searchRegExp = new RegExp(style, 'g'); // replace property:val with new property:val
|
|
327
|
+
|
|
328
|
+
var replacement = textForSource.replace(searchRegExp, // padding: ${gridSize()}px;
|
|
329
|
+
"".concat(rawProperty, ": ").concat(replacementValue));
|
|
330
|
+
|
|
331
|
+
if (!replacement) {
|
|
332
|
+
return [];
|
|
333
|
+
}
|
|
300
334
|
|
|
301
|
-
var replacement = textForSource.replace(searchRegExp, "".concat(rawProperty, ": ").concat(replacementValue, ";"));
|
|
302
335
|
return [fixer.insertTextBefore(parentNode, "// TODO Delete this comment after verifying spacing token -> previous value `".concat(value.trim(), "`\n")), fixer.replaceText(node.quasi, replacement)];
|
|
303
336
|
} : undefined
|
|
304
337
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
-
var
|
|
2
|
+
var typographyProperties = ['fontSize', 'fontWeight', 'fontFamily', 'lineHeight'];
|
|
3
|
+
var properties = ['padding', 'paddingBlock', 'paddingInline', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap'].concat(typographyProperties, [// 'width', re-enable later
|
|
3
4
|
// 'height', re-enable later
|
|
4
|
-
'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
|
|
5
|
+
'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap']);
|
|
5
6
|
export function findIdentifierInParentScope(_ref) {
|
|
6
7
|
var scope = _ref.scope,
|
|
7
8
|
identifierName = _ref.identifierName;
|
|
@@ -21,11 +22,21 @@ export function findIdentifierInParentScope(_ref) {
|
|
|
21
22
|
|
|
22
23
|
return null;
|
|
23
24
|
}
|
|
24
|
-
export var isSpacingProperty = function isSpacingProperty(
|
|
25
|
-
return properties.includes(
|
|
25
|
+
export var isSpacingProperty = function isSpacingProperty(propertyName) {
|
|
26
|
+
return properties.includes(propertyName);
|
|
27
|
+
};
|
|
28
|
+
export var isTypographyProperty = function isTypographyProperty(propertyName) {
|
|
29
|
+
return typographyProperties.includes(propertyName);
|
|
26
30
|
};
|
|
27
31
|
export var getValueFromShorthand = function getValueFromShorthand(str) {
|
|
28
|
-
|
|
32
|
+
var valueString = String(str);
|
|
33
|
+
var fontFamily = /(sans-serif$)|(monospace$)/;
|
|
34
|
+
|
|
35
|
+
if (fontFamily.test(valueString)) {
|
|
36
|
+
return [valueString];
|
|
37
|
+
} // If we want to filter out NaN just add .filter(Boolean)
|
|
38
|
+
|
|
39
|
+
|
|
29
40
|
return String(str).trim().split(' ').filter(function (val) {
|
|
30
41
|
return val !== '';
|
|
31
42
|
}).map(removePixelSuffix);
|
|
@@ -43,6 +54,14 @@ var isFontSizeSmall = function isFontSizeSmall(node) {
|
|
|
43
54
|
return isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && node.callee.name === 'fontSizeSmall';
|
|
44
55
|
};
|
|
45
56
|
|
|
57
|
+
var isFontFamily = function isFontFamily(node) {
|
|
58
|
+
return isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && (node.callee.name === 'fontFamily' || node.callee.name === 'getFontFamily');
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
var isCodeFontFamily = function isCodeFontFamily(node) {
|
|
62
|
+
return isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && (node.callee.name === 'codeFontFamily' || node.callee.name === 'getCodeFontFamily');
|
|
63
|
+
};
|
|
64
|
+
|
|
46
65
|
var isToken = function isToken(node) {
|
|
47
66
|
return isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && node.callee.name === 'token';
|
|
48
67
|
};
|
|
@@ -64,6 +83,14 @@ var getValueFromCallExpression = function getValueFromCallExpression(node, conte
|
|
|
64
83
|
return 11;
|
|
65
84
|
}
|
|
66
85
|
|
|
86
|
+
if (isFontFamily(node)) {
|
|
87
|
+
return "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isCodeFontFamily(node)) {
|
|
91
|
+
return "'SFMono-Medium', 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace";
|
|
92
|
+
}
|
|
93
|
+
|
|
67
94
|
if (isToken(node)) {
|
|
68
95
|
var args = node.arguments;
|
|
69
96
|
var call = "${token(".concat(args.map(function (argNode) {
|
package/dist/esm/version.json
CHANGED
|
@@ -4,7 +4,8 @@ export declare function findIdentifierInParentScope({ scope, identifierName, }:
|
|
|
4
4
|
scope: Scope.Scope;
|
|
5
5
|
identifierName: string;
|
|
6
6
|
}): Scope.Variable | null;
|
|
7
|
-
export declare const isSpacingProperty: (
|
|
7
|
+
export declare const isSpacingProperty: (propertyName: string) => boolean;
|
|
8
|
+
export declare const isTypographyProperty: (propertyName: string) => boolean;
|
|
8
9
|
export declare const getValueFromShorthand: (str: unknown) => any[];
|
|
9
10
|
export declare const getValue: (node: EslintNode, context: Rule.RuleContext) => string | number | any[] | null | undefined;
|
|
10
11
|
export declare const emToPixels: <T extends unknown>(value: T, fontSize: number | null | undefined) => number | T | null;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/eslint-plugin-design-system",
|
|
3
3
|
"description": "The essential plugin for use with the Atlassian Design System.",
|
|
4
|
-
"version": "4.13.
|
|
4
|
+
"version": "4.13.8",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"registry": "https://registry.npmjs.org/"
|