use crate::models::ParsedEntity;
pub fn prepare_entities(entities: &mut [ParsedEntity]) {
for entity in entities.iter_mut() {
entity.embed_text = build_embed_text(entity);
}
}
fn build_embed_text(entity: &ParsedEntity) -> String {
let mut parts: Vec<String> = Vec::with_capacity(8);
parts.push(format!("[{}] {}", entity.kind, entity.name));
if !entity.decorators.is_empty() {
let decorators_text = entity
.decorators
.iter()
.filter(|d| !d.trim().is_empty())
.cloned()
.collect::<Vec<_>>()
.join(", ");
if !decorators_text.is_empty() {
parts.push(format!("Decorators: {}", decorators_text));
}
}
if let Some(sig) = &entity.signature {
parts.push(format!("Signature: {sig}"));
}
if let Some(doc) = &entity.docstring
&& !doc.trim().is_empty()
{
parts.push(doc.trim().to_owned());
}
if !entity.inline_comments.is_empty() {
let inline_text = entity
.inline_comments
.iter()
.filter(|c| !c.trim().is_empty())
.cloned()
.collect::<Vec<_>>()
.join("\n");
if !inline_text.trim().is_empty() {
parts.push(format!("Implementation context:\n{}", inline_text));
}
}
parts.push(format!("File: {}:{}", entity.file_path, entity.start_line));
parts.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::{EntityKind, ParsedEntity};
#[test]
fn test_build_embed_text_minimal() {
let entity = ParsedEntity::new(
"MyClass",
EntityKind::Class,
"com.example.MyClass",
None,
None,
"java",
"com/example/MyClass.java",
10,
20,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[class] MyClass"));
assert!(embed_text.contains("File: com/example/MyClass.java:10"));
assert!(!embed_text.contains("Signature:"));
assert!(!embed_text.contains("Decorators:"));
}
#[test]
fn test_build_embed_text_full() {
let mut entity = ParsedEntity::new(
"saveUser",
EntityKind::Method,
"UserService.saveUser",
Some("public void saveUser(User user)".to_string()),
Some("Saves a new user to the database.".to_string()),
"java",
"UserService.java",
42,
50,
Some("UserService".to_string()),
"test-repo",
);
entity.decorators = vec!["@Transactional".to_string(), "@Override".to_string()];
entity.inline_comments = vec![
"// Check for duplicates".to_string(),
"/* Commit transaction */".to_string(),
];
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[method] saveUser"));
assert!(embed_text.contains("Signature: public void saveUser(User user)"));
assert!(embed_text.contains("Saves a new user to the database."));
assert!(embed_text.contains("Decorators: @Transactional, @Override"));
assert!(embed_text.contains(
"Implementation context:\n// Check for duplicates\n/* Commit transaction */"
));
assert!(embed_text.contains("File: UserService.java:42"));
}
#[test]
fn test_prepare_entities_batch() {
let entity1 = ParsedEntity::new(
"Class1",
EntityKind::Class,
"Class1",
None,
None,
"java",
"file1.java",
1,
10,
None,
"test-repo",
);
let entity2 = ParsedEntity::new(
"Class2",
EntityKind::Class,
"Class2",
None,
None,
"java",
"file2.java",
1,
10,
None,
"test-repo",
);
let mut entities = vec![entity1, entity2];
assert!(entities[0].embed_text.is_empty());
assert!(entities[1].embed_text.is_empty());
prepare_entities(&mut entities);
assert!(!entities[0].embed_text.is_empty());
assert!(!entities[1].embed_text.is_empty());
assert!(entities[0].embed_text.contains("Class1"));
assert!(entities[1].embed_text.contains("Class2"));
}
#[test]
fn test_build_embed_text_build_dependency() {
let entity = ParsedEntity::new(
"org.springframework:spring-core:5.3.29",
EntityKind::BuildDependency,
"org.springframework:spring-core:5.3.29",
Some("scope: compile".to_string()),
Some("Maven dependency: org.springframework:spring-core:5.3.29".to_string()),
"xml",
"pom.xml",
15,
19,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[build_dependency] org.springframework:spring-core:5.3.29"));
assert!(embed_text.contains("Signature: scope: compile"));
assert!(embed_text.contains("Maven dependency:"));
assert!(embed_text.contains("File: pom.xml:15"));
}
#[test]
fn test_build_embed_text_build_plugin() {
let entity = ParsedEntity::new(
"org.apache.maven.plugins:maven-compiler-plugin:3.11.0",
EntityKind::BuildPlugin,
"org.apache.maven.plugins:maven-compiler-plugin:3.11.0",
None,
Some("Maven plugin: org.apache.maven.plugins:maven-compiler-plugin:3.11.0".to_string()),
"xml",
"pom.xml",
30,
35,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[build_plugin]"));
assert!(embed_text.contains("maven-compiler-plugin"));
assert!(embed_text.contains("Maven plugin:"));
assert!(embed_text.contains("File: pom.xml:30"));
}
#[test]
fn test_build_embed_text_build_task() {
let entity = ParsedEntity::new(
"buildDocs",
EntityKind::BuildTask,
"buildDocs",
None,
Some("task buildDocs(type: Copy) {".to_string()),
"groovy",
"build.gradle",
25,
25,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[build_task] buildDocs"));
assert!(embed_text.contains("task buildDocs(type: Copy) {"));
assert!(embed_text.contains("File: build.gradle:25"));
}
#[test]
fn test_build_embed_text_pipeline_stage() {
let entity = ParsedEntity::new(
"stage: Build",
EntityKind::PipelineStage,
"stage: Build",
None,
Some("stage('Build') {".to_string()),
"groovy",
"Jenkinsfile",
10,
10,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[pipeline_stage] stage: Build"));
assert!(embed_text.contains("File: Jenkinsfile:10"));
}
#[test]
fn test_build_embed_text_pipeline_step() {
let entity = ParsedEntity::new(
"sh: mvn compile",
EntityKind::PipelineStep,
"sh: mvn compile",
None,
Some("sh 'mvn compile'".to_string()),
"groovy",
"Jenkinsfile",
12,
12,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[pipeline_step] sh: mvn compile"));
assert!(embed_text.contains("File: Jenkinsfile:12"));
}
#[test]
fn test_build_embed_text_groovy_class() {
let entity = ParsedEntity::new(
"MyGroovyClass",
EntityKind::GroovyClass,
"com.example.MyGroovyClass",
None,
Some("A Groovy class".to_string()),
"groovy",
"src/MyGroovyClass.groovy",
1,
10,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[groovy_class] MyGroovyClass"));
assert!(embed_text.contains("A Groovy class"));
}
#[test]
fn test_build_embed_text_groovy_interface() {
let entity = ParsedEntity::new(
"MyGroovyInterface",
EntityKind::GroovyInterface,
"com.example.MyGroovyInterface",
None,
None,
"groovy",
"src/MyGroovyInterface.groovy",
1,
5,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[groovy_interface] MyGroovyInterface"));
}
#[test]
fn test_build_embed_text_groovy_trait() {
let entity = ParsedEntity::new(
"MyGroovyTrait",
EntityKind::GroovyTrait,
"com.example.MyGroovyTrait",
None,
None,
"groovy",
"src/MyGroovyTrait.groovy",
1,
8,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[groovy_trait] MyGroovyTrait"));
}
#[test]
fn test_build_embed_text_groovy_method() {
let mut entity = ParsedEntity::new(
"save",
EntityKind::GroovyMethod,
"UserService.save",
Some("def save(User user)".to_string()),
Some("Saves the user".to_string()),
"groovy",
"UserService.groovy",
42,
46,
Some("UserService".to_string()),
"test-repo",
);
entity.decorators = vec!["@Transactional".to_string()];
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[groovy_method] save"));
assert!(embed_text.contains("Signature: def save(User user)"));
assert!(embed_text.contains("Saves the user"));
assert!(embed_text.contains("Decorators: @Transactional"));
}
#[test]
fn test_build_embed_text_groovy_property() {
let entity = ParsedEntity::new(
"config",
EntityKind::GroovyProperty,
"com.example.App.config",
None,
None,
"groovy",
"App.groovy",
3,
3,
None,
"test-repo",
);
let embed_text = build_embed_text(&entity);
assert!(embed_text.contains("[groovy_property] config"));
}
}