Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: strip export syntax from .mjs before global eval in QuickJS

Module eval scopes variables making lifecycle functions inaccessible.
Instead, strip export statements (export { ... } and export keyword)
from the source and eval as global script. Re-enable JS bridge.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+50 -19
+43 -11
fedac/native/cl/js-bridge.lisp
··· 190 190 (unless code 191 191 (format *error-output* "[js-bridge] Piece not found: ~A~%" path) 192 192 (return-from js-load-piece nil)) 193 - ;; Eval as ES module (supports export), then detect lifecycle globals 194 - ;; We inject globalThis assignments into the module source 195 - (let ((wrapper (format nil "~A~%~ 196 - globalThis.__piece_boot = typeof boot === 'function' ? boot : undefined;~%~ 197 - globalThis.__piece_paint = typeof paint === 'function' ? paint : undefined;~%~ 198 - globalThis.__piece_act = typeof act === 'function' ? act : undefined;~%~ 199 - globalThis.__piece_sim = typeof sim === 'function' ? sim : undefined;~%~ 200 - globalThis.__piece_leave = typeof leave === 'function' ? leave : undefined;~%" 201 - code))) 202 - (let ((rc (ac-native.quickjs:qjs-eval-module *ctx* wrapper (length wrapper) 203 - path))) 193 + ;; Strip ES module export syntax so we can eval as global script. 194 + ;; Module eval scopes variables, making them inaccessible from globalThis. 195 + ;; We strip: export { ... }; and export default/function/class/const/let/var 196 + (let* ((stripped code) 197 + ;; Remove "export { boot, paint, act, sim };" style 198 + (stripped (loop with s = stripped 199 + for pos = (search "export" s) 200 + while pos 201 + do (let ((after (subseq s (+ pos 6)))) 202 + (cond 203 + ;; export { ... } 204 + ((and (> (length after) 0) 205 + (char= (char (string-trim '(#\Space #\Tab) after) 0) #\{)) 206 + (let ((end (position #\} s :start pos))) 207 + (when end 208 + (let ((semi (position #\; s :start (1+ end)))) 209 + (setf s (concatenate 'string 210 + (subseq s 0 pos) 211 + (if semi (subseq s (1+ semi)) ""))))))) 212 + ;; export function/const/let/var/class — just remove "export " 213 + ((let ((trimmed (string-trim '(#\Space #\Tab) after))) 214 + (or (and (>= (length trimmed) 8) (string= "function" (subseq trimmed 0 8))) 215 + (and (>= (length trimmed) 5) (string= "const" (subseq trimmed 0 5))) 216 + (and (>= (length trimmed) 3) (string= "let" (subseq trimmed 0 3))) 217 + (and (>= (length trimmed) 3) (string= "var" (subseq trimmed 0 3))) 218 + (and (>= (length trimmed) 5) (string= "class" (subseq trimmed 0 5))) 219 + (and (>= (length trimmed) 7) (string= "default" (subseq trimmed 0 7))))) 220 + (setf s (concatenate 'string 221 + (subseq s 0 pos) 222 + (subseq s (+ pos 7))))) ; remove "export " 223 + (t (setf s (concatenate 'string 224 + (subseq s 0 (+ pos 6)) 225 + (subseq s (+ pos 6))))))) 226 + finally (return s))) 227 + (wrapper (format nil "~A~%~ 228 + if (typeof boot === 'function') globalThis.__piece_boot = boot;~%~ 229 + if (typeof paint === 'function') globalThis.__piece_paint = paint;~%~ 230 + if (typeof act === 'function') globalThis.__piece_act = act;~%~ 231 + if (typeof sim === 'function') globalThis.__piece_sim = sim;~%~ 232 + if (typeof leave === 'function') globalThis.__piece_leave = leave;~%" 233 + stripped))) 234 + (let ((rc (ac-native.quickjs:qjs-eval *ctx* wrapper (length wrapper) 235 + path 0))) 204 236 (when (= rc -1) 205 237 (format *error-output* "[js-bridge] Failed to load ~A~%" path) 206 238 (return-from js-load-piece nil))))
+7 -8
fedac/native/cl/main.lisp
··· 311 311 312 312 (defun main () 313 313 "AC Native OS entry point. Runs .mjs pieces via QuickJS or native CL notepat." 314 - ;; TODO: Re-enable QuickJS bridge once native CL notepat is stable 315 - ;; For now, always run native CL notepat (skip JS bridge) 316 - ;; (unless *js-fallback* 317 - ;; (let ((args (uiop:command-line-arguments))) 318 - ;; (when args 319 - ;; (let ((piece-path (first args))) 320 - ;; (when (and piece-path (search ".mjs" piece-path)) 321 - ;; (return-from main (main-js piece-path))))))) 314 + ;; Run .mjs pieces via QuickJS bridge 315 + (unless *js-fallback* 316 + (let ((args (uiop:command-line-arguments))) 317 + (when args 318 + (let ((piece-path (first args))) 319 + (when (and piece-path (search ".mjs" piece-path)) 320 + (return-from main (main-js piece-path))))))) 322 321 (setf *js-fallback* nil) 323 322 324 323 ;; No .mjs piece specified — fall back to native CL notepat