use(require(“atomy”))

require(“cgi”)

data(HTMLElement(@name, @attributes = #{}, @body = nil))

fn(word-name(word)):

Atomy Code StringLiteral new(word text to-s gsub("_", "-"))

fn(attr-to-pair(`.~name)): `(.class -> ~word-name(name)) fn(attr-to-pair(`#~name)): `(.id -> ~word-name(name)) fn(attr-to-pair(`(~x = ~y))): `(.~x -> ~y)

macro(<(~name)(~*attrs): ~*body):

`(HTMLElement new(
    .~name
    #{ ~*(attrs collect [a]: attr-to-pair(a)) }
    [~*body]))

macro(<(~name): ~*body):

`(HTMLElement new(.~name, #{}, [~*body]))

macro(<(~name)(~*attrs)):

`(HTMLElement new(
    .~name
    #{ ~*(attrs collect [a]: attr-to-pair(a)) }
    nil))

macro(<~name):

`(HTMLElement new(.~name))

data(UnescapedString(@raw))

def(UnescapedString to-s): @raw

fn(render(out, x & Array)):

x collect [y]: render(out, y)

fn(render(out, x & String)):

out << CGI escapeHTML(x)

fn(render(out, x)):

out << x to-s

stripped? = dynamic(false)

def(HTMLElement to-s):

out = ""

when(^stripped?):
  render(out, @body)
  return(out)

out << i"<#{@name}"

@attributes each [k, v]:
  v match:
    -- boolean attribute, enabled
    true:
      out << i" #{k}"

    -- boolean attribute, disabled
    false: ;

    -- string attribute
    _:
      out << i" #{k}=\"#{v}\""

unless(@body):
  out << " />"
  return(out)

out << ">"

render(out, @body)

out << i"</#{@name}>"

out

data(StrippedTags(@body))

def(StrippedTags to-s):

with(stripped? = true):
  out = ""
  render(out, @body)
  out