From 88ff7f4300dc99f131ccbad0dbf569c19a531726 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 13 Jan 2025 06:38:21 -0800 Subject: [PATCH] Support dashes in template variable/fn names --- src-tauri/yaak-templates/src/parser.rs | 50 +++++++++++++++++++- src-web/components/EnvironmentEditDialog.tsx | 2 +- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src-tauri/yaak-templates/src/parser.rs b/src-tauri/yaak-templates/src/parser.rs index de3abc26..f624b11b 100644 --- a/src-tauri/yaak-templates/src/parser.rs +++ b/src-tauri/yaak-templates/src/parser.rs @@ -268,7 +268,12 @@ impl Parser { let mut text = String::new(); while self.pos < self.chars.len() { let ch = self.peek_char(); - if ch.is_alphanumeric() || ch == '_' { + let is_valid = if start_pos == self.pos { + ch.is_alphabetic() // First char has to be alphabetic + } else { + ch.is_alphanumeric() || ch == '-' || ch == '-' + }; + if is_valid { text.push(ch); self.pos += 1; } else { @@ -422,6 +427,49 @@ mod tests { ); } + #[test] + fn var_dashes() { + let mut p = Parser::new("${[ a-b ]}"); + assert_eq!( + p.parse().tokens, + vec![ + Token::Tag { + val: Val::Var { name: "a-b".into() } + }, + Token::Eof + ] + ); + } + + #[test] + fn var_prefixes() { + let mut p = Parser::new("${[ -a ]}${[ _a ]}${[ 0a ]}"); + assert_eq!( + p.parse().tokens, + vec![ + Token::Raw { + // Shouldn't be parsed, because they're invalid + text: "${[ -a ]}${[ _a ]}${[ 0a ]}".into() + }, + Token::Eof + ] + ); + } + + #[test] + fn var_underscore_prefix() { + let mut p = Parser::new("${[ _a ]}"); + assert_eq!( + p.parse().tokens, + vec![ + Token::Raw { + text: "${[ _a ]}".into() + }, + Token::Eof + ] + ); + } + #[test] fn var_boolean() { let mut p = Parser::new("${[ true ]}${[ false ]}"); diff --git a/src-web/components/EnvironmentEditDialog.tsx b/src-web/components/EnvironmentEditDialog.tsx index c1a0f475..5dfe3d97 100644 --- a/src-web/components/EnvironmentEditDialog.tsx +++ b/src-web/components/EnvironmentEditDialog.tsx @@ -159,7 +159,7 @@ const EnvironmentEditor = function ({ const validateName = useCallback((name: string) => { // Empty just means the variable doesn't have a name yet, and is unusable 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 (