Separate defhsx package from hsx package

This commit is contained in:
paku 2024-05-28 12:33:01 +09:00
parent 8e5f597be6
commit ead5c408e3
10 changed files with 156 additions and 150 deletions

View file

@ -3,6 +3,6 @@
:pathname "tests" :pathname "tests"
:depends-on ("fiveam" :depends-on ("fiveam"
"hsx-test/element" "hsx-test/element"
"hsx-test/hsx" "hsx-test/defhsx"
"hsx-test/hsx-macro") "hsx-test/hsx")
:perform (test-op (op c) (symbol-call :fiveam :run-all-tests))) :perform (test-op (op c) (symbol-call :fiveam :run-all-tests)))

View file

@ -2,12 +2,13 @@
(:use #:cl) (:use #:cl)
(:import-from #:alexandria (:import-from #:alexandria
#:make-keyword) #:make-keyword)
(:import-from #:hsx/hsx (:import-from #:hsx/defhsx
#:defhsx)) #:defhsx))
(in-package #:hsx/builtin) (in-package #:hsx/builtin)
(defmacro define-and-export-builtin-elements (&rest names) (defmacro define-and-export-builtin-elements (&rest names)
`(progn `(eval-when (:compile-toplevel :load-toplevel :execute)
,@(mapcan (lambda (name) ,@(mapcan (lambda (name)
(list `(defhsx ,name ,(string-downcase name)) (list `(defhsx ,name ,(string-downcase name))
`(export ',name))) `(export ',name)))

35
src/defhsx.lisp Normal file
View file

@ -0,0 +1,35 @@
(uiop:define-package #:hsx/defhsx
(:use #:cl)
(:import-from #:alexandria
#:symbolicate)
(:import-from #:hsx/element
#:create-element)
(:export #:defhsx
#:defcomp))
(in-package #:hsx/defhsx)
(defmacro defhsx (name element-type)
`(eval-when (:compile-toplevel :load-toplevel :execute)
(defmacro ,name (&body body)
(multiple-value-bind (props children)
(parse-body body)
`(create-element ,',element-type (list ,@props) ,@children)))))
(defun parse-body (body)
(if (keywordp (first body))
(loop :for thing :on body :by #'cddr
:for (k v) := thing
:when (and (keywordp k) v)
:append (list k v) :into props
:when (not (keywordp k))
:return (values props thing)
:finally (return (values props nil)))
(values nil body)))
(defmacro defcomp (name props &body body)
(let ((%name (symbolicate '% name)))
`(eval-when (:compile-toplevel :load-toplevel :execute)
(defun ,%name ,props
,@body)
(defhsx ,name (fdefinition ',%name)))))

View file

@ -7,6 +7,7 @@
#:expand-component)) #:expand-component))
(in-package #:hsx/element) (in-package #:hsx/element)
;;;; class definitions ;;;; class definitions
(defclass element () (defclass element ()

View file

@ -1,45 +1,9 @@
(uiop:define-package #:hsx/hsx (uiop:define-package #:hsx/hsx
(:use #:cl) (:use #:cl)
(:import-from #:alexandria (:export #:hsx))
#:symbolicate)
(:import-from #:hsx/element
#:create-element)
(:export #:defhsx
#:defcomp
#:hsx))
(in-package #:hsx/hsx) (in-package #:hsx/hsx)
;;;; hsx definitions
(defmacro defhsx (name element-type)
(eval-when (:compile-toplevel :load-toplevel :execute)
`(defmacro ,name (&body body)
(multiple-value-bind (props children)
(parse-body body)
`(create-element ,',element-type (list ,@props) ,@children)))))
(defun parse-body (body)
(if (keywordp (first body))
(loop :for thing :on body :by #'cddr
:for (k v) := thing
:when (and (keywordp k) v)
:append (list k v) :into props
:when (not (keywordp k))
:return (values props thing)
:finally (return (values props nil)))
(values nil body)))
(defmacro defcomp (name props &body body)
(let ((%name (symbolicate '% name)))
`(eval-when (:compile-toplevel :load-toplevel :execute)
(defun ,%name ,props
,@body)
(defhsx ,name (fdefinition ',%name)))))
;;;; hsx macro to find hsx symbols
(defmacro hsx (&body form) (defmacro hsx (&body form)
(when (not (= (length form) 1)) (when (not (= (length form) 1))
(error "The body of the hsx macro must be a single form.")) (error "The body of the hsx macro must be a single form."))

View file

@ -1,6 +1,7 @@
(uiop:define-package :hsx (uiop:define-package :hsx
(:nicknames #:hsx/main) (:nicknames #:hsx/main)
(:use #:cl) (:use #:cl)
(:use-reexport #:hsx/hsx) (:use-reexport #:hsx/defhsx)
(:import-from #:hsx/builtin)) (:import-from #:hsx/builtin)
(:use-reexport #:hsx/hsx))
(in-package :hsx) (in-package :hsx)

88
tests/defhsx.lisp Normal file
View file

@ -0,0 +1,88 @@
(defpackage #:hsx-test/defhsx
(:use #:cl
#:fiveam
#:hsx/defhsx
#:hsx/builtin)
(:import-from #:hsx/element
#:create-element))
(in-package #:hsx-test/defhsx)
(def-suite defhsx-test)
(in-suite defhsx-test)
(test empty-hsx
(is (equal (macroexpand-1
'(div))
'(create-element
"div"
(list)))))
(test hsx-with-props
(is (equal (macroexpand-1
'(div :prop1 "value1" :prop2 "value2"))
'(create-element
"div"
(list :prop1 "value1" :prop2 "value2")))))
(test hsx-with-children
(is (equal (macroexpand-1
'(div
"child1"
"child2"))
'(create-element
"div"
(list)
"child1"
"child2"))))
(test hsx-with-props-and-children
(is (equal (macroexpand-1
'(div :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
"div"
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2"))))
(defhsx custom "custom")
(test hsx-for-custom-tag-element
(is (equal (macroexpand-1
'(custom :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
"custom"
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2"))))
(defhsx comp1 #'%comp1)
(defun %comp1 (&key prop1 prop2 children)
(declare (ignore prop1 prop2 children)))
(defcomp comp2 (&key prop1 prop2 children)
(declare (ignore prop1 prop2 children)))
(test hsx-for-component-element
(is (equal (macroexpand-1
'(comp1 :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
#'%comp1
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2")))
(is (equal (macroexpand-1
'(comp2 :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
(fdefinition '%comp2)
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2"))))

View file

@ -4,6 +4,7 @@
#:hsx/element)) #:hsx/element))
(in-package #:hsx-test/element) (in-package #:hsx-test/element)
(def-suite element-test) (def-suite element-test)
(in-suite element-test) (in-suite element-test)

View file

@ -1,31 +0,0 @@
(defpackage #:hsx-test/hsx-macro
(:use #:cl
#:fiveam)
(:import-from #:hsx/element
#:element-type
#:element-children)
(:import-from #:hsx/hsx
#:hsx
#:defcomp))
(in-package #:hsx-test/hsx-macro)
(def-suite hsx-macro-test)
(in-suite hsx-macro-test)
(defcomp div (&rest props)
(declare (ignore props))
"This is fake!")
(defcomp p (&rest props)
(declare (ignore props))
"This is fake!")
(test find-symbols
(let ((fake-elm (div :prop "value"
(p "brah"))))
(is (eql (element-type fake-elm) #'%div)
(eql (element-type (first (element-children fake-elm))) #'%p)))
(let ((true-elm (hsx (div :prop "value"
(p "brah")))))
(is (equal (element-type true-elm) "div")
(equal (element-type (first (element-children true-elm))) "p"))))

View file

@ -1,87 +1,33 @@
(defpackage #:hsx-test/hsx (defpackage #:hsx-test/hsx
(:use #:cl (:use #:cl
#:fiveam #:fiveam
#:hsx/hsx #:hsx/hsx)
#:hsx/builtin)
(:import-from #:hsx/element (:import-from #:hsx/element
#:create-element)) #:element-type
#:element-children)
(:import-from #:hsx/defhsx
#:defcomp)
(:import-from #:hsx/builtin))
(in-package #:hsx-test/hsx) (in-package #:hsx-test/hsx)
(def-suite hsx-test) (def-suite hsx-test)
(in-suite hsx-test) (in-suite hsx-test)
(test empty-hsx (defcomp div (&rest props)
(is (equal (macroexpand-1 (declare (ignore props))
'(div)) "This is fake!")
'(create-element
"div"
(list)))))
(test hsx-with-props (defcomp p (&rest props)
(is (equal (macroexpand-1 (declare (ignore props))
'(div :prop1 "value1" :prop2 "value2")) "This is fake!")
'(create-element
"div"
(list :prop1 "value1" :prop2 "value2")))))
(test hsx-with-children (test find-symbols
(is (equal (macroexpand-1 (let ((fake-elm (div :prop "value"
'(div (p "brah"))))
"child1" (is (eql (element-type fake-elm) #'%div)
"child2")) (eql (element-type (first (element-children fake-elm))) #'%p)))
'(create-element (let ((true-elm (hsx (div :prop "value"
"div" (p "brah")))))
(list) (is (equal (element-type true-elm) "div")
"child1" (equal (element-type (first (element-children true-elm))) "p"))))
"child2"))))
(test hsx-with-props-and-children
(is (equal (macroexpand-1
'(div :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
"div"
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2"))))
(defhsx custom "custom")
(test hsx-for-custom-tag-element
(is (equal (macroexpand-1
'(custom :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
"custom"
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2"))))
(defhsx comp1 #'%comp1)
(defun %comp1 (&key prop1 prop2 children)
(declare (ignore prop1 prop2 children)))
(defcomp comp2 (&key prop1 prop2 children)
(declare (ignore prop1 prop2 children)))
(test hsx-for-component-element
(is (equal (macroexpand-1
'(comp1 :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
#'%comp1
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2")))
(is (equal (macroexpand-1
'(comp2 :prop1 "value1" :prop2 "value2"
"child1"
"child2"))
'(create-element
(fdefinition '%comp2)
(list :prop1 "value1" :prop2 "value2")
"child1"
"child2"))))