weavatrix-parse 0.3.5

Dependency-free source tokenizer and structural extractor for repository intelligence
Documentation
use super::*;

#[test]
fn exported_function_extent_includes_its_body() {
    let source = "export function canDelete(viewer) {\n  return !viewer;\n}\n";
    let facts = extract(source, Language::JavaScript);
    let declaration = facts
        .declarations
        .iter()
        .find(|item| item.name == "canDelete")
        .expect("the exported function is declared");

    assert_eq!(
        &source[declaration.extent.start..declaration.extent.end],
        "export function canDelete(viewer) {\n  return !viewer;\n}"
    );
}

#[test]
fn class_bodies_yield_methods_and_fields_with_their_owner() {
    let source = "export class Service {\n\
         \x20 private cache = new Map();\n\
         \x20 readonly limit: number = 10;\n\
         \x20 async run(input: string) {\n\
         \x20   return this.helper(input);\n\
         \x20 }\n\
         \x20 helper(value: string) { return value; }\n\
         }\n";
    let facts = extract(source, Language::TypeScript);
    let declared = facts
        .declarations
        .iter()
        .map(|item| (item.name.as_str(), item.kind, item.owner.as_deref()))
        .collect::<Vec<_>>();
    assert!(
        declared.contains(&("Service", DeclarationKind::Class, None)),
        "got {declared:?}"
    );
    assert!(
        declared.contains(&("run", DeclarationKind::Method, Some("Service"))),
        "a class method is a declaration owned by its class, got {declared:?}"
    );
    assert!(
        declared.contains(&("helper", DeclarationKind::Method, Some("Service"))),
        "got {declared:?}"
    );
    assert!(
        declared.contains(&("cache", DeclarationKind::Field, Some("Service"))),
        "got {declared:?}"
    );
    let call = facts
        .references
        .iter()
        .find(|call| call.name == "helper")
        .expect("the call inside run is recorded");
    assert_eq!(call.receiver.as_deref(), Some("this"));
    assert_eq!(call.owner.as_deref(), Some("run"));
}

#[test]
fn arrow_constants_are_functions_and_plain_constants_are_not() {
    let source = "export const load = async () => { return 1; };\n\
         const multiline =\n(value) => value;\n\
         const limit = 10;\n";
    let facts = extract(source, Language::TypeScript);
    let kinds = facts
        .declarations
        .iter()
        .map(|item| (item.name.as_str(), item.kind, item.exported))
        .collect::<Vec<_>>();
    assert!(
        kinds.contains(&("load", DeclarationKind::Function, true)),
        "got {kinds:?}"
    );
    assert!(
        kinds.contains(&("multiline", DeclarationKind::Function, false)),
        "got {kinds:?}"
    );
    assert!(
        kinds.contains(&("limit", DeclarationKind::Constant, false)),
        "got {kinds:?}"
    );
}

#[test]
fn regexes_and_collection_initializers_are_not_arrow_functions() {
    let source = "const SAFE_SCRIPT = /^(?:test(?::|$)|[^:]+:(?:test|check)(?::|$))/i\n\
         const UNSAFE_SHELL_ARG = /[\\0\\r\\n&|<>^%!`\\\"]/ \n\
         const byId = new Map((graph.nodes || []).map((node) => [String(node.id), node]))\n\
         const files = new Set((graph.nodes || []).filter((node) => node.id))\n\
         const adjacency = new Map([...files].map((file) => [file, new Set()]))\n";
    let facts = extract(source, Language::JavaScript);
    for name in [
        "SAFE_SCRIPT",
        "UNSAFE_SHELL_ARG",
        "byId",
        "files",
        "adjacency",
    ] {
        let declaration = facts
            .declarations
            .iter()
            .find(|item| item.name == name)
            .unwrap_or_else(|| panic!("missing {name}: {facts:?}"));
        assert_eq!(
            declaration.kind,
            DeclarationKind::Constant,
            "{name} is a value initializer"
        );
    }
}

#[test]
fn exported_functions_and_returned_object_methods_are_declarations() {
    let source = "export function runCommand(command, args = [], options = {}) {}\n\
         export function createGate() {\n\
         \x20 return {\n\
         \x20   shouldShow({ force = false } = {}) { return force },\n\
         \x20   reset() {},\n\
         \x20 }\n\
         }\n\
         export function createClassifier() {\n\
         \x20 return { explain(path, options = {}) { return path } }\n\
         }\n";
    let facts = extract(source, Language::JavaScript);
    let declared = facts
        .declarations
        .iter()
        .map(|item| (item.name.as_str(), item.kind, item.owner.as_deref()))
        .collect::<Vec<_>>();
    assert!(
        declared.contains(&("runCommand", DeclarationKind::Function, None)),
        "got {declared:?}"
    );
    for (name, owner) in [
        ("shouldShow", "createGate"),
        ("reset", "createGate"),
        ("explain", "createClassifier"),
    ] {
        assert!(
            declared.contains(&(name, DeclarationKind::Method, Some(owner))),
            "missing {owner}.{name}; got {declared:?}"
        );
    }
}

#[test]
fn exporting_an_imported_binding_keeps_its_origin() {
    let source = "import { safeRead, MAX_FILE_BYTES } from '../util.js';\nexport { safeRead };\n";
    let facts = extract(source, Language::JavaScript);
    let forwarded = facts
        .imports
        .iter()
        .find(|item| item.reexport)
        .expect("local export of imported binding");
    assert_eq!(forwarded.specifier, "../util.js");
    assert_eq!(forwarded.names, ["safeRead"]);
    assert_eq!(
        forwarded.bindings,
        [ImportBinding {
            imported: "safeRead".to_owned(),
            local: "safeRead".to_owned(),
        }]
    );
}

#[test]
fn aliased_imports_preserve_original_and_local_names() {
    let facts = extract(
        "import Default, {\n\
         \x20 architectureViolation as violation,\n\
         \x20 matchComponentSelector as matches,\n\
         } from './architecture.js';\n\
         import * as catalog from './catalog.js';\n",
        Language::JavaScript,
    );
    let architecture = facts
        .imports
        .iter()
        .find(|item| item.specifier == "./architecture.js")
        .expect("architecture import");
    assert_eq!(architecture.names, ["Default", "violation", "matches"]);
    assert_eq!(
        architecture.bindings,
        [
            ImportBinding {
                imported: "default".to_owned(),
                local: "Default".to_owned(),
            },
            ImportBinding {
                imported: "architectureViolation".to_owned(),
                local: "violation".to_owned(),
            },
            ImportBinding {
                imported: "matchComponentSelector".to_owned(),
                local: "matches".to_owned(),
            },
        ]
    );
    let catalog = facts
        .imports
        .iter()
        .find(|item| item.specifier == "./catalog.js")
        .expect("namespace import");
    assert_eq!(
        catalog.bindings,
        [ImportBinding {
            imported: "*".to_owned(),
            local: "catalog".to_owned(),
        }]
    );
}

#[test]
fn typescript_di_wiring_is_use_reference_evidence() {
    let source = "import { Controller, Get } from '@nestjs/common';\n\
         import { UsersService } from './users.service';\n\
         @Controller('users')\n\
         export class UsersController {\n\
           private readonly registry: AuditRegistry;\n\
           constructor(private readonly usersService: UsersService) {}\n\
           @Get()\n\
           findAll(): string[] {\n\
             return this.usersService.findAll();\n\
           }\n\
         }\n";
    let facts = extract(source, Language::TypeScript);
    let uses = facts
        .references
        .iter()
        .filter(|reference| reference.kind == ReferenceKind::Uses)
        .map(|reference| (reference.name.clone(), reference.owner.clone()))
        .collect::<Vec<_>>();

    assert!(
        uses.iter()
            .any(|(name, owner)| name == "UsersService"

                && owner.as_deref() == Some("UsersController")),
        "constructor parameter type wires UsersService, got {uses:?}"
    );
    assert!(
        uses.iter()
            .any(|(name, owner)| name == "AuditRegistry"

                && owner.as_deref() == Some("UsersController")),
        "field annotation type wires AuditRegistry, got {uses:?}"
    );
    assert!(
        !uses
            .iter()
            .any(|(name, _)| name == "usersService" || name == "Controller"),
        "parameter names and decorators are not type uses: {uses:?}"
    );
}