Skip to content

Commit

Permalink
Allow the CLI to override the syntax config (#504)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Apr 28, 2024
1 parent b2301a6 commit a8d40e9
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ For upgrade instructions read the [UPDATING](UPDATING.md) guide.
Previously this behavior was hidden internally in the serde support. #495
- `UndefinedBehavior::Strict` now acts more delayed. This means that now `value.key is defined`
- Added support for line statements and comments. #503
- The CLI now accepts `--syntax` to reconfigure syntax flags such as delimiters. #504

## 1.0.21

Expand Down
1 change: 1 addition & 0 deletions minijinja-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ minijinja = { version = "=2.0.0-alpha.0", path = "../minijinja", features = [
"urlencode",
"fuel",
"unstable_machinery",
"custom_syntax",
] }
minijinja-contrib = { version = "=2.0.0-alpha.0", path = "../minijinja-contrib" }
rustyline = { version = "12.0.0", optional = true }
Expand Down
10 changes: 10 additions & 0 deletions minijinja-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ can be set to stdin at once.
enables strict mode. Undefined variables will then error upon rendering.
- `--no-include`:
disallows including or extending of templates from the file system.
- `--no-newline`:
Do not output a trailing newline
- `--trim-blocks`:
Enable the trim_blocks flag
- `--lstrip-blocks`:
Enable the lstrip_blocks flag
- `-s`, `--syntax <PAIR>`:
Changes a syntax feature (feature=value) [possible features: `block-start`, `block-end`, `variable-start`, `variable-end`, `comment-start`, `comment-end`, `line-statement-prefix`, `line-statement-comment`]
- `--safe-path <PATH>`:
Only allow includes from this path. Can be used multiple times.
- `--env`:
passes the environment variables to the template in the variable `ENV`
- `-E`, `--expr` `<EXPR>`:
Expand Down
6 changes: 5 additions & 1 deletion minijinja-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ pub(super) fn make_command() -> Command {
.action(ArgAction::Append),
arg!(--strict "disallow undefined variables in templates"),
arg!(--"no-include" "Disallow includes and extending"),
arg!(--"no-newline" "Do not output a newline"),
arg!(--"no-newline" "Do not output a trailing newline"),
arg!(--"trim-blocks" "Enable the trim_blocks flag"),
arg!(--"lstrip-blocks" "Enable the lstrip_blocks flag"),
arg!(-s --syntax <PAIR>... "Changes a syntax feature (feature=value) \
[possible features: block-start, block-end, variable-start, variable-end, \
comment-start, comment-end, line-statement-prefix, \
line-statement-comment]"),
arg!(--"safe-path" <PATH>... "Only allow includes from this path. Can be used multiple times.")
.conflicts_with("no-include")
.value_parser(value_parser!(PathBuf)),
Expand Down
55 changes: 54 additions & 1 deletion minijinja-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use clap::ArgMatches;
use minijinja::machinery::{
get_compiled_template, parse, tokenize, Instructions, WhitespaceConfig,
};
use minijinja::syntax::SyntaxConfig;
use minijinja::{
context, AutoEscape, Environment, Error as MError, ErrorKind, UndefinedBehavior, Value,
};
Expand Down Expand Up @@ -163,15 +164,59 @@ fn interpret_raw_value(s: &str) -> Result<Value, Error> {
.with_context(|| format!("invalid raw value '{}' (not valid {})", s, imp::FMT))
}

fn make_syntax(matches: &ArgMatches) -> Result<SyntaxConfig, Error> {
let mut iter = matches.get_many::<String>("syntax");

let mut f_block_start = "{%".to_string();
let mut f_block_end = "%}".to_string();
let mut f_variable_start = "{{".to_string();
let mut f_variable_end = "}}".to_string();
let mut f_comment_start = "{#".to_string();
let mut f_comment_end = "#}".to_string();
let mut f_line_statement_prefix = "".to_string();
let mut f_line_comment_prefix = "".to_string();

if let Some(ref mut iter) = iter {
for pair in iter {
let (key, value) = pair
.split_once('=')
.ok_or_else(|| anyhow!("syntax feature needs to be a key=value pair"))?;

*match key {
"block-start" => &mut f_block_start,
"block-end" => &mut f_block_end,
"variable-start" => &mut f_variable_start,
"variable-end" => &mut f_variable_end,
"comment-start" => &mut f_comment_start,
"comment-end" => &mut f_comment_end,
"line-statement-prefix" => &mut f_line_statement_prefix,
"line-comment-prefix" => &mut f_line_comment_prefix,
_ => bail!("unknown syntax feature '{}'", key),
} = value.to_string();
}
}

SyntaxConfig::builder()
.block_delimiters(f_block_start, f_block_end)
.variable_delimiters(f_variable_start, f_variable_end)
.comment_delimiters(f_comment_start, f_comment_end)
.line_statement_prefix(f_line_statement_prefix)
.line_comment_prefix(f_line_comment_prefix)
.build()
.context("could not configure syntax")
}

fn create_env(
matches: &ArgMatches,
cwd: PathBuf,
allowed_template: Option<String>,
safe_paths: Vec<PathBuf>,
stdin_used_for_data: bool,
syntax: SyntaxConfig,
) -> Environment<'static> {
let mut env = Environment::new();
env.set_debug(true);
env.set_syntax(syntax);

if let Some(fuel) = matches.get_one::<u64>("fuel") {
if *fuel > 0 {
Expand Down Expand Up @@ -352,7 +397,15 @@ fn execute() -> Result<i32, Error> {

let no_newline = matches.get_flag("no-newline");

let env = create_env(&matches, cwd, allowed_template, safe_paths, stdin_used);
let syntax = make_syntax(&matches)?;
let env = create_env(
&matches,
cwd,
allowed_template,
safe_paths,
stdin_used,
syntax,
);

if let Some(expr) = matches.get_one::<String>("expr") {
let rv = env.compile_expression(expr)?.eval(ctx)?;
Expand Down
23 changes: 23 additions & 0 deletions minijinja-cli/tests/test_basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,26 @@ fn test_stdin_template() {
----- stderr -----
"###);
}

#[test]
fn test_line_statement() {
let tmpl = file_with_contents("# for item in seq\n {{ item }}\n# endfor");
let input = file_with_contents_and_ext(r#"{"seq": [1, 2, 3]}"#, ".json");

assert_cmd_snapshot!(
cli()
.arg("-sline-statement-prefix=#")
.arg("--no-newline")
.arg(tmpl.path())
.arg(input.path()),
@r###"
success: true
exit_code: 0
----- stdout -----
1
2
3
----- stderr -----
"###);
}

0 comments on commit a8d40e9

Please sign in to comment.