use super::{Lens, LensContext, LensId, LensOutput};
use forge::budget::estimator::TokenEstimator;
use forge::signal::compactor;
pub struct ClarityLens;
impl Lens for ClarityLens {
fn id(&self) -> LensId {
LensId::Clarity
}
fn apply(&self, input: &str, _ctx: &LensContext) -> LensOutput {
let tokens_before = TokenEstimator::count_nonblocking(input);
let normalised = compactor::normalise(input);
let stripped = strip_line_comments(&normalised);
let compacted = compactor::collapse_blanks(&stripped);
let tokens_after = TokenEstimator::count_nonblocking(&compacted);
LensOutput {
content: compacted,
tokens_before,
tokens_after,
applied: vec!["clarity".into()],
}
}
}
fn strip_line_comments(input: &str) -> String {
let mut result = Vec::with_capacity(input.lines().count());
for line in input.lines() {
let trimmed = line.trim();
if trimmed.starts_with("//") || trimmed.starts_with('#') {
continue;
}
if trimmed.starts_with("* ")
|| trimmed == "*"
|| trimmed.starts_with("*/")
|| trimmed.starts_with("/**")
|| trimmed.starts_with("/*")
{
continue;
}
result.push(line);
}
let joined = result.join("\n");
if input.ends_with('\n') {
format!("{joined}\n")
} else {
joined
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strips_double_slash_comments() {
let input = "// comment\nfn foo() {}\n// another\nlet x = 1;\n";
let result = strip_line_comments(input);
assert!(!result.contains("// comment"));
assert!(!result.contains("// another"));
assert!(result.contains("fn foo()"));
assert!(result.contains("let x = 1;"));
}
#[test]
fn strips_hash_comments() {
let input = "# comment\ndef foo():\n pass\n";
let result = strip_line_comments(input);
assert!(!result.contains("# comment"));
assert!(result.contains("def foo():"));
}
#[test]
fn strips_jsdoc_blocks() {
let input = "/**\n * Authenticate a user.\n * @param email\n */\nasync login() {}\n";
let result = strip_line_comments(input);
assert!(!result.contains("/**"));
assert!(!result.contains("* Authenticate"));
assert!(result.contains("async login()"));
}
#[test]
fn preserves_trailing_newline() {
let input = "// comment\ncode();\n";
let result = strip_line_comments(input);
assert!(result.ends_with('\n'));
}
#[test]
fn no_trailing_newline_preserved() {
let input = "// comment\ncode()";
let result = strip_line_comments(input);
assert!(!result.ends_with('\n'));
assert!(result.contains("code()"));
}
}