From dc8290b51b6a64847b60e78833be60df6bfd7e17 Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Wed, 22 Feb 2023 10:48:04 +0100 Subject: [PATCH] Fix visibility issues for selene gen --- packages/cli/src/gen/doc2/builder.rs | 8 +++ packages/cli/src/gen/doc2/item.rs | 15 +++++ packages/cli/src/gen/doc2/parser.rs | 86 ++++++++++++++++------------ packages/cli/src/gen/selene_defs.rs | 17 +++--- 4 files changed, 82 insertions(+), 44 deletions(-) diff --git a/packages/cli/src/gen/doc2/builder.rs b/packages/cli/src/gen/doc2/builder.rs index 69ae329..dd5beee 100644 --- a/packages/cli/src/gen/doc2/builder.rs +++ b/packages/cli/src/gen/doc2/builder.rs @@ -4,6 +4,7 @@ use super::{item::DocItem, kind::DocItemKind}; #[derive(Debug, Default, Clone)] pub struct DocItemBuilder { + exported: bool, kind: Option, name: Option, meta: Option, @@ -20,6 +21,12 @@ impl DocItemBuilder { } } + #[allow(clippy::wrong_self_convention)] + pub fn as_exported(mut self) -> Self { + self.exported = true; + self + } + pub fn with_kind(mut self, kind: DocItemKind) -> Self { self.kind = Some(kind); self @@ -67,6 +74,7 @@ impl DocItemBuilder { let mut children = self.children; children.sort(); Ok(DocItem { + exported: self.exported, kind, name: self.name, meta: self.meta, diff --git a/packages/cli/src/gen/doc2/item.rs b/packages/cli/src/gen/doc2/item.rs index 97c02b7..78dda6f 100644 --- a/packages/cli/src/gen/doc2/item.rs +++ b/packages/cli/src/gen/doc2/item.rs @@ -7,6 +7,8 @@ use super::kind::DocItemKind; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DocItem { + #[serde(skip_serializing_if = "skip_serialize_is_false")] + pub(super) exported: bool, pub(super) kind: DocItemKind, #[serde(skip_serializing_if = "Option::is_none")] pub(super) name: Option, @@ -20,6 +22,11 @@ pub struct DocItem { pub(super) arg_types: Vec, } +#[allow(clippy::trivially_copy_pass_by_ref)] +fn skip_serialize_is_false(b: &bool) -> bool { + !b +} + impl PartialOrd for DocItem { fn partial_cmp(&self, other: &Self) -> Option { match self.kind.partial_cmp(&other.kind).unwrap() { @@ -53,10 +60,18 @@ impl Ord for DocItem { #[allow(dead_code)] impl DocItem { + pub fn is_exported(&self) -> bool { + self.exported + } + pub fn is_root(&self) -> bool { self.kind.is_root() } + pub fn is_table(&self) -> bool { + self.kind.is_table() + } + pub fn is_property(&self) -> bool { self.kind.is_property() } diff --git a/packages/cli/src/gen/doc2/parser.rs b/packages/cli/src/gen/doc2/parser.rs index 3cf113c..e907366 100644 --- a/packages/cli/src/gen/doc2/parser.rs +++ b/packages/cli/src/gen/doc2/parser.rs @@ -22,26 +22,31 @@ struct DocVisitorItem { type_info: TypeInfo, } -impl From for DocItem { - fn from(value: DocVisitorItem) -> Self { +impl DocVisitorItem { + fn into_doc_item(self, type_definition_declares: &Vec) -> DocItem { let mut builder = DocItemBuilder::new() - .with_kind(DocItemKind::from(&value.type_info)) - .with_name(&value.name); - if let Some(comment) = value.comment { + .with_kind(DocItemKind::from(&self.type_info)) + .with_name(&self.name); + if type_definition_declares.contains(&self.name) { + builder = builder.as_exported(); + } + if let Some(comment) = self.comment { builder = builder.with_children(&parse_moonwave_style_comment(&comment)); } - if let Some(args) = try_extract_normalized_function_args(&value.type_info) { - println!("{} > {args:?}", value.name); + if let Some(args) = try_extract_normalized_function_args(&self.type_info) { builder = builder.with_arg_types(&args); } - if let TypeInfo::Table { fields, .. } = value.type_info { + if let TypeInfo::Table { fields, .. } = self.type_info { for field in fields.iter() { if let TypeFieldKey::Name(name) = field.key() { - builder = builder.with_child(DocItem::from(DocVisitorItem { - name: name.token().to_string(), - comment: find_token_moonwave_comment(name), - type_info: field.value().clone(), - })); + builder = builder.with_child( + Self { + name: name.token().to_string(), + comment: find_token_moonwave_comment(name), + type_info: field.value().clone(), + } + .into_doc_item(type_definition_declares), + ); } } } @@ -54,9 +59,9 @@ impl From<&TypeInfo> for DocItemKind { match value { TypeInfo::Array { .. } | TypeInfo::Table { .. } => DocItemKind::Table, TypeInfo::Basic(_) | TypeInfo::String(_) => DocItemKind::Property, - TypeInfo::Optional { base, .. } => DocItemKind::from(base.as_ref()), + TypeInfo::Optional { base, .. } => Self::from(base.as_ref()), TypeInfo::Tuple { types, .. } => { - let mut kinds = types.iter().map(DocItemKind::from).collect::>(); + let mut kinds = types.iter().map(Self::from).collect::>(); let kinds_all_the_same = kinds.windows(2).all(|w| w[0] == w[1]); if kinds_all_the_same && !kinds.is_empty() { kinds.pop().unwrap() @@ -67,8 +72,8 @@ impl From<&TypeInfo> for DocItemKind { } } TypeInfo::Union { left, right, .. } | TypeInfo::Intersection { left, right, .. } => { - let kind_left = DocItemKind::from(left.as_ref()); - let kind_right = DocItemKind::from(right.as_ref()); + let kind_left = Self::from(left.as_ref()); + let kind_right = Self::from(right.as_ref()); if kind_left == kind_right { kind_left } else { @@ -86,13 +91,35 @@ impl From<&TypeInfo> for DocItemKind { } } +fn parse_type_definitions_declares(contents: &str) -> (String, Vec) { + // TODO: Properly handle the "declare class" syntax, for now we just skip it + let mut no_class_declares = contents.to_string(); + while let Some(dec) = no_class_declares.find("\ndeclare class") { + let end = no_class_declares.find("\nend").unwrap(); + let before = &no_class_declares[0..dec]; + let after = &no_class_declares[end + 4..]; + no_class_declares = format!("{before}{after}"); + } + let regex_declare = Regex::new(r#"declare (\w+): "#).unwrap(); + let resulting_contents = regex_declare + .replace_all(&no_class_declares, "export type $1 =") + .to_string(); + let found_declares = regex_declare + .captures_iter(&no_class_declares) + .map(|cap| cap[1].to_string()) + .collect(); + (resulting_contents, found_declares) +} + pub fn parse_type_definitions_into_doc_items(contents: S) -> Result> where S: AsRef, { let mut found_top_level_items = Vec::new(); - let ast = full_moon::parse(&cleanup_type_definitions(contents.as_ref())) - .context("Failed to parse type definitions")?; + let (type_definition_contents, type_definition_declares) = + parse_type_definitions_declares(contents.as_ref()); + let ast = + full_moon::parse(&type_definition_contents).context("Failed to parse type definitions")?; for stmt in ast.nodes().stmts() { if let Some((declaration, token_reference)) = match stmt { Stmt::ExportedTypeDeclaration(exp) => { @@ -108,7 +135,10 @@ where }); } } - Ok(found_top_level_items.drain(..).map(DocItem::from).collect()) + Ok(found_top_level_items + .drain(..) + .map(|visitor_item| visitor_item.into_doc_item(&type_definition_declares)) + .collect()) } fn simple_stringify_type_info(typ: &TypeInfo) -> String { @@ -261,19 +291,3 @@ fn find_token_moonwave_comment(token: &TokenReference) -> Option { .last() .map(|comment| comment.trim().to_string()) } - -fn cleanup_type_definitions(contents: &str) -> String { - // TODO: Properly handle the "declare class" syntax, for now we just skip it - let mut no_declares = contents.to_string(); - while let Some(dec) = no_declares.find("\ndeclare class") { - let end = no_declares.find("\nend").unwrap(); - let before = &no_declares[0..dec]; - let after = &no_declares[end + 4..]; - no_declares = format!("{before}{after}"); - } - let (regex, replacement) = ( - Regex::new(r#"declare (?P\w+): "#).unwrap(), - r#"export type $n = "#, - ); - regex.replace_all(&no_declares, replacement).to_string() -} diff --git a/packages/cli/src/gen/selene_defs.rs b/packages/cli/src/gen/selene_defs.rs index 3cfdb58..3041908 100644 --- a/packages/cli/src/gen/selene_defs.rs +++ b/packages/cli/src/gen/selene_defs.rs @@ -8,13 +8,14 @@ use super::doc2::{DocItem, DocItemKind, DocTree, PIPE_SEPARATOR}; pub fn generate_from_type_definitions(contents: &str) -> Result { let tree = DocTree::from_type_definitions(contents)?; let mut globals = YamlMapping::new(); - let top_level_items = tree.children().iter().filter(|top_level| { - top_level.is_function() - || top_level.children().iter().any(|top_level_child| { - top_level_child.is_tag() && top_level_child.get_name().unwrap() == "class" - }) + let top_level_exported_items = tree.children().iter().filter(|top_level| { + top_level.is_exported() + && (top_level.is_function() + || top_level.children().iter().any(|top_level_child| { + top_level_child.is_tag() && top_level_child.get_name().unwrap() == "class" + })) }); - for top_level_item in top_level_items { + for top_level_item in top_level_exported_items { match top_level_item.kind() { DocItemKind::Table => { let top_level_name = top_level_item @@ -24,7 +25,7 @@ pub fn generate_from_type_definitions(contents: &str) -> Result { for child_item in top_level_item .children() .iter() - .filter(|item| item.is_function() || item.is_property()) + .filter(|item| item.is_function() || item.is_table() || item.is_property()) { let child_name = child_item .get_name() @@ -64,7 +65,7 @@ pub fn generate_from_type_definitions(contents: &str) -> Result { fn doc_item_to_selene_yaml_mapping(item: &DocItem) -> Result { let mut mapping = YamlMapping::new(); - if item.is_property() { + if item.is_property() || item.is_table() { let property_access_tag = item .children() .iter()