Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/rules/no-invalid-properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
// Imports
//-----------------------------------------------------------------------------

import { isSyntaxMatchError, isSyntaxReferenceError } from "../util.js";
import {
isSyntaxMatchError,
isSyntaxReferenceError,
isEnvMatchError,
} from "../util.js";

//-----------------------------------------------------------------------------
// Type Definitions
Expand Down Expand Up @@ -463,7 +467,13 @@ export default /** @satisfies {NoInvalidPropertiesRuleDefinition} */ ({
});
return;
}

if (isEnvMatchError(error)) {
/*
* env() values are provided by the user agent and
* cannot be validated, so skip validation entirely.
*/
return;
}
if (
!allowUnknownVariables ||
isSyntaxReferenceError(error)
Expand Down
10 changes: 10 additions & 0 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,13 @@ export function isSyntaxMatchError(error) {
export function isSyntaxReferenceError(error) {
return typeof error.reference === "string";
}

/**
* Determines if an error is the lexer error thrown when a value containing
* `env()` cannot be matched against a syntax definition.
* @param {Object} error The error object to check.
* @returns {boolean} True if the error is the `env()` match error, false if not.
*/
export function isEnvMatchError(error) {
return error.message === "Matching for a tree with env() is not supported";

@lumirlumir lumirlumir Jul 21, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking comment: relying on an internal error message seems fragile because changes in csstree could break this check. Error messages are generally not a stable API and may vary between versions.

Currently, there does not appear to be a reliable way to distinguish this unsupported env() matching case from other generic errors, so checking the message may be the most practical option for now.

In the longer term, introducing a custom error class -- similar to the existing SyntaxReferenceError and SyntaxMatchError -- or exposing a stable error code such as ERR_LEXER_ENV_MATCH_UNSUPPORTED would provide a more robust solution.

@DMartens DMartens Jul 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an error only our fork of csstree throws (reference for upstream), so we could add an error code to this, but we can do this after this PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@minseonkkim

If you’d like to open an issue about it, that would be welcome.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened eslint/csstree#141 for this. Thanks for the suggestion!

}
41 changes: 41 additions & 0 deletions tests/rules/no-invalid-properties.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ ruleTester.run("no-invalid-properties", rule, {
"main { p:has(.child) { color: red; } }",
"main { p:has(.child:hover) { color: red; } }",
"main { p:first-of-type, span { color: red; } }",

// env() values are provided by the user agent and cannot be validated
"a { padding-top: env(safe-area-inset-top); }",
"a { padding-top: env(safe-area-inset-top, 20px); }",
"a { padding-top: calc(env(safe-area-inset-top) + 10px); }",
"a { width: env(titlebar-area-width); }",
"a { padding: env(safe-area-inset-top) 0 env(safe-area-inset-bottom) 0; }",
"a { padding: env(safe-area-inset-top) red }",
],
invalid: [
{
Expand Down Expand Up @@ -1454,5 +1462,38 @@ ruleTester.run("no-invalid-properties", rule, {
},
],
},
{
code: "a { paddin-top: env(safe-area-inset-top); }",
errors: [
{
messageId: "unknownProperty",
data: { property: "paddin-top" },
line: 1,
column: 5,
endLine: 1,
endColumn: 15,
},
],
},

/*
* Reporting an unknown `var()` nested inside `env()` is intentional:
* this rule also checks that custom properties are resolvable, and that
* check is independent of the syntax validation skipped for `env()`.
* We can revisit this once the rule supports partial validation of values.
*/
{
code: "a { padding: env(safe-area-inset-top, var(--external-padding)); }",
errors: [
{
messageId: "unknownVar",
data: { var: "--external-padding" },
line: 1,
column: 43,
endLine: 1,
endColumn: 61,
},
],
},
],
});