@atlaskit/eslint-plugin-design-system 8.19.1 → 8.19.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 +6 -0
- package/dist/cjs/rules/use-primitives/config/index.js +1 -1
- package/dist/cjs/rules/use-primitives/index.js +5 -6
- package/dist/cjs/rules/use-primitives/transformers/css-to-xcss.js +21 -7
- package/dist/cjs/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.js +30 -9
- package/dist/cjs/rules/use-primitives/utils/find-valid-styled-component-call.js +1 -0
- package/dist/cjs/rules/use-primitives/utils/get-variable-usage-count.js +1 -0
- package/dist/cjs/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +25 -5
- package/dist/es2019/rules/use-primitives/config/index.js +1 -1
- package/dist/es2019/rules/use-primitives/index.js +5 -6
- package/dist/es2019/rules/use-primitives/transformers/css-to-xcss.js +21 -7
- package/dist/es2019/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.js +30 -9
- package/dist/es2019/rules/use-primitives/utils/find-valid-styled-component-call.js +1 -0
- package/dist/es2019/rules/use-primitives/utils/get-variable-usage-count.js +1 -0
- package/dist/es2019/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +21 -5
- package/dist/esm/rules/use-primitives/config/index.js +1 -1
- package/dist/esm/rules/use-primitives/index.js +5 -6
- package/dist/esm/rules/use-primitives/transformers/css-to-xcss.js +21 -7
- package/dist/esm/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.js +30 -9
- package/dist/esm/rules/use-primitives/utils/find-valid-styled-component-call.js +1 -0
- package/dist/esm/rules/use-primitives/utils/get-variable-usage-count.js +1 -0
- package/dist/esm/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +24 -5
- package/dist/types/rules/use-primitives/config/index.d.ts +3 -1
- package/dist/types/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.d.ts +6 -1
- package/dist/types/rules/use-primitives/utils/get-variable-usage-count.d.ts +1 -0
- package/dist/types/rules/use-primitives/utils/is-valid-css-properties-to-transform.d.ts +2 -1
- package/dist/types-ts4.5/rules/use-primitives/config/index.d.ts +3 -1
- package/dist/types-ts4.5/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.d.ts +6 -1
- package/dist/types-ts4.5/rules/use-primitives/utils/get-variable-usage-count.d.ts +1 -0
- package/dist/types-ts4.5/rules/use-primitives/utils/is-valid-css-properties-to-transform.d.ts +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-design-system
|
|
2
2
|
|
|
3
|
+
## 8.19.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#66118](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/66118) [`93988e6fd035`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/93988e6fd035) - `use-primitives` now handles tokenised padding/margin properties. This change is guarded by a config flag and not enabled by default.
|
|
8
|
+
|
|
3
9
|
## 8.19.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.getConfig = void 0;
|
|
7
7
|
var defaults = {
|
|
8
|
-
patterns: ['
|
|
8
|
+
patterns: ['compiled-css-function']
|
|
9
9
|
};
|
|
10
10
|
var getConfig = exports.getConfig = function getConfig(overrides) {
|
|
11
11
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
|
@@ -37,7 +37,7 @@ var rule = (0, _createRule.createLintRule)({
|
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
var styledComponentVariableRef = (0, _utils.findValidStyledComponentCall)(node);
|
|
40
|
-
if (!styledComponentVariableRef || !(0, _eslintCodemodUtils.isNodeOfType)(styledComponentVariableRef.id, 'Identifier') || !(0, _utils.isValidCssPropertiesToTransform)(node)) {
|
|
40
|
+
if (!styledComponentVariableRef || !(0, _eslintCodemodUtils.isNodeOfType)(styledComponentVariableRef.id, 'Identifier') || !(0, _utils.isValidCssPropertiesToTransform)(node, config)) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
var styledComponentJsxRef = (0, _utils.findValidJsxUsageToTransform)(styledComponentVariableRef.id.name, context.getScope());
|
|
@@ -60,7 +60,9 @@ var rule = (0, _createRule.createLintRule)({
|
|
|
60
60
|
},
|
|
61
61
|
// transforms <div css={...}> usages
|
|
62
62
|
JSXOpeningElement: function JSXOpeningElement(node) {
|
|
63
|
-
|
|
63
|
+
if (!config.patterns.includes('compiled-css-function')) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
64
66
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'JSXOpeningElement')) {
|
|
65
67
|
return;
|
|
66
68
|
}
|
|
@@ -135,9 +137,6 @@ var shouldSuggestBox = function shouldSuggestBox(node, context, config
|
|
|
135
137
|
if (!cssVariableValue || !(0, _utils.isFunctionNamed)(cssVariableValue, 'css')) {
|
|
136
138
|
return false;
|
|
137
139
|
}
|
|
138
|
-
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
return (0, _utils.isValidCssPropertiesToTransform)(cssVariableValue.node.init);
|
|
140
|
+
return (0, _utils.isValidCssPropertiesToTransform)(cssVariableValue.node.init, config);
|
|
142
141
|
};
|
|
143
142
|
var _default = exports.default = rule;
|
|
@@ -39,7 +39,7 @@ var cssToXcssTransformer = exports.cssToXcssTransformer = function cssToXcssTran
|
|
|
39
39
|
fixer.replaceText(cssVariableValue.node.init.callee, (0, _eslintCodemodUtils.identifier)('xcss').toString())].concat((0, _toConsumableArray2.default)(styledObjectToXcssTokens(cssObjectExpression, fixer)));
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
// Update css object values to xcss values
|
|
42
|
+
// Update css object values to xcss values
|
|
43
43
|
// Note: `properties` in this context is a group of AST nodes that make up a key/value pair in an object.
|
|
44
44
|
// e.g. `padding: '8px'`. For clarity, it's renamed to `entry` inside the `.map()`.
|
|
45
45
|
var styledObjectToXcssTokens = exports.styledObjectToXcssTokens = function styledObjectToXcssTokens(styles, fixer) {
|
|
@@ -50,16 +50,30 @@ var styledObjectToXcssTokens = exports.styledObjectToXcssTokens = function style
|
|
|
50
50
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(entry.key, 'Identifier')) {
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
|
|
54
|
+
// maps literal values like: 8px to 'space.100'
|
|
55
|
+
if ((0, _eslintCodemodUtils.isNodeOfType)(entry.value, 'Literal')) {
|
|
56
|
+
var value = entry.value.value;
|
|
57
|
+
if (typeof value !== 'string') {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
return fixer.replaceText(entry.value, (0, _eslintCodemodUtils.literal)("'".concat(supportedStylesMap[entry.key.name][value], "'")).toString());
|
|
55
61
|
}
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
|
|
62
|
+
// maps token calls like: token('space.100') to 'space.100'
|
|
63
|
+
if ((0, _eslintCodemodUtils.isNodeOfType)(entry.value, 'CallExpression')) {
|
|
64
|
+
var callExpression = entry.value;
|
|
65
|
+
// skip if not a call to `token`
|
|
66
|
+
if (!(0, _eslintCodemodUtils.isNodeOfType)(callExpression.callee, 'Identifier') || callExpression.callee.name !== 'token' || !(0, _eslintCodemodUtils.isNodeOfType)(callExpression.arguments[0], 'Literal')) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// the first argument of `token` is the token name and
|
|
70
|
+
// can be given directly to `xcss` as it has been validated already.
|
|
71
|
+
return fixer.replaceText(entry.value, (0, _eslintCodemodUtils.literal)("'".concat(callExpression.arguments[0].value, "'")).toString());
|
|
59
72
|
}
|
|
60
|
-
return fixer.replaceText(entry.value, (0, _eslintCodemodUtils.literal)("'".concat(supportedStylesMap[entry.key.name][value], "'")).toString());
|
|
61
73
|
});
|
|
62
74
|
};
|
|
75
|
+
|
|
76
|
+
// TODO: https://product-fabric.atlassian.net/browse/DSP-16054
|
|
63
77
|
var spaceTokenMap = exports.spaceTokenMap = {
|
|
64
78
|
'0px': 'space.0',
|
|
65
79
|
'2px': 'space.025',
|
|
@@ -20,28 +20,49 @@ var convertASTObjectExpressionToJSObject = exports.convertASTObjectExpressionToJ
|
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// TODO:
|
|
23
|
+
// TODO: https://product-fabric.atlassian.net/browse/DSP-16055
|
|
24
|
+
// We need to harden this logic asap.
|
|
24
25
|
// It currently generates a false positive for:
|
|
25
26
|
// styled.div({
|
|
26
27
|
// marginTop: "0px",
|
|
27
|
-
// marginBottom:
|
|
28
|
+
// marginBottom: blah(...),
|
|
28
29
|
// })
|
|
29
|
-
// as the value for `marginBottom` is not a string,
|
|
30
|
-
// from the resulting map and this
|
|
30
|
+
// as the value for `marginBottom` is not a string nor a `token` call, it is just skipped
|
|
31
|
+
// from the resulting map and this is inaccurate.
|
|
31
32
|
styles.properties.forEach(function (prop) {
|
|
33
|
+
// cases we want to skip (see note above)
|
|
32
34
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(prop, 'Property')) {
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
37
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(prop.key, 'Identifier')) {
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
|
|
41
|
+
// a literal string value, the base case
|
|
42
|
+
if ((0, _eslintCodemodUtils.isNodeOfType)(prop.value, 'Literal') && typeof prop.value.value === 'string') {
|
|
43
|
+
styleObj[prop.key.name] = prop.value.value;
|
|
40
44
|
}
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
|
|
46
|
+
// try to handle a direct call to `token`
|
|
47
|
+
if ((0, _eslintCodemodUtils.isNodeOfType)(prop.value, 'CallExpression')) {
|
|
48
|
+
var _callExpression$argum;
|
|
49
|
+
var callExpression = prop.value;
|
|
50
|
+
// skip if not a call to `token`
|
|
51
|
+
if (!(0, _eslintCodemodUtils.isNodeOfType)(callExpression.callee, 'Identifier') || callExpression.callee.name !== 'token') {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// only two valid cases are supported
|
|
56
|
+
// one argument => token('space.100')
|
|
57
|
+
// two arguments => token('space.100', '8px')
|
|
58
|
+
if (callExpression.arguments.length !== 1 && callExpression.arguments.length !== 2 || !(0, _eslintCodemodUtils.isNodeOfType)(callExpression.arguments[0], 'Literal') || callExpression.arguments[1] && !(0, _eslintCodemodUtils.isNodeOfType)(callExpression.arguments[1], 'Literal')) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
styleObj[prop.key.name] = {
|
|
62
|
+
tokenName: String(callExpression.arguments[0].value),
|
|
63
|
+
fallbackValue: (_callExpression$argum = callExpression.arguments[1]) !== null && _callExpression$argum !== void 0 && _callExpression$argum.value ? String(callExpression.arguments[1].value) : undefined
|
|
64
|
+
};
|
|
43
65
|
}
|
|
44
|
-
styleObj[prop.key.name] = prop.value.value;
|
|
45
66
|
});
|
|
46
67
|
return styleObj;
|
|
47
68
|
};
|
|
@@ -34,6 +34,7 @@ var findValidStyledComponentCall = exports.findValidStyledComponentCall = functi
|
|
|
34
34
|
*
|
|
35
35
|
* In the future it could be enhanced to double check `styled` and `styled2`
|
|
36
36
|
* are Compiled imports but as is should work for the majority of use cases
|
|
37
|
+
* https://product-fabric.atlassian.net/browse/DSP-16058
|
|
37
38
|
*/
|
|
38
39
|
var isStyledCallExpression = function isStyledCallExpression(call) {
|
|
39
40
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(call, 'CallExpression')) {
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.getVariableUsagesCount = void 0;
|
|
7
7
|
/**
|
|
8
|
+
* TODO: Update this logic: https://product-fabric.atlassian.net/browse/DSP-16059
|
|
8
9
|
* Using Regex here because otherwise we'd need to traverse the entire AST
|
|
9
10
|
* We should harden this logic as we go.
|
|
10
11
|
*/
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
7
|
exports.isValidCssPropertiesToTransform = void 0;
|
|
8
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
7
9
|
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
8
10
|
var _cssToXcss = require("../transformers/css-to-xcss");
|
|
9
11
|
var _convertAstObjectExpressionToJsObject = require("./convert-ast-object-expression-to-js-object");
|
|
10
|
-
var isValidCssPropertiesToTransform = exports.isValidCssPropertiesToTransform = function isValidCssPropertiesToTransform(node) {
|
|
12
|
+
var isValidCssPropertiesToTransform = exports.isValidCssPropertiesToTransform = function isValidCssPropertiesToTransform(node, config) {
|
|
11
13
|
var cssObjectExpression = node.arguments[0];
|
|
12
14
|
// Bail on empty object calls
|
|
13
15
|
if (!cssObjectExpression || !(0, _eslintCodemodUtils.isNodeOfType)(cssObjectExpression, 'ObjectExpression')) {
|
|
@@ -18,6 +20,12 @@ var isValidCssPropertiesToTransform = exports.isValidCssPropertiesToTransform =
|
|
|
18
20
|
if (!cssObject || Object.keys(cssObject).length !== 1) {
|
|
19
21
|
return false;
|
|
20
22
|
}
|
|
23
|
+
// Short-circuit when token calls are found but pattern is not enabled in config
|
|
24
|
+
if (!config.patterns.includes('css-property-with-tokens') && Object.values(cssObject).some(function (value) {
|
|
25
|
+
return (0, _typeof2.default)(value) === 'object' && value.tokenName;
|
|
26
|
+
})) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
21
29
|
|
|
22
30
|
// NOTE: Our approach with this lint rule is to strictly whitelist css properties we can map.
|
|
23
31
|
// It means we have to provide mappings for everything (e.g. `display: block`).
|
|
@@ -25,10 +33,22 @@ var isValidCssPropertiesToTransform = exports.isValidCssPropertiesToTransform =
|
|
|
25
33
|
// than the rule reporting on things that can't be mapped.
|
|
26
34
|
var containsOnlyValidStyles = Object.keys(cssObject).every(function (styleProperty) {
|
|
27
35
|
var styleValue = cssObject[styleProperty];
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
|
|
37
|
+
// token function call
|
|
38
|
+
if ((0, _typeof2.default)(styleValue) === 'object') {
|
|
39
|
+
// if there is no fallback value, we just map to the token name, if one is found
|
|
40
|
+
if (!styleValue.fallbackValue) {
|
|
41
|
+
return _cssToXcss.supportedStylesMap[styleProperty] && Object.values(_cssToXcss.supportedStylesMap[styleProperty]).includes(styleValue.tokenName);
|
|
42
|
+
}
|
|
43
|
+
// token with fallback
|
|
44
|
+
return _cssToXcss.supportedStylesMap[styleProperty] && _cssToXcss.supportedStylesMap[styleProperty][styleValue.fallbackValue] === styleValue.tokenName;
|
|
45
|
+
} else {
|
|
46
|
+
// direct value used
|
|
47
|
+
return _cssToXcss.supportedStylesMap[styleProperty] &&
|
|
48
|
+
// Is the key something we can map
|
|
49
|
+
_cssToXcss.supportedStylesMap[styleProperty][styleValue] // Is the value something we can map
|
|
50
|
+
;
|
|
51
|
+
}
|
|
32
52
|
});
|
|
33
53
|
|
|
34
54
|
if (!containsOnlyValidStyles) {
|
|
@@ -31,7 +31,7 @@ const rule = createLintRule({
|
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
const styledComponentVariableRef = findValidStyledComponentCall(node);
|
|
34
|
-
if (!styledComponentVariableRef || !isNodeOfType(styledComponentVariableRef.id, 'Identifier') || !isValidCssPropertiesToTransform(node)) {
|
|
34
|
+
if (!styledComponentVariableRef || !isNodeOfType(styledComponentVariableRef.id, 'Identifier') || !isValidCssPropertiesToTransform(node, config)) {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
const styledComponentJsxRef = findValidJsxUsageToTransform(styledComponentVariableRef.id.name, context.getScope());
|
|
@@ -54,7 +54,9 @@ const rule = createLintRule({
|
|
|
54
54
|
},
|
|
55
55
|
// transforms <div css={...}> usages
|
|
56
56
|
JSXOpeningElement(node) {
|
|
57
|
-
|
|
57
|
+
if (!config.patterns.includes('compiled-css-function')) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
58
60
|
if (!isNodeOfType(node, 'JSXOpeningElement')) {
|
|
59
61
|
return;
|
|
60
62
|
}
|
|
@@ -129,9 +131,6 @@ const shouldSuggestBox = (node, context, config
|
|
|
129
131
|
if (!cssVariableValue || !isFunctionNamed(cssVariableValue, 'css')) {
|
|
130
132
|
return false;
|
|
131
133
|
}
|
|
132
|
-
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
return isValidCssPropertiesToTransform(cssVariableValue.node.init);
|
|
134
|
+
return isValidCssPropertiesToTransform(cssVariableValue.node.init, config);
|
|
136
135
|
};
|
|
137
136
|
export default rule;
|
|
@@ -31,7 +31,7 @@ export const cssToXcssTransformer = (node, context, fixer) => {
|
|
|
31
31
|
fixer.replaceText(cssVariableValue.node.init.callee, identifier('xcss').toString()), ...styledObjectToXcssTokens(cssObjectExpression, fixer)];
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
// Update css object values to xcss values
|
|
34
|
+
// Update css object values to xcss values
|
|
35
35
|
// Note: `properties` in this context is a group of AST nodes that make up a key/value pair in an object.
|
|
36
36
|
// e.g. `padding: '8px'`. For clarity, it's renamed to `entry` inside the `.map()`.
|
|
37
37
|
export const styledObjectToXcssTokens = (styles, fixer) => {
|
|
@@ -42,16 +42,30 @@ export const styledObjectToXcssTokens = (styles, fixer) => {
|
|
|
42
42
|
if (!isNodeOfType(entry.key, 'Identifier')) {
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
|
|
46
|
+
// maps literal values like: 8px to 'space.100'
|
|
47
|
+
if (isNodeOfType(entry.value, 'Literal')) {
|
|
48
|
+
const value = entry.value.value;
|
|
49
|
+
if (typeof value !== 'string') {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
return fixer.replaceText(entry.value, literal(`'${supportedStylesMap[entry.key.name][value]}'`).toString());
|
|
47
53
|
}
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
|
|
54
|
+
// maps token calls like: token('space.100') to 'space.100'
|
|
55
|
+
if (isNodeOfType(entry.value, 'CallExpression')) {
|
|
56
|
+
const callExpression = entry.value;
|
|
57
|
+
// skip if not a call to `token`
|
|
58
|
+
if (!isNodeOfType(callExpression.callee, 'Identifier') || callExpression.callee.name !== 'token' || !isNodeOfType(callExpression.arguments[0], 'Literal')) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// the first argument of `token` is the token name and
|
|
62
|
+
// can be given directly to `xcss` as it has been validated already.
|
|
63
|
+
return fixer.replaceText(entry.value, literal(`'${callExpression.arguments[0].value}'`).toString());
|
|
51
64
|
}
|
|
52
|
-
return fixer.replaceText(entry.value, literal(`'${supportedStylesMap[entry.key.name][value]}'`).toString());
|
|
53
65
|
});
|
|
54
66
|
};
|
|
67
|
+
|
|
68
|
+
// TODO: https://product-fabric.atlassian.net/browse/DSP-16054
|
|
55
69
|
export const spaceTokenMap = {
|
|
56
70
|
'0px': 'space.0',
|
|
57
71
|
'2px': 'space.025',
|
package/dist/es2019/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.js
CHANGED
|
@@ -13,28 +13,49 @@ export const convertASTObjectExpressionToJSObject = styles => {
|
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
// TODO:
|
|
16
|
+
// TODO: https://product-fabric.atlassian.net/browse/DSP-16055
|
|
17
|
+
// We need to harden this logic asap.
|
|
17
18
|
// It currently generates a false positive for:
|
|
18
19
|
// styled.div({
|
|
19
20
|
// marginTop: "0px",
|
|
20
|
-
// marginBottom:
|
|
21
|
+
// marginBottom: blah(...),
|
|
21
22
|
// })
|
|
22
|
-
// as the value for `marginBottom` is not a string,
|
|
23
|
-
// from the resulting map and this
|
|
23
|
+
// as the value for `marginBottom` is not a string nor a `token` call, it is just skipped
|
|
24
|
+
// from the resulting map and this is inaccurate.
|
|
24
25
|
styles.properties.forEach(prop => {
|
|
26
|
+
// cases we want to skip (see note above)
|
|
25
27
|
if (!isNodeOfType(prop, 'Property')) {
|
|
26
28
|
return;
|
|
27
29
|
}
|
|
28
30
|
if (!isNodeOfType(prop.key, 'Identifier')) {
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
|
|
34
|
+
// a literal string value, the base case
|
|
35
|
+
if (isNodeOfType(prop.value, 'Literal') && typeof prop.value.value === 'string') {
|
|
36
|
+
styleObj[prop.key.name] = prop.value.value;
|
|
33
37
|
}
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
|
|
39
|
+
// try to handle a direct call to `token`
|
|
40
|
+
if (isNodeOfType(prop.value, 'CallExpression')) {
|
|
41
|
+
var _callExpression$argum;
|
|
42
|
+
const callExpression = prop.value;
|
|
43
|
+
// skip if not a call to `token`
|
|
44
|
+
if (!isNodeOfType(callExpression.callee, 'Identifier') || callExpression.callee.name !== 'token') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// only two valid cases are supported
|
|
49
|
+
// one argument => token('space.100')
|
|
50
|
+
// two arguments => token('space.100', '8px')
|
|
51
|
+
if (callExpression.arguments.length !== 1 && callExpression.arguments.length !== 2 || !isNodeOfType(callExpression.arguments[0], 'Literal') || callExpression.arguments[1] && !isNodeOfType(callExpression.arguments[1], 'Literal')) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
styleObj[prop.key.name] = {
|
|
55
|
+
tokenName: String(callExpression.arguments[0].value),
|
|
56
|
+
fallbackValue: (_callExpression$argum = callExpression.arguments[1]) !== null && _callExpression$argum !== void 0 && _callExpression$argum.value ? String(callExpression.arguments[1].value) : undefined
|
|
57
|
+
};
|
|
36
58
|
}
|
|
37
|
-
styleObj[prop.key.name] = prop.value.value;
|
|
38
59
|
});
|
|
39
60
|
return styleObj;
|
|
40
61
|
};
|
|
@@ -29,6 +29,7 @@ export const findValidStyledComponentCall = node => {
|
|
|
29
29
|
*
|
|
30
30
|
* In the future it could be enhanced to double check `styled` and `styled2`
|
|
31
31
|
* are Compiled imports but as is should work for the majority of use cases
|
|
32
|
+
* https://product-fabric.atlassian.net/browse/DSP-16058
|
|
32
33
|
*/
|
|
33
34
|
const isStyledCallExpression = call => {
|
|
34
35
|
if (!isNodeOfType(call, 'CallExpression')) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
2
|
import { supportedStylesMap } from '../transformers/css-to-xcss';
|
|
3
3
|
import { convertASTObjectExpressionToJSObject } from './convert-ast-object-expression-to-js-object';
|
|
4
|
-
export const isValidCssPropertiesToTransform = node => {
|
|
4
|
+
export const isValidCssPropertiesToTransform = (node, config) => {
|
|
5
5
|
const cssObjectExpression = node.arguments[0];
|
|
6
6
|
// Bail on empty object calls
|
|
7
7
|
if (!cssObjectExpression || !isNodeOfType(cssObjectExpression, 'ObjectExpression')) {
|
|
@@ -12,6 +12,10 @@ export const isValidCssPropertiesToTransform = node => {
|
|
|
12
12
|
if (!cssObject || Object.keys(cssObject).length !== 1) {
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
15
|
+
// Short-circuit when token calls are found but pattern is not enabled in config
|
|
16
|
+
if (!config.patterns.includes('css-property-with-tokens') && Object.values(cssObject).some(value => typeof value === 'object' && value.tokenName)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
15
19
|
|
|
16
20
|
// NOTE: Our approach with this lint rule is to strictly whitelist css properties we can map.
|
|
17
21
|
// It means we have to provide mappings for everything (e.g. `display: block`).
|
|
@@ -19,10 +23,22 @@ export const isValidCssPropertiesToTransform = node => {
|
|
|
19
23
|
// than the rule reporting on things that can't be mapped.
|
|
20
24
|
const containsOnlyValidStyles = Object.keys(cssObject).every(styleProperty => {
|
|
21
25
|
const styleValue = cssObject[styleProperty];
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
|
|
27
|
+
// token function call
|
|
28
|
+
if (typeof styleValue === 'object') {
|
|
29
|
+
// if there is no fallback value, we just map to the token name, if one is found
|
|
30
|
+
if (!styleValue.fallbackValue) {
|
|
31
|
+
return supportedStylesMap[styleProperty] && Object.values(supportedStylesMap[styleProperty]).includes(styleValue.tokenName);
|
|
32
|
+
}
|
|
33
|
+
// token with fallback
|
|
34
|
+
return supportedStylesMap[styleProperty] && supportedStylesMap[styleProperty][styleValue.fallbackValue] === styleValue.tokenName;
|
|
35
|
+
} else {
|
|
36
|
+
// direct value used
|
|
37
|
+
return supportedStylesMap[styleProperty] &&
|
|
38
|
+
// Is the key something we can map
|
|
39
|
+
supportedStylesMap[styleProperty][styleValue] // Is the value something we can map
|
|
40
|
+
;
|
|
41
|
+
}
|
|
26
42
|
});
|
|
27
43
|
|
|
28
44
|
if (!containsOnlyValidStyles) {
|
|
@@ -31,7 +31,7 @@ var rule = createLintRule({
|
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
var styledComponentVariableRef = findValidStyledComponentCall(node);
|
|
34
|
-
if (!styledComponentVariableRef || !isNodeOfType(styledComponentVariableRef.id, 'Identifier') || !isValidCssPropertiesToTransform(node)) {
|
|
34
|
+
if (!styledComponentVariableRef || !isNodeOfType(styledComponentVariableRef.id, 'Identifier') || !isValidCssPropertiesToTransform(node, config)) {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
var styledComponentJsxRef = findValidJsxUsageToTransform(styledComponentVariableRef.id.name, context.getScope());
|
|
@@ -54,7 +54,9 @@ var rule = createLintRule({
|
|
|
54
54
|
},
|
|
55
55
|
// transforms <div css={...}> usages
|
|
56
56
|
JSXOpeningElement: function JSXOpeningElement(node) {
|
|
57
|
-
|
|
57
|
+
if (!config.patterns.includes('compiled-css-function')) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
58
60
|
if (!isNodeOfType(node, 'JSXOpeningElement')) {
|
|
59
61
|
return;
|
|
60
62
|
}
|
|
@@ -129,9 +131,6 @@ var shouldSuggestBox = function shouldSuggestBox(node, context, config
|
|
|
129
131
|
if (!cssVariableValue || !isFunctionNamed(cssVariableValue, 'css')) {
|
|
130
132
|
return false;
|
|
131
133
|
}
|
|
132
|
-
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
return isValidCssPropertiesToTransform(cssVariableValue.node.init);
|
|
134
|
+
return isValidCssPropertiesToTransform(cssVariableValue.node.init, config);
|
|
136
135
|
};
|
|
137
136
|
export default rule;
|
|
@@ -32,7 +32,7 @@ export var cssToXcssTransformer = function cssToXcssTransformer(node, context, f
|
|
|
32
32
|
fixer.replaceText(cssVariableValue.node.init.callee, identifier('xcss').toString())].concat(_toConsumableArray(styledObjectToXcssTokens(cssObjectExpression, fixer)));
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
// Update css object values to xcss values
|
|
35
|
+
// Update css object values to xcss values
|
|
36
36
|
// Note: `properties` in this context is a group of AST nodes that make up a key/value pair in an object.
|
|
37
37
|
// e.g. `padding: '8px'`. For clarity, it's renamed to `entry` inside the `.map()`.
|
|
38
38
|
export var styledObjectToXcssTokens = function styledObjectToXcssTokens(styles, fixer) {
|
|
@@ -43,16 +43,30 @@ export var styledObjectToXcssTokens = function styledObjectToXcssTokens(styles,
|
|
|
43
43
|
if (!isNodeOfType(entry.key, 'Identifier')) {
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
|
|
47
|
+
// maps literal values like: 8px to 'space.100'
|
|
48
|
+
if (isNodeOfType(entry.value, 'Literal')) {
|
|
49
|
+
var value = entry.value.value;
|
|
50
|
+
if (typeof value !== 'string') {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
return fixer.replaceText(entry.value, literal("'".concat(supportedStylesMap[entry.key.name][value], "'")).toString());
|
|
48
54
|
}
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
55
|
+
// maps token calls like: token('space.100') to 'space.100'
|
|
56
|
+
if (isNodeOfType(entry.value, 'CallExpression')) {
|
|
57
|
+
var callExpression = entry.value;
|
|
58
|
+
// skip if not a call to `token`
|
|
59
|
+
if (!isNodeOfType(callExpression.callee, 'Identifier') || callExpression.callee.name !== 'token' || !isNodeOfType(callExpression.arguments[0], 'Literal')) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// the first argument of `token` is the token name and
|
|
63
|
+
// can be given directly to `xcss` as it has been validated already.
|
|
64
|
+
return fixer.replaceText(entry.value, literal("'".concat(callExpression.arguments[0].value, "'")).toString());
|
|
52
65
|
}
|
|
53
|
-
return fixer.replaceText(entry.value, literal("'".concat(supportedStylesMap[entry.key.name][value], "'")).toString());
|
|
54
66
|
});
|
|
55
67
|
};
|
|
68
|
+
|
|
69
|
+
// TODO: https://product-fabric.atlassian.net/browse/DSP-16054
|
|
56
70
|
export var spaceTokenMap = {
|
|
57
71
|
'0px': 'space.0',
|
|
58
72
|
'2px': 'space.025',
|
|
@@ -15,28 +15,49 @@ export var convertASTObjectExpressionToJSObject = function convertASTObjectExpre
|
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// TODO:
|
|
18
|
+
// TODO: https://product-fabric.atlassian.net/browse/DSP-16055
|
|
19
|
+
// We need to harden this logic asap.
|
|
19
20
|
// It currently generates a false positive for:
|
|
20
21
|
// styled.div({
|
|
21
22
|
// marginTop: "0px",
|
|
22
|
-
// marginBottom:
|
|
23
|
+
// marginBottom: blah(...),
|
|
23
24
|
// })
|
|
24
|
-
// as the value for `marginBottom` is not a string,
|
|
25
|
-
// from the resulting map and this
|
|
25
|
+
// as the value for `marginBottom` is not a string nor a `token` call, it is just skipped
|
|
26
|
+
// from the resulting map and this is inaccurate.
|
|
26
27
|
styles.properties.forEach(function (prop) {
|
|
28
|
+
// cases we want to skip (see note above)
|
|
27
29
|
if (!isNodeOfType(prop, 'Property')) {
|
|
28
30
|
return;
|
|
29
31
|
}
|
|
30
32
|
if (!isNodeOfType(prop.key, 'Identifier')) {
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
|
|
36
|
+
// a literal string value, the base case
|
|
37
|
+
if (isNodeOfType(prop.value, 'Literal') && typeof prop.value.value === 'string') {
|
|
38
|
+
styleObj[prop.key.name] = prop.value.value;
|
|
35
39
|
}
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
|
|
41
|
+
// try to handle a direct call to `token`
|
|
42
|
+
if (isNodeOfType(prop.value, 'CallExpression')) {
|
|
43
|
+
var _callExpression$argum;
|
|
44
|
+
var callExpression = prop.value;
|
|
45
|
+
// skip if not a call to `token`
|
|
46
|
+
if (!isNodeOfType(callExpression.callee, 'Identifier') || callExpression.callee.name !== 'token') {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// only two valid cases are supported
|
|
51
|
+
// one argument => token('space.100')
|
|
52
|
+
// two arguments => token('space.100', '8px')
|
|
53
|
+
if (callExpression.arguments.length !== 1 && callExpression.arguments.length !== 2 || !isNodeOfType(callExpression.arguments[0], 'Literal') || callExpression.arguments[1] && !isNodeOfType(callExpression.arguments[1], 'Literal')) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
styleObj[prop.key.name] = {
|
|
57
|
+
tokenName: String(callExpression.arguments[0].value),
|
|
58
|
+
fallbackValue: (_callExpression$argum = callExpression.arguments[1]) !== null && _callExpression$argum !== void 0 && _callExpression$argum.value ? String(callExpression.arguments[1].value) : undefined
|
|
59
|
+
};
|
|
38
60
|
}
|
|
39
|
-
styleObj[prop.key.name] = prop.value.value;
|
|
40
61
|
});
|
|
41
62
|
return styleObj;
|
|
42
63
|
};
|
|
@@ -29,6 +29,7 @@ export var findValidStyledComponentCall = function findValidStyledComponentCall(
|
|
|
29
29
|
*
|
|
30
30
|
* In the future it could be enhanced to double check `styled` and `styled2`
|
|
31
31
|
* are Compiled imports but as is should work for the majority of use cases
|
|
32
|
+
* https://product-fabric.atlassian.net/browse/DSP-16058
|
|
32
33
|
*/
|
|
33
34
|
var isStyledCallExpression = function isStyledCallExpression(call) {
|
|
34
35
|
if (!isNodeOfType(call, 'CallExpression')) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import _typeof from "@babel/runtime/helpers/typeof";
|
|
1
2
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
3
|
import { supportedStylesMap } from '../transformers/css-to-xcss';
|
|
3
4
|
import { convertASTObjectExpressionToJSObject } from './convert-ast-object-expression-to-js-object';
|
|
4
|
-
export var isValidCssPropertiesToTransform = function isValidCssPropertiesToTransform(node) {
|
|
5
|
+
export var isValidCssPropertiesToTransform = function isValidCssPropertiesToTransform(node, config) {
|
|
5
6
|
var cssObjectExpression = node.arguments[0];
|
|
6
7
|
// Bail on empty object calls
|
|
7
8
|
if (!cssObjectExpression || !isNodeOfType(cssObjectExpression, 'ObjectExpression')) {
|
|
@@ -12,6 +13,12 @@ export var isValidCssPropertiesToTransform = function isValidCssPropertiesToTran
|
|
|
12
13
|
if (!cssObject || Object.keys(cssObject).length !== 1) {
|
|
13
14
|
return false;
|
|
14
15
|
}
|
|
16
|
+
// Short-circuit when token calls are found but pattern is not enabled in config
|
|
17
|
+
if (!config.patterns.includes('css-property-with-tokens') && Object.values(cssObject).some(function (value) {
|
|
18
|
+
return _typeof(value) === 'object' && value.tokenName;
|
|
19
|
+
})) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
15
22
|
|
|
16
23
|
// NOTE: Our approach with this lint rule is to strictly whitelist css properties we can map.
|
|
17
24
|
// It means we have to provide mappings for everything (e.g. `display: block`).
|
|
@@ -19,10 +26,22 @@ export var isValidCssPropertiesToTransform = function isValidCssPropertiesToTran
|
|
|
19
26
|
// than the rule reporting on things that can't be mapped.
|
|
20
27
|
var containsOnlyValidStyles = Object.keys(cssObject).every(function (styleProperty) {
|
|
21
28
|
var styleValue = cssObject[styleProperty];
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
// token function call
|
|
31
|
+
if (_typeof(styleValue) === 'object') {
|
|
32
|
+
// if there is no fallback value, we just map to the token name, if one is found
|
|
33
|
+
if (!styleValue.fallbackValue) {
|
|
34
|
+
return supportedStylesMap[styleProperty] && Object.values(supportedStylesMap[styleProperty]).includes(styleValue.tokenName);
|
|
35
|
+
}
|
|
36
|
+
// token with fallback
|
|
37
|
+
return supportedStylesMap[styleProperty] && supportedStylesMap[styleProperty][styleValue.fallbackValue] === styleValue.tokenName;
|
|
38
|
+
} else {
|
|
39
|
+
// direct value used
|
|
40
|
+
return supportedStylesMap[styleProperty] &&
|
|
41
|
+
// Is the key something we can map
|
|
42
|
+
supportedStylesMap[styleProperty][styleValue] // Is the value something we can map
|
|
43
|
+
;
|
|
44
|
+
}
|
|
26
45
|
});
|
|
27
46
|
|
|
28
47
|
if (!containsOnlyValidStyles) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
type Pattern = 'compiled-css-function' | 'compiled-styled-object' | 'css-template-literal' | 'css-property-with-tokens' | 'css-property-multiple-values';
|
|
1
2
|
export interface RuleConfig {
|
|
2
|
-
patterns:
|
|
3
|
+
patterns: Pattern[];
|
|
3
4
|
}
|
|
4
5
|
export declare const getConfig: (overrides: Partial<RuleConfig>) => Required<RuleConfig>;
|
|
6
|
+
export {};
|
package/dist/types/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
2
|
import { ObjectExpression } from 'eslint-codemod-utils';
|
|
3
|
+
type Token = {
|
|
4
|
+
tokenName: string;
|
|
5
|
+
fallbackValue: string | undefined;
|
|
6
|
+
};
|
|
3
7
|
export type CSSPropStyleObject = {
|
|
4
|
-
[key: string]: string | number;
|
|
8
|
+
[key: string]: string | number | Token;
|
|
5
9
|
};
|
|
6
10
|
/**
|
|
7
11
|
* Note: Not recursive. Only handles top level key/value pairs
|
|
8
12
|
*/
|
|
9
13
|
export declare const convertASTObjectExpressionToJSObject: (styles: ObjectExpression & Partial<Rule.NodeParentExtension>) => CSSPropStyleObject | false;
|
|
14
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
2
|
import { SimpleCallExpression } from 'eslint-codemod-utils';
|
|
3
|
-
|
|
3
|
+
import { RuleConfig } from '../config';
|
|
4
|
+
export declare const isValidCssPropertiesToTransform: (node: SimpleCallExpression & Rule.NodeParentExtension, config: RuleConfig) => boolean;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
type Pattern = 'compiled-css-function' | 'compiled-styled-object' | 'css-template-literal' | 'css-property-with-tokens' | 'css-property-multiple-values';
|
|
1
2
|
export interface RuleConfig {
|
|
2
|
-
patterns:
|
|
3
|
+
patterns: Pattern[];
|
|
3
4
|
}
|
|
4
5
|
export declare const getConfig: (overrides: Partial<RuleConfig>) => Required<RuleConfig>;
|
|
6
|
+
export {};
|
package/dist/types-ts4.5/rules/use-primitives/utils/convert-ast-object-expression-to-js-object.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
2
|
import { ObjectExpression } from 'eslint-codemod-utils';
|
|
3
|
+
type Token = {
|
|
4
|
+
tokenName: string;
|
|
5
|
+
fallbackValue: string | undefined;
|
|
6
|
+
};
|
|
3
7
|
export type CSSPropStyleObject = {
|
|
4
|
-
[key: string]: string | number;
|
|
8
|
+
[key: string]: string | number | Token;
|
|
5
9
|
};
|
|
6
10
|
/**
|
|
7
11
|
* Note: Not recursive. Only handles top level key/value pairs
|
|
8
12
|
*/
|
|
9
13
|
export declare const convertASTObjectExpressionToJSObject: (styles: ObjectExpression & Partial<Rule.NodeParentExtension>) => CSSPropStyleObject | false;
|
|
14
|
+
export {};
|
package/dist/types-ts4.5/rules/use-primitives/utils/is-valid-css-properties-to-transform.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
2
|
import { SimpleCallExpression } from 'eslint-codemod-utils';
|
|
3
|
-
|
|
3
|
+
import { RuleConfig } from '../config';
|
|
4
|
+
export declare const isValidCssPropertiesToTransform: (node: SimpleCallExpression & Rule.NodeParentExtension, config: RuleConfig) => boolean;
|
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": "8.19.
|
|
4
|
+
"version": "8.19.2",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"registry": "https://registry.npmjs.org/"
|