fix(parsers): more robust pwsh param parsing (#4884)

This commit is contained in:
HugoCasa
2024-12-09 20:55:43 +01:00
committed by GitHub
parent 69195b71f3
commit 7014389d67
3 changed files with 162 additions and 31 deletions
+156 -25
View File
@@ -9,7 +9,7 @@ use regex_lite::Regex;
use serde_json::json;
use std::collections::HashMap;
use std::{collections::HashMap, str::FromStr};
use windmill_parser::{Arg, MainArgSignature, Typ};
pub fn parse_bash_sig(code: &str) -> anyhow::Result<MainArgSignature> {
@@ -84,36 +84,94 @@ fn parse_bash_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
Ok(Some(args))
}
enum ParserState {
Normal,
InSingleQuote,
InDoubleQuote,
}
fn split_pwsh_args(code: &str) -> Vec<&str> {
let mut chars = code.char_indices().peekable();
let mut state = ParserState::Normal;
let mut splits = vec![];
let mut last_idx = 0;
while let Some((idx, char)) = chars.next() {
match (&state, char) {
(ParserState::Normal, '\'') => {
state = ParserState::InSingleQuote;
}
(ParserState::Normal, '"') => {
state = ParserState::InDoubleQuote;
}
(ParserState::InSingleQuote, '\'') => {
state = ParserState::Normal;
}
(ParserState::InDoubleQuote, '"') => {
state = ParserState::Normal;
}
(ParserState::Normal, ',') => {
splits.push(&code[last_idx..idx]);
last_idx = idx + 1; // skip the comma
}
_ => {}
}
}
if last_idx < code.len() {
splits.push(&code[last_idx..]);
}
splits
}
fn parse_powershell_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
let param_wrapper = RE_POWERSHELL_PARAM.captures(code);
let mut args = vec![];
if let Some(param_wrapper) = param_wrapper {
let param_wrapper = param_wrapper.get(1).unwrap().as_str();
for cap in RE_POWERSHELL_ARGS.captures_iter(param_wrapper) {
let typ = cap
.get(1)
.map(|x| x.as_str().to_string())
.unwrap_or("string".to_string());
let name = cap.get(2).unwrap().as_str().to_string();
let default = cap
.get(3)
.or(cap.get(4))
.map(|x| json!(x.as_str().to_string()));
let params = split_pwsh_args(param_wrapper);
for param in params {
if let Some(cap) = RE_POWERSHELL_ARGS.captures(param) {
let typ = cap.get(1).map(|x| x.as_str().to_string());
let name = cap.get(2).unwrap().as_str().to_string();
args.push(Arg {
name: name,
typ: match typ.as_str() {
"string" => Typ::Str(None),
"int" | "long" => Typ::Int,
"decimal" | "double" | "single" => Typ::Float,
"datetime" | "DateTime" => Typ::Datetime,
_ => Typ::Str(None),
},
default: default.clone(),
otyp: None,
has_default: default.is_some(),
oidx: None,
});
let mut parsed_typ = if let Some(typ) = typ {
match typ.as_str() {
"string" => Some(Typ::Str(None)),
"int" | "long" => Some(Typ::Int),
"decimal" | "double" | "single" => Some(Typ::Float),
"datetime" | "DateTime" => Some(Typ::Datetime),
_ => None,
}
} else {
None
};
let default = if let Some(x) = cap.get(3) {
Some(json!(x.as_str().to_string()))
} else if let Some(x) = cap.get(4) {
if parsed_typ.is_none() {
if x.as_str().parse::<i64>().is_ok() {
parsed_typ = Some(Typ::Int);
} else if x.as_str().parse::<f64>().is_ok() {
parsed_typ = Some(Typ::Float);
}
}
serde_json::Number::from_str(x.as_str())
.ok()
.map(serde_json::Value::Number)
} else {
None
};
args.push(Arg {
name: name,
typ: parsed_typ.unwrap_or(Typ::Str(None)),
default: default.clone(),
otyp: None,
has_default: default.is_some(),
oidx: None,
});
}
}
}
Ok(Some(args))
@@ -192,4 +250,77 @@ non_required="${5:-}"
Ok(())
}
#[test]
fn test_parse_powershell_sig() -> anyhow::Result<()> {
let code = r#"param($Msg, [string]$Msg2, $Dflt = "default value, with comma", [int]$Nb = 3 , $Nb2 = 5.0, $Nb3 = 5, $Wahoo = $env:WAHOO)"#;
assert_eq!(
parse_powershell_sig(code)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![
Arg {
otyp: None,
name: "Msg".to_string(),
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None
},
Arg {
otyp: None,
name: "Msg2".to_string(),
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None
},
Arg {
otyp: None,
name: "Dflt".to_string(),
typ: Typ::Str(None),
default: Some(json!("default value, with comma")),
has_default: true,
oidx: None
},
Arg {
otyp: None,
name: "Nb".to_string(),
typ: Typ::Int,
default: Some(json!(3)),
has_default: true,
oidx: None
},
Arg {
otyp: None,
name: "Nb2".to_string(),
typ: Typ::Float,
default: Some(json!(5.0)),
has_default: true,
oidx: None
},
Arg {
otyp: None,
name: "Nb3".to_string(),
typ: Typ::Int,
default: Some(json!(5)),
has_default: true,
oidx: None
},
Arg {
otyp: None,
name: "Wahoo".to_string(),
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None
}
],
no_main_func: None,
has_preprocessor: None
}
);
Ok(())
}
}
+4 -4
View File
@@ -72,7 +72,7 @@
"windmill-parser-wasm-go": "^1.429.0",
"windmill-parser-wasm-php": "^1.429.0",
"windmill-parser-wasm-py": "^1.429.0",
"windmill-parser-wasm-regex": "^1.429.0",
"windmill-parser-wasm-regex": "^1.435.2",
"windmill-parser-wasm-rust": "^1.429.0",
"windmill-parser-wasm-ts": "^1.429.0",
"windmill-parser-wasm-yaml": "^1.429.0",
@@ -13660,9 +13660,9 @@
"integrity": "sha512-cqc+tblQVHVrc8wNA4esVYD1Dv59XQJ4mHXFFPa8Lx5UjXv7FO/0VQxyQuRyXaP/V6J6DDy0oeN107eFNLxrBg=="
},
"node_modules/windmill-parser-wasm-regex": {
"version": "1.429.0",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.429.0.tgz",
"integrity": "sha512-rjgrgSYjEBU2+RB6ffFR+nmvEJdiqVKYiwugzHQE+VgVTYMJ0jLBE370n5dBjDj5KPsF+Sfmj6DIUK69uu9wSA=="
"version": "1.435.2",
"resolved": "https://registry.npmjs.org/windmill-parser-wasm-regex/-/windmill-parser-wasm-regex-1.435.2.tgz",
"integrity": "sha512-kQShKPNjXok8jV7b7llfvKhypHfqePwiKgTHm8MlzBt4BZC87xrQ7TH0eS9h7OSK9Q98H9fIiUr2AbN8zTCraA=="
},
"node_modules/windmill-parser-wasm-rust": {
"version": "1.429.0",
+2 -2
View File
@@ -128,8 +128,8 @@
"ol": "^7.4.0",
"openai": "^4.57.2",
"p-limit": "^6.1.0",
"pdfjs-dist": "4.8.69",
"panzoom": "^9.4.3",
"pdfjs-dist": "4.8.69",
"quill": "^1.3.7",
"rfc4648": "^1.5.3",
"svelte-carousel": "^1.0.25",
@@ -145,7 +145,7 @@
"windmill-parser-wasm-go": "^1.429.0",
"windmill-parser-wasm-php": "^1.429.0",
"windmill-parser-wasm-py": "^1.429.0",
"windmill-parser-wasm-regex": "^1.429.0",
"windmill-parser-wasm-regex": "^1.435.2",
"windmill-parser-wasm-rust": "^1.429.0",
"windmill-parser-wasm-ts": "^1.429.0",
"windmill-parser-wasm-yaml": "^1.429.0",