use oxc::ast::ast::{
BindingIdentifier, Function, IdentifierReference, VariableDeclarator,
};
use oxc::semantic::{Scoping, SymbolId};
#[inline]
pub fn get_reference_symbol(scoping: &Scoping, ident: &IdentifierReference) -> Option<SymbolId> {
let ref_id = ident.reference_id.get()?;
scoping.get_reference(ref_id).symbol_id()
}
#[inline]
pub fn get_binding_symbol(binding: &BindingIdentifier) -> Option<SymbolId> {
binding.symbol_id.get()
}
#[inline]
pub fn get_declarator_symbol(decl: &VariableDeclarator) -> Option<SymbolId> {
decl.id.get_binding_identifier().and_then(|b| b.symbol_id.get())
}
#[inline]
pub fn get_function_symbol(func: &Function) -> Option<SymbolId> {
func.id.as_ref().and_then(|id| id.symbol_id.get())
}
#[cfg(test)]
mod tests {
use super::*;
use oxc::allocator::Allocator;
use oxc::ast::ast::Statement;
use oxc::parser::Parser;
use oxc::semantic::SemanticBuilder;
use oxc::span::SourceType;
#[test]
fn test_resolve_const() {
let source = "const x = 42; x;";
let alloc = Allocator::default();
let ret = Parser::new(&alloc, source, SourceType::mjs()).parse();
let scoping = SemanticBuilder::new().build(&ret.program).semantic.into_scoping();
if let Statement::ExpressionStatement(stmt) = &ret.program.body[1] {
if let oxc::ast::ast::Expression::Identifier(ident) = &stmt.expression {
let sym = get_reference_symbol(&scoping, ident);
assert!(sym.is_some(), "should resolve const x");
}
}
}
#[test]
fn test_global_is_none() {
let source = "console.log(1);";
let alloc = Allocator::default();
let ret = Parser::new(&alloc, source, SourceType::mjs()).parse();
let scoping = SemanticBuilder::new().build(&ret.program).semantic.into_scoping();
if let Statement::ExpressionStatement(stmt) = &ret.program.body[0] {
if let oxc::ast::ast::Expression::CallExpression(call) = &stmt.expression {
if let oxc::ast::ast::Expression::StaticMemberExpression(member) = &call.callee {
if let oxc::ast::ast::Expression::Identifier(ident) = &member.object {
let sym = get_reference_symbol(&scoping, ident);
assert!(sym.is_none(), "console should be unresolved (global)");
}
}
}
}
}
#[test]
fn test_get_declarator_symbol() {
let alloc = Allocator::default();
let ret = Parser::new(&alloc, "const x = 1;", SourceType::mjs()).parse();
let _scoping = SemanticBuilder::new().build(&ret.program).semantic.into_scoping();
if let Statement::VariableDeclaration(decl) = &ret.program.body[0] {
let sym = get_declarator_symbol(&decl.declarations[0]);
assert!(sym.is_some(), "declarator should have symbol ID");
}
}
#[test]
fn test_get_function_symbol() {
let alloc = Allocator::default();
let ret = Parser::new(&alloc, "function foo() {}", SourceType::mjs()).parse();
let _scoping = SemanticBuilder::new().build(&ret.program).semantic.into_scoping();
if let Statement::FunctionDeclaration(func) = &ret.program.body[0] {
let sym = get_function_symbol(func);
assert!(sym.is_some(), "named function should have symbol ID");
}
}
}