Skip to content

Commit

Permalink
Merge pull request #4 from RickBarretto/html-v2
Browse files Browse the repository at this point in the history
Html v2 - Proposal
  • Loading branch information
drkameleon authored May 10, 2024
2 parents aa5c8a5 + 4f1df85 commit 06c17fc
Show file tree
Hide file tree
Showing 7 changed files with 352 additions and 59 deletions.
15 changes: 15 additions & 0 deletions exp.art
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import.verbose {src/html}!


print html [
head [
title "Hello"
meta #[name: "twitter:card"]
]

body [
h1 "Title"
input #[name: "user" type: "username"]
]

]
1 change: 1 addition & 0 deletions info.art
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
entry: {src/html}
requires: [> 0.9.83]
59 changes: 0 additions & 59 deletions main.art

This file was deleted.

145 changes: 145 additions & 0 deletions src/html.art
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
define :html [

init: method [][
elements: [
; Main
body head

; Web Components
slot template

; Editing
del ins

; Embedded Content
embed iframe object picture portal source svg math

; Forms
button datails fieldset form input label legend meter optgroup
option output progress select textarea

; Inline Text
a abbr b bdi bdo br cite code data dfn em i kbd mark q s rp rt
ruby samp small span strong sub sup time u var wbr

; Interactives
details dialog summary

; Metadata Content
base link meta title style

; Multimedia
area audio img map track video

; Scripting
canvas noscript script

; Content Sectioning
address article aside footer header h1 h2 h3 h4 h5 h6 hgroup main
nav section search

; Tables
caption col colgroup table tbody td tfoot th thead tr

; Text Content
blockquote dd div dl dt figcaption figure hr li menu ol p pre ul
]

loop elements 'el [
body: [\element x]
insert 'body 1 to :literal el
this\[el]: method [x] body
]
]

_process: method [content][
@content
]

kebab: method [content :string][
replace content "_" "-"
]

voidElement: method [tag :string :literal :word htmlAttributes :dictionary][
;; Void \elements are \elements without closing-tags.
;;
;; Format
;; ------
;; They follows the pattern: ``<tag key="value" .../>``
;;
;; Features
;; --------
;; Use Arturo's attributes to dynamically add html's attributes to it.
;;
;; Extra
;; -----
;; Read more about void \elements here:
;; <https://html.spec.whatwg.org/multipage/syntax.html#void-\elements/>

attributes: (
map htmlAttributes [key value] -> render {|\kebab key|="|value|"}
| append (map attrs [key value] -> render {|\kebab key|="|value|"})
| join.with: " "
)

if attributes <> "" -> prepend 'attributes " "
~"<|tag||attributes|/>"
]

element: method.public [tag :string :literal content :block :string :dictionary][
;; \elements refers to the normal \elements defined by the HTML5 standard.
;;
;; Format
;; ------
;; * They follows the pattern: ``<tag key="value" .../>content<tag />``.
;; * When ``content`` is a :block, the content will be intended by 2 spaces.
;;
;; Features
;; --------
;; Use Arturo's attributes to dynamically add html's attributes to it.
;;
;; Extra
;; -----
;; Read more about \elements here:
;; <https://html.spec.whatwg.org/multipage/syntax.html#\elements-2/>

if dictionary? content ->
return \voidElement tag content

attributes: (join.with: " " map attrs [key value] -> render {|\kebab key|="|value|"})
if attributes <> "" -> prepend 'attributes " "

if block? content ->
join.with: "\n" @[
~"<|tag||attributes|>"
indent.n: 2 join.with: "\n" @content
~"</|tag|>"
]

if string? content ->
~"<|tag||attributes|>|content|</|tag|>"
]

html: method [page :block][
html4: attr 'html4

doctype: (html4)?
-> {!html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
}
-> {!html
<!DOCTYPE html>
}

join.with: "\n" @[
doctype
\element 'html page
]
]

]

html: to :html []
fragment: $[content][
join.with: "\n" @ html\_process content
]!
9 changes: 9 additions & 0 deletions test.art
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#! arturo

import.version: 1.1.2 'unitt!

testPath: "test"

runTests (empty? arg)?
-> findTests.thatMatches: "*.test.art" testPath
-> map arg 'file [ ~"|testPath|/|file|.test.art" ]
147 changes: 147 additions & 0 deletions test/element.test.art
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import {unitt}!
import {src/html}!

test "generic elements follows the standard for :string" [
result: html\element "el" "Hello, World!"
assert -> "<el>Hello, World!</el>" = result
]


test "generic elements follows the standard for nested :block s" [
;; This test tests multiple things:
;; * Opening and closing tags:
;; Each element should be opened and closed
;; * Indentation
;; Two spaces must be added per element nesting
;; * Evaluation
;; the user shouldn't use '@ to evaluate, the element must do it

breakLine: "<br>"
bold: $[x][html\element "b" x]
paragraph: $[x][html\element "p" x]

expect: {!html
<p>
Hello,
<br>
<b>World</b>
!
</p>
}

result: paragraph [
"Hello,"
breakLine
bold "World" "!"
]

assert -> expect = result
]

test "indentation follows the nesting of elements" [
;; Also verifies the nesting for strings
;;
;; How the formatation must work:
;;
;; tag "Content"
;; ; <tag>Content</tag>
;;
;; tag ["Content"]
;; ; <tag>
;; ; Content
;; ; </tag>

divisory: $[x][html\element "div" x]

expect: {!html
<div>
Level 01
<div>
Level 02
<div>Level 03</div>
Level 02
</div>
Level 01
</div>
}

result: divisory [
"Level 01"
divisory [
"Level 02"
divisory "Level 03"
"Level 02"
]
"Level 01"
]

assert -> expect = result
]

test "dynamic attributes follows standard" [
;; We can dynamically add Elements's attributes by using Arturo's attributes
;;
;; How this must work:
;;
;; tag.class: "content" "Content"
;; ; <tag class="content">Content</tag>
;;
;; tag.author: "RickB" ["Content"]
;; ; <tag author="RickB">
;; ; Content
;; ; </tag>

divisory: $[x][html\element "div" x]
entry: $[x][html\element .name: x "input" ""]
button: $[x][html\element "button" x]

expect: {!html
<div class="login-box">
<input type="email" name="user"></input>
<input type="password" name="pwd"></input>
<button class="enter">Log In</button>
<button class="recover">Forgot my password</button>
</div>
}

result: divisory.class: "login-box" [
entry.type: 'email "user"
entry.type: 'password "pwd"
button.class: 'enter "Log In"
button.class: 'recover "Forgot my password"
]

assert -> expect = result
]


test "snake-case should be converted to kebab" [
divisory: $[x][html\element 'div x]
expect: {!html
<div aria-valuenow="50"></div>
}

result: divisory.aria_valuenow: 50 ""
assert -> expect = result

]


test "auto void elements when pass a :dictionary as parameter" [
input: $[x][html\element 'input x]
expect: {!html
<input type="email"></input>
}

result: input.type: "email" ""
assert -> expect = result


expect: {!html
<input type="email"/>
}

result: input #[type: "email"]
assert -> expect = result

]
Loading

0 comments on commit 06c17fc

Please sign in to comment.