Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 0 additions & 158 deletions .github/pull_request_template.md

This file was deleted.

14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ keywords = ["template", "minijinja", "cli", "environment", "variables"]
categories = ["command-line-utilities", "template-engine"]

[dependencies]
minijinja = { version = "2", features = ["builtins"] }
minijinja = { version = "2", features = ["builtins", "loader"] }
clap = { version = "4", features = ["derive"] }
serde = { version = "1", features = ["derive"] }
regex = "1"
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![Docker](https://img.shields.io/badge/docker-ghcr.io-blue)](https://github.com/bordeux/tmpltool/pkgs/container/tmpltool)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

A fast and simple command-line template rendering tool using [Tera](https://keats.github.io/tera/) templates with environment variables.
A fast and simple command-line template rendering tool using [MiniJinja](https://github.com/mitsuhiko/minijinja) templates with environment variables.

## Table of Contents

Expand Down Expand Up @@ -71,7 +71,7 @@ tmpltool greeting.tmpl
- **Validation**: Validate emails, URLs, IPs, UUIDs, regex matching
- **Security**: Built-in protections with optional `--trust` mode
- **Flexible I/O**: File or stdin input, file or stdout output
- **Full Tera Syntax**: Conditionals, loops, filters, and more
- **Full Jinja2 Syntax**: Conditionals, loops, filters, and more
- **Single Binary**: No runtime dependencies
- **Docker Support**: Multi-arch images available

Expand Down Expand Up @@ -285,7 +285,7 @@ tmpltool build-report.tmpl

## Template Syntax

tmpltool uses the [Tera](https://keats.github.io/tera/) template engine. For complete documentation, visit: https://keats.github.io/tera/docs/
tmpltool uses the [MiniJinja](https://github.com/mitsuhiko/minijinja) template engine, which is compatible with Python's Jinja2. For complete documentation, visit: https://docs.rs/minijinja/

### Variables

Expand Down Expand Up @@ -1346,4 +1346,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file

For more examples, see the [examples/](examples/) directory and [examples/README.md](examples/README.md).

For complete Tera syntax documentation, visit: https://keats.github.io/tera/docs/
For complete MiniJinja/Jinja2 syntax documentation, visit:
- MiniJinja Docs: https://docs.rs/minijinja/
- Jinja2 Template Designer: https://jinja.palletsprojects.com/templates/
6 changes: 6 additions & 0 deletions examples/test-include.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Testing relative path resolution:

File content from ./basic.tmpl parsed:
{% include "./basic.tmpl" %}

End of test.
43 changes: 43 additions & 0 deletions src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,49 @@ fn render(
// Set strict undefined behavior - fail on undefined variables (like Tera)
env.set_undefined_behavior(minijinja::UndefinedBehavior::Strict);

// Clone template_context for use in the loader closure
let loader_context = template_context.clone();

// Set up lazy template loader for includes
env.set_loader(move |name: &str| -> Result<Option<String>, minijinja::Error> {
// Validate path security unless in trust mode
if !loader_context.is_trust_mode() {
if name.starts_with('/') {
return Err(minijinja::Error::new(
minijinja::ErrorKind::InvalidOperation,
format!(
"Security: Absolute paths are not allowed: {}. Use --trust to bypass this restriction.",
name
),
));
}
if name.contains("..") {
return Err(minijinja::Error::new(
minijinja::ErrorKind::InvalidOperation,
format!(
"Security: Parent directory (..) traversal is not allowed: {}. Use --trust to bypass this restriction.",
name
),
));
}
}

// Resolve the template path relative to the base directory
let resolved_path = loader_context.resolve_path(name);

// Read the template file
match fs::read_to_string(&resolved_path) {
Ok(content) => Ok(Some(content)),
Err(e) => {
// Return a helpful error message
Err(minijinja::Error::new(
minijinja::ErrorKind::TemplateNotFound,
format!("Failed to load template '{}': {}", resolved_path.display(), e),
))
}
}
});

// Register all custom functions
functions::register_all(&mut env, template_context);

Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/expected/include_base.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Header: Default Header
Content from partial template.
User: guest
Footer: Done
5 changes: 5 additions & 0 deletions tests/fixtures/expected/include_nested.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Main template start
Level 1 start
Level 2: nested value
Level 1 end
Main template end
3 changes: 3 additions & 0 deletions tests/fixtures/templates/include_base.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Header: {{ get_env(name="HEADER", default="Default Header") }}
{% include "./include_partial.tmpl" %}
Footer: Done
3 changes: 3 additions & 0 deletions tests/fixtures/templates/include_nested_level1.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Level 1 start
{% include "./include_nested_level2.tmpl" %}
Level 1 end
1 change: 1 addition & 0 deletions tests/fixtures/templates/include_nested_level2.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Level 2: nested value
3 changes: 3 additions & 0 deletions tests/fixtures/templates/include_nested_main.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Main template start
{% include "./include_nested_level1.tmpl" %}
Main template end
2 changes: 2 additions & 0 deletions tests/fixtures/templates/include_partial.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Content from partial template.
User: guest
Loading