Group by function

This commit is contained in:
Joel Wachsler 2022-07-12 11:35:11 +00:00
parent 201ba025f3
commit aaf3153205
12 changed files with 130 additions and 130 deletions

View File

@ -7,14 +7,15 @@ use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use regex::Regex; use regex::Regex;
use crate::{parser, types, util}; use crate::{md_parser, parser, types, util};
use self::skeleton::{auth_ident, generate_skeleton}; use self::skeleton::{auth_ident, generate_skeleton};
pub fn generate(ast: &syn::DeriveInput, api_content: &str) -> TokenStream { pub fn generate(ast: &syn::DeriveInput, api_content: &str) -> TokenStream {
let ident = &ast.ident; 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 skeleton = generate_skeleton(ident);
let groups = generate_groups(api_groups); let groups = generate_groups(api_groups);

View File

@ -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,
}
}

View 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)
}
}

View File

@ -1,21 +1,5 @@
use crate::md_parser::MdContent; 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> { pub fn parse_method_description(content: &[MdContent]) -> Option<String> {
let return_desc = content let return_desc = content
.iter() .iter()

View File

@ -1,18 +1,36 @@
use crate::md_parser; mod description;
mod return_type;
mod url;
use super::{ use crate::{
description::parse_method_description, parameters::parse_parameters, md_parser,
return_type::parse_return_type, url_parser::get_method_url, util, ApiMethod, 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: ") util::find_content_starts_with(&child.content, "Name: ")
.map(|name| { .map(|name| {
name.trim_start_matches("Name: ") name.trim_start_matches("Name: ")
.trim_matches('`') .trim_matches('`')
.to_string() .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 { fn to_api_method(child: &md_parser::TokenTree, name: &str) -> ApiMethod {

View File

@ -1,8 +1,14 @@
use crate::{ use crate::{
md_parser::MdContent, 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> { pub fn parse_return_type(content: &[MdContent]) -> Option<ReturnType> {
let table = content let table = content
.iter() .iter()

View 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")
}

View 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,
}
}

View 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()
}

View File

@ -1,39 +1,12 @@
use crate::{md_parser, types}; use crate::{md_parser, types};
use self::api_group::parse_api_group; use self::group::parse_api_group;
mod api_group; mod group;
mod api_method;
mod description;
mod object_types; mod object_types;
mod parameters; mod parameters;
mod return_type;
mod url_parser;
mod util; 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)] #[derive(Debug)]
pub struct ReturnTypeParameter { pub struct ReturnTypeParameter {
pub name: String, pub name: String,
@ -41,10 +14,18 @@ pub struct ReturnTypeParameter {
pub return_type: types::Type, pub return_type: types::Type,
} }
pub fn parse_api_groups(content: &str) -> Vec<ApiGroup> { pub use group::ApiGroup;
parse_groups(extract_relevant_parts(md_parser::TokenTreeFactory::create( pub use group::ApiMethod;
content,
))) 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> { 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 relevant
} }
pub fn parse_groups(trees: Vec<md_parser::TokenTree>) -> Vec<ApiGroup> {
trees.into_iter().map(parse_api_group).collect()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -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")
}

View File

@ -2,26 +2,14 @@ use crate::md_parser::MdContent;
pub fn find_content_starts_with(content: &[MdContent], starts_with: &str) -> Option<String> { pub fn find_content_starts_with(content: &[MdContent], starts_with: &str) -> Option<String> {
content.iter().find_map(|row| match row { content.iter().find_map(|row| match row {
MdContent::Text(content) => { MdContent::Text(content) if content.starts_with(starts_with) => Some(content.into()),
if content.starts_with(starts_with) {
Some(content.into())
} else {
None
}
}
_ => None, _ => None,
}) })
} }
pub fn find_content_contains(content: &[MdContent], contains: &str) -> Option<String> { pub fn find_content_contains(content: &[MdContent], contains: &str) -> Option<String> {
content.iter().find_map(|row| match row { content.iter().find_map(|row| match row {
MdContent::Text(content) => { MdContent::Text(content) if content.contains(contains) => Some(content.into()),
if content.contains(contains) {
Some(content.into())
} else {
None
}
}
_ => None, _ => None,
}) })
} }