about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-05-08 18:39:27 +0200
committerbptato <nincsnevem662@gmail.com>2024-05-08 18:39:27 +0200
commit86f4c56507bc94d03e7d94be6ede884b9e7b5358 (patch)
tree929ce32ada67e8b1d57787d8e6d038fa603fc31e /src
parent5c891488423aa7ccbef2fb4332ff6cb4e3c05154 (diff)
downloadchawan-86f4c56507bc94d03e7d94be6ede884b9e7b5358.tar.gz
js: refactor
* prefix to-be-separated modules with js
* remove dynstreams dependency
* untangle from EmptyPromise
* move typeptr into tojs
Diffstat (limited to 'src')
-rw-r--r--src/config/chapath.nim2
-rw-r--r--src/config/config.nim6
-rw-r--r--src/html/chadombuilder.nim2
-rw-r--r--src/html/dom.nim6
-rw-r--r--src/html/env.nim9
-rw-r--r--src/html/event.nim2
-rw-r--r--src/io/promise.nim103
-rw-r--r--src/io/urlfilter.nim2
-rw-r--r--src/js/console.nim9
-rw-r--r--src/js/domexception.nim2
-rw-r--r--src/js/encoding.nim2
-rw-r--r--src/js/fromjs.nim39
-rw-r--r--src/js/javascript.nim21
-rw-r--r--src/js/jscolor.nim2
-rw-r--r--src/js/jserror.nim (renamed from src/js/error.nim)0
-rw-r--r--src/js/jsmodule.nim (renamed from src/js/module.nim)0
-rw-r--r--src/js/jsopaque.nim (renamed from src/js/opaque.nim)2
-rw-r--r--src/js/jspropenumlist.nim (renamed from src/js/propertyenumlist.nim)0
-rw-r--r--src/js/jsregex.nim (renamed from src/js/regex.nim)0
-rw-r--r--src/js/tojs.nim85
-rw-r--r--src/js/typeptr.nim18
-rw-r--r--src/loader/headers.nim2
-rw-r--r--src/loader/loader.nim2
-rw-r--r--src/loader/request.nim2
-rw-r--r--src/loader/response.nim2
-rw-r--r--src/local/client.nim17
-rw-r--r--src/local/container.nim2
-rw-r--r--src/local/pager.nim4
-rw-r--r--src/local/select.nim2
-rw-r--r--src/server/buffer.nim3
-rw-r--r--src/types/cookie.nim4
-rw-r--r--src/types/url.nim2
32 files changed, 183 insertions, 171 deletions
diff --git a/src/config/chapath.nim b/src/config/chapath.nim
index 8bab5070..c02a3f1e 100644
--- a/src/config/chapath.nim
+++ b/src/config/chapath.nim
@@ -2,9 +2,9 @@ import std/options
 import std/os
 import std/posix
 
-import js/error
 import js/fromjs
 import js/javascript
+import js/jserror
 import js/tojs
 import types/opt
 import utils/twtstr
diff --git a/src/config/config.nim b/src/config/config.nim
index 8ff736d0..cb2323cd 100644
--- a/src/config/config.nim
+++ b/src/config/config.nim
@@ -9,13 +9,13 @@ import config/chapath
 import config/mailcap
 import config/mimetypes
 import config/toml
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import js/jscolor
 import js/jstypes
-import js/propertyenumlist
-import js/regex
+import js/jspropenumlist
+import js/jsregex
 import js/tojs
 import loader/headers
 import types/cell
diff --git a/src/html/chadombuilder.nim b/src/html/chadombuilder.nim
index 716358d3..92effe3a 100644
--- a/src/html/chadombuilder.nim
+++ b/src/html/chadombuilder.nim
@@ -4,7 +4,7 @@ import std/options
 import html/catom
 import html/dom
 import html/enums
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import types/url
diff --git a/src/html/dom.nim b/src/html/dom.nim
index 961dedd8..dc12bb6e 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -22,12 +22,12 @@ import io/dynstream
 import io/promise
 import js/console
 import js/domexception
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import js/jsutils
-import js/opaque
-import js/propertyenumlist
+import js/jsopaque
+import js/jspropenumlist
 import js/timeout
 import js/tojs
 import loader/loader
diff --git a/src/html/env.nim b/src/html/env.nim
index 8545436f..ef4b4658 100644
--- a/src/html/env.nim
+++ b/src/html/env.nim
@@ -14,7 +14,7 @@ import js/base64
 import js/console
 import js/domexception
 import js/encoding
-import js/error
+import js/jserror
 import js/intl
 import js/javascript
 import js/jstypes
@@ -211,7 +211,12 @@ proc addScripting*(window: Window; selector: Selector[int]) =
   ctx.addEncodingModule()
 
 proc runJSJobs*(window: Window) =
-  window.jsrt.runJSJobs(window.console.err)
+  while true:
+    let r = window.jsrt.runJSJobs()
+    if r.isSome:
+      break
+    let ctx = r.error
+    ctx.writeException(window.console.err)
 
 proc newWindow*(scripting, images: bool; selector: Selector[int];
     attrs: WindowAttributes; factory: CAtomFactory;
diff --git a/src/html/event.nim b/src/html/event.nim
index b74649e8..7ae024db 100644
--- a/src/html/event.nim
+++ b/src/html/event.nim
@@ -3,7 +3,7 @@ import std/options
 import std/times
 
 import bindings/quickjs
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import js/jstypes
diff --git a/src/io/promise.nim b/src/io/promise.nim
index c675233f..6e57791b 100644
--- a/src/io/promise.nim
+++ b/src/io/promise.nim
@@ -1,10 +1,16 @@
 import std/tables
 
+import bindings/quickjs
+import js/jserror
+import js/javascript
+import js/jsutils
+import js/jsopaque
+import js/tojs
 import types/opt
 
 type
-  PromiseState* = enum
-    PROMISE_PENDING, PROMISE_FULFILLED, PROMISE_REJECTED
+  PromiseState = enum
+    psPending, psFulfilled, psRejected
 
   EmptyPromise* = ref object of RootObj
     cb: (proc())
@@ -47,7 +53,7 @@ proc resolve*(promise: EmptyPromise) =
     if promise.cb != nil:
       promise.cb()
     promise.cb = nil
-    promise.state = PROMISE_FULFILLED
+    promise.state = psFulfilled
     promise = promise.next
     if promise == nil:
       break
@@ -77,7 +83,7 @@ func empty*(map: PromiseMap): bool =
 proc then*(promise: EmptyPromise; cb: (proc())): EmptyPromise {.discardable.} =
   promise.cb = cb
   promise.next = EmptyPromise()
-  if promise.state == PROMISE_FULFILLED:
+  if promise.state == psFulfilled:
     promise.resolve()
   return promise.next
 
@@ -171,3 +177,92 @@ proc all*(promises: seq[EmptyPromise]): EmptyPromise =
   if promises.len == 0:
     res.resolve()
   return res
+
+# * Promise is converted to a JS promise which will be resolved when the Nim
+#   promise is resolved.
+
+proc promiseThenCallback(ctx: JSContext; this_val: JSValue; argc: cint;
+    argv: ptr UncheckedArray[JSValue]; magic: cint;
+    func_data: ptr UncheckedArray[JSValue]): JSValue {.cdecl.} =
+  let fun = func_data[0]
+  let op = JS_GetOpaque(fun, JS_GetClassID(fun))
+  if op != nil:
+    let p = cast[EmptyPromise](op)
+    p.resolve()
+    GC_unref(p)
+    JS_SetOpaque(fun, nil)
+  return JS_UNDEFINED
+
+proc fromJSEmptyPromise*(ctx: JSContext; val: JSValue): JSResult[EmptyPromise] =
+  if not JS_IsObject(val):
+    return err(newTypeError("Value is not an object"))
+  var p = EmptyPromise()
+  GC_ref(p)
+  let tmp = JS_NewObject(ctx)
+  JS_SetOpaque(tmp, cast[pointer](p))
+  let fun = JS_NewCFunctionData(ctx, promiseThenCallback, 0, 0, 1,
+    tmp.toJSValueArray())
+  JS_FreeValue(ctx, tmp)
+  let res = JS_Invoke(ctx, val, ctx.getOpaque().strRefs[jstThen], 1,
+    fun.toJSValueArray())
+  JS_FreeValue(ctx, fun)
+  if JS_IsException(res):
+    JS_FreeValue(ctx, res)
+    return err()
+  JS_FreeValue(ctx, res)
+  return ok(p)
+
+proc toJS*(ctx: JSContext; promise: EmptyPromise): JSValue =
+  var resolving_funcs: array[2, JSValue]
+  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
+  if JS_IsException(jsPromise):
+    return JS_EXCEPTION
+  promise.then(proc() =
+    let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 0, nil)
+    JS_FreeValue(ctx, res)
+    JS_FreeValue(ctx, resolving_funcs[0])
+    JS_FreeValue(ctx, resolving_funcs[1]))
+  return jsPromise
+
+proc toJS*[T](ctx: JSContext; promise: Promise[T]): JSValue =
+  var resolving_funcs: array[2, JSValue]
+  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
+  if JS_IsException(jsPromise):
+    return JS_EXCEPTION
+  promise.then(proc(x: T) =
+    let x = toJS(ctx, x)
+    let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1,
+      x.toJSValueArray())
+    JS_FreeValue(ctx, res)
+    JS_FreeValue(ctx, x)
+    JS_FreeValue(ctx, resolving_funcs[0])
+    JS_FreeValue(ctx, resolving_funcs[1]))
+  return jsPromise
+
+proc toJS*[T, E](ctx: JSContext; promise: Promise[Result[T, E]]): JSValue =
+  var resolving_funcs: array[2, JSValue]
+  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
+  if JS_IsException(jsPromise):
+    return JS_EXCEPTION
+  promise.then(proc(x: Result[T, E]) =
+    if x.isSome:
+      let x = when T is void:
+        JS_UNDEFINED
+      else:
+        toJS(ctx, x.get)
+      let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1,
+        x.toJSValueArray())
+      JS_FreeValue(ctx, res)
+      JS_FreeValue(ctx, x)
+    else: # err
+      let x = when E is void:
+        JS_UNDEFINED
+      else:
+        toJS(ctx, x.error)
+      let res = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
+        x.toJSValueArray())
+      JS_FreeValue(ctx, res)
+      JS_FreeValue(ctx, x)
+    JS_FreeValue(ctx, resolving_funcs[0])
+    JS_FreeValue(ctx, resolving_funcs[1]))
+  return jsPromise
diff --git a/src/io/urlfilter.nim b/src/io/urlfilter.nim
index 6bbb247c..4d1d2404 100644
--- a/src/io/urlfilter.nim
+++ b/src/io/urlfilter.nim
@@ -1,6 +1,6 @@
 import std/options
 
-import js/regex
+import js/jsregex
 import types/url
 
 #TODO add denyhost/s for blocklists
diff --git a/src/js/console.nim b/src/js/console.nim
index 3b28df5e..712f228c 100644
--- a/src/js/console.nim
+++ b/src/js/console.nim
@@ -1,4 +1,5 @@
 import io/dynstream
+import js/jserror
 import js/javascript
 
 type Console* = ref object
@@ -55,3 +56,11 @@ proc addConsoleModule*(ctx: JSContext) =
   #TODO console should not have a prototype
   # "For historical reasons, console is lowercased."
   ctx.registerType(Console, nointerface = true, name = "console")
+
+proc writeException*(ctx: JSContext; s: DynStream) =
+  s.write(ctx.getExceptionMsg())
+  s.sflush()
+
+proc writeException*(ctx: JSContext; s: DynStream; err: JSError) =
+  s.write(ctx.getExceptionMsg(err))
+  s.sflush()
diff --git a/src/js/domexception.nim b/src/js/domexception.nim
index 39537b0a..902cd618 100644
--- a/src/js/domexception.nim
+++ b/src/js/domexception.nim
@@ -1,7 +1,7 @@
 import std/tables
 
 import bindings/quickjs
-import js/error
+import js/jserror
 import js/javascript
 
 const NamesTable = {
diff --git a/src/js/encoding.nim b/src/js/encoding.nim
index cfcf8f07..edf0cf97 100644
--- a/src/js/encoding.nim
+++ b/src/js/encoding.nim
@@ -1,5 +1,5 @@
 import bindings/quickjs
-import js/error
+import js/jserror
 import js/javascript
 import js/jstypes
 
diff --git a/src/js/fromjs.nim b/src/js/fromjs.nim
index c5c80da1..7a8a0859 100644
--- a/src/js/fromjs.nim
+++ b/src/js/fromjs.nim
@@ -4,11 +4,9 @@ import std/tables
 import std/unicode
 
 import bindings/quickjs
-import io/promise
-import js/error
+import js/jserror
 import js/jstypes
-import js/jsutils
-import js/opaque
+import js/jsopaque
 import types/opt
 import utils/twtstr
 
@@ -374,37 +372,6 @@ proc fromJSArrayBufferView(ctx: JSContext; val: JSValue):
   )
   return ok(view)
 
-proc promiseThenCallback(ctx: JSContext; this_val: JSValue; argc: cint;
-    argv: ptr UncheckedArray[JSValue]; magic: cint;
-    func_data: ptr UncheckedArray[JSValue]): JSValue {.cdecl.} =
-  let fun = func_data[0]
-  let op = JS_GetOpaque(fun, JS_GetClassID(fun))
-  if op != nil:
-    let p = cast[EmptyPromise](op)
-    p.resolve()
-    GC_unref(p)
-    JS_SetOpaque(fun, nil)
-  return JS_UNDEFINED
-
-proc fromJSEmptyPromise(ctx: JSContext; val: JSValue): JSResult[EmptyPromise] =
-  if not JS_IsObject(val):
-    return err(newTypeError("Value is not an object"))
-  var p = EmptyPromise()
-  GC_ref(p)
-  let tmp = JS_NewObject(ctx)
-  JS_SetOpaque(tmp, cast[pointer](p))
-  let fun = JS_NewCFunctionData(ctx, promiseThenCallback, 0, 0, 1,
-    tmp.toJSValueArray())
-  JS_FreeValue(ctx, tmp)
-  let res = JS_Invoke(ctx, val, ctx.getOpaque().strRefs[jstThen], 1,
-    fun.toJSValueArray())
-  JS_FreeValue(ctx, fun)
-  if JS_IsException(res):
-    JS_FreeValue(ctx, res)
-    return err()
-  JS_FreeValue(ctx, res)
-  return ok(p)
-
 type FromJSAllowedT = (object and not (Result|Option|Table|JSValue|JSDict|
   JSArrayBuffer|JSArrayBufferView|JSUint8Array))
 
@@ -437,8 +404,6 @@ proc fromJS*[T](ctx: JSContext; val: JSValue): JSResult[T] =
     return fromJSEnum[T](ctx, val)
   elif T is JSValue:
     return ok(val)
-  elif T is EmptyPromise:
-    return fromJSEmptyPromise(ctx, val)
   elif T is ref object:
     return fromJSObject[T](ctx, val)
   elif T is void:
diff --git a/src/js/javascript.nim b/src/js/javascript.nim
index 90694e93..58b80c6f 100644
--- a/src/js/javascript.nim
+++ b/src/js/javascript.nim
@@ -48,12 +48,10 @@ import std/strutils
 import std/tables
 import std/unicode
 
-import io/dynstream
-import js/error
+import js/jserror
 import js/fromjs
-import js/opaque
+import js/jsopaque
 import js/tojs
-import js/typeptr
 import types/opt
 import utils/twtstr
 
@@ -225,20 +223,15 @@ proc getExceptionMsg*(ctx: JSContext; err: JSError): string =
     JS_FreeValue(ctx, ctx.toJS(err)) # note: this implicitly throws
   return ctx.getExceptionMsg()
 
-proc writeException*(ctx: JSContext; s: DynStream) =
-  s.write(ctx.getExceptionMsg())
-  s.sflush()
-
-proc writeException*(ctx: JSContext; s: DynStream; err: JSError) =
-  s.write(ctx.getExceptionMsg(err))
-  s.sflush()
-
-proc runJSJobs*(rt: JSRuntime; err: DynStream) =
+# Returns early with err(JSContext) if an exception was thrown in a
+# context.
+proc runJSJobs*(rt: JSRuntime): Err[JSContext] =
   while JS_IsJobPending(rt):
     var ctx: JSContext
     let r = JS_ExecutePendingJob(rt, addr ctx)
     if r == -1:
-      ctx.writeException(err)
+      return err(ctx)
+  ok()
 
 # Add all LegacyUnforgeable functions defined on the prototype chain to
 # the opaque.
diff --git a/src/js/jscolor.nim b/src/js/jscolor.nim
index 48f7fb34..a73fb599 100644
--- a/src/js/jscolor.nim
+++ b/src/js/jscolor.nim
@@ -1,7 +1,7 @@
 import std/strutils
 
 import bindings/quickjs
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import js/tojs
diff --git a/src/js/error.nim b/src/js/jserror.nim
index b4101830..b4101830 100644
--- a/src/js/error.nim
+++ b/src/js/jserror.nim
diff --git a/src/js/module.nim b/src/js/jsmodule.nim
index 636065b8..636065b8 100644
--- a/src/js/module.nim
+++ b/src/js/jsmodule.nim
diff --git a/src/js/opaque.nim b/src/js/jsopaque.nim
index 93900502..bfe8b07b 100644
--- a/src/js/opaque.nim
+++ b/src/js/jsopaque.nim
@@ -1,7 +1,7 @@
 import std/tables
 
 import bindings/quickjs
-import js/error
+import js/jserror
 import types/opt
 
 type
diff --git a/src/js/propertyenumlist.nim b/src/js/jspropenumlist.nim
index 65c16c2f..65c16c2f 100644
--- a/src/js/propertyenumlist.nim
+++ b/src/js/jspropenumlist.nim
diff --git a/src/js/regex.nim b/src/js/jsregex.nim
index f24633d1..f24633d1 100644
--- a/src/js/regex.nim
+++ b/src/js/jsregex.nim
diff --git a/src/js/tojs.nim b/src/js/tojs.nim
index 4090757d..7697ea4a 100644
--- a/src/js/tojs.nim
+++ b/src/js/tojs.nim
@@ -4,8 +4,6 @@
 #
 # * Primitives are converted to their respective JavaScript counterparts.
 # * seq is converted to a JS array. Note: this always copies the seq's contents.
-# * Promise is converted to a JS promise which will be resolved when the Nim
-#   promise is resolved.
 # * enum is converted to its stringifier's output.
 # * JSValue is returned as-is, *without* a DupValue operation.
 # * JSError is converted to a new error object corresponding to the error
@@ -41,12 +39,10 @@ import std/tables
 import std/unicode
 
 import bindings/quickjs
-import io/promise
-import js/error
+import js/jserror
 import js/jstypes
 import js/jsutils
-import js/opaque
-import js/typeptr
+import js/jsopaque
 import types/opt
 
 # Convert Nim types to the corresponding JavaScript type.
@@ -69,9 +65,6 @@ proc toJS*[T](ctx: JSContext; s: set[T]): JSValue
 proc toJS*(ctx: JSContext; t: tuple): JSValue
 proc toJS*(ctx: JSContext; e: enum): JSValue
 proc toJS*(ctx: JSContext; j: JSValue): JSValue
-proc toJS*[T](ctx: JSContext; promise: Promise[T]): JSValue
-proc toJS*[T, E](ctx: JSContext; promise: Promise[Result[T, E]]): JSValue
-proc toJS*(ctx: JSContext; promise: EmptyPromise): JSValue
 proc toJS*(ctx: JSContext; obj: ref object): JSValue
 proc toJS*(ctx: JSContext; err: JSError): JSValue
 proc toJS*(ctx: JSContext; abuf: JSArrayBuffer): JSValue
@@ -273,6 +266,25 @@ proc toJSP0(ctx: JSContext; p, tp: pointer; ctor: JSValue;
     JS_SetIsHTMLDDA(ctx, jsObj)
   return jsObj
 
+# Get a unique pointer for each type.
+proc getTypePtr*[T](x: T): pointer =
+  when T is RootRef:
+    # I'm so sorry.
+    # (This dereferences the object's first member, m_type. Probably.)
+    return cast[ptr pointer](x)[]
+  elif T is RootObj:
+    return cast[pointer](x)
+  else:
+    return getTypeInfo(x)
+
+func getTypePtr*(t: typedesc[ref object]): pointer =
+  var x = t()
+  return getTypePtr(x)
+
+func getTypePtr*(t: type): pointer =
+  var x: t
+  return getTypePtr(x)
+
 proc toJSRefObj(ctx: JSContext; obj: ref object): JSValue =
   if obj == nil:
     return JS_NULL
@@ -318,61 +330,6 @@ proc toJS(ctx: JSContext; e: enum): JSValue =
 proc toJS(ctx: JSContext; j: JSValue): JSValue =
   return j
 
-proc toJS(ctx: JSContext; promise: EmptyPromise): JSValue =
-  var resolving_funcs: array[2, JSValue]
-  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
-  if JS_IsException(jsPromise):
-    return JS_EXCEPTION
-  promise.then(proc() =
-    let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 0, nil)
-    JS_FreeValue(ctx, res)
-    JS_FreeValue(ctx, resolving_funcs[0])
-    JS_FreeValue(ctx, resolving_funcs[1]))
-  return jsPromise
-
-proc toJS[T](ctx: JSContext; promise: Promise[T]): JSValue =
-  var resolving_funcs: array[2, JSValue]
-  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
-  if JS_IsException(jsPromise):
-    return JS_EXCEPTION
-  promise.then(proc(x: T) =
-    let x = toJS(ctx, x)
-    let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1,
-      x.toJSValueArray())
-    JS_FreeValue(ctx, res)
-    JS_FreeValue(ctx, x)
-    JS_FreeValue(ctx, resolving_funcs[0])
-    JS_FreeValue(ctx, resolving_funcs[1]))
-  return jsPromise
-
-proc toJS[T, E](ctx: JSContext; promise: Promise[Result[T, E]]): JSValue =
-  var resolving_funcs: array[2, JSValue]
-  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
-  if JS_IsException(jsPromise):
-    return JS_EXCEPTION
-  promise.then(proc(x: Result[T, E]) =
-    if x.isSome:
-      let x = when T is void:
-        JS_UNDEFINED
-      else:
-        toJS(ctx, x.get)
-      let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1,
-        x.toJSValueArray())
-      JS_FreeValue(ctx, res)
-      JS_FreeValue(ctx, x)
-    else: # err
-      let x = when E is void:
-        JS_UNDEFINED
-      else:
-        toJS(ctx, x.error)
-      let res = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
-        x.toJSValueArray())
-      JS_FreeValue(ctx, res)
-      JS_FreeValue(ctx, x)
-    JS_FreeValue(ctx, resolving_funcs[0])
-    JS_FreeValue(ctx, resolving_funcs[1]))
-  return jsPromise
-
 proc toJS*(ctx: JSContext; err: JSError): JSValue =
   if err == nil:
     return JS_EXCEPTION
diff --git a/src/js/typeptr.nim b/src/js/typeptr.nim
deleted file mode 100644
index 55fd89c7..00000000
--- a/src/js/typeptr.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-# Get a unique pointer for each type.
-proc getTypePtr*[T](x: T): pointer =
-  when T is RootRef:
-    # I'm so sorry.
-    # (This dereferences the object's first member, m_type. Probably.)
-    return cast[ptr pointer](x)[]
-  elif T is RootObj:
-    return cast[pointer](x)
-  else:
-    return getTypeInfo(x)
-
-func getTypePtr*(t: typedesc[ref object]): pointer =
-  var x = t()
-  return getTypePtr(x)
-
-func getTypePtr*(t: type): pointer =
-  var x: t
-  return getTypePtr(x)
diff --git a/src/loader/headers.nim b/src/loader/headers.nim
index d870eaea..21900189 100644
--- a/src/loader/headers.nim
+++ b/src/loader/headers.nim
@@ -1,7 +1,7 @@
 import std/tables
 
 import bindings/quickjs
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import utils/twtstr
diff --git a/src/loader/loader.nim b/src/loader/loader.nim
index 3fa861e1..8c5fd5d5 100644
--- a/src/loader/loader.nim
+++ b/src/loader/loader.nim
@@ -33,7 +33,7 @@ import io/serversocket
 import io/socketstream
 import io/tempfile
 import io/urlfilter
-import js/error
+import js/jserror
 import js/javascript
 import loader/cgi
 import loader/connecterror
diff --git a/src/loader/request.nim b/src/loader/request.nim
index 732dfe67..8eeb17b8 100644
--- a/src/loader/request.nim
+++ b/src/loader/request.nim
@@ -3,7 +3,7 @@ import std/strutils
 import std/tables
 
 import bindings/quickjs
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import js/jstypes
diff --git a/src/loader/response.nim b/src/loader/response.nim
index 648b2e2b..63b07cf1 100644
--- a/src/loader/response.nim
+++ b/src/loader/response.nim
@@ -4,7 +4,7 @@ import std/tables
 import bindings/quickjs
 import io/promise
 import io/socketstream
-import js/error
+import js/jserror
 import js/javascript
 import loader/headers
 import loader/request
diff --git a/src/local/client.nim b/src/local/client.nim
index 237ee284..af5e89a0 100644
--- a/src/local/client.nim
+++ b/src/local/client.nim
@@ -30,14 +30,14 @@ import js/base64
 import js/console
 import js/domexception
 import js/encoding
-import js/error
+import js/jserror
 import js/fromjs
 import js/intl
 import js/javascript
 import js/jstypes
 import js/jsutils
-import js/module
-import js/opaque
+import js/jsmodule
+import js/jsopaque
 import js/timeout
 import js/tojs
 import loader/headers
@@ -113,7 +113,12 @@ proc interruptHandler(rt: JSRuntime; opaque: pointer): cint {.cdecl.} =
   return 0
 
 proc runJSJobs(client: Client) =
-  client.jsrt.runJSJobs(client.console.err)
+  while true:
+    let r = client.jsrt.runJSJobs()
+    if r.isSome:
+      break
+    let ctx = r.error
+    ctx.writeException(client.console.err)
 
 proc cleanup(client: Client) =
   if client.alive:
@@ -221,8 +226,8 @@ proc evalAction(client: Client; action: string; arg0: int32): EmptyPromise =
       client.quit(client.exitCode)
   if JS_IsException(ret):
     client.jsctx.writeException(client.console.err)
-  if JS_IsObject(ret):
-    let maybep = fromJS[EmptyPromise](ctx, ret)
+  elif JS_IsObject(ret):
+    let maybep = fromJSEmptyPromise(ctx, ret)
     if maybep.isSome:
       p = maybep.get
   JS_FreeValue(ctx, ret)
diff --git a/src/local/container.nim b/src/local/container.nim
index 85a855db..e4901902 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -13,7 +13,7 @@ import io/serversocket
 import io/socketstream
 import js/javascript
 import js/jstypes
-import js/regex
+import js/jsregex
 import layout/renderdocument
 import loader/headers
 import loader/loader
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 3d030b57..af9855bc 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -21,12 +21,12 @@ import io/socketstream
 import io/stdio
 import io/tempfile
 import io/urlfilter
-import js/error
+import js/jserror
 import js/fromjs
 import js/javascript
 import js/jstypes
 import js/jsutils
-import js/regex
+import js/jsregex
 import js/tojs
 import loader/connecterror
 import loader/headers
diff --git a/src/local/select.nim b/src/local/select.nim
index cbefea5a..997eff1c 100644
--- a/src/local/select.nim
+++ b/src/local/select.nim
@@ -1,6 +1,6 @@
 import std/unicode
 
-import js/regex
+import js/jsregex
 import server/buffer
 import types/cell
 import utils/luwrap
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 1bdf1c30..52ac2830 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -36,9 +36,10 @@ import io/posixstream
 import io/promise
 import io/serversocket
 import io/socketstream
+import js/console
 import js/fromjs
 import js/javascript
-import js/regex
+import js/jsregex
 import js/timeout
 import js/tojs
 import layout/renderdocument
diff --git a/src/types/cookie.nim b/src/types/cookie.nim
index 6918648f..d1302710 100644
--- a/src/types/cookie.nim
+++ b/src/types/cookie.nim
@@ -2,9 +2,9 @@ import std/strutils
 import std/times
 
 import io/urlfilter
-import js/error
+import js/jserror
 import js/javascript
-import js/regex
+import js/jsregex
 import types/url
 import types/opt
 import utils/twtstr
diff --git a/src/types/url.nim b/src/types/url.nim
index 860134c8..54d6f8ed 100644
--- a/src/types/url.nim
+++ b/src/types/url.nim
@@ -6,7 +6,7 @@ import std/tables
 import std/unicode
 
 import bindings/libunicode
-import js/error
+import js/jserror
 import js/javascript
 import lib/punycode
 import types/blob