fluidattacks-blends-domain 0.6.1

Blends functional core: pure AST graph to syntax graph (no_std)
Documentation
use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::vec::Vec;

use crate::ast::AstGraph;
use crate::query::{get_node_by_path, label_text, match_ast_d, match_ast_group, match_ast_group_d};
use crate::syntax::builders::import_global::build_import_global_node;
use crate::syntax::fields::javascript::import_statement;
use crate::syntax::readers::javascript::common::strip_quotes;
use crate::syntax::{SyntaxGraphArgs, SyntaxGraphError};
use crate::utilities::text_nodes::node_to_str;
use crate::NodeId;

pub fn reader(
    args: &mut SyntaxGraphArgs<'_>,
    n_id: NodeId,
) -> Result<Option<NodeId>, SyntaxGraphError> {
    let graph = args.ast_graph;
    let mut expression = args
        .required_field_alt(n_id, import_statement::SOURCE)
        .ok()
        .map(|source_id| strip_quotes(&node_to_str(graph, source_id)))
        .unwrap_or_default();

    let import_clauses = match_ast_group(
        graph,
        n_id,
        &["import_clause", "import_require_clause"],
        None,
    );
    let clause0 = import_clauses
        .get("import_clause")
        .filter(|v| !v.is_empty())
        .or_else(|| {
            import_clauses
                .get("import_require_clause")
                .filter(|v| !v.is_empty())
        })
        .and_then(|v| v.first().copied());

    let (alias, module_nodes) =
        clause0.map_or((None, Vec::new()), |clause| resolve_imports(graph, clause));

    if let Some(req0) = import_clauses
        .get("import_require_clause")
        .and_then(|v| v.first().copied())
    {
        if let Some(exp_id) = get_node_by_path(graph, req0, &["string", "string_fragment"]) {
            expression = label_text(graph, exp_id)
                .map(ToOwned::to_owned)
                .unwrap_or_default();
        }
    }

    build_import_global_node(args, n_id, expression, &module_nodes, alias).map(Some)
}

fn resolve_imports(graph: &AstGraph, clause: NodeId) -> (Option<String>, Vec<NodeId>) {
    let imports = match_ast_group(
        graph,
        clause,
        &["namespace_import", "named_imports", "identifier"],
        None,
    );
    let ns_identifier = imports
        .get("namespace_import")
        .and_then(|v| v.first())
        .and_then(|ns| match_ast_d(graph, *ns, "identifier", None));
    let first_identifier = imports.get("identifier").and_then(|v| v.first().copied());

    let mut alias = None;
    let mut module_nodes = Vec::new();
    if let Some(id) = ns_identifier.or(first_identifier) {
        alias = label_text(graph, id).map(ToOwned::to_owned);
    } else if let Some(named0) = imports
        .get("named_imports")
        .and_then(|v| v.first().copied())
    {
        module_nodes.extend(match_ast_group_d(graph, named0, "import_specifier", None));
    }
    if imports.get("identifier").is_some_and(|v| !v.is_empty()) {
        if let Some(named0) = imports
            .get("named_imports")
            .and_then(|v| v.first().copied())
        {
            module_nodes.extend(match_ast_group_d(graph, named0, "import_specifier", None));
        }
    }
    (alias, module_nodes)
}