# mm_tpl

Super Meimei Template Engine Module, based on art-template engine, provides powerful MVC pattern view rendering functionality with hook system, theme switching, and caching mechanism.

[中文文档](README.md) | [English Documentation](README_EN.md)

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Advanced Features](#advanced-features)
- [API Reference](#api-reference)
- [Notes](#notes)
- [Development](#development)
- [License](#license)

## Features

- 🚀 High-performance template engine based on art-template
- 🔧 Support for multiple template syntax rules
- 🎨 Theme switching and template file priority search
- ⚡ Built-in caching mechanism for performance optimization
- 🔌 Powerful hook system support
- 📁 Flexible directory structure support
- 🛡️ Comprehensive error handling mechanism

## Installation

```bash
npm install mm_tpl
```

## Quick Start

### 1. Install Dependencies

```bash
npm install mm_tpl
```

### 2. Initialize Template Engine

```javascript
const {Tpl} = require('mm_tpl');

// Create template instance
const tpl = new Tpl({
    root: process.cwd(),           // Root directory
    default_dir: "./template/",    // Default template directory
    default_theme: 'default',      // Default theme
    extname: ".html",             // Template file extension
    cache_root: './cache',        // Cache directory
    cache_extname: '.cache.html', // Cache file extension
    rules: [nativeRule, artRule, htmlRule, jsRule, pyRule, pyRule2] // Template rules
});
```

### 3. Basic Template Rendering

```javascript
// Simple variable substitution
const result = tpl.render("<div>${message}</div>", {
    message: "Hello World"
});
// Output: <div>Hello World</div>

// Compile template function
const compiled = tpl.compile("<div>${name} - ${age}</div>");
const result2 = compiled({ name: "John", age: 25 });
// Output: <div>John - 25</div>
```

### 4. Loop Rendering

```javascript
// Array loop
const arrayResult = tpl.render(`
    <ul>
        ${loop arr value idx}
            <li>${idx}: ${value}</li>
        ${/loop}
    </ul>
`, { 
    arr: [123, 234] 
});

// Object loop
const objectResult = tpl.render(`
    <dl>
        ${loop obj value key}
            <dt>${key}</dt>
            <dd>${value}</dd>
        ${/loop}
    </dl>
`, { 
    obj: { name: "John", age: 25 } 
});

// Traditional for loop
const forResult = tpl.render(`
    <ul>
        <!--[ for(var i = 0; i < arr.length; i++){ ]-->
            <li>${arr[i]}</li>
        <!--[ } ]-->
    </ul>
`, {
    arr: [123, 234]
});

// Each loop
const eachResult = tpl.render(`
    <ul>
        ${each arr}
            <li>${$value}</li>
        ${/each}
    </ul>
`, {
    arr: [123, 234]
});
// Output: 
// <ul>
//     <li>123</li>
//     <li>234</li>
// </ul>
```

### 5. View Rendering

```javascript
// Set global variables
$.globalBag.siteName = "My Website";

// Set view variables
tpl.set({
    title: "Homepage",
    keywords: "keywords"
});

// Render view file
const html = tpl.view("./views/index.html", {
    user: { name: "John" }
});
// Output: Rendering result <div>Hello World</div>

// Get view variable
const title = tpl.get("title");

// Delete view variable
tpl.del("keywords");
```

### 6. Caching Mechanism

```javascript
// Use cache for view rendering
const html = tpl.view("./views/page", {
    data: someData
}, {
    cache: true,                // Whether to use cache
    cache_filename: "./cache"   // Cache filename
});

// Clear cache
tpl.clearCache('./views/mall'); // Clear cache for specific directory
// or
tpl.clearCache(); // Clear all cache
```

### 7. Hook System

#### Add Function Hook
```javascript
$.hook.addFunc('list', async function(viewBag, req, type) {
    // Process list logic
    var query = req.query;
    if (query.user_id) {
        viewBag.user_id = query.user_id;
    }
    return someData;
}, 100, 'listFunc'); // sort: priority, alias: alias
```

#### Add Action Hook
```javascript
$.hook.addAction('header', function(viewBag, param) {
    return "<header>Website Header</header>";
}, 1, "headerAction");
```

#### Add Filter Hook
```javascript
$.hook.addFilter('content', function(viewBag, content, param) {
    return content.replace("old text", "new text");
}, 1, "contentFilter");
```

#### Execute Hooks
```javascript
// Execute function hook
const result = await tpl.runFunc('list', { query: { page: 1 } }, 'article');

// Execute action hook
const actionResult = tpl.runHook('header', { param: 'value' });

// Use hooks in template
const html = tpl.render(`
    <div>
        ${hookAction('header')}
        ${hookFilter('content', 'original content')}
    </div>
`, data);
```

#### Delete Hooks
```javascript
// Delete specific hook
$.hook.delFunc('list', 'listFunc');
$.hook.delAction('header', 'headerAction');
$.hook.delFilter('content', 'contentFilter');

// Clear all hooks
$.hook.clear();
```

## Advanced Features

### 1. Theme and Directory Support
```javascript
// Set current theme
tpl.current_theme = "dark";

// Template file search order (priority from high to low):
// 1. diy directory (custom directory)
// 2. Current theme directory
// 3. Default theme directory
```

### 2. Template Rules
Built-in support for multiple template rules, including:
- nativeRule: Native syntax rules
- artRule: art-template syntax rules
- htmlRule: HTML comment syntax rules
- jsRule: JavaScript syntax rules
- pyRule: Python-style syntax rules

### 3. Error Handling
```javascript
const html = tpl.view("./template.html", data);
if (tpl.error) {
    console.error("Rendering error:", tpl.error);
}
```

### 4. Character Escaping
```javascript
// Automatically escape special characters
const escaped = tpl.escape("<div>${content}</div>");
// Output: <div>·$·{content}</div>

// Restore escaped characters
const restored = tpl.escape(escaped, true);
// Output: <div>${content}</div>
```

### 5. Global Mounting
```javascript
// Automatically mount to global object
if (global.$ && !$.Tpl) {
    $.Tpl = Tpl;
    $.tpl = new Tpl();
}
```

## API Reference

### Tpl Class Methods

- `constructor(config)` - Constructor, create template instance
- `setConfig(config)` - Set configuration parameters
- `render(body, model, options)` - Render template string
- `compile(body, options)` - Compile template to function
- `view(file, model, options)` - Render template file
- `set(obj)` - Set view data
- `get(key)` - Get view data
- `del(keys)` - Delete view data
- `clearCache(path, file)` - Clear cache
- `runFunc(name, req, ...args)` - Execute function hook
- `runHook(name, req, ...args)` - Execute action hook (alias of runFunc)
- `escape(body, restore)` - Escape/restore characters

### Hook Class Methods

- `addFunc(name, func, sort, alias)` - Add function hook
- `addAction(name, func, sort, alias)` - Add action hook
- `addFilter(name, func, sort, alias)` - Add filter hook
- `runFunc(name, model, req, ...args)` - Execute function hook
- `runAction(name, model, ...args)` - Execute action hook
- `runFilter(name, model, ret, ...args)` - Execute filter hook
- `delFunc(name, alias)` - Delete function hook
- `delAction(name, alias)` - Delete action hook
- `delFilter(name, alias)` - Delete filter hook
- `clear(name)` - Clear hooks

## Notes

1. **Dependencies**: Requires `art-template` and `mm_expand` dependency packages
2. **Directory Permissions**: Ensure template directories have read/write permissions
3. **Cache Management**: Clean expired cache promptly to avoid memory leaks
4. **Hook Priority**: Lower numerical values indicate higher priority and earlier execution
5. **Async Processing**: Hook functions support async operations, pay attention to error handling
6. **File Search**: Template files are searched in priority order, ensure files exist
7. **Character Escaping**: Automatic handling of template syntax characters to avoid conflicts

## Development

```bash
# Run tests
npm test

# Check code coverage
npm run coverage
```

## License

MIT License