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 -->

  • runs of whitespace inside a text term collapse to a single space

    (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: &quot;Alegreya Sans SC&quot;, 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 verbatim text node: everything after # is literal, including leading spaces and newlines. No whitespace is consumed as a separator.

    (p (span hello) (# world))

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

  • whitespace you type around an element is content, so adjacency requires no space

    (p a (b c)) (p a(b c))

    <p>a <b>c</b></p> <p>a<b>c</b></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("(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)
Raw(String)
Element(String, Attrs, Array[SexpNode])
}

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

Use Raw for trusted content that should be inserted directly without escaping:

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

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

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

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

#
Attrs

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

#
Attrs::append_class

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

#
Attrs::upsert

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

#
SexpNode

pub(all) enum SexpNode {
Text(String)
Comment(String)
Raw(String)
Element(String, Attrs, 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

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

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

#
render_html_document

fn render_html_document(attrs : Attrs, 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 : Attrs) -> String

#
sexp_to_html

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