You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Provide, or document an existing supported mechanism for, comparing two
parsed CEL expressions by structure while ignoring source formatting and
parse metadata.
The intended comparison would:
ignore whitespace, redundant parentheses, source positions, and expression
node IDs;
treat equivalent literal spellings as equal when they parse to the same
literal value;
work for macro-backed expressions such as exists, all, and map;
compare expression structure rather than rendered text; and
avoid logical or algebraic equivalence. For example, a && b and b && a
would remain different.
A concrete downstream use case is configuration reconciliation. A Terraform
provider may receive a CEL expression from configuration, while the backing
API returns the same expression with different whitespace or fully
parenthesized formatting. Treating those values as different produces a
perpetual plan diff even though the parsed expression has not changed.
One example of this use case and its current workaround is:
The current cel-go APIs provide the underlying pieces, but not an explicit
equality contract:
cel.AstToString produces stable, semantically equivalent text when it can
unparse the expression.
cel.EnableMacroCallTracking allows macro calls to be reconstructed during
unparsing.
Comparing the expression protobufs with proto.Equal works for the cases
tested, but it is unclear whether equality across independently parsed ASTs,
including the treatment of expression IDs, is a supported guarantee.
(*cel.Ast).Expr() is deprecated in favor of cel.AstToParsedExpr, but
neither API documents structural comparison as a supported use case.
An explicit helper would let embedders use this behavior without depending on
unparser behavior or undocumented protobuf details.
Example
A possible API might look like this; the exact name and package are open for
discussion:
Comparing only the Expr fields from cel.AstToParsedExpr works for the
formatting, parenthesization, and macro cases tested. However, it is not
documented whether expression IDs are guaranteed to be stable across
independent parses or whether this is a supported equality mechanism.
If this is already the recommended approach, documenting that guarantee
would satisfy this request without adding another API.
Implement an application-specific recursive AST visitor
This avoids unparsing but duplicates cel-go's handling of expression kinds,
literals, comprehensions, optional syntax, and future AST additions in each
embedding application.
Continue comparing raw source strings
This cannot distinguish formatting-only changes from actual expression
changes and causes persistent configuration diffs.
Feature request checklist
Change
Provide, or document an existing supported mechanism for, comparing two
parsed CEL expressions by structure while ignoring source formatting and
parse metadata.
The intended comparison would:
node IDs;
literal value;
exists,all, andmap;a && bandb && awould remain different.
A concrete downstream use case is configuration reconciliation. A Terraform
provider may receive a CEL expression from configuration, while the backing
API returns the same expression with different whitespace or fully
parenthesized formatting. Treating those values as different produces a
perpetual plan diff even though the parsed expression has not changed.
One example of this use case and its current workaround is:
wandb/terraform-provider-orca#32
The current cel-go APIs provide the underlying pieces, but not an explicit
equality contract:
cel.AstToStringproduces stable, semantically equivalent text when it canunparse the expression.
cel.EnableMacroCallTrackingallows macro calls to be reconstructed duringunparsing.
proto.Equalworks for the casestested, but it is unclear whether equality across independently parsed ASTs,
including the treatment of expression IDs, is a supported guarantee.
(*cel.Ast).Expr()is deprecated in favor ofcel.AstToParsedExpr, butneither API documents structural comparison as a supported use case.
An explicit helper would let embedders use this behavior without depending on
unparser behavior or undocumented protobuf details.
Example
A possible API might look like this; the exact name and package are open for
discussion:
The implementation could instead live in
common/ast, for example:The important part is a documented contract that ignores IDs and source
metadata while comparing the parsed expression structure.
Alternatives considered
Compare
cel.AstToStringoutputThis works for many expressions when macro-call tracking is enabled, but
equality becomes dependent on an unparser that can return errors. Unparser
behavior also evolves independently; for example, parser/unparser: AstToString produces unparseable output for doubles in scientific notation #1325 required parser/unparser: emit valid CEL for doubles in scientific notation #1326 to
fix invalid output for doubles in scientific notation.
Compare expression protobufs with
proto.EqualComparing only the
Exprfields fromcel.AstToParsedExprworks for theformatting, parenthesization, and macro cases tested. However, it is not
documented whether expression IDs are guaranteed to be stable across
independent parses or whether this is a supported equality mechanism.
If this is already the recommended approach, documenting that guarantee
would satisfy this request without adding another API.
Implement an application-specific recursive AST visitor
This avoids unparsing but duplicates cel-go's handling of expression kinds,
literals, comprehensions, optional syntax, and future AST additions in each
embedding application.
Continue comparing raw source strings
This cannot distinguish formatting-only changes from actual expression
changes and causes persistent configuration diffs.