Group by function
This commit is contained in:
parent
201ba025f3
commit
aaf3153205
|
@ -7,14 +7,15 @@ use proc_macro2::TokenStream;
|
|||
use quote::{format_ident, quote};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{parser, types, util};
|
||||
use crate::{md_parser, parser, types, util};
|
||||
|
||||
use self::skeleton::{auth_ident, generate_skeleton};
|
||||
|
||||
pub fn generate(ast: &syn::DeriveInput, api_content: &str) -> TokenStream {
|
||||
let ident = &ast.ident;
|
||||
|
||||
let api_groups = parser::parse_api_groups(api_content);
|
||||
let token_tree = md_parser::TokenTreeFactory::create(api_content);
|
||||
let api_groups = parser::parse_api_groups(token_tree);
|
||||
|
||||
let skeleton = generate_skeleton(ident);
|
||||
let groups = generate_groups(api_groups);
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
use crate::md_parser;
|
||||
|
||||
use super::{
|
||||
api_method::parse_api_method, description::parse_group_description, url_parser::get_group_url,
|
||||
ApiGroup,
|
||||
};
|
||||
|
||||
pub fn parse_api_group(tree: md_parser::TokenTree) -> ApiGroup {
|
||||
let methods = tree
|
||||
.children
|
||||
.into_iter()
|
||||
.flat_map(parse_api_method)
|
||||
.collect();
|
||||
|
||||
let group_description = parse_group_description(&tree.content);
|
||||
let group_url = get_group_url(&tree.content);
|
||||
|
||||
let name = tree
|
||||
.title
|
||||
.unwrap()
|
||||
.to_lowercase()
|
||||
.trim_end_matches("(experimental)")
|
||||
.trim()
|
||||
.replace(' ', "_");
|
||||
|
||||
ApiGroup {
|
||||
name,
|
||||
methods,
|
||||
description: group_description,
|
||||
url: group_url,
|
||||
}
|
||||
}
|
17
qbittorrent-web-api-gen/src/parser/group/description.rs
Normal file
17
qbittorrent-web-api-gen/src/parser/group/description.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use crate::md_parser;
|
||||
|
||||
pub fn parse_group_description(content: &[md_parser::MdContent]) -> Option<String> {
|
||||
let return_desc = content
|
||||
.iter()
|
||||
.map(|row| row.inner_value_as_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
if return_desc.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(return_desc)
|
||||
}
|
||||
}
|
|
@ -1,21 +1,5 @@
|
|||
use crate::md_parser::MdContent;
|
||||
|
||||
pub fn parse_group_description(content: &[MdContent]) -> Option<String> {
|
||||
let return_desc = content
|
||||
.iter()
|
||||
.map(|row| row.inner_value_as_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
if return_desc.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(return_desc)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_method_description(content: &[MdContent]) -> Option<String> {
|
||||
let return_desc = content
|
||||
.iter()
|
|
@ -1,18 +1,36 @@
|
|||
use crate::md_parser;
|
||||
mod description;
|
||||
mod return_type;
|
||||
mod url;
|
||||
|
||||
use super::{
|
||||
description::parse_method_description, parameters::parse_parameters,
|
||||
return_type::parse_return_type, url_parser::get_method_url, util, ApiMethod,
|
||||
use crate::{
|
||||
md_parser,
|
||||
parser::{parameters::parse_parameters, util},
|
||||
types,
|
||||
};
|
||||
|
||||
pub fn parse_api_method(child: md_parser::TokenTree) -> Option<ApiMethod> {
|
||||
use self::{
|
||||
description::parse_method_description,
|
||||
return_type::{parse_return_type, ReturnType},
|
||||
url::get_method_url,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApiMethod {
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub parameters: Option<Vec<types::Type>>,
|
||||
pub return_type: Option<ReturnType>,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
pub fn parse_api_method(child: &md_parser::TokenTree) -> Option<ApiMethod> {
|
||||
util::find_content_starts_with(&child.content, "Name: ")
|
||||
.map(|name| {
|
||||
name.trim_start_matches("Name: ")
|
||||
.trim_matches('`')
|
||||
.to_string()
|
||||
})
|
||||
.map(|name| to_api_method(&child, &name))
|
||||
.map(|name| to_api_method(child, &name))
|
||||
}
|
||||
|
||||
fn to_api_method(child: &md_parser::TokenTree, name: &str) -> ApiMethod {
|
|
@ -1,8 +1,14 @@
|
|||
use crate::{
|
||||
md_parser::MdContent,
|
||||
parser::{object_types::parse_object_types, types, ReturnType, ReturnTypeParameter},
|
||||
parser::{object_types::parse_object_types, types, ReturnTypeParameter},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReturnType {
|
||||
pub is_list: bool,
|
||||
pub parameters: Vec<ReturnTypeParameter>,
|
||||
}
|
||||
|
||||
pub fn parse_return_type(content: &[MdContent]) -> Option<ReturnType> {
|
||||
let table = content
|
||||
.iter()
|
9
qbittorrent-web-api-gen/src/parser/group/method/url.rs
Normal file
9
qbittorrent-web-api-gen/src/parser/group/method/url.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use crate::{md_parser, parser::util};
|
||||
|
||||
pub fn get_method_url(content: &[md_parser::MdContent]) -> 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")
|
||||
}
|
40
qbittorrent-web-api-gen/src/parser/group/mod.rs
Normal file
40
qbittorrent-web-api-gen/src/parser/group/mod.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
mod description;
|
||||
mod method;
|
||||
mod url;
|
||||
|
||||
use crate::md_parser;
|
||||
|
||||
use self::{description::parse_group_description, method::parse_api_method, url::get_group_url};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApiGroup {
|
||||
pub name: String,
|
||||
pub methods: Vec<ApiMethod>,
|
||||
pub description: Option<String>,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
pub use method::ApiMethod;
|
||||
|
||||
pub fn parse_api_group(tree: &md_parser::TokenTree) -> ApiGroup {
|
||||
let methods = tree.children.iter().flat_map(parse_api_method).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,
|
||||
}
|
||||
}
|
14
qbittorrent-web-api-gen/src/parser/group/url.rs
Normal file
14
qbittorrent-web-api-gen/src/parser/group/url.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
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");
|
||||
|
||||
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()
|
||||
}
|
|
@ -1,39 +1,12 @@
|
|||
use crate::{md_parser, types};
|
||||
|
||||
use self::api_group::parse_api_group;
|
||||
use self::group::parse_api_group;
|
||||
|
||||
mod api_group;
|
||||
mod api_method;
|
||||
mod description;
|
||||
mod group;
|
||||
mod object_types;
|
||||
mod parameters;
|
||||
mod return_type;
|
||||
mod url_parser;
|
||||
mod util;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApiGroup {
|
||||
pub name: String,
|
||||
pub methods: Vec<ApiMethod>,
|
||||
pub description: Option<String>,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApiMethod {
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub parameters: Option<Vec<types::Type>>,
|
||||
pub return_type: Option<ReturnType>,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReturnType {
|
||||
pub is_list: bool,
|
||||
pub parameters: Vec<ReturnTypeParameter>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReturnTypeParameter {
|
||||
pub name: String,
|
||||
|
@ -41,10 +14,18 @@ pub struct ReturnTypeParameter {
|
|||
pub return_type: types::Type,
|
||||
}
|
||||
|
||||
pub fn parse_api_groups(content: &str) -> Vec<ApiGroup> {
|
||||
parse_groups(extract_relevant_parts(md_parser::TokenTreeFactory::create(
|
||||
content,
|
||||
)))
|
||||
pub use group::ApiGroup;
|
||||
pub use group::ApiMethod;
|
||||
|
||||
pub fn parse_api_groups(token_tree: md_parser::TokenTree) -> Vec<ApiGroup> {
|
||||
parse_groups(extract_relevant_parts(token_tree))
|
||||
}
|
||||
|
||||
pub fn parse_groups(trees: Vec<md_parser::TokenTree>) -> Vec<ApiGroup> {
|
||||
trees
|
||||
.into_iter()
|
||||
.map(|tree| parse_api_group(&tree))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn extract_relevant_parts(tree: md_parser::TokenTree) -> Vec<md_parser::TokenTree> {
|
||||
|
@ -64,10 +45,6 @@ fn extract_relevant_parts(tree: md_parser::TokenTree) -> Vec<md_parser::TokenTre
|
|||
relevant
|
||||
}
|
||||
|
||||
pub fn parse_groups(trees: Vec<md_parser::TokenTree>) -> Vec<ApiGroup> {
|
||||
trees.into_iter().map(parse_api_group).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
use regex::Regex;
|
||||
|
||||
use crate::{md_parser::MdContent, parser::util};
|
||||
|
||||
pub fn get_group_url(content: &[MdContent]) -> String {
|
||||
let row = util::find_content_contains(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 res = re.captures(&row).expect("Failed find capture");
|
||||
res[1].to_string()
|
||||
}
|
||||
|
||||
pub fn get_method_url(content: &[MdContent]) -> 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")
|
||||
}
|
|
@ -2,26 +2,14 @@ use crate::md_parser::MdContent;
|
|||
|
||||
pub fn find_content_starts_with(content: &[MdContent], starts_with: &str) -> Option<String> {
|
||||
content.iter().find_map(|row| match row {
|
||||
MdContent::Text(content) => {
|
||||
if content.starts_with(starts_with) {
|
||||
Some(content.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
MdContent::Text(content) if content.starts_with(starts_with) => Some(content.into()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_content_contains(content: &[MdContent], contains: &str) -> Option<String> {
|
||||
content.iter().find_map(|row| match row {
|
||||
MdContent::Text(content) => {
|
||||
if content.contains(contains) {
|
||||
Some(content.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
MdContent::Text(content) if content.contains(contains) => Some(content.into()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user