sexp-html

HTML's s-expression representation

s-exp
html
moon add kokic/sexp-html@0.5.0
Download zip
Author
Version
0.5.0
License
Apache-2.0
Last updated
7 days ago
Downloads
88

Dependencies

README

#S-Expression Notation for HTML

#Example

  • keep comments

    (% I want you to know since you came in my life)

    <!-- I want you to know since you came in my life -->

  • syntactic white spaces between terms will be ignored

    (p One hundred million and two thousand years from now (span (:style font-family: "Alegreya Sans SC", sans-serif) 爱してる) )

    <p>One hundred million and two thousand years from now <span style="font-family: \"Alegreya Sans SC\", sans-serif">爱してる</span> </p>

  • only parentheses need to be escaped

    (details (:open) (summary every day every night) \(I've been waiting to share my love with you\) you give light into the darkness skies )

    <details open> <summary>every day every night</summary> (I've been waiting to share my love with you) you give light into the darkness skies </details>

  • (~) emits a literal space, and (~tag ...) emits the normal element with one space on each side

    (p (~span hello)world)

    <p> <span>hello</span> world</p>

  • (# ...) emits an explicit raw text node and preserves the text after # exactly, including leading spaces and newlines

    The first whitespace character after # is only a separator and is not part of the text payload.

    (p (span hello) (# world))

    <p><span>hello</span> world</p>

#Specification

see SPEC.md.

#AST transform API

For custom forms that should become normal HTML-shaped nodes, parse to the public AST, transform it, then render it:

parse_sexp_html("(p (icon search))").map(transform).map(render_html)

The public AST is normalized to HTML-shaped nodes:

pub(all) enum SexpNode {
Text(String)
Comment(String)
RawHtml(String)
Element(String, HtmlAttrs, Array[SexpNode])
}

Syntax forms such as (# ...), (~), and (~tag ...) are expanded during parsing into ordinary Text and Element nodes.

Use RawHtml for trusted HTML that should be inserted directly without escaping:

render_html([
SexpNode::Element("p", HtmlAttrs({}), [
SexpNode::Text("<escaped> "),
SexpNode::RawHtml("<em>trusted</em>"),
]),
])

sexp-html also provides helpers for common HTML rendering operations:

let attrs : HtmlAttrs = HtmlAttrs({})
attrs.upsert("lang", Some("en"))
attrs.append_class("page")

render_open_tag("html", attrs)
render_html_document(attrs, head, body, Some("html"))

#
HtmlAttrs

pub(all) struct HtmlAttrs(Map[String, String?])

#
HtmlAttrs::append_class

fn HtmlAttrs::append_class(self : HtmlAttrs, class_name : String) -> Unit

#
HtmlAttrs::upsert

fn HtmlAttrs::upsert(attrs : HtmlAttrs, name : String, value : String?) -> Unit

#
SexpNode

pub(all) enum SexpNode {
Text(String)
Comment(String)
RawHtml(String)
Element(String, HtmlAttrs, Array[SexpNode])
}

#
escape_html_attr_value

fn escape_html_attr_value(value : String) -> String

#
escape_html_text

fn escape_html_text(text : String) -> String

#
html_to_sexp

fn html_to_sexp(source : String) -> Result[String, String]

#
is_sexp_close_paren

fn is_sexp_close_paren(ch : Char) -> Bool

Returns true for the closing delimiter of an S-expression list.

#
is_sexp_open_paren

fn is_sexp_open_paren(ch : Char) -> Bool

Returns true for the opening delimiter of an S-expression list.

#
is_sexp_paren

fn is_sexp_paren(ch : Char) -> Bool

Returns true for either S-expression list delimiter.

#
is_sexp_text_escape_target

fn is_sexp_text_escape_target(ch : Char) -> Bool

Returns true for characters escaped by S-expression text syntax.

#
is_void_element_name

fn is_void_element_name(tag : String) -> Bool

#
parse_sexp_html

fn parse_sexp_html(source : String) -> Result[Array[SexpNode], String]

Parses a full S-expression HTML fragment into normalized AST nodes.

#
render_html_document

fn render_html_document(html_attrs : HtmlAttrs, head : Array[SexpNode], body : Array[SexpNode], doctype : String?) -> String

#
render_html_fragment

fn render_html_fragment(nodes : Array[SexpNode], separator? : String) -> String

#
render_open_tag

fn render_open_tag(tag : String, attrs : HtmlAttrs) -> String

#
sexp_to_html

fn sexp_to_html(source : String, separator? : String) -> Result[String, String]