Skip to content

Bug: no-invalid-properties does not validate calc() contents #501

Description

@przemyslaw-zan

Environment

ESLint version: 9.39.4
@eslint/css version: 1.4.0
Node version: v24.15.0
npm version: 11.12.1
Operating System: Ubuntu (within WSL)

Which language are you using?

stylesheet

What did you do?

Configuration
import css from "@eslint/css";

export default [
	{
		files: ["**/*.css"],
		plugins: { css },
		language: "css/css",
		rules: {
			"css/no-invalid-properties": "error"
		}
	}
];
a {
	width: red;
	width: calc(red);
	width: calc(1px+2px);
	width: calc();
	width: calc(1px + );
	width: calc(1px ** 2px);
}

What did you expect to happen?

All six declarations reported as invalid. In particular:

  • calc(red), calc(), calc(1px + ) and calc(1px ** 2px) do not match the <calc-sum> grammar at all.
  • calc(1px+2px) is invalid per CSS Values and Units: "White space is required on both sides of the + and - operators." (1px+2px tokenizes as the two dimensions 1px and +2px with no operator between them.)

Browsers agree and drop all six declarations.

What actually happened?

Only the unwrapped width: red is reported. Every calc() variant passes:

/home/projects/eslint-css-calc-repro/style.css
  2:10  error  Invalid value 'red' for property 'width'. Expected auto | <length-percentage [0,∞]> | min-content | max-content | fit-content | fit-content( <length-percentage [0,∞]> ) | <calc-size()> | <anchor-size()> | stretch | <-non-standard-size>  css/no-invalid-properties

✖ 1 problem (1 error, 0 warnings)

So wrapping an arbitrary invalid value in calc() bypasses validation entirely - width: red is flagged while width: calc(red) is not.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/eslint-css-calc-repro

Participation

  • I am willing to submit a pull request for this issue.

AI acknowledgment

  • I did not use AI to generate this issue report.
  • (If the above is not checked) I have reviewed the AI-generated content before submitting.

Additional comments

It looks like math function contents are treated as opaque during value matching (possibly on the @eslint/css-tree side), i.e. a calc() is accepted wherever a numeric type is expected without checking its operands or operators.

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

Status
Feedback Needed

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions