use serde::Serialize;
pub mod build;
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct RouteCatalogSnapshot {
pub rule_sets: Vec<RuleSetView>,
pub fallback_respond_dir: Option<String>,
pub file_tree: Option<FileTreeView>,
pub script_routes: Vec<ScriptRouteView>,
}
impl RouteCatalogSnapshot {
pub fn empty() -> Self {
Self {
rule_sets: Vec::new(),
fallback_respond_dir: None,
file_tree: None,
script_routes: Vec::new(),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct RuleSetView {
pub index: usize,
pub source_path: String,
pub url_path_prefix: Option<String>,
pub respond_dir_prefix: Option<String>,
pub rules: Vec<RuleView>,
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct RuleView {
pub index: usize,
pub when: WhenView,
pub respond: RespondView,
}
impl RuleView {
pub fn summary(&self) -> String {
self.when.summary()
}
}
#[derive(Clone, Debug, Default, Serialize)]
#[non_exhaustive]
pub struct WhenView {
pub url_path: Option<UrlPathView>,
pub method: Option<String>,
pub has_header_conditions: bool,
pub has_body_conditions: bool,
}
impl WhenView {
pub fn summary(&self) -> String {
let mut parts: Vec<String> = Vec::new();
if let Some(method) = self.method.as_deref() {
parts.push(method.to_owned());
}
if let Some(url) = self.url_path.as_ref() {
parts.push(url.summary());
}
if self.has_header_conditions {
parts.push("+headers".to_owned());
}
if self.has_body_conditions {
parts.push("+body".to_owned());
}
if parts.is_empty() {
"(matches everything)".to_owned()
} else {
parts.join(" ")
}
}
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct UrlPathView {
pub value: String,
pub op: String,
}
impl UrlPathView {
pub fn summary(&self) -> String {
format!("{} {}", self.op, self.value)
}
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub enum RespondView {
File { path: String, csv_records_key: Option<String> },
Text { text: String, status: Option<u16> },
Status { code: u16 },
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct RouteMatchView {
pub matched: Option<MatchedRule>,
pub considered: Vec<MatchConsidered>,
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct MatchedRule {
pub rule_set_index: usize,
pub rule_index: usize,
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct MatchConsidered {
pub rule_set_index: usize,
pub rule_index: usize,
pub reason: String,
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct RouteValidation {
pub ok: bool,
pub issues: Vec<RouteValidationIssue>,
}
impl RouteValidation {
pub fn ok() -> Self {
Self {
ok: true,
issues: Vec::new(),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct RouteValidationIssue {
pub rule_set_index: usize,
pub rule_index: Option<usize>,
pub severity: ValidationSeverity,
pub message: String,
}
#[derive(Clone, Copy, Debug, Serialize)]
pub enum ValidationSeverity {
Error,
Warning,
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct FileTreeView {
pub root_path: String,
pub entries: Vec<FileNodeView>,
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct FileNodeView {
pub name: String,
pub path: String,
pub kind: FileNodeKind,
pub route_hint: Option<String>,
pub children: Option<Vec<FileNodeView>>,
}
#[derive(Clone, Copy, Debug, Serialize)]
pub enum FileNodeKind {
File,
Directory,
}
#[derive(Clone, Debug, Serialize)]
#[non_exhaustive]
pub struct ScriptRouteView {
pub index: usize,
pub source_file: String,
pub display_name: String,
}