Move methods to TokenTree

This commit is contained in:
Joel Wachsler 2022-07-19 20:53:55 +00:00
parent 47b9701321
commit bc8d014bc3
8 changed files with 162 additions and 157 deletions

View File

@ -1,17 +1,20 @@
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();
impl md_parser::TokenTree {
pub fn parse_group_description(&self) -> Option<String> {
let return_desc = self
.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)
if return_desc.is_empty() {
None
} else {
Some(return_desc)
}
}
}

View File

@ -1,35 +1,38 @@
use crate::md_parser::MdContent;
use crate::md_parser::{self, MdContent};
pub fn parse_method_description(content: &[MdContent]) -> Option<String> {
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::<Vec<String>>()
.join("\n")
.trim()
.to_string();
impl md_parser::TokenTree {
pub fn parse_method_description(&self) -> Option<String> {
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::<Vec<String>>()
.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)
}
}
}

View File

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

View File

@ -11,81 +11,84 @@ pub struct ReturnType {
pub parameters: Vec<ReturnTypeParameter>,
}
pub fn parse_return_type(content: &[MdContent]) -> Option<ReturnType> {
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<ReturnType> {
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(
&parameter.columns[1],
&parameter.columns[0],
Some(parameter.columns[2].clone()),
&types,
)
.unwrap_or_else(|| panic!("Failed to parse type {}", &parameter.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(
&parameter.columns[1],
&parameter.columns[0],
Some(parameter.columns[2].clone()),
&types,
)
.unwrap_or_else(|| panic!("Failed to parse type {}", &parameter.columns[1])),
})
.collect();
pub fn parse_object_types(&self) -> HashMap<String, types::TypeDescription> {
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<String, types::TypeDescription> {
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<types::TypeDescriptions> {

View File

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

View File

@ -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<ApiMethod> {
self.children.iter().flat_map(ApiMethod::try_new).collect()
}
}

View File

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

View File

@ -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<ApiGroup> {
}
pub fn parse_groups(trees: Vec<md_parser::TokenTree>) -> Vec<ApiGroup> {
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<md_parser::TokenTree> {