@atlaskit/eslint-plugin-design-system 8.23.0 → 8.23.2
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/ast-nodes/function-call.js +48 -0
- package/dist/cjs/ast-nodes/import.js +49 -0
- package/dist/cjs/ast-nodes/index.js +40 -0
- package/dist/cjs/ast-nodes/jsx-attribute.js +64 -0
- package/dist/cjs/ast-nodes/jsx-element.js +55 -0
- package/dist/cjs/ast-nodes/root.js +34 -0
- package/dist/cjs/rules/ensure-design-token-usage/error-boundary.js +24 -0
- package/dist/cjs/rules/ensure-design-token-usage/index.js +208 -177
- package/dist/cjs/rules/use-primitives/index.js +6 -76
- package/dist/cjs/rules/use-primitives/transformers/emotion-css/index.js +168 -0
- package/dist/cjs/rules/use-primitives/transformers/emotion-css/supported.js +52 -0
- package/dist/cjs/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +3 -0
- package/dist/es2019/ast-nodes/function-call.js +42 -0
- package/dist/es2019/ast-nodes/import.js +42 -0
- package/dist/es2019/ast-nodes/index.js +5 -0
- package/dist/es2019/ast-nodes/jsx-attribute.js +59 -0
- package/dist/es2019/ast-nodes/jsx-element.js +50 -0
- package/dist/es2019/ast-nodes/root.js +28 -0
- package/dist/es2019/rules/ensure-design-token-usage/error-boundary.js +19 -0
- package/dist/es2019/rules/ensure-design-token-usage/index.js +33 -16
- package/dist/es2019/rules/use-primitives/index.js +9 -79
- package/dist/es2019/rules/use-primitives/transformers/emotion-css/index.js +159 -0
- package/dist/es2019/rules/use-primitives/transformers/emotion-css/supported.js +46 -0
- package/dist/es2019/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +3 -0
- package/dist/esm/ast-nodes/function-call.js +42 -0
- package/dist/esm/ast-nodes/import.js +43 -0
- package/dist/esm/ast-nodes/index.js +5 -0
- package/dist/esm/ast-nodes/jsx-attribute.js +59 -0
- package/dist/esm/ast-nodes/jsx-element.js +50 -0
- package/dist/esm/ast-nodes/root.js +28 -0
- package/dist/esm/rules/ensure-design-token-usage/error-boundary.js +18 -0
- package/dist/esm/rules/ensure-design-token-usage/index.js +208 -177
- package/dist/esm/rules/use-primitives/index.js +9 -79
- package/dist/esm/rules/use-primitives/transformers/emotion-css/index.js +158 -0
- package/dist/esm/rules/use-primitives/transformers/emotion-css/supported.js +46 -0
- package/dist/esm/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +3 -0
- package/dist/types/ast-nodes/function-call.d.ts +21 -0
- package/dist/types/ast-nodes/import.d.ts +16 -0
- package/dist/types/ast-nodes/index.d.ts +5 -0
- package/dist/types/ast-nodes/jsx-attribute.d.ts +26 -0
- package/dist/types/ast-nodes/jsx-element.d.ts +21 -0
- package/dist/types/ast-nodes/root.d.ts +19 -0
- package/dist/types/rules/ensure-design-token-usage/error-boundary.d.ts +11 -0
- package/dist/types/rules/ensure-design-token-usage/types.d.ts +1 -0
- package/dist/types/rules/use-primitives/transformers/emotion-css/index.d.ts +35 -0
- package/dist/types/rules/use-primitives/transformers/emotion-css/supported.d.ts +9 -0
- package/dist/types-ts4.5/ast-nodes/function-call.d.ts +21 -0
- package/dist/types-ts4.5/ast-nodes/import.d.ts +16 -0
- package/dist/types-ts4.5/ast-nodes/index.d.ts +5 -0
- package/dist/types-ts4.5/ast-nodes/jsx-attribute.d.ts +26 -0
- package/dist/types-ts4.5/ast-nodes/jsx-element.d.ts +21 -0
- package/dist/types-ts4.5/ast-nodes/root.d.ts +19 -0
- package/dist/types-ts4.5/rules/ensure-design-token-usage/error-boundary.d.ts +11 -0
- package/dist/types-ts4.5/rules/ensure-design-token-usage/types.d.ts +1 -0
- package/dist/types-ts4.5/rules/use-primitives/transformers/emotion-css/index.d.ts +35 -0
- package/dist/types-ts4.5/rules/use-primitives/transformers/emotion-css/supported.d.ts +9 -0
- package/package.json +1 -1
|
@@ -6,13 +6,15 @@ import { createLintRule } from '../utils/create-rule';
|
|
|
6
6
|
import { includesHardCodedColor } from '../utils/is-color';
|
|
7
7
|
import { isDecendantOfGlobalToken, isDecendantOfStyleBlock, isDecendantOfType } from '../utils/is-node';
|
|
8
8
|
import { lintJSXIdentifierForColor, lintJSXLiteralForColor, lintJSXMemberForColor, lintObjectForColor, lintTemplateIdentifierForColor } from './color';
|
|
9
|
+
import { errorBoundary } from './error-boundary';
|
|
9
10
|
import ruleMeta from './rule-meta';
|
|
10
11
|
import { lintObjectForSpacing } from './spacing';
|
|
11
12
|
import { convertHyphenatedNameToCamelCase, emToPixels, getDomainsForProperty, getFontSizeFromNode, getFontSizeValueInScope, getTokenReplacement, getValueFromShorthand, getValueFromTemplateLiteralRaw, includesTokenString, insertTokensImport, isAuto, isCalc, isTokenValueString, isValidSpacingValue, isZero, processCssNode, splitShorthandValues } from './utils';
|
|
12
13
|
var defaultConfig = {
|
|
13
14
|
domains: ['color', 'spacing'],
|
|
14
15
|
applyImport: true,
|
|
15
|
-
shouldEnforceFallbacks: false
|
|
16
|
+
shouldEnforceFallbacks: false,
|
|
17
|
+
failSilently: false
|
|
16
18
|
};
|
|
17
19
|
var createWithConfig = function createWithConfig(initialConfig) {
|
|
18
20
|
return function (context) {
|
|
@@ -22,18 +24,27 @@ var createWithConfig = function createWithConfig(initialConfig) {
|
|
|
22
24
|
domains: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.domains) || initialConfig.domains,
|
|
23
25
|
applyImport: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.applyImport) !== undefined ? userConfig.applyImport : initialConfig.applyImport,
|
|
24
26
|
shouldEnforceFallbacks: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.shouldEnforceFallbacks) !== undefined ? userConfig.shouldEnforceFallbacks : initialConfig.shouldEnforceFallbacks,
|
|
25
|
-
exceptions: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.exceptions) || []
|
|
27
|
+
exceptions: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.exceptions) || [],
|
|
28
|
+
failSilently: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.failSilently) || defaultConfig.failSilently
|
|
26
29
|
};
|
|
27
30
|
var tokenNode = null;
|
|
28
31
|
return {
|
|
29
32
|
ImportDeclaration: function ImportDeclaration(node) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
return errorBoundary(function () {
|
|
34
|
+
if (node.source.value === '@atlaskit/tokens' && config.applyImport) {
|
|
35
|
+
tokenNode = node;
|
|
36
|
+
}
|
|
37
|
+
}, {
|
|
38
|
+
config: config
|
|
39
|
+
});
|
|
33
40
|
},
|
|
34
41
|
// For expressions within template literals (e.g. `color: ${red}`) - color only
|
|
35
42
|
'TemplateLiteral > Identifier': function TemplateLiteralIdentifier(node) {
|
|
36
|
-
return
|
|
43
|
+
return errorBoundary(function () {
|
|
44
|
+
return lintTemplateIdentifierForColor(node, context, config);
|
|
45
|
+
}, {
|
|
46
|
+
config: config
|
|
47
|
+
});
|
|
37
48
|
},
|
|
38
49
|
// const styles = css({ color: 'red', margin: '4px' }), styled.div({ color: 'red', margin: '4px' })
|
|
39
50
|
ObjectExpression: function (_ObjectExpression) {
|
|
@@ -45,220 +56,240 @@ var createWithConfig = function createWithConfig(initialConfig) {
|
|
|
45
56
|
};
|
|
46
57
|
return ObjectExpression;
|
|
47
58
|
}(function (parentNode) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Return for nested objects - these get handled automatically so without returning we'd be doubling up
|
|
54
|
-
if (parentNode.parent.type === 'Property') {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (!isDecendantOfStyleBlock(parentNode) && !isDecendantOfType(parentNode, 'JSXExpressionContainer')) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
function findObjectStyles(node) {
|
|
61
|
-
if (!isNodeOfType(node, 'Property')) {
|
|
59
|
+
return errorBoundary(function () {
|
|
60
|
+
// To force the correct node type
|
|
61
|
+
if (!isNodeOfType(parentNode, 'ObjectExpression')) {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!isNodeOfType(node.key, 'Identifier') && !isNodeOfType(node.key, 'Literal')) {
|
|
64
|
+
|
|
65
|
+
// Return for nested objects - these get handled automatically so without returning we'd be doubling up
|
|
66
|
+
if (parentNode.parent.type === 'Property') {
|
|
68
67
|
return;
|
|
69
68
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// Returns which domains to lint against based on rule's config and current property
|
|
73
|
-
var domains = getDomainsForProperty(propertyName, config.domains);
|
|
74
|
-
if (domains.length === 0 || isDecendantOfGlobalToken(node.value)) {
|
|
69
|
+
if (!isDecendantOfStyleBlock(parentNode) && !isDecendantOfType(parentNode, 'JSXExpressionContainer')) {
|
|
75
70
|
return;
|
|
76
71
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return context.report({
|
|
81
|
-
node: node,
|
|
82
|
-
messageId: 'noCalcUsage',
|
|
83
|
-
data: {
|
|
84
|
-
payload: "".concat(propertyName)
|
|
85
|
-
}
|
|
86
|
-
});
|
|
72
|
+
function findObjectStyles(node) {
|
|
73
|
+
if (!isNodeOfType(node, 'Property')) {
|
|
74
|
+
return;
|
|
87
75
|
}
|
|
88
|
-
if (node.value
|
|
76
|
+
if (isNodeOfType(node.value, 'ObjectExpression')) {
|
|
77
|
+
return node.value.properties.forEach(findObjectStyles);
|
|
78
|
+
}
|
|
79
|
+
if (!isNodeOfType(node.key, 'Identifier') && !isNodeOfType(node.key, 'Literal')) {
|
|
89
80
|
return;
|
|
90
81
|
}
|
|
82
|
+
var propertyName = isNodeOfType(node.key, 'Identifier') ? node.key.name : String(node.key.value);
|
|
83
|
+
|
|
84
|
+
// Returns which domains to lint against based on rule's config and current property
|
|
85
|
+
var domains = getDomainsForProperty(propertyName, config.domains);
|
|
86
|
+
if (domains.length === 0 || isDecendantOfGlobalToken(node.value)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (isNodeOfType(node.value, 'TemplateLiteral')) {
|
|
90
|
+
var value = getValueFromTemplateLiteralRaw(node.value, context);
|
|
91
|
+
if (Array.isArray(value) && value.some(isCalc)) {
|
|
92
|
+
return context.report({
|
|
93
|
+
node: node,
|
|
94
|
+
messageId: 'noCalcUsage',
|
|
95
|
+
data: {
|
|
96
|
+
payload: "".concat(propertyName)
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (node.value.expressions.some(isDecendantOfGlobalToken)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (domains.includes('color')) {
|
|
105
|
+
return lintObjectForColor(node, context, config);
|
|
106
|
+
}
|
|
107
|
+
if (domains.includes('spacing') || domains.includes('shape') || domains.includes('typography')) {
|
|
108
|
+
/**
|
|
109
|
+
* We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration
|
|
110
|
+
*/
|
|
111
|
+
var fontSize = getFontSizeFromNode(parentNode, context);
|
|
112
|
+
return lintObjectForSpacing(node, context, config, fontSize, tokenNode);
|
|
113
|
+
}
|
|
91
114
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration
|
|
98
|
-
*/
|
|
99
|
-
var fontSize = getFontSizeFromNode(parentNode, context);
|
|
100
|
-
return lintObjectForSpacing(node, context, config, fontSize, tokenNode);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
parentNode.properties.forEach(findObjectStyles);
|
|
115
|
+
parentNode.properties.forEach(findObjectStyles);
|
|
116
|
+
}, {
|
|
117
|
+
config: config
|
|
118
|
+
});
|
|
104
119
|
}),
|
|
105
120
|
// CSSTemplateLiteral and StyledTemplateLiteral
|
|
106
121
|
// const cssTemplateLiteral = css`color: red; padding: 12px`;
|
|
107
122
|
// const styledTemplateLiteral = styled.p`color: red; padding: 8px`;
|
|
108
123
|
'TaggedTemplateExpression[tag.name="css"],TaggedTemplateExpression[tag.object.name="styled"],TaggedTemplateExpression[tag.callee.name="styled"]': function TaggedTemplateExpressionTagNameCssTaggedTemplateExpressionTagObjectNameStyledTaggedTemplateExpressionTagCalleeNameStyled(node) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
var processedCssLines = processCssNode(node, context);
|
|
114
|
-
if (!processedCssLines) {
|
|
115
|
-
// if we can't get a processed css we bail
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
var globalFontSize = getFontSizeValueInScope(processedCssLines);
|
|
119
|
-
var textForSource = context.getSourceCode().getText(node.quasi);
|
|
120
|
-
var allReplacedValues = [];
|
|
121
|
-
var completeSource = processedCssLines.reduce(function (currentSource, _ref) {
|
|
122
|
-
var _ref2 = _slicedToArray(_ref, 2),
|
|
123
|
-
resolvedCssLine = _ref2[0],
|
|
124
|
-
originalCssLine = _ref2[1];
|
|
125
|
-
var _resolvedCssLine$spli = resolvedCssLine.split(':'),
|
|
126
|
-
_resolvedCssLine$spli2 = _slicedToArray(_resolvedCssLine$spli, 2),
|
|
127
|
-
originalProperty = _resolvedCssLine$spli2[0],
|
|
128
|
-
resolvedCssValues = _resolvedCssLine$spli2[1];
|
|
129
|
-
var _originalCssLine$spli = originalCssLine.split(':'),
|
|
130
|
-
_originalCssLine$spli2 = _slicedToArray(_originalCssLine$spli, 2),
|
|
131
|
-
_ = _originalCssLine$spli2[0],
|
|
132
|
-
originalCssValues = _originalCssLine$spli2[1];
|
|
133
|
-
var propertyName = convertHyphenatedNameToCamelCase(originalProperty);
|
|
134
|
-
var isFontFamily = /fontFamily/.test(propertyName);
|
|
135
|
-
var replacedValuesPerProperty = [originalProperty];
|
|
136
|
-
var domains = getDomainsForProperty(propertyName, config.domains);
|
|
137
|
-
if (domains.length === 0 || !resolvedCssValues) {
|
|
138
|
-
// in both of these cases no changes should be made to the current property
|
|
139
|
-
return currentSource;
|
|
124
|
+
return errorBoundary(function () {
|
|
125
|
+
// To force the correct node type
|
|
126
|
+
if (!isNodeOfType(node, 'TaggedTemplateExpression')) {
|
|
127
|
+
return;
|
|
140
128
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (includesHardCodedColor(resolvedCssValues)) {
|
|
146
|
-
context.report({
|
|
147
|
-
messageId: 'hardCodedColor',
|
|
148
|
-
node: node
|
|
149
|
-
});
|
|
150
|
-
return currentSource;
|
|
151
|
-
}
|
|
129
|
+
var processedCssLines = processCssNode(node, context);
|
|
130
|
+
if (!processedCssLines) {
|
|
131
|
+
// if we can't get a processed css we bail
|
|
132
|
+
return;
|
|
152
133
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
134
|
+
var globalFontSize = getFontSizeValueInScope(processedCssLines);
|
|
135
|
+
var textForSource = context.getSourceCode().getText(node.quasi);
|
|
136
|
+
var allReplacedValues = [];
|
|
137
|
+
var completeSource = processedCssLines.reduce(function (currentSource, _ref) {
|
|
138
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
139
|
+
resolvedCssLine = _ref2[0],
|
|
140
|
+
originalCssLine = _ref2[1];
|
|
141
|
+
var _resolvedCssLine$spli = resolvedCssLine.split(':'),
|
|
142
|
+
_resolvedCssLine$spli2 = _slicedToArray(_resolvedCssLine$spli, 2),
|
|
143
|
+
originalProperty = _resolvedCssLine$spli2[0],
|
|
144
|
+
resolvedCssValues = _resolvedCssLine$spli2[1];
|
|
145
|
+
var _originalCssLine$spli = originalCssLine.split(':'),
|
|
146
|
+
_originalCssLine$spli2 = _slicedToArray(_originalCssLine$spli, 2),
|
|
147
|
+
_ = _originalCssLine$spli2[0],
|
|
148
|
+
originalCssValues = _originalCssLine$spli2[1];
|
|
149
|
+
var propertyName = convertHyphenatedNameToCamelCase(originalProperty);
|
|
150
|
+
var isFontFamily = /fontFamily/.test(propertyName);
|
|
151
|
+
var replacedValuesPerProperty = [originalProperty];
|
|
152
|
+
var domains = getDomainsForProperty(propertyName, config.domains);
|
|
153
|
+
if (domains.length === 0 || !resolvedCssValues) {
|
|
154
|
+
// in both of these cases no changes should be made to the current property
|
|
156
155
|
return currentSource;
|
|
157
156
|
}
|
|
157
|
+
if (domains.includes('color')) {
|
|
158
|
+
if (includesTokenString(resolvedCssValues.trim())) {
|
|
159
|
+
return currentSource;
|
|
160
|
+
}
|
|
161
|
+
if (includesHardCodedColor(resolvedCssValues)) {
|
|
162
|
+
context.report({
|
|
163
|
+
messageId: 'hardCodedColor',
|
|
164
|
+
node: node
|
|
165
|
+
});
|
|
166
|
+
return currentSource;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (domains.includes('spacing') || domains.includes('typography') || domains.includes('shape')) {
|
|
170
|
+
if (!isValidSpacingValue(resolvedCssValues, globalFontSize)) {
|
|
171
|
+
// no changes should be made to the current property
|
|
172
|
+
return currentSource;
|
|
173
|
+
}
|
|
158
174
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
175
|
+
// gets the values from the associated property, numeric values or NaN
|
|
176
|
+
var processedNumericValues = getValueFromShorthand(resolvedCssValues);
|
|
177
|
+
var processedValues = splitShorthandValues(resolvedCssValues);
|
|
178
|
+
// only splits shorthand values but it does not transform NaNs so tokens are preserved
|
|
179
|
+
var originalValues = splitShorthandValues(originalCssValues);
|
|
164
180
|
|
|
165
|
-
|
|
166
|
-
|
|
181
|
+
// reconstructing the string
|
|
182
|
+
// should replace what it can and preserve the raw value for everything else
|
|
167
183
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
var replacementValue = processedNumericValues
|
|
185
|
+
// put together resolved value and original value on a tuple
|
|
186
|
+
.map(function (value, index) {
|
|
187
|
+
return [
|
|
188
|
+
// if emToPX conversion fails we'll default to original value
|
|
189
|
+
emToPixels(value, globalFontSize) || value, processedValues[index], originalValues[index]];
|
|
190
|
+
}).map(function (_ref3) {
|
|
191
|
+
var _ref4 = _slicedToArray(_ref3, 3),
|
|
192
|
+
numericOrNanValue = _ref4[0],
|
|
193
|
+
pxValue = _ref4[1],
|
|
194
|
+
originalValue = _ref4[2];
|
|
195
|
+
if (!originalValue) {
|
|
196
|
+
return originalValue;
|
|
197
|
+
}
|
|
198
|
+
if (isCalc(originalValue)) {
|
|
199
|
+
context.report({
|
|
200
|
+
node: node,
|
|
201
|
+
messageId: 'noCalcUsage',
|
|
202
|
+
data: {
|
|
203
|
+
payload: "".concat(propertyName)
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
return originalValue;
|
|
207
|
+
}
|
|
208
|
+
if (isTokenValueString(originalValue)) {
|
|
209
|
+
// if the value is already valid, nothing to report or replace
|
|
210
|
+
return originalValue;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// do not replace 0 or auto with tokens
|
|
214
|
+
if (isZero(pxValue) || isAuto(pxValue)) {
|
|
215
|
+
return originalValue;
|
|
216
|
+
}
|
|
217
|
+
if (isNaN(numericOrNanValue) && !isFontFamily) {
|
|
218
|
+
// do not report if we have nothing to replace with
|
|
219
|
+
return originalValue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// value is numeric or fontFamily, and needs replacing we'll report first
|
|
183
223
|
context.report({
|
|
184
224
|
node: node,
|
|
185
|
-
messageId: '
|
|
225
|
+
messageId: 'noRawSpacingValues',
|
|
186
226
|
data: {
|
|
187
|
-
payload: "".concat(propertyName)
|
|
227
|
+
payload: "".concat(propertyName, ":").concat(numericOrNanValue)
|
|
188
228
|
}
|
|
189
229
|
});
|
|
190
|
-
return originalValue;
|
|
191
|
-
}
|
|
192
|
-
if (isTokenValueString(originalValue)) {
|
|
193
|
-
// if the value is already valid, nothing to report or replace
|
|
194
|
-
return originalValue;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// do not replace 0 or auto with tokens
|
|
198
|
-
if (isZero(pxValue) || isAuto(pxValue)) {
|
|
199
|
-
return originalValue;
|
|
200
|
-
}
|
|
201
|
-
if (isNaN(numericOrNanValue) && !isFontFamily) {
|
|
202
|
-
// do not report if we have nothing to replace with
|
|
203
|
-
return originalValue;
|
|
204
|
-
}
|
|
205
230
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
data: {
|
|
211
|
-
payload: "".concat(propertyName, ":").concat(numericOrNanValue)
|
|
231
|
+
// from here on we know value is numeric or a font family, so it might or might not have a token equivalent
|
|
232
|
+
var replacementNode = getTokenReplacement(propertyName, numericOrNanValue);
|
|
233
|
+
if (!replacementNode) {
|
|
234
|
+
return originalValue;
|
|
212
235
|
}
|
|
213
|
-
|
|
236
|
+
var replacementToken = '${' + replacementNode.toString() + '}';
|
|
237
|
+
replacedValuesPerProperty.push(isFontFamily ? numericOrNanValue.trim() : pxValue);
|
|
238
|
+
return replacementToken;
|
|
239
|
+
}).join(' ');
|
|
240
|
+
if (replacedValuesPerProperty.length > 1) {
|
|
241
|
+
// first value is the property name, so it will always have at least 1
|
|
242
|
+
allReplacedValues.push(replacedValuesPerProperty);
|
|
243
|
+
}
|
|
214
244
|
|
|
215
|
-
//
|
|
216
|
-
var
|
|
217
|
-
|
|
218
|
-
|
|
245
|
+
// replace property:val with new property:val
|
|
246
|
+
var replacedCssLine = currentSource.replace(originalCssLine, // padding: ${gridSize()}px;
|
|
247
|
+
"".concat(originalProperty, ": ").concat(replacementValue));
|
|
248
|
+
if (!replacedCssLine) {
|
|
249
|
+
return currentSource;
|
|
219
250
|
}
|
|
220
|
-
|
|
221
|
-
replacedValuesPerProperty.push(isFontFamily ? numericOrNanValue.trim() : pxValue);
|
|
222
|
-
return replacementToken;
|
|
223
|
-
}).join(' ');
|
|
224
|
-
if (replacedValuesPerProperty.length > 1) {
|
|
225
|
-
// first value is the property name, so it will always have at least 1
|
|
226
|
-
allReplacedValues.push(replacedValuesPerProperty);
|
|
251
|
+
return replacedCssLine;
|
|
227
252
|
}
|
|
253
|
+
return currentSource;
|
|
254
|
+
}, textForSource);
|
|
255
|
+
if (completeSource !== textForSource) {
|
|
256
|
+
// means we found some replacement values, we'll give the option to fix them
|
|
228
257
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
258
|
+
context.report({
|
|
259
|
+
node: node,
|
|
260
|
+
messageId: 'autofixesPossible',
|
|
261
|
+
fix: function fix(fixer) {
|
|
262
|
+
return (!tokenNode && config.applyImport ? [insertTokensImport(fixer)] : []).concat([fixer.replaceText(node.quasi, completeSource)]);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
236
265
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// means we found some replacement values, we'll give the option to fix them
|
|
241
|
-
|
|
242
|
-
context.report({
|
|
243
|
-
node: node,
|
|
244
|
-
messageId: 'autofixesPossible',
|
|
245
|
-
fix: function fix(fixer) {
|
|
246
|
-
return (!tokenNode && config.applyImport ? [insertTokensImport(fixer)] : []).concat([fixer.replaceText(node.quasi, completeSource)]);
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
}
|
|
266
|
+
}, {
|
|
267
|
+
config: config
|
|
268
|
+
});
|
|
250
269
|
},
|
|
251
270
|
// For inline JSX styles - literals (e.g. <Test color="red"/>) - color only
|
|
252
271
|
'JSXAttribute > Literal': function JSXAttributeLiteral(node) {
|
|
253
|
-
return
|
|
272
|
+
return errorBoundary(function () {
|
|
273
|
+
return lintJSXLiteralForColor(node, context, config);
|
|
274
|
+
}, {
|
|
275
|
+
config: config
|
|
276
|
+
});
|
|
254
277
|
},
|
|
255
278
|
// For inline JSX styles - members (e.g. <Test color={color.red}/>) - color only
|
|
256
279
|
'JSXExpressionContainer > MemberExpression': function JSXExpressionContainerMemberExpression(node) {
|
|
257
|
-
return
|
|
280
|
+
return errorBoundary(function () {
|
|
281
|
+
return lintJSXMemberForColor(node, context, config);
|
|
282
|
+
}, {
|
|
283
|
+
config: config
|
|
284
|
+
});
|
|
258
285
|
},
|
|
259
286
|
// For inline JSX styles - identifiers (e.g. <Test color={red}/>) - color only
|
|
260
287
|
'JSXExpressionContainer > Identifier': function JSXExpressionContainerIdentifier(node) {
|
|
261
|
-
return
|
|
288
|
+
return errorBoundary(function () {
|
|
289
|
+
return lintJSXIdentifierForColor(node, context, config);
|
|
290
|
+
}, {
|
|
291
|
+
config: config
|
|
292
|
+
});
|
|
262
293
|
}
|
|
263
294
|
};
|
|
264
295
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
2
|
import { createLintRule } from '../utils/create-rule';
|
|
3
3
|
import { getConfig } from './config';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { styledComponentToPrimitive } from './transformers';
|
|
5
|
+
import { EmotionCSS } from './transformers/emotion-css';
|
|
6
|
+
import { findValidJsxUsageToTransform, findValidStyledComponentCall, isValidCssPropertiesToTransform } from './utils';
|
|
6
7
|
var boxDocsUrl = 'https://atlassian.design/components/primitives/box';
|
|
7
8
|
var rule = createLintRule({
|
|
8
9
|
meta: {
|
|
@@ -53,84 +54,13 @@ var rule = createLintRule({
|
|
|
53
54
|
});
|
|
54
55
|
},
|
|
55
56
|
// transforms <div css={...}> usages
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (!isNodeOfType(node.name, 'JSXIdentifier')) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (!isNodeOfType(node.parent, 'JSXElement')) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
var suggestBox = shouldSuggestBox(node.parent, context, config);
|
|
70
|
-
if (suggestBox) {
|
|
71
|
-
context.report({
|
|
72
|
-
node: node,
|
|
73
|
-
messageId: 'preferPrimitivesBox',
|
|
74
|
-
data: {
|
|
75
|
-
element: node.name.name
|
|
76
|
-
},
|
|
77
|
-
suggest: [{
|
|
78
|
-
desc: "Convert to Box",
|
|
79
|
-
fix: jsxElementToBoxTransformer(node.parent, context)
|
|
80
|
-
}]
|
|
81
|
-
});
|
|
82
|
-
}
|
|
57
|
+
JSXElement: function JSXElement(node) {
|
|
58
|
+
EmotionCSS.lint(node, {
|
|
59
|
+
context: context,
|
|
60
|
+
config: config
|
|
61
|
+
});
|
|
83
62
|
}
|
|
84
63
|
};
|
|
85
64
|
}
|
|
86
65
|
});
|
|
87
|
-
var shouldSuggestBox = function shouldSuggestBox(node, context, config
|
|
88
|
-
// scope: Scope.Scope,
|
|
89
|
-
) {
|
|
90
|
-
if (!node) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Currently we only support `div`, but possibly more in future
|
|
95
|
-
if (!isValidTagName(node)) {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Currently we only support elements that contain only a `css` attr, possibly more in future
|
|
100
|
-
if (!containsOnlySupportedAttrs(node)) {
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Get the `css` attr
|
|
105
|
-
var cssAttr = getJSXAttributeByName(node.openingElement, 'css');
|
|
106
|
-
|
|
107
|
-
// Get the prop value, e.g. `myStyles` in `css={myStyles}`
|
|
108
|
-
var cssVariableName = getAttributeValueIdentifier(cssAttr);
|
|
109
|
-
|
|
110
|
-
// `cssVariableName` could be undefined if the maker has
|
|
111
|
-
// done something like `css={[styles1, styles2]}`, `css={...styles}`, etc
|
|
112
|
-
if (!cssVariableName) {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Make sure the variable is not used in multiple JSX elements:
|
|
118
|
-
* ```
|
|
119
|
-
* <div css={paddingStyles}></div>
|
|
120
|
-
* <input css={paddingStyles}></input>
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
if (getVariableUsagesCount(cssVariableName, context) !== 1) {
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Find where `cssVariableName` is defined. We're looking for `const myStyles = css({...})`
|
|
128
|
-
var cssVariableDefinition = getIdentifierInParentScope(context.getScope(), cssVariableName);
|
|
129
|
-
var cssVariableValue = getVariableDefinitionValue(cssVariableDefinition);
|
|
130
|
-
// Check if `cssVariableValue` is a function called `css()`
|
|
131
|
-
if (!cssVariableValue || !isFunctionNamed(cssVariableValue, 'css')) {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
return isValidCssPropertiesToTransform(cssVariableValue.node.init, config);
|
|
135
|
-
};
|
|
136
66
|
export default rule;
|