@atlaskit/eslint-plugin-design-system 8.25.2 → 8.27.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 +42 -0
- package/README.md +4 -0
- package/constellation/index/usage.mdx +402 -6
- package/dist/cjs/presets/all.codegen.js +5 -1
- package/dist/cjs/presets/recommended.codegen.js +5 -1
- package/dist/cjs/rules/consistent-css-prop-usage/index.js +254 -32
- package/dist/cjs/rules/index.codegen.js +9 -1
- package/dist/cjs/rules/no-empty-styled-expression/index.js +75 -0
- package/dist/cjs/rules/no-exported-css/index.js +37 -0
- package/dist/cjs/rules/no-exported-keyframes/index.js +37 -0
- package/dist/cjs/rules/no-invalid-css-map/index.js +102 -0
- package/dist/cjs/rules/no-invalid-css-map/utils.js +193 -0
- package/dist/cjs/rules/utils/create-no-exported-rule/check-if-supported-export.js +158 -0
- package/dist/cjs/rules/utils/create-no-exported-rule/is-styled-component.js +80 -0
- package/dist/cjs/rules/utils/create-no-exported-rule/main.js +66 -0
- package/dist/cjs/rules/utils/get-first-supported-import.js +28 -0
- package/dist/cjs/rules/utils/is-supported-import.js +53 -16
- package/dist/es2019/presets/all.codegen.js +5 -1
- package/dist/es2019/presets/recommended.codegen.js +5 -1
- package/dist/es2019/rules/consistent-css-prop-usage/index.js +251 -33
- package/dist/es2019/rules/index.codegen.js +9 -1
- package/dist/es2019/rules/no-empty-styled-expression/index.js +65 -0
- package/dist/es2019/rules/no-exported-css/index.js +31 -0
- package/dist/es2019/rules/no-exported-keyframes/index.js +31 -0
- package/dist/es2019/rules/no-invalid-css-map/index.js +95 -0
- package/dist/es2019/rules/no-invalid-css-map/utils.js +134 -0
- package/dist/es2019/rules/utils/create-no-exported-rule/check-if-supported-export.js +142 -0
- package/dist/es2019/rules/utils/create-no-exported-rule/is-styled-component.js +70 -0
- package/dist/es2019/rules/utils/create-no-exported-rule/main.js +59 -0
- package/dist/es2019/rules/utils/get-first-supported-import.js +22 -0
- package/dist/es2019/rules/utils/is-supported-import.js +50 -15
- package/dist/esm/presets/all.codegen.js +5 -1
- package/dist/esm/presets/recommended.codegen.js +5 -1
- package/dist/esm/rules/consistent-css-prop-usage/index.js +255 -33
- package/dist/esm/rules/index.codegen.js +9 -1
- package/dist/esm/rules/no-empty-styled-expression/index.js +68 -0
- package/dist/esm/rules/no-exported-css/index.js +31 -0
- package/dist/esm/rules/no-exported-keyframes/index.js +31 -0
- package/dist/esm/rules/no-invalid-css-map/index.js +96 -0
- package/dist/esm/rules/no-invalid-css-map/utils.js +186 -0
- package/dist/esm/rules/utils/create-no-exported-rule/check-if-supported-export.js +151 -0
- package/dist/esm/rules/utils/create-no-exported-rule/is-styled-component.js +74 -0
- package/dist/esm/rules/utils/create-no-exported-rule/main.js +60 -0
- package/dist/esm/rules/utils/get-first-supported-import.js +22 -0
- package/dist/esm/rules/utils/is-supported-import.js +51 -15
- package/dist/types/index.codegen.d.ts +8 -0
- package/dist/types/presets/all.codegen.d.ts +5 -1
- package/dist/types/presets/recommended.codegen.d.ts +5 -1
- package/dist/types/rules/consistent-css-prop-usage/types.d.ts +7 -2
- package/dist/types/rules/index.codegen.d.ts +4 -0
- package/dist/types/rules/no-empty-styled-expression/index.d.ts +3 -0
- package/dist/types/rules/no-exported-css/index.d.ts +3 -0
- package/dist/types/rules/no-exported-keyframes/index.d.ts +3 -0
- package/dist/types/rules/no-invalid-css-map/index.d.ts +3 -0
- package/dist/types/rules/no-invalid-css-map/utils.d.ts +14 -0
- package/dist/types/rules/use-primitives/utils/update-jsx-attribute-by-name.d.ts +1 -1
- package/dist/types/rules/utils/create-no-exported-rule/check-if-supported-export.d.ts +15 -0
- package/dist/types/rules/utils/create-no-exported-rule/is-styled-component.d.ts +14 -0
- package/dist/types/rules/utils/create-no-exported-rule/main.d.ts +19 -0
- package/dist/types/rules/utils/create-rule.d.ts +1 -1
- package/dist/types/rules/utils/get-first-supported-import.d.ts +17 -0
- package/dist/types/rules/utils/is-supported-import.d.ts +26 -8
- package/dist/types-ts4.5/index.codegen.d.ts +8 -0
- package/dist/types-ts4.5/presets/all.codegen.d.ts +5 -1
- package/dist/types-ts4.5/presets/recommended.codegen.d.ts +5 -1
- package/dist/types-ts4.5/rules/consistent-css-prop-usage/types.d.ts +7 -2
- package/dist/types-ts4.5/rules/index.codegen.d.ts +4 -0
- package/dist/types-ts4.5/rules/no-empty-styled-expression/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-exported-css/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-exported-keyframes/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-invalid-css-map/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-invalid-css-map/utils.d.ts +14 -0
- package/dist/types-ts4.5/rules/use-primitives/utils/update-jsx-attribute-by-name.d.ts +1 -1
- package/dist/types-ts4.5/rules/utils/create-no-exported-rule/check-if-supported-export.d.ts +15 -0
- package/dist/types-ts4.5/rules/utils/create-no-exported-rule/is-styled-component.d.ts +14 -0
- package/dist/types-ts4.5/rules/utils/create-no-exported-rule/main.d.ts +19 -0
- package/dist/types-ts4.5/rules/utils/create-rule.d.ts +1 -1
- package/dist/types-ts4.5/rules/utils/get-first-supported-import.d.ts +17 -0
- package/dist/types-ts4.5/rules/utils/is-supported-import.d.ts +26 -8
- package/package.json +3 -1
|
@@ -9,21 +9,28 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
|
|
|
9
9
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
10
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
11
11
|
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
12
|
+
var _estraverse = _interopRequireDefault(require("estraverse"));
|
|
12
13
|
var _assign = _interopRequireDefault(require("lodash/assign"));
|
|
14
|
+
var _astNodes = require("../../ast-nodes");
|
|
13
15
|
var _createRule = require("../utils/create-rule");
|
|
16
|
+
var _getFirstSupportedImport = require("../utils/get-first-supported-import");
|
|
17
|
+
var _getImportNodeBySource = require("../utils/get-import-node-by-source");
|
|
18
|
+
var _isSupportedImport = require("../utils/is-supported-import");
|
|
14
19
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
15
20
|
|
|
16
|
-
// File-level tracking of styles hoisted from the
|
|
21
|
+
// File-level tracking of styles hoisted from the cssAtTopOfModule/cssAtBottomOfModule fixers
|
|
17
22
|
var hoistedCss = [];
|
|
23
|
+
var isDOMElementName = function isDOMElementName(elementName) {
|
|
24
|
+
return elementName.charAt(0) !== elementName.charAt(0).toUpperCase() && elementName.charAt(0) === elementName.charAt(0).toLowerCase();
|
|
25
|
+
};
|
|
18
26
|
function isCssCallExpression(node, cssFunctions) {
|
|
19
27
|
cssFunctions = [].concat((0, _toConsumableArray2.default)(cssFunctions), ['cssMap']);
|
|
20
28
|
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');
|
|
21
29
|
}
|
|
22
30
|
function findSpreadProperties(node) {
|
|
23
|
-
// @ts-ignore
|
|
24
31
|
return node.properties.filter(function (property) {
|
|
25
32
|
return property.type === 'SpreadElement' ||
|
|
26
|
-
// @ts-
|
|
33
|
+
// @ts-expect-error
|
|
27
34
|
property.type === 'ExperimentalSpreadProperty';
|
|
28
35
|
});
|
|
29
36
|
}
|
|
@@ -34,9 +41,8 @@ var getProgramNode = function getProgramNode(expression) {
|
|
|
34
41
|
return expression.parent;
|
|
35
42
|
};
|
|
36
43
|
|
|
37
|
-
// TODO: This can be optimised by implementing a fixer at the very end (Program:exit) and handling all validations at once
|
|
38
44
|
/**
|
|
39
|
-
* Generates the declarator string when fixing the
|
|
45
|
+
* Generates the declarator string when fixing the cssAtTopOfModule/cssAtBottomOfModule cases.
|
|
40
46
|
* When `styles` already exists, `styles_1, styles_2, ..., styles_X` are incrementally created for each unhoisted style.
|
|
41
47
|
* The generated `styles` varibale declaration names must be manually modified to be more informative at the discretion of owning teams.
|
|
42
48
|
*/
|
|
@@ -68,7 +74,7 @@ var getDeclaratorString = function getDeclaratorString(context) {
|
|
|
68
74
|
hoistedCss = [].concat((0, _toConsumableArray2.default)(hoistedCss), ["".concat(declaratorName).concat(count)]);
|
|
69
75
|
return "".concat(declaratorName).concat(count);
|
|
70
76
|
};
|
|
71
|
-
function analyzeIdentifier(context, sourceIdentifier, configuration) {
|
|
77
|
+
function analyzeIdentifier(context, sourceIdentifier, configuration, cssAttributeName) {
|
|
72
78
|
var _getIdentifierInParen, _getIdentifierInParen2;
|
|
73
79
|
var scope = context.getScope();
|
|
74
80
|
var _ref = (_getIdentifierInParen = (_getIdentifierInParen2 = (0, _eslintCodemodUtils.getIdentifierInParentScope)(scope, sourceIdentifier.name)) === null || _getIdentifierInParen2 === void 0 ? void 0 : _getIdentifierInParen2.identifiers) !== null && _getIdentifierInParen !== void 0 ? _getIdentifierInParen : [],
|
|
@@ -90,8 +96,11 @@ function analyzeIdentifier(context, sourceIdentifier, configuration) {
|
|
|
90
96
|
// When variable is declared inside the component
|
|
91
97
|
context.report({
|
|
92
98
|
node: sourceIdentifier,
|
|
93
|
-
messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : '
|
|
99
|
+
messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
|
|
94
100
|
fix: function fix(fixer) {
|
|
101
|
+
if (configuration.fixNamesOnly) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
95
104
|
return fixCssNotInModuleScope(fixer, context, configuration, identifier);
|
|
96
105
|
}
|
|
97
106
|
});
|
|
@@ -99,10 +108,30 @@ function analyzeIdentifier(context, sourceIdentifier, configuration) {
|
|
|
99
108
|
}
|
|
100
109
|
if (identifier.parent && identifier.parent.init && !isCssCallExpression(identifier.parent.init, configuration.cssFunctions)) {
|
|
101
110
|
// When variable value is not of type css({})
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
111
|
+
var value = identifier.parent.init;
|
|
112
|
+
if (!value) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
var valueExpression =
|
|
116
|
+
// @ts-expect-error remove once eslint types are switched to @typescript-eslint
|
|
117
|
+
value.type === 'TSAsExpression' ? value.expression : value;
|
|
118
|
+
if (['ObjectExpression', 'TemplateLiteral'].includes(valueExpression.type)) {
|
|
119
|
+
context.report({
|
|
120
|
+
node: identifier,
|
|
121
|
+
messageId: 'cssObjectTypeOnly',
|
|
122
|
+
fix: function fix(fixer) {
|
|
123
|
+
if (configuration.fixNamesOnly) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
return addCssFunctionCall(fixer, context, identifier.parent, configuration, cssAttributeName);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
context.report({
|
|
131
|
+
node: identifier,
|
|
132
|
+
messageId: 'cssObjectTypeOnly'
|
|
133
|
+
});
|
|
134
|
+
}
|
|
106
135
|
return;
|
|
107
136
|
}
|
|
108
137
|
var spreadProperties = (0, _eslintCodemodUtils.isNodeOfType)(identifier.parent.init, 'CallExpression') && findSpreadProperties(identifier.parent.init.arguments[0]);
|
|
@@ -118,12 +147,133 @@ function analyzeIdentifier(context, sourceIdentifier, configuration) {
|
|
|
118
147
|
}
|
|
119
148
|
|
|
120
149
|
/**
|
|
121
|
-
*
|
|
150
|
+
* Returns a fixer that adds `import { css } from 'import-source'` or
|
|
151
|
+
* `import { xcss } from 'import-source'` to the start of the file, depending
|
|
152
|
+
* on the value of cssAttributeName and importSource.
|
|
153
|
+
*/
|
|
154
|
+
var addImportSource = function addImportSource(context, fixer, configuration, cssAttributeName) {
|
|
155
|
+
var importSource = cssAttributeName === 'xcss' ? configuration.xcssImportSource : configuration.cssImportSource;
|
|
156
|
+
|
|
157
|
+
// Add the `import { css } from 'my-css-in-js-library';` statement
|
|
158
|
+
var packageImport = (0, _getFirstSupportedImport.getFirstSupportedImport)(context, [importSource]);
|
|
159
|
+
if (packageImport) {
|
|
160
|
+
var addCssImport = _astNodes.Import.insertNamedSpecifiers(packageImport, [cssAttributeName], fixer);
|
|
161
|
+
if (addCssImport) {
|
|
162
|
+
return addCssImport;
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
return (0, _eslintCodemodUtils.insertAtStartOfFile)(fixer, "".concat((0, _eslintCodemodUtils.insertImportDeclaration)(importSource, [cssAttributeName]), ";\n"));
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Returns a list of fixes that:
|
|
171
|
+
* - add the `css` or `xcss` function call around the current node.
|
|
172
|
+
* - add an import statement for the package from which `css` is imported
|
|
173
|
+
*/
|
|
174
|
+
var addCssFunctionCall = function addCssFunctionCall(fixer, context, node, configuration, cssAttributeName) {
|
|
175
|
+
var fixes = [];
|
|
176
|
+
var sourceCode = context.getSourceCode();
|
|
177
|
+
if (node.type !== 'VariableDeclarator' || !node.init || !cssAttributeName) {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
var compiledImportFix = addImportSource(context, fixer, configuration, cssAttributeName);
|
|
181
|
+
if (compiledImportFix) {
|
|
182
|
+
fixes.push(compiledImportFix);
|
|
183
|
+
}
|
|
184
|
+
var init = node.init;
|
|
185
|
+
var initString = sourceCode.getText(init);
|
|
186
|
+
if (node.init.type === 'TemplateLiteral') {
|
|
187
|
+
fixes.push(fixer.replaceText(init, "".concat(cssAttributeName).concat(initString)));
|
|
188
|
+
} else {
|
|
189
|
+
fixes.push(fixer.replaceText(init, "".concat(cssAttributeName, "(").concat(initString, ")")));
|
|
190
|
+
}
|
|
191
|
+
return fixes;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Check if the expression has or potentially has a local variable
|
|
196
|
+
* (as opposed to an imported one), erring on the side ot "yes"
|
|
197
|
+
* when an expression is too complicated to analyse.
|
|
198
|
+
*
|
|
199
|
+
* This is useful because expressions containing local variables
|
|
200
|
+
* cannot be easily hoisted, whereas this is not a problem with imported
|
|
201
|
+
* variables.
|
|
202
|
+
*
|
|
203
|
+
* @param context Context of the rule.
|
|
204
|
+
* @param node Any node that is potentially hoistable.
|
|
205
|
+
* @returns Whether the node potentially has a local variable (and thus is not safe to hoist).
|
|
206
|
+
*/
|
|
207
|
+
var potentiallyHasLocalVariable = function potentiallyHasLocalVariable(context, node) {
|
|
208
|
+
var hasPotentiallyLocalVariable = false;
|
|
209
|
+
var isImportedVariable = function isImportedVariable(identifier) {
|
|
210
|
+
return !!(0, _getImportNodeBySource.getModuleOfIdentifier)(context.getSourceCode(), identifier);
|
|
211
|
+
};
|
|
212
|
+
_estraverse.default.traverse(node, {
|
|
213
|
+
enter: function enter(node, _parent) {
|
|
214
|
+
if ((0, _eslintCodemodUtils.isNodeOfType)(node, 'SpreadElement') ||
|
|
215
|
+
// @ts-expect-error remove once we can be sure that no parser interprets
|
|
216
|
+
// the spread operator as ExperimentalSpreadProperty anymore
|
|
217
|
+
(0, _eslintCodemodUtils.isNodeOfType)(node, 'ExperimentalSpreadProperty')) {
|
|
218
|
+
// Spread elements could contain anything... so we don't bother.
|
|
219
|
+
//
|
|
220
|
+
// e.g. <div css={css({ ...(!height && { visibility: 'hidden' })} />
|
|
221
|
+
hasPotentiallyLocalVariable = true;
|
|
222
|
+
this.break();
|
|
223
|
+
}
|
|
224
|
+
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'Property')) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
switch (node.value.type) {
|
|
228
|
+
case 'Literal':
|
|
229
|
+
break;
|
|
230
|
+
case 'Identifier':
|
|
231
|
+
// e.g. css({ margin: myVariable })
|
|
232
|
+
if (!isImportedVariable(node.value.name)) {
|
|
233
|
+
hasPotentiallyLocalVariable = true;
|
|
234
|
+
}
|
|
235
|
+
this.break();
|
|
236
|
+
break;
|
|
237
|
+
case 'MemberExpression':
|
|
238
|
+
// e.g. css({ margin: props.color })
|
|
239
|
+
// css({ margin: props.media.color })
|
|
240
|
+
if (node.value.object.type === 'Identifier' && isImportedVariable(node.value.object.name)) {
|
|
241
|
+
// We found an imported variable, don't do anything.
|
|
242
|
+
} else {
|
|
243
|
+
// e.g. css({ margin: [some complicated expression].media.color })
|
|
244
|
+
// This can potentially get too complex, so we assume there's a local
|
|
245
|
+
// variable in there somewhere.
|
|
246
|
+
hasPotentiallyLocalVariable = true;
|
|
247
|
+
}
|
|
248
|
+
this.break();
|
|
249
|
+
break;
|
|
250
|
+
case 'TemplateLiteral':
|
|
251
|
+
if (!!node.value.expressions.length) {
|
|
252
|
+
// Too many edge cases here, don't bother...
|
|
253
|
+
// e.g. css({ animation: `${expandStyles(right, rightExpanded, isExpanded)} 0.2s ease-in-out` });
|
|
254
|
+
hasPotentiallyLocalVariable = true;
|
|
255
|
+
this.break();
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
default:
|
|
259
|
+
// Catch-all for values such as "A && B", "A ? B : C"
|
|
260
|
+
hasPotentiallyLocalVariable = true;
|
|
261
|
+
this.break();
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
return hasPotentiallyLocalVariable;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Fixer for the cssAtTopOfModule/cssAtBottomOfModule violation cases.
|
|
122
271
|
* This deals with Identifiers and Expressions passed from the traverseExpressionWithConfig() function.
|
|
272
|
+
*
|
|
123
273
|
* @param fixer The ESLint RuleFixer object
|
|
124
|
-
* @param context The context of the
|
|
274
|
+
* @param context The context of the rule
|
|
125
275
|
* @param configuration The configuration of the rule, determining whether the fix is implmeneted at the top or bottom of the module
|
|
126
|
-
* @param node
|
|
276
|
+
* @param node Any potentially hoistable node, or an identifier.
|
|
127
277
|
* @param cssAttributeName An optional parameter only added when we fix an ObjectExpression
|
|
128
278
|
*/
|
|
129
279
|
var fixCssNotInModuleScope = function fixCssNotInModuleScope(fixer, context, configuration, node, cssAttributeName) {
|
|
@@ -142,35 +292,42 @@ var fixCssNotInModuleScope = function fixCssNotInModuleScope(fixer, context, con
|
|
|
142
292
|
});
|
|
143
293
|
}
|
|
144
294
|
var moduleString;
|
|
145
|
-
var
|
|
295
|
+
var fixes = [];
|
|
146
296
|
if (node.type === 'Identifier') {
|
|
147
297
|
var identifier = node;
|
|
148
298
|
var declarator = identifier.parent.parent;
|
|
149
299
|
moduleString = sourceCode.getText(declarator);
|
|
150
|
-
|
|
300
|
+
fixes.push(fixer.remove(declarator));
|
|
151
301
|
} else {
|
|
302
|
+
if (potentiallyHasLocalVariable(context, node)) {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
152
305
|
var _declarator = getDeclaratorString(context);
|
|
153
306
|
var text = sourceCode.getText(node);
|
|
154
307
|
|
|
155
308
|
// If this has been passed, then we know it's an ObjectExpression
|
|
156
309
|
if (cssAttributeName) {
|
|
157
310
|
moduleString = "const ".concat(_declarator, " = ").concat(cssAttributeName, "(").concat(text, ");");
|
|
311
|
+
var compiledImportFix = addImportSource(context, fixer, configuration, cssAttributeName);
|
|
312
|
+
if (compiledImportFix) {
|
|
313
|
+
fixes.push(compiledImportFix);
|
|
314
|
+
}
|
|
158
315
|
} else {
|
|
159
|
-
moduleString =
|
|
316
|
+
moduleString = "const ".concat(_declarator, " = ").concat(text, ";");
|
|
160
317
|
}
|
|
161
|
-
|
|
318
|
+
fixes.push(fixer.replaceText(node, _declarator));
|
|
162
319
|
}
|
|
163
|
-
return [].concat(
|
|
164
|
-
// Insert the node either before or after
|
|
320
|
+
return [].concat(fixes, [
|
|
321
|
+
// Insert the node either before or after, depending on the rule configuration
|
|
165
322
|
configuration.stylesPlacement === 'bottom' ? fixer.insertTextAfter(fixerNodePlacement, '\n' + moduleString) : fixer.insertTextBefore(fixerNodePlacement, moduleString + '\n')]);
|
|
166
323
|
};
|
|
167
324
|
|
|
168
325
|
/**
|
|
169
326
|
* Handle different cases based on what's been passed in the css-related JSXAttribute
|
|
170
|
-
* @param context the context of the
|
|
327
|
+
* @param context the context of the rule
|
|
171
328
|
* @param expression the expression of the JSXAttribute value
|
|
172
329
|
* @param configuration what css-related functions to account for (eg. css, xcss, cssMap), and whether to detect bottom vs top expressions
|
|
173
|
-
* @param cssAttributeName used to encapsulate ObjectExpressions when
|
|
330
|
+
* @param cssAttributeName used to encapsulate ObjectExpressions when cssAtTopOfModule/cssAtBottomOfModule violations are triggered
|
|
174
331
|
*/
|
|
175
332
|
var traverseExpressionWithConfig = function traverseExpressionWithConfig(context, expression, configuration, cssAttributeName) {
|
|
176
333
|
function traverseExpression(expression) {
|
|
@@ -178,7 +335,7 @@ var traverseExpressionWithConfig = function traverseExpressionWithConfig(context
|
|
|
178
335
|
case 'Identifier':
|
|
179
336
|
// {styles}
|
|
180
337
|
// We've found an identifier - time to analyze it!
|
|
181
|
-
analyzeIdentifier(context, expression, configuration);
|
|
338
|
+
analyzeIdentifier(context, expression, configuration, cssAttributeName);
|
|
182
339
|
break;
|
|
183
340
|
case 'ArrayExpression':
|
|
184
341
|
// {[styles, moreStyles]}
|
|
@@ -207,8 +364,12 @@ var traverseExpressionWithConfig = function traverseExpressionWithConfig(context
|
|
|
207
364
|
// We've found elements that shouldn't be here! Report an error.
|
|
208
365
|
context.report({
|
|
209
366
|
node: expression,
|
|
210
|
-
messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : '
|
|
367
|
+
messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
|
|
211
368
|
fix: function fix(fixer) {
|
|
369
|
+
if (configuration.fixNamesOnly) {
|
|
370
|
+
return [];
|
|
371
|
+
}
|
|
372
|
+
|
|
212
373
|
// Don't fix CallExpressions unless they're from cssFunctions or cssMap
|
|
213
374
|
if (expression.type === 'CallExpression' && !isCssCallExpression(expression, configuration.cssFunctions)) {
|
|
214
375
|
return [];
|
|
@@ -220,6 +381,17 @@ var traverseExpressionWithConfig = function traverseExpressionWithConfig(context
|
|
|
220
381
|
}
|
|
221
382
|
});
|
|
222
383
|
break;
|
|
384
|
+
|
|
385
|
+
// @ts-expect-error - our ESLint-related types assume vanilla JS, when in fact
|
|
386
|
+
// it is running @typescript-eslint
|
|
387
|
+
//
|
|
388
|
+
// Switching to the more accurate @typescript-eslint types would break
|
|
389
|
+
// eslint-codemod-utils and all ESLint rules in packages/design-system,
|
|
390
|
+
// so we just leave this as-is.
|
|
391
|
+
case 'TSAsExpression':
|
|
392
|
+
// @ts-expect-error
|
|
393
|
+
traverseExpression(expression.expression);
|
|
394
|
+
break;
|
|
223
395
|
default:
|
|
224
396
|
// Do nothing!
|
|
225
397
|
break;
|
|
@@ -229,10 +401,15 @@ var traverseExpressionWithConfig = function traverseExpressionWithConfig(context
|
|
|
229
401
|
};
|
|
230
402
|
var defaultConfig = {
|
|
231
403
|
cssFunctions: ['css', 'xcss'],
|
|
232
|
-
stylesPlacement: 'top'
|
|
404
|
+
stylesPlacement: 'top',
|
|
405
|
+
cssImportSource: _isSupportedImport.CSS_IN_JS_IMPORTS.compiled,
|
|
406
|
+
xcssImportSource: _isSupportedImport.CSS_IN_JS_IMPORTS.atlaskitPrimitives,
|
|
407
|
+
excludeReactComponents: false,
|
|
408
|
+
fixNamesOnly: false
|
|
233
409
|
};
|
|
234
410
|
var rule = (0, _createRule.createLintRule)({
|
|
235
411
|
meta: {
|
|
412
|
+
type: 'problem',
|
|
236
413
|
name: 'consistent-css-prop-usage',
|
|
237
414
|
docs: {
|
|
238
415
|
description: 'Ensures consistency with `css` and `xcss` prop usages',
|
|
@@ -242,13 +419,42 @@ var rule = (0, _createRule.createLintRule)({
|
|
|
242
419
|
},
|
|
243
420
|
fixable: 'code',
|
|
244
421
|
messages: {
|
|
245
|
-
|
|
422
|
+
cssAtTopOfModule: "Create styles at the top of the module scope using the respective css function.",
|
|
246
423
|
cssAtBottomOfModule: "Create styles at the bottom of the module scope using the respective css function.",
|
|
247
|
-
cssObjectTypeOnly: "Create styles using objects passed to
|
|
248
|
-
cssInModule: "Imported styles should not be used
|
|
424
|
+
cssObjectTypeOnly: "Create styles using objects passed to a css function call, e.g. `css({ textAlign: 'center'; })`.",
|
|
425
|
+
cssInModule: "Imported styles should not be used; instead define in the module, import a component, or use a design token.",
|
|
249
426
|
cssArrayStylesOnly: "Compose styles with an array on the css prop instead of using object spread.",
|
|
427
|
+
noMemberExpressions: "Styles should be a regular variable (e.g. 'buttonStyles'), not a member of an object (e.g. 'myObject.styles').",
|
|
250
428
|
shouldEndInStyles: 'Declared styles should end in "styles".'
|
|
251
|
-
}
|
|
429
|
+
},
|
|
430
|
+
schema: [{
|
|
431
|
+
type: 'object',
|
|
432
|
+
properties: {
|
|
433
|
+
cssFunctions: {
|
|
434
|
+
type: 'array',
|
|
435
|
+
items: [{
|
|
436
|
+
type: 'string'
|
|
437
|
+
}]
|
|
438
|
+
},
|
|
439
|
+
stylesPlacement: {
|
|
440
|
+
type: 'string',
|
|
441
|
+
enum: ['top', 'bottom']
|
|
442
|
+
},
|
|
443
|
+
cssImportSource: {
|
|
444
|
+
type: 'string'
|
|
445
|
+
},
|
|
446
|
+
xcssImportSource: {
|
|
447
|
+
type: 'string'
|
|
448
|
+
},
|
|
449
|
+
excludeReactComponents: {
|
|
450
|
+
type: 'boolean'
|
|
451
|
+
},
|
|
452
|
+
fixNamesOnly: {
|
|
453
|
+
type: 'boolean'
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
additionalProperties: false
|
|
457
|
+
}]
|
|
252
458
|
},
|
|
253
459
|
create: function create(context) {
|
|
254
460
|
var _ref3;
|
|
@@ -290,9 +496,20 @@ var rule = (0, _createRule.createLintRule)({
|
|
|
290
496
|
});
|
|
291
497
|
}
|
|
292
498
|
});
|
|
293
|
-
}), (0, _defineProperty2.default)(_ref3, "JSXAttribute", function JSXAttribute(
|
|
499
|
+
}), (0, _defineProperty2.default)(_ref3, "JSXAttribute", function JSXAttribute(nodeOriginal) {
|
|
500
|
+
var node = nodeOriginal;
|
|
294
501
|
var name = node.name,
|
|
295
502
|
value = node.value;
|
|
503
|
+
if (mergedConfig.excludeReactComponents && node.parent.type === 'JSXOpeningElement') {
|
|
504
|
+
// e.g. <item.before />
|
|
505
|
+
if (node.parent.name.type === 'JSXMemberExpression') {
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
// e.g. <div />, <MenuItem />
|
|
509
|
+
if (node.parent.name.type === 'JSXIdentifier' && !isDOMElementName(node.parent.name.name)) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
296
513
|
|
|
297
514
|
// Always reset to empty array
|
|
298
515
|
hoistedCss = [];
|
|
@@ -300,11 +517,16 @@ var rule = (0, _createRule.createLintRule)({
|
|
|
300
517
|
// When not a jsx expression. For eg. css=""
|
|
301
518
|
if ((value === null || value === void 0 ? void 0 : value.type) !== 'JSXExpressionContainer') {
|
|
302
519
|
context.report({
|
|
303
|
-
node:
|
|
304
|
-
messageId: mergedConfig.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : '
|
|
520
|
+
node: node,
|
|
521
|
+
messageId: mergedConfig.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule'
|
|
305
522
|
});
|
|
306
523
|
return;
|
|
307
524
|
}
|
|
525
|
+
if (value.expression.type === 'JSXEmptyExpression') {
|
|
526
|
+
// e.g. the comment in
|
|
527
|
+
// <div css={/* Hello there */} />
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
308
530
|
traverseExpressionWithConfig(context, value.expression, mergedConfig, name.name);
|
|
309
531
|
}
|
|
310
532
|
}), _ref3;
|
|
@@ -15,6 +15,10 @@ var _noCssTaggedTemplateExpression = _interopRequireDefault(require("./no-css-ta
|
|
|
15
15
|
var _noDeprecatedApis = _interopRequireDefault(require("./no-deprecated-apis"));
|
|
16
16
|
var _noDeprecatedDesignTokenUsage = _interopRequireDefault(require("./no-deprecated-design-token-usage"));
|
|
17
17
|
var _noDeprecatedImports = _interopRequireDefault(require("./no-deprecated-imports"));
|
|
18
|
+
var _noEmptyStyledExpression = _interopRequireDefault(require("./no-empty-styled-expression"));
|
|
19
|
+
var _noExportedCss = _interopRequireDefault(require("./no-exported-css"));
|
|
20
|
+
var _noExportedKeyframes = _interopRequireDefault(require("./no-exported-keyframes"));
|
|
21
|
+
var _noInvalidCssMap = _interopRequireDefault(require("./no-invalid-css-map"));
|
|
18
22
|
var _noMargin = _interopRequireDefault(require("./no-margin"));
|
|
19
23
|
var _noNestedStyles = _interopRequireDefault(require("./no-nested-styles"));
|
|
20
24
|
var _noPhysicalProperties = _interopRequireDefault(require("./no-physical-properties"));
|
|
@@ -30,7 +34,7 @@ var _usePrimitives = _interopRequireDefault(require("./use-primitives"));
|
|
|
30
34
|
var _useVisuallyHidden = _interopRequireDefault(require("./use-visually-hidden"));
|
|
31
35
|
/**
|
|
32
36
|
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
33
|
-
* @codegen <<SignedSource::
|
|
37
|
+
* @codegen <<SignedSource::0a2d88c9772eb438048415f13550f592>>
|
|
34
38
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
35
39
|
*/
|
|
36
40
|
var _default = exports.default = {
|
|
@@ -44,6 +48,10 @@ var _default = exports.default = {
|
|
|
44
48
|
'no-deprecated-apis': _noDeprecatedApis.default,
|
|
45
49
|
'no-deprecated-design-token-usage': _noDeprecatedDesignTokenUsage.default,
|
|
46
50
|
'no-deprecated-imports': _noDeprecatedImports.default,
|
|
51
|
+
'no-empty-styled-expression': _noEmptyStyledExpression.default,
|
|
52
|
+
'no-exported-css': _noExportedCss.default,
|
|
53
|
+
'no-exported-keyframes': _noExportedKeyframes.default,
|
|
54
|
+
'no-invalid-css-map': _noInvalidCssMap.default,
|
|
47
55
|
'no-margin': _noMargin.default,
|
|
48
56
|
'no-nested-styles': _noNestedStyles.default,
|
|
49
57
|
'no-physical-properties': _noPhysicalProperties.default,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
|
+
var _createRule = require("../utils/create-rule");
|
|
10
|
+
var _isSupportedImport = require("../utils/is-supported-import");
|
|
11
|
+
var isEmptyStyledExpression = function isEmptyStyledExpression(node) {
|
|
12
|
+
var _node$arguments = (0, _slicedToArray2.default)(node.arguments, 1),
|
|
13
|
+
firstArg = _node$arguments[0];
|
|
14
|
+
if (node.arguments.length === 0) {
|
|
15
|
+
return true;
|
|
16
|
+
} else if (node.arguments.length === 1 && (firstArg === null || firstArg === void 0 ? void 0 : firstArg.type) === 'ArrayExpression') {
|
|
17
|
+
return firstArg.elements.length === 0;
|
|
18
|
+
} else if (node.arguments.length === 1 && (firstArg === null || firstArg === void 0 ? void 0 : firstArg.type) === 'ObjectExpression') {
|
|
19
|
+
return firstArg.properties.length === 0;
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
var createNoEmptyStyledExpressionRule = function createNoEmptyStyledExpressionRule(isEmptyStyledExpression, messageId) {
|
|
24
|
+
return function (context) {
|
|
25
|
+
var importSources = (0, _isSupportedImport.getImportSources)(context);
|
|
26
|
+
return {
|
|
27
|
+
'CallExpression[callee.type="MemberExpression"]': function CallExpressionCalleeTypeMemberExpression(node) {
|
|
28
|
+
var _context$getScope = context.getScope(),
|
|
29
|
+
references = _context$getScope.references;
|
|
30
|
+
|
|
31
|
+
// If we have styled.div(...), make sure `callee` only refers to the
|
|
32
|
+
// `styled` part instead of the whole `styled.div` expression.
|
|
33
|
+
var callee = node.callee.type === 'MemberExpression' ? node.callee.object : node.callee;
|
|
34
|
+
if (!(0, _isSupportedImport.isStyled)(callee, references, importSources)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!isEmptyStyledExpression(node)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
context.report({
|
|
41
|
+
messageId: messageId,
|
|
42
|
+
node: node
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
var noEmptyStyledExpressionRule = (0, _createRule.createLintRule)({
|
|
49
|
+
meta: {
|
|
50
|
+
name: 'no-empty-styled-expression',
|
|
51
|
+
docs: {
|
|
52
|
+
description: 'Forbids any styled expression to be used when passing empty arguments to styled.div() (or other JSX elements).',
|
|
53
|
+
recommended: true,
|
|
54
|
+
severity: 'warn'
|
|
55
|
+
},
|
|
56
|
+
messages: {
|
|
57
|
+
unexpected: 'Found an empty expression, or empty object argument passed to `styled` function call. This unnecessarily causes a major performance penalty - please use a plain JSX element or a React fragment instead (e.g. `<div>Hello</div>` or `<>Hello</>`).'
|
|
58
|
+
},
|
|
59
|
+
type: 'problem',
|
|
60
|
+
schema: [{
|
|
61
|
+
type: 'object',
|
|
62
|
+
properties: {
|
|
63
|
+
importSources: {
|
|
64
|
+
type: 'array',
|
|
65
|
+
items: [{
|
|
66
|
+
type: 'string'
|
|
67
|
+
}]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
additionalProperties: false
|
|
71
|
+
}]
|
|
72
|
+
},
|
|
73
|
+
create: createNoEmptyStyledExpressionRule(isEmptyStyledExpression, 'unexpected')
|
|
74
|
+
});
|
|
75
|
+
var _default = exports.default = noEmptyStyledExpressionRule;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _main = require("../utils/create-no-exported-rule/main");
|
|
8
|
+
var _createRule = require("../utils/create-rule");
|
|
9
|
+
var _isSupportedImport = require("../utils/is-supported-import");
|
|
10
|
+
var noExportedCssRule = (0, _createRule.createLintRule)({
|
|
11
|
+
meta: {
|
|
12
|
+
name: 'no-exported-css',
|
|
13
|
+
type: 'problem',
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Forbid exporting `css` function calls. Exporting `css` function calls can result in unexpected behaviour at runtime, and is not statically analysable.',
|
|
16
|
+
recommended: true,
|
|
17
|
+
severity: 'warn'
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
unexpected: "`css` can't be exported - this will cause unexpected behaviour at runtime. Instead, please move your `css(...)` code to the same file where these styles are being used."
|
|
21
|
+
},
|
|
22
|
+
schema: [{
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
importSources: {
|
|
26
|
+
type: 'array',
|
|
27
|
+
items: [{
|
|
28
|
+
type: 'string'
|
|
29
|
+
}]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
additionalProperties: false
|
|
33
|
+
}]
|
|
34
|
+
},
|
|
35
|
+
create: (0, _main.createNoExportedRule)(_isSupportedImport.isCss, 'unexpected')
|
|
36
|
+
});
|
|
37
|
+
var _default = exports.default = noExportedCssRule;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _main = require("../utils/create-no-exported-rule/main");
|
|
8
|
+
var _createRule = require("../utils/create-rule");
|
|
9
|
+
var _isSupportedImport = require("../utils/is-supported-import");
|
|
10
|
+
var noExportedKeyframesRule = (0, _createRule.createLintRule)({
|
|
11
|
+
meta: {
|
|
12
|
+
name: 'no-exported-keyframes',
|
|
13
|
+
type: 'problem',
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Forbid exporting `keyframes` function calls. Exporting `css` function calls can result in unexpected behaviour at runtime, and is not statically analysable.',
|
|
16
|
+
recommended: true,
|
|
17
|
+
severity: 'warn'
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
unexpected: "`keyframes` can't be exported - this will cause unexpected behaviour at runtime. Instead, please move your `keyframes(...)` code to the same file where these styles are being used."
|
|
21
|
+
},
|
|
22
|
+
schema: [{
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
importSources: {
|
|
26
|
+
type: 'array',
|
|
27
|
+
items: [{
|
|
28
|
+
type: 'string'
|
|
29
|
+
}]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
additionalProperties: false
|
|
33
|
+
}]
|
|
34
|
+
},
|
|
35
|
+
create: (0, _main.createNoExportedRule)(_isSupportedImport.isKeyframes, 'unexpected')
|
|
36
|
+
});
|
|
37
|
+
var _default = exports.default = noExportedKeyframesRule;
|