@atlaskit/eslint-plugin-design-system 8.7.0 → 8.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/constellation/index/usage.mdx +17 -2
- package/dist/cjs/rules/consistent-css-prop-usage/index.js +107 -95
- package/dist/cjs/rules/consistent-css-prop-usage/types.js +5 -0
- package/dist/cjs/rules/ensure-design-token-usage/index.js +24 -2
- package/dist/cjs/rules/ensure-design-token-usage/rule-meta.js +1 -0
- package/dist/cjs/rules/ensure-design-token-usage/spacing.js +19 -4
- package/dist/cjs/rules/ensure-design-token-usage/utils.js +9 -4
- package/dist/es2019/rules/consistent-css-prop-usage/index.js +62 -51
- package/dist/es2019/rules/consistent-css-prop-usage/types.js +1 -0
- package/dist/es2019/rules/ensure-design-token-usage/index.js +25 -3
- package/dist/es2019/rules/ensure-design-token-usage/rule-meta.js +1 -0
- package/dist/es2019/rules/ensure-design-token-usage/spacing.js +19 -4
- package/dist/es2019/rules/ensure-design-token-usage/utils.js +7 -3
- package/dist/esm/rules/consistent-css-prop-usage/index.js +107 -95
- package/dist/esm/rules/consistent-css-prop-usage/types.js +1 -0
- package/dist/esm/rules/ensure-design-token-usage/index.js +25 -3
- package/dist/esm/rules/ensure-design-token-usage/rule-meta.js +1 -0
- package/dist/esm/rules/ensure-design-token-usage/spacing.js +19 -4
- package/dist/esm/rules/ensure-design-token-usage/utils.js +7 -3
- package/dist/types/rules/consistent-css-prop-usage/types.d.ts +4 -0
- package/dist/types/rules/ensure-design-token-usage/utils.d.ts +15 -0
- package/dist/types-ts4.5/rules/consistent-css-prop-usage/types.d.ts +4 -0
- package/dist/types-ts4.5/rules/ensure-design-token-usage/utils.d.ts +15 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-design-system
|
|
2
2
|
|
|
3
|
+
## 8.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`6c149f3e71d`](https://bitbucket.org/atlassian/atlassian-frontend/commits/6c149f3e71d) - The `ensure-design-token-usage` rules now report on use of the CSS `calc` function when used with padding, margin, and gap properties.
|
|
8
|
+
|
|
9
|
+
## 8.7.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`d6845989896`](https://bitbucket.org/atlassian/atlassian-frontend/commits/d6845989896) - Configuration added to consistent-css-prop-usage where it is now possible to specify what function names the rule should lint against, and what position is recommended for styles (top or bottom).
|
|
14
|
+
|
|
3
15
|
## 8.7.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ module.exports = {
|
|
|
49
49
|
|
|
50
50
|
| Rule | Description | Recommended | Fixable | Suggestions |
|
|
51
51
|
| ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- | ----------- |
|
|
52
|
-
| <a href="./src/rules/consistent-css-prop-usage/README.md">consistent-css-prop-usage</a> | Ensures consistency with
|
|
52
|
+
| <a href="./src/rules/consistent-css-prop-usage/README.md">consistent-css-prop-usage</a> | Ensures consistency with `css` and `xcss` prop usages | Yes | Yes | |
|
|
53
53
|
| <a href="./src/rules/ensure-design-token-usage/README.md">ensure-design-token-usage</a> | Enforces usage of design tokens rather than hard-coded values. | Yes | Yes | Yes |
|
|
54
54
|
| <a href="./src/rules/ensure-design-token-usage-preview/README.md">ensure-design-token-usage/preview</a> | Enforces usage of pre-release design tokens rather than hard-coded values. | | Yes | Yes |
|
|
55
55
|
| <a href="./src/rules/icon-label/README.md">icon-label</a> | Enforces accessible usage of icon labels when composed with Atlassian Design System components. | Yes | Yes | |
|
|
@@ -13,7 +13,7 @@ This plugin contains rules that should be used when working with the [Atlassian
|
|
|
13
13
|
|
|
14
14
|
| Rule | Description | Recommended | Fixable | Suggestions |
|
|
15
15
|
| ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- | ----------- |
|
|
16
|
-
| <a href="#consistent-css-prop-usage">consistent-css-prop-usage</a> | Ensures consistency with
|
|
16
|
+
| <a href="#consistent-css-prop-usage">consistent-css-prop-usage</a> | Ensures consistency with `css` and `xcss` prop usages | Yes | Yes | |
|
|
17
17
|
| <a href="#ensure-design-token-usage">ensure-design-token-usage</a> | Enforces usage of design tokens rather than hard-coded values. | Yes | Yes | Yes |
|
|
18
18
|
| <a href="#ensure-design-token-usage-preview">ensure-design-token-usage/preview</a> | Enforces usage of pre-release design tokens rather than hard-coded values. | | Yes | Yes |
|
|
19
19
|
| <a href="#icon-label">icon-label</a> | Enforces accessible usage of icon labels when composed with Atlassian Design System components. | Yes | Yes | |
|
|
@@ -51,7 +51,9 @@ This rule checks for the following cases:
|
|
|
51
51
|
- When styles are coming from outside of the module i.e. using imports.
|
|
52
52
|
- When styles are spread inside another styles and not using array composition.
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
All the above can also work for custom `css` functions, such as `xcss` (https://atlassian.design/components/primitives/xcss/).
|
|
55
|
+
|
|
56
|
+
This rule has options - see below.
|
|
55
57
|
|
|
56
58
|
<h3>Examples</h3>
|
|
57
59
|
|
|
@@ -128,6 +130,19 @@ function Button({ children }) {
|
|
|
128
130
|
}
|
|
129
131
|
```
|
|
130
132
|
|
|
133
|
+
<h3>Options</h3>
|
|
134
|
+
|
|
135
|
+
This rule comes with options to support different repository configurations.
|
|
136
|
+
|
|
137
|
+
#### cssFunctions
|
|
138
|
+
|
|
139
|
+
An array of function names the linting rule should target. Defaults to `['css', 'xcss']`.
|
|
140
|
+
|
|
141
|
+
#### stylesPlacement
|
|
142
|
+
|
|
143
|
+
The rule prevents inline styles from being created. This option defines what the error message should say: "(...) styles at the top (...)" or "(...) styles at the bottom (...)".
|
|
144
|
+
Defaults to `top`.
|
|
145
|
+
|
|
131
146
|
## ensure-design-token-usage
|
|
132
147
|
|
|
133
148
|
Using design tokens results in a harmonious experience for end users whilst providing theming and consistency.
|
|
@@ -5,12 +5,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.default = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
8
9
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
10
|
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
11
|
+
var _assign = _interopRequireDefault(require("lodash/assign"));
|
|
10
12
|
var _createRule = require("../utils/create-rule");
|
|
11
13
|
var declarationSuffix = 'Styles';
|
|
12
|
-
function isCssCallExpression(node) {
|
|
13
|
-
return !!((0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') && node.callee && node.callee.type === 'Identifier' && (node.callee.name
|
|
14
|
+
function isCssCallExpression(node, cssFunctions) {
|
|
15
|
+
return !!((0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') && node.callee && node.callee.type === 'Identifier' && cssFunctions.includes(node.callee.name) && node.arguments.length && node.arguments[0].type === 'ObjectExpression');
|
|
14
16
|
}
|
|
15
17
|
function findSpreadProperties(node) {
|
|
16
18
|
// @ts-ignore
|
|
@@ -20,7 +22,7 @@ function findSpreadProperties(node) {
|
|
|
20
22
|
property.type === 'ExperimentalSpreadProperty';
|
|
21
23
|
});
|
|
22
24
|
}
|
|
23
|
-
function analyzeIdentifier(context, sourceIdentifier) {
|
|
25
|
+
function analyzeIdentifier(context, sourceIdentifier, configuration) {
|
|
24
26
|
var _getIdentifierInParen;
|
|
25
27
|
var scope = context.getScope();
|
|
26
28
|
var _ref = ((_getIdentifierInParen = (0, _eslintCodemodUtils.getIdentifierInParentScope)(scope, sourceIdentifier.name)) === null || _getIdentifierInParen === void 0 ? void 0 : _getIdentifierInParen.identifiers) || [],
|
|
@@ -42,11 +44,11 @@ function analyzeIdentifier(context, sourceIdentifier) {
|
|
|
42
44
|
// When variable is declared inside the component
|
|
43
45
|
context.report({
|
|
44
46
|
node: sourceIdentifier,
|
|
45
|
-
messageId: 'cssOnTopOfModule'
|
|
47
|
+
messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssOnTopOfModule'
|
|
46
48
|
});
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
|
-
if (identifier.parent && identifier.parent.init && !isCssCallExpression(identifier.parent.init)) {
|
|
51
|
+
if (identifier.parent && identifier.parent.init && !isCssCallExpression(identifier.parent.init, configuration.cssFunctions)) {
|
|
50
52
|
// When variable value is not of type css({})
|
|
51
53
|
context.report({
|
|
52
54
|
node: identifier,
|
|
@@ -65,117 +67,127 @@ function analyzeIdentifier(context, sourceIdentifier) {
|
|
|
65
67
|
});
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
70
|
+
var traverseExpressionWithConfig = function traverseExpressionWithConfig(context, expression, configuration) {
|
|
71
|
+
function traverseExpression(expression) {
|
|
72
|
+
switch (expression.type) {
|
|
73
|
+
case 'Identifier':
|
|
74
|
+
// {styles}
|
|
75
|
+
// We've found an identifier - time to analyze it!
|
|
76
|
+
analyzeIdentifier(context, expression, configuration);
|
|
77
|
+
break;
|
|
78
|
+
case 'ArrayExpression':
|
|
79
|
+
// {[styles, moreStyles]}
|
|
80
|
+
// We've found an array expression - let's traverse again over each element individually.
|
|
81
|
+
expression.elements.forEach(function (element) {
|
|
82
|
+
return traverseExpression(element);
|
|
83
|
+
});
|
|
84
|
+
break;
|
|
85
|
+
case 'LogicalExpression':
|
|
86
|
+
// {isEnabled && styles}
|
|
87
|
+
// We've found a logical expression - we're only interested in the right expression so
|
|
88
|
+
// let's traverse that and see what it is!
|
|
89
|
+
traverseExpression(expression.right);
|
|
90
|
+
break;
|
|
91
|
+
case 'ConditionalExpression':
|
|
92
|
+
// {isEnabled ? styles : null}
|
|
93
|
+
// We've found a conditional expression - we're only interested in the consequent and
|
|
94
|
+
// alternate (styles : null)
|
|
95
|
+
traverseExpression(expression.consequent);
|
|
96
|
+
traverseExpression(expression.alternate);
|
|
97
|
+
break;
|
|
98
|
+
case 'CallExpression':
|
|
99
|
+
case 'ObjectExpression':
|
|
100
|
+
case 'TaggedTemplateExpression':
|
|
101
|
+
case 'TemplateLiteral':
|
|
102
|
+
// We've found elements that shouldn't be here! Report an error.
|
|
103
|
+
context.report({
|
|
104
|
+
node: expression,
|
|
105
|
+
messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssOnTopOfModule'
|
|
106
|
+
});
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
// Do nothing!
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
108
112
|
}
|
|
109
|
-
|
|
113
|
+
traverseExpression(expression);
|
|
114
|
+
};
|
|
115
|
+
var defaultConfig = {
|
|
116
|
+
cssFunctions: ['css', 'xcss'],
|
|
117
|
+
stylesPlacement: 'top'
|
|
118
|
+
};
|
|
110
119
|
var rule = (0, _createRule.createLintRule)({
|
|
111
120
|
meta: {
|
|
112
121
|
name: 'consistent-css-prop-usage',
|
|
113
122
|
docs: {
|
|
114
|
-
description: 'Ensures consistency with
|
|
123
|
+
description: 'Ensures consistency with `css` and `xcss` prop usages',
|
|
115
124
|
url: 'https://developer.atlassian.com/cloud/framework/atlassian-frontend/development/styling',
|
|
116
125
|
recommended: true,
|
|
117
126
|
severity: 'error'
|
|
118
127
|
},
|
|
119
128
|
fixable: 'code',
|
|
120
129
|
messages: {
|
|
121
|
-
cssOnTopOfModule: "Create styles at the top of the module scope using the css function.",
|
|
130
|
+
cssOnTopOfModule: "Create styles at the top of the module scope using the respective css function.",
|
|
131
|
+
cssAtBottomOfModule: "Create styles at the bottom of the module scope using the respective css function.",
|
|
122
132
|
cssObjectTypeOnly: "Create styles using objects passed to the css function.",
|
|
123
133
|
cssInModule: "Imported styles should not be used, instead define in the module, import a component, or use a design token.",
|
|
124
|
-
cssArrayStylesOnly: "Compose styles with an array on the
|
|
134
|
+
cssArrayStylesOnly: "Compose styles with an array on the css prop instead of using object spread.",
|
|
125
135
|
shouldEndInStyles: 'Declared styles should end in "styles".'
|
|
126
136
|
}
|
|
127
137
|
},
|
|
128
138
|
create: function create(context) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
var _ref3;
|
|
140
|
+
var mergedConfig = (0, _assign.default)({}, defaultConfig, context.options[0]);
|
|
141
|
+
var callSelector = mergedConfig.cssFunctions.map(function (fn) {
|
|
142
|
+
return "CallExpression[callee.name=".concat(fn, "]");
|
|
143
|
+
}).join(',');
|
|
144
|
+
return _ref3 = {}, (0, _defineProperty2.default)(_ref3, callSelector, function (node) {
|
|
145
|
+
if (node.parent.type !== 'VariableDeclarator') {
|
|
146
|
+
// We aren't interested in these that don't have a parent.
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
var identifier = node.parent.id;
|
|
150
|
+
if (identifier.type === 'Identifier' && identifier.name.endsWith(declarationSuffix)) {
|
|
151
|
+
// Already prefixed! Nothing to do.
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
context.report({
|
|
155
|
+
node: identifier,
|
|
156
|
+
messageId: 'shouldEndInStyles',
|
|
157
|
+
fix: function fix(fixer) {
|
|
158
|
+
var _context$getScope$var;
|
|
159
|
+
var identifierName = identifier.type === 'Identifier' ? identifier.name : '';
|
|
160
|
+
var references = ((_context$getScope$var = context.getScope().variables.find(function (varb) {
|
|
161
|
+
return varb.name === identifierName;
|
|
162
|
+
})) === null || _context$getScope$var === void 0 ? void 0 : _context$getScope$var.references) || [];
|
|
163
|
+
var newIdentifierName = "".concat(identifierName
|
|
164
|
+
// Remove "Style" if it is already defined.
|
|
165
|
+
.replace(/Style$/, '')).concat(declarationSuffix);
|
|
166
|
+
return references.filter(function (ref) {
|
|
167
|
+
return ref.identifier.name === identifierName;
|
|
168
|
+
}).map(function (ref) {
|
|
169
|
+
if (ref.identifier.parent && ref.identifier.parent.shorthand) {
|
|
170
|
+
return fixer.replaceText(ref.identifier, "".concat(identifierName, ": ").concat(newIdentifierName));
|
|
171
|
+
}
|
|
172
|
+
return fixer.replaceText(ref.identifier, newIdentifierName);
|
|
173
|
+
});
|
|
134
174
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
175
|
+
});
|
|
176
|
+
}), (0, _defineProperty2.default)(_ref3, "JSXAttribute", function JSXAttribute(node) {
|
|
177
|
+
var name = node.name,
|
|
178
|
+
value = node.value;
|
|
179
|
+
if (name.type === 'JSXIdentifier' && mergedConfig.cssFunctions.includes(name.name)) {
|
|
180
|
+
// When not a jsx expression. For eg. css=""
|
|
181
|
+
if ((value === null || value === void 0 ? void 0 : value.type) !== 'JSXExpressionContainer') {
|
|
182
|
+
context.report({
|
|
183
|
+
node: value,
|
|
184
|
+
messageId: mergedConfig.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssOnTopOfModule'
|
|
185
|
+
});
|
|
138
186
|
return;
|
|
139
187
|
}
|
|
140
|
-
context.
|
|
141
|
-
node: identifier,
|
|
142
|
-
messageId: 'shouldEndInStyles',
|
|
143
|
-
fix: function fix(fixer) {
|
|
144
|
-
var _context$getScope$var;
|
|
145
|
-
var identifierName = identifier.type === 'Identifier' ? identifier.name : '';
|
|
146
|
-
var references = ((_context$getScope$var = context.getScope().variables.find(function (varb) {
|
|
147
|
-
return varb.name === identifierName;
|
|
148
|
-
})) === null || _context$getScope$var === void 0 ? void 0 : _context$getScope$var.references) || [];
|
|
149
|
-
var newIdentifierName = "".concat(identifierName
|
|
150
|
-
// Remove "Style" if it is already defined.
|
|
151
|
-
.replace(/Style$/, '')).concat(declarationSuffix);
|
|
152
|
-
return references.filter(function (ref) {
|
|
153
|
-
return ref.identifier.name === identifierName;
|
|
154
|
-
}).map(function (ref) {
|
|
155
|
-
if (ref.identifier.parent && ref.identifier.parent.shorthand) {
|
|
156
|
-
return fixer.replaceText(ref.identifier, "".concat(identifierName, ": ").concat(newIdentifierName));
|
|
157
|
-
}
|
|
158
|
-
return fixer.replaceText(ref.identifier, newIdentifierName);
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
},
|
|
163
|
-
JSXAttribute: function JSXAttribute(node) {
|
|
164
|
-
var name = node.name,
|
|
165
|
-
value = node.value;
|
|
166
|
-
if (name.type === 'JSXIdentifier' && (name.name === 'css' || name.name === 'xcss')) {
|
|
167
|
-
// When not a jsx expression. For eg. css=""
|
|
168
|
-
if ((value === null || value === void 0 ? void 0 : value.type) !== 'JSXExpressionContainer') {
|
|
169
|
-
context.report({
|
|
170
|
-
node: value,
|
|
171
|
-
messageId: 'cssOnTopOfModule'
|
|
172
|
-
});
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
traverseExpression(context, value.expression);
|
|
176
|
-
}
|
|
188
|
+
traverseExpressionWithConfig(context, value.expression, mergedConfig);
|
|
177
189
|
}
|
|
178
|
-
};
|
|
190
|
+
}), _ref3;
|
|
179
191
|
}
|
|
180
192
|
});
|
|
181
193
|
var _default = rule;
|
|
@@ -79,8 +79,20 @@ var createWithConfig = function createWithConfig(initialConfig) {
|
|
|
79
79
|
if (domains.length === 0 || (0, _isNode.isDecendantOfGlobalToken)(node.value)) {
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
|
-
if ((0, _eslintCodemodUtils.isNodeOfType)(node.value, 'TemplateLiteral')
|
|
83
|
-
|
|
82
|
+
if ((0, _eslintCodemodUtils.isNodeOfType)(node.value, 'TemplateLiteral')) {
|
|
83
|
+
var value = (0, _utils.getValueFromTemplateLiteralRaw)(node.value, context);
|
|
84
|
+
if (Array.isArray(value) && value.some(_utils.isCalc)) {
|
|
85
|
+
return context.report({
|
|
86
|
+
node: node,
|
|
87
|
+
messageId: 'noCalcUsage',
|
|
88
|
+
data: {
|
|
89
|
+
payload: "".concat(propertyName)
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (node.value.expressions.some(_isNode.isDecendantOfGlobalToken)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
84
96
|
}
|
|
85
97
|
if (domains.includes('color')) {
|
|
86
98
|
return (0, _color.lintObjectForColor)(node, context, config);
|
|
@@ -172,6 +184,16 @@ var createWithConfig = function createWithConfig(initialConfig) {
|
|
|
172
184
|
if (!originalValue) {
|
|
173
185
|
return originalValue;
|
|
174
186
|
}
|
|
187
|
+
if ((0, _utils.isCalc)(originalValue)) {
|
|
188
|
+
context.report({
|
|
189
|
+
node: node,
|
|
190
|
+
messageId: 'noCalcUsage',
|
|
191
|
+
data: {
|
|
192
|
+
payload: "".concat(propertyName)
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return originalValue;
|
|
196
|
+
}
|
|
175
197
|
if ((0, _utils.isTokenValueString)(originalValue)) {
|
|
176
198
|
// if the value is already valid, nothing to report or replace
|
|
177
199
|
return originalValue;
|
|
@@ -42,6 +42,7 @@ var ruleMeta = {
|
|
|
42
42
|
noRawRadiusValues: 'The use of shape tokens is preferred over the direct application of border properties.\n\n@meta <<{{payload}}>>',
|
|
43
43
|
noRawSpacingValues: 'The use of spacing primitives or tokens is preferred over the direct application of spacing properties.\n\n@meta <<{{payload}}>>',
|
|
44
44
|
autofixesPossible: 'Automated corrections available for spacing values. Apply autofix to replace values with appropriate tokens',
|
|
45
|
+
noCalcUsage: 'The use of space tokens is preferred over using the CSS calc function. If using a value that is not aligned to the spacing scale, consider aligning to the scale and using tokens instead.',
|
|
45
46
|
hardCodedColor: "Colors can be sourced from the global theme using the token function.",
|
|
46
47
|
legacyElevation: "Elevations can be sourced from the global theme using the token function made of both a background and shadow. Use \"card\" for card elevations, and \"overlay\" for anything else that should appear elevated."
|
|
47
48
|
}
|
|
@@ -22,13 +22,19 @@ var lintObjectForSpacing = function lintObjectForSpacing(node, context, ruleConf
|
|
|
22
22
|
});
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
+
var propertyName = node.key.name;
|
|
26
|
+
var isFontFamily = /fontFamily/.test(propertyName);
|
|
25
27
|
|
|
26
|
-
//
|
|
28
|
+
// Report on CSS calc function for strings
|
|
27
29
|
if ((0, _eslintCodemodUtils.isNodeOfType)(node.value, 'Literal') && (0, _utils.isCalc)(node.value.value)) {
|
|
28
|
-
return
|
|
30
|
+
return context.report({
|
|
31
|
+
node: node,
|
|
32
|
+
messageId: 'noCalcUsage',
|
|
33
|
+
data: {
|
|
34
|
+
payload: "".concat(propertyName)
|
|
35
|
+
}
|
|
36
|
+
});
|
|
29
37
|
}
|
|
30
|
-
var propertyName = node.key.name;
|
|
31
|
-
var isFontFamily = /fontFamily/.test(propertyName);
|
|
32
38
|
var value = (0, _utils.getValue)(node.value, context);
|
|
33
39
|
|
|
34
40
|
// Value is a token string (e.g. set via a variable)
|
|
@@ -87,6 +93,15 @@ var lintObjectForSpacing = function lintObjectForSpacing(node, context, ruleConf
|
|
|
87
93
|
* { padding: '8px 0px' }
|
|
88
94
|
*/
|
|
89
95
|
valuesForProperty.forEach(function (val) {
|
|
96
|
+
if ((0, _utils.isCalc)(val)) {
|
|
97
|
+
return context.report({
|
|
98
|
+
node: node,
|
|
99
|
+
messageId: 'noCalcUsage',
|
|
100
|
+
data: {
|
|
101
|
+
payload: "".concat(propertyName, ":").concat(val)
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
90
105
|
var pixelValue = (0, _utils.emToPixels)(val, fontSize);
|
|
91
106
|
|
|
92
107
|
// Do not report or suggest a token to replace 0 or auto
|
|
@@ -13,7 +13,7 @@ exports.getFontSizeValueInScope = getFontSizeValueInScope;
|
|
|
13
13
|
exports.getRawExpression = void 0;
|
|
14
14
|
exports.getTokenNodeForValue = getTokenNodeForValue;
|
|
15
15
|
exports.getTokenReplacement = getTokenReplacement;
|
|
16
|
-
exports.getValueFromShorthand = exports.getValue = void 0;
|
|
16
|
+
exports.getValueFromTemplateLiteralRaw = exports.getValueFromShorthand = exports.getValue = void 0;
|
|
17
17
|
exports.includesTokenString = includesTokenString;
|
|
18
18
|
exports.insertTokensImport = insertTokensImport;
|
|
19
19
|
exports.isSpacingProperty = exports.isCalc = exports.isAuto = void 0;
|
|
@@ -207,7 +207,7 @@ var getValueFromUnaryExpression = function getValueFromUnaryExpression(node, con
|
|
|
207
207
|
* // results in [2, 4, 0]
|
|
208
208
|
* ```
|
|
209
209
|
*/
|
|
210
|
-
var
|
|
210
|
+
var getValueFromTemplateLiteralRaw = function getValueFromTemplateLiteralRaw(node, context) {
|
|
211
211
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, "TemplateLiteral")) {
|
|
212
212
|
return null;
|
|
213
213
|
}
|
|
@@ -218,7 +218,12 @@ var getValueFromTemplateLiteral = function getValueFromTemplateLiteral(node, con
|
|
|
218
218
|
if (fontFamily.test(combinedString)) {
|
|
219
219
|
return combinedString;
|
|
220
220
|
}
|
|
221
|
-
return combinedString.split(' ')
|
|
221
|
+
return combinedString.split(' ');
|
|
222
|
+
};
|
|
223
|
+
exports.getValueFromTemplateLiteralRaw = getValueFromTemplateLiteralRaw;
|
|
224
|
+
var getValueFromTemplateLiteral = function getValueFromTemplateLiteral(node, context) {
|
|
225
|
+
var value = getValueFromTemplateLiteralRaw(node, context);
|
|
226
|
+
return Array.isArray(value) ? value.map(removePixelSuffix) : value;
|
|
222
227
|
};
|
|
223
228
|
var getValueFromBinaryExpression = function getValueFromBinaryExpression(node, context) {
|
|
224
229
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'BinaryExpression')) {
|
|
@@ -252,7 +257,7 @@ var emToPixels = function emToPixels(value, fontSize) {
|
|
|
252
257
|
exports.emToPixels = emToPixels;
|
|
253
258
|
var percentageOrEmOrAuto = /(%$)|(\d+em$)|(auto$)/;
|
|
254
259
|
var removePixelSuffix = function removePixelSuffix(value) {
|
|
255
|
-
if (typeof value === 'string' && percentageOrEmOrAuto.test(value)) {
|
|
260
|
+
if (typeof value === 'string' && (percentageOrEmOrAuto.test(value) || isCalc(value))) {
|
|
256
261
|
return value;
|
|
257
262
|
}
|
|
258
263
|
return Number(typeof value === 'string' ? value.replace('px', '') : value);
|