2024-10-03 00:54:43 +00:00
|
|
|
(defpackage #:hsx/utils
|
2024-05-31 09:39:25 +00:00
|
|
|
(:use #:cl)
|
|
|
|
(:import-from #:alexandria
|
|
|
|
#:alist-hash-table)
|
|
|
|
(:export #:escape-html-attribute
|
2024-10-03 00:54:43 +00:00
|
|
|
#:escape-html-text-content
|
|
|
|
#:minify))
|
|
|
|
(in-package #:hsx/utils)
|
2024-05-31 09:39:25 +00:00
|
|
|
|
|
|
|
(defparameter *text-content-escape-map*
|
|
|
|
(alist-hash-table
|
|
|
|
'((#\& . "&")
|
|
|
|
(#\< . "<")
|
|
|
|
(#\> . ">")
|
|
|
|
(#\" . """)
|
|
|
|
(#\' . "'")
|
|
|
|
(#\/ . "/")
|
|
|
|
(#\` . "`")
|
|
|
|
(#\= . "="))))
|
|
|
|
|
|
|
|
(defparameter *attribute-escape-map*
|
|
|
|
(alist-hash-table
|
|
|
|
'((#\" . """))))
|
|
|
|
|
|
|
|
(defun escape-char (char escape-map)
|
2024-10-03 00:54:43 +00:00
|
|
|
(or (gethash char escape-map)
|
2024-05-31 09:39:25 +00:00
|
|
|
char))
|
|
|
|
|
|
|
|
(defun escape-string (string escape-map)
|
|
|
|
(if (stringp string)
|
|
|
|
(with-output-to-string (s)
|
|
|
|
(loop
|
|
|
|
:for c :across string
|
|
|
|
:do (write (escape-char c escape-map) :stream s :escape nil)))
|
|
|
|
string))
|
|
|
|
|
|
|
|
(defun escape-html-text-content (text)
|
|
|
|
(escape-string text *text-content-escape-map*))
|
|
|
|
|
|
|
|
(defun escape-html-attribute (text)
|
|
|
|
(escape-string text *attribute-escape-map*))
|
2024-10-03 00:54:43 +00:00
|
|
|
|
|
|
|
(defun minify (input-string)
|
|
|
|
(with-output-to-string (out)
|
|
|
|
(let ((previous-space-p nil))
|
|
|
|
(loop for char across input-string do
|
|
|
|
(cond
|
|
|
|
((whitespace-p char)
|
|
|
|
(unless previous-space-p
|
|
|
|
(write-char #\Space out))
|
|
|
|
(setf previous-space-p t))
|
|
|
|
(t
|
|
|
|
(write-char char out)
|
|
|
|
(setf previous-space-p nil)))))))
|
|
|
|
|
|
|
|
(defun whitespace-p (char)
|
|
|
|
(member char '(#\Space #\Newline #\Tab #\Return) :test #'char=))
|