Skip to content

feat: unify equality operators and add condition validation#84

Merged
vaceslav merged 4 commits intomainfrom
feat/unify-operators-and-condition-validation
Mar 16, 2026
Merged

feat: unify equality operators and add condition validation#84
vaceslav merged 4 commits intomainfrom
feat/unify-operators-and-condition-validation

Conversation

@vaceslav
Copy link
Contributor

Summary

Closes #83

  • Unified equality operators: Both = and == now work in both {{#if}} conditionals and {{(...)}} boolean expressions. Previously = only worked in conditionals and == only in boolean expressions, with the wrong operator silently producing incorrect results.
  • Added Validate() method: New public API on IConditionEvaluator and IConditionContext for pure syntax validation without data context. Detects unknown operators ($, &&, ||, <>, ===), unbalanced quotes, missing operands, consecutive operators/operands.
  • Updated documentation: FAQ, conditionals guide, boolean expressions guide, and processing warnings docs updated to reflect unified operator support.

Test plan

  • All 1088 existing tests pass (no regressions)
  • 6 new == operator tests in ConditionalEvaluatorTests
  • 25 new validation tests in ConditionValidationTests
  • dotnet format --verify-no-changes passes
  • Review that = works in boolean expressions ({{(Status = "Active")}})
  • Review that == works in conditionals ({{#if Status == "Active"}})
  • Review Validate() API returns correct issues for invalid expressions

Unify the two condition systems so both accept `=` and `==` for equality,
and add a `Validate()` method to detect invalid syntax before evaluation.
Documents that comparing a non-existent nested property (e.g., var1.var2)
against any value always returns false, since null != any literal.
- Use StringComparison.OrdinalIgnoreCase instead of ToLower() for not-operator check
- Remove dead == hint branch in IsSuspectedUnknownOperator
- Fix stale comment in ProcessingWarningsIntegrationTests
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR expands the conditional/expression language to accept both = and == for equality, and introduces a new public validation API to check conditional expressions for syntax issues without evaluating them.

Changes:

  • Add == support to the conditional evaluator and = support to the boolean expression parser.
  • Introduce Validate(string) on IConditionEvaluator / IConditionContext plus new ConditionValidationResult / ConditionValidationIssue types.
  • Update documentation and tests to reflect the new operator support and validation behavior.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
TriasDev.Templify/Expressions/BooleanExpressionParser.cs Adds single = as an equality operator for {{(...)}} boolean expressions.
TriasDev.Templify/Conditionals/IConditionEvaluator.cs Adds new public Validate(string) API to the evaluator interface (breaking change).
TriasDev.Templify/Conditionals/IConditionContext.cs Adds new public Validate(string) API to the context interface (breaking change).
TriasDev.Templify/Conditionals/ConditionValidationResult.cs New result type for syntactic validation.
TriasDev.Templify/Conditionals/ConditionValidationIssue.cs New issue type + enum describing validation findings.
TriasDev.Templify/Conditionals/ConditionEvaluator.cs Implements Validate(string) by delegating to the internal evaluator.
TriasDev.Templify/Conditionals/ConditionContext.cs Implements Validate(string) by delegating to the internal evaluator.
TriasDev.Templify/Conditionals/ConditionalEvaluator.cs Adds == as an equality operator and implements token-based syntax validation.
TriasDev.Templify.Tests/Integration/ProcessingWarningsIntegrationTests.cs Updates invalid-expression warning test to use === now that = is valid.
TriasDev.Templify.Tests/ConditionValidationTests.cs Adds unit tests for the new validation API and issue types.
TriasDev.Templify.Tests/ConditionalEvaluatorTests.cs Adds == evaluation tests and some nested-variable comparison cases.
docs/for-template-authors/conditionals.md Updates template-author docs to state = and == are both accepted.
docs/for-template-authors/boolean-expressions.md Updates boolean expression docs to include = as supported equality.
docs/for-developers/processing-warnings.md Updates ExpressionFailed examples to reflect === as invalid.
docs/FAQ.md Updates FAQ operator guidance to include = and ==.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +57 to +61
/// // result3.IsValid == false
/// // result3.Issues[0].Type == ConditionValidationIssueType.UnknownOperator
/// </code>
/// </example>
ConditionValidationResult Validate(string expression);
Comment on lines +37 to +43
#region Validate

/// <summary>
/// Validates a conditional expression for syntactic correctness without evaluating it.
/// This is a pure syntax check that does not require a data context.
/// </summary>
/// <param name="expression">The expression to validate.</param>
Comment on lines 156 to 176
private bool TryParseComparisonOperator(out ComparisonOperator op)
{
op = ComparisonOperator.Equal;

if (Consume("=="))
{
op = ComparisonOperator.Equal;
return true;
}
if (Consume("!="))
{
op = ComparisonOperator.NotEqual;
return true;
}
// Single = (must be after == and != checks to avoid consuming first = of ==)
if (Consume('='))
{
op = ComparisonOperator.Equal;
return true;
}
if (Consume(">="))
Comment on lines +33 to +40
/// <summary>
/// Validates a conditional expression for syntactic correctness without evaluating it.
/// This is a pure syntax check that does not use the pre-loaded data.
/// </summary>
/// <param name="expression">The expression to validate.</param>
/// <returns>A <see cref="ConditionValidationResult"/> indicating whether the expression is valid and any issues found.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="expression"/> is null.</exception>
ConditionValidationResult Validate(string expression);
Comment on lines +170 to +175
// Single = (must be after == and != checks to avoid consuming first = of ==)
if (Consume('='))
{
op = ComparisonOperator.Equal;
return true;
}
- Add == to supported operators in IConditionEvaluator XML docs
- Add = to supported operators in BooleanExpressionParser XML docs
- Add unit test for single = operator in BooleanExpressionParserTests
@vaceslav vaceslav merged commit 13883fc into main Mar 16, 2026
14 checks passed
@vaceslav vaceslav deleted the feat/unify-operators-and-condition-validation branch March 16, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unify equality operators and add condition validation

2 participants