Fix visibility issues for selene gen

This commit is contained in:
Filip Tibell 2023-02-22 10:48:04 +01:00
parent 67f9d4eb9f
commit dc8290b51b
No known key found for this signature in database
4 changed files with 82 additions and 44 deletions

View file

@ -4,6 +4,7 @@ use super::{item::DocItem, kind::DocItemKind};
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct DocItemBuilder { pub struct DocItemBuilder {
exported: bool,
kind: Option<DocItemKind>, kind: Option<DocItemKind>,
name: Option<String>, name: Option<String>,
meta: Option<String>, meta: Option<String>,
@ -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 { pub fn with_kind(mut self, kind: DocItemKind) -> Self {
self.kind = Some(kind); self.kind = Some(kind);
self self
@ -67,6 +74,7 @@ impl DocItemBuilder {
let mut children = self.children; let mut children = self.children;
children.sort(); children.sort();
Ok(DocItem { Ok(DocItem {
exported: self.exported,
kind, kind,
name: self.name, name: self.name,
meta: self.meta, meta: self.meta,

View file

@ -7,6 +7,8 @@ use super::kind::DocItemKind;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct DocItem { pub struct DocItem {
#[serde(skip_serializing_if = "skip_serialize_is_false")]
pub(super) exported: bool,
pub(super) kind: DocItemKind, pub(super) kind: DocItemKind,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub(super) name: Option<String>, pub(super) name: Option<String>,
@ -20,6 +22,11 @@ pub struct DocItem {
pub(super) arg_types: Vec<String>, pub(super) arg_types: Vec<String>,
} }
#[allow(clippy::trivially_copy_pass_by_ref)]
fn skip_serialize_is_false(b: &bool) -> bool {
!b
}
impl PartialOrd for DocItem { impl PartialOrd for DocItem {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self.kind.partial_cmp(&other.kind).unwrap() { match self.kind.partial_cmp(&other.kind).unwrap() {
@ -53,10 +60,18 @@ impl Ord for DocItem {
#[allow(dead_code)] #[allow(dead_code)]
impl DocItem { impl DocItem {
pub fn is_exported(&self) -> bool {
self.exported
}
pub fn is_root(&self) -> bool { pub fn is_root(&self) -> bool {
self.kind.is_root() self.kind.is_root()
} }
pub fn is_table(&self) -> bool {
self.kind.is_table()
}
pub fn is_property(&self) -> bool { pub fn is_property(&self) -> bool {
self.kind.is_property() self.kind.is_property()
} }

View file

@ -22,26 +22,31 @@ struct DocVisitorItem {
type_info: TypeInfo, type_info: TypeInfo,
} }
impl From<DocVisitorItem> for DocItem { impl DocVisitorItem {
fn from(value: DocVisitorItem) -> Self { fn into_doc_item(self, type_definition_declares: &Vec<String>) -> DocItem {
let mut builder = DocItemBuilder::new() let mut builder = DocItemBuilder::new()
.with_kind(DocItemKind::from(&value.type_info)) .with_kind(DocItemKind::from(&self.type_info))
.with_name(&value.name); .with_name(&self.name);
if let Some(comment) = value.comment { 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)); builder = builder.with_children(&parse_moonwave_style_comment(&comment));
} }
if let Some(args) = try_extract_normalized_function_args(&value.type_info) { if let Some(args) = try_extract_normalized_function_args(&self.type_info) {
println!("{} > {args:?}", value.name);
builder = builder.with_arg_types(&args); 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() { for field in fields.iter() {
if let TypeFieldKey::Name(name) = field.key() { if let TypeFieldKey::Name(name) = field.key() {
builder = builder.with_child(DocItem::from(DocVisitorItem { builder = builder.with_child(
name: name.token().to_string(), Self {
comment: find_token_moonwave_comment(name), name: name.token().to_string(),
type_info: field.value().clone(), 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 { match value {
TypeInfo::Array { .. } | TypeInfo::Table { .. } => DocItemKind::Table, TypeInfo::Array { .. } | TypeInfo::Table { .. } => DocItemKind::Table,
TypeInfo::Basic(_) | TypeInfo::String(_) => DocItemKind::Property, 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, .. } => { TypeInfo::Tuple { types, .. } => {
let mut kinds = types.iter().map(DocItemKind::from).collect::<Vec<_>>(); let mut kinds = types.iter().map(Self::from).collect::<Vec<_>>();
let kinds_all_the_same = kinds.windows(2).all(|w| w[0] == w[1]); let kinds_all_the_same = kinds.windows(2).all(|w| w[0] == w[1]);
if kinds_all_the_same && !kinds.is_empty() { if kinds_all_the_same && !kinds.is_empty() {
kinds.pop().unwrap() kinds.pop().unwrap()
@ -67,8 +72,8 @@ impl From<&TypeInfo> for DocItemKind {
} }
} }
TypeInfo::Union { left, right, .. } | TypeInfo::Intersection { left, right, .. } => { TypeInfo::Union { left, right, .. } | TypeInfo::Intersection { left, right, .. } => {
let kind_left = DocItemKind::from(left.as_ref()); let kind_left = Self::from(left.as_ref());
let kind_right = DocItemKind::from(right.as_ref()); let kind_right = Self::from(right.as_ref());
if kind_left == kind_right { if kind_left == kind_right {
kind_left kind_left
} else { } else {
@ -86,13 +91,35 @@ impl From<&TypeInfo> for DocItemKind {
} }
} }
fn parse_type_definitions_declares(contents: &str) -> (String, Vec<String>) {
// 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<S>(contents: S) -> Result<Vec<DocItem>> pub fn parse_type_definitions_into_doc_items<S>(contents: S) -> Result<Vec<DocItem>>
where where
S: AsRef<str>, S: AsRef<str>,
{ {
let mut found_top_level_items = Vec::new(); let mut found_top_level_items = Vec::new();
let ast = full_moon::parse(&cleanup_type_definitions(contents.as_ref())) let (type_definition_contents, type_definition_declares) =
.context("Failed to parse type definitions")?; 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() { for stmt in ast.nodes().stmts() {
if let Some((declaration, token_reference)) = match stmt { if let Some((declaration, token_reference)) = match stmt {
Stmt::ExportedTypeDeclaration(exp) => { 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 { fn simple_stringify_type_info(typ: &TypeInfo) -> String {
@ -261,19 +291,3 @@ fn find_token_moonwave_comment(token: &TokenReference) -> Option<String> {
.last() .last()
.map(|comment| comment.trim().to_string()) .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<n>\w+): "#).unwrap(),
r#"export type $n = "#,
);
regex.replace_all(&no_declares, replacement).to_string()
}

View file

@ -8,13 +8,14 @@ use super::doc2::{DocItem, DocItemKind, DocTree, PIPE_SEPARATOR};
pub fn generate_from_type_definitions(contents: &str) -> Result<String> { pub fn generate_from_type_definitions(contents: &str) -> Result<String> {
let tree = DocTree::from_type_definitions(contents)?; let tree = DocTree::from_type_definitions(contents)?;
let mut globals = YamlMapping::new(); let mut globals = YamlMapping::new();
let top_level_items = tree.children().iter().filter(|top_level| { let top_level_exported_items = tree.children().iter().filter(|top_level| {
top_level.is_function() top_level.is_exported()
|| top_level.children().iter().any(|top_level_child| { && (top_level.is_function()
top_level_child.is_tag() && top_level_child.get_name().unwrap() == "class" || 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() { match top_level_item.kind() {
DocItemKind::Table => { DocItemKind::Table => {
let top_level_name = top_level_item let top_level_name = top_level_item
@ -24,7 +25,7 @@ pub fn generate_from_type_definitions(contents: &str) -> Result<String> {
for child_item in top_level_item for child_item in top_level_item
.children() .children()
.iter() .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 let child_name = child_item
.get_name() .get_name()
@ -64,7 +65,7 @@ pub fn generate_from_type_definitions(contents: &str) -> Result<String> {
fn doc_item_to_selene_yaml_mapping(item: &DocItem) -> Result<YamlMapping> { fn doc_item_to_selene_yaml_mapping(item: &DocItem) -> Result<YamlMapping> {
let mut mapping = YamlMapping::new(); let mut mapping = YamlMapping::new();
if item.is_property() { if item.is_property() || item.is_table() {
let property_access_tag = item let property_access_tag = item
.children() .children()
.iter() .iter()