Skip to main content

hm_dsl_engine/
lib.rs

1use std::path::Path;
2
3use async_trait::async_trait;
4use serde::Deserialize;
5
6pub mod detect;
7pub mod python_engine;
8pub mod ts_engine;
9
10mod bundled_sources;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum DslLanguage {
14    Python,
15    TypeScript,
16}
17
18#[derive(Debug, Clone, Deserialize)]
19pub struct PipelineMeta {
20    pub slug: String,
21    pub name: String,
22}
23
24#[async_trait]
25pub trait DslEngine: Send + Sync {
26    async fn list_pipelines(&self, project_dir: &Path) -> anyhow::Result<Vec<PipelineMeta>>;
27    async fn render_pipeline_json(&self, project_dir: &Path, slug: &str) -> anyhow::Result<String>;
28    /// Emit the full discovery envelope JSON for every pipeline in the repo:
29    /// `{"schema_version": "...", "pipelines": [{slug, name, allow_manual,
30    /// triggers, definition}, ...]}`. Returned verbatim from the DSL runtime so
31    /// the backend's pipeline discovery can consume it directly.
32    async fn registry_json(&self, project_dir: &Path) -> anyhow::Result<String>;
33}
34
35/// Return an appropriate [`DslEngine`] for the given language.
36///
37/// # Errors
38///
39/// Returns an error if the required system runtime (`python3`, `node`/`bun`)
40/// is not found on PATH.
41pub fn engine_for(lang: DslLanguage) -> anyhow::Result<Box<dyn DslEngine>> {
42    match lang {
43        DslLanguage::Python => {
44            let engine = python_engine::SubprocessPythonEngine::new()?;
45            Ok(Box::new(engine))
46        }
47        DslLanguage::TypeScript => {
48            let engine = ts_engine::SubprocessTsEngine::new()?;
49            Ok(Box::new(engine))
50        }
51    }
52}