#@transform

    A composable DOM rewrite pipeline. Build an array of TransformSpec values and hand them to apply_transforms along with a node. Each spec runs over the tree in order and can drop, unwrap, escape, edit, or annotate matching elements.

    The examples below are mbt check blocks and run as part of moon test transform.

    #The five element actions

    ///|
    pub(all) enum DecideAction {
    Keep // leave alone
    Drop // remove the element and its subtree
    Unwrap // remove the tag but splice children up
    Empty // keep the tag, remove the children
    Escape // serialize the tag to its HTML-escaped text form
    }

    Each action has a dedicated constructor (drop, unwrap, escape, empty) and decide runs your callback to pick per node.

    ///|
    test "readme transform actions" {
    let frag = @dom.fragment(children=[
    @dom.element("script", children=[@dom.text("alert(1)")]),
    @dom.element("font", children=[@dom.text("loud")]),
    ])
    let out = @transform.apply_transforms(frag, [
    @transform.TransformSpec::drop("script"),
    @transform.TransformSpec::unwrap("font"),
    ])
    inspect(
    @ser.to_html(out, pretty=false),
    content=(
    #|loud
    ),
    )
    }

    #Shaping attributes

    drop_attrs, set_attrs, allowlist_attrs, merge_attrs, and edit_attrs cover the common attribute changes. merge_attrs is especially handy for token-list attributes like rel:

    ///|
    test "readme transform merge_attrs" {
    let frag = @dom.fragment(children=[
    @dom.element(
    "a",
    attrs={ "href": Some("https://example.com"), "rel": Some("nofollow") },
    children=[@dom.text("link")],
    ),
    ])
    let out = @transform.apply_transforms(frag, [
    @transform.TransformSpec::merge_attrs("a", attr="rel", tokens=[
    "noopener", "noreferrer",
    ]),
    ])
    inspect(
    @ser.to_html(out, pretty=false),
    content=(
    #|<a href="https://example.com" rel="nofollow noopener noreferrer">link</a>
    ),
    )
    }

    #Composing with stage

    stage bundles a set of transforms into one logical spec — useful when you want to keep your top-level pipeline short.

    ///|
    test "readme transform stage" {
    let frag = @dom.fragment(children=[
    @dom.element("script", children=[@dom.text("evil")]),
    @dom.comment(" tracking "),
    @dom.element("p", children=[@dom.text("keep")]),
    ])
    let cleanup = @transform.TransformSpec::stage([
    @transform.TransformSpec::drop("script"),
    @transform.TransformSpec::drop_comments(),
    ])
    let out = @transform.apply_transforms(frag, [cleanup])
    inspect(
    @ser.to_html(out, pretty=false),
    content=(
    #|<p>keep</p>
    ),
    )
    }

    #Feature-flagging with enabled

    Every spec constructor accepts enabled=false to skip the step without restructuring the pipeline.

    ///|
    test "readme transform enabled flag" {
    let frag = @dom.fragment(children=[
    @dom.element("script", children=[@dom.text("kept")]),
    ])
    let out = @transform.apply_transforms(frag, [
    @transform.TransformSpec::drop("script", enabled=false),
    ])
    inspect(
    @ser.to_html(out, pretty=false),
    content=(
    #|<script>kept</script>
    ),
    )
    }

    #Telemetry hooks

    Every spec constructor also accepts hook= (called per matching node) and report= (called with a string code and optional node when the spec changes something). They let you collect counters and audit trails without altering the rewrite itself.

    DecideAction

    pub(all) enum DecideAction {
    Keep
    Drop
    Unwrap
    Empty
    Escape
    } derive(Eq,
    Debug
    )

    Action returned by a TransformSpec::decide callback.

    Keep leaves the matched node unchanged. The other variants apply the same structural operations as the corresponding selector transforms.

    DecideAction::equal

    #deprecated("implicit derived-impl promotion; call the trait method directly")
    fn DecideAction::equal(DecideAction, DecideAction) -> Bool

    DecideAction::not_equal

    #deprecated("implicit derived-impl promotion; call the trait method directly")
    fn DecideAction::not_equal(x : DecideAction, y : DecideAction) -> Bool

    DecideAction::to_repr

    #deprecated("implicit derived-impl promotion; call the trait method directly")
    fn DecideAction::to_repr(DecideAction) ->
    Repr

    TransformSpec

    pub struct TransformSpec {
    // private fields
    } derive(
    Debug
    )

    A DOM transform specification for apply_transforms.

    The current port covers deterministic structural, attribute, callback, URL/style, utility, and sanitizer transforms. Most selector and node-kind transforms also support hook/report callbacks.

    TransformSpec::allow_style_attrs

    fn TransformSpec::allow_style_attrs(selector : StringView, allowed_css_properties~ : Array[String], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that sanitizes inline style attributes.

    TransformSpec::allowlist_attrs

    fn TransformSpec::allowlist_attrs(selector : StringView, allowed_attributes : Map[String, Array[String]], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that keeps only allowed attributes on matching elements.

    TransformSpec::collapse_whitespace

    fn TransformSpec::collapse_whitespace(skip_tags? : Array[String], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that collapses runs of HTML whitespace in text nodes.

    TransformSpec::decide

    fn TransformSpec::decide(selector : StringView, callback : (
    Node
    ) -> DecideAction, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that chooses a structural action for matching nodes.

    TransformSpec::drop

    fn TransformSpec::drop(selector : StringView, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that removes elements matching selector.

    TransformSpec::drop_attrs

    fn TransformSpec::drop_attrs(selector : StringView, patterns : Array[String], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that removes matching attributes from matching elements.

    TransformSpec::drop_comments

    fn TransformSpec::drop_comments(enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that removes comment nodes.

    TransformSpec::drop_doctype

    fn TransformSpec::drop_doctype(enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that removes doctype nodes.

    TransformSpec::drop_foreign_namespaces

    fn TransformSpec::drop_foreign_namespaces(enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that removes elements outside the HTML namespace.

    TransformSpec::drop_url_attrs

    fn TransformSpec::drop_url_attrs(selector : StringView, url_policy~ :
    UrlPolicy
    , enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that validates URL-valued attributes with url_policy.

    TransformSpec::edit

    fn TransformSpec::edit(selector : StringView, callback : (
    Node
    ) -> Unit, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that invokes callback for matching elements.

    TransformSpec::edit_attrs

    fn TransformSpec::edit_attrs(selector : StringView, callback : (
    Node
    ) -> Map[String, String?]?, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that replaces matching element attributes when callback returns a map.

    TransformSpec::edit_document

    fn TransformSpec::edit_document(callback : (
    Node
    ) -> Unit, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that invokes callback once on the supplied root.

    TransformSpec::empty

    fn TransformSpec::empty(selector : StringView, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that removes all children from matching elements.

    TransformSpec::escape

    fn TransformSpec::escape(selector : StringView, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that emits matching element tags as text and keeps children.

    TransformSpec::linkify

    fn TransformSpec::linkify(config? :
    LinkifyConfig
    , skip_tags? : Array[String], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that linkifies URL and email text nodes.

    TransformSpec::merge_attrs

    fn TransformSpec::merge_attrs(tag : StringView, attr~ : StringView, tokens~ : Array[String], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that merges tokens into a whitespace-delimited attribute.

    TransformSpec::prune_empty

    fn TransformSpec::prune_empty(selector : StringView, strip_whitespace? : Bool, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that recursively removes empty matching elements.

    TransformSpec::sanitize

    Build a transform that sanitizes the DOM tree with an optional policy.

    TransformSpec::set_attrs

    fn TransformSpec::set_attrs(selector : StringView, attrs : Map[String, String?], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that sets or adds attributes on matching elements.

    TransformSpec::stage

    fn TransformSpec::stage(transforms : Array[TransformSpec], enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build an explicit transform stage. Stages split a transform list into separate passes and may report against the current root before the pass.

    TransformSpec::unwrap

    fn TransformSpec::unwrap(selector : StringView, enabled? : Bool, hook? : (
    Node
    ) -> Unit, report? : (String,
    Node
    ?) -> Unit) -> TransformSpec

    Build a transform that replaces matching elements with their children.

    apply_transforms

    Apply DOM transforms in order.

    The transform mutates and returns the current root. Selector transforms process the children of the supplied root, matching the Python constructor-time pipeline where the root is normally a document or document fragment container.