aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorcolin <colin@cicadas.surf>2023-11-18 15:25:51 -0800
committercolin <colin@cicadas.surf>2023-11-18 15:25:51 -0800
commitc201a822f264041a1b9169824c0f9acbfae9cf6e (patch)
tree47ebbdfeaf4bc184a676537ec03637b3ec023c5d /src/client
parent1d3d018f01ffb71dcdeaa086b3025a00428b45c1 (diff)
version 1.0
Diffstat (limited to 'src/client')
-rw-r--r--src/client/dexador.lisp205
-rw-r--r--src/client/parenscript.lisp3
2 files changed, 208 insertions, 0 deletions
diff --git a/src/client/dexador.lisp b/src/client/dexador.lisp
new file mode 100644
index 0000000..2503b5e
--- /dev/null
+++ b/src/client/dexador.lisp
@@ -0,0 +1,205 @@
+;;;; lazybones-client.lisp -- macro to generate a set of http request functions given an APP instance
+
+;; Copyright (C) 2022 Colin Okay
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+(defpackage #:lazybones/client.dexador
+ (:use #:cl)
+ (:local-nicknames (#:a #:alexandria-2))
+ (:export #:generate))
+
+(in-package :lazybones/client.dexador)
+
+
+
+(defun endpoint-defun-name (ep)
+ "Returns the string name of a defun for making requests to
+endpoint EP."
+ (with-output-to-string (*standard-output*)
+ (princ (string-downcase (symbol-name (lazybones::endpoint-method ep))))
+ (princ "-")
+ (loop for (term . more) on (lazybones::endpoint-dispatch-pattern ep)
+ when (and (stringp term) (plusp (length term)))
+ do (princ (string-downcase term))
+ when (listp term)
+ do (princ (string-downcase (car term)))
+ when (and more (plusp (length term)))
+ do (princ "/"))))
+
+(defun endpoint-defun-route-var-names (ep)
+ "Returns a list of strings representing the names of route variables
+extracted from endpoint EP, to be used as variable names in the defun
+for making requests to that endpoint."
+ (lazybones::endpoint-route-vars ep))
+
+(defun endpoint-defun-query-var-names (ep)
+ "Returns a list of strings representing the names of query parameter
+variables extraced from the endpoint EP, to be used as variable names
+in the defun for making request to that endpoint."
+ (mapcar (a:compose #'symbol-name #'first)
+ (lazybones::endpoint-params ep)))
+
+
+(defun endpoint-accepts-body-p (ep)
+ (member (lazybones::endpoint-method ep) '(:post :put :patch)) )
+
+(defun endpoint-defun-lambda-list (ep)
+ "Returns a string representation of the lambda list of the defun
+for making requests to endpoint EP."
+ (format
+ nil
+ "(~{~a ~} %host &key ~:[~;%content-type %body ~] %headers %cookies)"
+ (append
+ (endpoint-defun-route-var-names ep)
+ (endpoint-defun-query-var-names ep))
+ (endpoint-accepts-body-p ep)))
+
+
+(defun endpoint-defun-dexador-uri-route-format-string (ep)
+ "Returns a string representing a format string, intended to be
+ embedded into the body of a defun for making requests to the
+ endpoint Ep. It is designed to be passed to FORMAT, where route
+ variables are substituted into the string."
+ (str:join "/"
+ (mapcar (lambda (x) (if (listp x) "~a" x))
+ (lazybones::endpoint-dispatch-pattern ep))))
+
+(defun endpoint-defun-dexador-uri-route-query-format-string (ep)
+ "Returns a string representing a format string, intended to be
+ embedded into the body of a defun for making requests to the
+ endpoint EP. It is desienged to be passed to FORMAT, where query
+ paramters are substituted into the string, if they exist."
+ (with-output-to-string (*standard-output*)
+ (loop
+ for first = t then nil
+ for varname in (endpoint-defun-query-var-names ep)
+ do
+ (princ "~@[")
+ (unless first (princ #\&))
+ (princ (string-upcase varname))
+ (princ "=~a~]"))))
+
+(defun endpoint-defun-dexador-request-uri (app ep)
+ "Returns a string representation of code that generates a URI for
+ passing to the dexador request function within the body of the defun
+ for making requests to the endpoint EP of the application APP."
+ (concatenate
+ 'string
+ "(format nil "
+ "\""
+ "~a"
+ (lazybones::app-prefix app)
+ (endpoint-defun-dexador-uri-route-format-string ep)
+ "?"
+ (endpoint-defun-dexador-uri-route-query-format-string ep)
+ "\" "
+ "%host "
+ (str:join " " (endpoint-defun-route-var-names ep))
+ " "
+ (str:join " " (endpoint-defun-query-var-names ep))
+ ")"))
+
+(defun endpoint-defun-body (app ep)
+ "Returns a string representation of the function body of a defun
+ for making requests to the endpoint EP in the app APP."
+ (format
+ nil
+ " (dexador:~a~% ~a~%~{ ~a~^~%~})"
+ (string-downcase (symbol-name (lazybones::endpoint-method ep)))
+ (endpoint-defun-dexador-request-uri app ep)
+ (append
+ (if (endpoint-accepts-body-p ep)
+ (list ":content %body"
+ ":cookie-jar %cookies"
+ ":headers (if %content-type (cons (cons \"Content-Type\" %content-type) %headers) %headers)")
+ (list ":cookie-jar %cookies"
+ ":headers %headers")))))
+
+(defun generate-defun-for-endpoint (app ep)
+ "Returns a string representation of a defun form for a function that
+makes a request to the endpoint EP."
+ (format nil
+ "(defun ~a~% ~a~% ~s~%~a)"
+ (endpoint-defun-name ep)
+ (endpoint-defun-lambda-list ep)
+ (lazybones::endpoint-documentation ep)
+ (endpoint-defun-body app ep)))
+
+
+(defun all-function-names (app)
+ (mapcar 'endpoint-defun-name (lazybones::app-endpoints app)))
+
+(defun app-client-package-name (app)
+ (format nil "~a-CLIENT" (lazybones::app-name app)))
+
+
+(defun generate-defsystem-for-client-of-app (app)
+ (with-output-to-string (*standard-output*)
+ (princ "(asdf:defsystem #:") (princ (app-client-package-name app))
+ (terpri)
+ (princ " :depends-on (#:dexador)")
+ (terpri)
+ (princ " :components ((:file ")
+ (princ #\")
+ (princ (string-downcase (app-client-package-name app)))
+ (princ #\")
+ (princ ")))")))
+
+
+(defun generate-defpackage-for-client-of-app (app)
+ (with-output-to-string (out)
+ (format
+ out
+ "
+;;;; DO NOT EDIT! THIS FILE HAS BEEN GENERATED BY LAZYBONES-CLIENT
+
+(defpackage #:~a
+ (:use :cl)
+ (:export ~%~{ #:~a~^~%~}))"
+ (app-client-package-name app)
+ (all-function-names app))
+ (terpri out)
+ (format out "(in-package :~a)" (app-client-package-name app))
+ (terpri out)))
+
+(defun client-asd-file-name (app)
+ (format nil "~a.asd" (string-downcase (app-client-package-name app))))
+
+(defun client-lisp-file-name (app)
+ (format nil "~a.lisp" (string-downcase (app-client-package-name app))))
+
+(defun generate-client-functions-for-app (app)
+ (loop for ep in (lazybones::app-endpoints app)
+ collect (generate-defun-for-endpoint app ep)))
+
+(defun generate (directory app)
+ "Generate "
+ (assert (uiop:directory-exists-p directory))
+
+ (alexandria:write-string-into-file
+ (generate-defsystem-for-client-of-app app)
+ (merge-pathnames (client-asd-file-name app) directory))
+
+ (alexandria:write-string-into-file
+ (with-output-to-string (*standard-output*)
+ (princ (generate-defpackage-for-client-of-app app))
+ (princ #\newline) (princ #\newline)
+ (princ #\newline) (princ #\newline)
+ (dolist (defun-string (generate-client-functions-for-app app))
+ (princ defun-string)
+ (princ #\newline) (princ #\newline)))
+ (merge-pathnames (client-lisp-file-name app) directory))
+ :ok)
diff --git a/src/client/parenscript.lisp b/src/client/parenscript.lisp
new file mode 100644
index 0000000..75afbd7
--- /dev/null
+++ b/src/client/parenscript.lisp
@@ -0,0 +1,3 @@
+(defpackage #:lazybones/client.parenscript
+ (:use #:cl)
+ (:export #:generate))