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