Remove ASCII-based escaping

This commit is contained in:
paku 2024-02-10 21:02:45 +09:00
parent a637a2edbc
commit 050c14209c
3 changed files with 19 additions and 55 deletions

View file

@ -9,7 +9,7 @@ It's
- Powerful: help you define reusable and composable components, like that in React - Powerful: help you define reusable and composable components, like that in React
- Modern: focus only on HTML5 - Modern: focus only on HTML5
# Changes from Flute # Differences from Flute
- Added: - Added:
- React-like fragment `(<> ...)`. It lets you group elements without a wrapper element. - React-like fragment `(<> ...)`. It lets you group elements without a wrapper element.
@ -18,7 +18,8 @@ It's
- Element functions are wrapped in macros for natural indentation. - Element functions are wrapped in macros for natural indentation.
- Bugfix. https://github.com/ailisp/flute/issues/5, https://github.com/ailisp/flute/issues/7 - Bugfix. https://github.com/ailisp/flute/issues/5, https://github.com/ailisp/flute/issues/7
- Removed: - Removed:
- CSS style id and class attributes (e.g. `div#id.class`) - Attributes like CSS selectors (e.g. `div#id.class`)
- ASCII-based escaping. Piccolo only supports UTF-8.
# Getting started # Getting started
@ -242,7 +243,7 @@ The `HTML` element is a little special, it's with `<!DOCTYPE html>` prefix to ma
;; ;;
;; Create a attrs aoject, given an alist of (:attr . "attr-value") pair. ;; Create a attrs aoject, given an alist of (:attr . "attr-value") pair.
;; Attribute values (cdr of each element in alist) will be escaped if ;; Attribute values (cdr of each element in alist) will be escaped if
;; *ESCAPE-HTML* is not NIL ;; *ESCAPE-HTML* is t.
;; Function COPY-ATTRS ATTRS ;; Function COPY-ATTRS ATTRS
;; ;;
@ -304,15 +305,11 @@ The `HTML` element is a little special, it's with `<!DOCTYPE html>` prefix to ma
```lisp ```lisp
;; Variable *ESCAPE-HTML* ;; Variable *ESCAPE-HTML*
;; ;;
;; Specify the escape option when generate html, can be :UTF8, :ASCII, :ATTR or NIL. ;; Specify the escape option when generate html with UTF-8, can be t or NIL.
;; If :UTF8, escape only #\<, #\> and #\& in body, and \" in attribute keys. #\' will ;; If t, escape only #\<, #\> and #\& in body, and \" in attribute keys. #\' will
;; in attribute keys will not be escaped since piccolo will always use double quote for ;; in attribute keys will not be escaped since piccolo will always use double quote for
;; attribute keys. ;; attribute keys.
;; If :ASCII, besides what escaped in :UTF8, also escape all non-ascii characters.
;; If :ATTR, only #\" in attribute values will be escaped.
;; If NIL, nothing is escaped and programmer is responsible to escape elements properly. ;; If NIL, nothing is escaped and programmer is responsible to escape elements properly.
;; When given :ASCII and :ATTR, it's possible to insert html text as a children, e.g.
;; (div :id "container" "Some <b>text</b>")
;; All the escapes are done in element creation time. ;; All the escapes are done in element creation time.
;; Function ESCAPE-STRING STRING TEST ;; Function ESCAPE-STRING STRING TEST
@ -320,17 +317,11 @@ The `HTML` element is a little special, it's with `<!DOCTYPE html>` prefix to ma
;; Escape the STRING if it's a STRING and escaping all charaters C that satisfied ;; Escape the STRING if it's a STRING and escaping all charaters C that satisfied
;; (FUNCALL TEST C). Return the new STRING after escape. ;; (FUNCALL TEST C). Return the new STRING after escape.
;; Function UTF8-HTML-ESCAPE-CHAR-P CHAR ;; Function HTML-ESCAPE-CHAR-P CHAR
;; ;;
;; Return T if CHAR is a CHARACTER that need to be escaped when HTML is UTF-8 encoded. ;; Return T if CHAR is a CHARACTER that need to be escaped when HTML is UTF-8 encoded.
;; Return NIL otherwise. ;; Return NIL otherwise.
;; Function ASCII-HTML-ESCAPE-CHAR-P CHAR
;;
;; Return T if CHAR is a CHARACTER that need to be escaped when HTML is ASCII encoded.
;; Return NIL otherwise.
;; Function ATTR-VALUE-ESCAPE-CHAR-P CHAR ;; Function ATTR-VALUE-ESCAPE-CHAR-P CHAR
;; ;;
;; Return T if CHAR is a CHARACTER that need to be escaped when as an attribute value. ;; Return T if CHAR is a CHARACTER that need to be escaped when as an attribute value.

View file

@ -1,32 +1,18 @@
(uiop:define-package #:piccolo/escape (uiop:define-package #:piccolo/escape
(:use #:cl) (:use #:cl)
(:export #:*escape-html* (:export #:*escape-html*
#:utf8-html-escape-char-p #:html-escape-char-p
#:ascii-html-escape-char-p
#:attr-value-escape-char-p #:attr-value-escape-char-p
#:escape-string #:escape-string
#:escape-attrs-alist #:escape-attrs-alist
#:escape-children)) #:escape-children))
(in-package #:piccolo/escape) (in-package #:piccolo/escape)
(defparameter *escape-html* :utf8 (defparameter *escape-html* t)
"Specify the escape option when generate html, can be :UTF8, :ASCII, :ATTR or NIL.
If :UTF8, escape only #\<, #\> and #\& in body, and \" in attribute keys. #\' will
in attribute keys will not be escaped since piccolo will always use double quote for
attribute keys.
If :ASCII, besides what escaped in :UTF8, also escape all non-ascii characters.
If :ATTR, only #\" in attribute values will be escaped.
If NIL, nothing is escaped and programmer is responsible to escape elements properly.
When given :ASCII and :ATTR, it's possible to insert html text as a children, e.g.
(div :id \"container\" \"Some <b>text</b>\")")
(defun utf8-html-escape-char-p (char) (defun html-escape-char-p (char)
(find char "<>&")) (find char "<>&"))
(defun ascii-html-escape-char-p (char)
(or (utf8-html-escape-char-p char)
(> (char-code char) 127)))
(defun attr-value-escape-char-p (char) (defun attr-value-escape-char-p (char)
(eql char #\")) (eql char #\"))
@ -35,16 +21,18 @@ When given :ASCII and :ATTR, it's possible to insert html text as a children, e.
(#\< "&lt;") (#\< "&lt;")
(#\> "&gt;") (#\> "&gt;")
(#\& "&amp;") (#\& "&amp;")
(#\' "&#039;")
(#\" "&quot;") (#\" "&quot;")
(t (format nil "&#~d;" (char-code char))))) (t (error "Escaped character is undefined: ~a" char))))
(defun escape-string (string &optional (test #'utf8-html-escape-char-p)) (defun escape-string (string test)
(if (stringp string) (if (stringp string)
(with-output-to-string (s) (with-output-to-string (s)
(loop (loop
for c across string for c across string
do (write (if (funcall test c) (escape-char c) c) :stream s :escape nil))) do (write (if (funcall test c)
(escape-char c)
c)
:stream s :escape nil)))
string)) string))
(defun escape-attrs-alist (alist) (defun escape-attrs-alist (alist)
@ -56,9 +44,6 @@ When given :ASCII and :ATTR, it's possible to insert html text as a children, e.
(defun escape-children (children) (defun escape-children (children)
(mapcar (lambda (child) (mapcar (lambda (child)
(if (stringp child) (if (stringp child)
(case *escape-html* (escape-string child #'html-escape-char-p)
(:utf8 (escape-string child))
(:ascii (escape-string child #'ascii-html-escape-char-p))
(otherwise child))
child)) child))
children)) children))

View file

@ -178,11 +178,7 @@
(:data . "'<>")) )) (:data . "'<>")) ))
(is (equal escaped-attrs-alist (attrs-alist (element-attrs (new-a))))) (is (equal escaped-attrs-alist (attrs-alist (element-attrs (new-a)))))
(let ((*escape-html* nil)) (let ((*escape-html* nil))
(is (equal *a-attrs* (attrs-alist (element-attrs (new-a)))))) (is (equal *a-attrs* (attrs-alist (element-attrs (new-a))))))))
(let ((*escape-html* :attr))
(is (equal escaped-attrs-alist (attrs-alist (element-attrs (new-a))))))
(let ((*escape-html* :ascii))
(is (equal escaped-attrs-alist (attrs-alist (element-attrs (new-a))))))))
(test escape-children (test escape-children
(let ((a (new-a))) (let ((a (new-a)))
@ -191,15 +187,7 @@
(is (string= "child'<>&quot;.html" (attr (element-attrs (third (element-children a))) :href))) (is (string= "child'<>&quot;.html" (attr (element-attrs (third (element-children a))) :href)))
(is (string= "child'&lt;&gt;\"" (first (element-children (third (element-children a)))))) (is (string= "child'&lt;&gt;\"" (first (element-children (third (element-children a))))))
(is (string= (string (code-char 128)) (second (element-children (third (element-children a)))))) (is (string= (string (code-char 128)) (second (element-children (third (element-children a))))))
(is (string= (string (code-char 128)) (fourth (element-children a))))) (is (string= (string (code-char 128)) (fourth (element-children a))))))
(let* ((*escape-html* :ascii)
(a (new-a)))
(is (string= "child text 1" (first (element-children a))))
(is (string= "child text 2 &lt;br&gt; &amp;" (second (element-children a))))
(is (string= "child'<>&quot;.html" (attr (element-attrs (third (element-children a))) :href)))
(is (string= "child'&lt;&gt;\"" (first (element-children (third (element-children a))))))
(is (string= "&#128;" (second (element-children (third (element-children a))))))
(is (string= "&#128;" (fourth (element-children a))))))
(in-suite attr-access) (in-suite attr-access)