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-aware but phase-local — parser plugins
7//! classify framework-owned attributes, capture processed component templates,
8//! and emit per-element hydration metadata for the handler.
9
10pub mod fast;
11pub mod fast_v2;
12pub mod fast_v3;
13pub mod webui;
14
15use crate::component_registry::Component;
16use crate::Result;
17
18/// Parser-owned decision about how an attribute should be handled.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum AttributeAction {
21 /// Let the parser process the attribute normally.
22 Keep,
23 /// Skip the attribute without incrementing the element binding count.
24 Skip,
25 /// Skip the attribute and count it as a dynamic binding.
26 SkipAndCountBinding,
27}
28
29/// Build artifacts extracted from a parser plugin after parsing completes.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub enum ParserPluginArtifacts {
32 /// The plugin did not produce any post-parse artifacts.
33 None,
34 /// Client component templates keyed by tag name.
35 ComponentTemplates(Vec<(String, String)>),
36}
37
38/// A parser plugin that can customize template parsing behavior.
39///
40/// Plugins receive callbacks at key points during HTML parsing:
41/// - **Fragment lifecycle**: `start_fragment` before a fragment parse begins
42/// - **Component registration**: `register_component_template` when a component template is finalized
43/// - **Attribute classification**: `classify_attribute` for framework-specific attrs
44/// - **Element completion**: `finish_element` after attributes are processed
45///
46/// WebUI calls these hooks during parsing; plugins decide what (if anything) to do.
47pub trait ParserPlugin {
48 /// Called before parsing begins for a fragment.
49 ///
50 /// Plugins can use this to reset fragment-local counters while preserving
51 /// global build-level state such as tracked component templates.
52 fn start_fragment(&mut self, _fragment_id: &str) {}
53
54 /// Called when a component template has been fully processed for the active
55 /// CSS strategy and wrapped for shadow DOM rendering.
56 fn register_component_template(
57 &mut self,
58 tag_name: &str,
59 component: &Component,
60 processed_template: &str,
61 ) -> Result<()>;
62
63 /// Decide how a framework-owned attribute should be handled.
64 fn classify_attribute(&mut self, attr_name: &str) -> AttributeAction;
65
66 /// Called after all attributes on an element have been processed.
67 /// `binding_attribute_count` is the number of dynamic attribute bindings found.
68 /// Returns optional opaque bytes to emit as a `Plugin` protocol fragment.
69 fn finish_element(&mut self, binding_attribute_count: u32) -> Option<Vec<u8>>;
70
71 /// Consume the plugin and return any build artifacts it captured.
72 fn into_artifacts(self: Box<Self>) -> ParserPluginArtifacts {
73 ParserPluginArtifacts::None
74 }
75}