use async_trait::async_trait;
use recoco::base::value::Value;
use recoco::ops::factory_bases::SimpleFunctionFactoryBase;
use recoco::ops::interface::{FlowInstanceContext, SimpleFunctionExecutor};
use recoco::ops::sdk::{OpArgsResolver, SimpleFunctionAnalysisOutput};
use serde::Deserialize;
use std::sync::Arc;
pub struct ThreadParseFactory;
#[derive(Debug, Clone, Deserialize)]
pub struct ThreadParseSpec {}
#[async_trait]
impl SimpleFunctionFactoryBase for ThreadParseFactory {
type Spec = ThreadParseSpec;
type ResolvedArgs = ();
fn name(&self) -> &str {
"thread_parse"
}
async fn analyze<'a>(
&'a self,
_spec: &'a Self::Spec,
_args_resolver: &mut OpArgsResolver<'a>,
_context: &FlowInstanceContext,
) -> Result<SimpleFunctionAnalysisOutput<Self::ResolvedArgs>, recoco::prelude::Error> {
Ok(SimpleFunctionAnalysisOutput {
resolved_args: (),
output_schema: crate::conversion::get_thread_parse_output_schema(),
behavior_version: Some(1),
})
}
async fn build_executor(
self: Arc<Self>,
_spec: Self::Spec,
_resolved_args: Self::ResolvedArgs,
_context: Arc<FlowInstanceContext>,
) -> Result<impl SimpleFunctionExecutor, recoco::prelude::Error> {
Ok(ThreadParseExecutor)
}
}
pub struct ThreadParseExecutor;
#[async_trait]
impl SimpleFunctionExecutor for ThreadParseExecutor {
async fn evaluate(&self, input: Vec<Value>) -> Result<Value, recoco::prelude::Error> {
let content = input
.first()
.ok_or_else(|| recoco::prelude::Error::client("Missing content"))?
.as_str()
.map_err(|e| recoco::prelude::Error::client(e.to_string()))?;
let lang_str = input
.get(1)
.ok_or_else(|| recoco::prelude::Error::client("Missing language"))?
.as_str()
.map_err(|e| recoco::prelude::Error::client(e.to_string()))?;
let path_str = input
.get(2)
.and_then(|v| v.as_str().ok())
.map(|v| v.to_string())
.unwrap_or_else(|| "unknown".to_string());
let lang = thread_language::from_extension_str(lang_str)
.or_else(|| {
let p = std::path::PathBuf::from(format!("dummy.{}", lang_str));
thread_language::from_extension(&p)
})
.ok_or_else(|| {
recoco::prelude::Error::client(format!("Unsupported language: {}", lang_str))
})?;
use thread_ast_engine::tree_sitter::LanguageExt;
let root = lang.ast_grep(content);
let fingerprint = thread_services::conversion::compute_content_fingerprint(content);
let path = std::path::PathBuf::from(&path_str);
let mut doc =
thread_services::conversion::root_to_parsed_document(root, path, lang, fingerprint);
thread_services::conversion::extract_basic_metadata(&doc)
.map(|metadata| {
doc.metadata = metadata;
})
.map_err(|e| {
recoco::prelude::Error::internal_msg(format!("Extraction error: {}", e))
})?;
use crate::conversion::serialize_parsed_doc;
serialize_parsed_doc(&doc)
}
fn enable_cache(&self) -> bool {
true
}
fn timeout(&self) -> Option<std::time::Duration> {
Some(std::time::Duration::from_secs(30))
}
}