relay-knowledge 1.1.17

Graph-database-based knowledge graph project.
Documentation
use tree_sitter::{Language, Node, Parser};

use super::{dynamic_import, re_export};

#[test]
fn javascript_re_exports_require_an_ast_source_field() {
    let source = r#"
export { createClient } from "@scope/client";
export * from "./runtime.js";
export function marketplaceCopy() {
    return `Choose provider and model from the marketplace`;
}
"#;

    assert_eq!(
        javascript_re_exports("javascript", source),
        [
            "export { createClient } from \"@scope/client\";",
            "export * from \"./runtime.js\";",
        ]
    );
}

#[test]
fn typescript_re_exports_require_an_ast_source_field() {
    let source = r#"
export type { RuntimeConfig } from "@scope/runtime";
export { RuntimeController } from "./controller";
export function renderTemplate(): string {
    return `This deliberately says from inside an ordinary exported function`;
}
"#;

    assert_eq!(
        javascript_re_exports("typescript", source),
        [
            "export type { RuntimeConfig } from \"@scope/runtime\";",
            "export { RuntimeController } from \"./controller\";",
        ]
    );
}

#[test]
fn exported_function_with_large_template_is_not_an_import() {
    let template = format!(
        "export function renderMarkup() {{ return `{} from the marketplace`; }}",
        "x".repeat(40 * 1_024)
    );

    assert!(javascript_re_exports("javascript", &template).is_empty());
}

#[test]
fn dynamic_imports_remain_module_edges() {
    let source = r#"
async function loadRuntime() {
    return await import("@scope/runtime/client");
}
"#;
    let tree = parse(source, javascript_language());
    let mut imports = Vec::new();
    visit_nodes(tree.root_node(), &mut |node| {
        if let Some((module, _)) = dynamic_import("javascript", source, node) {
            imports.push(module);
        }
    });

    assert_eq!(imports, ["await import(\"@scope/runtime/client\")"]);
}

fn javascript_re_exports(language_id: &str, source: &str) -> Vec<String> {
    let language = match language_id {
        "javascript" => javascript_language(),
        "typescript" => typescript_language(),
        other => panic!("unsupported test language {other}"),
    };
    let tree = parse(source, language);
    let mut imports = Vec::new();
    visit_nodes(tree.root_node(), &mut |node| {
        if let Some((module, _)) = re_export(language_id, source, node) {
            imports.push(module);
        }
    });
    imports
}

fn parse(source: &str, language: Language) -> tree_sitter::Tree {
    let mut parser = Parser::new();
    parser
        .set_language(&language)
        .expect("test grammar should be compatible");
    parser
        .parse(source, None)
        .expect("test source should parse")
}

fn visit_nodes(node: Node<'_>, visit: &mut impl FnMut(Node<'_>)) {
    visit(node);
    for index in 0..node.child_count() {
        let Ok(index) = u32::try_from(index) else {
            continue;
        };
        if let Some(child) = node.child(index) {
            visit_nodes(child, visit);
        }
    }
}

fn javascript_language() -> Language {
    tree_sitter_javascript::LANGUAGE.into()
}

fn typescript_language() -> Language {
    tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()
}