diff options
author | Lars Wirzenius <liw@liw.fi> | 2023-04-09 10:55:01 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2023-04-09 10:55:01 +0300 |
commit | c55a41936938dce5adc22dece6b7ea02e14980ae (patch) | |
tree | f0651f38922880f917e455f80d682e380d1393c1 | |
parent | e8ca964f345d716cd776f3d54676d226b6e17b89 (diff) | |
download | html-page-c55a41936938dce5adc22dece6b7ea02e14980ae.tar.gz |
docs: add doc comments for all public symbols
Sponsored-by: author
-rw-r--r-- | src/lib.rs | 75 |
1 files changed, 60 insertions, 15 deletions
@@ -1,6 +1,13 @@ -//! Construct and manipulate an HTML page represented using Rust types. +//! Construct and manipulate an HTML element represented using Rust types. +//! +//! Conceptually, an element has a tag, optional attributes, and +//! optional children. A child can consist of non-HTML text, or be an +//! element of its own. +//! +//! This crate aims to follow the WhatWG specification at +//! <https://html.spec.whatwg.org/>. -//! Represent an HTML element. +#![deny(missing_docs)] use html_escape::{encode_double_quoted_attribute, encode_safe}; use std::collections::HashMap; @@ -9,8 +16,10 @@ use std::fmt::{Display, Formatter}; /// The tag of an HTML5 element. /// /// Note that we only support HTML5 elements, as listed on -/// <https://html.spec.whatwg.org/multipage/#toc-semantics/>. +/// <https://html.spec.whatwg.org//>. #[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[allow(missing_docs)] // the variants are just element names, no need + // to document each separately pub enum Tag { A, Abbr, @@ -171,12 +180,28 @@ impl Display for Attributes { } } +/// The value of an element attribute. +/// +/// Attributes may be "boolean" (just the name of an attribute), or a +/// key/value pair, where the value is a string. Technically, in HTML, +/// a boolean attribute with a true value can be expressed as a +/// key/value pair with a value that is an empty string or the name of +/// the attribute, but in this representation we make it more +/// explicit. #[derive(Clone, Debug, Eq, PartialEq)] pub enum AttributeValue { + /// The value of a key/value attribute. String(String), + /// A boolean attribute. It the attribute is present, the value is + /// true. Boolean, } +/// An HTML element. +/// +/// The element has a [`Tag`], possibly some attributes, and possibly +/// some children. It may also have a location: this is used when the +/// element is constructed by parsing some input value. #[derive(Clone, Debug, Eq, PartialEq)] pub struct Element { loc: Option<(usize, usize)>, @@ -186,6 +211,7 @@ pub struct Element { } impl Element { + /// Create a new element, with a given tag. pub fn new(tag: Tag) -> Self { Self { tag, @@ -195,47 +221,61 @@ impl Element { } } + /// Set the location of an element in a source file. pub fn with_location(mut self, line: usize, col: usize) -> Self { self.loc = Some((line, col)); self } + /// Return the [`Tag`] of the element. pub fn tag(&self) -> Tag { self.tag } + /// Return the location of the element. pub fn location(&self) -> Option<(usize, usize)> { self.loc } + /// Return an iterator over the names of the attributes of an element. pub fn attributes(&self) -> impl Iterator<Item = &str> { self.attrs.names() } + /// Return the value of an attribute, if the attribute is set. + /// Otherwise, return `None`. pub fn attribute(&self, name: &str) -> Option<&AttributeValue> { self.attrs.get(name) } + /// Set a key/value attribute. If the attribute was already set, + /// change the value it has. pub fn set_attribute(&mut self, name: &str, value: &str) { self.attrs.set(name, value); } + /// Set a boolean attribute. pub fn set_boolean_attribute(&mut self, name: &str) { self.attrs.set_boolean(name); } + /// Remove an attribute, which can be key/value or boolean. pub fn unset_attribute(&mut self, name: &str) { self.attrs.unset(name); } - pub fn children(&self) -> &[Content] { - &self.children + /// Append text to element. It will be escaped, if needed, when + /// the element is serialized. + pub fn push_text(&mut self, text: &str) { + self.children.push(Content::text(text)); } - pub fn push_child(&mut self, child: Content) { - self.children.push(child); + /// Append a child element to this element. + pub fn push_child(&mut self, child: &Element) { + self.children.push(Content::element(child)); } + /// Serialize an element into HTML. pub fn serialize(&self) -> String { format!("{}", self) } @@ -256,17 +296,22 @@ impl Display for Element { } } +/// Represent content in HTML. #[derive(Clone, Debug, Eq, PartialEq)] -pub enum Content { +enum Content { + /// Non-HTML text. Text(String), + /// An HTML element. Element(Element), } impl Content { + /// Create a new [`Content::Text`]. pub fn text(s: &str) -> Self { Self::Text(s.into()) } + /// Create a new [`Content::Element`]. pub fn element(e: &Element) -> Self { Self::Element(e.clone()) } @@ -338,15 +383,15 @@ mod test { #[test] fn element_has_no_children_initially() { let e = Element::new(Tag::P); - assert!(e.children().is_empty()); + assert!(e.children.is_empty()); } #[test] fn add_child_to_element() { let mut e = Element::new(Tag::P); let child = Content::text("foo"); - e.push_child(child.clone()); - assert_eq!(e.children(), &[child]); + e.push_text("foo"); + assert_eq!(e.children, &[child]); } #[test] @@ -385,17 +430,17 @@ mod test { #[test] fn element_can_be_serialized() { let mut e = Element::new(Tag::P); - e.push_child(Content::text("hello ")); + e.push_text("hello "); let mut world = Element::new(Tag::B); - world.push_child(Content::text("world")); - e.push_child(Content::Element(world)); + world.push_text("world"); + e.push_child(&world); assert_eq!(e.serialize(), "<P>hello <B>world</B></P>"); } #[test] fn dangerous_text_is_escaped() { let mut e = Element::new(Tag::P); - e.push_child(Content::text("hello <world>")); + e.push_text("hello <world>"); assert_eq!(e.serialize(), "<P>hello <world></P>"); } } |