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 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);

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;
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()

View File

@ -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 {

View File

@ -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()

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 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::*;

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> {
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,
})
}