Skip to content

Commit 592f365

Browse files
authored
feat: add support for include and inherit (#9)
* Flag to parse everything in the same path as the template * Logic for 'include' flag * Option to define a different 'include' path * Logic for `include-path` option * Document new `--include` flag and `--include-path` option * Update **tera cli** usage documentation * Tera's **include** example * Tera's **inheritance** example * Update markdown README file
1 parent 55be2a2 commit 592f365

9 files changed

Lines changed: 99 additions & 14 deletions

File tree

README.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ By default, your ENV variables will be loaded at the root of the context data. F
125125

126126
While the syntax is a little more verbose, paired with `--fail-on-collision`, this option allows ensuring that nothing happens in your back.
127127

128+
### External files
129+
130+
Using the `--include` flag, the command will scan recursively for files that could be [included](https://tera.netlify.app/docs/#include), used as [macros](https://tera.netlify.app/docs/#macros) or for [inheritance](https://tera.netlify.app/docs/#inheritance). By default, it will scan the folder where the main template is located, unless the `--include-path` option is given.
131+
132+
From this repository, you can test **include** feature with the command `USER="[YOURNAME]" tera --template data/include/hello.txt --include --env-only` and test **inheritance** feature with `USER="[YOURNAME]" tera --template data/inheritance/child.txt --inherit --env-only`.
133+
128134
### Output
129135

130136
By default,
@@ -159,13 +165,20 @@ Passing the `-a | --escape` flag allows escaping the content.
159165
be raised
160166
--fail-on-collision if you prefer your data to override the ENV
161167
-h, --help Prints help information
168+
-i, --include This flag tells the command to parse all templates found in the same
169+
path where the given template is located [aliases: inherit]
162170
-s, --stdin The context data can be passed using stdin
163171
-V, --version Prints version information
164172

165173
OPTIONS:
166-
--env-key <env-key> By default, if --env is set, the environment variables will be
167-
attached at the root of the context. This is convenient but may end
168-
up conflicting with your data. To prevent collisions, you can
169-
provide a custom key with this option
170-
-o, --out <out> Optional output file. If not passed, using stdout
171-
-t, --template <template> Location of the template
174+
--env-key <env-key>
175+
By default, if --env is set, the environment variables will be attached at the root of
176+
the context. This is convenient but may end up conflicting with your data. To prevent
177+
collisions, you can provide a custom key with this option
178+
179+
--include-path <include-path>
180+
Option to define a different path from which search and parse templates [aliases:
181+
inherit-path]
182+
183+
-o, --out <out> Optional output file. If not passed, using stdout
184+
-t, --template <template> Location of the template

README_src.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ By default, your ENV variables will be loaded at the root of the context data. F
9999

100100
While the syntax is a little more verbose, paired with `--fail-on-collision`, this option allows ensuring that nothing happens in your back.
101101

102+
=== External files
103+
104+
Using the `--include` flag, the command will scan recursively for files that could be https://tera.netlify.app/docs/#include[included], used as https://tera.netlify.app/docs/#macros[macros] or for https://tera.netlify.app/docs/#inheritance[inheritance]. By default, it will scan the folder where the main template is located, unless the `--include-path` option is given.
105+
106+
From this repository, you can test *include* feature with the command `USER="[YOURNAME]" tera --template data/include/hello.txt --include --env-only` and test *inheritance* feature with `USER="[YOURNAME]" tera --template data/inheritance/child.txt --inherit --env-only`.
107+
102108
=== Output
103109

104110
By default,

data/include/hello.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Hello {{ USER }}, this is the Hello template.
2+
{% include "world.txt" %}

data/include/world.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is the world template.

data/inheritance/base.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This is a BASE template.
2+
3+
The default greetings shows "Greetings!" but we can improve that with inheritance!
4+
5+
{% block greetings %}
6+
Greetings!
7+
{% endblock greetings %}

data/inheritance/child.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{% extends "base.txt" %}
2+
3+
The following block will replace our greetings in the base.
4+
5+
{% block greetings %}
6+
May the force be with you **{{ USER }}**
7+
{% endblock greetings %}

doc/usage.adoc

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ FLAGS:
2222
be raised
2323
--fail-on-collision if you prefer your data to override the ENV
2424
-h, --help Prints help information
25+
-i, --include This flag tells the command to parse all templates found in the same
26+
path where the given template is located [aliases: inherit]
2527
-s, --stdin The context data can be passed using stdin
2628
-V, --version Prints version information
2729

2830
OPTIONS:
29-
--env-key <env-key> By default, if --env is set, the environment variables will be
30-
attached at the root of the context. This is convenient but may end
31-
up conflicting with your data. To prevent collisions, you can
32-
provide a custom key with this option
33-
-o, --out <out> Optional output file. If not passed, using stdout
34-
-t, --template <template> Location of the template
31+
--env-key <env-key>
32+
By default, if --env is set, the environment variables will be attached at the root of
33+
the context. This is convenient but may end up conflicting with your data. To prevent
34+
collisions, you can provide a custom key with this option
35+
36+
--include-path <include-path>
37+
Option to define a different path from which search and parse templates [aliases:
38+
inherit-path]
39+
40+
-o, --out <out> Optional output file. If not passed, using stdout
41+
-t, --template <template> Location of the template

src/main.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use clap::{crate_name, crate_version, Clap};
77
use env_logger::Env;
88
use log::{debug, info, trace};
99
use opts::*;
10-
use std::{fs::File, io::Write};
10+
use std::{fs::canonicalize, fs::File, io::Write, string::String};
1111
use tera::{Context, Tera};
1212

1313
fn main() -> Result<(), String> {
@@ -22,14 +22,47 @@ fn main() -> Result<(), String> {
2222

2323
let autoescape = opts.autoescape;
2424
let output = opts.out.to_owned();
25+
let mut include = opts.include;
26+
let mut path = canonicalize(&opts.template).unwrap();
27+
28+
if opts.include_path.is_some() {
29+
include = true;
30+
path = canonicalize(opts.include_path.as_ref().unwrap()).unwrap();
31+
}
2532

2633
let mut wrapped_context = wrapped_context::WrappedContext::new(opts);
2734
wrapped_context.create_context();
2835

2936
let context: &Context = wrapped_context.context();
3037
trace!("context:\n{:#?}", context);
3138

32-
let rendered = Tera::one_off(&template, context, autoescape).unwrap();
39+
let rendered;
40+
41+
if include {
42+
let mut dir = path.to_str().unwrap();
43+
44+
if path.is_file() {
45+
dir = path.parent().unwrap().to_str().unwrap();
46+
}
47+
48+
let glob = dir.to_owned() + "/**/*";
49+
50+
let mut tera = match Tera::new(&glob) {
51+
Ok(t) => t,
52+
Err(e) => {
53+
println!("Parsing error(s): {}", e);
54+
::std::process::exit(1);
55+
}
56+
};
57+
58+
if !autoescape {
59+
tera.autoescape_on(vec![]);
60+
}
61+
62+
rendered = tera.render_str(&template, context).unwrap();
63+
} else {
64+
rendered = Tera::one_off(&template, context, autoescape).unwrap();
65+
}
3366

3467
println!("{}", rendered);
3568

src/opts.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ pub struct Opts {
1111
#[clap(short, long)]
1212
pub template: PathBuf,
1313

14+
/// This flag tells the command to parse all templates found in the same
15+
/// path where the given template is located.
16+
#[clap(short, long, visible_alias = "inherit")]
17+
pub include: bool,
18+
19+
/// Option to define a different path from which search and parse templates.
20+
#[clap(long, visible_alias = "inherit-path")]
21+
pub include_path: Option<PathBuf>,
22+
1423
/// Location of the context data. This file can be of the following type:
1524
/// json | toml | yaml. If you prefer to pass the data as stdin, use `--stdin`
1625
#[clap(index = 1, required_unless_present_any = &["stdin", "env-only"], conflicts_with = "env-only")]

0 commit comments

Comments
 (0)