Skip to content

Commit 5a93ebe

Browse files
committed
fixup: use JSXExpressionContainer check or capital function
1 parent 52da194 commit 5a93ebe

File tree

2 files changed

+37
-9
lines changed

2 files changed

+37
-9
lines changed

configs/eslint-plugin-compass/rules/no-inline-emotion-css.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,39 @@ function isCssCall(node) {
1616
}
1717

1818
/**
19-
* Checks if a call is inside a function.
19+
* Checks if a call is inside a react function.
20+
* This only checks for JSXExpressionContainers or an uppercase function name,
21+
* so it may miss some cases.
2022
* @param {Object} context - ESLint context.
2123
* @returns {boolean} - Whether we're inside a function.
2224
*/
23-
function isInsideFunction(context) {
25+
function isInsideReactFunction(context) {
2426
const ancestors = context.getAncestors();
2527

26-
return ancestors.some(
28+
const hasJSXAncestor = ancestors.some(
29+
(ancestor) => ancestor.type === 'JSXExpressionContainer'
30+
);
31+
32+
if (hasJSXAncestor) {
33+
return true;
34+
}
35+
36+
const currentFunction = ancestors.find(
2737
(ancestor) =>
2838
ancestor.type === 'FunctionDeclaration' ||
2939
ancestor.type === 'FunctionExpression' ||
3040
ancestor.type === 'ArrowFunctionExpression'
3141
);
42+
if (currentFunction) {
43+
// If the function name starts with an uppercase letter maybe it's a React component.
44+
if (
45+
currentFunction.type === 'FunctionDeclaration' &&
46+
currentFunction.id &&
47+
/^[A-Z]/.test(currentFunction.id.name)
48+
) {
49+
return true;
50+
}
51+
}
3252
}
3353

3454
/** @type {import('eslint').Rule.RuleModule} */
@@ -46,13 +66,13 @@ module.exports = {
4666

4767
create(context) {
4868
return {
49-
// Check for css() calls in functions.
69+
// Check for dynamic css() calls in react rendering.
5070
CallExpression(node) {
5171
if (!isCssCall(node)) {
5272
return;
5373
}
5474

55-
if (isInsideFunction(context)) {
75+
if (isInsideReactFunction(context)) {
5676
context.report({
5777
node,
5878
messageId: 'noInlineCSS',

configs/eslint-plugin-compass/rules/no-inline-emotion-css.test.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,28 @@ function pineapple() { return pineappleStyles; };`,
1919
{
2020
code: `
2121
const pineappleStyles = css({ background: 'purple' });
22-
function pineapple() { return (<div className={pineappleStyles}>pineapples</div>); }`,
22+
function Pineapple() { return (<div className={pineappleStyles}>pineapples</div>); }`,
2323
parserOptions: { ecmaVersion: 2021, ecmaFeatures: { jsx: true } },
2424
},
25-
],
26-
invalid: [
2725
{
2826
code: "function pineapple() { const dynamicSet = css({ background: 'orange' }); }",
2927
parserOptions: { ecmaVersion: 2021 },
28+
},
29+
],
30+
invalid: [
31+
{
32+
code: `
33+
function Pineapple() {
34+
const pineappleStyles = css({ background: 'purple' });
35+
return (<div className={pineappleStyles}>pineapples</div>);
36+
}`,
37+
parserOptions: { ecmaVersion: 2021, ecmaFeatures: { jsx: true } },
3038
errors: [
3139
"Don't use a dynamic css() call in the render method, this creates a new class name every time component updates and is not performant. Static styles can be defined with css outside of render, dynamic should be passed through the style prop.",
3240
],
3341
},
3442
{
35-
code: "function pineapple() { return (<div className={css({ background: 'purple' })}>pineapples</div>); }",
43+
code: "function Pineapple() { return (<div className={css({ background: 'purple' })}>pineapples</div>); }",
3644
parserOptions: { ecmaVersion: 2021, ecmaFeatures: { jsx: true } },
3745

3846
errors: [

0 commit comments

Comments
 (0)