Text Replacer
Powerful string template processor with variables, control structures, and transformation pipes
The Text Replacer is a powerful, extensible string template processor that supports advanced template features including variable replacement, control structures, and transformation pipes.
Table of Contents
- Overview
- Basic Usage
- Template Syntax
- Variable Replacement
- Control Structures
- Transformation Pipes
- Advanced Features
- API Reference
Overview
The Text Replacer uses a template syntax with #{...} delimiters and supports:
- Variable replacement with nested property access
- Control structures (if/unless/each loops)
- Transformation pipes for data formatting
- Recursive variable resolution
Template Syntax
Variable Expressions
Variables can be accessed using either the explicit #{show ...} syntax or the shortcut #{...} syntax:
// Explicit syntax (traditional)
#{show userName}
#{show user.name}
#{show user.profile.email}
// Shortcut syntax (recommended for simplicity)
#{userName}
#{user.name}
#{user.profile.email}
// Both work with nested properties
#{show address.street}
#{address.street} // Shortcut - cleaner and easier to read
// Both work with array access
#{show users.0.name}
#{users.0.name} // Shortcut
// Both work with transformation pipes
#{show price | round:2}
#{price | round:2} // Shortcut
#{show date | format:dd.MM.yyyy}
#{date | format:dd.MM.yyyy} // Shortcut
Control Structures
Conditional Blocks
Control structures still use explicit keywords, but you can use shortcut syntax for variables inside them:
// If condition - using shortcut syntax for variables
#{if user.isActive}
Welcome back, #{user.name}!
#{/if}
// Unless condition - mixing both syntaxes is fine
#{unless user.isBlocked}
You have access to this content, #{show user.email}.
#{/unless}
Loops
// Each loop - using shortcut syntax
#{each items as item}
- #{item.name}: #{item.price}
#{/each}
// With index access
#{each users as user}
#{userIndex}: #{user.name}
#{/each}
Variable Replacement
Basic Variables
const context = { greeting: "Hello", name: "World" };
// Using traditional syntax
const template1 = "#{show greeting} #{show name}!";
// Using shortcut syntax (recommended)
const template2 = "#{greeting} #{name}!";
const result = replaceVariables(template2, context);
// Output: "Hello World!"
Nested Properties
The shortcut syntax really shines with nested properties:
const context = {
user: {
personal: {
firstName: "John",
lastName: "Doe"
}
}
};
// Traditional syntax
const template1 = "#{show user.personal.firstName} #{show user.personal.lastName}";
// Shortcut syntax - much cleaner!
const template2 = "#{user.personal.firstName} #{user.personal.lastName}";
const result = replaceVariables(template2, context);
// Output: "John Doe"
Real-World Example: Address Formatting
const context = {
address: {
street: "Hauptstraße 123",
city: "Berlin",
zip: "10115",
country: "Germany"
}
};
// Shortcut syntax makes this very readable
const template = "#{address.street}, #{address.zip} #{address.city}, #{address.country}";
const result = replaceVariables(template, context);
// Output: "Hauptstraße 123, 10115 Berlin, Germany"
Array Access
const context = {
colors: ["red", "green", "blue"],
users: [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 }
]
};
// Shortcut syntax with arrays
const template = "Color: #{colors.1}, User: #{users.0.name}";
const result = replaceVariables(template, context);
// Output: "Color: green, User: Alice"
Recursive Variables
For complex recursive patterns, you may want to use the explicit show keyword:
const context = {
settings: { theme: "dark", language: "en" },
currentSetting: "theme",
prefix: "settings"
};
// For nested recursive variables, explicit 'show' is recommended
const template = "Current theme: #{show #{show prefix}.#{show currentSetting}}";
const result = replaceVariables(template, context);
// Output: "Current theme: dark"
Control Structures
If/Unless Conditions
const context = { user: { isAdmin: true, isActive: false } };
// If condition
const template1 = `
#{if user.isAdmin}
<div>Admin Panel</div>
#{/if}
`;
// Unless condition
const template2 = `
#{unless user.isActive}
<div>Account suspended</div>
#{/unless}
`;
Each Loops
const context = {
products: [
{ name: "Laptop", price: 999 },
{ name: "Mouse", price: 25 },
{ name: "Keyboard", price: 75 }
]
};
// Using shortcut syntax inside loops
const template = `
<ul>
#{each products as product}
<li>#{product.name} - $#{product.price}</li>
#{/each}
</ul>
`;
Nested Control Structures
const context = {
departments: [
{
name: "Engineering",
employees: [
{ name: "Alice", role: "Developer" },
{ name: "Bob", role: "Designer" }
]
},
{
name: "Marketing",
employees: [
{ name: "Charlie", role: "Manager" }
]
}
]
};
// Shortcut syntax works great in nested structures
const template = `
#{each departments as dept}
<h2>#{dept.name}</h2>
#{if dept.employees}
<ul>
#{each dept.employees as emp}
<li>#{emp.name} - #{emp.role}</li>
#{/each}
</ul>
#{/if}
#{/each}
`;
Transformation Pipes
Pipes transform data before output. Use the | symbol to apply pipes. The shortcut syntax works seamlessly with pipes:
// Traditional syntax
#{show value | pipeName}
#{show value | pipeName:parameter}
#{show value | pipe1 | pipe2:param}
// Shortcut syntax (recommended)
#{value | pipeName}
#{value | pipeName:parameter}
#{value | pipe1 | pipe2:param}
Text Transformation Pipes
uppercase
Converts text to uppercase.
const context = { name: "john" };
// Using shortcut syntax
const template = "Hello #{name | uppercase}!";
// Output: "Hello JOHN!"
lowercase
Converts text to lowercase.
const context = { name: "JOHN" };
const template = "Hello #{name | lowercase}!";
// Output: "Hello john!"
capitalize
Capitalizes the first letter, lowercases the rest.
const context = { name: "jOHN" };
const template = "Hello #{name | capitalize}!";
// Output: "Hello John!"
Date Formatting Pipes
format
Formats dates using date-fns format strings.
const context = {
timestamp: 1734885600000,
dateString: "2024-12-22"
};
// Default format (yyyy-MM-dd) - shortcut syntax
const template1 = "Date: #{timestamp | format}";
// Output: "Date: 2024-12-22"
// Custom format
const template2 = "Date: #{timestamp | format:dd.MM.yyyy}";
// Output: "Date: 22.12.2024"
// Time format
const template3 = "Time: #{timestamp | format:HH:mm:ss}";
// Output: "Time: 14:30:00"
// Real-world example
const template4 = "Created on #{timestamp | format:dd.MM.yyyy} at #{timestamp | format:HH:mm}";
// Output: "Created on 22.12.2024 at 14:30"
humanizeDuration
Converts milliseconds to human-readable duration.
const context = { duration: 3665000 }; // 1 hour, 1 minute, 5 seconds
const template = "Duration: #{duration | humanizeDuration}";
// Output: "Duration: 1h 1m 5s"
Number Formatting Pipes
round
Rounds numbers to specified decimal places.
const context = { price: 12.456789 };
// Default (0 decimal places)
const template1 = "Price: #{price | round}";
// Output: "Price: 12"
// 2 decimal places - shortcut syntax
const template2 = "Price: #{price | round:2}";
// Output: "Price: 12,46" (German format with comma)
// Real-world example
const context2 = { total: 1234.56 };
const template3 = "Total: €#{total | round:2}";
// Output: "Total: €1234,56"
calc
Performs arithmetic operations.
const context = {
price: 100,
taxRate: 0.19,
quantity: 3
};
// Multiplication - shortcut syntax
const template1 = "Tax: #{price | calc:multiply:0.19}";
// Output: "Tax: 19"
// Addition
const template2 = "Total: #{show price | calc:add:50}";
// Output: "Total: 150"
// Supported operations: add, subtract, multiply, divide
truncateToRange
Constrains numbers to a specified range.
const context = {
score: 150,
temperature: -5
};
// Constrain to 0-100 range
const template1 = "Score: #{show score | truncateToRange:0:100}";
// Output: "Score: 100"
// Constrain temperature
const template2 = "Temp: #{show temperature | truncateToRange:0:50}";
// Output: "Temp: 0"
Array Processing Pipes
sum
Calculates the sum of array elements.
const context = {
numbers: [1, 2, 3, 4, 5],
items: [
{ price: 10.50 },
{ price: 25.00 },
{ price: 15.75 }
]
};
// Sum simple array
const template1 = "Total: #{show numbers | sum}";
// Output: "Total: 15"
// Sum with path
const template2 = "Total: #{show items | sum:price}";
// Output: "Total: 51.25"
Data Transformation Pipes
mapping
Maps values from one set to another.
const context = {
status: "active",
priority: "high"
};
// Map status codes to labels
const template1 = "Status: #{show status | mapping:active,inactive,pending:Active,Inactive,Pending}";
// Output: "Status: Active"
// With default value
const template2 = "Priority: #{show priority | mapping:low,medium:Low,Medium:Unknown}";
// Output: "Priority: Unknown"
translate
Translates inline translation objects.
const context = {
message: {
en: "Hello",
de: "Hallo",
fr: "Bonjour"
}
};
// Default language (de)
const template1 = "#{show message | translate}";
// Output: "Hallo"
// Specific language
const template2 = "#{show message | translate:en}";
// Output: "Hello"
default
Provides fallback values for null/undefined/empty values.
const context = {
name: null,
title: "",
description: "Some text"
};
// Shortcut syntax with default pipe
const template = `
Name: #{name | default Anonymous}
Title: #{title | default Untitled}
Description: #{description | default No description}
`;
// Output:
// Name: Anonymous
// Title: Untitled
// Description: Some text
Chaining Pipes
Pipes can be chained for complex transformations. The shortcut syntax keeps this very readable:
const context = {
price: 123.456,
name: "premium product"
};
// Chain multiple pipes - shortcut syntax
const template = `
Product: #{name | capitalize}
Price: $#{price | calc:multiply:1.2 | round:2}
`;
// Output:
// Product: Premium Product
// Price: $148,15
More Chaining Examples
// Complex price calculation with tax
const context = {
basePrice: 99.99,
taxRate: 0.19
};
const template = "Final Price: €#{basePrice | calc:add:#{basePrice | calc:multiply:0.19} | round:2}";
// Output: "Final Price: €118,99"
// Text transformation chain
const context2 = { userName: "JOHN DOE" };
const template2 = "Welcome, #{userName | lowercase | capitalize}!";
// Output: "Welcome, John Doe!"
Advanced Features
Shortcut Syntax Best Practices
✅ DO:
- Use shortcut syntax for simple variable access:
#{user.name} - Use shortcut syntax with pipes:
#{price | round:2} - Mix both syntaxes in the same template if needed
- Use explicit
showfor very complex recursive patterns
❌ DON'T:
- Don't use shortcut syntax for control structures: Use
#{if condition}, not#{condition}alone - Don't worry about consistency - both syntaxes work identically
Error Handling
The template processor gracefully handles errors with both syntaxes:
const context = { user: { name: "John" } };
// Missing property with default - shortcut syntax
const template1 = "Age: #{user.age | default Unknown}";
// Output: "Age: Unknown"
// Invalid pipe parameters
const template2 = "#{user.name | round:invalid}";
// Output: "John" (pipe ignored, original value returned)
// Note: When using shortcut syntax with removeUnmappedContent: false,
// missing variables will show as #{show property} instead of #{property}
const template3 = "Status: #{user.status}";
// With removeUnmappedContent: false → "Status: #{show user.status}"
// With removeUnmappedContent: true → "Status: "
Performance Optimization
- Lazy evaluation: Only processes templates when needed
- Efficient parsing: Optimized regex patterns
- Shortcut preprocessing: Converts
#{...}to#{show ...}once, then processes normally - Caching: Pipes cache results where possible
- Loop protection: Prevents infinite recursion
Configuration Options
const options = {
removeUnmappedContent: true // Remove variables that can't be resolved
};
const result = replaceVariables(template, context, options);
API Reference
replaceVariables<T>(content: string, context: T, options?: Options): string
Processes a template string with the given context.
Parameters
content: string- The template string to processcontext: T extends Json- The context object containing dataoptions?: Options- Optional configuration
Options
interface Options {
removeUnmappedContent?: boolean; // Default: false
}
Returns
string - The processed template string
Example
// Using shortcut syntax
const result = replaceVariables(
"Hello #{name}!",
{ name: "World" },
{ removeUnmappedContent: true }
);
// Using traditional syntax (also works)
const result2 = replaceVariables(
"Hello #{show name}!",
{ name: "World" },
{ removeUnmappedContent: true }
);
Built-in Pipes
All pipes work with both traditional #{show property | pipe} and shortcut #{property | pipe} syntax:
| Pipe | Syntax | Description |
|---|---|---|
uppercase |
| uppercase |
Convert to uppercase |
lowercase |
| lowercase |
Convert to lowercase |
capitalize |
| capitalize |
Capitalize first letter |
format |
| format:pattern |
Format dates |
round |
| round:decimals |
Round numbers |
calc |
| calc:operation:value |
Arithmetic operations |
humanizeDuration |
| humanizeDuration |
Format durations |
truncateToRange |
| truncateToRange:min:max |
Constrain to range |
mapping |
| mapping:from:to:default |
Map values |
sum |
| sum:path? |
Sum array elements |
translate |
| translate:language? |
Translate i18n objects |
default |
| default value |
Fallback values |
Error Handling
The template processor handles errors gracefully:
- Missing variables: Returns empty string or original template (based on options)
- Invalid pipes: Ignores the pipe and returns original value
- Malformed expressions: Leaves expression unchanged
- Infinite recursion: Protected by iteration limits
- Shortcut syntax: Unmapped variables show as
#{show property}whenremoveUnmappedContent: false
Best Practices
- Use shortcut syntax for cleaner, more readable templates:
#{user.name}instead of#{show user.name} - Use meaningful variable names in your context objects
- Test edge cases with null/undefined values
- Chain pipes logically from general to specific transformations
- Use default pipes for optional values
- Keep templates readable with proper indentation
- Validate context data before processing templates
- Mix syntaxes freely - both work identically, choose based on readability
Common Patterns
Form Templates
const context = {
user: { name: "John", email: "john@example.com" },
errors: { name: null, email: "Invalid email" }
};
// Using shortcut syntax for cleaner forms
const template = `
<div>
<label>Name: #{user.name}</label>
#{if errors.name}
<span class="error">#{errors.name}</span>
#{/if}
</div>
<div>
<label>Email: #{user.email}</label>
#{if errors.email}
<span class="error">#{errors.email}</span>
#{/if}
</div>
`;
Email Templates
const context = {
user: { name: "John", orders: [{ id: 1, total: 99.99 }] },
company: { name: "ACME Corp" }
};
// Shortcut syntax makes email templates very readable
const template = `
Dear #{user.name | capitalize},
Thank you for your recent orders:
#{each user.orders as order}
- Order ##{order.id}: $#{order.total | round:2}
#{/each}
Best regards,
#{company.name}
`;
Address Formatting Template
const context = {
customer: {
name: "Alice Johnson",
address: {
street: "Hauptstraße 123",
city: "Berlin",
zip: "10115",
country: "Germany"
}
}
};
// Real-world address template with shortcut syntax
const template = `
Shipping Address:
#{customer.name}
#{customer.address.street}
#{customer.address.zip} #{customer.address.city}
#{customer.address.country}
`;
// Output:
// Shipping Address:
// Alice Johnson
// Hauptstraße 123
// 10115 Berlin
// Germany
Report Templates
const context = {
report: {
title: "Sales Report",
period: "2024-Q1",
data: [
{ month: "Jan", sales: 10000 },
{ month: "Feb", sales: 12000 },
{ month: "Mar", sales: 15000 }
]
}
};
// Shortcut syntax for reports
const template = `
# #{report.title}
Period: #{report.period}
## Monthly Sales
#{each report.data as item}
- #{item.month}: $#{item.sales | round:0}
#{/each}
Total: $#{report.data | sum:sales | round:0}
`;
Invoice Template Example
const context = {
invoice: {
number: "INV-2024-001",
date: 1734885600000,
customer: {
name: "ABC Company",
address: "Main Street 45, 12345 Berlin"
},
items: [
{ description: "Consulting Services", quantity: 8, rate: 150 },
{ description: "Software License", quantity: 1, rate: 500 }
],
taxRate: 0.19
}
};
// Complete invoice template using shortcut syntax
const template = `
INVOICE #{invoice.number}
Date: #{invoice.date | format:dd.MM.yyyy}
Bill To:
#{invoice.customer.name}
#{invoice.customer.address}
Items:
#{each invoice.items as item}
#{item.description}
Quantity: #{item.quantity} x €#{item.rate} = €#{item.quantity | calc:multiply:#{item.rate}}
#{/each}
Subtotal: €#{invoice.items | sum:rate}
Tax (19%): €#{invoice.items | sum:rate | calc:multiply:0.19 | round:2}
Total: €#{invoice.items | sum:rate | calc:multiply:1.19 | round:2}
`;
This documentation provides a comprehensive guide to using the Text Replacer system with both traditional #{show property} and shortcut #{property} syntax.