use serde_json::Value;
use std::fmt;
use std::sync::Arc;
use crate::consts::{NOT_SUPPORTED, STRUCTS};
pub type BeforeTransform = Arc<dyn Fn(Value, &ResolvedOptions) -> Value + Send + Sync>;
pub type AfterTransform = Arc<dyn Fn(Value, &ResolvedOptions) -> Value + Send + Sync>;
pub type PatternPropertiesHandler = Arc<dyn Fn(Value) -> Value + Send + Sync>;
#[derive(Clone, Default)]
pub struct Options {
pub date_to_date_time: Option<bool>,
pub clone_schema: Option<bool>,
pub support_pattern_properties: Option<bool>,
pub keep_not_supported: Option<Vec<String>>,
pub strict_mode: Option<bool>,
pub remove_read_only: Option<bool>,
pub remove_write_only: Option<bool>,
pub pattern_properties_handler: Option<PatternPropertiesHandler>,
pub definition_keywords: Option<Vec<String>>,
pub before_transform: Option<BeforeTransform>,
pub after_transform: Option<AfterTransform>,
}
impl Options {
pub fn new() -> Self {
Self::default()
}
pub fn date_to_date_time(mut self, value: bool) -> Self {
self.date_to_date_time = Some(value);
self
}
pub fn clone_schema(mut self, value: bool) -> Self {
self.clone_schema = Some(value);
self
}
pub fn support_pattern_properties(mut self, value: bool) -> Self {
self.support_pattern_properties = Some(value);
self
}
pub fn keep_not_supported(mut self, value: Vec<String>) -> Self {
self.keep_not_supported = Some(value);
self
}
pub fn strict_mode(mut self, value: bool) -> Self {
self.strict_mode = Some(value);
self
}
pub fn remove_read_only(mut self, value: bool) -> Self {
self.remove_read_only = Some(value);
self
}
pub fn remove_write_only(mut self, value: bool) -> Self {
self.remove_write_only = Some(value);
self
}
pub fn definition_keywords(mut self, value: Vec<String>) -> Self {
self.definition_keywords = Some(value);
self
}
pub fn pattern_properties_handler<F>(mut self, handler: F) -> Self
where
F: Fn(Value) -> Value + Send + Sync + 'static,
{
self.pattern_properties_handler = Some(Arc::new(handler));
self
}
pub fn before_transform<F>(mut self, hook: F) -> Self
where
F: Fn(Value, &ResolvedOptions) -> Value + Send + Sync + 'static,
{
self.before_transform = Some(Arc::new(hook));
self
}
pub fn after_transform<F>(mut self, hook: F) -> Self
where
F: Fn(Value, &ResolvedOptions) -> Value + Send + Sync + 'static,
{
self.after_transform = Some(Arc::new(hook));
self
}
}
impl fmt::Debug for Options {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Options")
.field("date_to_date_time", &self.date_to_date_time)
.field("clone_schema", &self.clone_schema)
.field(
"support_pattern_properties",
&self.support_pattern_properties,
)
.field("keep_not_supported", &self.keep_not_supported)
.field("strict_mode", &self.strict_mode)
.field("remove_read_only", &self.remove_read_only)
.field("remove_write_only", &self.remove_write_only)
.field(
"pattern_properties_handler",
&closure_field(self.pattern_properties_handler.is_some()),
)
.field("definition_keywords", &self.definition_keywords)
.field(
"before_transform",
&closure_field(self.before_transform.is_some()),
)
.field(
"after_transform",
&closure_field(self.after_transform.is_some()),
)
.finish()
}
}
fn closure_field(set: bool) -> &'static str {
if set {
"Some(<closure>)"
} else {
"None"
}
}
#[derive(Clone)]
pub struct ResolvedOptions {
pub(crate) date_to_date_time: bool,
pub(crate) support_pattern_properties: bool,
pub(crate) strict_mode: bool,
pub(crate) definition_keywords: Vec<String>,
pub(crate) pattern_properties_handler: Option<PatternPropertiesHandler>,
pub(crate) before_transform: Option<BeforeTransform>,
pub(crate) after_transform: Option<AfterTransform>,
pub(crate) remove_props: Vec<&'static str>,
pub(crate) not_supported: Vec<&'static str>,
}
pub(crate) fn resolve_options(options: &Options) -> ResolvedOptions {
let date_to_date_time = options.date_to_date_time.unwrap_or(false);
let support_pattern_properties = options.support_pattern_properties.unwrap_or(false);
let keep_not_supported = options.keep_not_supported.clone().unwrap_or_default();
let definition_keywords = options.definition_keywords.clone().unwrap_or_default();
let strict_mode = options.strict_mode.unwrap_or(true);
let mut remove_props = Vec::new();
if options.remove_read_only.unwrap_or(false) {
remove_props.push("readOnly");
}
if options.remove_write_only.unwrap_or(false) {
remove_props.push("writeOnly");
}
let not_supported: Vec<&'static str> = NOT_SUPPORTED
.iter()
.copied()
.filter(|kw| !keep_not_supported.iter().any(|k| k == kw))
.collect();
ResolvedOptions {
date_to_date_time,
support_pattern_properties,
strict_mode,
definition_keywords,
pattern_properties_handler: options.pattern_properties_handler.clone(),
before_transform: options.before_transform.clone(),
after_transform: options.after_transform.clone(),
remove_props,
not_supported,
}
}
impl ResolvedOptions {
pub(crate) const STRUCTS: &'static [&'static str] = STRUCTS;
pub fn date_to_date_time(&self) -> bool {
self.date_to_date_time
}
pub fn support_pattern_properties(&self) -> bool {
self.support_pattern_properties
}
pub fn strict_mode(&self) -> bool {
self.strict_mode
}
pub fn definition_keywords(&self) -> &[String] {
&self.definition_keywords
}
}
impl fmt::Debug for ResolvedOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ResolvedOptions")
.field("date_to_date_time", &self.date_to_date_time)
.field(
"support_pattern_properties",
&self.support_pattern_properties,
)
.field("strict_mode", &self.strict_mode)
.field("definition_keywords", &self.definition_keywords)
.field(
"pattern_properties_handler",
&closure_field(self.pattern_properties_handler.is_some()),
)
.field(
"before_transform",
&closure_field(self.before_transform.is_some()),
)
.field(
"after_transform",
&closure_field(self.after_transform.is_some()),
)
.field("remove_props", &self.remove_props)
.field("not_supported", &self.not_supported)
.finish()
}
}