use std::collections::HashMap;
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct RawGrammar {
#[serde(rename = "scopeName")]
pub scope_name: String,
pub name: Option<String>,
#[serde(rename = "fileTypes", default)]
pub file_types: Vec<String>,
#[serde(rename = "firstLineMatch")]
pub first_line_match: Option<String>,
#[serde(default)]
pub patterns: Vec<RawRule>,
#[serde(default)]
pub repository: HashMap<String, RawRule>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct RawRule {
pub include: Option<String>,
#[serde(rename = "match")]
pub match_: Option<String>,
pub name: Option<String>,
pub captures: Option<HashMap<String, RawCapture>>,
pub begin: Option<String>,
#[serde(rename = "beginCaptures")]
pub begin_captures: Option<HashMap<String, RawCapture>>,
pub end: Option<String>,
#[serde(rename = "endCaptures")]
pub end_captures: Option<HashMap<String, RawCapture>>,
#[serde(rename = "while")]
pub while_: Option<String>,
#[serde(rename = "contentName")]
pub content_name: Option<String>,
#[serde(
rename = "applyEndPatternLast",
default,
deserialize_with = "lenient_bool"
)]
pub apply_end_pattern_last: bool,
#[serde(default)]
pub patterns: Vec<RawRule>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct RawCapture {
pub name: Option<String>,
}
impl RawGrammar {
pub fn from_json(source: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(source)
}
}
fn lenient_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
D: serde::Deserializer<'de>,
{
struct LenientBoolVisitor;
impl serde::de::Visitor<'_> for LenientBoolVisitor {
type Value = bool;
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("a boolean, or a truthy/falsy number")
}
fn visit_bool<E>(self, v: bool) -> Result<bool, E> {
Ok(v)
}
fn visit_u64<E>(self, v: u64) -> Result<bool, E> {
Ok(v != 0)
}
fn visit_i64<E>(self, v: i64) -> Result<bool, E> {
Ok(v != 0)
}
fn visit_f64<E>(self, v: f64) -> Result<bool, E> {
Ok(v != 0.0)
}
}
deserializer.deserialize_any(LenientBoolVisitor)
}