webui_parser/plugin/mod.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT license.
3
4//! Parser plugin trait and built-in plugin implementations.
5//!
6//! The plugin system is framework-agnostic — WebUI provides parsing hooks
7//! and plugins decide what to do. Different frameworks (FAST, LIT, etc.)
8//! implement `ParserPlugin` with their own component discovery and
9//! hydration data emission logic.
10
11pub mod fast;
12
13pub use fast::generate_f_template;
14pub use fast::FastParserPlugin;
15
16use crate::component_registry::Component;
17use crate::Result;
18use std::any::Any;
19
20/// A parser plugin that can customize template parsing behavior.
21///
22/// Plugins receive callbacks at key points during HTML parsing:
23/// - **Component discovery**: `on_parse_component` when a custom element is found
24/// - **Attribute filtering**: `should_skip_attribute` to skip framework-specific attrs
25/// - **Body end injection**: `on_body_end` to inject framework content before `</body>`
26/// - **Element completion**: `on_element_parsed` after attributes are processed
27///
28/// WebUI calls these hooks during parsing; plugins decide what (if anything) to do.
29pub trait ParserPlugin: Any {
30 /// Called when a component element is encountered during parsing.
31 /// Use to track components for later template generation.
32 fn on_parse_component(&mut self, tag_name: &str, component: &Component) -> Result<()>;
33
34 /// Return `true` if this attribute should be skipped during parsing.
35 /// Framework-specific client-side bindings (e.g., `@click`, `f-ref`)
36 /// should be skipped since they are only meaningful at runtime.
37 fn should_skip_attribute(&self, attr_name: &str) -> bool;
38
39 /// Called when the `</body>` closing tag is encountered.
40 /// Returns optional raw HTML content to inject before `</body>`.
41 /// FAST uses this for `<f-template>` wrappers.
42 fn on_body_end(&mut self) -> Option<String>;
43
44 /// Called after all attributes on an element have been processed.
45 /// `binding_attribute_count` is the number of dynamic attribute bindings found.
46 /// Returns optional opaque bytes to emit as a `Plugin` protocol fragment.
47 fn on_element_parsed(&mut self, binding_attribute_count: u32) -> Option<Vec<u8>>;
48
49 /// Downcast to `Any` for plugin-specific access.
50 fn as_any(&self) -> &dyn Any;
51
52 /// Downcast to mutable `Any` for plugin-specific access.
53 fn as_any_mut(&mut self) -> &mut dyn Any;
54}