Skip to content

Commit 15d9d74

Browse files
feat: add new cases and fix syntax
1 parent 4f3ba2b commit 15d9d74

2 files changed

Lines changed: 230 additions & 41 deletions

File tree

packages/eslint-plugin/src/rules/no_static_z_index.test.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,5 +238,94 @@ ruleTester.run('no-static-z-index', NoStaticZIndex, {
238238
languageOptions,
239239
errors: [{ messageId: 'noStaticZIndexSpecific' }],
240240
},
241+
{
242+
// Invalid: Variable with static value used in css prop (object style, nested)
243+
filename: 'test.tsx',
244+
code: dedent`
245+
import React from 'react';
246+
import { css } from '@emotion/react';
247+
248+
const myCss = css({ container: { zIndex: 100 } });
249+
250+
function TestComponent() {
251+
return <div css={myCss}>test</div>
252+
}`,
253+
languageOptions,
254+
errors: [{ messageId: 'noStaticZIndexSpecificDeclaredVariable' }],
255+
},
256+
{
257+
// Invalid: css array, one with static z-index
258+
filename: 'test.tsx',
259+
code: dedent`
260+
import { css } from '@emotion/react';
261+
262+
function TestComponent() {
263+
return <div css={[someStyle, css({ zIndex: 9 })]}>test</div>
264+
}
265+
`,
266+
languageOptions,
267+
errors: [{ messageId: 'noStaticZIndexSpecific' }],
268+
},
269+
{
270+
// Invalid: Conditional expression with static z-index
271+
filename: 'test.tsx',
272+
code: dedent`
273+
import React from 'react';
274+
275+
function TestComponent() {
276+
const isTrue = true;
277+
return (
278+
<div style={{ zIndex: isTrue ? 10 : 20 }}>test</div>
279+
)
280+
}`,
281+
languageOptions,
282+
errors: [
283+
{ messageId: 'noStaticZIndexSpecific' },
284+
{ messageId: 'noStaticZIndexSpecific' },
285+
],
286+
},
287+
{
288+
// Invalid: Logical expression with static z-index
289+
filename: 'test.tsx',
290+
code: dedent`
291+
import React from 'react';
292+
293+
function TestComponent() {
294+
const isTrue = true;
295+
return (
296+
<div style={{ zIndex: isTrue || 10 }}>test</div>
297+
)
298+
}`,
299+
languageOptions,
300+
errors: [{ messageId: 'noStaticZIndexSpecific' }],
301+
},
302+
{
303+
// Invalid: TSAsExpression with static z-index
304+
filename: 'test.tsx',
305+
code: dedent`
306+
import React from 'react';
307+
308+
function TestComponent() {
309+
return (
310+
<div style={{ zIndex: 10 as number }}>test</div>
311+
)
312+
}`,
313+
languageOptions,
314+
errors: [{ messageId: 'noStaticZIndexSpecific' }],
315+
},
316+
{
317+
// Invalid: UnaryExpression with static z-index
318+
filename: 'test.tsx',
319+
code: dedent`
320+
import React from 'react';
321+
322+
function TestComponent() {
323+
return (
324+
<div style={{ zIndex: -1 }}>test</div>
325+
)
326+
}`,
327+
languageOptions,
328+
errors: [{ messageId: 'noStaticZIndexSpecific' }],
329+
},
241330
],
242331
});

packages/eslint-plugin/src/rules/no_static_z_index.ts

Lines changed: 141 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -82,48 +82,82 @@ const raiseReportIfPropertyHasInvalidZIndex = (
8282
return didReport;
8383
}
8484

85-
// Handle Literal values: zIndex: 10, 'z-index': '10'
86-
if (propertyNode.value.type === 'Literal') {
87-
if (
88-
(didReport = checkPropertySpecifiesInvalidZIndex(
89-
propertyName,
90-
propertyNode.value.value
91-
))
92-
) {
93-
context.report(messageToReport);
85+
const visitNode = (node: TSESTree.Node) => {
86+
// Handle Literal values: zIndex: 10, 'z-index': '10'
87+
if (node.type === 'Literal') {
88+
if (checkPropertySpecifiesInvalidZIndex(propertyName, node.value)) {
89+
didReport = true;
90+
context.report({
91+
...messageToReport,
92+
loc: node.loc,
93+
});
94+
}
9495
}
95-
}
96-
// Handle Identifier values: zIndex: someVar
97-
else if (propertyNode.value.type === 'Identifier') {
98-
const identifierName = propertyNode.value.name;
99-
const identifierDeclaration = context.sourceCode
100-
.getScope(propertyNode)
101-
.variables.find((variable) => variable.name === identifierName);
102-
103-
const identifierDeclarationInit =
104-
identifierDeclaration?.defs[0]?.node.type === 'VariableDeclarator'
105-
? identifierDeclaration.defs[0].node.init
106-
: undefined;
107-
108-
if (
109-
identifierDeclarationInit?.type === 'Literal' &&
110-
checkPropertySpecifiesInvalidZIndex(
111-
propertyName,
112-
identifierDeclarationInit.value
113-
)
114-
) {
115-
context.report({
116-
loc: propertyNode.value.loc,
117-
messageId: 'noStaticZIndexSpecificDeclaredVariable',
118-
data: {
119-
property: propertyName,
120-
line: String(propertyNode.value.loc.start.line),
121-
variableName: propertyNode.value.name,
122-
},
123-
});
124-
125-
didReport = true;
96+
// Handle Identifier values: zIndex: someVar
97+
else if (node.type === 'Identifier') {
98+
const identifierName = node.name;
99+
const identifierDeclaration = context.sourceCode
100+
.getScope(node)
101+
.variables.find((variable) => variable.name === identifierName);
102+
103+
const identifierDeclarationInit =
104+
identifierDeclaration?.defs[0]?.node.type === 'VariableDeclarator'
105+
? identifierDeclaration.defs[0].node.init
106+
: undefined;
107+
108+
if (
109+
identifierDeclarationInit?.type === 'Literal' &&
110+
checkPropertySpecifiesInvalidZIndex(
111+
propertyName,
112+
identifierDeclarationInit.value
113+
)
114+
) {
115+
didReport = true;
116+
context.report({
117+
loc: node.loc,
118+
messageId: 'noStaticZIndexSpecificDeclaredVariable',
119+
data: {
120+
property: propertyName,
121+
line: String(node.loc.start.line),
122+
variableName: node.name,
123+
},
124+
});
125+
}
126+
} else if (node.type === 'ConditionalExpression') {
127+
visitNode(node.consequent);
128+
visitNode(node.alternate);
129+
} else if (node.type === 'LogicalExpression') {
130+
visitNode(node.left);
131+
visitNode(node.right);
132+
} else if (node.type === 'TSAsExpression') {
133+
visitNode(node.expression);
134+
} else if (node.type === 'UnaryExpression') {
135+
if (node.operator === '-') {
136+
if (
137+
node.argument.type === 'Literal' &&
138+
typeof node.argument.value === 'number'
139+
) {
140+
if (
141+
checkPropertySpecifiesInvalidZIndex(
142+
propertyName,
143+
-node.argument.value
144+
)
145+
) {
146+
didReport = true;
147+
context.report({
148+
...messageToReport,
149+
loc: node.loc,
150+
});
151+
}
152+
} else {
153+
visitNode(node.argument);
154+
}
155+
}
126156
}
157+
};
158+
159+
if (propertyNode.value) {
160+
visitNode(propertyNode.value);
127161
}
128162

129163
return didReport;
@@ -136,7 +170,36 @@ const handleObjectProperties = (
136170
reportMessage: ReportDescriptor<MessageIds>
137171
) => {
138172
if (property.type === 'Property') {
139-
raiseReportIfPropertyHasInvalidZIndex(context, property, reportMessage);
173+
if (property.value.type === 'ObjectExpression') {
174+
property.value.properties.forEach((nestedProperty) => {
175+
const nestedReportMessage = {
176+
...reportMessage,
177+
loc: nestedProperty.loc,
178+
};
179+
180+
if (nestedReportMessage.data) {
181+
const newData: Record<string, unknown> = {
182+
...nestedReportMessage.data,
183+
property: getPropertyName(nestedProperty) || 'unknown',
184+
};
185+
186+
if ('line' in newData) {
187+
newData.line = String(nestedProperty.loc.start.line);
188+
}
189+
190+
nestedReportMessage.data = newData;
191+
}
192+
193+
handleObjectProperties(
194+
context,
195+
propertyParentNode,
196+
nestedProperty,
197+
nestedReportMessage
198+
);
199+
});
200+
} else {
201+
raiseReportIfPropertyHasInvalidZIndex(context, property, reportMessage);
202+
}
140203
} else if (property.type === 'SpreadElement') {
141204
if (property.argument.type !== 'Identifier') {
142205
return;
@@ -336,6 +399,43 @@ export const NoStaticZIndex = ESLintUtils.RuleCreator.withoutDocs({
336399
return;
337400
}
338401

402+
// Handle inline ArrayExpression: css={[...]}
403+
if (expression.type === 'ArrayExpression') {
404+
expression.elements.forEach((element) => {
405+
if (!element) return;
406+
407+
if (element.type === 'ObjectExpression') {
408+
element.properties.forEach((property) => {
409+
handleObjectProperties(context, node, property, {
410+
loc: property.loc,
411+
messageId: 'noStaticZIndexSpecific',
412+
data: {
413+
property: getPropertyName(property) || 'unknown',
414+
},
415+
});
416+
});
417+
} else if (
418+
element.type === 'CallExpression' &&
419+
element.callee.type === 'Identifier' &&
420+
element.callee.name === 'css'
421+
) {
422+
element.arguments.forEach((argument) => {
423+
if (argument.type === 'ObjectExpression') {
424+
argument.properties.forEach((property) => {
425+
handleObjectProperties(context, node, property, {
426+
loc: property.loc,
427+
messageId: 'noStaticZIndexSpecific',
428+
data: {
429+
property: getPropertyName(property) || 'unknown',
430+
},
431+
});
432+
});
433+
}
434+
});
435+
}
436+
});
437+
}
438+
339439
// Handle css prop with template literal or function
340440
if (node.name.name === 'css') {
341441
// css={`...`}

0 commit comments

Comments
 (0)