Skip to main content

gritpack_searchlib/
lib.rs

1#![allow(dead_code)]
2
3//! Compiler-facing resolver and grammar integration surface for Gritpack.
4//!
5//! This crate is the handoff boundary for compiler, language-server, and other
6//! language-tooling integrations. It intentionally exposes the narrow read-side
7//! resolver API, the build-side grammar publication helpers, and the shared
8//! grammar model types.
9//!
10//! # Who This Is For
11//!
12//! `gritpack-searchlib` is for compiler and toolchain authors who need to work
13//! against a compiled Gritpack project snapshot.
14//!
15//! The primary workflow is:
16//!
17//! 1. define grammar metadata in [`grammar`]
18//! 2. publish that metadata into an existing project snapshot with [`build`]
19//! 3. reopen the snapshot through [`resolver`]
20//! 4. start from authoritative participating files
21//! 5. use grammar-aware narrowing only as an optimization layer
22//!
23//! # Public Modules
24//!
25//! - [`build`] publishes grammar specifications and external-driver payloads
26//!   into a project snapshot
27//! - [`grammar`] defines the build-side grammar model and query-time capability
28//!   contract
29//! - [`resolver`] exposes the read-only resolver API over compiled snapshot state
30//!
31//! # Correctness Model
32//!
33//! The key rule for consumers is:
34//!
35//! - participating files are the correctness baseline
36//! - grammar-aware queries are narrowing optimizations over that baseline
37//!
38//! If a narrowing answer is non-authoritative, callers should fall back to the
39//! broader participating-file set before making semantic decisions.
40//!
41//! # Quick Start
42//!
43//! ```no_run
44//! use gritpack_searchlib::grammar::GrammarId;
45//! use gritpack_searchlib::resolver::{
46//!     LoadedProjectResolver, ModuleQuery, PackageScope, ParticipatingFileQuery,
47//!     QuerySelection, ReferenceQuery,
48//! };
49//!
50//! # async fn demo() -> Result<(), gritpack_searchlib::CliError> {
51//! let resolver = LoadedProjectResolver::open(std::path::Path::new("/workspace/project")).await?;
52//!
53//! let participating = resolver.participating_files(&ParticipatingFileQuery {
54//!     package_scope: PackageScope::AnyDependency,
55//! });
56//! assert!(participating.authoritative);
57//!
58//! let grammar = GrammarId {
59//!     dialect: "lumen/1.0.0".to_string(),
60//!     name: "modules".to_string(),
61//!     version: 1,
62//! };
63//!
64//! match resolver.files_for_query(
65//!     &grammar,
66//!     &ReferenceQuery::Modules(vec![ModuleQuery {
67//!         package_scope: PackageScope::AnyDependency,
68//!         name: "demo::thing".to_string(),
69//!     }]),
70//! )? {
71//!     Some(QuerySelection::Files(selection)) if selection.authoritative => {
72//!         for path in selection.file_paths {
73//!             println!("candidate={path}");
74//!         }
75//!     }
76//!     _ => {}
77//! }
78//! # Ok(())
79//! # }
80//! ```
81
82use std::path::{Component, Path, PathBuf};
83
84use sha2::{Digest, Sha256};
85
86pub mod build;
87mod environment;
88pub mod grammar;
89mod layout;
90mod models;
91pub mod resolver;
92mod runtime;
93mod state;
94mod support;
95
96pub use models::CliError;
97
98fn sanitize_relative_package_path(path: &Path) -> Result<PathBuf, CliError> {
99	let mut result = PathBuf::new();
100	for component in path.components() {
101		match component {
102			Component::Normal(part) => result.push(part),
103			Component::CurDir => {}
104			_ => {
105				return Err(CliError::Message(format!(
106					"refusing to use unsafe package path: {}",
107					path.display()
108				)))
109			}
110		}
111	}
112	Ok(result)
113}
114
115fn sanitize_archive_path(path: &Path) -> Result<PathBuf, CliError> {
116	let mut result = PathBuf::new();
117	for component in path.components() {
118		match component {
119			Component::Normal(part) => result.push(part),
120			Component::CurDir => {}
121			_ => {
122				return Err(CliError::Message(format!(
123					"refusing to unpack unsafe archive path: {}",
124					path.display()
125				)))
126			}
127		}
128	}
129	Ok(result)
130}
131
132fn sha256_hex(bytes: &[u8]) -> String {
133	let mut hasher = Sha256::new();
134	hasher.update(bytes);
135	format!("{:x}", hasher.finalize())
136}