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)]
pub struct DocItemBuilder {
exported: bool,
kind: Option<DocItemKind>,
name: 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 {
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,

View file

@ -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<String>,
@ -20,6 +22,11 @@ pub struct DocItem {
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 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
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()
}

View file

@ -22,26 +22,31 @@ struct DocVisitorItem {
type_info: TypeInfo,
}
impl From<DocVisitorItem> for DocItem {
fn from(value: DocVisitorItem) -> Self {
impl DocVisitorItem {
fn into_doc_item(self, type_definition_declares: &Vec<String>) -> 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::<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]);
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<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>>
where
S: AsRef<str>,
{
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<String> {
.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<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> {
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<String> {
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<String> {
fn doc_item_to_selene_yaml_mapping(item: &DocItem) -> Result<YamlMapping> {
let mut mapping = YamlMapping::new();
if item.is_property() {
if item.is_property() || item.is_table() {
let property_access_tag = item
.children()
.iter()