Skip to content

Commit

Permalink
Extract and copy rustdoc comments into type definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
sisou committed Aug 14, 2023
1 parent 66cddfe commit 33ce45d
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 6 deletions.
6 changes: 6 additions & 0 deletions tsify-macros/src/attrs.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use serde_derive_internals::ast::Field;

use crate::comments::extract_doc_comments;

#[derive(Debug, Default)]
pub struct TsifyContainerAttars {
pub into_wasm_abi: bool,
pub from_wasm_abi: bool,
pub namespace: bool,
pub comments: Vec<String>,
}

impl TsifyContainerAttars {
Expand All @@ -13,6 +16,7 @@ impl TsifyContainerAttars {
into_wasm_abi: false,
from_wasm_abi: false,
namespace: false,
comments: extract_doc_comments(&input.attrs),
};

for attr in &input.attrs {
Expand Down Expand Up @@ -60,13 +64,15 @@ impl TsifyContainerAttars {
pub struct TsifyFieldAttrs {
pub type_override: Option<String>,
pub optional: bool,
pub comments: Vec<String>,
}

impl TsifyFieldAttrs {
pub fn from_serde_field(field: &Field) -> syn::Result<Self> {
let mut attrs = Self {
type_override: None,
optional: false,
comments: extract_doc_comments(&field.original.attrs),
};

for attr in &field.original.attrs {
Expand Down
69 changes: 69 additions & 0 deletions tsify-macros/src/comments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use proc_macro2::TokenTree;
use quote::ToTokens;

use crate::typescript::TsType;

/// Extract the documentation comments from a Vec of attributes
pub fn extract_doc_comments(attrs: &[syn::Attribute]) -> Vec<String> {
attrs
.iter()
.filter_map(|a| {
// if the path segments include an ident of "doc" we know this
// this is a doc comment
if a.path()
.segments
.iter()
.any(|s| s.ident.to_string() == "doc")
{
Some(a.to_token_stream().into_iter().filter_map(|t| match t {
TokenTree::Group(group) => {
// this will return the inner tokens of the group
// which will be the doc comments
Some(
group
.stream()
.into_iter()
.filter_map(|t| match t {
TokenTree::Literal(lit) => {
// this will always return the quoted string, we deal with
// that in the cli when we read in the comments
Some(lit.to_string())
}
_ => None,
})
.collect::<Vec<_>>()
.join(""),
)
}
_ => None,
}))
} else {
None
}
})
//Fold up the [[String]] iter we created into Vec<String>
.fold(vec![], |mut acc, a| {
acc.extend(a);
acc
})
}

pub fn format_doc_comments(comments: &Vec<String>) -> String {
let comment = comments
.iter()
.map(|line| format!(" *{}\n", line.trim_matches('"')))
.collect::<Vec<_>>()
.join("");

format!("/**\n{} */\n", comment)
}

pub fn clean_comments(typ: &mut TsType) -> () {
if let TsType::TypeLit(ref mut lit) = typ {
lit.members.iter_mut().for_each(|elem| {
elem.comments = vec![];
// Recurse
clean_comments(&mut elem.type_ann);
});
}
}
52 changes: 47 additions & 5 deletions tsify-macros/src/decl.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
use std::fmt::Display;
use std::ops::Deref;
use std::{fmt::Display, vec};

use crate::typescript::{TsType, TsTypeElement, TsTypeLit};
use crate::comments::clean_comments;
use crate::{
comments::format_doc_comments,
typescript::{TsType, TsTypeElement, TsTypeLit},
};

#[derive(Clone)]
pub struct TsTypeAliasDecl {
pub id: String,
pub export: bool,
pub type_params: Vec<String>,
pub type_ann: TsType,
pub comments: Vec<String>,
}

impl TsTypeAliasDecl {
pub fn to_string_with_indent(&self, indent: usize) -> String {
let out = self.to_string();
let indent_str = " ".repeat(indent);
out.split("\n")
.map(|line| format!("{}{}", indent_str, line))
.collect::<Vec<_>>()
.join("\n")
}
}

impl Display for TsTypeAliasDecl {
Expand All @@ -20,6 +36,10 @@ impl Display for TsTypeAliasDecl {
format!("{}<{}>", self.id, type_params)
};

if !self.comments.is_empty() {
write!(f, "{}", format_doc_comments(&self.comments))?;
}

if self.export {
write!(f, "export ")?;
}
Expand All @@ -32,10 +52,15 @@ pub struct TsInterfaceDecl {
pub type_params: Vec<String>,
pub extends: Vec<TsType>,
pub body: Vec<TsTypeElement>,
pub comments: Vec<String>,
}

impl Display for TsInterfaceDecl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if !self.comments.is_empty() {
write!(f, "{}", format_doc_comments(&self.comments))?;
}

write!(f, "export interface {}", self.id)?;

if !self.type_params.is_empty() {
Expand All @@ -60,7 +85,7 @@ impl Display for TsInterfaceDecl {
let members = self
.body
.iter()
.map(|elem| format!("\n {elem};"))
.map(|elem| format!("\n{};", elem.to_string_with_indent(4)))
.collect::<Vec<_>>()
.join("");

Expand All @@ -74,6 +99,7 @@ pub struct TsEnumDecl {
pub type_params: Vec<String>,
pub members: Vec<TsTypeAliasDecl>,
pub namespace: bool,
pub comments: Vec<String>,
}

const ALPHABET_UPPER: [char; 26] = [
Expand Down Expand Up @@ -141,6 +167,7 @@ impl TsEnumDecl {
key: t.key.clone(),
optional: t.optional,
type_ann: TsEnumDecl::replace_type_params(t.type_ann.clone(), type_args),
comments: vec![],
})
.collect(),
}),
Expand Down Expand Up @@ -187,6 +214,7 @@ impl Display for TsEnumDecl {
export: false,
type_params: type_refs,
type_ann: ts_type,
comments: vec![],
}
})
.collect::<Vec<_>>()
Expand All @@ -197,6 +225,11 @@ impl Display for TsEnumDecl {
for type_ref in type_refs {
writeln!(f, "{}", type_ref)?;
}

if !self.comments.is_empty() {
write!(f, "{}", format_doc_comments(&self.comments))?;
}

write!(f, "declare namespace {}", self.id)?;

if self.members.is_empty() {
Expand All @@ -214,8 +247,9 @@ impl Display for TsEnumDecl {
.type_ann
.clone()
.prefix_type_refs(&prefix, &self.type_params),
comments: elem.comments.clone(),
})
.map(|elem| format!("\n {elem}"))
.map(|elem| format!("\n{}", elem.to_string_with_indent(4)))
.collect::<Vec<_>>()
.join("");

Expand All @@ -232,9 +266,17 @@ impl Display for TsEnumDecl {
type_ann: TsType::Union(
self.members
.iter()
.map(|member| member.type_ann.clone())
.map(|member| {
// let mut type_refs = Vec::new();
// TsEnumDecl::replace_type_params(member.type_ann.clone(), &mut type_refs)

let mut clone = member.type_ann.clone();
clean_comments(&mut clone);
clone
})
.collect(),
),
comments: self.comments.clone(),
}
.fmt(f)
}
Expand Down
1 change: 1 addition & 0 deletions tsify-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod attrs;
mod comments;
mod container;
mod ctxt;
mod decl;
Expand Down
9 changes: 9 additions & 0 deletions tsify-macros/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde_derive_internals::{

use crate::{
attrs::TsifyFieldAttrs,
comments::extract_doc_comments,
container::Container,
decl::{Decl, TsEnumDecl, TsInterfaceDecl, TsTypeAliasDecl},
typescript::{TsType, TsTypeElement, TsTypeLit},
Expand Down Expand Up @@ -74,6 +75,7 @@ impl<'a> Parser<'a> {
export: true,
type_params: self.create_relevant_type_params(type_ann.type_ref_names()),
type_ann,
comments: extract_doc_comments(&self.container.serde_container.original.attrs),
})
}

Expand All @@ -95,6 +97,7 @@ impl<'a> Parser<'a> {
type_params,
extends,
body: members,
comments: extract_doc_comments(&self.container.serde_container.original.attrs),
})
} else {
let extra = TsType::Intersection(
Expand Down Expand Up @@ -124,6 +127,7 @@ impl<'a> Parser<'a> {
key: tag.clone(),
type_ann: TsType::Lit(name),
optional: false,
comments: vec![],
};

let mut vec = Vec::with_capacity(members.len() + 1);
Expand Down Expand Up @@ -224,10 +228,13 @@ impl<'a> Parser<'a> {
type_ann
};

let comments = extract_doc_comments(&field.original.attrs);

TsTypeElement {
key,
type_ann,
optional: optional || !default_is_none,
comments,
}
})
.collect();
Expand All @@ -248,6 +255,7 @@ impl<'a> Parser<'a> {
let decl = self.create_type_alias_decl(self.parse_variant(variant));
if let Decl::TsTypeAlias(mut type_alias) = decl {
type_alias.id = variant.attrs.name().serialize_name();
type_alias.comments = extract_doc_comments(&variant.original.attrs);

type_alias
} else {
Expand All @@ -268,6 +276,7 @@ impl<'a> Parser<'a> {
type_params: relevant_type_params,
members,
namespace: self.container.attrs.namespace,
comments: extract_doc_comments(&self.container.serde_container.original.attrs),
})
}

Expand Down
5 changes: 4 additions & 1 deletion tsify-macros/src/type_alias.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use proc_macro2::TokenStream;
use quote::quote;

use crate::{ctxt::Ctxt, decl::TsTypeAliasDecl, typescript::TsType};
use crate::{
comments::extract_doc_comments, ctxt::Ctxt, decl::TsTypeAliasDecl, typescript::TsType,
};

pub fn expend(item: syn::ItemType) -> syn::Result<TokenStream> {
let ctxt = Ctxt::new();
Expand All @@ -17,6 +19,7 @@ pub fn expend(item: syn::ItemType) -> syn::Result<TokenStream> {
.map(|ty| ty.ident.to_string())
.collect(),
type_ann,
comments: extract_doc_comments(&item.attrs),
};

let decl_str = decl.to_string();
Expand Down
Loading

0 comments on commit 33ce45d

Please sign in to comment.