use alloc::string::String;
use crate::syntax::builders::import_statement::{build_import_node, ImportElement, ImportLabel};
use crate::syntax::SyntaxNode;
use crate::syntax::{SyntaxGraphArgs, SyntaxGraphError};
use crate::NodeId;
#[allow(
dead_code,
reason = "wired when a consuming language reader lands, #26623"
)]
#[allow(
clippy::too_many_arguments,
reason = "mirrors the Python build_export_statement_node inputs"
)]
pub fn build_export_statement_node(
args: &mut SyntaxGraphArgs<'_>,
n_id: NodeId,
expression: Option<String>,
exported_block: Option<NodeId>,
reexport_specifiers: &[(NodeId, String, Option<String>)],
default_export: Option<NodeId>,
) -> Result<NodeId, SyntaxGraphError> {
args.syntax_graph.add_node(
n_id,
SyntaxNode::Export {
expression: expression.filter(|value| !value.is_empty()),
declaration_id: exported_block,
},
);
if let Some(exported_block) = exported_block {
let built = args.generic(exported_block)?;
args.syntax_graph.add_ast_edge(n_id, built);
}
for (spec_n_id, spec_expression, spec_alias) in reexport_specifiers {
build_import_node(
args,
*spec_n_id,
&ImportElement {
expression: Some(spec_expression.clone()),
alias: spec_alias.clone(),
label_type: ImportLabel::ModuleImport,
..ImportElement::default()
},
)?;
}
if let Some(default_keyword_nid) = default_export {
args.syntax_graph
.add_node(default_keyword_nid, SyntaxNode::Default);
}
Ok(n_id)
}
#[cfg(test)]
mod tests {
use super::build_export_statement_node;
use crate::ast::{AstGraph, AstNode};
use crate::syntax::{
SyntaxGraph, SyntaxGraphArgs, SyntaxGraphError, SyntaxMetadata, SyntaxNode, SyntaxReader,
};
use crate::{Language, NodeId};
use alloc::borrow::ToOwned;
use alloc::string::String;
fn no_dispatch(_: &str) -> Option<SyntaxReader> {
None
}
#[test]
fn the_exported_block_reexports_and_default_keyword_are_all_wired() {
let mut ast = AstGraph::new();
ast.add_node(NodeId(2), AstNode::new(1, 1, "declaration".to_owned()));
let mut graph = SyntaxGraph::new();
let mut meta = SyntaxMetadata::seeded(NodeId(10));
let result = {
let mut args = SyntaxGraphArgs::new(
Language::JavaScript,
&ast,
&mut graph,
&mut meta,
no_dispatch,
);
build_export_statement_node(
&mut args,
NodeId(1),
Some(String::from("default")),
Some(NodeId(2)),
&[(NodeId(3), String::from("./module"), Some(String::from("m")))],
Some(NodeId(4)),
)
};
let built_id = result.expect("the builder must succeed");
assert_eq!(built_id, NodeId(1));
let Some(SyntaxNode::Export {
expression,
declaration_id,
}) = graph.nodes.get(&NodeId(1))
else {
panic!("the builder must emit the expected node");
};
assert_eq!(expression.as_deref(), Some("default"));
assert_eq!(*declaration_id, Some(NodeId(2)));
assert!(graph
.edges
.get(&NodeId(1))
.is_some_and(|adjacent| adjacent.contains_key(&NodeId(2))));
let Some(SyntaxNode::ModuleImport {
expression: reexport_expression,
alias: reexport_alias,
}) = graph.nodes.get(&NodeId(3))
else {
panic!("the reexport specifier must be wired as a ModuleImport node");
};
assert_eq!(reexport_expression, "./module");
assert_eq!(reexport_alias.as_deref(), Some("m"));
assert!(matches!(
graph.nodes.get(&NodeId(4)),
Some(SyntaxNode::Default)
));
}
#[test]
fn empty_expression_is_normalized_to_none_and_optional_fields_are_skipped() {
let ast = AstGraph::new();
let mut graph = SyntaxGraph::new();
let mut meta = SyntaxMetadata::seeded(NodeId(10));
let result = {
let mut args = SyntaxGraphArgs::new(
Language::JavaScript,
&ast,
&mut graph,
&mut meta,
no_dispatch,
);
build_export_statement_node(&mut args, NodeId(1), Some(String::new()), None, &[], None)
};
let built_id = result.expect("the builder must succeed");
assert_eq!(built_id, NodeId(1));
let Some(SyntaxNode::Export {
expression,
declaration_id,
}) = graph.nodes.get(&NodeId(1))
else {
panic!("the builder must emit the expected node");
};
assert_eq!(*expression, None);
assert_eq!(*declaration_id, None);
assert!(!graph.nodes.contains_key(&NodeId(4)));
}
#[test]
fn missing_exported_block_ast_node_propagates_the_error() {
let ast = AstGraph::new();
let mut graph = SyntaxGraph::new();
let mut meta = SyntaxMetadata::seeded(NodeId(10));
let result = {
let mut args = SyntaxGraphArgs::new(
Language::JavaScript,
&ast,
&mut graph,
&mut meta,
no_dispatch,
);
build_export_statement_node(&mut args, NodeId(1), None, Some(NodeId(2)), &[], None)
};
assert!(matches!(result, Err(SyntaxGraphError::MissingAstNode)));
}
}