Skip to main content

mati_core/analysis/parser/
import.rs

1//! Structured import representation for cross-file resolution.
2//!
3//! Raw import strings (`Vec<String>`) lack the structural information needed
4//! for production-grade import resolution across 12 languages. This module
5//! provides `ImportStatement` — a typed representation that carries the import
6//! path, its structural classification, and source location.
7//!
8//! Each language parser produces `Vec<ImportStatement>` during tree-sitter
9//! extraction. The classification into `ImportKind` happens at parse time,
10//! eliminating the need for a separate `is_external_import()` pass during
11//! edge construction.
12
13use serde::{Deserialize, Serialize};
14
15/// A single import statement extracted from source code by tree-sitter.
16///
17/// Carries enough information for the resolver to decide whether to attempt
18/// resolution, and for debugging/IDE integration via the line number.
19#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub struct ImportStatement {
21    /// The raw path/module string as extracted from source.
22    ///
23    /// - **Rust**: the `use` argument without the `as` alias (e.g. `crate::store::db`)
24    /// - **Python**: the dotted module name (e.g. `django.conf` or `.helpers`)
25    /// - **TypeScript/JavaScript**: the module specifier without quotes (e.g. `./utils` or `react`)
26    /// - **Go**: the import path without quotes (e.g. `fmt` or `github.com/user/pkg`)
27    /// - **Java**: the fully-qualified class/package name (e.g. `java.util.List`)
28    /// - **C/C++**: the filename inside the include directive (e.g. `stdio.h` or `myheader.h`)
29    /// - **Ruby**: the argument to `require`/`require_relative`
30    /// - **Scala**: the import path without `import ` prefix
31    /// - **Elixir**: the module name from `import`/`alias`/`use`/`require`
32    /// - **Haskell**: the module name (e.g. `Data.List`)
33    pub path: String,
34
35    /// Structural classification that determines resolver behavior.
36    pub kind: ImportKind,
37
38    /// Line number in the source file where the import appears (1-indexed).
39    /// Used for debugging and future IDE integration. 0 if unknown.
40    pub line: u32,
41}
42
43/// Classification of an import statement that determines how the resolver
44/// handles it.
45///
46/// An import can only have one kind. Priority when multiple could apply:
47/// `External` > `Relative` > `Wildcard` > `Normal`. External imports are
48/// never resolved; relative imports use the importing file's directory as
49/// base; wildcards may match multiple targets in future phases.
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
51pub enum ImportKind {
52    /// Standard import (e.g. `use foo::bar;`, `import X`, `#include "foo.h"`).
53    /// The resolver will attempt to resolve this against the file index.
54    Normal,
55
56    /// Wildcard / glob import (e.g. `use foo::*;`, `from x import *`, `import com.acme.*`).
57    /// The resolver will attempt resolution but may match multiple targets.
58    Wildcard,
59
60    /// Relative import that resolves from the importing file's directory.
61    /// Used by Python (`.x`, `..x`), Ruby (`require_relative`), C (`#include "..."`),
62    /// and TS/JS (`./foo`, `../bar`).
63    Relative,
64
65    /// External / third-party import that should be skipped by the resolver.
66    /// (e.g. Rust non-crate imports, TS/JS bare specifiers, C angle-bracket system headers)
67    External,
68
69    /// Class inheritance: `class Foo < Bar` produces an Inherits import for Bar.
70    /// Used by Ruby/Rails for autoload-implicit dependencies resolved via Zeitwerk
71    /// path conventions.
72    Inherits,
73
74    /// Module inclusion: `include Foo`, `extend Foo`, `prepend Foo` all produce
75    /// an Includes import. Used by Ruby/Rails for concerns and shared modules,
76    /// resolved via Zeitwerk path conventions.
77    Includes,
78}
79
80impl ImportStatement {
81    /// Create a new import statement with all fields specified.
82    pub fn new(path: impl Into<String>, kind: ImportKind, line: u32) -> Self {
83        Self {
84            path: path.into(),
85            kind,
86            line,
87        }
88    }
89
90    /// Convenience: create a Normal import at the given line.
91    #[cfg(test)]
92    pub fn normal(path: impl Into<String>, line: u32) -> Self {
93        Self::new(path, ImportKind::Normal, line)
94    }
95
96    /// Convenience: create an External import at the given line.
97    #[cfg(test)]
98    pub fn external(path: impl Into<String>, line: u32) -> Self {
99        Self::new(path, ImportKind::External, line)
100    }
101}