use tree_sitter::Node;
use crate::code::parser::{
imports::quoted_specifier,
nodes::{SyntaxRange, compact_whitespace, node_text, syntax_range},
};
pub(in crate::code::parser) fn dynamic_import(
language_id: &str,
content: &str,
node: Node<'_>,
) -> Option<(String, SyntaxRange)> {
if !matches!(language_id, "javascript" | "jsx" | "typescript" | "tsx")
|| node.kind() != "call_expression"
{
return None;
}
let function = node.child_by_field_name("function")?;
if function.kind() != "import" {
return None;
}
first_direct_string_argument(content, node.child_by_field_name("arguments")?)?;
let source = dynamic_import_source(content, node);
Some(source)
}
fn dynamic_import_source(content: &str, node: Node<'_>) -> (String, SyntaxRange) {
let source_node = node
.parent()
.filter(|parent| parent.kind() == "await_expression")
.unwrap_or(node);
(
compact_whitespace(&node_text(content, source_node)),
syntax_range(source_node),
)
}
fn first_direct_string_argument(content: &str, arguments: Node<'_>) -> Option<String> {
for index in 0..arguments.named_child_count() {
let Ok(index) = u32::try_from(index) else {
continue;
};
let child = arguments.named_child(index)?;
if matches!(child.kind(), "string" | "string_literal") {
return Some(node_text(content, child));
}
return None;
}
None
}
pub(in crate::code::parser) fn re_export(
language_id: &str,
content: &str,
node: Node<'_>,
) -> Option<(String, SyntaxRange)> {
if !matches!(language_id, "javascript" | "jsx" | "typescript" | "tsx")
|| node.kind() != "export_statement"
{
return None;
}
let source = node.child_by_field_name("source")?;
if !matches!(source.kind(), "string" | "string_literal")
|| quoted_specifier(&node_text(content, source)).is_none()
{
return None;
}
Some((
compact_whitespace(&node_text(content, node)),
syntax_range(node),
))
}
#[cfg(test)]
#[path = "imports_tests.rs"]
mod tests;