use anyhow::{Context, Result}; use std::path::Path; use tree_sitter::{Node, Parser}; #[derive(Debug, Clone, serde::Serialize)] pub struct Symbol { pub name: String, pub kind: String, pub line: usize, pub end_line: usize, pub signature: Option, pub parent: Option, } #[derive(Debug, Clone)] pub struct IdentRef { pub name: String, pub line: usize, /// Resolved import path if known (e.g. "windmill_common::error::Error") pub import_path: Option, } /// A `use` import with its scope #[derive(Debug, Clone)] pub struct ImportEntry { /// The short name (e.g. "Error") pub name: String, /// Full path (e.g. "windmill_common::error::Error") pub full_path: String, /// Line where the use is declared pub line: usize, /// End of the scope this use lives in (file end for top-level, block end for scoped) pub scope_end: usize, } pub struct ParseResult { pub symbols: Vec, pub refs: Vec, } pub enum Lang { Rust, Typescript, Tsx, } impl Lang { pub fn from_path(path: &Path) -> Option { match path.extension()?.to_str()? { "rs" => Some(Self::Rust), "tsx" | "jsx" => Some(Self::Tsx), "ts" | "js" => Some(Self::Typescript), "svelte" => Some(Self::Typescript), // we extract