move openapi to openapi module
This commit is contained in:
parent
9534daf4f0
commit
c4ceb92e11
@ -18,7 +18,7 @@ pub struct World {
|
|||||||
pub exports: Vec<Interface>,
|
pub exports: Vec<Interface>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight, derive_setters::Setters)]
|
||||||
pub struct Interface {
|
pub struct Interface {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub records: BTreeSet<Record>,
|
pub records: BTreeSet<Record>,
|
||||||
@ -42,6 +42,7 @@ impl Ord for Interface {
|
|||||||
pub struct Record {
|
pub struct Record {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub fields: BTreeSet<Field>,
|
pub fields: BTreeSet<Field>,
|
||||||
|
pub added_fields: BTreeSet<Field>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Record {
|
impl PartialOrd for Record {
|
||||||
@ -84,7 +85,7 @@ pub struct Parameter {
|
|||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub field_type: String,
|
pub field_type: WitType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Field {
|
impl PartialOrd for Field {
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
use std::collections::BTreeSet;
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use tailcall_valid::{Valid, Validator};
|
use tailcall_valid::{Valid, Validator};
|
||||||
use crate::config::schema_document::{SchemaDocument, Field, Interface, Record};
|
use crate::config::config::{Config, Field, Interface, Record};
|
||||||
use crate::config::wit_types::WitType;
|
use crate::config::wit_types::WitType;
|
||||||
use crate::merge_right::MergeRight;
|
use crate::merge_right::MergeRight;
|
||||||
use crate::tryfold::TryFold;
|
use crate::tryfold::TryFold;
|
||||||
|
|
||||||
pub fn fix_args(config: SchemaDocument) -> Valid<SchemaDocument, anyhow::Error, anyhow::Error> {
|
pub fn fix_args(config: Config) -> Valid<Config, anyhow::Error, anyhow::Error> {
|
||||||
Valid::succeed(config)
|
Valid::succeed(config)
|
||||||
.and_then(|mut config| {
|
.and_then(|mut config| {
|
||||||
Valid::from_iter(config.interfaces.iter().cloned().collect::<Vec<_>>(), |mut interface| {
|
Valid::from_iter(config.interfaces.iter().cloned().collect::<Vec<_>>(), |mut interface| {
|
||||||
@ -94,8 +93,8 @@ interface types {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn fix_field<'a>() -> TryFold<'a, (&'a SchemaDocument, &'a Interface, &'a Record, &'a Field, &'a WitType), Field, anyhow::Error> {
|
fn fix_field<'a>() -> TryFold<'a, (&'a Config, &'a Interface, &'a Record, &'a Field, &'a WitType), Field, anyhow::Error> {
|
||||||
TryFold::<(&SchemaDocument, &Interface, &Record, &Field, &WitType), Field, anyhow::Error>::new(move |(config, interface, rec, field, wit), mut o| {
|
TryFold::<(&Config, &Interface, &Record, &Field, &WitType), Field, anyhow::Error>::new(move |(config, interface, rec, field, wit), o| {
|
||||||
match &wit {
|
match &wit {
|
||||||
WitType::Option(x) => {
|
WitType::Option(x) => {
|
||||||
return fix_field().try_fold(&(*config, *interface, *rec, *field, x), o);
|
return fix_field().try_fold(&(*config, *interface, *rec, *field, x), o);
|
||||||
@ -119,7 +118,7 @@ fn fix_field<'a>() -> TryFold<'a, (&'a SchemaDocument, &'a Interface, &'a Record
|
|||||||
WitType::Tuple(x) => {
|
WitType::Tuple(x) => {
|
||||||
// TODO: Fix the possible conflicts here
|
// TODO: Fix the possible conflicts here
|
||||||
return Valid::from_iter(x.iter(), |x| fix_field().try_fold(&(*config, *interface, *rec, *field, x), o.clone()))
|
return Valid::from_iter(x.iter(), |x| fix_field().try_fold(&(*config, *interface, *rec, *field, x), o.clone()))
|
||||||
.and_then(|v| Valid::succeed(v.into_iter().fold((*field).clone(), |mut a, b| {
|
.and_then(|v| Valid::succeed(v.into_iter().fold((*field).clone(), |a, b| {
|
||||||
a.merge_right(b)
|
a.merge_right(b)
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use tailcall_valid::{Valid, Validator};
|
use tailcall_valid::{Valid, Validator};
|
||||||
use crate::config::schema_document::{SchemaDocument, Field, Interface, Record};
|
|
||||||
use crate::config::wit_types::WitType;
|
|
||||||
use crate::openapi_spec::{OpenApiSpec, Resolved};
|
|
||||||
|
|
||||||
pub fn handle_types(mut config: SchemaDocument, spec: &OpenApiSpec<Resolved>) -> Valid<SchemaDocument, Error, Error> {
|
use crate::config::config::{Config, Field, Interface, Record};
|
||||||
|
use crate::config::wit_types::WitType;
|
||||||
|
use crate::openapi::openapi_spec::{OpenApiSpec, Resolved};
|
||||||
|
|
||||||
|
pub fn handle_types(mut config: Config, spec: &OpenApiSpec<Resolved>) -> Valid<Config, Error, Error> {
|
||||||
let mut generated_records = BTreeSet::new();
|
let mut generated_records = BTreeSet::new();
|
||||||
|
|
||||||
fn process_wit_type(
|
fn process_wit_type(
|
||||||
@ -60,7 +62,7 @@ pub fn handle_types(mut config: SchemaDocument, spec: &OpenApiSpec<Resolved>) ->
|
|||||||
.and_then(|schemas| {
|
.and_then(|schemas| {
|
||||||
Valid::from_iter(schemas.iter(), |(record_name, schema)| {
|
Valid::from_iter(schemas.iter(), |(record_name, schema)| {
|
||||||
Valid::from_option(schema.type_.as_ref(), anyhow!("Type is required"))
|
Valid::from_option(schema.type_.as_ref(), anyhow!("Type is required"))
|
||||||
.and_then(|type_| {
|
.and_then(|_type_| {
|
||||||
Valid::from_option(schema.properties.as_ref(), anyhow!("Properties are required"))
|
Valid::from_option(schema.properties.as_ref(), anyhow!("Properties are required"))
|
||||||
.and_then(|properties| {
|
.and_then(|properties| {
|
||||||
Valid::from_iter(properties, |(field_name, field_schema)| {
|
Valid::from_iter(properties, |(field_name, field_schema)| {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
pub mod schema_document;
|
pub mod config;
|
||||||
pub mod wit_types;
|
pub mod wit_types;
|
||||||
pub mod to_wit;
|
pub mod to_wit;
|
||||||
pub mod fixargs;
|
pub mod fixargs;
|
||||||
pub mod handle_files;
|
pub mod handle_files;
|
||||||
pub mod config;
|
|
||||||
pub mod to_config;
|
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
use std::collections::BTreeSet;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use macros::MergeRight;
|
|
||||||
use crate::config::wit_types::WitType;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct SchemaDocument {
|
|
||||||
pub package: String,
|
|
||||||
pub interfaces: BTreeSet<Interface>,
|
|
||||||
pub world: World,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct World {
|
|
||||||
pub name: String,
|
|
||||||
pub uses: Vec<UseStatement>,
|
|
||||||
pub imports: Vec<Interface>,
|
|
||||||
pub exports: Vec<Interface>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight, derive_setters::Setters)]
|
|
||||||
pub struct Interface {
|
|
||||||
pub name: String,
|
|
||||||
pub records: BTreeSet<Record>,
|
|
||||||
pub uses: Vec<UseStatement>,
|
|
||||||
pub functions: Vec<Function>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Interface {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.name.cmp(&other.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Interface {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.name.cmp(&other.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct Record {
|
|
||||||
pub name: String,
|
|
||||||
pub fields: BTreeSet<Field>,
|
|
||||||
pub added_fields: BTreeSet<Field>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Record {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.name.cmp(&other.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Record {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.name.cmp(&other.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct UseStatement {
|
|
||||||
pub name: String,
|
|
||||||
pub items: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct Function {
|
|
||||||
pub name: String,
|
|
||||||
pub parameters: Vec<Parameter>,
|
|
||||||
pub return_type: ReturnTy,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct ReturnTy {
|
|
||||||
pub return_type: String,
|
|
||||||
pub error_type: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct Parameter {
|
|
||||||
pub name: String,
|
|
||||||
pub parameter_type: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, MergeRight)]
|
|
||||||
pub struct Field {
|
|
||||||
pub name: String,
|
|
||||||
pub field_type: WitType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Field {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.name.cmp(&other.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Field {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.name.cmp(&other.name)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
use tailcall_valid::Valid;
|
|
||||||
use crate::config::config::Config;
|
|
||||||
use crate::config::schema_document::SchemaDocument;
|
|
||||||
|
|
||||||
impl SchemaDocument {
|
|
||||||
pub fn to_config(&self) -> Valid<Config, anyhow::Error, anyhow::Error> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +1,8 @@
|
|||||||
use crate::config::schema_document::{SchemaDocument, Field, Function, Interface, Parameter, Record, ReturnTy, UseStatement, World};
|
use crate::config::config::{Config, Field, Function, Interface, Parameter, Record, ReturnTy, UseStatement, World};
|
||||||
use crate::config::wit_types::WitType;
|
use crate::config::wit_types::WitType;
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub trait ToWit {
|
|
||||||
fn to_wit(&self) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref RESERVED_WORDS: HashSet<&'static str> = {
|
static ref RESERVED_WORDS: HashSet<&'static str> = {
|
||||||
let mut set = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
@ -41,7 +37,7 @@ fn generate_wit_name(name: &str) -> String {
|
|||||||
final_name
|
final_name
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchemaDocument {
|
impl Config {
|
||||||
pub fn to_wit(&self) -> String {
|
pub fn to_wit(&self) -> String {
|
||||||
let package = format!("package {};\n", generate_wit_name(&self.package));
|
let package = format!("package {};\n", generate_wit_name(&self.package));
|
||||||
let world = self.world.to_wit();
|
let world = self.world.to_wit();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tailcall_valid::{Valid, Validator};
|
use tailcall_valid::{Valid, Validator};
|
||||||
|
|
||||||
use crate::openapi_spec::{OpenApiSpec, Resolved, Schema};
|
use crate::openapi::openapi_spec::{OpenApiSpec, Resolved, Schema};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, strum_macros::Display, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, strum_macros::Display, Serialize, Deserialize)]
|
||||||
pub enum WitType {
|
pub enum WitType {
|
||||||
@ -102,7 +102,7 @@ impl WitType {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::openapi_spec::Components;
|
use crate::openapi::openapi_spec::Components;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
16
src/main.rs
16
src/main.rs
@ -1,6 +1,11 @@
|
|||||||
|
use anyhow::{bail, Result};
|
||||||
|
use convert_case::{Case, Casing};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use crate::value::value;
|
||||||
|
|
||||||
mod value;
|
mod value;
|
||||||
mod openapi;
|
mod openapi;
|
||||||
mod openapi_spec;
|
|
||||||
mod config;
|
mod config;
|
||||||
mod transformer;
|
mod transformer;
|
||||||
mod transform;
|
mod transform;
|
||||||
@ -8,11 +13,6 @@ mod tryfold;
|
|||||||
mod merge_right;
|
mod merge_right;
|
||||||
mod primitive;
|
mod primitive;
|
||||||
|
|
||||||
use serde_json::{Map, Value};
|
|
||||||
use anyhow::{Result, bail};
|
|
||||||
use convert_case::{Casing, Case};
|
|
||||||
use crate::value::value;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct WIPValue(Value);
|
pub struct WIPValue(Value);
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ impl WIPValue {
|
|||||||
if let Value::Object(schemas_map) = schemas {
|
if let Value::Object(schemas_map) = schemas {
|
||||||
wip.push_str("interface types {\n");
|
wip.push_str("interface types {\n");
|
||||||
for (name, schema) in schemas_map {
|
for (name, schema) in schemas_map {
|
||||||
let record = Self::process_schema(name, schema, schemas_map)?;
|
let record = Self::process_schema(name, schema)?;
|
||||||
wip.push_str(&record);
|
wip.push_str(&record);
|
||||||
}
|
}
|
||||||
wip.push_str("}\n\n");
|
wip.push_str("}\n\n");
|
||||||
@ -57,7 +57,7 @@ impl WIPValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_schema(name: &str, schema: &Value, schemas_map: &Map<String, Value>) -> Result<String> {
|
fn process_schema(name: &str, schema: &Value) -> Result<String> {
|
||||||
if let Value::Object(schema_map) = schema {
|
if let Value::Object(schema_map) = schema {
|
||||||
let mut record = format!(" record {} {{\n", name.from_case(Case::Camel).to_case(Case::Kebab));
|
let mut record = format!(" record {} {{\n", name.from_case(Case::Camel).to_case(Case::Kebab));
|
||||||
if let Some(properties) = schema_map.get("properties") {
|
if let Some(properties) = schema_map.get("properties") {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
|
|
||||||
use crate::config::wit_types::WitType;
|
use crate::config::wit_types::WitType;
|
||||||
|
|
||||||
pub trait MergeRight {
|
pub trait MergeRight {
|
||||||
@ -87,8 +88,6 @@ impl MergeRight for WitType {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
|
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
use super::MergeRight;
|
use super::MergeRight;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
|
2
src/openapi/mod.rs
Normal file
2
src/openapi/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod openapi_spec;
|
||||||
|
pub mod openapi;
|
@ -1,25 +1,8 @@
|
|||||||
use anyhow::Error;
|
|
||||||
use tailcall_valid::{Valid, Validator};
|
|
||||||
|
|
||||||
use crate::config::schema_document::SchemaDocument;
|
|
||||||
use crate::config::fixargs::fix_args;
|
|
||||||
use crate::config::handle_files::handle_types;
|
|
||||||
use crate::openapi_spec::OpenApiSpec;
|
|
||||||
|
|
||||||
fn to_config(spec: OpenApiSpec) -> Valid<SchemaDocument, Error, Error> {
|
|
||||||
let spec = spec.into_resolved();
|
|
||||||
Valid::succeed(SchemaDocument::default())
|
|
||||||
.and_then(|config| handle_types(config, &spec))
|
|
||||||
.and_then(|config| fix_args(config))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod t {
|
mod t {
|
||||||
use tailcall_valid::Validator;
|
use tailcall_valid::Validator;
|
||||||
use wit_parser::Resolve;
|
use wit_parser::Resolve;
|
||||||
|
use crate::openapi::openapi_spec::OpenApiSpec;
|
||||||
use crate::openapi::to_config;
|
|
||||||
use crate::openapi_spec::OpenApiSpec;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tp() {
|
fn tp() {
|
||||||
@ -27,7 +10,7 @@ mod t {
|
|||||||
let content = std::fs::read_to_string(path).unwrap();
|
let content = std::fs::read_to_string(path).unwrap();
|
||||||
|
|
||||||
let y: OpenApiSpec = serde_yaml::from_str(&content).unwrap();
|
let y: OpenApiSpec = serde_yaml::from_str(&content).unwrap();
|
||||||
let mut res = to_config(y).to_result();
|
let mut res = y.into_config().to_result();
|
||||||
match res.as_mut() {
|
match res.as_mut() {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
// println!("{}", serde_json::to_string_pretty(v).unwrap());
|
// println!("{}", serde_json::to_string_pretty(v).unwrap());
|
@ -6,7 +6,7 @@ use schemars::JsonSchema;
|
|||||||
use tailcall_valid::{Valid, Validator};
|
use tailcall_valid::{Valid, Validator};
|
||||||
use crate::config::fixargs::fix_args;
|
use crate::config::fixargs::fix_args;
|
||||||
use crate::config::handle_files::handle_types;
|
use crate::config::handle_files::handle_types;
|
||||||
use crate::config::schema_document::SchemaDocument;
|
use crate::config::config::Config;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Unresolved;
|
pub struct Unresolved;
|
||||||
@ -247,15 +247,15 @@ pub struct XML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OpenApiSpec<Resolved> {
|
impl OpenApiSpec<Resolved> {
|
||||||
fn to_config(&self) -> Valid<SchemaDocument, Error, Error> {
|
pub fn to_config(&self) -> Valid<Config, Error, Error> {
|
||||||
Valid::succeed(SchemaDocument::default())
|
Valid::succeed(Config::default())
|
||||||
.and_then(|config| handle_types(config, &self))
|
.and_then(|config| handle_types(config, &self))
|
||||||
.and_then(|config| fix_args(config))
|
.and_then(|config| fix_args(config))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenApiSpec<Unresolved> {
|
impl OpenApiSpec<Unresolved> {
|
||||||
fn into_config(self) -> Valid<SchemaDocument, Error, Error> {
|
pub fn into_config(self) -> Valid<Config, Error, Error> {
|
||||||
self.into_resolved()
|
self.into_resolved()
|
||||||
.to_config()
|
.to_config()
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user