Skip to main content

camel_cli/
lib.rs

1pub mod commands;
2mod security;
3pub mod template;
4
5use std::sync::Arc;
6
7// ---------------------------------------------------------------------------
8// Lint catalog registration — handle-free mirror of `commands::run`
9// ---------------------------------------------------------------------------
10
11/// Register a `ComponentBundle` from an empty TOML table, dropping any handle.
12/// On empty-config build error, log at warn and skip — lint must degrade
13/// gracefully (the skipped scheme surfaces as `unverified-scheme`), never fail
14/// to construct its catalog.
15macro_rules! register_bundle_empty {
16    ($ctx:expr, $Bundle:ty) => {{
17        let key = <$Bundle as camel_component_api::ComponentBundle>::config_key();
18        match <$Bundle as camel_component_api::ComponentBundle>::from_toml(
19            ::toml::Value::Table(::toml::map::Map::new()),
20        ) {
21            Ok(bundle) => {
22                <$Bundle as camel_component_api::ComponentBundle>::register_all(
23                    bundle,
24                    &mut *$ctx,
25                );
26            }
27            Err(err) => {
28                tracing::warn!(
29                    bundle = %key,
30                    error = %err,
31                    "lint catalog: empty-config build failed; skipping bundle (surfaces as unverified-scheme)"
32                );
33            }
34        }
35    }};
36}
37
38/// Like [`register_bundle_empty!`], but wires an empty datasource catalog
39/// (sql/surrealdb bundles). An empty catalog is acceptable — metadata is
40/// queryable regardless of configured datasources.
41macro_rules! register_datasource_bundle_empty {
42    ($ctx:expr, $Bundle:ty, $catalog:expr) => {{
43        let key = <$Bundle as camel_component_api::ComponentBundle>::config_key();
44        match <$Bundle as camel_component_api::ComponentBundle>::from_toml(
45            ::toml::Value::Table(::toml::map::Map::new()),
46        ) {
47            Ok(bundle) => {
48                let bundle = bundle.with_catalog(::std::sync::Arc::clone(&$catalog));
49                <$Bundle as camel_component_api::ComponentBundle>::register_all(
50                    bundle,
51                    &mut *$ctx,
52                );
53            }
54            Err(err) => {
55                tracing::warn!(
56                    bundle = %key,
57                    error = %err,
58                    "lint catalog: empty-config build failed; skipping datasource bundle (surfaces as unverified-scheme)"
59                );
60            }
61        }
62    }};
63}
64
65/// Register the built-in components into `ctx` for lint catalog population.
66///
67/// This mirrors `commands::run`'s registration list but is HANDLE-FREE: it
68/// passes empty/default config to every bundle, registers bridge components
69/// without their runtime handles (no `xsd_bridge_backend` / `bridge_runtime`,
70/// no `BridgeCleanup`), and drops any pool returned by jms/cxf. It SKIPS the
71/// path/route-coupled bundles: `wasm` (needs a config-relative `base_dir`) and
72/// `exec` (route-conditional registration). Skipped schemes surface as
73/// `unverified-scheme` notes in lint output, which is the accepted
74/// graceful-degradation behaviour.
75///
76/// Because `Component::metadata()` has a trait default returning
77/// `ComponentMetadata::minimal(scheme)` and `Registry::register()` harvests
78/// it unconditionally, registering each builtin makes its scheme queryable by
79/// the lint catalog (rich metadata where the component opts into it, a
80/// minimal-but-present entry otherwise).
81///
82/// Drift tradeoff: this list and `run`'s list are kept separate on purpose —
83/// `run`'s registration is lifecycle-entangled with bridge/pool/datasource/
84/// path handles that lint has no use for. The drift is bounded and caught by
85/// the corpus baseline (`tests/lint_corpus.rs`); unification is tracked by a
86/// bd follow-up.
87pub fn register_builtin_components_for_lint(ctx: &mut camel_core::CamelContext) {
88    use camel_api::datasource::DatasourceCatalog;
89    use camel_core::datasource::RuntimeDatasourceCatalog;
90
91    // --- Config-independent components (handle-free) ---
92    ctx.register_component(camel_component_timer::TimerComponent::new());
93    ctx.register_component(camel_component_cron::CronComponent::new());
94    ctx.register_component(camel_component_log::LogComponent::new());
95    ctx.register_component(camel_component_direct::DirectComponent::new());
96    ctx.register_component(camel_component_seda::SedaComponent::new());
97    ctx.register_component(camel_component_mock::MockComponent::new());
98    ctx.register_component(camel_component_controlbus::ControlBusComponent::new());
99
100    // --- Bridge components WITHOUT their runtime handles ---
101    // validator: xsd_bridge_backend() not captured, no backend stored.
102    ctx.register_component(camel_component_validator::ValidatorComponent::new());
103    // xslt / xj: bridge_runtime() not captured, no BridgeCleanup installed.
104    // Lint is short-lived; no shutdown cleanup needed.
105    ctx.register_component(camel_xslt::XsltComponent::default());
106    ctx.register_component(camel_xj::XjComponent::default());
107
108    // --- Empty datasource catalog for sql/surrealdb bundles ---
109    let datasource_catalog: Arc<dyn DatasourceCatalog> = Arc::new(RuntimeDatasourceCatalog::new(
110        std::collections::HashMap::new(),
111    ));
112
113    // --- Always-on bundles with empty config ---
114    register_bundle_empty!(ctx, camel_component_http::HttpBundle);
115    #[cfg(feature = "http-static")]
116    register_bundle_empty!(ctx, camel_component_http::HttpStaticBundle);
117    register_bundle_empty!(ctx, camel_component_ws::WsBundle);
118    register_bundle_empty!(ctx, camel_component_file::FileBundle);
119    register_bundle_empty!(ctx, camel_component_container::ContainerBundle);
120    register_bundle_empty!(ctx, camel_template::TemplateBundle);
121    register_bundle_empty!(ctx, camel_master::MasterBundle);
122    register_bundle_empty!(ctx, camel_component_opensearch::OpenSearchBundle);
123    register_bundle_empty!(ctx, camel_component_redis::RedisBundle);
124
125    // jms / cxf: registered without capturing their pool handle (lint has no
126    // runtime use for a bridge pool; metadata is harvested at register time).
127    register_bundle_empty!(ctx, camel_component_jms::JmsBundle);
128    register_bundle_empty!(ctx, camel_component_cxf::CxfBundle);
129
130    // --- Datasource bundles (empty datasource catalog) ---
131    register_datasource_bundle_empty!(ctx, camel_component_sql::SqlBundle, datasource_catalog);
132    #[cfg(feature = "surrealdb")]
133    register_datasource_bundle_empty!(
134        ctx,
135        camel_component_surrealdb::SurrealDbBundle,
136        datasource_catalog
137    );
138
139    // --- Feature-gated bundles (empty config) ---
140    #[cfg(feature = "kafka")]
141    register_bundle_empty!(ctx, camel_component_kafka::KafkaBundle);
142    #[cfg(feature = "mqtt")]
143    register_bundle_empty!(ctx, camel_component_mqtt::MqttBundle);
144    #[cfg(feature = "grpc")]
145    register_bundle_empty!(ctx, camel_component_grpc::GrpcBundle);
146    #[cfg(feature = "llm")]
147    register_bundle_empty!(ctx, camel_component_llm::LlmBundle);
148
149    // --- Skipped (path/route-coupled) ---
150    // wasm: needs a config-relative `base_dir`; lint has no canonical config.
151    // exec: route-conditional; lint has no discovered routes to gate on.
152    // Both surface as `unverified-scheme` in lint output by design.
153}