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::query::{label_text, match_ast_group_d};
use crate::syntax::builders::export_statement::build_export_statement_node;
use crate::syntax::fields::javascript::{export_specifier, export_statement};
use crate::syntax::{SyntaxGraphArgs, SyntaxGraphError};
use crate::utilities::text_nodes::node_to_str;
use crate::{CodeGraph, NodeId};

fn reexport_specifier(
    args: &SyntaxGraphArgs<'_>,
    spec_id: NodeId,
    module_path: &str,
) -> Option<(NodeId, String, Option<String>)> {
    let graph = args.ast_graph;
    let name_id = args
        .required_field_alt(spec_id, export_specifier::NAME)
        .ok()?;
    let spec_name = label_text(graph, name_id).unwrap_or_default().to_owned();
    let spec_alias = args
        .optional_field_alt(spec_id, export_specifier::ALIAS)
        .and_then(|alias_id| label_text(graph, alias_id))
        .map_or_else(|| spec_name.clone(), ToOwned::to_owned);
    let mut expression = module_path.to_owned();
    expression.push('.');
    expression.push_str(&spec_name);
    Some((spec_id, expression, Some(spec_alias)))
}

fn collect_reexports(
    args: &SyntaxGraphArgs<'_>,
    n_id: NodeId,
    source_id: NodeId,
) -> Vec<(NodeId, String, Option<String>)> {
    let graph = args.ast_graph;
    let raw = node_to_str(graph, source_id);
    let module_path = raw
        .get(1..raw.len().saturating_sub(1))
        .unwrap_or_default()
        .to_owned();
    match_ast_group_d(graph, n_id, "export_clause", Some(1))
        .into_iter()
        .flat_map(|clause_id| match_ast_group_d(graph, clause_id, "export_specifier", Some(1)))
        .filter_map(|spec_id| reexport_specifier(args, spec_id, &module_path))
        .collect()
}

pub fn reader(
    args: &mut SyntaxGraphArgs<'_>,
    n_id: NodeId,
) -> Result<Option<NodeId>, SyntaxGraphError> {
    let graph = args.ast_graph;
    let mut expression: Option<String> = None;
    let mut export_block = args.optional_field_alt(n_id, export_statement::DECLARATION);

    if let Some(block) = export_block {
        if matches!(graph.label_type(block), Some("identifier" | "string")) {
            expression = Some(node_to_str(graph, block));
            export_block = None;
        }
    } else if let Some(child_id) = match_ast_group_d(graph, n_id, "identifier", Some(1))
        .first()
        .copied()
    {
        expression = Some(node_to_str(graph, child_id));
    }

    let reexport_specifiers = args
        .optional_field_alt(n_id, export_statement::SOURCE)
        .map(|source_id| collect_reexports(args, n_id, source_id))
        .unwrap_or_default();

    let default_export = match_ast_group_d(graph, n_id, "default", Some(1))
        .first()
        .copied();

    build_export_statement_node(
        args,
        n_id,
        expression,
        export_block,
        &reexport_specifiers,
        default_export,
    )
    .map(Some)
}