mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-25 02:08:28 +02:00
Support _PREFIXED variable names and fail when variable missing
This commit is contained in:
@@ -6,6 +6,9 @@ pub enum Error {
|
|||||||
#[error("Render Error: {0}")]
|
#[error("Render Error: {0}")]
|
||||||
RenderError(String),
|
RenderError(String),
|
||||||
|
|
||||||
|
#[error("Render Error: Variable \"{0}\" is not defined in active environment")]
|
||||||
|
VariableNotFound(String),
|
||||||
|
|
||||||
#[error("Render Error: Max recursion depth exceeded")]
|
#[error("Render Error: Max recursion depth exceeded")]
|
||||||
RenderStackExceededError,
|
RenderStackExceededError,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,9 +269,9 @@ impl Parser {
|
|||||||
while self.pos < self.chars.len() {
|
while self.pos < self.chars.len() {
|
||||||
let ch = self.peek_char();
|
let ch = self.peek_char();
|
||||||
let is_valid = if start_pos == self.pos {
|
let is_valid = if start_pos == self.pos {
|
||||||
ch.is_alphabetic() // First char has to be alphabetic
|
ch.is_alphabetic() || ch == '_' // First is more restrictive
|
||||||
} else {
|
} else {
|
||||||
ch.is_alphanumeric() || ch == '-' || ch == '_'
|
ch.is_alphanumeric() || ch == '_' || ch == '-'
|
||||||
};
|
};
|
||||||
if is_valid {
|
if is_valid {
|
||||||
text.push(ch);
|
text.push(ch);
|
||||||
@@ -457,13 +457,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn var_prefixes() {
|
fn var_prefixes() {
|
||||||
let mut p = Parser::new("${[ -a ]}${[ _a ]}${[ 0a ]}");
|
let mut p = Parser::new("${[ -a ]}${[ 0a ]}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
p.parse().tokens,
|
p.parse().tokens,
|
||||||
vec![
|
vec![
|
||||||
Token::Raw {
|
Token::Raw {
|
||||||
// Shouldn't be parsed, because they're invalid
|
// Shouldn't be parsed, because they're invalid
|
||||||
text: "${[ -a ]}${[ _a ]}${[ 0a ]}".into()
|
text: "${[ -a ]}${[ 0a ]}".into()
|
||||||
},
|
},
|
||||||
Token::Eof
|
Token::Eof
|
||||||
]
|
]
|
||||||
@@ -476,8 +476,8 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
p.parse().tokens,
|
p.parse().tokens,
|
||||||
vec![
|
vec![
|
||||||
Token::Raw {
|
Token::Tag {
|
||||||
text: "${[ _a ]}".into()
|
val: Val::Var { name: "_a".into() }
|
||||||
},
|
},
|
||||||
Token::Eof
|
Token::Eof
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::error::Error::RenderStackExceededError;
|
use crate::error::Error::{RenderStackExceededError, VariableNotFound};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::{FnArg, Parser, Token, Tokens, Val};
|
use crate::{FnArg, Parser, Token, Tokens, Val};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
@@ -100,7 +100,7 @@ async fn render_tag<T: TemplateCallback>(
|
|||||||
let r = Box::pin(parse_and_render_with_depth(v, vars, cb, depth)).await?;
|
let r = Box::pin(parse_and_render_with_depth(v, vars, cb, depth)).await?;
|
||||||
r.to_string()
|
r.to_string()
|
||||||
}
|
}
|
||||||
None => "".into(),
|
None => return Err(VariableNotFound(name)),
|
||||||
},
|
},
|
||||||
Val::Bool { value } => value.to_string(),
|
Val::Bool { value } => value.to_string(),
|
||||||
Val::Fn { name, args } => {
|
Val::Fn { name, args } => {
|
||||||
@@ -142,7 +142,7 @@ async fn render_tag<T: TemplateCallback>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod parse_and_render_tests {
|
mod parse_and_render_tests {
|
||||||
use crate::error::Error::{RenderError, RenderStackExceededError};
|
use crate::error::Error::{RenderError, RenderStackExceededError, VariableNotFound};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::renderer::TemplateCallback;
|
use crate::renderer::TemplateCallback;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
@@ -200,6 +200,19 @@ mod parse_and_render_tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn render_missing_var() -> Result<()> {
|
||||||
|
let empty_cb = EmptyCB {};
|
||||||
|
let template = "${[ foo ]}";
|
||||||
|
let vars = HashMap::new();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse_and_render(template, &vars, &empty_cb).await,
|
||||||
|
Err(VariableNotFound("foo".to_string()))
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn render_self_referencing_var() -> Result<()> {
|
async fn render_self_referencing_var() -> Result<()> {
|
||||||
let empty_cb = EmptyCB {};
|
let empty_cb = EmptyCB {};
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ const EnvironmentEditor = function ({
|
|||||||
const validateName = useCallback((name: string) => {
|
const validateName = useCallback((name: string) => {
|
||||||
// Empty just means the variable doesn't have a name yet, and is unusable
|
// Empty just means the variable doesn't have a name yet, and is unusable
|
||||||
if (name === '') return true;
|
if (name === '') return true;
|
||||||
return name.match(/^[a-z][a-z0-9_-]*$/i) != null;
|
return name.match(/^[a-z_][a-z0-9_-]*$/i) != null;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user