diff --git a/qbittorrent-web-api-gen/src/parser/group/description.rs b/qbittorrent-web-api-gen/src/parser/group/description.rs index c47d531..395973b 100644 --- a/qbittorrent-web-api-gen/src/parser/group/description.rs +++ b/qbittorrent-web-api-gen/src/parser/group/description.rs @@ -1,17 +1,20 @@ use crate::md_parser; -pub fn parse_group_description(content: &[md_parser::MdContent]) -> Option { - let return_desc = content - .iter() - .map(|row| row.inner_value_as_string()) - .collect::>() - .join("\n") - .trim() - .to_string(); +impl md_parser::TokenTree { + pub fn parse_group_description(&self) -> Option { + let return_desc = self + .content + .iter() + .map(|row| row.inner_value_as_string()) + .collect::>() + .join("\n") + .trim() + .to_string(); - if return_desc.is_empty() { - None - } else { - Some(return_desc) + if return_desc.is_empty() { + None + } else { + Some(return_desc) + } } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/description.rs b/qbittorrent-web-api-gen/src/parser/group/method/description.rs index dfeab4e..fb892b8 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/description.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/description.rs @@ -1,35 +1,38 @@ -use crate::md_parser::MdContent; +use crate::md_parser::{self, MdContent}; -pub fn parse_method_description(content: &[MdContent]) -> Option { - let return_desc = content - .iter() - // skip until we get to the "Returns:" text - .skip_while(|row| match row { - MdContent::Asterisk(text) => !text.starts_with("Returns:"), - _ => true, - }) - // there is one space before the table - .skip(2) - .skip_while(|row| match row { - MdContent::Text(text) => !text.is_empty(), - _ => true, - }) - // and there is one space after the table - .skip(1) - // then what is left should be the description - .flat_map(|row| match row { - MdContent::Text(text) => Some(text), - _ => None, - }) - .cloned() - .collect::>() - .join("\n") - .trim() - .to_string(); +impl md_parser::TokenTree { + pub fn parse_method_description(&self) -> Option { + let return_desc = self + .content + .iter() + // skip until we get to the "Returns:" text + .skip_while(|row| match row { + MdContent::Asterisk(text) => !text.starts_with("Returns:"), + _ => true, + }) + // there is one space before the table + .skip(2) + .skip_while(|row| match row { + MdContent::Text(text) => !text.is_empty(), + _ => true, + }) + // and there is one space after the table + .skip(1) + // then what is left should be the description + .flat_map(|row| match row { + MdContent::Text(text) => Some(text), + _ => None, + }) + .cloned() + .collect::>() + .join("\n") + .trim() + .to_string(); - if return_desc.is_empty() { - None - } else { - Some(return_desc) + if return_desc.is_empty() { + None + } else { + Some(return_desc) + } } } diff --git a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs index fe9b399..b920f10 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/mod.rs @@ -2,15 +2,9 @@ mod description; mod return_type; mod url; -use std::collections::HashMap; - use crate::{md_parser, parser::util, types}; - pub use return_type::ReturnType; - -use self::{ - description::parse_method_description, return_type::parse_return_type, url::get_method_url, -}; +use std::collections::HashMap; #[derive(Debug)] pub struct ApiMethod { @@ -61,11 +55,11 @@ impl ApiMethod { fn new(child: &md_parser::TokenTree, name: &str) -> Self { let tables = Tables::from(child); - let method_description = parse_method_description(&child.content); - let return_type = parse_return_type(&child.content); + let method_description = child.parse_method_description(); + let return_type = child.parse_return_type(); // let return_type = tables.return_type().map(|r| ReturnType::new(r)); let parameters = tables.parameters().map(ApiParameters::new); - let method_url = get_method_url(&child.content); + let method_url = child.get_method_url(); ApiMethod { name: name.to_string(), diff --git a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs index 6ff8342..3691c1f 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/return_type.rs @@ -11,81 +11,84 @@ pub struct ReturnType { pub parameters: Vec, } -pub fn parse_return_type(content: &[MdContent]) -> Option { - let table = content - .iter() - // The response is a ... <-- Trying to find this line - // <-- The next line is empty - // Table with the return type <-- And then extract the following type table - .skip_while(|row| match row { - MdContent::Text(text) => !text.starts_with("The response is a"), - _ => true, +impl md_parser::TokenTree { + pub fn parse_return_type(&self) -> Option { + let table = self + .content + .iter() + // The response is a ... <-- Trying to find this line + // <-- The next line is empty + // Table with the return type <-- And then extract the following type table + .skip_while(|row| match row { + MdContent::Text(text) => !text.starts_with("The response is a"), + _ => true, + }) + .find_map(|row| match row { + MdContent::Table(table) => Some(table), + _ => None, + })?; + + let types = self.parse_object_types(); + + let parameters = table + .rows + .iter() + .map(|parameter| ReturnTypeParameter { + name: parameter.columns[0].clone(), + description: parameter.columns[2].clone(), + return_type: types::Type::from( + ¶meter.columns[1], + ¶meter.columns[0], + Some(parameter.columns[2].clone()), + &types, + ) + .unwrap_or_else(|| panic!("Failed to parse type {}", ¶meter.columns[1])), + }) + .collect(); + + Some(ReturnType { + parameters, + is_list: self.is_list(), }) - .find_map(|row| match row { - MdContent::Table(table) => Some(table), - _ => None, - })?; + } - let types = parse_object_types(content); + fn is_list(&self) -> bool { + self.content + .iter() + .find_map(|row| match row { + MdContent::Text(text) if text.starts_with("The response is a") => Some(text), + _ => None, + }) + .map(|found| found.contains("array")) + .unwrap_or_else(|| false) + } - let parameters = table - .rows - .iter() - .map(|parameter| ReturnTypeParameter { - name: parameter.columns[0].clone(), - description: parameter.columns[2].clone(), - return_type: types::Type::from( - ¶meter.columns[1], - ¶meter.columns[0], - Some(parameter.columns[2].clone()), - &types, - ) - .unwrap_or_else(|| panic!("Failed to parse type {}", ¶meter.columns[1])), - }) - .collect(); + pub fn parse_object_types(&self) -> HashMap { + let mut output = HashMap::new(); + let mut content_it = self.content.iter(); - let is_list = content - .iter() - .find_map(|row| match row { - MdContent::Text(text) if text.starts_with("The response is a") => Some(text), - _ => None, - }) - .map(|found| found.contains("array")) - .unwrap_or_else(|| false); + while let Some(entry) = content_it.next() { + if let md_parser::MdContent::Text(content) = entry { + const POSSIBLE_VALUES_OF: &str = "Possible values of "; + if content.contains(POSSIBLE_VALUES_OF) { + // is empty + content_it.next(); + if let Some(md_parser::MdContent::Table(table)) = content_it.next() { + let enum_types = to_type_descriptions(table); - Some(ReturnType { - parameters, - is_list, - }) -} + let name = content + .trim_start_matches(POSSIBLE_VALUES_OF) + .replace('`', "") + .replace(':', ""); -pub fn parse_object_types( - content: &[md_parser::MdContent], -) -> HashMap { - let mut output = HashMap::new(); - let mut content_it = content.iter(); - - while let Some(entry) = content_it.next() { - if let md_parser::MdContent::Text(content) = entry { - const POSSIBLE_VALUES_OF: &str = "Possible values of "; - if content.contains(POSSIBLE_VALUES_OF) { - // is empty - content_it.next(); - if let Some(md_parser::MdContent::Table(table)) = content_it.next() { - let enum_types = to_type_descriptions(table); - - let name = content - .trim_start_matches(POSSIBLE_VALUES_OF) - .replace('`', "") - .replace(':', ""); - - output.insert(name, types::TypeDescription { values: enum_types }); + output.insert(name, types::TypeDescription { values: enum_types }); + } } } } - } - output + output + } } fn to_type_descriptions(table: &md_parser::Table) -> Vec { diff --git a/qbittorrent-web-api-gen/src/parser/group/method/url.rs b/qbittorrent-web-api-gen/src/parser/group/method/url.rs index 5358362..1911961 100644 --- a/qbittorrent-web-api-gen/src/parser/group/method/url.rs +++ b/qbittorrent-web-api-gen/src/parser/group/method/url.rs @@ -1,9 +1,11 @@ use crate::{md_parser, parser::util}; -pub fn get_method_url(content: &[md_parser::MdContent]) -> String { - const START: &str = "Name: "; +impl md_parser::TokenTree { + pub fn get_method_url(&self) -> String { + const START: &str = "Name: "; - util::find_content_starts_with(content, START) - .map(|text| text.trim_start_matches(START).trim_matches('`').to_string()) - .expect("Could find method url") + util::find_content_starts_with(&self.content, START) + .map(|text| text.trim_start_matches(START).trim_matches('`').to_string()) + .expect("Could find method url") + } } diff --git a/qbittorrent-web-api-gen/src/parser/group/mod.rs b/qbittorrent-web-api-gen/src/parser/group/mod.rs index b4be43d..df6730d 100644 --- a/qbittorrent-web-api-gen/src/parser/group/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/group/mod.rs @@ -4,7 +4,6 @@ mod url; use crate::md_parser; -use self::{description::parse_group_description, url::get_group_url}; pub use method::*; #[derive(Debug)] @@ -15,25 +14,29 @@ pub struct ApiGroup { pub url: String, } -pub fn parse_api_group(tree: &md_parser::TokenTree) -> ApiGroup { - let methods = tree.children.iter().flat_map(ApiMethod::try_new).collect(); - - let group_description = parse_group_description(&tree.content); - let group_url = get_group_url(&tree.content); - - let name = tree - .title - .clone() - .unwrap() - .to_lowercase() - .trim_end_matches("(experimental)") - .trim() - .replace(' ', "_"); - - ApiGroup { - name, - methods, - description: group_description, - url: group_url, +impl ApiGroup { + pub fn new(tree: &md_parser::TokenTree) -> ApiGroup { + ApiGroup { + name: tree.name(), + methods: tree.methods(), + description: tree.parse_group_description(), + url: tree.get_group_url(), + } + } +} + +impl md_parser::TokenTree { + fn name(&self) -> String { + self.title + .clone() + .unwrap() + .to_lowercase() + .trim_end_matches("(experimental)") + .trim() + .replace(' ', "_") + } + + fn methods(&self) -> Vec { + self.children.iter().flat_map(ApiMethod::try_new).collect() } } diff --git a/qbittorrent-web-api-gen/src/parser/group/url.rs b/qbittorrent-web-api-gen/src/parser/group/url.rs index 993c9b8..b806b8c 100644 --- a/qbittorrent-web-api-gen/src/parser/group/url.rs +++ b/qbittorrent-web-api-gen/src/parser/group/url.rs @@ -2,13 +2,15 @@ use regex::Regex; use crate::{md_parser, parser::util}; -pub fn get_group_url(content: &[md_parser::MdContent]) -> String { - let row = util::find_content_contains(content, "API methods are under") - .expect("Could not find api method"); +impl md_parser::TokenTree { + pub fn get_group_url(&self) -> String { + let row = util::find_content_contains(&self.content, "API methods are under") + .expect("Could not find api method"); - let re = Regex::new(r#"All (?:\w+\s?)+ API methods are under "(\w+)", e.g."#) - .expect("Failed to create regex"); + let re = Regex::new(r#"All (?:\w+\s?)+ API methods are under "(\w+)", e.g."#) + .expect("Failed to create regex"); - let res = re.captures(&row).expect("Failed find capture"); - res[1].to_string() + let res = re.captures(&row).expect("Failed find capture"); + res[1].to_string() + } } diff --git a/qbittorrent-web-api-gen/src/parser/mod.rs b/qbittorrent-web-api-gen/src/parser/mod.rs index 414d179..ec3b78a 100644 --- a/qbittorrent-web-api-gen/src/parser/mod.rs +++ b/qbittorrent-web-api-gen/src/parser/mod.rs @@ -1,7 +1,5 @@ use crate::{md_parser, types}; -use self::group::parse_api_group; - mod group; mod util; @@ -19,10 +17,7 @@ pub fn parse_api_groups(token_tree: md_parser::TokenTree) -> Vec { } pub fn parse_groups(trees: Vec) -> Vec { - trees - .into_iter() - .map(|tree| parse_api_group(&tree)) - .collect() + trees.iter().map(ApiGroup::new).collect() } fn extract_relevant_parts(tree: md_parser::TokenTree) -> Vec {