#![allow(clippy::unwrap_used)]
#![allow(clippy::indexing_slicing)]
pub mod contract;
pub mod dialect;
pub mod engine;
pub mod logging;
pub mod source_map;
pub mod transforms;
pub mod types;
pub use contract::*;
pub use dialect::*;
pub use engine::*;
pub use logging::*;
pub use source_map::*;
pub use transforms::*;
pub use types::*;
use std::borrow::Cow;
pub trait PreflightFormatter: Send + Sync {
type Error: std::error::Error + Send + Sync + 'static;
fn format<'a>(
&self,
source: &'a [u8],
dialect: ShellDialect,
config: FormatConfig,
) -> std::result::Result<FormattedSource<'a>, Self::Error>;
}
pub struct RashFormatter {
engine: NormalizationEngine,
_contract_system: contract::ContractSystem,
}
impl RashFormatter {
pub fn new() -> Self {
Self {
engine: NormalizationEngine::new(),
_contract_system: contract::ContractSystem::new(),
}
}
}
impl Default for RashFormatter {
fn default() -> Self {
Self::new()
}
}
impl PreflightFormatter for RashFormatter {
type Error = crate::Error;
fn format<'a>(
&self,
source: &'a [u8],
dialect: ShellDialect,
config: FormatConfig,
) -> std::result::Result<FormattedSource<'a>, Self::Error> {
let source_str = std::str::from_utf8(source)
.map_err(|e| crate::Error::Internal(format!("Invalid UTF-8: {e}")))?;
if self.engine.is_canonical(source) {
return Ok(FormattedSource {
text: Cow::Borrowed(source_str),
source_map: SourceMap::identity(source.len()),
metadata: SemanticMetadata::default(),
canonical_hash: blake3::hash(source).into(),
transforms: logging::TransformLog::new(),
});
}
let mut engine = self.engine.clone();
engine.normalize(source, dialect, config)
}
}
#[cfg(test)]
#[path = "formatter_tests.rs"]
mod formatter_tests;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_formatter_creation() {
let formatter = RashFormatter::new();
assert!(std::ptr::eq(&formatter as *const _, &formatter as *const _));
}
#[test]
fn test_format_identity() {
let formatter = RashFormatter::new();
let source = b"echo hello";
let config = FormatConfig::default();
let result = formatter.format(source, ShellDialect::Posix, config);
assert!(result.is_ok());
let formatted = result.unwrap();
assert_eq!(formatted.text.as_ref(), "echo hello");
}
#[test]
fn test_format_invalid_utf8() {
let formatter = RashFormatter::new();
let source = &[0xff, 0xfe, 0xfd]; let config = FormatConfig::default();
let result = formatter.format(source, ShellDialect::Posix, config);
assert!(result.is_err());
}
}