Legal Markdown supports powerful conditional logic using Handlebars-style syntax with enhanced expression evaluation.
- Overview
- Basic Conditionals
- Comparison Operators
- Comparison Helpers
- Boolean Operators
- Value Types
- Else Branches
- Nested Conditionals
- Unless (Negative Conditional)
- Array Iteration with Conditionals
- Best Practices
- Comparison with Other Template Engines
- Technical Details
Legal Markdown supports full conditional expressions with comparison and boolean operators, making it more powerful than Handlebars (which requires helper functions) and on par with Liquid templates.
Key Features:
- ✅ Comparison operators:
==,!=,>,<,>=,<= - ✅ Boolean operators:
&&,|| - ✅ Automatic inline conversion to helper subexpressions
- ✅ Nested expressions with parentheses
- ✅ Multiple value types: strings, numbers, booleans, null
- ✅ Dot notation for nested objects
- ✅ Else branches for alternative content
Check if a variable exists and is truthy:
---
includeWarranty: true
---{{#if includeWarranty}}
## Warranty Clause
This product includes a warranty... {{/if}}Check if an object property exists:
---
client:
name: 'Acme Corp'
---{{#if client.name}} Client: {{client.name}} {{/if}}Legal Markdown supports full comparison expressions. Inline expressions are automatically converted to Handlebars helper subexpressions during processing.
Use == for loose equality checks:
---
contract:
type: 'service'
---{{#if contract.type == "service"}}
## Service Agreement Terms
This is a service agreement... {{else}}
## Product Sale Terms
This is a product sale... {{/if}}Compare numeric values with >, <, >=, <=:
---
contract:
amount: 50000
jurisdiction: 'spain'
---{{#if contract.amount > 10000}} **High Value Contract** - Special terms apply
{{/if}}
{{#if contract.amount >= 100000}} Board approval required {{/if}}Use != to check inequality:
---
status: 'active'
---{{#if status != "cancelled"}} This contract is active {{/if}}This inline syntax is converted internally to:
{{#if (neq status "cancelled")}}.
Combine multiple conditions using && (AND) and || (OR).
Both conditions must be true:
---
contract:
amount: 50000
jurisdiction: 'spain'
type: 'service'
---{{#if contract.amount > 10000 && contract.jurisdiction == "spain"}}
## Spanish High-Value Contract Provisions
Special provisions for Spanish contracts over €10,000... {{/if}}At least one condition must be true:
---
jurisdiction: 'madrid'
---{{#if jurisdiction == "madrid" || jurisdiction == "barcelona"}} Applicable law:
Spanish Civil Code {{/if}}Handlebars {{#if}} only checks truthiness. For comparisons, use subexpression
helpers:
| Helper | Usage | Description |
|---|---|---|
eq |
{{#if (eq a b)}} |
Equal (===) |
neq |
{{#if (neq a b)}} |
Not equal (!==) |
gt |
{{#if (gt a b)}} |
Greater than |
gte |
{{#if (gte a b)}} |
Greater or equal |
lt |
{{#if (lt a b)}} |
Less than |
lte |
{{#if (lte a b)}} |
Less or equal |
and |
{{#if (and a b)}} |
Logical AND |
or |
{{#if (or a b)}} |
Logical OR |
not |
{{#if (not a)}} |
Logical NOT |
For convenience, inline comparisons are automatically converted:
Combine AND/OR with parentheses for grouping:
---
amount: 75000
type: 'service'
vip: false
jurisdiction: 'spain'
---{{#if (amount > 50000 && type == "service") || vip == true}} VIP service terms
apply {{/if}}- AND (
&&) has higher precedence than OR (||) - Use parentheses to control evaluation order
<!-- AND is evaluated first --> {{#if premium && active || trial}} Content
{{/if}}
<!-- Equivalent to: (premium && active) || trial -->
<!-- Use parentheses to change order --> {{#if premium && (active || trial)}}
Content {{/if}}Legal Markdown correctly handles different value types in comparisons:
Compare strings using quotes:
---
city: 'madrid'
---{{#if city == "madrid"}} Madrid-specific clause {{/if}}Compare numbers without quotes:
---
amount: 15000
---{{#if amount > 1000}} High-value contract {{/if}}
{{#if amount >= 10000 && amount < 50000}} Mid-tier pricing applies {{/if}}Use boolean values directly:
---
active: true
premium: false
---{{#if active == true}} Active account {{/if}}
{{#if active}} Active account {{/if}}
<!-- Same as above -->
{{#if premium == false}} Standard features only {{/if}}Check for null or missing values:
---
description: null
---{{#if description == null}} No description provided {{/if}}Provide alternative content when a condition is false:
---
contract:
type: 'service'
---{{#if contract.type == "service"}} Service agreement clauses {{else}} Standard
sale clauses {{/if}}While Legal Markdown doesn't have else if, you can nest conditions:
{{#if tier == "premium"}} Premium features {{else}} {{#if tier == "standard"}}
Standard features {{else}} Basic features {{/if}} {{/if}}Conditions can be nested for complex logic:
---
contract:
jurisdiction: 'spain'
amount: 50000
---{{#if contract.jurisdiction == "spain"}} Spanish law applies
{{#if contract.amount > 10000}} High-value Spanish contract addendum {{/if}}
{{else}} {{#if contract.jurisdiction == "portugal"}} Portuguese law applies
{{/if}} {{/if}}Use unless to show content when a condition is false:
---
contract:
expired: false
---{{#unless contract.expired}} This contract is still active {{/unless}}Equivalent to:
{{#if contract.expired == false}} This contract is still active {{/if}}Combine conditionals with array iteration:
---
parties:
- name: 'Acme Corp'
role: 'client'
vip: true
- name: 'Tech Solutions'
role: 'contractor'
vip: false
---{{#parties}}
- **{{name}}** {{#if role == "client"}} (Client - invoicing entity) {{else}}
(Contractor - service provider) {{/if}} {{#if vip}} **VIP Client** - Priority
support {{/if}} {{/parties}}Output:
- **Acme Corp** (Client - invoicing entity) **VIP Client** - Priority support
- **Tech Solutions** (Contractor - service provider)For very complex conditions, consider pre-computing boolean values in metadata:
---
contract:
amount: 50000
jurisdiction: 'spain'
# Pre-computed
isHighValueSpanishContract: true
---{{#if isHighValueSpanishContract}} Special provisions... {{/if}}Advantages:
- More readable templates
- Easier to test business logic
- Reusable across multiple conditions
# Good
{{#if requiresBoardApproval}} Executive approval needed {{/if}}
# Less clear
{{#if amount > 100000 && type == "acquisition"}} Executive approval needed
{{/if}}Break complex conditions into nested ifs when appropriate:
<!-- Instead of this -->
{{#if type == "service" && (jurisdiction == "spain" || jurisdiction ==
"portugal") && amount > 10000}} Content {{/if}}
<!-- Consider this -->
{{#if type == "service"}} {{#if jurisdiction == "spain" || jurisdiction ==
"portugal"}} {{#if amount > 10000}} Content {{/if}} {{/if}} {{/if}}Add comments in YAML or markdown to explain complex logic:
---
# High-value contracts in EU require additional approvals
requiresExecutiveApproval: true # Based on amount > 100000 && region == "EU"
---Test your conditions with various values:
# Test with:
# - Empty strings
# - Zero values
# - Null/undefined
# - Boundary values (e.g., exactly 10000)
amount: 0 # Will this work as expected?
status: '' # Is empty string falsy?Legal Markdown has more ergonomic conditional syntax than Handlebars:
| Feature | Handlebars | Liquid | Legal Markdown |
|---|---|---|---|
| Simple truthiness | ✅ {{#if var}} |
✅ {% if var %} |
✅ {{#if var}} |
| Comparisons | ❌ Requires {{#if (eq a b)}} |
✅ {% if a == b %} |
✅ {{#if a == b}}* |
| Numeric | ❌ Requires {{#if (gt a 10)}} |
✅ {% if a > 10 %} |
✅ {{#if a > 10}}* |
| Boolean logic | ❌ Requires {{#if (and a b)}} |
✅ {% if a and b %} |
✅ {{#if a && b}}* |
| Else branches | ✅ {{else}} |
✅ {% else %} |
✅ {{else}} |
| Unless | ✅ {{#unless}} |
✅ {% unless %} |
✅ {{#unless}} |
* Inline expressions are automatically converted to helper subexpressions
(eq, gt, and, etc.).
Why this matters:
- No helper functions needed - Direct comparison syntax is more readable
- Familiar syntax - Similar to JavaScript, easier for developers
- Less verbose - Compare
{{#if a == b}}vs{{#if (eq a b)}}
Conditional evaluation happens in Phase 3 of the processing pipeline, after variable expansion:
- Phase 1: Context Building (parse YAML, merge options)
- Phase 2: Variable Expansion (
{{variable}}→ actual values) - Phase 3: Conditional Evaluation (
{{#if}}blocks) - Phase 4: Structure Parsing (headers, cross-references)
This ensures that conditionals evaluate against expanded values, not raw
{{variable}} syntax. (Fixes Issue #120)
Conditional evaluation happens in src/extensions/template-loops.ts:
Main functions:
evaluateCondition()- Entry point, delegates to specialized evaluatorsevaluateBooleanExpression()- Handles&&and||operatorsevaluateComparisonExpression()- Handles==,!=,>,<,>=,<=parseComparisonValue()- Parses string/number/boolean literals and variablesresolveVariablePath()- Resolves nested object paths (e.g.,client.name)
Evaluation logic:
function evaluateCondition(condition: string, metadata: Record<string, any>): boolean {
// 1. Check for boolean operators
if (condition.includes('&&') || condition.includes('||')) {
return evaluateBooleanExpression(condition, metadata);
}
// 2. Check for comparison operators
if (condition.includes('==') || condition.includes('!=') || ...) {
return evaluateComparisonExpression(condition, metadata);
}
// 3. Fallback to truthiness check
const value = resolveVariablePath(condition, metadata);
return isTruthy(value);
}Expression evaluation adds minimal overhead:
- Simple variable check: < 0.1ms
- Comparison expression: < 0.5ms
- Complex boolean expression: < 1ms
No significant impact on document processing time.
---
confidentiality_required: true
jurisdiction: 'California'
contract_value: 75000
client_type: 'enterprise'
---{{#if confidentiality_required}}
## Confidentiality
All information is confidential. {{/if}}
{{#if contract_value > 50000 && client_type == "enterprise"}}
## Enterprise High-Value Terms
Special provisions for enterprise contracts over $50,000. {{/if}}
{{#if jurisdiction == "California"}} This agreement is governed by California
law. {{/if}}---
service_tier: 'premium'
region: 'US'
active_subscription: true
---{{#if service_tier == "premium" && active_subscription}}
## Premium Service Features
- 24/7 priority support
- Dedicated account manager
- 99.9% uptime SLA
{{#if region == "US"}}
### US-Specific Benefits
- Toll-free phone support
- Business hours: All US time zones {{/if}} {{/if}}---
contract:
amount: 25000
duration: 12
region: 'EU'
---{{#if contract.amount < 10000}} Standard pricing tier {{else}} {{#if
contract.amount >= 10000 && contract.amount < 50000}} Mid-tier pricing {{else}}
Enterprise pricing {{/if}} {{/if}}
{{#if contract.duration >= 12 && contract.amount > 10000}} Annual discount
applied {{/if}}
{{#if contract.region == "EU" && contract.amount > 15000}} VAT calculation
required {{/if}}- Optional Clauses - Alternative conditional syntaxes
- Variables & Mixins - Variable substitution basics
- YAML Frontmatter - Defining variables for conditions
- Helper Functions - Date, number, and string formatting