What problem do you want to solve?
When a value contains var() or env(), Lexer#matchProperty() / matchSyntax() returns a match result whose error is a plain Error object:
// lib/lexer/Lexer.js — matchSyntax()
if (valueHasVar(tokens)) {
return buildMatchResult(null, new Error('Matching for a tree with var() is not supported'));
}
if (valueHasEnv(tokens)) {
return buildMatchResult(null, new Error('Matching for a tree with env() is not supported'));
}
Consumers that need to distinguish this "matching is unsupported for this value" case from other generic errors currently have no reliable way to do so. The only option is comparing the error message string. For example, in eslint/css#510 the plugin has to do:
// eslint/css src/util.js
export function isEnvMatchError(error) {
return error.message === "Matching for a tree with env() is not supported";
}
During review of that PR it was pointed out that relying on an internal error message is fragile: error messages are not a stable API and may change between versions, which would silently break downstream detection. Unlike SyntaxMatchError / SyntaxReferenceError, these two errors carry no distinguishing property that consumers could check instead.
Since these errors only exist in this fork (upstream csstree does not throw them), downstream consumers cannot rely on any upstream convention either.
What do you think is the correct solution?
Give these errors a stable, documented identity. Two options were discussed in the eslint/css PR review:
- Add a stable
code property to the existing errors:
const error = new Error('Matching for a tree with env() is not supported');
error.code = 'ERR_LEXER_ENV_MATCH_UNSUPPORTED'; // and ERR_LEXER_VAR_MATCH_UNSUPPORTED
- This is the smallest change — no new public class — and consumers can check
error.code === 'ERR_LEXER_ENV_MATCH_UNSUPPORTED' regardless of future message wording changes.
- Introduce a custom error class following the existing
SyntaxReferenceError / SyntaxMatchError pattern (lib/lexer/error.js, via createCustomError)
Either way, both the var() and env() errors should be covered in the same change, since they have the same shape and downstream code handles both.
I have a slight preference for option 1 (error code) as the smaller change, but I'm happy to implement whichever direction the team prefers.
Participation
AI acknowledgment
Additional comments
No response
What problem do you want to solve?
When a value contains
var()orenv(),Lexer#matchProperty()/matchSyntax()returns a match result whoseerroris a plainErrorobject:Consumers that need to distinguish this "matching is unsupported for this value" case from other generic errors currently have no reliable way to do so. The only option is comparing the error message string. For example, in eslint/css#510 the plugin has to do:
During review of that PR it was pointed out that relying on an internal error message is fragile: error messages are not a stable API and may change between versions, which would silently break downstream detection. Unlike
SyntaxMatchError/SyntaxReferenceError, these two errors carry no distinguishing property that consumers could check instead.Since these errors only exist in this fork (upstream csstree does not throw them), downstream consumers cannot rely on any upstream convention either.
What do you think is the correct solution?
Give these errors a stable, documented identity. Two options were discussed in the eslint/css PR review:
codeproperty to the existing errors:error.code === 'ERR_LEXER_ENV_MATCH_UNSUPPORTED'regardless of future message wording changes.SyntaxReferenceError/SyntaxMatchErrorpattern (lib/lexer/error.js, viacreateCustomError)Either way, both the
var()andenv()errors should be covered in the same change, since they have the same shape and downstream code handles both.I have a slight preference for option 1 (error code) as the smaller change, but I'm happy to implement whichever direction the team prefers.
Participation
AI acknowledgment
Additional comments
No response