use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use strum::{EnumDiscriminants, IntoStaticStr};
use crate::NodeId;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FileStructData {
pub node: NodeId,
pub kind: String,
pub data: FileStructValue,
pub node_range: Option<Vec<NodeId>>,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum FileStructValue {
MethodName(String),
Children(BTreeMap<String, FileStructData>),
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FileInstanceData {
pub object: String,
pub source: String,
pub source_type: String,
}
#[derive(Clone, PartialEq, Eq, Debug, EnumDiscriminants)]
#[strum_discriminants(name(SyntaxKind), derive(PartialOrd, Ord, Hash, IntoStaticStr))]
pub enum SyntaxNode {
Annotation {
name: String,
arguments_id: Option<NodeId>,
},
Argument,
ArgumentList,
ArrayInitializer,
Assignment {
variable_id: NodeId,
value_id: Option<NodeId>,
operator: Option<String>,
},
Attribute {
name: String,
},
AwaitExpression {
expression_id: NodeId,
},
BinaryOperation {
operator: String,
left_id: Option<NodeId>,
right_id: Option<NodeId>,
},
Break,
CatchClause {
block_id: Option<NodeId>,
catch_declaration: Option<NodeId>,
},
CatchDeclaration,
Class {
name: String,
block_id: Option<NodeId>,
modifiers_id: Option<NodeId>,
inherited_class: Option<String>,
access_modifiers: Option<String>,
},
ClassBody,
Comment {
comment: String,
},
Continue,
Declaration {
name: String,
block_id: Option<NodeId>,
access_modifiers: Option<String>,
},
DeclarationBlock,
Default,
DoStatement {
block_id: NodeId,
condition_id: NodeId,
},
ElementAccess {
expression_id: NodeId,
arguments_id: Option<NodeId>,
},
ElseClause {
block_id: NodeId,
},
ExecutionBlock,
Export {
expression: Option<String>,
declaration_id: Option<NodeId>,
},
ExpressionStatement,
File,
FinallyClause {
block_id: Option<NodeId>,
},
ForEachStatement {
variable_id: NodeId,
iterable_item_id: NodeId,
block_id: Option<NodeId>,
},
ForStatement {
block_id: NodeId,
initializer_id: Option<NodeId>,
condition_id: Option<NodeId>,
update_id: Option<NodeId>,
},
If {
condition_id: NodeId,
true_id: Option<NodeId>,
false_id: Option<NodeId>,
initializer: Option<NodeId>,
},
Import {
expression: Option<String>,
alias: Option<String>,
method_name: Option<String>,
import_type: Option<String>,
},
JsxElement,
LambdaFunctionType,
Literal {
value: String,
value_type: String,
},
MemberAccess {
member: String,
expression: String,
expression_id: NodeId,
symbol_scope: Option<NodeId>,
},
Metadata {
path: String,
structure: BTreeMap<String, FileStructData>,
instances: BTreeMap<String, BTreeMap<String, FileInstanceData>>,
imports: Vec<String>,
package: Option<String>,
},
MethodDeclaration {
name: Option<String>,
access_modifiers: Option<String>,
block_id: Option<NodeId>,
modifiers_id: Option<NodeId>,
parameters_id: Option<NodeId>,
},
MethodInvocation {
expression: String,
object: Option<String>,
symbol_scope: Option<NodeId>,
expression_id: Option<NodeId>,
arguments_id: Option<NodeId>,
object_id: Option<NodeId>,
block_id: Option<NodeId>,
receiver_type_fqn: Option<String>,
},
MissingNode {
node_type: String,
},
Modifiers,
ModuleImport {
expression: String,
alias: Option<String>,
},
NamedArgument {
value_id: NodeId,
argument_name: Option<String>,
},
Namespace {
name: String,
block_id: Option<NodeId>,
},
NewExpression {
constructor_id: NodeId,
arguments_id: Option<NodeId>,
},
Object {
name: Option<String>,
tf_reference: Option<String>,
},
ObjectCreation {
name: String,
arguments_id: Option<NodeId>,
initializer_id: Option<NodeId>,
},
Pair {
key_id: NodeId,
value_id: NodeId,
},
Parameter {
variable: Option<String>,
variable_type: Option<String>,
value_id: Option<NodeId>,
parameter_mode: Option<String>,
},
ParameterList,
ParenthesizedExpression,
ReservedWord {
value: String,
},
RestPattern {
value_id: NodeId,
},
Return {
value_id: Option<NodeId>,
},
Selector {
selector_name: Option<String>,
},
SpreadElement {
value_id: NodeId,
},
SwitchBody,
SwitchSection {
case_expression: String,
},
SwitchStatement {
block_id: NodeId,
value_id: NodeId,
},
SymbolLookup {
symbol: String,
symbol_scope: Option<NodeId>,
value: Option<String>,
},
TernaryOperation {
condition_id: NodeId,
true_id: NodeId,
false_id: NodeId,
},
This {
value: String,
},
ThrowStatement {
expression_id: Option<NodeId>,
},
TryStatement {
block_id: NodeId,
resources_id: Option<NodeId>,
},
UnaryExpression {
operator: String,
operand_id: NodeId,
},
UsingStatement {
block_id: NodeId,
declaration_id: Option<NodeId>,
},
VariableDeclaration {
variable: String,
variable_type: Option<String>,
value_id: Option<NodeId>,
variable_id: Option<NodeId>,
access_modifier: Option<String>,
},
WhileStatement {
block_id: NodeId,
condition_id: Option<NodeId>,
},
}
impl SyntaxNode {
#[must_use]
pub const fn arguments_id(&self) -> Option<NodeId> {
match self {
Self::Annotation { arguments_id, .. }
| Self::ElementAccess { arguments_id, .. }
| Self::MethodInvocation { arguments_id, .. }
| Self::NewExpression { arguments_id, .. }
| Self::ObjectCreation { arguments_id, .. } => *arguments_id,
_ => None,
}
}
#[must_use]
pub const fn block_id(&self) -> Option<NodeId> {
match self {
Self::CatchClause { block_id, .. }
| Self::Class { block_id, .. }
| Self::Declaration { block_id, .. }
| Self::FinallyClause { block_id }
| Self::ForEachStatement { block_id, .. }
| Self::MethodDeclaration { block_id, .. }
| Self::MethodInvocation { block_id, .. }
| Self::Namespace { block_id, .. } => *block_id,
Self::DoStatement { block_id, .. }
| Self::ElseClause { block_id }
| Self::ForStatement { block_id, .. }
| Self::SwitchStatement { block_id, .. }
| Self::TryStatement { block_id, .. }
| Self::UsingStatement { block_id, .. }
| Self::WhileStatement { block_id, .. } => Some(*block_id),
_ => None,
}
}
#[must_use]
pub fn name(&self) -> Option<&str> {
match self {
Self::Annotation { name, .. }
| Self::Attribute { name }
| Self::Class { name, .. }
| Self::Declaration { name, .. }
| Self::Namespace { name, .. }
| Self::ObjectCreation { name, .. } => Some(name.as_str()),
Self::MethodDeclaration { name, .. } | Self::Object { name, .. } => name.as_deref(),
_ => None,
}
}
#[must_use]
pub fn variable(&self) -> Option<&str> {
match self {
Self::VariableDeclaration { variable, .. } => Some(variable.as_str()),
Self::Parameter { variable, .. } => variable.as_deref(),
_ => None,
}
}
#[must_use]
pub const fn symbol(&self) -> Option<&str> {
match self {
Self::SymbolLookup { symbol, .. } => Some(symbol.as_str()),
_ => None,
}
}
#[must_use]
pub fn expression(&self) -> Option<&str> {
match self {
Self::MemberAccess { expression, .. }
| Self::MethodInvocation { expression, .. }
| Self::ModuleImport { expression, .. } => Some(expression.as_str()),
Self::Export { expression, .. } | Self::Import { expression, .. } => {
expression.as_deref()
}
_ => None,
}
}
#[must_use]
pub fn alias(&self) -> Option<&str> {
match self {
Self::Import { alias, .. } | Self::ModuleImport { alias, .. } => alias.as_deref(),
_ => None,
}
}
#[must_use]
pub fn value(&self) -> Option<&str> {
match self {
Self::Literal { value, .. } | Self::ReservedWord { value } | Self::This { value } => {
Some(value.as_str())
}
Self::SymbolLookup { value, .. } => value.as_deref(),
_ => None,
}
}
#[must_use]
pub const fn object_id(&self) -> Option<NodeId> {
match self {
Self::MethodInvocation { object_id, .. } => *object_id,
_ => None,
}
}
#[must_use]
pub const fn value_id(&self) -> Option<NodeId> {
match self {
Self::Assignment { value_id, .. }
| Self::Parameter { value_id, .. }
| Self::Return { value_id }
| Self::VariableDeclaration { value_id, .. } => *value_id,
Self::NamedArgument { value_id, .. }
| Self::Pair { value_id, .. }
| Self::RestPattern { value_id }
| Self::SpreadElement { value_id }
| Self::SwitchStatement { value_id, .. } => Some(*value_id),
_ => None,
}
}
#[must_use]
pub const fn variable_id(&self) -> Option<NodeId> {
match self {
Self::VariableDeclaration { variable_id, .. } => *variable_id,
Self::Assignment { variable_id, .. } | Self::ForEachStatement { variable_id, .. } => {
Some(*variable_id)
}
_ => None,
}
}
#[must_use]
pub(crate) const fn symbol_scope(&self) -> Option<NodeId> {
match self {
Self::MemberAccess { symbol_scope, .. }
| Self::MethodInvocation { symbol_scope, .. }
| Self::SymbolLookup { symbol_scope, .. } => *symbol_scope,
_ => None,
}
}
#[must_use]
pub fn label_type(&self) -> &'static str {
SyntaxKind::from(self).into()
}
}
#[cfg(test)]
mod tests {
use super::SyntaxNode;
use alloc::borrow::ToOwned;
#[test]
fn label_type_pins_the_contract_strings() {
assert_eq!(SyntaxNode::Default.label_type(), "Default");
assert_eq!(SyntaxNode::Break.label_type(), "Break");
assert_eq!(SyntaxNode::ArgumentList.label_type(), "ArgumentList");
assert_eq!(
SyntaxNode::Attribute {
name: "route".to_owned(),
}
.label_type(),
"Attribute"
);
assert_eq!(
SyntaxNode::MissingNode {
node_type: "stream".to_owned(),
}
.label_type(),
"MissingNode"
);
}
}