use schemars::JsonSchema;
use serde::Deserialize;
use super::de::{Located, Loose, Map, UnknownKeys};
type JsonMap = serde_json::Map<String, serde_json::Value>;
type Raw = Option<Located<serde_json::Value>>;
#[derive(Deserialize, JsonSchema)]
#[serde(transparent)]
#[schemars(title = "DRE Sets")]
pub struct SetsFile(pub Map<Loose<Option<SetConfig>>>);
#[derive(Deserialize, JsonSchema)]
#[schemars(rename = "set", deny_unknown_fields)]
pub struct SetConfig {
pub profile: Option<Loose<String>>,
#[serde(default)]
#[schemars(schema_with = "any_map")]
pub vars: Option<Loose<JsonMap>>,
pub locale: Option<Loose<String>>,
}
#[derive(Deserialize, JsonSchema)]
#[serde(transparent)]
#[schemars(title = "DRE timings", extend("propertyNames" = {"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"}))]
pub struct TimingsFile(pub Map<Loose<TimingConfig>>);
#[derive(Deserialize, JsonSchema)]
#[schemars(rename = "timing", deny_unknown_fields)]
pub struct TimingConfig {
#[serde(default)]
#[schemars(with = "String")]
pub cron: Raw,
#[serde(default)]
#[schemars(with = "Every")]
pub every: Raw,
#[serde(default)]
#[schemars(with = "String")]
pub rrule: Raw,
#[serde(default)]
#[schemars(with = "String", regex(pattern = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"))]
pub starting: Raw,
#[serde(default)]
#[schemars(with = "String", regex(pattern = "^[0-9]{2}:[0-9]{2}$"))]
pub at: Raw,
#[serde(default)]
#[schemars(with = "Vec<Date>")]
pub except: Raw,
#[serde(default)]
#[schemars(with = "Vec<Date>")]
pub also: Raw,
pub timezone: Option<Loose<String>>,
#[serde(rename = "$unknown", default)]
#[schemars(skip)]
pub unknown: UnknownKeys,
}
impl TimingConfig {
pub fn block(&self) -> JsonMap {
block([
("cron", &self.cron),
("every", &self.every),
("rrule", &self.rrule),
("starting", &self.starting),
("at", &self.at),
("except", &self.except),
("also", &self.also),
])
}
}
#[derive(Deserialize, JsonSchema)]
#[serde(transparent)]
#[schemars(title = "DRE schedules")]
pub struct SchedulesFile(pub Vec<Located<Loose<ScheduleConfig>>>);
#[derive(Deserialize, JsonSchema)]
#[schemars(rename = "schedule", deny_unknown_fields)]
pub struct ScheduleConfig {
#[schemars(required, regex(pattern = "^[A-Za-z_][A-Za-z0-9_]*$"))]
pub name: Option<Loose<String>>,
pub report: Option<Loose<String>>,
pub set: Option<Loose<String>>,
pub select: Option<Loose<String>>,
#[serde(default)]
#[schemars(schema_with = "any_map")]
pub vars: Option<Loose<JsonMap>>,
#[schemars(regex(pattern = "^[A-Za-z_][A-Za-z0-9_]*$"))]
pub timing: Option<Loose<String>>,
pub timezone: Option<Located<Loose<String>>>,
pub enabled: Option<Loose<bool>>,
#[serde(default)]
#[schemars(with = "String")]
pub cron: Raw,
#[serde(default)]
#[schemars(with = "Every")]
pub every: Raw,
#[serde(default)]
#[schemars(with = "String")]
pub rrule: Raw,
#[serde(default)]
#[schemars(with = "String", regex(pattern = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"))]
pub starting: Raw,
#[serde(default)]
#[schemars(with = "String", regex(pattern = "^[0-9]{2}:[0-9]{2}$"))]
pub at: Raw,
#[serde(default)]
#[schemars(with = "Vec<Date>")]
pub except: Raw,
#[serde(default)]
#[schemars(with = "Vec<Date>")]
pub also: Raw,
#[serde(rename = "$unknown", default)]
#[schemars(skip)]
pub unknown: UnknownKeys,
}
impl ScheduleConfig {
pub fn timing_keys(&self) -> Vec<&'static str> {
let mut keys: Vec<(&'static str, (usize, usize))> = [
("cron", &self.cron),
("every", &self.every),
("rrule", &self.rrule),
("starting", &self.starting),
("at", &self.at),
("except", &self.except),
("also", &self.also),
]
.into_iter()
.filter_map(|(k, v)| v.as_ref().map(|v| (k, (v.line, v.column))))
.collect();
if let Some(tz) = &self.timezone {
keys.push(("timezone", (tz.line, tz.column)));
}
keys.sort_by_key(|(_, at)| *at);
keys.into_iter().map(|(k, _)| k).collect()
}
pub fn block(&self) -> JsonMap {
block([
("cron", &self.cron),
("every", &self.every),
("rrule", &self.rrule),
("starting", &self.starting),
("at", &self.at),
("except", &self.except),
("also", &self.also),
])
}
}
fn block<const N: usize>(keys: [(&str, &Raw); N]) -> JsonMap {
let mut written: Vec<(&str, &Located<serde_json::Value>)> = keys
.into_iter()
.filter_map(|(k, v)| Some((k, v.as_ref()?)))
.collect();
written.sort_by_key(|(_, v)| (v.line, v.column));
written
.into_iter()
.map(|(k, v)| (k.to_string(), v.value.clone()))
.collect()
}
#[derive(JsonSchema)]
#[schemars(deny_unknown_fields, inline, extend("minProperties" = 1, "maxProperties" = 1))]
#[allow(dead_code)]
struct Every {
#[schemars(range(min = 1))]
days: Option<u32>,
#[schemars(range(min = 1))]
weeks: Option<u32>,
#[schemars(range(min = 1))]
months: Option<u32>,
}
#[derive(JsonSchema)]
#[schemars(inline)]
#[allow(dead_code)]
struct Date(#[schemars(regex(pattern = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"))] String);
fn any_map(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({"type": "object", "additionalProperties": true})
}