#![allow(dead_code)]
use std::any::Any;
use std::path::PathBuf;
use thread_utilities::RapidMap;
#[cfg(feature = "ast-grep-backend")]
use thread_ast_engine::{Node, NodeMatch, Position, Root};
#[cfg(feature = "ast-grep-backend")]
pub use thread_ast_engine::source::Doc;
#[cfg(feature = "ast-grep-backend")]
use thread_ast_engine::pinned::PinnedNodeData;
#[cfg(feature = "ast-grep-backend")]
pub type PinnedNodeResult<D> = PinnedNodeData<D, Node<'static, D>>;
#[cfg(not(feature = "ast-grep-backend"))]
pub type PinnedNodeResult<D> = PinnedNodeData<D>;
#[cfg(feature = "ast-grep-backend")]
pub use thread_ast_engine::{
Node as AstNode, NodeMatch as AstNodeMatch, Position as AstPosition, Root as AstRoot,
};
#[cfg(feature = "ast-grep-backend")]
pub use thread_language::{SupportLang, SupportLangErr};
#[cfg(not(feature = "ast-grep-backend"))]
pub trait Doc = Clone + 'static;
#[cfg(not(feature = "ast-grep-backend"))]
#[derive(Debug, Clone)]
pub struct Root<D>(pub std::marker::PhantomData<D>);
#[cfg(not(feature = "ast-grep-backend"))]
impl<D: Doc> Root<D> {
pub fn root<'a>(&'a self) -> Node<'a, D> {
Node(std::marker::PhantomData)
}
pub fn generate(&self) -> String {
String::new()
}
}
#[cfg(not(feature = "ast-grep-backend"))]
#[derive(Debug, Clone)]
pub struct Node<'a, D>(pub std::marker::PhantomData<&'a D>);
#[cfg(not(feature = "ast-grep-backend"))]
#[derive(Debug, Clone)]
pub struct NodeMatch<'a, D>(pub std::marker::PhantomData<&'a D>);
#[cfg(not(feature = "ast-grep-backend"))]
impl<'a, D> std::ops::Deref for NodeMatch<'a, D> {
type Target = Node<'a, D>;
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self as *const Node<'a, D>) }
}
}
#[cfg(not(feature = "ast-grep-backend"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Position {
pub row: usize,
pub column: usize,
pub index: usize,
}
#[cfg(not(feature = "ast-grep-backend"))]
impl Position {
pub fn new(row: usize, column: usize, index: usize) -> Self {
Self { row, column, index }
}
}
#[cfg(not(feature = "ast-grep-backend"))]
#[derive(Debug, Clone)]
pub struct PinnedNodeData<D>(pub std::marker::PhantomData<D>);
#[cfg(not(feature = "ast-grep-backend"))]
impl<D: Doc> PinnedNodeData<D> {
pub fn new<F, T>(_root: &Root<D>, _f: F) -> Self
where
F: FnOnce(&Root<D>) -> T,
{
Self(std::marker::PhantomData)
}
}
#[cfg(not(feature = "ast-grep-backend"))]
pub trait MatcherExt {}
#[cfg(not(feature = "ast-grep-backend"))]
impl<T> MatcherExt for T {}
#[cfg(not(feature = "ast-grep-backend"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SupportLang {
Bash,
C,
Cpp,
CSharp,
Css,
Go,
Elixir,
Haskell,
Html,
Java,
JavaScript,
Kotlin,
Lua,
Nix,
Php,
Python,
Ruby,
Rust,
Scala,
Swift,
TypeScript,
Tsx,
Yaml,
}
#[cfg(not(feature = "ast-grep-backend"))]
impl SupportLang {
pub fn from_path(_path: &std::path::Path) -> Option<Self> {
Some(Self::Rust)
}
}
#[cfg(not(feature = "ast-grep-backend"))]
#[derive(Debug, Clone)]
pub struct SupportLangErr(pub String);
#[cfg(not(feature = "ast-grep-backend"))]
impl std::fmt::Display for SupportLangErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(not(feature = "ast-grep-backend"))]
impl std::error::Error for SupportLangErr {}
#[derive(Debug)]
pub struct ParsedDocument<D: Doc> {
pub ast_root: Root<D>,
pub file_path: PathBuf,
pub language: SupportLang,
pub content_fingerprint: recoco_utils::fingerprint::Fingerprint,
pub metadata: DocumentMetadata,
pub(crate) internal: Box<dyn Any + Send + Sync>,
}
impl<D: Doc> ParsedDocument<D> {
pub fn new(
ast_root: Root<D>,
file_path: PathBuf,
language: SupportLang,
content_fingerprint: recoco_utils::fingerprint::Fingerprint,
) -> Self {
Self {
ast_root,
file_path,
language,
content_fingerprint,
metadata: DocumentMetadata::default(),
internal: Box::new(()),
}
}
pub fn root(&self) -> Node<'_, D> {
self.ast_root.root()
}
pub fn ast_grep_root(&self) -> &Root<D> {
&self.ast_root
}
pub fn ast_grep_root_mut(&mut self) -> &mut Root<D> {
&mut self.ast_root
}
pub fn pin_for_threading(&self) -> PinnedNodeResult<D> {
#[cfg(feature = "ast-grep-backend")]
return PinnedNodeData::new(self.ast_root.clone(), |r| r.root());
#[cfg(not(feature = "ast-grep-backend"))]
return PinnedNodeData::new(&self.ast_root, |_| ());
}
pub fn generate(&self) -> String {
#[cfg(feature = "ast-grep-backend")]
{
use thread_ast_engine::source::Content;
let root_node = self.root();
let doc = root_node.get_doc();
let range = root_node.range();
let bytes = doc.get_source().get_range(range);
D::Source::encode_bytes(bytes).into_owned()
}
#[cfg(not(feature = "ast-grep-backend"))]
self.ast_root.generate()
}
pub fn metadata(&self) -> &DocumentMetadata {
&self.metadata
}
pub fn metadata_mut(&mut self) -> &mut DocumentMetadata {
&mut self.metadata
}
}
#[derive(Debug)]
pub struct CodeMatch<'tree, D: Doc> {
pub node_match: NodeMatch<'tree, D>,
pub context: MatchContext,
pub relationships: Vec<CrossFileRelationship>,
}
impl<'tree, D: Doc> CodeMatch<'tree, D> {
pub fn new(node_match: NodeMatch<'tree, D>) -> Self {
Self {
node_match,
context: MatchContext::default(),
relationships: Vec::new(),
}
}
pub fn ast_node_match(&self) -> &NodeMatch<'tree, D> {
&self.node_match
}
pub fn node(&self) -> &Node<'tree, D> {
&self.node_match
}
#[cfg(any(feature = "ast-grep-backend", feature = "matching"))]
pub fn get_env(&self) -> &thread_ast_engine::MetaVarEnv<'tree, D> {
self.node_match.get_env()
}
pub fn add_relationship(&mut self, relationship: CrossFileRelationship) {
self.relationships.push(relationship);
}
pub fn relationships(&self) -> &[CrossFileRelationship] {
&self.relationships
}
}
#[derive(Debug, Default, Clone)]
pub struct DocumentMetadata {
pub defined_symbols: RapidMap<String, SymbolInfo>,
pub imported_symbols: RapidMap<String, ImportInfo>,
pub exported_symbols: RapidMap<String, ExportInfo>,
pub function_calls: Vec<CallInfo>,
pub type_info: Vec<TypeInfo>,
pub language_metadata: RapidMap<String, String>,
}
#[derive(Debug, Clone)]
pub struct SymbolInfo {
pub name: String,
pub kind: SymbolKind,
pub position: Position,
pub scope: String,
pub visibility: Visibility,
}
#[derive(Debug, Clone)]
pub struct ImportInfo {
pub symbol_name: String,
pub source_path: String,
pub import_kind: ImportKind,
pub position: Position,
}
#[derive(Debug, Clone)]
pub struct ExportInfo {
pub symbol_name: String,
pub export_kind: ExportKind,
pub position: Position,
}
#[derive(Debug, Clone)]
pub struct CallInfo {
pub function_name: String,
pub position: Position,
pub arguments_count: usize,
pub is_resolved: bool,
pub target_file: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct TypeInfo {
pub type_name: String,
pub position: Position,
pub kind: TypeKind,
pub generic_params: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct CrossFileRelationship {
pub kind: RelationshipKind,
pub source_file: PathBuf,
pub target_file: PathBuf,
pub source_symbol: String,
pub target_symbol: String,
pub relationship_data: RapidMap<String, String>,
}
#[derive(Debug, Default, Clone)]
pub struct MatchContext {
pub execution_scope: ExecutionScope,
pub analysis_depth: AnalysisDepth,
pub context_data: RapidMap<String, String>,
}
#[derive(Debug, Clone, Default)]
pub enum ExecutionScope {
#[default]
File,
Module(PathBuf),
Codebase,
Custom(Vec<PathBuf>),
}
#[derive(Debug, Clone, Default)]
pub enum AnalysisDepth {
Syntax,
#[default]
Local,
Deep,
Complete,
}
#[derive(Debug, Clone)]
pub struct AnalysisContext {
pub scope: ExecutionScope,
pub depth: AnalysisDepth,
pub base_directory: PathBuf,
pub include_patterns: Vec<String>,
pub exclude_patterns: Vec<String>,
pub max_files: Option<usize>,
pub execution_config: ExecutionConfig,
pub context_data: RapidMap<String, String>,
}
impl Default for AnalysisContext {
fn default() -> Self {
Self {
scope: ExecutionScope::File,
depth: AnalysisDepth::Local,
base_directory: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
include_patterns: vec!["**/*".to_string()],
exclude_patterns: vec!["**/node_modules/**".to_string(), "**/target/**".to_string()],
max_files: None,
execution_config: ExecutionConfig::default(),
context_data: thread_utilities::get_map(),
}
}
}
#[derive(Debug, Clone)]
pub struct ExecutionConfig {
pub strategy: ExecutionStrategy,
pub max_concurrency: Option<usize>,
pub chunk_size: Option<usize>,
pub operation_timeout: Option<std::time::Duration>,
}
impl Default for ExecutionConfig {
fn default() -> Self {
Self {
strategy: ExecutionStrategy::Auto,
max_concurrency: None,
chunk_size: None,
operation_timeout: None,
}
}
}
#[derive(Debug, Clone, Default)]
pub enum ExecutionStrategy {
#[default]
Auto,
Sequential,
Rayon,
Chunked,
Custom(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum SymbolKind {
Function,
Class,
Interface,
Variable,
Constant,
Type,
Module,
Namespace,
Enum,
Field,
Property,
Method,
Constructor,
Other(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Visibility {
Public,
Private,
Protected,
Internal,
Package,
Other(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum ImportKind {
Named,
Default,
Namespace,
SideEffect,
Dynamic,
Other(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExportKind {
Named,
Default,
Namespace,
Reexport,
Other(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum TypeKind {
Primitive,
Struct,
Class,
Interface,
Union,
Enum,
Generic,
Function,
Array,
Other(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum RelationshipKind {
Calls,
Imports,
Inherits,
Implements,
Uses,
DependsOn,
References,
Custom(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Range {
pub start: Position,
pub end: Position,
}
impl Range {
pub fn new(start: Position, end: Position) -> Self {
Self { start, end }
}
pub fn from_ast_positions(start: Position, end: Position) -> Self {
Self { start, end }
}
pub fn contains(&self, pos: Position) -> bool {
pos >= self.start && pos <= self.end
}
pub fn overlaps(&self, other: &Range) -> bool {
self.start <= other.end && other.start <= self.end
}
}