typescript_webidl/type_checker/
mod.rs1use crate::types::WebIdlResult;
3use oak_idl::ast::{IdlItem, IdlRoot};
4
5pub struct WebIdlTypeChecker {
7 pub webidl_result: WebIdlResult,
9}
10
11impl WebIdlTypeChecker {
12 pub fn new(webidl_result: WebIdlResult) -> Self {
20 Self { webidl_result }
21 }
22
23 pub fn check_type_compatibility(&self, ts_type: &str, webidl_type: &str) -> bool {
32 let type_map = vec![
34 ("string", "DOMString"),
35 ("string", "ByteString"),
36 ("string", "USVString"),
37 ("string", "string"),
38 ("number", "byte"),
39 ("number", "octet"),
40 ("number", "short"),
41 ("number", "unsigned short"),
42 ("number", "long"),
43 ("number", "unsigned long"),
44 ("number", "long long"),
45 ("number", "unsigned long long"),
46 ("number", "float"),
47 ("number", "unrestricted float"),
48 ("number", "double"),
49 ("number", "unrestricted double"),
50 ("number", "integer"),
51 ("number", "unsigned integer"),
52 ("boolean", "boolean"),
53 ("any", "any"),
54 ("undefined", "undefined"),
55 ("null", "null"),
56 ("void", "void"),
57 ];
58
59 for (ts, webidl) in type_map {
61 if ts == ts_type && webidl == webidl_type {
62 return true;
63 }
64 }
65
66 if self.check_complex_type_compatibility(ts_type, webidl_type) {
68 return true;
69 }
70
71 self.check_user_defined_types(ts_type, webidl_type)
73 }
74
75 fn check_complex_type_compatibility(&self, ts_type: &str, webidl_type: &str) -> bool {
84 if ts_type.starts_with("Array<") && webidl_type.starts_with("sequence<") {
86 let ts_inner = &ts_type[6..ts_type.len() - 1];
87 let webidl_inner = &webidl_type[9..webidl_type.len() - 1];
88 return self.check_type_compatibility(ts_inner, webidl_inner);
89 }
90
91 if ts_type.starts_with("Promise<") && webidl_type.starts_with("Promise<") {
93 let ts_inner = &ts_type[8..ts_type.len() - 1];
94 let webidl_inner = &webidl_type[8..webidl_type.len() - 1];
95 return self.check_type_compatibility(ts_inner, webidl_inner);
96 }
97
98 if ts_type.contains("|") && webidl_type.contains("or") {
100 let ts_types: Vec<&str> = ts_type.split("|").map(|t| t.trim()).collect();
101 let webidl_types: Vec<&str> = webidl_type.split("or").map(|t| t.trim()).collect();
102
103 if ts_types.len() != webidl_types.len() {
104 return false;
105 }
106
107 for (ts, webidl) in ts_types.iter().zip(webidl_types.iter()) {
108 if !self.check_type_compatibility(ts, webidl) {
109 return false;
110 }
111 }
112
113 return true;
114 }
115
116 if ts_type.starts_with("{") && ts_type.contains("[key:") && webidl_type.starts_with("record<") {
118 return true;
119 }
120
121 false
122 }
123
124 fn check_user_defined_types(&self, ts_type: &str, webidl_type: &str) -> bool {
133 if ts_type == webidl_type {
135 return true;
136 }
137
138 self.check_type_alias_compatibility(ts_type, webidl_type)
140 }
141
142 fn check_type_alias_compatibility(&self, ts_type: &str, webidl_type: &str) -> bool {
151 for item in &self.webidl_result.root.items {
153 if let IdlItem::Typedef(typedef) = item {
154 if typedef.name == webidl_type {
155 return self.check_type_compatibility(ts_type, &typedef.type_name);
157 }
158 }
159 }
160
161 false
162 }
163
164 pub fn validate_webidl_types(&self) -> bool {
169 if self.webidl_result.root.items.is_empty() {
171 return false;
172 }
173
174 self.validate_items(&self.webidl_result.root)
176 }
177
178 fn validate_items(&self, root: &IdlRoot) -> bool {
186 for item in &root.items {
187 match item {
188 IdlItem::Interface(interface) => {
189 if interface.name.is_empty() {
191 return false;
192 }
193 }
194 IdlItem::Struct(struct_) => {
195 if struct_.name.is_empty() {
197 return false;
198 }
199 }
200 IdlItem::Enum(enum_) => {
201 if enum_.name.is_empty() {
203 return false;
204 }
205 if enum_.variants.is_empty() {
207 return false;
208 }
209 }
210 IdlItem::Typedef(typedef) => {
211 if typedef.name.is_empty() {
213 return false;
214 }
215 }
216 IdlItem::Const(const_) => {
217 if const_.name.is_empty() {
219 return false;
220 }
221 }
222 IdlItem::Module(module) => {
223 if module.name.is_empty() {
225 return false;
226 }
227 if !self.validate_items(&IdlRoot { items: module.items.clone() }) {
229 return false;
230 }
231 }
232 _ => {
233 }
235 }
236 }
237
238 true
239 }
240}