about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2025-02-01 16:03:14 +0100
committerbptato <nincsnevem662@gmail.com>2025-02-01 16:03:14 +0100
commit8b8f2cbba10f50ae51e09fd08b58500b98346b8e (patch)
treebab1838d2ba82980d61b6b7c16fe86b2deeb6d05 /src
parent81c89e6de45c704d319e01ff1e641e3066705c9a (diff)
downloadchawan-8b8f2cbba10f50ae51e09fd08b58500b98346b8e.tar.gz
dom: handle exceptions in module script
Diffstat (limited to 'src')
-rw-r--r--src/html/dom.nim17
-rw-r--r--src/io/promise.nim90
2 files changed, 80 insertions, 27 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim
index 11a91ef1..94e3fef0 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -5179,12 +5179,18 @@ proc fetchDescendantsAndLink(element: HTMLScriptElement; script: Script;
     window.logException(script.baseURL)
     return
   ctx.setImportMeta(script.record, true)
-  #TODO I think record can be a promise with TLA, and then this doesn't
-  # work at all
   let res = JS_EvalFunction(ctx, script.record)
   if JS_IsException(res):
     window.logException(script.baseURL)
     return
+  var p: Promise[JSValue]
+  if ctx.fromJS(res, p).isSome:
+    p.then(proc(res: JSValue) =
+      if JS_IsException(res):
+        window.logException(script.baseURL)
+    )
+  else:
+    window.logException(script.baseURL)
   JS_FreeValue(ctx, res)
 
 #TODO settings object
@@ -5282,16 +5288,13 @@ proc execute*(element: HTMLScriptElement) =
     let window = document.window
     if window != nil and window.jsctx != nil:
       let script = element.scriptResult.script
-      let urls = script.baseURL.serialize(excludepassword = true)
       let ctx = window.jsctx
       if JS_IsException(script.record):
-        window.console.error("Exception in document", urls,
-          ctx.getExceptionMsg())
+        window.logException(script.baseURL)
       else:
         let ret = ctx.evalFunction(script.record)
         if JS_IsException(ret):
-          window.console.error("Exception in document", urls,
-            ctx.getExceptionMsg())
+          window.logException(script.baseURL)
         JS_FreeValue(ctx, ret)
     document.currentScript = oldCurrentScript
   else: discard #TODO
diff --git a/src/io/promise.nim b/src/io/promise.nim
index 544ed0a2..918c9b3b 100644
--- a/src/io/promise.nim
+++ b/src/io/promise.nim
@@ -149,39 +149,89 @@ proc all*(promises: seq[EmptyPromise]): EmptyPromise =
 
 # 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;
+proc promiseThenCallback(ctx: JSContext; this: JSValue; argc: cint;
     argv: ptr UncheckedArray[JSValue]; magic: cint;
-    func_data: ptr UncheckedArray[JSValue]): JSValue {.cdecl.} =
-  let fun = func_data[0]
+    funcData: ptr UncheckedArray[JSValue]): JSValue {.cdecl.} =
+  let fun = funcData[0]
   let op = JS_GetOpaque(fun, JS_GetClassID(fun))
   if op != nil:
-    let p = cast[EmptyPromise](op)
-    p.resolve()
+    var vals: seq[JSValue] = @[]
+    for it in argv.toOpenArray(0, argc - 1):
+      vals.add(it)
+    let p = cast[Promise[seq[JSValue]]](op)
+    p.resolve(vals)
+    GC_unref(p)
+    JS_SetOpaque(fun, nil)
+  return JS_UNDEFINED
+
+proc promiseCatchCallback(ctx: JSContext; this: JSValue; argc: cint;
+    argv: ptr UncheckedArray[JSValue]; magic: cint;
+    funcData: ptr UncheckedArray[JSValue]): JSValue {.cdecl.} =
+  let fun = funcData[0]
+  let op = JS_GetOpaque(fun, JS_GetClassID(fun))
+  if op != nil and argc > 0:
+    let vals = @[JS_Throw(ctx, argv[0])]
+    let p = cast[Promise[seq[JSValue]]](op)
+    p.resolve(vals)
     GC_unref(p)
     JS_SetOpaque(fun, nil)
   return JS_UNDEFINED
 
-proc fromJS*(ctx: JSContext; val: JSValue; res: var EmptyPromise): Opt[void] =
+proc fromJS*(ctx: JSContext; val: JSValue; res: out Promise[seq[JSValue]]):
+    Opt[void] =
   if not JS_IsObject(val):
     JS_ThrowTypeError(ctx, "value is not an object")
+    res = nil
     return err()
-  res = EmptyPromise()
-  GC_ref(res)
+  res = Promise[seq[JSValue]]()
   let tmp = JS_NewObject(ctx)
   JS_SetOpaque(tmp, cast[pointer](res))
-  let fun = JS_NewCFunctionData(ctx, promiseThenCallback, 0, 0, 1,
-    tmp.toJSValueArray())
-  JS_FreeValue(ctx, tmp)
-  let val = JS_Invoke(ctx, val, ctx.getOpaque().strRefs[jstThen], 1,
-    fun.toJSValueArray())
-  JS_FreeValue(ctx, fun)
-  if JS_IsException(val):
+  block then:
+    let fun = JS_NewCFunctionData(ctx, promiseThenCallback, 0, 0, 1,
+      tmp.toJSValueArray())
+    let val = JS_Invoke(ctx, val, ctx.getOpaque().strRefs[jstThen], 1,
+      fun.toJSValueArray())
+    JS_FreeValue(ctx, fun)
+    if JS_IsException(val):
+      res = nil
+      return err()
     JS_FreeValue(ctx, val)
-    GC_unref(res)
-    res = nil
-    return err()
-  JS_FreeValue(ctx, val)
+  block catch:
+    let fun = JS_NewCFunctionData(ctx, promiseCatchCallback, 0, 0, 1,
+      tmp.toJSValueArray())
+    let val = JS_Invoke(ctx, val, ctx.getOpaque().strRefs[jstCatch], 1,
+      fun.toJSValueArray())
+    JS_FreeValue(ctx, fun)
+    if JS_IsException(val):
+      res = nil
+      return err()
+    JS_FreeValue(ctx, val)
+  JS_FreeValue(ctx, tmp)
+  GC_ref(res)
+  return ok()
+
+proc fromJS*(ctx: JSContext; val: JSValue; res: out EmptyPromise): Opt[void] =
+  var res1: Promise[seq[JSValue]]
+  ?ctx.fromJS(val, res1)
+  let res2 = EmptyPromise()
+  res1.then(proc(_: seq[JSValue]) =
+    res2.resolve()
+  )
+  res = res2
+  return ok()
+
+proc fromJS*(ctx: JSContext; val: JSValue; res: out Promise[JSValue]):
+    Opt[void] =
+  var res1: Promise[seq[JSValue]]
+  ?ctx.fromJS(val, res1)
+  let res2 = Promise[JSValue]()
+  res1.then(proc(s: seq[JSValue]) =
+    if s.len > 0:
+      res2.resolve(s[0])
+    else:
+      res2.resolve(JS_UNDEFINED)
+  )
+  res = res2
   return ok()
 
 proc toJS*(ctx: JSContext; promise: EmptyPromise): JSValue =