diff --git a/happyx.nimble b/happyx.nimble index 5dfb2aac..eb9d955a 100755 --- a/happyx.nimble +++ b/happyx.nimble @@ -2,7 +2,7 @@ description = "Macro-oriented asynchronous web-framework written with ♥" author = "HapticX" -version = "4.4.4" +version = "4.5.0" license = "MIT" srcDir = "src" installExt = @["nim"] diff --git a/src/happyx/core/constants.nim b/src/happyx/core/constants.nim index ed8b4498..7e27d476 100755 --- a/src/happyx/core/constants.nim +++ b/src/happyx/core/constants.nim @@ -98,8 +98,8 @@ const nim_2_0_0* = (NimMajor, NimMinor, NimPatch) >= (2, 0, 0) # Framework version HpxMajor* = 4 - HpxMinor* = 4 - HpxPatch* = 4 + HpxMinor* = 5 + HpxPatch* = 0 HpxVersion* = $HpxMajor & "." & $HpxMinor & "." & $HpxPatch diff --git a/src/happyx/private/macro_utils.nim b/src/happyx/private/macro_utils.nim index e163d3fa..3297b065 100644 --- a/src/happyx/private/macro_utils.nim +++ b/src/happyx/private/macro_utils.nim @@ -142,6 +142,18 @@ proc formatNode*(node: NimNode): NimNode = node +proc liveviewParam*(name: string): NimNode = + newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( + newCall("declared", ident(name)), + ident(name) + ), newNimNode(nnkElifBranch).add( + newCall("declared", newDotExpr(ident"self", ident(name))), + newDotExpr(ident"self", ident(name)) + ), newNimNode(nnkElse).add( + newLit"" + )) + + proc useComponent*(statement: NimNode, inCycle, inComponent: bool, cycleTmpVar: string, compTmpVar: NimNode, cycleVars: var seq[NimNode], returnTagRef: bool = true, constructor: bool = false, @@ -229,69 +241,13 @@ proc useComponent*(statement: NimNode, inCycle, inComponent: bool, objConstr.add(stringId) when not defined(js) and enableLiveViews: objConstr.add( - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"urlPath"), - ident"urlPath" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"urlPath")), - newDotExpr(ident"self", ident"urlPath") - ), newNimNode(nnkElse).add( - newLit"" - )), - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"hostname"), - ident"hostname" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"hostname")), - newDotExpr(ident"self", ident"hostname") - ), newNimNode(nnkElse).add( - newLit"" - )), - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"query"), - ident"query" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"query")), - newDotExpr(ident"self", ident"query") - ), newNimNode(nnkElse).add( - newLit"" - )), - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"queryArr"), - ident"queryArr" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"queryArr")), - newDotExpr(ident"self", ident"queryArr") - ), newNimNode(nnkElse).add( - newLit"" - )), - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"reqMethod"), - ident"reqMethod" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"reqMethod")), - newDotExpr(ident"self", ident"reqMethod") - ), newNimNode(nnkElse).add( - newLit"" - )), - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"inCookies"), - ident"inCookies" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"inCookies")), - newDotExpr(ident"self", ident"inCookies") - ), newNimNode(nnkElse).add( - newLit"" - )), - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"headers"), - ident"headers" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"headers")), - newDotExpr(ident"self", ident"headers") - ), newNimNode(nnkElse).add( - newLit"" - )), + liveviewParam("urlPath"), + liveviewParam("hostname"), + liveviewParam("query"), + liveviewParam("queryArr"), + liveviewParam("reqMethod"), + liveviewParam("inCookies"), + liveviewParam("headers"), ) if statement[1].kind == nnkCall: for i in 1.. 1: + nextRouteDecorators.add(body[idx].copy()) + elif body[idx].kind == nnkCommand and body[idx][0] == ident"mount": if body[idx][1].kind == nnkInfix and body[idx][1][0] == ident"->": # handle mount let @@ -63,10 +76,16 @@ proc findAndReplaceMount*(body: NimNode) = elif statement[1].kind in [nnkStrLit, nnkTripleStrLit]: statement[1] = newLit($route & $statement[1]) # Add mount routes + for decorator in nextRouteDecorators: + inc offset + body.insert(i, decorator) if (statement.kind in [nnkCall, nnkCommand] and $statement[0] != "mount") or (statement.kind == nnkPrefix and $statement[0] == "@"): inc offset body.insert(i, statement) + nextRouteDecorators = @[] + else: + nextRouteDecorators = @[] macro mount*(mountName, body: untyped): untyped = diff --git a/src/happyx/spa/components.nim b/src/happyx/spa/components.nim index fb4f31ee..1d528fb7 100644 --- a/src/happyx/spa/components.nim +++ b/src/happyx/spa/components.nim @@ -390,81 +390,25 @@ macro component*(name, body: untyped): untyped = initObjConstr.add( newColonExpr( ident"urlPath", - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"urlPath"), - ident"urlPath" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"urlPath")), - newDotExpr(ident"self", ident"urlPath") - ), newNimNode(nnkElse).add( - newLit"" - )) + liveviewParam("urlPath") ), newColonExpr( ident"hostname", - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"hostname"), - ident"hostname" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"hostname")), - newDotExpr(ident"self", ident"hostname") - ), newNimNode(nnkElse).add( - newLit"" - )) + liveviewParam("hostname") ), newColonExpr( ident"query", - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"query"), - ident"query" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"query")), - newDotExpr(ident"self", ident"query") - ), newNimNode(nnkElse).add( - newLit"" - )) + liveviewParam("query") ), newColonExpr( ident"queryArr", - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"queryArr"), - ident"queryArr" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"queryArr")), - newDotExpr(ident"self", ident"queryArr") - ), newNimNode(nnkElse).add( - newLit"" - )) + liveviewParam("queryArr") ), newColonExpr( ident"reqMethod", - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"reqMethod"), - ident"reqMethod" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"reqMethod")), - newDotExpr(ident"self", ident"reqMethod") - ), newNimNode(nnkElse).add( - newLit"" - )) + liveviewParam("reqMethod") ), newColonExpr( ident"inCookies", - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"inCookies"), - ident"inCookies" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"inCookies")), - newDotExpr(ident"self", ident"inCookies") - ), newNimNode(nnkElse).add( - newLit"" - )) + liveviewParam("inCookies") ), newColonExpr( ident"headers", - newNimNode(nnkWhenStmt).add(newNimNode(nnkElifBranch).add( - newCall("declared", ident"headers"), - ident"headers" - ), newNimNode(nnkElifBranch).add( - newCall("declared", newDotExpr(ident"self", ident"headers")), - newDotExpr(ident"self", ident"headers") - ), newNimNode(nnkElse).add( - newLit"" - )) + liveviewParam("headers") ), ) initProc[2] = generics.copy() diff --git a/src/happyx/spa/renderer.nim b/src/happyx/spa/renderer.nim index 27f38f62..61468ea4 100644 --- a/src/happyx/spa/renderer.nim +++ b/src/happyx/spa/renderer.nim @@ -149,8 +149,10 @@ when enableDefaultComponents: var components* = newTable[cstring, BaseComponent]() else: var - requestResult* = newTable[string, string]() - componentsResult* = newTable[string, string]() + requestResult* {.threadvar.}: TableRef[string, string] + componentsResult* {.threadvar.}: TableRef[string, string] + requestResult = newTable[string, string]() + componentsResult = newTable[string, string]() when defined(js): @@ -213,12 +215,13 @@ else: requestResult[host] = "route:" & path proc injectJs*(host, script: string) = requestResult[host] = "script:" & fmt"" + proc js*(host, script: string) = + requestResult[host] = "script:" & fmt"" proc route*(comp: BaseComponent, path: string) = componentsResult[comp.uniqCompId] = "route:" & path proc js*(comp: BaseComponent, script: string) = componentsResult[comp.uniqCompId] = "script:" & fmt"" proc rerender*(query, queryArr, reqMethod, inCookies, headers: auto, hostname, urlPath: string) = - echo "rerender for " & hostname requestResult[hostname] = "rerender:" & liveviewRoutes[urlPath]( query, queryArr, reqMethod, inCookies, headers, nil ).children[1].ugly() diff --git a/src/happyx/spa/tag.nim b/src/happyx/spa/tag.nim index c0385f21..a2b23eee 100644 --- a/src/happyx/spa/tag.nim +++ b/src/happyx/spa/tag.nim @@ -441,7 +441,10 @@ proc tagFromString*(source: string): TagRef {.inline.} = let xmlNode = parseHtml(source) result = initTag("div", @[], true) result.xmlTree2Tag(nil, xmlNode) - result = result.children[0].children[0].TagRef + when defined(js): + result = result.children[0].children[0].TagRef + else: + result = result.children[0].children[0] proc addArg*(self: TagRef, arg: string) = @@ -467,11 +470,13 @@ proc addArgIter*(self: TagRef, arg: string) = ## See also `addArg function #addArg,TagRef,string`_ when defined(js): self.setAttribute(cstring(arg), "") + for i in self.children: + i.TagRef.addArgIter(arg) else: if self.args.len == 0: self.args.add(arg) - for i in self.children: - i.TagRef.addArgIter(arg) + for i in self.children: + i.addArgIter(arg) proc toSeqIter*(self: TagRef): seq[TagRef] = @@ -485,7 +490,7 @@ proc toSeqIter*(self: TagRef): seq[TagRef] = result.add(i) else: for child in self.children: - for i in child.TagRef.toSeqIter: + for i in child.toSeqIter: result.add(i) return result @@ -506,7 +511,10 @@ func lvl*(self: TagRef): int = var tag = self when defined(js): while not tag.parentElement.isNil: - tag = tag.parentElement.TagRef + when defined(js): + tag = tag.parentElement.TagRef + else: + tag = tag.parentElement if not tag.onlyChildren: inc result else: @@ -527,7 +535,10 @@ func `[]`*(self: TagRef, attrName: string): string = func `[]`*(self: TagRef, index: int): TagRef = ## Returns tag by index - self.children[index].TagRef + when defined(js): + self.children[index].TagRef + else: + self.children[index] func `[]=`*(self: TagRef, attrName: string, attrValue: string) = diff --git a/src/happyx/ssr/form_data.nim b/src/happyx/ssr/form_data.nim index 8e5eb6b4..36309df6 100644 --- a/src/happyx/ssr/form_data.nim +++ b/src/happyx/ssr/form_data.nim @@ -37,9 +37,7 @@ type FormDataItem* = object proc parseFormData*(formData: string): (StringTableRef, TableRef[string, FormDataItem]) = ## Parses `form-data` into `StringTableRef` result = (newStringTable(), newTable[string, FormDataItem]()) - let - lineSeparator = "\r\n" - lines = formData.split("\r\n") + let lines = formData.split("\r\n") var key = "" data = "" diff --git a/src/happyx/ssr/request_models.nim b/src/happyx/ssr/request_models.nim index a1dada98..d6fadc72 100644 --- a/src/happyx/ssr/request_models.nim +++ b/src/happyx/ssr/request_models.nim @@ -84,7 +84,6 @@ import # stdlib std/macros, std/macrocache, - std/strtabs, std/strutils, std/strformat, # Happyx diff --git a/src/happyx/ssr/server.nim b/src/happyx/ssr/server.nim index 33ef571f..fc091e84 100755 --- a/src/happyx/ssr/server.nim +++ b/src/happyx/ssr/server.nim @@ -758,6 +758,9 @@ macro routes*(server: Server, body: untyped = newStmtList()): untyped = ), statement[2] )) nextRouteDecorators = @[] + # mount ... + elif statement.kind == nnkCommand and statement[0] == ident"mount" and statement[1].kind == nnkInfix and statement[1][0] == ident"->": + nextRouteDecorators = @[] # reqMethod "/...": # ... elif statement[0].kind == nnkIdent and statement[0] != ident"mount" and statement[1].kind in {nnkStrLit, nnkTripleStrLit, nnkInfix}: diff --git a/src/happyx/ssr/types.nim b/src/happyx/ssr/types.nim index 55f0b491..70017d9f 100644 --- a/src/happyx/ssr/types.nim +++ b/src/happyx/ssr/types.nim @@ -1,7 +1,7 @@ import std/logging, std/tables, - ../spa/[tag, renderer], + ../spa/renderer, ../core/constants when enableHttpx: diff --git a/src/happyx/ssr/websockets.nim b/src/happyx/ssr/websockets.nim index 51c5b6f4..2f5c5633 100644 --- a/src/happyx/ssr/websockets.nim +++ b/src/happyx/ssr/websockets.nim @@ -1,7 +1,10 @@ import std/macros, - ../core/constants, - ../private/macro_utils + ../core/constants + + +when enableHttpBeast: + import ../private/macro_utils proc handleWebsockets*(wsClosedConnection: NimNode): tuple[wsStmtList, insertWsList: NimNode] = diff --git a/tests/testc6.nim b/tests/testc6.nim index e92da8a2..989f2afc 100644 --- a/tests/testc6.nim +++ b/tests/testc6.nim @@ -26,10 +26,21 @@ decorator HelloWorld: statementList[0].del(statementList[0].len-1) +mount Test: + get "/": + echo 1 + + get "/test": + echo 1 + + serve("127.0.0.1", 5000): "/": return "Hello, world!" + @HelloWorld(1, 2, 3, req) + mount "/test" -> Test + @HelloWorld(1, 2, 3, req) "/test-deco": return "Hello, world!"