1 | use std::cell::RefCell; |
2 | use std::collections::HashMap; |
3 | |
4 | use super::{add_alias, ToTypeDef, TypeDef}; |
5 | use crate::{js_doc_from_comments, ty_to_ts_type, NapiImpl, NapiStruct, NapiStructKind}; |
6 | |
7 | thread_local! { |
8 | pub(crate) static TASK_STRUCTS: RefCell<HashMap<String, String>> = Default::default(); |
9 | pub(crate) static CLASS_STRUCTS: RefCell<HashMap<String, String>> = Default::default(); |
10 | } |
11 | |
12 | impl ToTypeDef for NapiStruct { |
13 | fn to_type_def(&self) -> Option<TypeDef> { |
14 | CLASS_STRUCTS.with(|c: &RefCell>| { |
15 | c.borrow_mut() |
16 | .insert(self.name.to_string(), self.js_name.clone()); |
17 | }); |
18 | add_alias(self.name.to_string(), self.js_name.to_string()); |
19 | |
20 | Some(TypeDef { |
21 | kind: String::from(if self.kind == NapiStructKind::Object { |
22 | "interface" |
23 | } else { |
24 | "struct" |
25 | }), |
26 | name: self.js_name.to_owned(), |
27 | original_name: Some(self.name.to_string()), |
28 | def: self.gen_ts_class(), |
29 | js_mod: self.js_mod.to_owned(), |
30 | js_doc: js_doc_from_comments(&self.comments), |
31 | }) |
32 | } |
33 | } |
34 | |
35 | impl ToTypeDef for NapiImpl { |
36 | fn to_type_def(&self) -> Option<TypeDef> { |
37 | if let Some(output_type) = &self.task_output_type { |
38 | TASK_STRUCTS.with(|t| { |
39 | let (resolved_type, is_optional) = ty_to_ts_type(output_type, false, true, false); |
40 | t.borrow_mut().insert( |
41 | self.name.to_string(), |
42 | if resolved_type == "undefined" { |
43 | "void" .to_owned() |
44 | } else if is_optional { |
45 | format!(" {} | null" , resolved_type) |
46 | } else { |
47 | resolved_type |
48 | }, |
49 | ); |
50 | }); |
51 | } |
52 | |
53 | if let Some(output_type) = &self.iterator_yield_type { |
54 | let next_type = if let Some(ref ty) = self.iterator_next_type { |
55 | ty_to_ts_type(ty, false, false, false).0 |
56 | } else { |
57 | "void" .to_owned() |
58 | }; |
59 | let return_type = if let Some(ref ty) = self.iterator_return_type { |
60 | ty_to_ts_type(ty, false, false, false).0 |
61 | } else { |
62 | "void" .to_owned() |
63 | }; |
64 | Some(TypeDef { |
65 | kind: "impl" .to_owned(), |
66 | name: self.js_name.to_owned(), |
67 | original_name: None, |
68 | def: format!( |
69 | "[Symbol.iterator](): Iterator< {}, {}, {}>" , |
70 | ty_to_ts_type(output_type, false, true, false).0, |
71 | return_type, |
72 | next_type, |
73 | ), |
74 | js_mod: self.js_mod.to_owned(), |
75 | js_doc: "" .to_string(), |
76 | }) |
77 | } else { |
78 | Some(TypeDef { |
79 | kind: "impl" .to_owned(), |
80 | name: self.js_name.to_owned(), |
81 | original_name: None, |
82 | def: self |
83 | .items |
84 | .iter() |
85 | .filter_map(|f| { |
86 | if f.skip_typescript { |
87 | None |
88 | } else { |
89 | Some(format!( |
90 | " {}{}" , |
91 | js_doc_from_comments(&f.comments), |
92 | f.to_type_def() |
93 | .map_or(String::default(), |type_def| type_def.def) |
94 | )) |
95 | } |
96 | }) |
97 | .collect::<Vec<_>>() |
98 | .join(" \\n" ), |
99 | js_mod: self.js_mod.to_owned(), |
100 | js_doc: "" .to_string(), |
101 | }) |
102 | } |
103 | } |
104 | } |
105 | |
106 | impl NapiStruct { |
107 | fn gen_ts_class(&self) -> String { |
108 | let mut ctor_args = vec![]; |
109 | let def = self |
110 | .fields |
111 | .iter() |
112 | .filter(|f| f.getter) |
113 | .filter_map(|f| { |
114 | if f.skip_typescript { |
115 | return None; |
116 | } |
117 | |
118 | let mut field_str = String::from("" ); |
119 | |
120 | if !f.comments.is_empty() { |
121 | field_str.push_str(&js_doc_from_comments(&f.comments)) |
122 | } |
123 | |
124 | if !f.setter { |
125 | field_str.push_str("readonly " ) |
126 | } |
127 | |
128 | let (arg, is_optional) = ty_to_ts_type(&f.ty, false, true, false); |
129 | let arg = f.ts_type.as_ref().map(|ty| ty.to_string()).unwrap_or(arg); |
130 | |
131 | let arg = match is_optional { |
132 | false => format!(" {}: {}" , &f.js_name, arg), |
133 | true => match self.use_nullable { |
134 | false => format!(" {}?: {}" , &f.js_name, arg), |
135 | true => format!(" {}: {} | null" , &f.js_name, arg), |
136 | }, |
137 | }; |
138 | if self.kind == NapiStructKind::Constructor { |
139 | ctor_args.push(arg.clone()); |
140 | } |
141 | field_str.push_str(&arg); |
142 | |
143 | Some(field_str) |
144 | }) |
145 | .collect::<Vec<_>>() |
146 | .join(" \\n" ); |
147 | |
148 | if self.kind == NapiStructKind::Constructor { |
149 | format!(" {}\\nconstructor( {})" , def, ctor_args.join(", " )) |
150 | } else { |
151 | def |
152 | } |
153 | } |
154 | } |
155 | |