diff options
author | bptato <nincsnevem662@gmail.com> | 2025-02-01 16:03:14 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2025-02-01 16:03:14 +0100 |
commit | 8b8f2cbba10f50ae51e09fd08b58500b98346b8e (patch) | |
tree | bab1838d2ba82980d61b6b7c16fe86b2deeb6d05 /src | |
parent | 81c89e6de45c704d319e01ff1e641e3066705c9a (diff) | |
download | chawan-8b8f2cbba10f50ae51e09fd08b58500b98346b8e.tar.gz |
dom: handle exceptions in module script
Diffstat (limited to 'src')
-rw-r--r-- | src/html/dom.nim | 17 | ||||
-rw-r--r-- | src/io/promise.nim | 90 |
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 = |