1#![allow(dead_code)]
5use std::any::Any;
26use std::path::PathBuf;
27use thread_utilities::RapidMap;
28
29#[cfg(feature = "ast-grep-backend")]
31use thread_ast_engine::{Node, NodeMatch, Position, Root};
32
33#[cfg(feature = "ast-grep-backend")]
34pub use thread_ast_engine::source::Doc;
35
36#[cfg(feature = "ast-grep-backend")]
37use thread_ast_engine::pinned::PinnedNodeData;
38
39#[cfg(feature = "ast-grep-backend")]
40pub type PinnedNodeResult<D> = PinnedNodeData<D, Node<'static, D>>;
41
42#[cfg(not(feature = "ast-grep-backend"))]
43pub type PinnedNodeResult<D> = PinnedNodeData<D>;
44
45#[cfg(feature = "ast-grep-backend")]
47pub use thread_ast_engine::{
48 Node as AstNode, NodeMatch as AstNodeMatch, Position as AstPosition, Root as AstRoot,
49};
50
51#[cfg(feature = "ast-grep-backend")]
52pub use thread_language::{SupportLang, SupportLangErr};
53
54#[cfg(not(feature = "ast-grep-backend"))]
55pub trait Doc = Clone + 'static;
56
57#[cfg(not(feature = "ast-grep-backend"))]
58#[derive(Debug, Clone)]
59pub struct Root<D>(pub std::marker::PhantomData<D>);
60
61#[cfg(not(feature = "ast-grep-backend"))]
62impl<D: Doc> Root<D> {
63 pub fn root<'a>(&'a self) -> Node<'a, D> {
64 Node(std::marker::PhantomData)
65 }
66
67 pub fn generate(&self) -> String {
68 String::new()
69 }
70}
71
72#[cfg(not(feature = "ast-grep-backend"))]
73#[derive(Debug, Clone)]
74pub struct Node<'a, D>(pub std::marker::PhantomData<&'a D>);
75
76#[cfg(not(feature = "ast-grep-backend"))]
77#[derive(Debug, Clone)]
78pub struct NodeMatch<'a, D>(pub std::marker::PhantomData<&'a D>);
79
80#[cfg(not(feature = "ast-grep-backend"))]
81impl<'a, D> std::ops::Deref for NodeMatch<'a, D> {
82 type Target = Node<'a, D>;
83 fn deref(&self) -> &Self::Target {
84 unsafe { &*(self as *const Self as *const Node<'a, D>) }
85 }
86}
87
88#[cfg(not(feature = "ast-grep-backend"))]
89#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
90pub struct Position {
91 pub row: usize,
92 pub column: usize,
93 pub index: usize,
94}
95
96#[cfg(not(feature = "ast-grep-backend"))]
97impl Position {
98 pub fn new(row: usize, column: usize, index: usize) -> Self {
99 Self { row, column, index }
100 }
101}
102
103#[cfg(not(feature = "ast-grep-backend"))]
104#[derive(Debug, Clone)]
105pub struct PinnedNodeData<D>(pub std::marker::PhantomData<D>);
106
107#[cfg(not(feature = "ast-grep-backend"))]
108impl<D: Doc> PinnedNodeData<D> {
109 pub fn new<F, T>(_root: &Root<D>, _f: F) -> Self
110 where
111 F: FnOnce(&Root<D>) -> T,
112 {
113 Self(std::marker::PhantomData)
114 }
115}
116
117#[cfg(not(feature = "ast-grep-backend"))]
118pub trait MatcherExt {}
119
120#[cfg(not(feature = "ast-grep-backend"))]
121impl<T> MatcherExt for T {}
122
123#[cfg(not(feature = "ast-grep-backend"))]
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126pub enum SupportLang {
127 Bash,
128 C,
129 Cpp,
130 CSharp,
131 Css,
132 Go,
133 Elixir,
134 Haskell,
135 Html,
136 Java,
137 JavaScript,
138 Kotlin,
139 Lua,
140 Nix,
141 Php,
142 Python,
143 Ruby,
144 Rust,
145 Scala,
146 Swift,
147 TypeScript,
148 Tsx,
149 Yaml,
150}
151
152#[cfg(not(feature = "ast-grep-backend"))]
153impl SupportLang {
154 pub fn from_path(_path: &std::path::Path) -> Option<Self> {
155 Some(Self::Rust)
157 }
158}
159
160#[cfg(not(feature = "ast-grep-backend"))]
161#[derive(Debug, Clone)]
162pub struct SupportLangErr(pub String);
163
164#[cfg(not(feature = "ast-grep-backend"))]
165impl std::fmt::Display for SupportLangErr {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 write!(f, "{}", self.0)
168 }
169}
170
171#[cfg(not(feature = "ast-grep-backend"))]
172impl std::error::Error for SupportLangErr {}
173
174#[derive(Debug)]
180pub struct ParsedDocument<D: Doc> {
181 pub ast_root: Root<D>,
183
184 pub file_path: PathBuf,
186
187 pub language: SupportLang,
189
190 pub content_fingerprint: recoco_utils::fingerprint::Fingerprint,
192
193 pub metadata: DocumentMetadata,
195
196 pub(crate) internal: Box<dyn Any + Send + Sync>,
198}
199
200impl<D: Doc> ParsedDocument<D> {
201 pub fn new(
203 ast_root: Root<D>,
204 file_path: PathBuf,
205 language: SupportLang,
206 content_fingerprint: recoco_utils::fingerprint::Fingerprint,
207 ) -> Self {
208 Self {
209 ast_root,
210 file_path,
211 language,
212 content_fingerprint,
213 metadata: DocumentMetadata::default(),
214 internal: Box::new(()),
215 }
216 }
217
218 pub fn root(&self) -> Node<'_, D> {
220 self.ast_root.root()
221 }
222
223 pub fn ast_grep_root(&self) -> &Root<D> {
225 &self.ast_root
226 }
227
228 pub fn ast_grep_root_mut(&mut self) -> &mut Root<D> {
230 &mut self.ast_root
231 }
232
233 pub fn pin_for_threading(&self) -> PinnedNodeResult<D> {
235 #[cfg(feature = "ast-grep-backend")]
236 return PinnedNodeData::new(self.ast_root.clone(), |r| r.root());
237
238 #[cfg(not(feature = "ast-grep-backend"))]
239 return PinnedNodeData::new(&self.ast_root, |_| ());
240 }
241
242 pub fn generate(&self) -> String {
244 #[cfg(feature = "ast-grep-backend")]
245 {
246 use thread_ast_engine::source::Content;
247 let root_node = self.root();
248 let doc = root_node.get_doc();
249 let range = root_node.range();
250 let bytes = doc.get_source().get_range(range);
251 D::Source::encode_bytes(bytes).into_owned()
252 }
253 #[cfg(not(feature = "ast-grep-backend"))]
254 self.ast_root.generate()
255 }
256
257 pub fn metadata(&self) -> &DocumentMetadata {
259 &self.metadata
260 }
261
262 pub fn metadata_mut(&mut self) -> &mut DocumentMetadata {
264 &mut self.metadata
265 }
266}
267
268#[derive(Debug)]
273pub struct CodeMatch<'tree, D: Doc> {
274 pub node_match: NodeMatch<'tree, D>,
276
277 pub context: MatchContext,
279
280 pub relationships: Vec<CrossFileRelationship>,
282}
283
284impl<'tree, D: Doc> CodeMatch<'tree, D> {
285 pub fn new(node_match: NodeMatch<'tree, D>) -> Self {
287 Self {
288 node_match,
289 context: MatchContext::default(),
290 relationships: Vec::new(),
291 }
292 }
293
294 pub fn ast_node_match(&self) -> &NodeMatch<'tree, D> {
296 &self.node_match
297 }
298
299 pub fn node(&self) -> &Node<'tree, D> {
301 &self.node_match
302 }
303
304 #[cfg(any(feature = "ast-grep-backend", feature = "matching"))]
305 pub fn get_env(&self) -> &thread_ast_engine::MetaVarEnv<'tree, D> {
307 self.node_match.get_env()
308 }
309
310 pub fn add_relationship(&mut self, relationship: CrossFileRelationship) {
312 self.relationships.push(relationship);
313 }
314
315 pub fn relationships(&self) -> &[CrossFileRelationship] {
317 &self.relationships
318 }
319}
320
321#[derive(Debug, Default, Clone)]
323pub struct DocumentMetadata {
324 pub defined_symbols: RapidMap<String, SymbolInfo>,
326
327 pub imported_symbols: RapidMap<String, ImportInfo>,
329
330 pub exported_symbols: RapidMap<String, ExportInfo>,
332
333 pub function_calls: Vec<CallInfo>,
335
336 pub type_info: Vec<TypeInfo>,
338
339 pub language_metadata: RapidMap<String, String>,
341}
342
343#[derive(Debug, Clone)]
345pub struct SymbolInfo {
346 pub name: String,
347 pub kind: SymbolKind,
348 pub position: Position,
349 pub scope: String,
350 pub visibility: Visibility,
351}
352
353#[derive(Debug, Clone)]
355pub struct ImportInfo {
356 pub symbol_name: String,
357 pub source_path: String,
358 pub import_kind: ImportKind,
359 pub position: Position,
360}
361
362#[derive(Debug, Clone)]
364pub struct ExportInfo {
365 pub symbol_name: String,
366 pub export_kind: ExportKind,
367 pub position: Position,
368}
369
370#[derive(Debug, Clone)]
372pub struct CallInfo {
373 pub function_name: String,
374 pub position: Position,
375 pub arguments_count: usize,
376 pub is_resolved: bool,
377 pub target_file: Option<PathBuf>,
378}
379
380#[derive(Debug, Clone)]
382pub struct TypeInfo {
383 pub type_name: String,
384 pub position: Position,
385 pub kind: TypeKind,
386 pub generic_params: Vec<String>,
387}
388
389#[derive(Debug, Clone)]
391pub struct CrossFileRelationship {
392 pub kind: RelationshipKind,
393 pub source_file: PathBuf,
394 pub target_file: PathBuf,
395 pub source_symbol: String,
396 pub target_symbol: String,
397 pub relationship_data: RapidMap<String, String>,
398}
399
400#[derive(Debug, Default, Clone)]
402pub struct MatchContext {
403 pub execution_scope: ExecutionScope,
404 pub analysis_depth: AnalysisDepth,
405 pub context_data: RapidMap<String, String>,
406}
407
408#[derive(Debug, Clone, Default)]
410pub enum ExecutionScope {
411 #[default]
413 File,
414 Module(PathBuf),
416 Codebase,
418 Custom(Vec<PathBuf>),
420}
421
422#[derive(Debug, Clone, Default)]
424pub enum AnalysisDepth {
425 Syntax,
427 #[default]
429 Local,
430 Deep,
432 Complete,
434}
435
436#[derive(Debug, Clone)]
438pub struct AnalysisContext {
439 pub scope: ExecutionScope,
441
442 pub depth: AnalysisDepth,
444
445 pub base_directory: PathBuf,
447
448 pub include_patterns: Vec<String>,
450
451 pub exclude_patterns: Vec<String>,
453
454 pub max_files: Option<usize>,
456
457 pub execution_config: ExecutionConfig,
459
460 pub context_data: RapidMap<String, String>,
462}
463
464impl Default for AnalysisContext {
465 fn default() -> Self {
466 Self {
467 scope: ExecutionScope::File,
468 depth: AnalysisDepth::Local,
469 base_directory: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
470 include_patterns: vec!["**/*".to_string()],
471 exclude_patterns: vec!["**/node_modules/**".to_string(), "**/target/**".to_string()],
472 max_files: None,
473 execution_config: ExecutionConfig::default(),
474 context_data: thread_utilities::get_map(),
475 }
476 }
477}
478
479#[derive(Debug, Clone)]
481pub struct ExecutionConfig {
482 pub strategy: ExecutionStrategy,
484
485 pub max_concurrency: Option<usize>,
487
488 pub chunk_size: Option<usize>,
490
491 pub operation_timeout: Option<std::time::Duration>,
493}
494
495impl Default for ExecutionConfig {
496 fn default() -> Self {
497 Self {
498 strategy: ExecutionStrategy::Auto,
499 max_concurrency: None,
500 chunk_size: None,
501 operation_timeout: None,
502 }
503 }
504}
505
506#[derive(Debug, Clone, Default)]
508pub enum ExecutionStrategy {
509 #[default]
511 Auto,
512 Sequential,
514 Rayon,
516 Chunked,
518 Custom(String),
520}
521
522#[derive(Debug, Clone, PartialEq)]
525pub enum SymbolKind {
526 Function,
527 Class,
528 Interface,
529 Variable,
530 Constant,
531 Type,
532 Module,
533 Namespace,
534 Enum,
535 Field,
536 Property,
537 Method,
538 Constructor,
539 Other(String),
540}
541
542#[derive(Debug, Clone, PartialEq)]
543pub enum Visibility {
544 Public,
545 Private,
546 Protected,
547 Internal,
548 Package,
549 Other(String),
550}
551
552#[derive(Debug, Clone, PartialEq)]
553pub enum ImportKind {
554 Named,
555 Default,
556 Namespace,
557 SideEffect,
558 Dynamic,
559 Other(String),
560}
561
562#[derive(Debug, Clone, PartialEq)]
563pub enum ExportKind {
564 Named,
565 Default,
566 Namespace,
567 Reexport,
568 Other(String),
569}
570
571#[derive(Debug, Clone, PartialEq)]
572pub enum TypeKind {
573 Primitive,
574 Struct,
575 Class,
576 Interface,
577 Union,
578 Enum,
579 Generic,
580 Function,
581 Array,
582 Other(String),
583}
584
585#[derive(Debug, Clone, PartialEq)]
586pub enum RelationshipKind {
587 Calls,
589 Imports,
591 Inherits,
593 Implements,
595 Uses,
597 DependsOn,
599 References,
601 Custom(String),
603}
604
605#[derive(Debug, Clone, Copy, PartialEq, Eq)]
607pub struct Range {
608 pub start: Position,
609 pub end: Position,
610}
611
612impl Range {
613 pub fn new(start: Position, end: Position) -> Self {
614 Self { start, end }
615 }
616
617 pub fn from_ast_positions(start: Position, end: Position) -> Self {
619 Self { start, end }
620 }
621
622 pub fn contains(&self, pos: Position) -> bool {
624 pos >= self.start && pos <= self.end
625 }
626
627 pub fn overlaps(&self, other: &Range) -> bool {
629 self.start <= other.end && other.start <= self.end
630 }
631}