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 arguments_id(&self) -> Option<NodeId> {
271 match self {
272 Self::Annotation { arguments_id, .. }
273 | Self::ElementAccess { arguments_id, .. }
274 | Self::MethodInvocation { arguments_id, .. }
275 | Self::NewExpression { arguments_id, .. }
276 | Self::ObjectCreation { arguments_id, .. } => *arguments_id,
277 _ => None,
278 }
279 }
280
281 #[must_use]
282 pub const fn block_id(&self) -> Option<NodeId> {
283 match self {
284 Self::CatchClause { block_id, .. }
285 | Self::Class { block_id, .. }
286 | Self::Declaration { block_id, .. }
287 | Self::FinallyClause { block_id }
288 | Self::ForEachStatement { block_id, .. }
289 | Self::MethodDeclaration { block_id, .. }
290 | Self::MethodInvocation { block_id, .. }
291 | Self::Namespace { block_id, .. } => *block_id,
292 Self::DoStatement { block_id, .. }
293 | Self::ElseClause { block_id }
294 | Self::ForStatement { block_id, .. }
295 | Self::SwitchStatement { block_id, .. }
296 | Self::TryStatement { block_id, .. }
297 | Self::UsingStatement { block_id, .. }
298 | Self::WhileStatement { block_id, .. } => Some(*block_id),
299 _ => None,
300 }
301 }
302
303 #[must_use]
304 pub fn name(&self) -> Option<&str> {
305 match self {
306 Self::Annotation { name, .. }
307 | Self::Attribute { name }
308 | Self::Class { name, .. }
309 | Self::Declaration { name, .. }
310 | Self::Namespace { name, .. }
311 | Self::ObjectCreation { name, .. } => Some(name.as_str()),
312 Self::MethodDeclaration { name, .. } | Self::Object { name, .. } => name.as_deref(),
313 _ => None,
314 }
315 }
316
317 #[must_use]
318 pub fn variable(&self) -> Option<&str> {
319 match self {
320 Self::VariableDeclaration { variable, .. } => Some(variable.as_str()),
321 Self::Parameter { variable, .. } => variable.as_deref(),
322 _ => None,
323 }
324 }
325
326 #[must_use]
327 pub const fn symbol(&self) -> Option<&str> {
328 match self {
329 Self::SymbolLookup { symbol, .. } => Some(symbol.as_str()),
330 _ => None,
331 }
332 }
333
334 #[must_use]
335 pub fn expression(&self) -> Option<&str> {
336 match self {
337 Self::MemberAccess { expression, .. }
338 | Self::MethodInvocation { expression, .. }
339 | Self::ModuleImport { expression, .. } => Some(expression.as_str()),
340 Self::Export { expression, .. } | Self::Import { expression, .. } => {
341 expression.as_deref()
342 }
343 _ => None,
344 }
345 }
346
347 #[must_use]
348 pub fn alias(&self) -> Option<&str> {
349 match self {
350 Self::Import { alias, .. } | Self::ModuleImport { alias, .. } => alias.as_deref(),
351 _ => None,
352 }
353 }
354
355 #[must_use]
356 pub fn value(&self) -> Option<&str> {
357 match self {
358 Self::Literal { value, .. } | Self::ReservedWord { value } | Self::This { value } => {
359 Some(value.as_str())
360 }
361 Self::SymbolLookup { value, .. } => value.as_deref(),
362 _ => None,
363 }
364 }
365
366 #[must_use]
367 pub const fn object_id(&self) -> Option<NodeId> {
368 match self {
369 Self::MethodInvocation { object_id, .. } => *object_id,
370 _ => None,
371 }
372 }
373
374 #[must_use]
375 pub const fn value_id(&self) -> Option<NodeId> {
376 match self {
377 Self::Assignment { value_id, .. }
378 | Self::Parameter { value_id, .. }
379 | Self::Return { value_id }
380 | Self::VariableDeclaration { value_id, .. } => *value_id,
381 Self::NamedArgument { value_id, .. }
382 | Self::Pair { value_id, .. }
383 | Self::RestPattern { value_id }
384 | Self::SpreadElement { value_id }
385 | Self::SwitchStatement { value_id, .. } => Some(*value_id),
386 _ => None,
387 }
388 }
389
390 #[must_use]
391 pub const fn variable_id(&self) -> Option<NodeId> {
392 match self {
393 Self::VariableDeclaration { variable_id, .. } => *variable_id,
394 Self::Assignment { variable_id, .. } | Self::ForEachStatement { variable_id, .. } => {
395 Some(*variable_id)
396 }
397 _ => None,
398 }
399 }
400
401 #[must_use]
402 pub(crate) const fn symbol_scope(&self) -> Option<NodeId> {
403 match self {
404 Self::MemberAccess { symbol_scope, .. }
405 | Self::MethodInvocation { symbol_scope, .. }
406 | Self::SymbolLookup { symbol_scope, .. } => *symbol_scope,
407 _ => None,
408 }
409 }
410
411 #[must_use]
412 pub fn label_type(&self) -> &'static str {
413 SyntaxKind::from(self).into()
414 }
415}
416
417#[cfg(test)]
418mod tests {
419 use super::SyntaxNode;
420 use alloc::borrow::ToOwned;
421
422 #[test]
423 fn label_type_pins_the_contract_strings() {
424 assert_eq!(SyntaxNode::Default.label_type(), "Default");
425 assert_eq!(SyntaxNode::Break.label_type(), "Break");
426 assert_eq!(SyntaxNode::ArgumentList.label_type(), "ArgumentList");
427 assert_eq!(
428 SyntaxNode::Attribute {
429 name: "route".to_owned(),
430 }
431 .label_type(),
432 "Attribute"
433 );
434 assert_eq!(
435 SyntaxNode::MissingNode {
436 node_type: "stream".to_owned(),
437 }
438 .label_type(),
439 "MissingNode"
440 );
441 }
442}