
# Text Replacer v3 Documentation

The Text Replacer v3 is a powerful, extensible string template processor that supports advanced template features including variable replacement, control structures, and transformation pipes.

## Table of Contents

1. [Overview](#overview)
2. [Basic Usage](#basic-usage)
3. [Template Syntax](#template-syntax)
4. [Variable Replacement](#variable-replacement)
5. [Control Structures](#control-structures)
6. [Transformation Pipes](#transformation-pipes)
7. [Advanced Features](#advanced-features)
8. [Migration from v2](#migration-from-v2)
9. [API Reference](#api-reference)

## Overview

The Text Replacer v3 uses a new 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**
- **Extensible architecture** for custom pipes

### Key Features

- 🔧 **Extensible pipe system** - Easy to add custom transformations
- 🎯 **Type-safe** - Full TypeScript support
- 🚀 **Performance optimized** - Efficient template processing
- 🔄 **Recursive resolution** - Handle nested variable references
- 📊 **Rich data handling** - Support for objects, arrays, and complex data structures

## Basic Usage

```typescript
import { replaceVariables } from "./utils/text-replacer-v3";

const context = { name: "John", age: 30 };
const template = "Hello #{show name}, you are #{show age} years old!";
const result = replaceVariables(template, context);
console.log(result); // "Hello John, you are 30 years old!"
```

### Shortcut Syntax

For convenience, you can omit the `show` keyword when accessing variables. This shortcut syntax makes templates more concise and easier to read:

```typescript
import { replaceVariables } from "./utils/text-replacer-v3";

const context = { name: "John", age: 30 };
// Both syntaxes work identically:
const template1 = "Hello #{show name}, you are #{show age} years old!";
const template2 = "Hello #{name}, you are #{age} years old!"; // Shortcut syntax
const result = replaceVariables(template2, context);
console.log(result); // "Hello John, you are 30 years old!"
```

**Key Points:**
- `#{property}` is automatically converted to `#{show property}`
- Works with all features: nested properties, arrays, pipes, etc.
- Control structures (`if`, `unless`, `each`) still require explicit keywords
- You can mix both syntaxes in the same template

## Template Syntax

### Variable Expressions

Variables can be accessed using either the explicit `#{show ...}` syntax or the shortcut `#{...}` syntax:

```typescript
// 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:

```typescript
// 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

```typescript
// 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

```typescript
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:

```typescript
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

```typescript
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

```typescript
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:

```typescript
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

```typescript
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

```typescript
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

```typescript
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:

```typescript
// 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.

```typescript
const context = { name: "john" };
// Using shortcut syntax
const template = "Hello #{name | uppercase}!";
// Output: "Hello JOHN!"
```

#### `lowercase`
Converts text to lowercase.

```typescript
const context = { name: "JOHN" };
const template = "Hello #{name | lowercase}!";
// Output: "Hello john!"
```

#### `capitalize`
Capitalizes the first letter, lowercases the rest.

```typescript
const context = { name: "jOHN" };
const template = "Hello #{name | capitalize}!";
// Output: "Hello John!"
```

### Date Formatting Pipes

#### `format`
Formats dates using date-fns format strings.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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:

```typescript
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

```typescript
// 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 `show` for 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:

```typescript
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

```typescript
const options = {
  removeUnmappedContent: true // Remove variables that can't be resolved
};

const result = replaceVariables(template, context, options);
```

## Migration from v2

### Syntax Changes

| v2 Syntax         | v3 Syntax               | Notes                    |
| ----------------- | ----------------------- | ------------------------ |
| `${variable}`     | `#{show variable}`      | New explicit show syntax |
| `#{if condition}` | `#{if condition}`       | Unchanged                |
| `#{each items}`   | `#{each items as item}` | Requires 'as' keyword    |

### Pipe Changes

| v2 Pipe         | v3 Pipe          | Changes                          |
| --------------- | ---------------- | -------------------------------- |
| `format`        | `format:pattern` | Now supports custom patterns     |
| `default:value` | `default value`  | Space-separated instead of colon |

### Migration Example

```typescript
// v2 Template
const v2Template = `
Hello ${user.name}!
#{if user.isActive}
  ${user.email}
#{/if}
`;

// v3 Template
const v3Template = `
Hello #{show user.name}!
#{if user.isActive}
  #{show user.email}
#{/if}
`;
```

## 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 process
- `context: T extends Json` - The context object containing data
- `options?: Options` - Optional configuration

#### Options

```typescript
interface Options {
  removeUnmappedContent?: boolean; // Default: false
}
```

#### Returns

`string` - The processed template string

#### Example

```typescript
// 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}` when `removeUnmappedContent: false`

### Best Practices

1. **Use shortcut syntax** for cleaner, more readable templates: `#{user.name}` instead of `#{show user.name}`
2. **Use meaningful variable names** in your context objects
3. **Test edge cases** with null/undefined values
4. **Chain pipes logically** from general to specific transformations
5. **Use default pipes** for optional values
6. **Keep templates readable** with proper indentation
7. **Validate context data** before processing templates
8. **Mix syntaxes freely** - both work identically, choose based on readability

### Common Patterns

#### Form Templates

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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 v3 system effectively with both traditional `#{show property}` and shortcut `#{property}` syntax.
