npm package: @iqai/prompt-weaver
Description: A powerful template engine for building and rendering prompts with an extensible transformer system
Latest version: 1.1.1

<div align="center">

<img src="./logo.png" alt="Prompt Weaver Logo" width="100">

# Prompt Weaver

**Craft Powerful, Type-Safe LLM Prompts with Ease**

A powerful, extensible template engine built for the AI era. Prompt Weaver combines the flexibility of Handlebars with the safety of TypeScript and Zod/Standard Schema.

[Features](#-features) • [Quick Start](#-quick-start) • [The Two Approaches](#️-the-two-approaches-builder-vs-weaver) • [Templating Syntax](#-templating-syntax-handlebars) • [Transformers](#️-built-in-transformers) • [Type Safety](#-validation--type-safety)

</div>

-----

## 📖 Introduction

Writing prompts for LLMs often involves messy string concatenation, zero type safety, and repetitive code. **Prompt Weaver** solves this by treating prompts like software artifacts.

It allows you to build dynamic prompts using **templates**, validate input data with **schemas** (Zod, Valibot, etc.), and transform data (dates, currency, arrays) directly within the prompt.

## ✨ Features

- **🎨 Powerful Templating**: Logic-rich templates with loops (`{{#each}}`), conditionals (`{{#if}}`), and switch/case logic.

- **✅ Type Safety & Validation**: First-class support for **Standard Schema** (Zod, ArkType, Valibot). Get automatic TypeScript type inference.

- **🔧 Rich Toolset**: Built-in transformers for Dates, Strings, JSON, Currencies, and Arrays.

- **🏗️ Fluent Builder API**: Construct prompts programmatically using a chainable JavaScript/TypeScript API with support for JSON, links, images, and checkboxes.

- **🧩 Reusable Partials**: Don't repeat yourself—compose prompts from reusable fragments (headers, footers, rules). Partials are pre-compiled for optimal performance.

- **⚡ Performance Optimized**: Template compilation caching and pre-compiled partials for faster rendering.

- **🎯 Extensible**: Create custom transformers and helpers to suit your specific domain.

-----

## 📦 Installation

```bash
npm install @iqai/prompt-weaver

# or

pnpm add @iqai/prompt-weaver

# or

yarn add @iqai/prompt-weaver
```

-----

## 🚀 Quick Start

### 1. The "Hello World"

Start simple. Define a template, inject data, and get a string.

```typescript
import { PromptWeaver } from "@iqai/prompt-weaver";

// 1. Define a template with variables and a transformer
const template = "Hello {{name}}, your balance is {{currency balance}}.";

// 2. Initialize Weaver
const weaver = new PromptWeaver(template);

// 3. Render
const result = weaver.format({
  name: "Alice",
  balance: 1234.56
});

console.log(result);
// Output: "Hello Alice, your balance is $1,234.56."
```

### 2. The Feature Showcase

Here is a more complex example showing loops, conditionals, and formatting.

<details>
<summary><strong>View Complex Example Code</strong></summary>

```typescript
const template = `
You are helping {{userName}}.

## Task Details

- **Deadline**: {{relativeTime deadline}} ({{formatDate deadline "MMM DD"}})
- **Status**: {{#if isPremium}}⭐ Premium{{else}}Standard{{/if}}

## Requirements

{{#each requirements}}
{{increment @index}}. {{this}}
{{/each}}
`;

const weaver = new PromptWeaver(template);

const output = weaver.format({
  userName: "Alice",
  isPremium: true,
  deadline: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days from now
  requirements: ["Plan project", "Review code"]
});
```

**Output:**

```text
You are helping Alice.

## Task Details

- **Deadline**: in 7 days (Dec 12)
- **Status**: ⭐ Premium

## Requirements

1. Plan project
2. Review code
```

</details>

-----

## ⚖️ The Two Approaches: Builder vs. Weaver

Prompt Weaver offers two ways to create prompts. You can use them separately or together.

| Feature | **PromptWeaver** | **PromptBuilder** |
| :--- | :--- | :--- |
| **Best For...** | Static templates, recurring tasks, separating content from code. | Dynamic logic, building prompts on the fly based on runtime conditions. |
| **Input** | String template (Handlebars syntax). | Method chaining (Fluent API). |
| **Example** | `new PromptWeaver("Hello {{name}}")` | `new PromptBuilder().text("Hello").text(name)` |

### Using the Builder (Fluent API)

Perfect for when you need to construct a prompt logically in your code.

```typescript
import { PromptBuilder } from "@iqai/prompt-weaver";

const builder = new PromptBuilder()
  .heading(1, "User Profile")
  .section("Info", "Name: {{name}}")
  .list(["Rule 1", "Rule 2"])
  .conditional(true, "✅ Verified", "❌ Unverified")
  .json({ version: "1.0", status: "active" }) // Format JSON
  .link("Documentation", "https://example.com") // Add markdown link
  .checkboxes([
    { text: "Task 1", checked: true },
    { text: "Task 2", checked: false }
  ]); // Add task list

// Convert to Weaver to render data
const weaver = builder.toPromptWeaver();
const output = weaver.format({ name: "Alice" });
```

**Output:**

````text
# User Profile

## Info

Name: Alice

- Rule 1
- Rule 2

✅ Verified

```json
{
  "version": "1.0",
  "status": "active"
}
```

[Documentation](https://example.com)

- [x] Task 1
- [ ] Task 2
````

### When to Use Each Approach

| Scenario | Use Builder | Use Weaver | Use Both |
|----------|-------------|------------|----------|
| Static template strings | ❌ | ✅ | ❌ |
| Dynamic prompt construction | ✅ | ❌ | ✅ |
| Template rendering with data | ❌ | ✅ | ✅ |
| Reusable templates | ❌ | ✅ | ✅ |
| Complex programmatic logic | ✅ | ❌ | ✅ |

### Workflow: Build → Convert → Render

```typescript
import { PromptBuilder } from "@iqai/prompt-weaver";

// Step 1: Build programmatically
const builder = new PromptBuilder()
  .heading(1, "User Dashboard")
  .section("Welcome", "Hello {{userName}}!")
  .section("Account Info", "Your balance is {{currency balance}}")
  .conditional(isPremium, "⭐ Premium Member", "Upgrade to Premium");

// Step 2: Convert to PromptWeaver for rendering
const weaver = builder.toPromptWeaver();

// Step 3: Render with data (can be called multiple times)
const output1 = weaver.format({ userName: "Alice", balance: 1000, isPremium: true });
const output2 = weaver.format({ userName: "Bob", balance: 500, isPremium: false });

// Output 1:
// # User Dashboard
//
// ## Welcome
//
// Hello Alice!
//
// ## Account Info
//
// Your balance is $1,000.00
//
// ⭐ Premium Member

// Output 2:
// # User Dashboard
//
// ## Welcome
//
// Hello Bob!
//
// ## Account Info
//
// Your balance is $500.00
//
// Upgrade to Premium

// Step 4: Optional - Validate with schema (TypeScript infers types automatically)
import { z } from 'zod';
const schema = z.object({
  userName: z.string(),
  balance: z.number(),
  isPremium: z.boolean(),
});

// TypeScript automatically infers types from the schema
const weaverWithSchema = builder.toPromptWeaver({ schema });

// format() automatically validates when schema is provided - TypeScript knows the exact shape
const validatedOutput = weaverWithSchema.format({ 
  userName: "Alice", 
  balance: 1000, 
  isPremium: true 
});
```

-----

## 🎨 Templating Syntax

Prompt Weaver utilizes Handlebars syntax for control flow and data formatting.

### Variable Interpolation & Transformers

Variables are interpolated using `{{variableName}}`. Format variables using **transformers** (Handlebars helpers): `{{transformer variableName}}` or `{{transformer variableName arg1 arg2}}`.

**Basic examples:**
```handlebars
Hello {{name}}!                        <!-- Simple variable -->
Hello {{capitalize name}}!             <!-- With transformer -->
Your balance is {{currency balance}}   <!-- Format as currency -->
Due {{relativeTime deadline}}         <!-- Relative time -->
```

Transformers allow you to format data directly within your templates without preprocessing. See the [Built-in Transformers](#️-built-in-transformers) section below for available options.

<details>
<summary><strong>View Detailed Examples</strong></summary>

**Transformers with arguments:**
```handlebars
{{ellipsis text 50}}                  <!-- Truncate to 50 chars -->
{{formatDate date "YYYY-MM-DD"}}      <!-- Format date with pattern -->
{{formatDate date "MMMM DD, YYYY"}}  <!-- Full month name: December 25, 2023 -->
{{formatDate date "DDDD, MMM DD"}}    <!-- Day name: Monday, Dec 25 -->
{{replace text "old" "new"}}          <!-- Replace text -->
{{filter users "status" "active"}}    <!-- Filter by property equals value -->
{{reduce numbers 0 "sum"}}            <!-- Reduce with operation -->
```

**Chaining transformers in expressions:**
```handlebars
{{#each (sort (filter users "active") "name")}}
  {{increment @index}}. {{capitalize name}} - {{currency balance}}
{{/each}}
```

</details>

### Loops

```handlebars
{{#each items}}
  {{increment @index}}. {{this}}
{{else}}
  No items found.
{{/each}}
```

### Conditionals

```handlebars
{{#if isPremium}}
  Premium Content
{{else}}
  Standard Content
{{/if}}
```

### Switch/Case

```handlebars
{{#switch role}}
  {{#case "admin"}} You are an Admin {{/case}}
  {{#case "user"}} You are a User {{/case}}
{{/switch}}
```

### Context Switching

```handlebars
{{#with user}}
  Name: {{name}}
  Email: {{email}}
{{/with}}
```

### Special Variables

- `@index` - Current index in `{{#each}}` loops (0-based)
- `@key` - Current key in `{{#each}}` loops over objects
- `@first` - `true` on first iteration
- `@last` - `true` on last iteration
- `@root` - Access root context from nested contexts
- `this` - Current context value in loops

### Partials (Reusable Fragments)

Define reusable template fragments that can be included anywhere using `{{> partialName}}`. Perfect for headers, footers, user cards, or any repeated sections.

**Basic usage:**
```typescript
const template = "{{> header}}\n{{content}}\n{{> footer}}";
const weaver = new PromptWeaver(template, {
  partials: {
    header: "# {{title}}\n---",
    footer: "---\nPlease respond in JSON format."
  }
});

// Or register programmatically:
weaver.setPartial("header", "# {{title}}\n---");
```

Partials inherit the parent context and can include other partials. They can be reused across multiple PromptWeaver instances, enabling DRY principles.

<details>
<summary><strong>View Detailed Examples</strong></summary>

**Context Access & Nesting:**

Partials inherit the parent context and can include other partials:

```typescript
const template = "{{> pageLayout}}";
const weaver = new PromptWeaver(template, {
  partials: {
    pageLayout: `
{{> header}}
{{content}}
{{> footer}}
`,
    header: "# {{title}}\n---",
    footer: `---
Generated on {{formatDate date "YYYY-MM-DD"}}`
  }
});

const output = weaver.format({
  title: "My Page",
  content: "Main content here",
  date: new Date()
});
```

**Real-World Example:**

Compose complex prompts from reusable components:

```typescript
const promptTemplate = `
{{> systemHeader}}
{{> taskSection}}
{{> outputFormat}}
`;

const weaver = new PromptWeaver(promptTemplate, {
  partials: {
    systemHeader: `You are {{role}}, an expert in {{domain}}.{{#if companyName}} Working for {{companyName}}.{{/if}}`,
    taskSection: `
## Task
{{taskDescription}}
{{#if requirements}}
## Requirements
{{#each requirements}}
- {{this}}
{{/each}}
{{/if}}
`,
    outputFormat: `{{#if jsonOutput}}Please respond in valid JSON format.{{else}}{{outputFormat}}{{/if}}`
  }
});
```

**Reusability Example:**

Partials can be reused across multiple PromptWeaver instances. Define a partial once and use it in different templates:

```typescript
// Define a reusable partial template
const userCardPartial = `
## User Profile
- **Name**: {{name}}
- **Email**: {{email}}
- **Role**: {{role}}
{{#if isPremium}}⭐ Premium Member{{/if}}
---`;

// Use the same partial in multiple PromptWeaver instances
const emailTemplate = `{{> userCard}}\n\nYour account summary:\n{{summary}}`;
const reportTemplate = `{{> userCard}}\n\n## Activity Report\n{{report}}`;

const emailWeaver = new PromptWeaver(emailTemplate, {
  partials: { userCard: userCardPartial }
});

const reportWeaver = new PromptWeaver(reportTemplate, {
  partials: { userCard: userCardPartial }
});

// Both instances can use the same partial with different data
const emailOutput = emailWeaver.format({
  name: "Alice",
  email: "alice@example.com",
  role: "Developer",
  isPremium: true,
  summary: "You have 5 unread messages."
});

const reportOutput = reportWeaver.format({
  name: "Alice",
  email: "alice@example.com",
  role: "Developer",
  isPremium: true,
  report: "Last login: 2 hours ago"
});
```

**Output:**

```text
## User Profile
- **Name**: Alice
- **Email**: alice@example.com
- **Role**: Developer
⭐ Premium Member
---

Your account summary:
You have 5 unread messages.
```

The same `userCard` partial is reused in both templates, demonstrating how partials enable DRY (Don't Repeat Yourself) principles across your prompt templates.

</details>

-----

## 🛠️ Built-in Transformers

Prompt Weaver comes with a massive library of transformers to format data directly inside your prompt.

### 📝 String & Content

<details>
<summary>Expand String Transformers</summary>

| Transformer | Example | Result |
| :--- | :--- | :--- |
| `upper` | `{{upper text}}` | HELLO |
| `lower` | `{{lower text}}` | hello |
| `capitalize` | `{{capitalize text}}` | Hello |
| `ellipsis` | `{{ellipsis text 10}}` | Hello w... |
| `json` | `{{json data}}` | `{"a":1}` |
| `pluralize` | `{{pluralize word}}` | apples |

**Also available:** `replace`, `replaceAll`, `regexReplace`, `trim`, `trimStart`, `trimEnd`, `slugify`, `kebabCase`, `camelCase`, `snakeCase`, `split`, `join`, `truncate`, `slice`, `substring`, `padStart`, `padEnd`, `singularize`

📖 **[View all String Transformers →](TRANSFORMERS.md#-string--content-transformers)**

</details>

### 📅 Date & Time

<details>
<summary>Expand Date Transformers</summary>

| Transformer | Example | Result |
| :--- | :--- | :--- |
| `formatDate` | `{{formatDate date "YYYY-MM-DD"}}` | 2023-12-25 |
| `formatDate` | `{{formatDate date "MMMM DD, YYYY"}}` | December 25, 2023 |
| `formatDate` | `{{formatDate date "DDDD, MMM DD"}}` | Monday, Dec 25 |
| `relativeTime` | `{{relativeTime date}}` | 2 hours ago |
| `isToday` | `{{isToday date}}` | true/false |

**Date format patterns:** `YYYY` (4-digit year), `YY` (2-digit year), `MMMM` (full month), `MMM` (abbreviated month), `MM` (2-digit month), `M` (single digit month), `DDDD` (full day), `DDD` (abbreviated day), `DD` (2-digit day), `D` (single digit day), `HH` (hours), `mm` (minutes), `ss` (seconds)

**Also available:** `formatTime`, `formatDateTime`, `isPast`, `isFuture`, `addDays`, `subtractDays`, `addHours`, `subtractHours`, `addMinutes`, `subtractMinutes`, `timestamp`, `unixTimestamp`

📖 **[View all Date Transformers →](TRANSFORMERS.md#-date--time-transformers)**

</details>

### 🔢 Math & Numbers

<details>
<summary>Expand Number Transformers</summary>

| Transformer | Example | Result |
| :--- | :--- | :--- |
| `currency` | `{{currency price}}` | $1,234.56 |
| `percent` | `{{percent val}}` | 12.34% |
| `compact` | `{{compact views}}` | 1.2M |
| `add` | `{{add 5 2}}` | 7 |

**Also available:** `subtract`, `multiply`, `divide`, `increment`, `price`, `signedPercent`, `signedCurrency`, `integer`, `number`

📖 **[View all Number Transformers →](TRANSFORMERS.md#-math--number-transformers)**

</details>

### 📊 Collections (Arrays/Objects)

<details>
<summary>Expand Collection Transformers</summary>

| Transformer | Example | Description |
| :--- | :--- | :--- |
| `filter` | `{{filter users "active"}}` | Filter array by property truthiness |
| `filter` | `{{filter users "status" "active"}}` | Filter array by property equals value |
| `map` | `{{map users "name"}}` | Extract property from objects |
| `sort` | `{{sort items "price"}}` | Sort array |
| `reduce` | `{{reduce numbers 0 "sum"}}` | Reduce array with operation (sum, multiply, max, min, concat) |
| `first` / `last` | `{{first items}}` | Get first/last item |
| `pick` | `{{pick user "name" "id"}}` | Pick specific object keys |

**Also available:** `find`, `findIndex`, `includes`, `reverse`, `nth`, `unique`, `groupBy`, `partition`, `chunk`, `flatten`, `arraySlice`, `length`, `reduce`, `get`, `has`, `keys`, `values`, `omit`, `merge`, `defaults`, `deepGet`, `isEmpty`, `isNotEmpty`

📖 **[View all Collection Transformers →](TRANSFORMERS.md#-collection-transformers-arrays)**

</details>

### 🔀 Logic & Comparison

<details>
<summary>Expand Logic Transformers</summary>

```handlebars
{{#if (eq status "active")}} ... {{/if}}
{{#if (gt age 18)}} ... {{/if}}
{{coalesce value "fallback"}}
{{ifElse isPremium "Rich" "Poor"}}
```

**Also available:** `ne` (not equal), `gte`, `lt`, `lte`, `and`, `or`, `default`, `exists`, `isDefined`

📖 **[View all Logic & Comparison Transformers →](TRANSFORMERS.md#-logic--comparison-transformers)**

</details>

> 📚 **Complete Reference**: See [TRANSFORMERS.md](TRANSFORMERS.md) for the full list of all available transformers with detailed examples and usage.

-----

## ✅ Validation & Type Safety

This is where Prompt Weaver shines. By integrating **Standard Schema** (Zod, Valibot, ArkType), you get runtime validation AND build-time TypeScript inference automatically.

### The "Magic" of Inference

You don't need to manually define interfaces. Just pass a schema, and `format()` automatically validates and enforces type safety.

```typescript
import { z } from 'zod';
import { PromptWeaver } from "@iqai/prompt-weaver";

// 1. Define Schema
const schema = z.object({
  username: z.string(),
  age: z.number().positive(),
  email: z.string().email().optional()
});

// 2. Pass schema to Weaver
const weaver = new PromptWeaver(template, { schema });

// 3. Type-Safe Formatting with Automatic Validation
// TypeScript will now ERROR if you miss 'username' or if 'age' is a string!
// format() automatically validates the data against the schema at runtime
const output = weaver.format({
  username: "Alice", 
  age: 30,
  // email is optional, so we can omit it safely
});

// ❌ This will give a TypeScript error AND throw at runtime
// weaver.format({}); // Missing required fields
```

### Validation Methods

- `weaver.format(data)`: **Automatically validates** when a schema is provided, renders, and throws error if invalid. Type-safe!
- `weaver.formatAsync(data)`: **Automatically validates** asynchronously when a schema is provided (use for schemas with async refinements/transforms). Returns a Promise.
- `weaver.validateSchema(data)`: Just runs validation, returning a success/failure object (doesn't render).

**Example:**

```typescript
import { SchemaValidationError } from "@iqai/prompt-weaver";

// format() automatically validates when schema is provided
try {
  const output = weaver.format({ username: "Alice", age: 30 });
  console.log("Rendered:", output);
} catch (error) {
  if (error instanceof SchemaValidationError) {
    console.error("Validation errors:", error.issues);
  }
}

// formatAsync() for schemas with async validation
const schema = z.object({
  email: z.string().email().refine(async (email) => {
    return await checkEmailExists(email);
  }),
  name: z.string(),
});

const weaver = new PromptWeaver(template, { schema });
const output = await weaver.formatAsync({ email: "alice@example.com", name: "Alice" });

// Or validate separately without rendering
const result = weaver.validateSchema({ username: "Alice", age: 30 });
if (result.success) {
  console.log("Valid data:", result.data); // ✅ TypeScript infers the output type
} else {
  console.error("Validation errors:", result.issues);
}
```

**Async validation:**

```typescript
const result = await weaver.validateSchemaAsync({ username: "Alice", age: 30 });
```

> [!NOTE]
> Prompt Weaver supports any Standard Schema-compatible validation library, including:
> - **Zod** (3.24+)
> - **Valibot** (1.0+)
> - **ArkType** (2.0+)
> - And other libraries that implement the [Standard Schema](https://standardschema.dev) specification

### Template Validation

```typescript
import { validateTemplate } from "@iqai/prompt-weaver";

const result = validateTemplate(templateSource);
if (!result.valid) {
  console.error("Template errors:", result.errors);
}
```

-----

## 🧩 Advanced Usage

### Composition

Merge multiple templates into one context. The `compose` method merges templates **in the order they appear in the array**, separated by two newlines (`\n\n`) by default.

```typescript
const headerTemplate = "# {{title}}";
const bodyTemplate = "{{content}}";
const footerTemplate = "---\nGenerated on {{formatDate date}}";

// Templates are merged in order: header → body → footer
const composed = PromptWeaver.compose([headerTemplate, bodyTemplate, footerTemplate]);
const weaver = new PromptWeaver(composed);

const output = weaver.format({
  title: "My Document",
  content: "Main content here",
  date: new Date()
});
```

**Output:**

```text
# My Document

Main content here

---
Generated on Dec 12, 2024
```

**Custom Separator:**

You can specify a custom separator between templates:

```typescript
// Use a single newline instead of double newline
const composed = PromptWeaver.compose([headerTemplate, bodyTemplate], "\n");

// Use a custom separator
const composed = PromptWeaver.compose([headerTemplate, bodyTemplate], "\n---\n");
```

**Direct Creation:**

Or create a PromptWeaver instance directly from composed templates:

```typescript
import { z } from 'zod';

const schema = z.object({
  title: z.string(),
  content: z.string(),
});

const weaver = PromptWeaver.composeAndCreate(
  [headerTemplate, bodyTemplate, footerTemplate],
  { schema }
);
```

### Custom Transformers

Register your own logic globally or scoped to an instance.

**Global Registration (Simple):**

```typescript
import { registerTransformer } from "@iqai/prompt-weaver";

// Simple transformer (no options)
registerTransformer("reverse", (str) => str.split("").reverse().join(""));
// Use: {{reverse text}}

// Transformer with options
registerTransformer("truncate", (value, maxLength) => {
  const str = String(value);
  const length = Number(maxLength) || 50;
  return str.length > length ? `${str.slice(0, length - 3)}...` : str;
});
// Use: {{truncate longText 100}}
```

**Scoped Registry (Isolation):**

```typescript
import { TransformerRegistry } from "@iqai/prompt-weaver";

// Create isolated registry
const registry = TransformerRegistry.createScoped();
registry.registerTransformer("customHelper", (value, option1, option2) => {
  return `Custom: ${value} (${option1}, ${option2})`;
}, {
  description: "A custom helper with two options",
  version: "1.0.0"
});

// Only this instance uses this registry
const weaver = new PromptWeaver(template, { registry });
```

**When to use which:**
- **Global registration** (`registerTransformer()`) - Use for shared transformers across your app
- **Scoped registry** (`TransformerRegistry.createScoped()`) - Use for isolation, testing, or per-instance transformer sets

### Core API Methods

**PromptWeaver Class:**

```typescript
// Constructor
new PromptWeaver(templateSource, options?)

// Options
interface PromptWeaverOptions {
  registry?: TransformerRegistry; // Custom transformer registry (defaults to global)
  partials?: Record<string, string>; // Partial templates
  schema?: StandardSchemaV1; // Standard Schema validator (Zod, Valibot, ArkType, etc.)
  enableCache?: boolean; // Enable template compilation caching (default: true)
}

// Methods
weaver.format(data)                    // Render the template with data (automatically validates if schema provided)
weaver.formatAsync(data)               // Render asynchronously (use for schemas with async validation)
weaver.validateSchema(data)            // Validate data against schema (requires schema option)
weaver.extractVariables()              // Get required variables from template
weaver.setPartial(name, templateSource) // Register a partial template
weaver.getMetadata()                   // Get template metadata
PromptWeaver.compose(templateSources, separator?) // Compose multiple templates (static)
```

**PromptBuilder Methods:**

All methods return `this` for method chaining.

**Content Methods:**
- `.section(title?, content?)` - Add a section (content can be string or function)
- `.text(text)` - Add raw text content
- `.code(code, language?)` - Add code block with optional language
- `.list(items, ordered?)` - Add list (ordered or unordered)
- `.table(headers, rows)` - Add markdown table
- `.heading(level, text)` - Add heading (level 1-6)
- `.quote(text)` - Add blockquote
- `.separator(char?)` - Add separator line (default: "---")
- `.horizontalRule(char?)` - Alias for separator
- `.json(data, indent?)` - Format JSON data with indentation (default: 2 spaces)
- `.link(text, url)` - Create markdown link
- `.image(alt, url, title?)` - Create markdown image
- `.checkbox(text, checked?)` - Add checkbox/task list item
- `.checkboxes(items)` - Add multiple checkboxes (items can be strings or `{text, checked}` objects)

**Control Flow Methods:**
- `.conditional(condition, ifTrue, ifFalse?)` - Add conditional content based on boolean
- `.loop(items, callback)` - Add content by iterating over items

**Utility Methods:**
- `.build()` - Build final prompt string
- `.toPromptWeaver(options?)` - Convert to PromptWeaver instance for rendering
- `.clear()` - Clear all content and start fresh

-----

## 💡 Real-World Examples

<details>
<summary><strong>🤖 Code Review Assistant</strong></summary>

Generates a structured prompt for reviewing PRs, handling code blocks and arrays of criteria.

```typescript
const codeFence = "```";
const codeReviewTemplate = `
You are an expert code reviewer specializing in {{language}}.

## Code to Review

${codeFence}{{language}}
{{code}}
${codeFence}

## Review Criteria

{{#each criteria}}
- {{this}}
{{/each}}

## Context

- Repository: {{repoName}}
- Pull Request: #{{prNumber}}
- Author: {{authorName}}
- Files Changed: {{filesChanged}}

Please provide a thorough code review focusing on:
1. Code quality and best practices
2. Potential bugs or security issues
3. Performance optimizations
4. Test coverage recommendations

{{#if includeExamples}}
## Example Review Format

Please structure your review as:
- **Critical Issues**: List any blocking issues
- **Suggestions**: Improvement recommendations
- **Questions**: Clarifications needed
{{/if}}
`;

const weaver = new PromptWeaver(codeReviewTemplate);
const reviewPrompt = weaver.format({
  language: "TypeScript",
  code: "function calculateTotal(items: Item[]) { return items.reduce((sum, item) => sum + item.price, 0); }",
  criteria: [
    "Type safety and error handling",
    "Performance and scalability",
    "Code readability and maintainability"
  ],
  repoName: "my-app",
  prNumber: 42,
  authorName: "John Doe",
  filesChanged: 3,
  includeExamples: true
});
```

</details>

<details>
<summary><strong>📊 Data Analysis</strong></summary>

Takes raw data numbers and dates, formats them readable, and adds warnings if outliers are detected.

```typescript
const analysisTemplate = `
You are a data analyst with expertise in {{domain}}.

## Dataset Overview

- **Total Records**: {{integer totalRecords}}
- **Date Range**: {{formatDate startDate "YYYY-MM-DD"}} to {{formatDate endDate "YYYY-MM-DD"}}
- **Key Metrics**: {{#each metrics}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}

## Data Summary

{{#if hasOutliers}}
⚠️ **Note**: This dataset contains {{outlierCount}} outliers that may need special handling.
{{/if}}

## Analysis Request

{{request}}

{{#if includeVisualizations}}
## Visualization Requirements

Please suggest appropriate visualizations for:
{{#each visualizationTypes}}
- {{this}}
{{/each}}
{{/if}}

## Expected Output Format

1. **Executive Summary**: High-level insights (2-3 sentences)
2. **Key Findings**: {{findingsCount}} main observations
3. **Recommendations**: Actionable next steps
4. **Data Quality Notes**: Any concerns or limitations
`;

const analysisWeaver = new PromptWeaver(analysisTemplate);
const analysisPrompt = analysisWeaver.format({
  domain: "e-commerce",
  totalRecords: 125000,
  startDate: new Date("2024-01-01"),
  endDate: new Date("2024-03-31"),
  metrics: ["Revenue", "Conversion Rate", "Customer Lifetime Value"],
  hasOutliers: true,
  outlierCount: 47,
  request: "Analyze sales trends and identify factors contributing to revenue growth in Q1 2024.",
  includeVisualizations: true,
  visualizationTypes: ["Time series", "Cohort analysis", "Funnel visualization"],
  findingsCount: 5
});
```

</details>

<details>
<summary><strong>📞 Customer Support</strong></summary>

Formats a customer ticket with history, deciding tone based on "Premium" status variables.

```typescript
const supportTemplate = `
You are a customer support specialist for {{companyName}}.

## Customer Information

- **Name**: {{customerName}}
- **Account Type**: {{accountType}}
- **Member Since**: {{formatDate memberSince "MMMM YYYY"}}
{{#if isPremium}}
- ⭐ **Premium Member**
{{/if}}

## Issue Details

**Ticket ID**: {{ticketId}}
**Category**: {{category}}
**Priority**: {{upper priority}}
**Reported**: {{relativeTime reportedAt}}

**Description**:
{{issueDescription}}

{{#if previousTickets}}
## Previous Interactions

This customer has {{previousTickets.length}} previous {{pluralize "ticket" previousTickets.length}}:
{{#each previousTickets}}
- Ticket #{{ticketNumber}}: {{summary}} ({{status}})
{{/each}}
{{/if}}

{{#if orderHistory}}
## Recent Order History

{{#each orderHistory}}
- Order #{{orderNumber}}: {{productName}} - {{formatDate orderDate "MMM DD, YYYY"}} - {{capitalize status}}
{{/each}}
{{/if}}

## Response Guidelines

1. Acknowledge the customer's concern with empathy
2. Provide a clear, step-by-step solution
3. {{#if isPremium}}Offer priority escalation if needed{{else}}Suggest self-service options where appropriate{{/if}}
4. Set clear expectations for resolution timeline
5. End with a warm, helpful closing

Please draft a professional, helpful response that resolves their issue.
`;

const supportWeaver = new PromptWeaver(supportTemplate);
const supportPrompt = supportWeaver.format({
  companyName: "TechCorp",
  customerName: "Sarah Johnson",
  accountType: "Business",
  memberSince: new Date("2023-06-15"),
  isPremium: true,
  ticketId: "TC-2024-0847",
  category: "Billing",
  priority: "high",
  reportedAt: new Date(Date.now() - 2 * 60 * 60 * 1000), // 2 hours ago
  issueDescription: "I was charged twice for my subscription renewal. The charge appeared on both my credit card and PayPal account.",
  previousTickets: [
    { ticketNumber: "TC-2024-0721", summary: "Feature request", status: "resolved" }
  ],
  orderHistory: [
    { orderNumber: "ORD-1234", productName: "Pro Plan", orderDate: new Date("2024-03-01"), status: "completed" }
  ]
});
```

</details>

<details>
<summary><strong>🏗️ Programmatic Prompt Building</strong></summary>

Build prompts dynamically based on runtime conditions:

```typescript
import { PromptBuilder } from "@iqai/prompt-weaver";

const builder = new PromptBuilder()
  .heading(1, "AI Code Assistant")
  .section("Role", "You are an expert software engineer specializing in {{language}}.")
  .section("Task", "{{taskDescription}}");

// Conditionally add context section
if (includeContext) {
  builder
    .heading(2, "Context")
    .text("Current codebase:")
    .code(existingCode, "typescript")
    .text(`\nRelated files: ${relatedFiles.join(", ")}`);
}

// Build requirements section
builder.section("Requirements", () => {
  const reqBuilder = new PromptBuilder().list(requirements);
  if (hasConstraints) {
    reqBuilder.heading(3, "Constraints").list(constraints);
  }
  return reqBuilder.build();
});

builder.section("Output Format", "Please provide:\n1. Complete code solution\n2. Brief explanation\n3. Testing recommendations");

// Convert to PromptWeaver and render with data
const weaver = builder.toPromptWeaver();
const output = weaver.format({
  language: "TypeScript",
  taskDescription: "Create a function to calculate Fibonacci numbers",
  // ... other data
});
```

**Key Benefits:**
- Build prompts programmatically with full control flow
- Use conditionals, loops, and dynamic content
- Convert to PromptWeaver for template rendering with variables
- Validate data against the built template

</details>

-----

## ⚠️ Error Handling

Prompt Weaver provides specific error classes for debugging with enhanced error messages.

- `SchemaValidationError`: Thrown when data doesn't match your Zod/Valibot schema. Includes detailed validation issues.
- `TemplateCompilationError`: Thrown when your Handlebars syntax is broken (e.g., unclosed tags). Includes surrounding code context, line numbers, and helpful suggestions.

**Example:**

```typescript
import { SchemaValidationError, TemplateCompilationError } from "@iqai/prompt-weaver";
import { z } from 'zod';

const schema = z.object({
  name: z.string(),
  age: z.number(),
});

try {
  const weaver = new PromptWeaver(template, { schema });
  // format() automatically validates when schema is provided
  const output = weaver.format({ name: "Alice", age: 30 });
} catch (error) {
  if (error instanceof SchemaValidationError) {
    console.error("Validation failed:", error.issues);
    console.error(error.getFormattedMessage());
    // Detailed validation error messages from your schema library
  } else if (error instanceof TemplateCompilationError) {
    console.error(error.getFormattedMessage());
    // Enhanced error message includes:
    // - Line and column numbers
    // - Surrounding code context
    // - Helpful suggestions for fixing common errors
  }
}
```

-----

<div align="center">

Built with 💙 by IQ AI Team

</div>