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    // Parameter property declarations create another symbol at the same name node; node2sym keeps the primary symbol.
59    #[serde(default, deserialize_with = "vecmap_or_empty")]
60    pub parameter_property_symbols: Vec<(NodeReference, u32)>,
61    // Globals and dependency exports qualified by namespace and name.
62    #[serde(default)]
63    pub external_symbols: Vec<ExternalSymbol>,
64}
65
66#[derive(Debug, Clone, Deserialize)]
67pub struct NodeReference {
68    pub sourcefile_id: u32,
69    pub start: u32,
70    pub end: u32,
71}
72
73#[derive(Debug, Clone, Deserialize)]
74pub struct SymbolData {
75    #[serde(with = "serde_bytes")]
76    pub name: Vec<u8>,
77    pub flags: u32,
78    pub check_flags: u32,
79    #[serde(default)]
80    pub decl: Option<NodeReference>,
81}
82
83#[derive(Debug, Clone, Deserialize)]
84pub struct ExternalSymbol {
85    pub symbol_id: u32,
86    #[serde(with = "serde_bytes")]
87    pub namespace: Vec<u8>,
88    #[serde(with = "serde_bytes")]
89    pub name: Vec<u8>,
90}
91
92#[derive(Debug, Clone, Deserialize)]
93pub struct TypeData {
94    pub id: u32,
95    pub flags: u32,
96    #[serde(default)]
97    pub object_flags: u32,
98    #[serde(default)]
99    pub symbol: Option<u32>,
100}
101
102#[derive(Debug, Clone, Deserialize)]
103pub struct PrimTypes {
104    pub string: u32,
105    pub number: u32,
106    pub any: u32,
107    pub error: u32,
108    pub unknown: u32,
109    pub never: u32,
110    pub undefined: u32,
111    pub null: u32,
112    pub void: u32,
113    pub bool: u32,
114}
115
116#[derive(Debug, Clone, Deserialize)]
117pub struct TypeExtra {
118    pub name: HashMap<TypeId, serde_bytes::ByteBuf>,
119    pub func: HashMap<TypeId, FunctionData>,
120}
121#[derive(Debug, Clone, Deserialize)]
122pub struct FunctionData {
123    pub signatures: Vec<Signature>,
124}
125#[derive(Debug, Clone, Deserialize)]
126pub struct Signature {
127    pub result: TypeId,
128}
129
130fn vecmap<'de, K, V, D>(deserializer: D) -> Result<Vec<(K, V)>, D::Error>
131where
132    D: Deserializer<'de>,
133    K: Deserialize<'de>,
134    V: Deserialize<'de>,
135{
136    use serde::de::Visitor;
137    use std::marker::PhantomData;
138
139    struct VecMap<K, V>(PhantomData<(K, V)>);
140
141    impl<'de, K, V> Visitor<'de> for VecMap<K, V>
142    where
143        K: Deserialize<'de>,
144        V: Deserialize<'de>,
145    {
146        type Value = Vec<(K, V)>;
147
148        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
149            write!(formatter, "vec map")
150        }
151
152        fn visit_unit<E>(self) -> Result<Self::Value, E>
153        where
154            E: serde::de::Error,
155        {
156            Ok(Vec::new())
157        }
158
159        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
160        where
161            A: serde::de::MapAccess<'de>,
162        {
163            let len = map.size_hint().unwrap_or_default();
164            let len = std::cmp::min(len, 4096);
165            let mut out = Vec::with_capacity(len);
166
167            while let Some(e) = map.next_entry()? {
168                out.push(e);
169            }
170
171            Ok(out)
172        }
173    }
174
175    deserializer.deserialize_map(VecMap(PhantomData))
176}
177
178fn vecmap_or_empty<'de, K, V, D>(deserializer: D) -> Result<Vec<(K, V)>, D::Error>
179where
180    D: Deserializer<'de>,
181    K: Deserialize<'de>,
182    V: Deserialize<'de>,
183{
184    use serde::de::Visitor;
185    use std::marker::PhantomData;
186
187    struct VecMapOrEmpty<K, V>(PhantomData<(K, V)>);
188
189    impl<'de, K, V> Visitor<'de> for VecMapOrEmpty<K, V>
190    where
191        K: Deserialize<'de>,
192        V: Deserialize<'de>,
193    {
194        type Value = Vec<(K, V)>;
195
196        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
197            write!(formatter, "vec map or nothing")
198        }
199
200        fn visit_unit<E>(self) -> Result<Self::Value, E>
201        where
202            E: serde::de::Error,
203        {
204            Ok(Vec::new())
205        }
206
207        fn visit_none<E>(self) -> Result<Self::Value, E>
208        where
209            E: serde::de::Error,
210        {
211            Ok(Vec::new())
212        }
213
214        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
215        where
216            A: serde::de::MapAccess<'de>,
217        {
218            let len = map.size_hint().unwrap_or_default();
219            let len = std::cmp::min(len, 4096);
220            let mut out = Vec::with_capacity(len);
221
222            while let Some(e) = map.next_entry()? {
223                out.push(e);
224            }
225
226            Ok(out)
227        }
228    }
229
230    deserializer.deserialize_any(VecMapOrEmpty(PhantomData))
231}
232
233impl Semantic {
234    /// Returns the value (local variable) symbol of an identifier in the shorthand property assignment.
235    ///
236    /// This is necessary as an identifier in shorthand property assignment contains two meanings:
237    /// property name and property value. For example, in `{ x }`, `x` is both the property name
238    /// and references the variable value.
239    ///
240    /// # Arguments
241    /// * `location` - The node reference to query
242    ///
243    /// # Returns
244    /// * `Some(u32)` - The symbol ID if found and has Value or Alias flags
245    /// * `None` - If no symbol is found or the symbol doesn't have the required flags
246    ///
247    /// # Reference
248    /// TypeScript implementation: https://github.com/microsoft/TypeScript/blob/9e8eaa1746b0d09c3cd29048126ef9cf24f29c03/src/compiler/checker.ts
249    pub fn get_shorthand_assignment_value_symbol(&self, location: &NodeReference) -> Option<u32> {
250        // Look up in the shorthand_symbols mapping
251        self.shorthand_symbols
252            .iter()
253            .find(|(node_ref, _)| {
254                node_ref.sourcefile_id == location.sourcefile_id
255                    && node_ref.start == location.start
256                    && node_ref.end == location.end
257            })
258            .map(|(_, sym_id)| *sym_id)
259    }
260
261    /// Returns the extra symbol declared by a parameter property name.
262    ///
263    /// TypeScript parameter properties such as `constructor(private x: string)` declare two
264    /// symbols at the same source location. The primary symbol remains in `node2sym`; this
265    /// method returns the other one.
266    pub fn get_parameter_property_symbol(&self, location: &NodeReference) -> Option<u32> {
267        self.parameter_property_symbols
268            .iter()
269            .find(|(node_ref, _)| {
270                node_ref.sourcefile_id == location.sourcefile_id
271                    && node_ref.start == location.start
272                    && node_ref.end == location.end
273            })
274            .map(|(_, sym_id)| *sym_id)
275    }
276}