mod bindings;
mod macros;
use oxc_ast::ast::{Declaration, Expression, Statement};
use oxc_span::GetSpan;
use crate::analysis::{
ImportStatementInfo, InvalidExport, InvalidExportKind, ReExportInfo, TypeExport, TypeExportKind,
};
use crate::scope::{BlockKind, BlockScopeData, ClosureScopeData, ExternalModuleScopeData};
use crate::ScopeBinding;
use vize_carton::CompactString;
use vize_relief::BindingType;
use super::extract::{
detect_setup_context_violation, process_call_expression, process_invalid_export,
process_type_export,
};
use super::walk::{extract_function_params, walk_expression, walk_statement};
use super::ScriptParseResult;
pub fn process_statement(result: &mut ScriptParseResult, stmt: &Statement<'_>, source: &str) {
match stmt {
Statement::VariableDeclaration(decl) => {
for declarator in decl.declarations.iter() {
macros::process_variable_declarator(result, declarator, decl.kind, source);
}
}
Statement::FunctionDeclaration(func) => {
if let Some(id) = &func.id {
let name = id.name.as_str();
result.bindings.add(name, BindingType::SetupConst);
result
.binding_spans
.insert(CompactString::new(name), (id.span.start, id.span.end));
}
let params = extract_function_params(&func.params);
let name = func
.id
.as_ref()
.map(|id| CompactString::new(id.name.as_str()));
result.scopes.enter_closure_scope(
ClosureScopeData {
name,
param_names: params,
is_arrow: false,
is_async: func.r#async,
is_generator: func.generator,
},
func.span.start,
func.span.end,
);
if let Some(body) = &func.body {
for stmt in body.statements.iter() {
walk_statement(result, stmt, source);
}
}
result.scopes.exit_scope();
}
Statement::ClassDeclaration(class) => {
if let Some(id) = &class.id {
let name = id.name.as_str();
result.bindings.add(name, BindingType::SetupConst);
result
.binding_spans
.insert(CompactString::new(name), (id.span.start, id.span.end));
}
}
Statement::ExpressionStatement(expr_stmt) => {
if let Expression::CallExpression(call) = &expr_stmt.expression {
detect_setup_context_violation(result, call);
process_call_expression(result, call, source);
}
walk_expression(result, &expr_stmt.expression, source);
}
Statement::ImportDeclaration(import) => {
result.import_statements.push(ImportStatementInfo {
start: import.span.start,
end: import.span.end,
});
let is_type_only = import.import_kind.is_type();
let source_name = import.source.value.as_str();
let span = import.span;
result.scopes.enter_external_module_scope(
ExternalModuleScopeData {
source: CompactString::new(source_name),
is_type_only,
},
span.start,
span.end,
);
if let Some(specifiers) = &import.specifiers {
for spec in specifiers.iter() {
let (name, is_type_spec, local_span) = match spec {
oxc_ast::ast::ImportDeclarationSpecifier::ImportSpecifier(s) => {
(s.local.name.as_str(), s.import_kind.is_type(), s.local.span)
}
oxc_ast::ast::ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
(s.local.name.as_str(), false, s.local.span)
}
oxc_ast::ast::ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
(s.local.name.as_str(), false, s.local.span)
}
};
result
.binding_spans
.insert(CompactString::new(name), (local_span.start, local_span.end));
let binding_type = if is_type_only || is_type_spec {
BindingType::ExternalModule
} else {
match spec {
oxc_ast::ast::ImportDeclarationSpecifier::ImportSpecifier(_) => {
BindingType::SetupMaybeRef
}
_ => BindingType::SetupConst, }
};
result.scopes.add_binding(
CompactString::new(name),
ScopeBinding::new(binding_type, span.start),
);
if !is_type_only && !is_type_spec {
result.bindings.add(name, binding_type);
}
}
}
result.scopes.exit_scope();
}
Statement::ExportNamedDeclaration(export) => {
if export.source.is_some() {
result.re_exports.push(ReExportInfo {
start: export.span.start,
end: export.span.end,
});
return;
}
if let Some(decl) = &export.declaration {
match decl {
Declaration::TSTypeAliasDeclaration(_)
| Declaration::TSInterfaceDeclaration(_) => {
process_type_export(result, decl, stmt.span());
}
_ => {
if export.export_kind.is_type() {
process_type_export(result, decl, stmt.span());
} else {
process_invalid_export(result, decl, stmt.span());
}
}
}
}
}
Statement::ExportDefaultDeclaration(export) => {
result.invalid_exports.push(InvalidExport {
name: CompactString::new("default"),
kind: InvalidExportKind::Default,
start: export.span.start,
end: export.span.end,
});
}
Statement::TSTypeAliasDeclaration(type_alias) => {
let name = type_alias.id.name.as_str();
result.type_exports.push(TypeExport {
name: CompactString::new(name),
kind: TypeExportKind::Type,
start: type_alias.span.start,
end: type_alias.span.end,
hoisted: true,
});
}
Statement::TSInterfaceDeclaration(interface) => {
let name = interface.id.name.as_str();
result.type_exports.push(TypeExport {
name: CompactString::new(name),
kind: TypeExportKind::Interface,
start: interface.span.start,
end: interface.span.end,
hoisted: true,
});
}
Statement::BlockStatement(block) => {
result.scopes.enter_block_scope(
BlockScopeData {
kind: BlockKind::Block,
},
block.span.start,
block.span.end,
);
for stmt in block.body.iter() {
walk_statement(result, stmt, source);
}
result.scopes.exit_scope();
}
_ => {}
}
}