experiment: Add ParenScript setup and utilities

- Add parenscript dependency to asteroid.asd
- Create parenscript-utils.lisp with helper functions and macros
- Add PARENSCRIPT-EXPERIMENT.org documenting the conversion plan
- Goal: Replace all JavaScript with ParenScript for full-stack Lisp
This commit is contained in:
glenneth 2025-11-06 10:11:04 +03:00
parent 5e92dab33b
commit 303a834ef9
3 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,74 @@
#+TITLE: ParenScript Conversion Experiment
#+AUTHOR: Glenn
#+DATE: 2025-11-06
* Overview
This branch experiments with converting all JavaScript files to ParenScript, allowing us to write client-side code in Common Lisp that compiles to JavaScript.
* Goals
- Replace all =.js= files with ParenScript equivalents
- Maintain same functionality
- Improve code maintainability by using one language (Lisp) for both frontend and backend
- Take advantage of Lisp macros for client-side code generation
* Current JavaScript Files
- =static/js/admin.js= - Admin dashboard functionality
- =static/js/auth-ui.js= - Authentication UI
- =static/js/front-page.js= - Front page interactions
- =static/js/player.js= - Audio player controls
- =static/js/profile.js= - User profile page
- =static/js/users.js= - User management
* Implementation Plan
** Phase 1: Setup [DONE]
- [X] Add ParenScript dependency to =asteroid.asd=
- [X] Create =parenscript-utils.lisp= with helper functions
- [X] Create experimental branch
** Phase 2: Convert Simple Files First
- [ ] Convert =auth-ui.js= (smallest, simplest)
- [ ] Convert =profile.js=
- [ ] Convert =users.js=
** Phase 3: Convert Complex Files
- [ ] Convert =player.js= (audio player logic)
- [ ] Convert =front-page.js= (pop-out player, frameset mode)
- [ ] Convert =admin.js= (queue management, track controls)
** Phase 4: Testing & Refinement
- [ ] Test all functionality
- [ ] Optimize generated JavaScript
- [ ] Document ParenScript patterns used
* Benefits
** Code Reuse
- Share utility functions between frontend and backend
- Use same data structures and validation logic
** Macros
- Create domain-specific macros for common UI patterns
- Generate repetitive JavaScript code programmatically
** Type Safety
- Catch more errors at compile time
- Better IDE support with Lisp tooling
** Maintainability
- Single language for entire stack
- Easier refactoring across frontend/backend boundary
* ParenScript Resources
- [[https://parenscript.common-lisp.dev/][ParenScript Documentation]]
- [[https://github.com/vsedach/Parenscript][ParenScript GitHub]]
* Notes
This is an EXPERIMENTAL branch. The goal is to evaluate ParenScript for this project, not to immediately replace all JavaScript.
If successful, we can merge incrementally, one file at a time.

View File

@ -17,6 +17,7 @@
:r-simple-rate :r-simple-rate
:r-simple-profile :r-simple-profile
:lass :lass
:parenscript
:cl-json :cl-json
:alexandria :alexandria
:local-time :local-time
@ -38,6 +39,7 @@
(:file "conditions") (:file "conditions")
(:file "database") (:file "database")
(:file "template-utils") (:file "template-utils")
(:file "parenscript-utils")
(:file "stream-media") (:file "stream-media")
(:file "user-management") (:file "user-management")
(:file "playlist-management") (:file "playlist-management")

33
parenscript-utils.lisp Normal file
View File

@ -0,0 +1,33 @@
;;;; parenscript-utils.lisp
;;;; Utilities for generating JavaScript from ParenScript
(in-package :asteroid)
;;; ParenScript compilation utilities
(defun compile-ps-to-js (ps-code)
"Compile ParenScript code to JavaScript string"
(ps:ps* ps-code))
(defmacro define-js-route (name (&rest args) &body parenscript-body)
"Define a route that serves compiled ParenScript as JavaScript"
`(define-page ,name (,@args)
(:content-type "application/javascript")
(ps:ps ,@parenscript-body)))
;;; Common ParenScript macros and utilities
(defmacro ps-defun (name args &body body)
"Define a ParenScript function"
`(ps:defun ,name ,args ,@body))
(defmacro ps-api-call (endpoint method data success-callback error-callback)
"Generate ParenScript for making API calls with fetch"
`(ps:ps
(fetch ,endpoint
(ps:create :method ,method
:headers (ps:create "Content-Type" "application/json")
:body (ps:chain -j-s-o-n (stringify ,data))))
(then (lambda (response) (ps:chain response (json))))
(then ,success-callback)
(catch ,error-callback)))