feat(java): Phase 1.5 — tree-sitter Java frontend, package-aware mv, e2e fixtures
This commit is contained in:
parent
55670030c3
commit
603f916ee9
25 changed files with 1288 additions and 366 deletions
|
|
@ -4,20 +4,25 @@
|
|||
//!
|
||||
//! - A [`Language`] parses one source file into [`ImportRecord`]s: every
|
||||
//! *static-ish* module reference (TS `import`/`export from`/`require`/
|
||||
//! dynamic `import()`).
|
||||
//! - [`crate::core::parser_support::resolve`] turns a specifier into a
|
||||
//! project-relative file path using a resolver aware of the indexed file
|
||||
//! set. Non-project (package/bare) specifiers resolve to `None`.
|
||||
//! dynamic `import()`; Java single-type and static-member `import`s —
|
||||
//! on-demand `pkg.*` imports are deliberately not extracted).
|
||||
//! - Java files additionally expose their [`PackageDecl`] via
|
||||
//! [`Language::extract_package`]; resolution of Java specifiers goes
|
||||
//! through [`java::JavaClassIndex`] instead of [`resolve`] (TS relative
|
||||
//! specifiers). External Java imports (jdk, third-party) simply never
|
||||
//! appear in the class index.
|
||||
//! - Rewrites must touch **only the specifier string**, never the rest of
|
||||
//! the statement (KISS + no formatter dependency): that is why
|
||||
//! [`ImportRecord::span`] is a byte range into the original source.
|
||||
|
||||
use std::ops::Range;
|
||||
use std::path::Path;
|
||||
|
||||
pub mod java;
|
||||
pub mod resolve;
|
||||
pub mod ts;
|
||||
|
||||
/// Source languages `jmove` understands (Phase 1: TypeScript/JavaScript).
|
||||
/// Source languages `jmove` understands (TS/JS in Phase 1, Java in Phase 1.5).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum SourceLanguage {
|
||||
/// `.ts` (non-TSX) sources.
|
||||
|
|
@ -26,6 +31,8 @@ pub enum SourceLanguage {
|
|||
Tsx,
|
||||
/// Plain `.js` / `.mjs` / `.cjs` sources.
|
||||
JavaScript,
|
||||
/// `.java` sources.
|
||||
Java,
|
||||
}
|
||||
|
||||
impl SourceLanguage {
|
||||
|
|
@ -36,6 +43,7 @@ impl SourceLanguage {
|
|||
"ts" | "mts" | "cts" => Some(Self::TypeScript),
|
||||
"tsx" | "jsx" => Some(Self::Tsx),
|
||||
"js" | "mjs" | "cjs" => Some(Self::JavaScript),
|
||||
"java" => Some(Self::Java),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -56,16 +64,27 @@ impl SourceLanguage {
|
|||
/// One module reference found in a source file.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ImportRecord {
|
||||
/// Raw specifier text as written, e.g. `"../utils/format"`.
|
||||
/// Raw specifier text as written, e.g. `"../utils/format"` (TS) or
|
||||
/// `"com.example.utils.Parser"` (Java).
|
||||
pub specifier: String,
|
||||
/// Byte range of the *specifier string contents* (inside the quotes,
|
||||
/// without the quote characters) in the parsed file. The rewriter
|
||||
/// replaces exactly this span and nothing else.
|
||||
pub span: std::ops::Range<usize>,
|
||||
pub span: Range<usize>,
|
||||
/// `true` for dynamic `import("...")` / `require("...")` occurrences.
|
||||
pub is_dynamic: bool,
|
||||
}
|
||||
|
||||
/// A Java `package` declaration: dotted name plus the byte span of the name
|
||||
/// (quotes have no meaning here — the span covers `com.example.utils`).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PackageDecl {
|
||||
/// Declared package name, e.g. `"com.example.utils"`.
|
||||
pub name: String,
|
||||
/// Byte range of the package name in the parsed file.
|
||||
pub span: Range<usize>,
|
||||
}
|
||||
|
||||
/// A language frontend that extracts imports from source text.
|
||||
pub trait Language: Send + Sync {
|
||||
/// The language this frontend handles.
|
||||
|
|
@ -74,10 +93,21 @@ pub trait Language: Send + Sync {
|
|||
/// Extract all import records from `source` in byte-offset order.
|
||||
/// Parse errors must not be fatal: return what was understood.
|
||||
fn extract_imports(&self, source: &str) -> Vec<ImportRecord>;
|
||||
|
||||
/// Extract the `package` declaration, if this language has one and the
|
||||
/// file declares it. Default: no package concept (TS/JS).
|
||||
fn extract_package(&self, _source: &str) -> Option<PackageDecl> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the default frontend for `lang`.
|
||||
#[must_use]
|
||||
pub fn frontend_for(lang: SourceLanguage) -> Box<dyn Language> {
|
||||
Box::new(ts::TreeSitterTs::new(lang))
|
||||
match lang {
|
||||
SourceLanguage::Java => Box::new(java::TreeSitterJava::new()),
|
||||
SourceLanguage::TypeScript | SourceLanguage::Tsx | SourceLanguage::JavaScript => {
|
||||
Box::new(ts::TreeSitterTs::new(lang))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue