diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config/chapath.nim | 5 | ||||
-rw-r--r-- | src/config/config.nim | 6 | ||||
-rw-r--r-- | src/html/catom.nim | 9 | ||||
-rw-r--r-- | src/html/dom.nim | 64 | ||||
-rw-r--r-- | src/html/env.nim | 5 | ||||
-rw-r--r-- | src/html/event.nim | 35 | ||||
-rw-r--r-- | src/html/xmlhttprequest.nim | 20 | ||||
-rw-r--r-- | src/io/bufwriter.nim | 9 | ||||
-rw-r--r-- | src/io/promise.nim | 24 | ||||
-rw-r--r-- | src/js/console.nim | 29 | ||||
-rw-r--r-- | src/js/domexception.nim | 2 | ||||
-rw-r--r-- | src/js/encoding.nim | 15 | ||||
-rw-r--r-- | src/js/jscolor.nim | 34 | ||||
-rw-r--r-- | src/js/timeout.nim | 6 | ||||
-rw-r--r-- | src/loader/headers.nim | 26 | ||||
-rw-r--r-- | src/loader/loaderhandle.nim | 9 | ||||
-rw-r--r-- | src/loader/request.nim | 137 | ||||
-rw-r--r-- | src/local/client.nim | 12 | ||||
-rw-r--r-- | src/local/container.nim | 2 | ||||
-rw-r--r-- | src/local/pager.nim | 64 | ||||
-rw-r--r-- | src/server/buffer.nim | 5 | ||||
-rw-r--r-- | src/types/blob.nim | 2 | ||||
-rw-r--r-- | src/types/url.nim | 9 | ||||
-rw-r--r-- | src/utils/luwrap.nim | 11 | ||||
-rw-r--r-- | src/version.nim | 2 |
25 files changed, 276 insertions, 266 deletions
diff --git a/src/config/chapath.nim b/src/config/chapath.nim index 8397cb3d..9878e09b 100644 --- a/src/config/chapath.nim +++ b/src/config/chapath.nim @@ -4,7 +4,6 @@ import std/posix import monoucha/fromjs import monoucha/javascript -import monoucha/jserror import monoucha/tojs import types/opt import utils/twtstr @@ -283,8 +282,8 @@ proc unquote(p: string): ChaPathResult[string] = proc toJS*(ctx: JSContext; p: ChaPath): JSValue = toJS(ctx, $p) -proc fromJSChaPath*(ctx: JSContext; val: JSValue): JSResult[ChaPath] = - return cast[JSResult[ChaPath]](fromJS[string](ctx, val)) +proc fromJS*(ctx: JSContext; val: JSValue; res: var ChaPath): Opt[void] = + return ctx.fromJS(val, string(res)) proc unquote*(p: ChaPath): ChaPathResult[string] = let s = ?unquote(string(p)) diff --git a/src/config/config.nim b/src/config/config.nim index 3c733bc5..b0064aa2 100644 --- a/src/config/config.nim +++ b/src/config/config.nim @@ -13,7 +13,6 @@ import js/jscolor import loader/headers import monoucha/fromjs import monoucha/javascript -import monoucha/jserror import monoucha/jspropenumlist import monoucha/jsregex import monoucha/jstypes @@ -195,9 +194,8 @@ jsDestructor(Config) converter toStr*(p: ChaPathResolved): string {.inline.} = return string(p) -proc fromJSChaPathResolved(ctx: JSContext; val: JSValue): - JSResult[ChaPathResolved] = - return cast[JSResult[ChaPathResolved]](fromJS[string](ctx, val)) +proc fromJS(ctx: JSContext; val: JSValue; res: var ChaPathResolved): Opt[void] = + return ctx.fromJS(val, string(res)) proc `[]=`(a: var ActionMap; b, c: string) = a.t[b] = c diff --git a/src/html/catom.nim b/src/html/catom.nim index 0ff7b949..111abb8d 100644 --- a/src/html/catom.nim +++ b/src/html/catom.nim @@ -6,7 +6,6 @@ import std/strutils import chame/tags import monoucha/fromjs import monoucha/javascript -import monoucha/jserror import monoucha/tojs import types/opt import utils/twtstr @@ -207,9 +206,11 @@ proc toAtom*(ctx: JSContext; atom: StaticAtom): CAtom = proc toStaticAtom*(ctx: JSContext; atom: CAtom): StaticAtom = return ctx.getFactory().toStaticAtom(atom) -proc fromJSCAtom*(ctx: JSContext; val: JSValue): JSResult[CAtom] = - let s = ?fromJS[string](ctx, val) - return ok(ctx.getFactory().toAtom(s)) +proc fromJS*(ctx: JSContext; val: JSValue; res: var CAtom): Opt[void] = + var s: string + ?ctx.fromJS(val, s) + res = ctx.getFactory().toAtom(s) + return ok() proc toJS*(ctx: JSContext; atom: CAtom): JSValue = return ctx.toJS(ctx.getFactory().toStr(atom)) diff --git a/src/html/dom.nim b/src/html/dom.nim index 950bdd7b..e58be7fc 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -908,13 +908,15 @@ proc reflectAttr(element: Element; name: CAtom; value: Option[string]) # preparation for Worker support.) func getGlobal*(ctx: JSContext): Window = let global = JS_GetGlobalObject(ctx) - let window = fromJS[Window](ctx, global).get + var window: Window + assert ctx.fromJS(global, window).isSome JS_FreeValue(ctx, global) return window func getWindow*(ctx: JSContext): Window = let global = JS_GetGlobalObject(ctx) - let window = fromJS[Window](ctx, global).get + var window: Window + assert ctx.fromJS(global, window).isSome JS_FreeValue(ctx, global) return window @@ -1481,12 +1483,15 @@ func namedItem(collection: HTMLCollection; s: string): Element {.jsfunc.} = return it return nil -func getter[T: uint32|string](collection: HTMLCollection; u: T): - Option[Element] {.jsgetprop.} = - when T is uint32: - return option(collection.item(u)) - else: - return option(collection.namedItem(u)) +func getter(ctx: JSContext; collection: HTMLCollection; atom: JSAtom): + Opt[Option[Element]] {.jsgetprop.} = + var u: uint32 + if ctx.fromJS(atom, u).isSome: + return ok(option(collection.item(u))) + var s: string + if ctx.fromJS(atom, s).isSome: + return ok(option(collection.namedItem(s))) + return err() func names(ctx: JSContext; collection: HTMLCollection): JSPropertyEnumList {.jspropnames.} = @@ -2622,7 +2627,7 @@ func newText*(document: Document; data: string): Text = ) func newText(ctx: JSContext; data = ""): Text {.jsctor.} = - let window = ctx.getGlobalOpaque(Window).get + let window = ctx.getGlobal() return window.document.newText(data) func newCDATASection(document: Document; data: string): CDATASection = @@ -2645,7 +2650,7 @@ func newDocumentFragment(document: Document): DocumentFragment = return DocumentFragment(internalDocument: document, index: -1) func newDocumentFragment(ctx: JSContext): DocumentFragment {.jsctor.} = - let window = ctx.getGlobalOpaque(Window).get + let window = ctx.getGlobal() return window.document.newDocumentFragment() func newComment(document: Document; data: string): Comment = @@ -2656,7 +2661,7 @@ func newComment(document: Document; data: string): Comment = ) func newComment(ctx: JSContext; data: string = ""): Comment {.jsctor.} = - let window = ctx.getGlobalOpaque(Window).get + let window = ctx.getGlobal() return window.document.newComment(data) #TODO custom elements @@ -4288,7 +4293,7 @@ const (ReflectTable, TagReflectMap, ReflectAllStartIndex) = (func(): ( proc jsReflectGet(ctx: JSContext; this: JSValue; magic: cint): JSValue {.cdecl.} = let entry = ReflectTable[uint16(magic)] - let op = getOpaque0(this) + let op = this.getOpaque() if unlikely(not ctx.isInstanceOf(this, "Element") or op == nil): return JS_ThrowTypeError(ctx, "Reflected getter called on a value that is not an element") @@ -4320,40 +4325,41 @@ proc jsReflectSet(ctx: JSContext; this, val: JSValue; magic: cint): JSValue return JS_ThrowTypeError(ctx, "Reflected getter called on a value that is not an element") let entry = ReflectTable[uint16(magic)] - let op = getOpaque0(this) + let op = this.getOpaque() assert op != nil let element = cast[Element](op) if element.tagType notin entry.tags: return JS_ThrowTypeError(ctx, "Invalid tag type %s", element.tagType) case entry.t of rtStr: - let x = fromJS[string](ctx, val) - if x.isSome: - element.attr(entry.attrname, x.get) + var x: string + if ctx.fromJS(val, x).isSome: + element.attr(entry.attrname, x) of rtBool: - let x = fromJS[bool](ctx, val) - if x.isSome: - if x.get: + var x: bool + if ctx.fromJS(val, x).isSome: + if x: element.attr(entry.attrname, "") else: let i = element.findAttr(entry.attrname) if i != -1: element.delAttr(i) of rtLong: - let x = fromJS[int32](ctx, val) - if x.isSome: - element.attrl(entry.attrname, x.get) + var x: int32 + if ctx.fromJS(val, x).isSome: + element.attrl(entry.attrname, x) of rtUlong: - let x = fromJS[uint32](ctx, val) - if x.isSome: - element.attrul(entry.attrname, x.get) + var x: uint32 + if ctx.fromJS(val, x).isSome: + element.attrul(entry.attrname, x) of rtUlongGz: - let x = fromJS[uint32](ctx, val) - if x.isSome: - element.attrulgz(entry.attrname, x.get) + var x: uint32 + if ctx.fromJS(val, x).isSome: + element.attrulgz(entry.attrname, x) of rtFunction: if JS_IsFunction(ctx, val): - let target = fromJS[EventTarget](ctx, this).get + var target: EventTarget + assert ctx.fromJS(this, target).isSome ctx.definePropertyC(this, $entry.attrname, JS_DupValue(ctx, val)) #TODO I haven't checked but this might also be wrong let ctype = ctx.getGlobal().toAtom(entry.ctype) diff --git a/src/html/env.nim b/src/html/env.nim index fed27096..4ecdc08b 100644 --- a/src/html/env.nim +++ b/src/html/env.nim @@ -166,8 +166,9 @@ proc addNavigatorModule*(ctx: JSContext) = ctx.registerType(History) ctx.registerType(Storage) -proc fetch(window: Window; input: JSValue; init = none(RequestInit)): - JSResult[FetchPromise] {.jsfunc.} = +proc fetch(window: Window; input: JSValue; + init = RequestInit(window: JS_UNDEFINED)): JSResult[FetchPromise] + {.jsfunc.} = let input = ?newRequest(window.jsctx, input, init) #TODO cors requests? if not window.settings.origin.isSameOrigin(input.request.url.origin): diff --git a/src/html/event.nim b/src/html/event.nim index 67131e63..732af7bc 100644 --- a/src/html/event.nim +++ b/src/html/event.nim @@ -68,17 +68,17 @@ jsDestructor(EventTarget) # Forward declaration hack var isDefaultPassive*: proc(target: EventTarget): bool {.nimcall, noSideEffect.} = nil -var getParent*: proc(ctx: JSContext; target: EventTarget, event: Event): +var getParent*: proc(ctx: JSContext; target: EventTarget; event: Event): EventTarget {.nimcall.} type EventInit* = object of JSDict - bubbles: bool - cancelable: bool - composed: bool + bubbles* {.jsdefault.}: bool + cancelable* {.jsdefault.}: bool + composed* {.jsdefault.}: bool CustomEventInit = object of EventInit - detail: JSValue + detail* {.jsdefault: JS_NULL.}: JSValue # Event proc innerEventCreationSteps*(event: Event; eventInitDict: EventInit) = @@ -161,11 +161,11 @@ func composed(this: Event): bool {.jsfget.} = return efComposed in this.flags # CustomEvent -proc newCustomEvent(ctype: CAtom; eventInitDict = CustomEventInit()): - JSResult[CustomEvent] {.jsctor.} = +proc newCustomEvent(ctx: JSContext; ctype: CAtom; + eventInitDict = CustomEventInit()): JSResult[CustomEvent] {.jsctor.} = let event = CustomEvent() event.innerEventCreationSteps(eventInitDict) - event.detail = eventInitDict.detail + event.detail = JS_DupValue(ctx, eventInitDict.detail) event.ctype = ctype return ok(event) @@ -240,12 +240,13 @@ proc removeAnEventListener(eventTarget: EventTarget; ctx: JSContext; i: int) = eventTarget.eventListeners.delete(i) proc flatten(ctx: JSContext; options: JSValue): bool = + result = false if JS_IsBool(options): - return fromJS[bool](ctx, options).get(false) + discard ctx.fromJS(options, result) if JS_IsObject(options): let x = JS_GetPropertyStr(ctx, options, "capture") - return fromJS[bool](ctx, x).get(false) - return false + discard ctx.fromJS(x, result) + JS_FreeValue(ctx, x) proc flattenMore(ctx: JSContext; options: JSValue): tuple[ @@ -254,20 +255,18 @@ proc flattenMore(ctx: JSContext; options: JSValue): passive: Option[bool] #TODO signals ] = - if JS_IsUndefined(options): - return let capture = flatten(ctx, options) var once = false - var passive: Option[bool] + var passive = none(bool) if JS_IsObject(options): let jsOnce = JS_GetPropertyStr(ctx, options, "once") - once = fromJS[bool](ctx, jsOnce).get(false) + discard ctx.fromJS(jsOnce, once) JS_FreeValue(ctx, jsOnce) let jsPassive = JS_GetPropertyStr(ctx, options, "passive") - let x = fromJS[bool](ctx, jsPassive) + var x: bool + if ctx.fromJS(jsPassive, x).isSome: + passive = some(x) JS_FreeValue(ctx, jsPassive) - if x.isSome: - passive = some(x.get) return (capture, once, passive) proc addEventListener*(ctx: JSContext; eventTarget: EventTarget; ctype: CAtom; diff --git a/src/html/xmlhttprequest.nim b/src/html/xmlhttprequest.nim index c402f6b4..16b6e012 100644 --- a/src/html/xmlhttprequest.nim +++ b/src/html/xmlhttprequest.nim @@ -2,6 +2,7 @@ import std/options import std/strutils import std/tables +import chagashi/decoder import html/catom import html/dom import html/event @@ -169,7 +170,8 @@ proc fireProgressEvent(window: Window; target: EventTarget; name: StaticAtom; # Forward declaration hack var windowFetch*: proc(window: Window; input: JSValue; - init = none(RequestInit)): JSResult[FetchPromise] {.nimcall.} = nil + init = RequestInit(window: JS_UNDEFINED)): JSResult[FetchPromise] + {.nimcall.} = nil proc errorSteps(window: Window; this: XMLHttpRequest; name: StaticAtom) = this.readyState = xhrsDone @@ -211,15 +213,16 @@ proc send(ctx: JSContext; this: XMLHttpRequest; body = JS_NULL): DOMResult[void] body = JS_NULL let request = newRequest(this.requestURL, this.requestMethod, this.headers) if not JS_IsNull(body): - let document = fromJS[Document](ctx, body) - if document.isSome: - #TODO replace surrogates - let document = document.get - request.body = RequestBody(t: rbtString, s: document.serializeFragment()) + var document: Document = nil + if ctx.fromJS(body, document).isSome: + request.body = RequestBody( + t: rbtString, + s: document.serializeFragment().toValidUTF8() # replace surrogates + ) #TODO else... if "Content-Type" in this.headers: request.headers["Content-Type"].setContentTypeAttr("charset", "UTF-8") - elif document.isSome: + elif document != nil: request.headers["Content-Type"] = "text/html;charset=UTF-8" let jsRequest = JSRequest( #TODO unsafe request flag, client, cors credentials mode, @@ -326,7 +329,8 @@ proc jsReflectSet(ctx: JSContext; this, val: JSValue; magic: cint): JSValue {.cdecl.} = if JS_IsFunction(ctx, val): let atom = ReflectMap[magic] - let target = fromJS[EventTarget](ctx, this).get + var target: EventTarget + assert ctx.fromJS(this, target).isSome ctx.definePropertyC(this, "on" & $atom, JS_DupValue(ctx, val)) #TODO I haven't checked but this might also be wrong doAssert ctx.addEventListener(target, ctx.toAtom(atom), val).isSome diff --git a/src/io/bufwriter.nim b/src/io/bufwriter.nim index 437fa24f..241d77cc 100644 --- a/src/io/bufwriter.nim +++ b/src/io/bufwriter.nim @@ -21,11 +21,10 @@ type BufferedWriter* = object bufLen: int sendAux: seq[FileHandle] -{.warning[Deprecated]: off.}: - proc `=destroy`(writer: var BufferedWriter) = - if writer.buffer != nil: - dealloc(writer.buffer) - writer.buffer = nil +proc `=destroy`(writer: var BufferedWriter) = + if writer.buffer != nil: + dealloc(writer.buffer) + writer.buffer = nil proc swrite*(writer: var BufferedWriter; n: SomeNumber) proc swrite*[T](writer: var BufferedWriter; s: set[T]) diff --git a/src/io/promise.nim b/src/io/promise.nim index 41ccceb4..3c01e214 100644 --- a/src/io/promise.nim +++ b/src/io/promise.nim @@ -1,7 +1,6 @@ import std/tables import monoucha/quickjs -import monoucha/jserror import monoucha/javascript import monoucha/jsutils import monoucha/jsopaque @@ -201,24 +200,27 @@ proc promiseThenCallback(ctx: JSContext; this_val: JSValue; argc: cint; JS_SetOpaque(fun, nil) return JS_UNDEFINED -proc fromJSEmptyPromise*(ctx: JSContext; val: JSValue): JSResult[EmptyPromise] = +proc fromJS*(ctx: JSContext; val: JSValue; res: var EmptyPromise): Opt[void] = if not JS_IsObject(val): - return errTypeError("Value is not an object") - var p = EmptyPromise() - GC_ref(p) + JS_ThrowTypeError(ctx, "value is not an object") + return err() + res = EmptyPromise() + GC_ref(res) let tmp = JS_NewObject(ctx) - JS_SetOpaque(tmp, cast[pointer](p)) + JS_SetOpaque(tmp, cast[pointer](res)) 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, + let val = JS_Invoke(ctx, val, ctx.getOpaque().strRefs[jstThen], 1, fun.toJSValueArray()) JS_FreeValue(ctx, fun) - if JS_IsException(res): - JS_FreeValue(ctx, res) + if JS_IsException(val): + JS_FreeValue(ctx, val) + GC_unref(res) + res = nil return err() - JS_FreeValue(ctx, res) - return ok(p) + JS_FreeValue(ctx, val) + return ok() proc toJS*(ctx: JSContext; promise: EmptyPromise): JSValue = if promise == nil: diff --git a/src/js/console.nim b/src/js/console.nim index b61dedf7..755910a5 100644 --- a/src/js/console.nim +++ b/src/js/console.nim @@ -1,7 +1,6 @@ import io/dynstream import monoucha/fromjs import monoucha/javascript -import monoucha/jserror import types/opt type Console* = ref object @@ -33,11 +32,13 @@ proc log*(console: Console; ss: varargs[string]) = proc error*(console: Console; ss: varargs[string]) = console.log(ss) -proc log*(ctx: JSContext; console: Console; ss: varargs[JSValue]): - JSResult[void] {.jsfunc.} = +proc log*(ctx: JSContext; console: Console; ss: varargs[JSValue]): Opt[void] + {.jsfunc.} = var buf = "" for i, val in ss: - buf &= ?fromJS[string](ctx, val) + var res: string + ?ctx.fromJS(val, res) + buf &= res if i != ss.high: buf &= ' ' buf &= '\n' @@ -49,20 +50,20 @@ proc clear(console: Console) {.jsfunc.} = console.clearFun() # For now, these are the same as log(). -proc debug(ctx: JSContext; console: Console; ss: varargs[JSValue]): - JSResult[void] {.jsfunc.} = +proc debug(ctx: JSContext; console: Console; ss: varargs[JSValue]): Opt[void] + {.jsfunc.} = return log(ctx, console, ss) -proc error(ctx: JSContext; console: Console; ss: varargs[JSValue]): - JSResult[void] {.jsfunc.} = +proc error(ctx: JSContext; console: Console; ss: varargs[JSValue]): Opt[void] + {.jsfunc.} = return log(ctx, console, ss) -proc info(ctx: JSContext; console: Console; ss: varargs[JSValue]): - JSResult[void] {.jsfunc.} = +proc info(ctx: JSContext; console: Console; ss: varargs[JSValue]): Opt[void] + {.jsfunc.} = return log(ctx, console, ss) -proc warn(ctx: JSContext; console: Console; ss: varargs[JSValue]): - JSResult[void] {.jsfunc.} = +proc warn(ctx: JSContext; console: Console; ss: varargs[JSValue]): Opt[void] + {.jsfunc.} = return log(ctx, console, ss) proc show(console: Console) {.jsfunc.} = @@ -81,7 +82,3 @@ proc addConsoleModule*(ctx: JSContext) = 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 1fab7ed9..d07e88f4 100644 --- a/src/js/domexception.nim +++ b/src/js/domexception.nim @@ -1,5 +1,3 @@ -import std/tables - import monoucha/javascript import monoucha/jserror import monoucha/quickjs diff --git a/src/js/encoding.nim b/src/js/encoding.nim index 2394cc6c..7d1bd126 100644 --- a/src/js/encoding.nim +++ b/src/js/encoding.nim @@ -13,7 +13,7 @@ type encoding: Charset ignoreBOM {.jsget.}: bool errorMode: DecoderErrorMode - doNotFlush: bool + stream: bool bomSeen: bool tdctx: TextDecoderContext @@ -21,10 +21,10 @@ jsDestructor(JSTextDecoder) jsDestructor(JSTextEncoder) type TextDecoderOptions = object of JSDict - fatal: bool - ignoreBOM: bool + fatal {.jsdefault.}: bool + ignoreBOM {.jsdefault.}: bool -func newJSTextDecoder(label = "utf-8", options = TextDecoderOptions()): +func newJSTextDecoder(label = "utf-8"; options = TextDecoderOptions()): JSResult[JSTextDecoder] {.jsctor.} = let encoding = getCharset(label) if encoding in {CHARSET_UNKNOWN, CHARSET_REPLACEMENT}: @@ -52,17 +52,16 @@ proc decode0(this: JSTextDecoder; ctx: JSContext; input: JSArrayBufferView; return ok(JS_NewStringLen(ctx, cstring(oq), csize_t(oq.len))) type TextDecodeOptions = object of JSDict - stream: bool + stream {.jsdefault.}: bool #TODO AllowSharedBufferSource proc decode(ctx: JSContext; this: JSTextDecoder; input = none(JSArrayBufferView); options = TextDecodeOptions()): JSResult[JSValue] {.jsfunc.} = - if not this.doNotFlush: + if not this.stream: this.tdctx = initTextDecoderContext(this.encoding, this.errorMode) this.bomSeen = false - if this.doNotFlush != options.stream: - this.doNotFlush = options.stream + this.stream = options.stream if input.isSome: return this.decode0(ctx, input.get, options.stream) return ok(JS_NewString(ctx, "")) diff --git a/src/js/jscolor.nim b/src/js/jscolor.nim index 8491e778..fef9c8aa 100644 --- a/src/js/jscolor.nim +++ b/src/js/jscolor.nim @@ -2,7 +2,6 @@ import std/strutils import monoucha/fromjs import monoucha/javascript -import monoucha/jserror import monoucha/quickjs import monoucha/tojs import types/color @@ -10,12 +9,12 @@ import types/opt import utils/charcategory import utils/twtstr -func parseLegacyColor*(s: string): JSResult[RGBColor] = +func parseLegacyColor*(s: string): Result[RGBColor, cstring] = if s == "": - return errTypeError("Color value must not be the empty string") + return err(cstring"color value must not be the empty string") let s = s.strip(chars = AsciiWhitespace).toLowerAscii() if s == "transparent": - return errTypeError("Color must not be transparent") + return err(cstring"color must not be transparent") return ok(parseLegacyColor0(s)) proc toJS*(ctx: JSContext; rgb: RGBColor): JSValue = @@ -25,8 +24,15 @@ proc toJS*(ctx: JSContext; rgb: RGBColor): JSValue = res.pushHex(rgb.b) return toJS(ctx, res) -proc fromJSRGBColor*(ctx: JSContext; val: JSValue): JSResult[RGBColor] = - return parseLegacyColor(?fromJS[string](ctx, val)) +proc fromJS*(ctx: JSContext; val: JSValue; res: var RGBColor): Err[void] = + var s: string + ?ctx.fromJS(val, s) + let x = parseLegacyColor(s) + if x.isNone: + JS_ThrowTypeError(ctx, x.error) + return err() + res = x.get + return ok() proc toJS*(ctx: JSContext; rgba: ARGBColor): JSValue = var res = "#" @@ -36,12 +42,16 @@ proc toJS*(ctx: JSContext; rgba: ARGBColor): JSValue = res.pushHex(rgba.a) return toJS(ctx, res) -proc fromJSARGBColor*(ctx: JSContext; val: JSValue): JSResult[ARGBColor] = +proc fromJS*(ctx: JSContext; val: JSValue; res: var ARGBColor): Err[void] = if JS_IsNumber(val): # as hex - return ok(ARGBColor(?fromJS[uint32](ctx, val))) + ?ctx.fromJS(val, uint32(res)) + return ok() # parse - let x = parseARGBColor(?fromJS[string](ctx, val)) - if x.isSome: - return ok(x.get) - return errTypeError("Unrecognized color") + var s: string + ?ctx.fromJS(val, s) + if (let x = parseARGBColor(s); x.isSome): + res = x.get + return ok() + JS_ThrowTypeError(ctx, "unrecognized color") + return err() diff --git a/src/js/timeout.nim b/src/js/timeout.nim index f8b8ed8a..0213156a 100644 --- a/src/js/timeout.nim +++ b/src/js/timeout.nim @@ -75,9 +75,9 @@ proc runEntry(state: var TimeoutState; entry: TimeoutEntry; name: string) = state.jsctx.writeException(state.err) JS_FreeValue(state.jsctx, ret) else: - let s = fromJS[string](state.jsctx, entry.val) - if s.isSome: - state.evalJSFree(s.get, name) + var s: string + if state.jsctx.fromJS(entry.val, s).isSome: + state.evalJSFree(s, name) proc runTimeoutFd*(state: var TimeoutState; fd: int): bool = if fd notin state.timeoutFds: diff --git a/src/loader/headers.nim b/src/loader/headers.nim index bed8f8e8..6b598cc2 100644 --- a/src/loader/headers.nim +++ b/src/loader/headers.nim @@ -34,21 +34,23 @@ jsDestructor(Headers) const HTTPWhitespace = {'\n', '\r', '\t', ' '} -proc fromJSHeadersInit(ctx: JSContext; val: JSValue): JSResult[HeadersInit] = +proc fromJS(ctx: JSContext; val: JSValue; res: var HeadersInit): Err[void] = if JS_IsUndefined(val) or JS_IsNull(val): - return err(nil) - if (let x = fromJS[Headers](ctx, val); x.isSome): - var s: seq[(string, string)] = @[] - for k, v in x.get.table: + return err() + var headers: Headers + if ctx.fromJS(val, headers).isSome: + res = HeadersInit(t: hitSequence, s: @[]) + for k, v in headers.table: for vv in v: - s.add((k, vv)) - return ok(HeadersInit(t: hitSequence, s: s)) + res.s.add((k, vv)) + return ok() if ctx.isSequence(val): - let x = fromJS[seq[(string, string)]](ctx, val) - if x.isSome: - return ok(HeadersInit(t: hitSequence, s: x.get)) - let x = ?fromJS[Table[string, string]](ctx, val) - return ok(HeadersInit(t: hitTable, tab: x)) + res = HeadersInit(t: hitSequence) + if ctx.fromJS(val, res.s).isSome: + return ok() + res = HeadersInit(t: hitTable) + ?ctx.fromJS(val, res.tab) + return ok() const TokenChars = { '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~' diff --git a/src/loader/loaderhandle.nim b/src/loader/loaderhandle.nim index cb05efa1..11c33606 100644 --- a/src/loader/loaderhandle.nim +++ b/src/loader/loaderhandle.nim @@ -56,11 +56,10 @@ type when defined(debug): url*: URL -{.warning[Deprecated]:off.}: - proc `=destroy`(buffer: var LoaderBufferObj) = - if buffer.page != nil: - dealloc(buffer.page) - buffer.page = nil +proc `=destroy`(buffer: var LoaderBufferObj) = + if buffer.page != nil: + dealloc(buffer.page) + buffer.page = nil # for debugging when defined(debug): diff --git a/src/loader/request.nim b/src/loader/request.nim index 23be8ba8..2af5dcf3 100644 --- a/src/loader/request.nim +++ b/src/loader/request.nim @@ -161,44 +161,36 @@ type str: string RequestInit* = object of JSDict - #TODO aliasing in dicts - `method`: HttpMethod # default: GET - headers: Option[HeadersInit] - body: Option[BodyInit] - referrer: Option[string] - referrerPolicy: Option[ReferrerPolicy] - credentials: Option[CredentialsMode] - mode: Option[RequestMode] - window: Option[JSValue] + `method`* {.jsdefault.}: Option[HttpMethod] #TODO aliasing in dicts + headers* {.jsdefault.}: Option[HeadersInit] + body* {.jsdefault.}: Option[BodyInit] + referrer* {.jsdefault.}: Option[string] + referrerPolicy* {.jsdefault.}: Option[ReferrerPolicy] + credentials* {.jsdefault.}: Option[CredentialsMode] + mode* {.jsdefault.}: Option[RequestMode] + window* {.jsdefault: JS_UNDEFINED.}: JSValue -proc fromJSBodyInit(ctx: JSContext; val: JSValue): JSResult[BodyInit] = - if JS_IsUndefined(val) or JS_IsNull(val): - return err(nil) - block formData: - let x = fromJS[FormData](ctx, val) - if x.isSome: - return ok(BodyInit(t: bitFormData, formData: x.get)) - block blob: - let x = fromJS[Blob](ctx, val) - if x.isSome: - return ok(BodyInit(t: bitBlob, blob: x.get)) - block searchParams: - let x = fromJS[URLSearchParams](ctx, val) - if x.isSome: - return ok(BodyInit(t: bitUrlSearchParams, searchParams: x.get)) - block str: - let x = fromJS[string](ctx, val) - if x.isSome: - return ok(BodyInit(t: bitString, str: x.get)) - return errTypeError("Invalid body init type") +proc fromJS(ctx: JSContext; val: JSValue; res: var BodyInit): Opt[void] = + if not JS_IsUndefined(val) and not JS_IsNull(val): + res = BodyInit(t: bitFormData) + if ctx.fromJS(val, res.formData).isSome: + return ok() + res = BodyInit(t: bitBlob) + if ctx.fromJS(val, res.blob).isSome: + return ok() + res = BodyInit(t: bitUrlSearchParams) + if ctx.fromJS(val, res.searchParams).isSome: + return ok() + res = BodyInit(t: bitString) + if ctx.fromJS(val, res.str).isSome: + return ok() + JS_ThrowTypeError(ctx, "invalid body init type") + return err() var getAPIBaseURLImpl*: proc(ctx: JSContext): URL {.noSideEffect, nimcall.} -proc newRequest*(ctx: JSContext; resource: JSValue; init = none(RequestInit)): - JSResult[JSRequest] {.jsctor.} = - defer: - if init.isSome and init.get.window.isSome: - JS_FreeValue(ctx, init.get.window.get) +proc newRequest*(ctx: JSContext; resource: JSValue; + init = RequestInit(window: JS_UNDEFINED)): JSResult[JSRequest] {.jsctor.} = let headers = newHeaders(hgRequest) var fallbackMode = opt(rmCors) var window = RequestWindow(t: rwtClient) @@ -207,51 +199,50 @@ proc newRequest*(ctx: JSContext; resource: JSValue; init = none(RequestInit)): var httpMethod = hmGet var referrer: URL = nil var url: URL = nil - if JS_IsString(resource): - let s = ?fromJS[string](ctx, resource) - url = ?parseJSURL(s, option(ctx.getAPIBaseURLImpl())) - else: - let resource = ?fromJS[JSRequest](ctx, resource) - url = resource.url - httpMethod = resource.request.httpMethod - headers.table = resource.headers.table - referrer = resource.request.referrer - credentials = resource.credentialsMode - body = resource.request.body + if (var res: JSRequest; ctx.fromJS(resource, res).isSome): + url = res.url + httpMethod = res.request.httpMethod + headers.table = res.headers.table + referrer = res.request.referrer + credentials = res.credentialsMode + body = res.request.body fallbackMode = opt(RequestMode) - window = resource.window + window = res.window + else: + var s: string + ?ctx.fromJS(resource, s) + url = ?parseJSURL(s, option(ctx.getAPIBaseURLImpl())) if url.username != "" or url.password != "": return errTypeError("Input URL contains a username or password") var mode = fallbackMode.get(rmNoCors) let destination = rdNone #TODO origin, window - if init.isSome: #TODO spec wants us to check if it's "not empty"... - let init = init.get - if init.window.isSome: - if not JS_IsNull(init.window.get): - return errTypeError("Expected window to be null") - window = RequestWindow(t: rwtNoWindow) - if mode == rmNavigate: - mode = rmSameOrigin - #TODO flags? - #TODO referrer - httpMethod = init.`method` - if init.body.isSome: - let ibody = init.body.get - case ibody.t - of bitFormData: - body = RequestBody(t: rbtMultipart, multipart: ibody.formData) - of bitString: - body = RequestBody(t: rbtString, s: ibody.str) - else: discard #TODO - if httpMethod in {hmGet, hmHead}: - return errTypeError("HEAD or GET Request cannot have a body.") - if init.headers.isSome: - ?headers.fill(init.headers.get) - if init.credentials.isSome: - credentials = init.credentials.get - if init.mode.isSome: - mode = init.mode.get + if not JS_IsUndefined(init.window): + if not JS_IsNull(init.window): + return errTypeError("Expected window to be null") + window = RequestWindow(t: rwtNoWindow) + if mode == rmNavigate: + mode = rmSameOrigin + #TODO flags? + #TODO referrer + if init.`method`.isSome: + httpMethod = init.`method`.get + if init.body.isSome: + let ibody = init.body.get + case ibody.t + of bitFormData: + body = RequestBody(t: rbtMultipart, multipart: ibody.formData) + of bitString: + body = RequestBody(t: rbtString, s: ibody.str) + else: discard #TODO + if httpMethod in {hmGet, hmHead}: + return errTypeError("HEAD or GET Request cannot have a body.") + if init.headers.isSome: + ?headers.fill(init.headers.get) + if init.credentials.isSome: + credentials = init.credentials.get + if init.mode.isSome: + mode = init.mode.get if mode == rmNoCors: headers.guard = hgRequestNoCors return ok(JSRequest( diff --git a/src/local/client.nim b/src/local/client.nim index f63668d2..d3fd9ebe 100644 --- a/src/local/client.nim +++ b/src/local/client.nim @@ -148,9 +148,9 @@ proc command0(client: Client; src: string; filename = "<command>"; client.jsctx.writeException(client.console.err) else: if not silence: - let str = fromJS[string](client.jsctx, ret) - if str.isSome: - client.console.log(str.get) + var res: string + if client.jsctx.fromJS(ret, res).isSome: + client.console.log(res) JS_FreeValue(client.jsctx, ret) proc command(client: Client; src: string) = @@ -207,9 +207,9 @@ proc evalAction(client: Client; action: string; arg0: int32): EmptyPromise = if JS_IsException(ret): client.jsctx.writeException(client.console.err) elif JS_IsObject(ret): - let maybep = fromJSEmptyPromise(ctx, ret) - if maybep.isSome: - p = maybep.get + var maybep: EmptyPromise + if ctx.fromJS(ret, maybep).isSome: + p = maybep JS_FreeValue(ctx, ret) return p diff --git a/src/local/container.nim b/src/local/container.nim index 8a057885..108c631e 100644 --- a/src/local/container.nim +++ b/src/local/container.nim @@ -1583,7 +1583,7 @@ proc cursorPrevMatch*(container: Container; regex: Regex; wrap, refresh: bool; type SelectionOptions = object of JSDict - selectionType: SelectionType + selectionType {.jsdefault.}: SelectionType proc cursorToggleSelection(container: Container; n = 1; opts = SelectionOptions()): Highlight {.jsfunc.} = diff --git a/src/local/pager.nim b/src/local/pager.nim index 44237da8..79fe0e79 100644 --- a/src/local/pager.nim +++ b/src/local/pager.nim @@ -1152,13 +1152,13 @@ proc applySiteconf(pager: Pager; url: var URL; charsetOverride: Charset; let fun = sc.rewrite_url.get var arg0 = ctx.toJS(url) let ret = JS_Call(ctx, fun, JS_UNDEFINED, 1, arg0.toJSValueArray()) - let nu = fromJS[URL](ctx, ret) - if nu.isSome: - if nu.get != nil: - url = nu.get - elif JS_IsException(ret): + var nu: URL + if ctx.fromJS(ret, nu).isSome: + if nu != nil: + url = nu + else: #TODO should writeException the message to console - pager.alert("Error rewriting URL: " & ctx.getExceptionMsg(nu.error)) + pager.alert("Error rewriting URL: " & ctx.getExceptionMsg()) JS_FreeValue(ctx, arg0) JS_FreeValue(ctx, ret) if sc.cookie.isSome: @@ -1254,13 +1254,13 @@ proc omniRewrite(pager: Pager; s: string): string = let ctx = pager.jsctx var arg0 = ctx.toJS(s) let jsRet = JS_Call(ctx, fun, JS_UNDEFINED, 1, arg0.toJSValueArray()) - let ret = fromJS[string](ctx, jsRet) - JS_FreeValue(ctx, jsRet) - JS_FreeValue(ctx, arg0) - if ret.isSome: - return ret.get + defer: JS_FreeValue(ctx, jsRet) + defer: JS_FreeValue(ctx, arg0) + var res: string + if ctx.fromJS(jsRet, res).isSome: + return res pager.alert("Error in substitution of " & $rule.match & " for " & s & - ": " & ctx.getExceptionMsg(ret.error)) + ": " & ctx.getExceptionMsg()) return s # When the user has passed a partial URL as an argument, they might've meant @@ -1480,18 +1480,22 @@ proc load(pager: Pager; s = "") {.jsfunc.} = # Go to specific URL (for JS) type GotoURLDict = object of JSDict - contentType: Option[string] - replace: Container + contentType {.jsdefault.}: Option[string] + replace {.jsdefault.}: Container proc jsGotoURL(pager: Pager; v: JSValue; t = GotoURLDict()): JSResult[void] {.jsfunc: "gotoURL".} = - let request = if (let x = fromJS[JSRequest](pager.jsctx, v); x.isSome): - x.get.request - elif (let x = fromJS[URL](pager.jsctx, v); x.isSome): - newRequest(x.get) + var request: Request = nil + var jsRequest: JSRequest = nil + if pager.jsctx.fromJS(v, jsRequest).isSome: + request = jsRequest.request else: - let s = ?fromJS[string](pager.jsctx, v) - newRequest(?newURL(s)) + var url: URL = nil + if pager.jsctx.fromJS(v, url).isNone: + var s: string + ?pager.jsctx.fromJS(v, s) + url = ?newURL(s) + request = newRequest(url) discard pager.gotoURL(request, contentType = t.contentType, replace = t.replace) return ok() @@ -1508,27 +1512,27 @@ proc setEnvVars(pager: Pager) {.jsfunc.} = except OSError: pager.alert("Warning: failed to set some environment variables") -#TODO use default values instead... type ExternDict = object of JSDict - setenv: Option[bool] - suspend: Option[bool] - wait: bool + setenv {.jsdefault: true.}: bool + suspend {.jsdefault: true.}: bool + wait {.jsdefault: false.}: bool #TODO we should have versions with retval as int? -proc extern(pager: Pager; cmd: string; t = ExternDict()): bool {.jsfunc.} = - if t.setenv.get(true): +proc extern(pager: Pager; cmd: string; + t = ExternDict(setenv: true, suspend: true)): bool {.jsfunc.} = + if t.setenv: pager.setEnvVars() - if t.suspend.get(true): + if t.suspend: return runProcess(pager.term, cmd, t.wait) else: return runProcess(cmd) -proc externCapture(pager: Pager; cmd: string): Opt[string] {.jsfunc.} = +proc externCapture(pager: Pager; cmd: string): Option[string] {.jsfunc.} = pager.setEnvVars() var s: string if not runProcessCapture(cmd, s): - return err() - return ok(s) + return none(string) + return some(s) proc externInto(pager: Pager; cmd, ins: string): bool {.jsfunc.} = pager.setEnvVars() diff --git a/src/server/buffer.nim b/src/server/buffer.nim index a1e273cc..7abac9e1 100644 --- a/src/server/buffer.nim +++ b/src/server/buffer.nim @@ -1426,10 +1426,11 @@ proc evalJSURL(buffer: Buffer; url: URL): Opt[string] = return err() # error if JS_IsUndefined(ret): return err() # no need to navigate - let s = ?fromJS[string](ctx, ret) + var res: string + ?ctx.fromJS(ret, res) JS_FreeValue(ctx, ret) # Navigate to result. - return ok(s) + return ok(res) proc click(buffer: Buffer; anchor: HTMLAnchorElement): ClickResult = var repaint = buffer.restoreFocus() diff --git a/src/types/blob.nim b/src/types/blob.nim index fb0bd92a..acffedf8 100644 --- a/src/types/blob.nim +++ b/src/types/blob.nim @@ -52,7 +52,7 @@ proc newWebFile*(name: string; fd: FileHandle): WebFile = type BlobPropertyBag = object of JSDict - `type`: string + `type` {.jsdefault.}: string #TODO endings FilePropertyBag = object of BlobPropertyBag diff --git a/src/types/url.nim b/src/types/url.nim index 23485602..7ecc9531 100644 --- a/src/types/url.nim +++ b/src/types/url.nim @@ -1060,11 +1060,12 @@ proc newURL*(url: URL): URL = result = URL() url.cloneInto(result) -proc setHref(url: URL; s: string): Err[JSError] {.jsfset: "href".} = +proc setHref(ctx: JSContext; url: URL; s: string) {.jsfset: "href".} = let purl = basicParseURL(s) - if purl.isNone: - return errTypeError(s & " is not a valid URL") - purl.get.cloneInto(url) + if purl.isSome: + purl.get.cloneInto(url) + else: + JS_ThrowTypeError(ctx, "%s is not a valid URL", s) func isIP*(url: URL): bool = return url.host.t in {htIpv4, htIpv6} diff --git a/src/utils/luwrap.nim b/src/utils/luwrap.nim index 926cf0c0..6081cdf8 100644 --- a/src/utils/luwrap.nim +++ b/src/utils/luwrap.nim @@ -94,12 +94,11 @@ type LUContext* = ref LUContextObj -{.warning[Deprecated]: off.}: - proc `=destroy`*(ctx: var LUContextObj) = - for lur, cr in ctx.crs.mpairs: - if lur in ctx.inited: - cr_free(addr cr) - ctx.inited = {} +proc `=destroy`*(ctx: var LUContextObj) = + for lur, cr in ctx.crs.mpairs: + if lur in ctx.inited: + cr_free(addr cr) + ctx.inited = {} proc initGeneralCategory(ctx: LUContext; lur: LURangeType) = if lur notin ctx.inited: diff --git a/src/version.nim b/src/version.nim index 8de8caea..2593a9c4 100644 --- a/src/version.nim +++ b/src/version.nim @@ -29,4 +29,4 @@ tryImport monoucha/version, "monoucha" static: checkVersion("chagashi", 0, 5, 4) checkVersion("chame", 1, 0, 1) - checkVersion("monoucha", 0, 2, 3) + checkVersion("monoucha", 0, 3, 0) |