Skip to main content

tsgo_client/
proto.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Deserializer};
4use serde_bytes::Bytes;
5type TypeId = u32;
6#[derive(Debug, Clone, Deserialize)]
7#[non_exhaustive]
8pub struct ProjectResponse<'base> {
9    #[serde(borrow)]
10    pub root_files: Vec<&'base str>,
11    pub source_files: Vec<&'base Bytes>,
12    pub module_list: Vec<&'base str>,
13    #[serde(default)]
14    pub module_exports: Vec<Vec<u32>>,
15    pub semantic: Semantic,
16    pub diagnostics: Vec<Diagnostic>,
17    pub source_file_extra: Vec<SourceFileExtra>,
18}
19#[derive(Debug, Clone, Deserialize)]
20pub struct SourceFileExtra {
21    pub has_common_js_module_indicator: bool,
22    pub has_external_module_indicator: bool,
23}
24#[derive(Debug, Clone, Deserialize)]
25pub struct Location {
26    pub start: u32,
27    pub end: u32,
28}
29#[derive(Debug, Clone, Deserialize)]
30pub struct Diagnostic {
31    pub message: String,
32    pub category: u32,
33    pub file: u32,
34    pub loc: Location,
35}
36#[derive(Debug, Clone, Deserialize)]
37pub struct Semantic {
38    #[serde(deserialize_with = "vecmap")]
39    pub symtab: Vec<(u32, SymbolData)>,
40    #[serde(deserialize_with = "vecmap")]
41    pub typetab: Vec<(u32, TypeData)>,
42    #[serde(deserialize_with = "vecmap")]
43    pub sym2type: Vec<(u32, u32)>,
44    #[serde(deserialize_with = "vecmap")]
45    pub node2sym: Vec<(NodeReference, u32)>,
46    #[serde(deserialize_with = "vecmap")]
47    pub node2type: Vec<(NodeReference, u32)>,
48    #[serde(default, deserialize_with = "vecmap_or_empty")]
49    pub node_flags: Vec<(NodeReference, u32)>,
50    pub type_extra: TypeExtra,
51    pub primtypes: PrimTypes,
52    // (aliasSymbolId, targetSymbolId)
53    #[serde(default, deserialize_with = "vecmap_or_empty")]
54    pub alias_symbols: Vec<(u32, u32)>,
55    // Shorthand property assignment value symbols (node -> value_symbol_id)
56    #[serde(default, deserialize_with = "vecmap_or_empty")]
57    pub shorthand_symbols: Vec<(NodeReference, u32)>,
58    // Shorthand object binding symbols (local_symbol_id -> property_symbol_id).
59    #[serde(default, deserialize_with = "vecmap_or_empty")]
60    pub shorthand_binding_symbols: Vec<(u32, u32)>,
61    // Parameter property declarations create another symbol at the same name node; node2sym keeps the primary symbol.
62    #[serde(default, deserialize_with = "vecmap_or_empty")]
63    pub parameter_property_symbols: Vec<(NodeReference, u32)>,
64    // Globals and dependency exports qualified by namespace and name.
65    #[serde(default)]
66    pub external_symbols: Vec<ExternalSymbol>,
67}
68
69#[derive(Debug, Clone, Deserialize)]
70pub struct NodeReference {
71    pub sourcefile_id: u32,
72    pub start: u32,
73    pub end: u32,
74}
75
76#[derive(Debug, Clone, Deserialize)]
77pub struct SymbolData {
78    #[serde(with = "serde_bytes")]
79    pub name: Vec<u8>,
80    pub flags: u32,
81    pub check_flags: u32,
82    #[serde(default)]
83    pub decl: Option<NodeReference>,
84}
85
86#[derive(Debug, Clone, Deserialize)]
87pub struct ExternalSymbol {
88    pub symbol_id: u32,
89    #[serde(with = "serde_bytes")]
90    pub namespace: Vec<u8>,
91    #[serde(with = "serde_bytes")]
92    pub name: Vec<u8>,
93}
94
95#[derive(Debug, Clone, Deserialize)]
96pub struct TypeData {
97    pub id: u32,
98    pub flags: u32,
99    #[serde(default)]
100    pub object_flags: u32,
101    #[serde(default)]
102    pub symbol: Option<u32>,
103}
104
105#[derive(Debug, Clone, Deserialize)]
106pub struct PrimTypes {
107    pub string: u32,
108    pub number: u32,
109    pub any: u32,
110    pub error: u32,
111    pub unknown: u32,
112    pub never: u32,
113    pub undefined: u32,
114    pub null: u32,
115    pub void: u32,
116    pub bool: u32,
117}
118
119#[derive(Debug, Clone, Deserialize)]
120pub struct TypeExtra {
121    pub name: HashMap<TypeId, serde_bytes::ByteBuf>,
122    pub func: HashMap<TypeId, FunctionData>,
123}
124#[derive(Debug, Clone, Deserialize)]
125pub struct FunctionData {
126    pub signatures: Vec<Signature>,
127}
128#[derive(Debug, Clone, Deserialize)]
129pub struct Signature {
130    pub result: TypeId,
131}
132
133fn vecmap<'de, K, V, D>(deserializer: D) -> Result<Vec<(K, V)>, D::Error>
134where
135    D: Deserializer<'de>,
136    K: Deserialize<'de>,
137    V: Deserialize<'de>,
138{
139    use serde::de::Visitor;
140    use std::marker::PhantomData;
141
142    struct VecMap<K, V>(PhantomData<(K, V)>);
143
144    impl<'de, K, V> Visitor<'de> for VecMap<K, V>
145    where
146        K: Deserialize<'de>,
147        V: Deserialize<'de>,
148    {
149        type Value = Vec<(K, V)>;
150
151        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
152            write!(formatter, "vec map")
153        }
154
155        fn visit_unit<E>(self) -> Result<Self::Value, E>
156        where
157            E: serde::de::Error,
158        {
159            Ok(Vec::new())
160        }
161
162        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
163        where
164            A: serde::de::MapAccess<'de>,
165        {
166            let len = map.size_hint().unwrap_or_default();
167            let len = std::cmp::min(len, 4096);
168            let mut out = Vec::with_capacity(len);
169
170            while let Some(e) = map.next_entry()? {
171                out.push(e);
172            }
173
174            Ok(out)
175        }
176    }
177
178    deserializer.deserialize_map(VecMap(PhantomData))
179}
180
181fn vecmap_or_empty<'de, K, V, D>(deserializer: D) -> Result<Vec<(K, V)>, D::Error>
182where
183    D: Deserializer<'de>,
184    K: Deserialize<'de>,
185    V: Deserialize<'de>,
186{
187    use serde::de::Visitor;
188    use std::marker::PhantomData;
189
190    struct VecMapOrEmpty<K, V>(PhantomData<(K, V)>);
191
192    impl<'de, K, V> Visitor<'de> for VecMapOrEmpty<K, V>
193    where
194        K: Deserialize<'de>,
195        V: Deserialize<'de>,
196    {
197        type Value = Vec<(K, V)>;
198
199        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
200            write!(formatter, "vec map or nothing")
201        }
202
203        fn visit_unit<E>(self) -> Result<Self::Value, E>
204        where
205            E: serde::de::Error,
206        {
207            Ok(Vec::new())
208        }
209
210        fn visit_none<E>(self) -> Result<Self::Value, E>
211        where
212            E: serde::de::Error,
213        {
214            Ok(Vec::new())
215        }
216
217        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
218        where
219            A: serde::de::MapAccess<'de>,
220        {
221            let len = map.size_hint().unwrap_or_default();
222            let len = std::cmp::min(len, 4096);
223            let mut out = Vec::with_capacity(len);
224
225            while let Some(e) = map.next_entry()? {
226                out.push(e);
227            }
228
229            Ok(out)
230        }
231    }
232
233    deserializer.deserialize_any(VecMapOrEmpty(PhantomData))
234}
235
236impl Semantic {
237    /// Returns the value (local variable) symbol of an identifier in the shorthand property assignment.
238    ///
239    /// This is necessary as an identifier in shorthand property assignment contains two meanings:
240    /// property name and property value. For example, in `{ x }`, `x` is both the property name
241    /// and references the variable value.
242    ///
243    /// # Arguments
244    /// * `location` - The node reference to query
245    ///
246    /// # Returns
247    /// * `Some(u32)` - The symbol ID if found and has Value or Alias flags
248    /// * `None` - If no symbol is found or the symbol doesn't have the required flags
249    ///
250    /// # Reference
251    /// TypeScript implementation: https://github.com/microsoft/TypeScript/blob/9e8eaa1746b0d09c3cd29048126ef9cf24f29c03/src/compiler/checker.ts
252    pub fn get_shorthand_assignment_value_symbol(&self, location: &NodeReference) -> Option<u32> {
253        // Look up in the shorthand_symbols mapping
254        self.shorthand_symbols
255            .iter()
256            .find(|(node_ref, _)| {
257                node_ref.sourcefile_id == location.sourcefile_id
258                    && node_ref.start == location.start
259                    && node_ref.end == location.end
260            })
261            .map(|(_, sym_id)| *sym_id)
262    }
263
264    /// Returns the source property symbol of a shorthand object binding name.
265    ///
266    /// In `const { x } = value`, this maps the newly declared local `x` symbol
267    /// to the property symbol equivalent to `x` in `value.x`.
268    pub fn get_shorthand_binding_property_symbol(&self, local_symbol: u32) -> Option<u32> {
269        self.shorthand_binding_symbols
270            .iter()
271            .find(|(symbol, _)| *symbol == local_symbol)
272            .map(|(_, sym_id)| *sym_id)
273    }
274
275    /// Returns the extra symbol declared by a parameter property name.
276    ///
277    /// TypeScript parameter properties such as `constructor(private x: string)` declare two
278    /// symbols at the same source location. The primary symbol remains in `node2sym`; this
279    /// method returns the other one.
280    pub fn get_parameter_property_symbol(&self, location: &NodeReference) -> Option<u32> {
281        self.parameter_property_symbols
282            .iter()
283            .find(|(node_ref, _)| {
284                node_ref.sourcefile_id == location.sourcefile_id
285                    && node_ref.start == location.start
286                    && node_ref.end == location.end
287            })
288            .map(|(_, sym_id)| *sym_id)
289    }
290}