diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /vendor/markup5ever/interface | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/markup5ever/interface')
-rw-r--r-- | vendor/markup5ever/interface/mod.rs | 377 | ||||
-rw-r--r-- | vendor/markup5ever/interface/tree_builder.rs | 253 |
2 files changed, 630 insertions, 0 deletions
diff --git a/vendor/markup5ever/interface/mod.rs b/vendor/markup5ever/interface/mod.rs new file mode 100644 index 000000000..f498fdfbf --- /dev/null +++ b/vendor/markup5ever/interface/mod.rs @@ -0,0 +1,377 @@ +// Copyright 2014-2017 The html5ever Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Types for tag and attribute names, and tree-builder functionality. + +use std::fmt; +use tendril::StrTendril; + +pub use self::tree_builder::{create_element, AppendNode, AppendText, ElementFlags, NodeOrText}; +pub use self::tree_builder::{LimitedQuirks, NoQuirks, Quirks, QuirksMode}; +pub use self::tree_builder::{NextParserState, Tracer, TreeSink}; +use super::{LocalName, Namespace, Prefix}; + +/// An [expanded name], containing the tag and the namespace. +/// +/// [expanded name]: https://www.w3.org/TR/REC-xml-names/#dt-expname +#[derive(Copy, Clone, Eq, Hash)] +pub struct ExpandedName<'a> { + pub ns: &'a Namespace, + pub local: &'a LocalName, +} + +impl<'a, 'b> PartialEq<ExpandedName<'a>> for ExpandedName<'b> { + fn eq(&self, other: &ExpandedName<'a>) -> bool { + self.ns == other.ns && self.local == other.local + } +} + +impl<'a> fmt::Debug for ExpandedName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.ns.is_empty() { + write!(f, "{}", self.local) + } else { + write!(f, "{{{}}}:{}", self.ns, self.local) + } + } +} + +/// Helper to quickly create an expanded name. +/// +/// Can be used with no namespace as `expanded_name!("", "some_name")` +/// or with a namespace as `expanded_name!(ns "some_name")`. In the +/// latter case, `ns` is one of the symbols which the [`ns!`][ns] +/// macro accepts; note the lack of a comma between the `ns` and +/// `"some_name"`. +/// +/// [ns]: macro.ns.html +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate markup5ever; +/// +/// # fn main() { +/// use markup5ever::ExpandedName; +/// +/// assert_eq!( +/// expanded_name!("", "div"), +/// ExpandedName { +/// ns: &ns!(), +/// local: &local_name!("div") +/// } +/// ); +/// +/// assert_eq!( +/// expanded_name!(html "div"), +/// ExpandedName { +/// ns: &ns!(html), +/// local: &local_name!("div") +/// } +/// ); +/// # } +#[macro_export] +macro_rules! expanded_name { + ("", $local: tt) => { + $crate::interface::ExpandedName { + ns: &ns!(), + local: &local_name!($local), + } + }; + ($ns: ident $local: tt) => { + $crate::interface::ExpandedName { + ns: &ns!($ns), + local: &local_name!($local), + } + }; +} + +pub mod tree_builder; + +/// A fully qualified name (with a namespace), used to depict names of tags and attributes. +/// +/// Namespaces can be used to differentiate between similar XML fragments. For example: +/// +/// ```text +/// // HTML +/// <table> +/// <tr> +/// <td>Apples</td> +/// <td>Bananas</td> +/// </tr> +/// </table> +/// +/// // Furniture XML +/// <table> +/// <name>African Coffee Table</name> +/// <width>80</width> +/// <length>120</length> +/// </table> +/// ``` +/// +/// Without XML namespaces, we can't use those two fragments in the same document +/// at the same time. However if we declare a namespace we could instead say: +/// +/// ```text +/// +/// // Furniture XML +/// <furn:table xmlns:furn="https://furniture.rs"> +/// <furn:name>African Coffee Table</furn:name> +/// <furn:width>80</furn:width> +/// <furn:length>120</furn:length> +/// </furn:table> +/// ``` +/// +/// and bind the prefix `furn` to a different namespace. +/// +/// For this reason we parse names that contain a colon in the following way: +/// +/// ```text +/// <furn:table> +/// | | +/// | +- local name +/// | +/// prefix (when resolved gives namespace_url `https://furniture.rs`) +/// ``` +/// +/// NOTE: `Prefix`, `LocalName` and `Prefix` are all derivative of +/// `string_cache::atom::Atom` and `Atom` implements `Deref<str>`. +/// +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone)] +#[cfg_attr(feature = "heap_size", derive(HeapSizeOf))] +pub struct QualName { + /// The prefix of qualified (e.g. `furn` in `<furn:table>` above). + /// Optional (since some namespaces can be empty or inferred), and + /// only useful for namespace resolution (since different prefix + /// can still resolve to same namespace) + /// + /// ``` + /// + /// # fn main() { + /// use markup5ever::{QualName, Namespace, LocalName, Prefix}; + /// + /// let qual = QualName::new( + /// Some(Prefix::from("furn")), + /// Namespace::from("https://furniture.rs"), + /// LocalName::from("table"), + /// ); + /// + /// assert_eq!("furn", &qual.prefix.unwrap()); + /// + /// # } + /// ``` + pub prefix: Option<Prefix>, + /// The namespace after resolution (e.g. `https://furniture.rs` in example above). + /// + /// ``` + /// # use markup5ever::{QualName, Namespace, LocalName, Prefix}; + /// + /// # fn main() { + /// # let qual = QualName::new( + /// # Some(Prefix::from("furn")), + /// # Namespace::from("https://furniture.rs"), + /// # LocalName::from("table"), + /// # ); + /// + /// assert_eq!("https://furniture.rs", &qual.ns); + /// # } + /// ``` + /// + /// When matching namespaces used by HTML we can use `ns!` macro. + /// Although keep in mind that ns! macro only works with namespaces + /// that are present in HTML spec (like `html`, `xmlns`, `svg`, etc.). + /// + /// ``` + /// #[macro_use] extern crate markup5ever; + /// + /// # use markup5ever::{QualName, Namespace, LocalName, Prefix}; + /// + /// let html_table = QualName::new( + /// None, + /// ns!(html), + /// LocalName::from("table"), + /// ); + /// + /// assert!( + /// match html_table.ns { + /// ns!(html) => true, + /// _ => false, + /// } + /// ); + /// + /// ``` + pub ns: Namespace, + /// The local name (e.g. `table` in `<furn:table>` above). + /// + /// ``` + /// # use markup5ever::{QualName, Namespace, LocalName, Prefix}; + /// + /// # fn main() { + /// # let qual = QualName::new( + /// # Some(Prefix::from("furn")), + /// # Namespace::from("https://furniture.rs"), + /// # LocalName::from("table"), + /// # ); + /// + /// assert_eq!("table", &qual.local); + /// # } + /// ``` + /// When matching local name we can also use the `local_name!` macro: + /// + /// ``` + /// #[macro_use] extern crate markup5ever; + /// + /// # use markup5ever::{QualName, Namespace, LocalName, Prefix}; + /// + /// # let qual = QualName::new( + /// # Some(Prefix::from("furn")), + /// # Namespace::from("https://furniture.rs"), + /// # LocalName::from("table"), + /// # ); + /// + /// // Initialize qual to furniture example + /// + /// assert!( + /// match qual.local { + /// local_name!("table") => true, + /// _ => false, + /// } + /// ); + /// + /// ``` + pub local: LocalName, +} + +impl QualName { + /// Basic constructor function. + /// + /// First let's try it for the following example where `QualName` + /// is defined as: + /// ```text + /// <furn:table> <!-- namespace url is https://furniture.rs --> + /// ``` + /// + /// Given this definition, we can define `QualName` using strings. + /// + /// ``` + /// use markup5ever::{QualName, Namespace, LocalName, Prefix}; + /// + /// # fn main() { + /// let qual_name = QualName::new( + /// Some(Prefix::from("furn")), + /// Namespace::from("https://furniture.rs"), + /// LocalName::from("table"), + /// ); + /// # } + /// ``` + /// + /// If we were instead to construct this element instead: + /// + /// ```text + /// + /// <table> + /// ^^^^^---- no prefix and thus default html namespace + /// + /// ``` + /// + /// Or could define it using macros, like so: + /// + /// ``` + /// #[macro_use] extern crate markup5ever; + /// use markup5ever::{QualName, Namespace, LocalName, Prefix}; + /// + /// # fn main() { + /// let qual_name = QualName::new( + /// None, + /// ns!(html), + /// local_name!("table") + /// ); + /// # } + /// ``` + /// + /// Let's analyse the above example. + /// Since we have no prefix its value is None. Second we have html namespace. + /// In html5ever html namespaces are supported out of the box, + /// we can write `ns!(html)` instead of typing `Namespace::from("http://www.w3.org/1999/xhtml")`. + /// Local name is also one of the HTML elements local names, so can + /// use `local_name!("table")` macro. + /// + #[inline] + pub fn new(prefix: Option<Prefix>, ns: Namespace, local: LocalName) -> QualName { + QualName { + prefix, + ns, + local, + } + } + + /// Take a reference of `self` as an `ExpandedName`, dropping the unresolved prefix. + /// + /// In XML and HTML prefixes are only used to extract the relevant namespace URI. + /// Expanded name only contains resolved namespace and tag name, which are only + /// relevant parts of an XML or HTML tag and attribute name respectively. + /// + /// In lieu of our XML Namespace example + /// + /// ```text + /// <furn:table> <!-- namespace url is https://furniture.rs --> + /// ``` + /// For it the expanded name would become roughly equivalent to: + /// + /// ```text + /// ExpandedName { + /// ns: "https://furniture.rs", + /// local: "table", + /// } + /// ``` + /// + #[inline] + pub fn expanded(&self) -> ExpandedName { + ExpandedName { + ns: &self.ns, + local: &self.local, + } + } +} + +/// A tag attribute, e.g. `class="test"` in `<div class="test" ...>`. +/// +/// The namespace on the attribute name is almost always ns!(""). +/// The tokenizer creates all attributes this way, but the tree +/// builder will adjust certain attribute names inside foreign +/// content (MathML, SVG). +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] +pub struct Attribute { + /// The name of the attribute (e.g. the `class` in `<div class="test">`) + pub name: QualName, + /// The value of the attribute (e.g. the `"test"` in `<div class="test">`) + pub value: StrTendril, +} + +#[cfg(test)] +mod tests { + use super::Namespace; + + #[test] + fn ns_macro() { + assert_eq!(ns!(), Namespace::from("")); + + assert_eq!(ns!(html), Namespace::from("http://www.w3.org/1999/xhtml")); + assert_eq!( + ns!(xml), + Namespace::from("http://www.w3.org/XML/1998/namespace") + ); + assert_eq!(ns!(xmlns), Namespace::from("http://www.w3.org/2000/xmlns/")); + assert_eq!(ns!(xlink), Namespace::from("http://www.w3.org/1999/xlink")); + assert_eq!(ns!(svg), Namespace::from("http://www.w3.org/2000/svg")); + assert_eq!( + ns!(mathml), + Namespace::from("http://www.w3.org/1998/Math/MathML") + ); + } +} diff --git a/vendor/markup5ever/interface/tree_builder.rs b/vendor/markup5ever/interface/tree_builder.rs new file mode 100644 index 000000000..43361f360 --- /dev/null +++ b/vendor/markup5ever/interface/tree_builder.rs @@ -0,0 +1,253 @@ +// Copyright 2014-2017 The html5ever Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains functionality for managing the DOM, including adding/removing nodes. +//! +//! It can be used by a parser to create the DOM graph structure in memory. + +use crate::interface::{Attribute, ExpandedName, QualName}; +use std::borrow::Cow; +use tendril::StrTendril; + +pub use self::NodeOrText::{AppendNode, AppendText}; +pub use self::QuirksMode::{LimitedQuirks, NoQuirks, Quirks}; + +/// Something which can be inserted into the DOM. +/// +/// Adjacent sibling text nodes are merged into a single node, so +/// the sink may not want to allocate a `Handle` for each. +pub enum NodeOrText<Handle> { + AppendNode(Handle), + AppendText(StrTendril), +} + +/// A document's quirks mode, for compatibility with old browsers. See [quirks mode on wikipedia] +/// for more information. +/// +/// [quirks mode on wikipedia]: https://en.wikipedia.org/wiki/Quirks_mode +#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)] +pub enum QuirksMode { + /// Full quirks mode + Quirks, + /// Almost standards mode + LimitedQuirks, + /// Standards mode + NoQuirks, +} + +/// Whether to interrupt further parsing of the current input until +/// the next explicit resumption of the tokenizer, or continue without +/// any interruption. +#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)] +pub enum NextParserState { + /// Stop further parsing. + Suspend, + /// Continue without interruptions. + Continue, +} + +/// Special properties of an element, useful for tagging elements with this information. +#[derive(Default)] +pub struct ElementFlags { + /// A document fragment should be created, associated with the element, + /// and returned in TreeSink::get_template_contents. + /// + /// See [template-contents in the whatwg spec][whatwg template-contents]. + /// + /// [whatwg template-contents]: https://html.spec.whatwg.org/multipage/#template-contents + pub template: bool, + + /// This boolean should be recorded with the element and returned + /// in TreeSink::is_mathml_annotation_xml_integration_point + /// + /// See [html-integration-point in the whatwg spec][whatwg integration-point]. + /// + /// [whatwg integration-point]: https://html.spec.whatwg.org/multipage/#html-integration-point + pub mathml_annotation_xml_integration_point: bool, + + // Prevent construction from outside module + _private: (), +} + +/// A constructor for an element. +/// +/// # Examples +/// +/// Create an element like `<div class="test-class-name"></div>`: +pub fn create_element<Sink>(sink: &mut Sink, name: QualName, attrs: Vec<Attribute>) -> Sink::Handle +where + Sink: TreeSink, +{ + let mut flags = ElementFlags::default(); + match name.expanded() { + expanded_name!(html "template") => flags.template = true, + expanded_name!(mathml "annotation-xml") => { + flags.mathml_annotation_xml_integration_point = attrs.iter().any(|attr| { + attr.name.expanded() == expanded_name!("", "encoding") && + (attr.value.eq_ignore_ascii_case("text/html") || + attr.value.eq_ignore_ascii_case("application/xhtml+xml")) + }) + }, + _ => {}, + } + sink.create_element(name, attrs, flags) +} + +/// Methods a parser can use to create the DOM. The DOM provider implements this trait. +/// +/// Having this as a trait potentially allows multiple implementations of the DOM to be used with +/// the same parser. +pub trait TreeSink { + /// `Handle` is a reference to a DOM node. The tree builder requires + /// that a `Handle` implements `Clone` to get another reference to + /// the same node. + type Handle: Clone; + + /// The overall result of parsing. + /// + /// This should default to Self, but default associated types are not stable yet. + /// [rust-lang/rust#29661](https://github.com/rust-lang/rust/issues/29661) + type Output; + + /// Consume this sink and return the overall result of parsing. + /// + /// TODO:This should default to `fn finish(self) -> Self::Output { self }`, + /// but default associated types are not stable yet. + /// [rust-lang/rust#29661](https://github.com/rust-lang/rust/issues/29661) + fn finish(self) -> Self::Output; + + /// Signal a parse error. + fn parse_error(&mut self, msg: Cow<'static, str>); + + /// Get a handle to the `Document` node. + fn get_document(&mut self) -> Self::Handle; + + /// What is the name of this element? + /// + /// Should never be called on a non-element node; + /// feel free to `panic!`. + fn elem_name<'a>(&'a self, target: &'a Self::Handle) -> ExpandedName<'a>; + + /// Create an element. + /// + /// When creating a template element (`name.ns.expanded() == expanded_name!(html "template")`), + /// an associated document fragment called the "template contents" should + /// also be created. Later calls to self.get_template_contents() with that + /// given element return it. + /// See [the template element in the whatwg spec][whatwg template]. + /// + /// [whatwg template]: https://html.spec.whatwg.org/multipage/#the-template-element + fn create_element( + &mut self, + name: QualName, + attrs: Vec<Attribute>, + flags: ElementFlags, + ) -> Self::Handle; + + /// Create a comment node. + fn create_comment(&mut self, text: StrTendril) -> Self::Handle; + + /// Create a Processing Instruction node. + fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> Self::Handle; + + /// Append a node as the last child of the given node. If this would + /// produce adjacent sibling text nodes, it should concatenate the text + /// instead. + /// + /// The child node will not already have a parent. + fn append(&mut self, parent: &Self::Handle, child: NodeOrText<Self::Handle>); + + /// When the insertion point is decided by the existence of a parent node of the + /// element, we consider both possibilities and send the element which will be used + /// if a parent node exists, along with the element to be used if there isn't one. + fn append_based_on_parent_node( + &mut self, + element: &Self::Handle, + prev_element: &Self::Handle, + child: NodeOrText<Self::Handle>, + ); + + /// Append a `DOCTYPE` element to the `Document` node. + fn append_doctype_to_document( + &mut self, + name: StrTendril, + public_id: StrTendril, + system_id: StrTendril, + ); + + /// Mark a HTML `<script>` as "already started". + fn mark_script_already_started(&mut self, _node: &Self::Handle) {} + + /// Indicate that a node was popped off the stack of open elements. + fn pop(&mut self, _node: &Self::Handle) {} + + /// Get a handle to a template's template contents. The tree builder + /// promises this will never be called with something else than + /// a template element. + fn get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle; + + /// Do two handles refer to the same node? + fn same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool; + + /// Set the document's quirks mode. + fn set_quirks_mode(&mut self, mode: QuirksMode); + + /// Append a node as the sibling immediately before the given node. + /// + /// The tree builder promises that `sibling` is not a text node. However its + /// old previous sibling, which would become the new node's previous sibling, + /// could be a text node. If the new node is also a text node, the two should + /// be merged, as in the behavior of `append`. + /// + /// NB: `new_node` may have an old parent, from which it should be removed. + fn append_before_sibling(&mut self, sibling: &Self::Handle, new_node: NodeOrText<Self::Handle>); + + /// Add each attribute to the given element, if no attribute with that name + /// already exists. The tree builder promises this will never be called + /// with something else than an element. + fn add_attrs_if_missing(&mut self, target: &Self::Handle, attrs: Vec<Attribute>); + + /// Associate the given form-associatable element with the form element + fn associate_with_form( + &mut self, + _target: &Self::Handle, + _form: &Self::Handle, + _nodes: (&Self::Handle, Option<&Self::Handle>), + ) { + } + + /// Detach the given node from its parent. + fn remove_from_parent(&mut self, target: &Self::Handle); + + /// Remove all the children from node and append them to new_parent. + fn reparent_children(&mut self, node: &Self::Handle, new_parent: &Self::Handle); + + /// Returns true if the adjusted current node is an HTML integration point + /// and the token is a start tag. + fn is_mathml_annotation_xml_integration_point(&self, _handle: &Self::Handle) -> bool { + false + } + + /// Called whenever the line number changes. + fn set_current_line(&mut self, _line_number: u64) {} + + /// Indicate that a `script` element is complete. + fn complete_script(&mut self, _node: &Self::Handle) -> NextParserState { + NextParserState::Continue + } +} + +/// Trace hooks for a garbage-collected DOM. +pub trait Tracer { + type Handle; + + /// Upon a call to `trace_handles`, the tree builder will call this method + /// for each handle in its internal state. + fn trace_handle(&self, node: &Self::Handle); +} |