///|
/// JavaScript Runtime - QuickJS implementation
///
/// Uses quickjs-emscripten for sandboxed JavaScript execution.
/// DOM operations are queued and executed after JS completes.
///|
/// Global state for context management
priv struct RuntimeState {
mut counter : Int
contexts : Map[Int, @dom.DomTree]
mut initialized : Bool
}
///|
/// Global runtime state
let runtime_state : RuntimeState = {
counter: 0,
contexts: {},
initialized: false,
}
///|
/// Allocate a stable runtime context id
fn allocate_runtime_context_id() -> Int {
let id = runtime_state.counter
runtime_state.counter = runtime_state.counter + 1
id
}
///|
/// Update DomTree mapping for an existing context id
fn update_context(id : Int, dom : @dom.DomTree) -> Unit {
runtime_state.contexts.set(id, dom)
}
///|
/// QuickJS runtime implementation
priv struct QuickJsRuntime {
_unused : Int
}
///|
let quickjs_runtime : QuickJsRuntime = { _unused: 0 }
///|
fn default_js_runtime() -> &JsRuntime {
quickjs_runtime as &JsRuntime
}
///|
impl JsRuntime for QuickJsRuntime with fn init(self : QuickJsRuntime) -> Unit {
let _ = self
if !runtime_state.initialized {
let success = quickjs_init()
if success {
runtime_state.initialized = true
}
}
}
///|
impl JsRuntime for QuickJsRuntime with fn execute(
self : QuickJsRuntime,
context_id : Int,
dom : @dom.DomTree,
code : String,
async_mode : AsyncExecutionMode,
) -> JsResult raise JsError {
let _ = self
update_context(context_id, dom)
// Generate DOM initialization code from DomTree
// This populates the mock DOM with actual HTML content
let dom_init_code = create_dom_init_code(dom)
// Execute against a stable runtime context so top-level JS state survives.
let flush_async = match async_mode {
ImmediateFlush => true
DeferredFlush => false
}
let result_json = quickjs_execute_with_mock_dom(
context_id, dom_init_code, code, flush_async,
)
// Parse result
let (result, dom_ops) = parse_js_result_with_ops(result_json)
// Apply DOM operations to actual DomTree
apply_dom_ops(dom, dom_ops)
result
}
///|
impl JsRuntime for QuickJsRuntime with fn tick(
self : QuickJsRuntime,
context_id : Int,
dom : @dom.DomTree,
) -> JsResult raise JsError {
let _ = self
update_context(context_id, dom)
let result_json = quickjs_tick_with_mock_dom(context_id)
let (result, dom_ops) = parse_js_result_with_ops(result_json)
apply_dom_ops(dom, dom_ops)
result
}
///|
/// Initialize JS runtime with QuickJS
pub fn init_js_runtime() -> Unit {
quickjs_runtime.init()
}