1use alloc::collections::BTreeMap;
4use alloc::string::String;
5use alloc::vec::Vec;
6
7use strum::{EnumDiscriminants, IntoStaticStr};
8
9use crate::NodeId;
10
11#[derive(Clone, PartialEq, Eq, Debug)]
12pub struct FileStructData {
13 pub node: NodeId,
14 pub kind: String,
15 pub data: FileStructValue,
16 pub node_range: Option<Vec<NodeId>>,
17}
18
19#[derive(Clone, PartialEq, Eq, Debug)]
20pub enum FileStructValue {
21 MethodName(String),
22 Children(BTreeMap<String, FileStructData>),
23}
24
25#[derive(Clone, PartialEq, Eq, Debug)]
26pub struct FileInstanceData {
27 pub object: String,
28 pub source: String,
29 pub source_type: String,
30}
31
32#[derive(Clone, PartialEq, Eq, Debug, EnumDiscriminants)]
33#[strum_discriminants(name(SyntaxKind), derive(PartialOrd, Ord, Hash, IntoStaticStr))]
34pub enum SyntaxNode {
35 Annotation {
36 name: String,
37 arguments_id: Option<NodeId>,
38 },
39 Argument,
40 ArgumentList,
41 ArrayInitializer,
42 Assignment {
43 variable_id: NodeId,
44 value_id: Option<NodeId>,
45 operator: Option<String>,
46 },
47 Attribute {
48 name: String,
49 },
50 AwaitExpression {
51 expression_id: NodeId,
52 },
53 BinaryOperation {
54 operator: String,
55 left_id: Option<NodeId>,
56 right_id: Option<NodeId>,
57 },
58 Break,
59 CatchClause {
60 block_id: Option<NodeId>,
61 catch_declaration: Option<NodeId>,
62 },
63 CatchDeclaration,
64 Class {
65 name: String,
66 block_id: Option<NodeId>,
67 modifiers_id: Option<NodeId>,
68 inherited_class: Option<String>,
69 access_modifiers: Option<String>,
70 },
71 ClassBody,
72 Comment {
73 comment: String,
74 },
75 Continue,
76 Declaration {
77 name: String,
78 block_id: Option<NodeId>,
79 access_modifiers: Option<String>,
80 },
81 DeclarationBlock,
82 Default,
83 DoStatement {
84 block_id: NodeId,
85 condition_id: NodeId,
86 },
87 ElementAccess {
88 expression_id: NodeId,
89 arguments_id: Option<NodeId>,
90 },
91 ElseClause {
92 block_id: NodeId,
93 },
94 ExecutionBlock,
95 Export {
96 expression: Option<String>,
97 declaration_id: Option<NodeId>,
98 },
99 ExpressionStatement,
100 File,
101 FinallyClause {
102 block_id: Option<NodeId>,
103 },
104 ForEachStatement {
105 variable_id: NodeId,
106 iterable_item_id: NodeId,
107 block_id: Option<NodeId>,
108 },
109 ForStatement {
110 block_id: NodeId,
111 initializer_id: Option<NodeId>,
112 condition_id: Option<NodeId>,
113 update_id: Option<NodeId>,
114 },
115 If {
116 condition_id: NodeId,
117 true_id: Option<NodeId>,
118 false_id: Option<NodeId>,
119 initializer: Option<NodeId>,
120 },
121 Import {
122 expression: Option<String>,
123 alias: Option<String>,
124 method_name: Option<String>,
125 import_type: Option<String>,
126 },
127 JsxElement,
128 LambdaFunctionType,
129 Literal {
130 value: String,
131 value_type: String,
132 },
133 MemberAccess {
134 member: String,
135 expression: String,
136 expression_id: NodeId,
137 symbol_scope: Option<NodeId>,
138 },
139 Metadata {
140 path: String,
141 structure: BTreeMap<String, FileStructData>,
142 instances: BTreeMap<String, BTreeMap<String, FileInstanceData>>,
143 imports: Vec<String>,
144 package: Option<String>,
145 },
146 MethodDeclaration {
147 name: Option<String>,
148 access_modifiers: Option<String>,
149 block_id: Option<NodeId>,
150 modifiers_id: Option<NodeId>,
151 parameters_id: Option<NodeId>,
152 },
153 MethodInvocation {
154 expression: String,
155 object: Option<String>,
156 symbol_scope: Option<NodeId>,
157 expression_id: Option<NodeId>,
158 arguments_id: Option<NodeId>,
159 object_id: Option<NodeId>,
160 block_id: Option<NodeId>,
161 receiver_type_fqn: Option<String>,
162 },
163 MissingNode {
164 node_type: String,
165 },
166 Modifiers,
167 ModuleImport {
168 expression: String,
169 alias: Option<String>,
170 },
171 NamedArgument {
172 value_id: NodeId,
173 argument_name: Option<String>,
174 },
175 Namespace {
176 name: String,
177 block_id: Option<NodeId>,
178 },
179 NewExpression {
180 constructor_id: NodeId,
181 arguments_id: Option<NodeId>,
182 },
183 Object {
184 name: Option<String>,
185 tf_reference: Option<String>,
186 },
187 ObjectCreation {
188 name: String,
189 arguments_id: Option<NodeId>,
190 initializer_id: Option<NodeId>,
191 },
192 Pair {
193 key_id: NodeId,
194 value_id: NodeId,
195 },
196 Parameter {
197 variable: Option<String>,
198 variable_type: Option<String>,
199 value_id: Option<NodeId>,
200 parameter_mode: Option<String>,
201 },
202 ParameterList,
203 ParenthesizedExpression,
204 ReservedWord {
205 value: String,
206 },
207 RestPattern {
208 value_id: NodeId,
209 },
210 Return {
211 value_id: Option<NodeId>,
212 },
213 Selector {
214 selector_name: Option<String>,
215 },
216 SpreadElement {
217 value_id: NodeId,
218 },
219 SwitchBody,
220 SwitchSection {
221 case_expression: String,
222 },
223 SwitchStatement {
224 block_id: NodeId,
225 value_id: NodeId,
226 },
227 SymbolLookup {
228 symbol: String,
229 symbol_scope: Option<NodeId>,
230 value: Option<String>,
231 },
232 TernaryOperation {
233 condition_id: NodeId,
234 true_id: NodeId,
235 false_id: NodeId,
236 },
237 This {
238 value: String,
239 },
240 ThrowStatement {
241 expression_id: Option<NodeId>,
242 },
243 TryStatement {
244 block_id: NodeId,
245 resources_id: Option<NodeId>,
246 },
247 UnaryExpression {
248 operator: String,
249 operand_id: NodeId,
250 },
251 UsingStatement {
252 block_id: NodeId,
253 declaration_id: Option<NodeId>,
254 },
255 VariableDeclaration {
256 variable: String,
257 variable_type: Option<String>,
258 value_id: Option<NodeId>,
259 variable_id: Option<NodeId>,
260 access_modifier: Option<String>,
261 },
262 WhileStatement {
263 block_id: NodeId,
264 condition_id: Option<NodeId>,
265 },
266}
267
268impl SyntaxNode {
269 #[must_use]
270 pub const fn block_id(&self) -> Option<NodeId> {
271 match self {
272 Self::CatchClause { block_id, .. }
273 | Self::Class { block_id, .. }
274 | Self::Declaration { block_id, .. }
275 | Self::FinallyClause { block_id }
276 | Self::ForEachStatement { block_id, .. }
277 | Self::MethodDeclaration { block_id, .. }
278 | Self::MethodInvocation { block_id, .. }
279 | Self::Namespace { block_id, .. } => *block_id,
280 Self::DoStatement { block_id, .. }
281 | Self::ElseClause { block_id }
282 | Self::ForStatement { block_id, .. }
283 | Self::SwitchStatement { block_id, .. }
284 | Self::TryStatement { block_id, .. }
285 | Self::UsingStatement { block_id, .. }
286 | Self::WhileStatement { block_id, .. } => Some(*block_id),
287 _ => None,
288 }
289 }
290
291 #[must_use]
292 pub fn name(&self) -> Option<&str> {
293 match self {
294 Self::Annotation { name, .. }
295 | Self::Attribute { name }
296 | Self::Class { name, .. }
297 | Self::Declaration { name, .. }
298 | Self::Namespace { name, .. }
299 | Self::ObjectCreation { name, .. } => Some(name.as_str()),
300 Self::MethodDeclaration { name, .. } | Self::Object { name, .. } => name.as_deref(),
301 _ => None,
302 }
303 }
304
305 #[must_use]
306 pub fn variable(&self) -> Option<&str> {
307 match self {
308 Self::VariableDeclaration { variable, .. } => Some(variable.as_str()),
309 Self::Parameter { variable, .. } => variable.as_deref(),
310 _ => None,
311 }
312 }
313
314 #[must_use]
315 pub const fn symbol(&self) -> Option<&str> {
316 match self {
317 Self::SymbolLookup { symbol, .. } => Some(symbol.as_str()),
318 _ => None,
319 }
320 }
321
322 #[must_use]
323 pub fn expression(&self) -> Option<&str> {
324 match self {
325 Self::MemberAccess { expression, .. }
326 | Self::MethodInvocation { expression, .. }
327 | Self::ModuleImport { expression, .. } => Some(expression.as_str()),
328 Self::Export { expression, .. } | Self::Import { expression, .. } => {
329 expression.as_deref()
330 }
331 _ => None,
332 }
333 }
334
335 #[must_use]
336 pub fn alias(&self) -> Option<&str> {
337 match self {
338 Self::Import { alias, .. } | Self::ModuleImport { alias, .. } => alias.as_deref(),
339 _ => None,
340 }
341 }
342
343 #[must_use]
344 pub fn value(&self) -> Option<&str> {
345 match self {
346 Self::Literal { value, .. } | Self::ReservedWord { value } | Self::This { value } => {
347 Some(value.as_str())
348 }
349 Self::SymbolLookup { value, .. } => value.as_deref(),
350 _ => None,
351 }
352 }
353
354 #[must_use]
355 pub const fn value_id(&self) -> Option<NodeId> {
356 match self {
357 Self::Assignment { value_id, .. }
358 | Self::Parameter { value_id, .. }
359 | Self::Return { value_id }
360 | Self::VariableDeclaration { value_id, .. } => *value_id,
361 Self::NamedArgument { value_id, .. }
362 | Self::Pair { value_id, .. }
363 | Self::RestPattern { value_id }
364 | Self::SpreadElement { value_id }
365 | Self::SwitchStatement { value_id, .. } => Some(*value_id),
366 _ => None,
367 }
368 }
369
370 #[must_use]
371 pub const fn variable_id(&self) -> Option<NodeId> {
372 match self {
373 Self::VariableDeclaration { variable_id, .. } => *variable_id,
374 Self::Assignment { variable_id, .. } | Self::ForEachStatement { variable_id, .. } => {
375 Some(*variable_id)
376 }
377 _ => None,
378 }
379 }
380
381 #[must_use]
382 pub(crate) const fn symbol_scope(&self) -> Option<NodeId> {
383 match self {
384 Self::MemberAccess { symbol_scope, .. }
385 | Self::MethodInvocation { symbol_scope, .. }
386 | Self::SymbolLookup { symbol_scope, .. } => *symbol_scope,
387 _ => None,
388 }
389 }
390
391 #[must_use]
392 pub fn label_type(&self) -> &'static str {
393 SyntaxKind::from(self).into()
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::SyntaxNode;
400 use alloc::borrow::ToOwned;
401
402 #[test]
403 fn label_type_pins_the_contract_strings() {
404 assert_eq!(SyntaxNode::Default.label_type(), "Default");
405 assert_eq!(SyntaxNode::Break.label_type(), "Break");
406 assert_eq!(SyntaxNode::ArgumentList.label_type(), "ArgumentList");
407 assert_eq!(
408 SyntaxNode::Attribute {
409 name: "route".to_owned(),
410 }
411 .label_type(),
412 "Attribute"
413 );
414 assert_eq!(
415 SyntaxNode::MissingNode {
416 node_type: "stream".to_owned(),
417 }
418 .label_type(),
419 "MissingNode"
420 );
421 }
422}