`;
+ }).join("");
+ """)
+}
diff --git a/docs/src/files/howtos/CORS.scala b/docs/src/files/howtos/CORS.scala
index 93a9ce8..36eb7f1 100644
--- a/docs/src/files/howtos/CORS.scala
+++ b/docs/src/files/howtos/CORS.scala
@@ -1,6 +1,6 @@
package files.howtos
-import utils.Bundle.*
+import utils.*
object CORS extends HowToPage {
@@ -21,10 +21,10 @@ object CORS extends HowToPage {
use the `withCorsSettings` method and set desired config:
```scala
import ba.sake.sharaf.handlers.cors.CorsSettings
- import ba.sake.sharaf.*, routing.*
+ import ba.sake.sharaf.*
val corsSettings = CorsSettings.default.withAllowedOrigins(Set("https://example.com"))
- SharafHandler(routes).withCorsSettings(corsSettings)...
+ UndertowSharafServer(routes).withCorsSettings(corsSettings)...
```
""".md
)
diff --git a/docs/src/files/howtos/ExceptionHandler.scala b/docs/src/files/howtos/ExceptionHandler.scala
index 93936ce..f0982da 100644
--- a/docs/src/files/howtos/ExceptionHandler.scala
+++ b/docs/src/files/howtos/ExceptionHandler.scala
@@ -1,6 +1,6 @@
package files.howtos
-import utils.Bundle.*
+import utils.*
object ExceptionHandler extends HowToPage {
@@ -15,16 +15,16 @@ object ExceptionHandler extends HowToPage {
"How to customize the Exception handler?",
s"""
- Use the `withExceptionMapper` on `SharafHandler`:
+ Use the `withExceptionMapper` on `UndertowSharafServer`:
```scala
val customExceptionMapper: ExceptionMapper = {
case e: MyException =>
val errorPage = MyErrorPage(e.getMessage())
Response.withBody(errorPage)
- .withStatus(StatusCodes.INTERNAL_SERVER_ERROR)
+ .withStatus(StatusCode.InternalServerError)
}
val finalExceptionMapper = customExceptionMapper.orElse(ExceptionMapper.default)
- val httpHandler = SharafHandler(routes)
+ val server = UndertowSharafServer(routes)
.withExceptionMapper(finalExceptionMapper)
```
diff --git a/docs/src/files/howtos/ExternalConfig.scala b/docs/src/files/howtos/ExternalConfig.scala
index 4651dd7..78b8ed8 100644
--- a/docs/src/files/howtos/ExternalConfig.scala
+++ b/docs/src/files/howtos/ExternalConfig.scala
@@ -1,7 +1,6 @@
package files.howtos
-import utils.Consts
-import utils.Bundle.*
+import utils.*
object ExternalConfig extends HowToPage {
diff --git a/docs/src/files/howtos/HowToPage.scala b/docs/src/files/howtos/HowToPage.scala
index 793b15b..cdcd395 100644
--- a/docs/src/files/howtos/HowToPage.scala
+++ b/docs/src/files/howtos/HowToPage.scala
@@ -1,9 +1,8 @@
package files.howtos
import utils.*
-import Bundle.*
-trait HowToPage extends DocPage {
+trait HowToPage extends utils.DocPage {
override def categoryPosts =
List(
@@ -21,5 +20,5 @@ trait HowToPage extends DocPage {
override def pageCategory = Some("How-Tos")
- override def navbar = Some(Navbar.withActiveUrl(Index.ref))
+ override def currentCategoryPage = Some(Index)
}
diff --git a/docs/src/files/howtos/Index.scala b/docs/src/files/howtos/Index.scala
index fbea058..27c8e5f 100644
--- a/docs/src/files/howtos/Index.scala
+++ b/docs/src/files/howtos/Index.scala
@@ -1,7 +1,6 @@
package files.howtos
-import utils.Bundle.*
-import utils.Consts
+import utils.*
object Index extends HowToPage {
diff --git a/docs/src/files/howtos/NotFound.scala b/docs/src/files/howtos/NotFound.scala
index ed1f82f..a8ffa30 100644
--- a/docs/src/files/howtos/NotFound.scala
+++ b/docs/src/files/howtos/NotFound.scala
@@ -1,6 +1,6 @@
package files.howtos
-import utils.Bundle.*
+import utils.*
object NotFound extends HowToPage {
@@ -15,11 +15,11 @@ object NotFound extends HowToPage {
"How to customize 404 NotFound handler?",
s"""
- Use the `withNotFoundHandler` on `SharafHandler`:
+ Use the `withNotFoundHandler` on `UndertowSharafServer`:
```scala
- SharafHandler(routes).withNotFoundHandler { req =>
+ UndertowSharafServer(routes).withNotFoundHandler { req =>
Response.withBody(MyCustomNotFoundPage)
- .withStatus(StatusCodes.NOT_FOUND)
+ .withStatus(StatusCode.NotFound)
}
```
diff --git a/docs/src/files/howtos/QueryParams.scala b/docs/src/files/howtos/QueryParams.scala
index 41c0e2f..82a3e36 100644
--- a/docs/src/files/howtos/QueryParams.scala
+++ b/docs/src/files/howtos/QueryParams.scala
@@ -1,6 +1,6 @@
package files.howtos
-import utils.Bundle.*
+import utils.*
object QueryParams extends HowToPage {
@@ -87,7 +87,7 @@ object QueryParams extends HowToPage {
val customSection = Section(
"How to bind a custom query parameter?",
- s"""
+ """
When you want to handle a custom *scalar* value in query params,
you need to implement a `QueryStringRW[T]` instance manually:
```scala
@@ -103,7 +103,7 @@ object QueryParams extends HowToPage {
}
private def typeError(path: String, tpe: String, value: Any): Nothing =
- throw ParsingException(ParseError(path, s"invalid $$tpe", Some(value)))
+ throw ParsingException(ParseError(path, s"invalid \$tpe", Some(value)))
```
Then you can use it:
diff --git a/docs/src/files/howtos/Redirect.scala b/docs/src/files/howtos/Redirect.scala
index 1ce4869..9964822 100644
--- a/docs/src/files/howtos/Redirect.scala
+++ b/docs/src/files/howtos/Redirect.scala
@@ -1,6 +1,6 @@
package files.howtos
-import utils.Bundle.*
+import utils.*
object Redirect extends HowToPage {
diff --git a/docs/src/files/howtos/ResponseBody.scala b/docs/src/files/howtos/ResponseBody.scala
index dda92b3..f98ca1e 100644
--- a/docs/src/files/howtos/ResponseBody.scala
+++ b/docs/src/files/howtos/ResponseBody.scala
@@ -1,6 +1,6 @@
package files.howtos
-import utils.Bundle.*
+import utils.*
object ResponseBody extends HowToPage {
@@ -23,7 +23,7 @@ object ResponseBody extends HowToPage {
override def write(value: MyXML, exchange: HttpServerExchange): Unit =
exchange.getResponseSender.send(value.asString)
override def headers(value: String): Seq[(HttpString, Seq[String])] = Seq(
- Headers.CONTENT_TYPE -> Seq("text/xml")
+ HttpString(HeaderNames.ContentType) -> Seq("text/xml")
)
}
```
diff --git a/docs/src/files/howtos/Routes.scala b/docs/src/files/howtos/Routes.scala
index 65a15b3..85b4da0 100644
--- a/docs/src/files/howtos/Routes.scala
+++ b/docs/src/files/howtos/Routes.scala
@@ -1,6 +1,6 @@
package files.howtos
-import utils.Bundle.*
+import utils.*
object Routes extends HowToPage {
@@ -69,7 +69,7 @@ object Routes extends HowToPage {
val enumPathSection = Section(
"How to bind path parameter as an enum?",
- s"""
+ """
Sharaf needs a `FromPathParam[T]` instance for the `param[T]` extractor.
It can automatically derive an instance for singleton enums:
@@ -80,7 +80,7 @@ object Routes extends HowToPage {
val routes = Routes:
case GET -> Path("pricing", param[Cloud](cloud)) =>
- Response.withBody(s"cloud = $${cloud}")
+ Response.withBody(s"cloud = \${cloud}")
```
""".md
@@ -88,14 +88,14 @@ object Routes extends HowToPage {
val regexPathSection = Section(
"How to bind path parameter as a regex?",
- s"""
+ """
```scala
val userIdRegex = "user_id_(\\d+)".r
val routes = Routes:
case GET -> Path("pricing", userIdRegex(userId)) =>
- Response.withBody(s"userId = $${userId}")
+ Response.withBody(s"userId = \${userId}")
```
Note that the `userId` is bound as a `String`.
@@ -111,7 +111,7 @@ object Routes extends HowToPage {
val customPathSection = Section(
"How to bind a custom path parameter?",
- s"""
+ """
Sharaf needs a `FromPathParam[T]` instance available:
```scala
import ba.sake.sharaf.routing.*
@@ -123,7 +123,7 @@ object Routes extends HowToPage {
val routes = Routes:
case GET -> Path("pricing", param[MyType](myType)) =>
- Response.withBody(s"myType = $${myType}")
+ Response.withBody(s"myType = \${myType}")
```
""".md
)
@@ -150,7 +150,7 @@ object Routes extends HowToPage {
override def routes: Routes = Routes:
case ...
- val handler = SharafHandler(
+ val server = UndertowSharafServer(
new MyController1, new MyController2
)
```
diff --git a/docs/src/files/howtos/UploadFile.scala b/docs/src/files/howtos/UploadFile.scala
index 338fbbe..3d09384 100644
--- a/docs/src/files/howtos/UploadFile.scala
+++ b/docs/src/files/howtos/UploadFile.scala
@@ -1,7 +1,6 @@
package files.howtos
-import utils.Bundle.*
-import utils.Consts
+import utils.*
object UploadFile extends HowToPage {
diff --git a/docs/src/files/philosophy/Alternatives.scala b/docs/src/files/philosophy/Alternatives.scala
index d80d4e8..5bfb0e8 100644
--- a/docs/src/files/philosophy/Alternatives.scala
+++ b/docs/src/files/philosophy/Alternatives.scala
@@ -1,6 +1,6 @@
package files.philosophy
-import utils.Bundle.*
+import utils.*
object Alternatives extends PhilosophyPage {
diff --git a/docs/src/files/philosophy/Authentication.scala b/docs/src/files/philosophy/Authentication.scala
index 5b0a907..201c4cf 100644
--- a/docs/src/files/philosophy/Authentication.scala
+++ b/docs/src/files/philosophy/Authentication.scala
@@ -1,6 +1,6 @@
package files.philosophy
-import utils.Bundle.*
+import utils.*
object Authentication extends PhilosophyPage {
@@ -52,7 +52,7 @@ object Authentication extends PhilosophyPage {
val denyByDefaultSection = Section(
"Deny by Default Principle",
- s"""
+ """
One important principle in security is the "deny by default" principle.
You should use whitelisting, allow access only to what is needed.
This is because it is easy to forget to deny something, and it is hard to remember everything that should be denied.
@@ -75,7 +75,7 @@ object Authentication extends PhilosophyPage {
There are also:
- `excludeBranch("/somepath")` to exclude all paths starting with "/somepath"
- - `excludeRegex("^/somepath/.*$$")` to exclude all paths matching the regex (be careful with this one!)
+ - `excludeRegex("^/somepath/.*\$")` to exclude all paths matching the regex (be careful with this one!)
""".md
)
}
diff --git a/docs/src/files/philosophy/Authorization.scala b/docs/src/files/philosophy/Authorization.scala
index b2d21dc..b64a1c3 100644
--- a/docs/src/files/philosophy/Authorization.scala
+++ b/docs/src/files/philosophy/Authorization.scala
@@ -1,6 +1,6 @@
package files.philosophy
-import utils.Bundle.*
+import utils.*
object Authorization extends PhilosophyPage {
diff --git a/docs/src/files/philosophy/DependencyInjection.scala b/docs/src/files/philosophy/DependencyInjection.scala
index 4207601..b958ede 100644
--- a/docs/src/files/philosophy/DependencyInjection.scala
+++ b/docs/src/files/philosophy/DependencyInjection.scala
@@ -1,6 +1,6 @@
package files.philosophy
-import utils.Bundle.*
+import utils.*
object DependencyInjection extends PhilosophyPage {
diff --git a/docs/src/files/philosophy/Index.scala b/docs/src/files/philosophy/Index.scala
index 7964348..4aadfc9 100644
--- a/docs/src/files/philosophy/Index.scala
+++ b/docs/src/files/philosophy/Index.scala
@@ -1,7 +1,6 @@
package files.philosophy
-import utils.Bundle.*
-import utils.Consts
+import utils.*
object Index extends PhilosophyPage {
@@ -25,7 +24,7 @@ object Index extends PhilosophyPage {
- [tupson](https://github.com/sake92/tupson) for JSON
- [formson](${Consts.GhSourcesUrl}/formson) for forms
- [validson](${Consts.GhSourcesUrl}/validson) for validation
- - [hepek-components](https://github.com/sake92/hepek) for HTML (with [scalatags](https://github.com/com-lihaoyi/scalatags))
+ - [scalatags](https://github.com/com-lihaoyi/scalatags) for HTML
- [sttp](https://sttp.softwaremill.com/en/latest/) for firing HTTP requests
- [typesafe-config](https://github.com/lightbend/config) for configuration
diff --git a/docs/src/files/philosophy/PhilosophyPage.scala b/docs/src/files/philosophy/PhilosophyPage.scala
index 6c717f0..2a20a6d 100644
--- a/docs/src/files/philosophy/PhilosophyPage.scala
+++ b/docs/src/files/philosophy/PhilosophyPage.scala
@@ -1,9 +1,6 @@
package files.philosophy
-import utils.*
-import Bundle.*
-
-trait PhilosophyPage extends DocPage {
+trait PhilosophyPage extends utils.DocPage {
override def categoryPosts = List(
Index,
@@ -16,5 +13,5 @@ trait PhilosophyPage extends DocPage {
override def pageCategory = Some("Philosophy")
- override def navbar = Some(Navbar.withActiveUrl(Index.ref))
+ override def currentCategoryPage = Some(Index)
}
diff --git a/docs/src/files/philosophy/QueryParamsHandling.scala b/docs/src/files/philosophy/QueryParamsHandling.scala
index 712d663..cd2a630 100644
--- a/docs/src/files/philosophy/QueryParamsHandling.scala
+++ b/docs/src/files/philosophy/QueryParamsHandling.scala
@@ -1,6 +1,6 @@
package files.philosophy
-import utils.Bundle.*
+import utils.*
import files.howtos.QueryParams
object QueryParamsHandling extends PhilosophyPage {
diff --git a/docs/src/files/philosophy/RoutesMatching.scala b/docs/src/files/philosophy/RoutesMatching.scala
index cf9a5ca..06d5987 100644
--- a/docs/src/files/philosophy/RoutesMatching.scala
+++ b/docs/src/files/philosophy/RoutesMatching.scala
@@ -1,6 +1,6 @@
package files.philosophy
-import utils.Bundle.*
+import utils.*
object RoutesMatching extends PhilosophyPage {
diff --git a/docs/src/files/reference/Index.scala b/docs/src/files/reference/Index.scala
index 136e65f..f2e43c2 100644
--- a/docs/src/files/reference/Index.scala
+++ b/docs/src/files/reference/Index.scala
@@ -1,7 +1,7 @@
package files.reference
+import scalatags.Text.all.*
import utils.*
-import Bundle.*, Tags.*
object Index extends ReferencePage {
@@ -15,11 +15,8 @@ object Index extends ReferencePage {
s"${Consts.ProjectName} reference",
div(
s"""
- ...
-
- ```scala
- println("Hello!")
- ```
+
+ Take a look at [Sharaf scaladoc](https://javadoc.io/doc/ba.sake/sharaf_3).
""".md
)
)
diff --git a/docs/src/files/reference/ReferencePage.scala b/docs/src/files/reference/ReferencePage.scala
index 59db421..227039f 100644
--- a/docs/src/files/reference/ReferencePage.scala
+++ b/docs/src/files/reference/ReferencePage.scala
@@ -1,7 +1,7 @@
package files.reference
+import files.tutorials.Index
import utils.*
-import Bundle.*
trait ReferencePage extends DocPage {
@@ -9,5 +9,5 @@ trait ReferencePage extends DocPage {
override def pageCategory = Some("Reference")
- override def navbar = Some(Navbar.withActiveUrl(Index.ref))
+ override def currentCategoryPage = Some(Index)
}
diff --git a/docs/src/files/tutorials/HTML.scala b/docs/src/files/tutorials/HTML.scala
index c5942b4..8326a51 100644
--- a/docs/src/files/tutorials/HTML.scala
+++ b/docs/src/files/tutorials/HTML.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object HTML extends TutorialPage {
diff --git a/docs/src/files/tutorials/HTMX.scala b/docs/src/files/tutorials/HTMX.scala
index abc5f6a..4afb768 100644
--- a/docs/src/files/tutorials/HTMX.scala
+++ b/docs/src/files/tutorials/HTMX.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object HTMX extends TutorialPage {
@@ -21,7 +20,7 @@ object HTMX extends TutorialPage {
Sharaf is using the [hepek-components](https://sake92.github.io/hepek/hepek/components/reference/bundle-reference.html)
as its template engine, which has support for HTMX attributes.
- You can lots of examples in [examples/scala-cli/htmx](${Consts.GhSourcesUrl}/examples/scala-cli/htmx) folder.
+ You can lots of examples in [examples/htmx](${Consts.GhSourcesUrl}/examples/htmx) folder.
---
diff --git a/docs/src/files/tutorials/HandlingForms.scala b/docs/src/files/tutorials/HandlingForms.scala
index c48609b..ad247d4 100644
--- a/docs/src/files/tutorials/HandlingForms.scala
+++ b/docs/src/files/tutorials/HandlingForms.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object HandlingForms extends TutorialPage {
diff --git a/docs/src/files/tutorials/HelloWorld.scala b/docs/src/files/tutorials/HelloWorld.scala
index acce19e..4ad1857 100644
--- a/docs/src/files/tutorials/HelloWorld.scala
+++ b/docs/src/files/tutorials/HelloWorld.scala
@@ -1,7 +1,7 @@
package files.tutorials
+import scalatags.Text.all.*
import utils.*
-import Bundle.*, Tags.*
object HelloWorld extends TutorialPage {
diff --git a/docs/src/files/tutorials/Index.scala b/docs/src/files/tutorials/Index.scala
index 59a41c1..e369b2b 100644
--- a/docs/src/files/tutorials/Index.scala
+++ b/docs/src/files/tutorials/Index.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object Index extends TutorialPage {
@@ -55,7 +54,7 @@ object Index extends TutorialPage {
"Examples",
s"""
- [scala-cli examples](${Consts.GhSourcesUrl}/examples/scala-cli), standalone examples using scala-cli
- - [scala-cli HTMX examples](${Consts.GhSourcesUrl}/examples/scala-cli/htmx), standalone examples featuring HTMX
+ - [scala-cli HTMX examples](${Consts.GhSourcesUrl}/examples/htmx), standalone examples featuring HTMX
- [API example](${Consts.GhSourcesUrl}/examples/api) featuring JSON and validation
- [full-stack example](${Consts.GhSourcesUrl}/examples/fullstack) featuring HTML, static files and forms
- [sharaf-todo-backend](https://github.com/sake92/sharaf-todo-backend), implementation of the [todobackend.com](http://todobackend.com/) spec, featuring CORS handling
diff --git a/docs/src/files/tutorials/JsonAPI.scala b/docs/src/files/tutorials/JsonAPI.scala
index 3427bee..1949efc 100644
--- a/docs/src/files/tutorials/JsonAPI.scala
+++ b/docs/src/files/tutorials/JsonAPI.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object JsonAPI extends TutorialPage {
@@ -12,11 +11,13 @@ object JsonAPI extends TutorialPage {
super.blogSettings.withSections(modelSection, routesSection, runSection)
private val snip1 = ScalaCliFiles.json_api.snippet(until = "val routes").indent(4)
+
private val snip2 = ScalaCliFiles.json_api
- .snippet(from = "val routes", until = "Undertow.builder")
+ .snippet(from = "val routes", until = "UndertowSharafServer")
.indent(4)
.trim
- private val snip3 = ScalaCliFiles.json_api.snippet(from = "Undertow.builder").indent(4)
+
+ private val snip3 = ScalaCliFiles.json_api.snippet(from = "UndertowSharafServer").indent(4)
val modelSection = Section(
"Model definition",
diff --git a/docs/src/files/tutorials/PathParams.scala b/docs/src/files/tutorials/PathParams.scala
index 9df64f6..2879142 100644
--- a/docs/src/files/tutorials/PathParams.scala
+++ b/docs/src/files/tutorials/PathParams.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object PathParams extends TutorialPage {
diff --git a/docs/src/files/tutorials/QueryParams.scala b/docs/src/files/tutorials/QueryParams.scala
index 0daabb3..ef52f22 100644
--- a/docs/src/files/tutorials/QueryParams.scala
+++ b/docs/src/files/tutorials/QueryParams.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object QueryParams extends TutorialPage {
diff --git a/docs/src/files/tutorials/SqlDb.scala b/docs/src/files/tutorials/SqlDb.scala
index 6acde39..f837603 100644
--- a/docs/src/files/tutorials/SqlDb.scala
+++ b/docs/src/files/tutorials/SqlDb.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object SqlDb extends TutorialPage {
@@ -35,10 +34,10 @@ object SqlDb extends TutorialPage {
private val snip1 = ScalaCliFiles.sql_db.snippet(until = "case class Customer").indent(4)
private val snip2 = ScalaCliFiles.sql_db
- .snippet(from = "case class Customer", until = "Undertow.builder")
+ .snippet(from = "case class Customer", until = "UndertowSharafServer")
.indent(4)
.trim
- private val snip3 = ScalaCliFiles.sql_db.snippet(from = "Undertow.builder").indent(4)
+ private val snip3 = ScalaCliFiles.sql_db.snippet(from = "UndertowSharafServer").indent(4)
val squerySetup = Section(
"Squery setup",
diff --git a/docs/src/files/tutorials/StaticFiles.scala b/docs/src/files/tutorials/StaticFiles.scala
index 0c161a0..2eaf9fd 100644
--- a/docs/src/files/tutorials/StaticFiles.scala
+++ b/docs/src/files/tutorials/StaticFiles.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object StaticFiles extends TutorialPage {
diff --git a/docs/src/files/tutorials/Tests.scala b/docs/src/files/tutorials/Tests.scala
index deba8c1..8ca4f09 100644
--- a/docs/src/files/tutorials/Tests.scala
+++ b/docs/src/files/tutorials/Tests.scala
@@ -1,7 +1,7 @@
package files.tutorials
+import scalatags.Text.all.*
import utils.*
-import Bundle.*, Tags.*
object Tests extends TutorialPage {
diff --git a/docs/src/files/tutorials/TutorialPage.scala b/docs/src/files/tutorials/TutorialPage.scala
index 9e0c5af..6016879 100644
--- a/docs/src/files/tutorials/TutorialPage.scala
+++ b/docs/src/files/tutorials/TutorialPage.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
// TODO logging, logback + slf4j
// TODO docker
@@ -34,5 +33,5 @@ trait TutorialPage extends DocPage {
override def pageCategory = Some("Tutorials")
- override def navbar = Some(Navbar.withActiveUrl(Index.ref))
+ override def currentCategoryPage = Some(Index)
}
diff --git a/docs/src/files/tutorials/Validation.scala b/docs/src/files/tutorials/Validation.scala
index d5ac0ca..cee8979 100644
--- a/docs/src/files/tutorials/Validation.scala
+++ b/docs/src/files/tutorials/Validation.scala
@@ -1,7 +1,6 @@
package files.tutorials
import utils.*
-import Bundle.*
object Validation extends TutorialPage {
@@ -57,7 +56,7 @@ object Validation extends TutorialPage {
"invalidArguments": [
{
"reason": "must not be blank",
- "path": "$$.brand",
+ "path": "\\$$.brand",
"value": ""
}
],
@@ -88,12 +87,12 @@ object Validation extends TutorialPage {
"invalidArguments": [
{
"reason": "must not be blank",
- "path": "$$.brand",
+ "path": "\\$$.brand",
"value": " "
},
{
"reason": "must not be negative",
- "path": "$$.quantity",
+ "path": "\\$$.quantity",
"value": "-5"
}
],
diff --git a/docs/src/utils/Consts.scala b/docs/src/utils/Consts.scala
index b31628e..564af9b 100644
--- a/docs/src/utils/Consts.scala
+++ b/docs/src/utils/Consts.scala
@@ -6,7 +6,7 @@ object Consts:
val ArtifactOrg = "ba.sake"
val ArtifactName = "sharaf"
- val ArtifactVersion = "0.9.2"
+ val ArtifactVersion = "0.10.0"
val GhHandle = "sake92"
val GhProjectName = "sharaf"
@@ -14,3 +14,9 @@ object Consts:
val GhSourcesUrl = s"https://github.com/${GhHandle}/${GhProjectName}/tree/main"
val tq = """""""""
+
+ def allSearchIndexedPages = Seq(files.Index) ++
+ files.tutorials.Index.categoryPosts ++
+ files.howtos.Index.categoryPosts ++
+ files.reference.Index.categoryPosts ++
+ files.philosophy.Index.categoryPosts
diff --git a/docs/src/utils/ScalaCliFiles.scala b/docs/src/utils/ScalaCliFiles.scala
index c6c0cc1..14eb24f 100644
--- a/docs/src/utils/ScalaCliFiles.scala
+++ b/docs/src/utils/ScalaCliFiles.scala
@@ -18,22 +18,22 @@ extension (str: String) {
object ScalaCliFiles:
- val hello = get("hello.sc")
- val path_params = get("path_params.sc")
- val query_params = get("query_params.sc")
- val static_files = get("static_files.sc")
- val html_scalatags = get("html_scalatags.sc")
- val html_hepek = get("html_hepek.sc")
- val htmx_load_snippet = get(os.RelPath("htmx") / "htmx_load_snippet.sc")
- val form_handling = get("form_handling.sc")
- val json_api = get("json_api.sc")
- val json_api_test = get("json_api.test.scala")
+ val hello = get(os.RelPath("scala-cli/hello.sc"))
+ val path_params = get(os.RelPath("scala-cli/path_params.sc"))
+ val query_params = get(os.RelPath("scala-cli/query_params.sc"))
+ val static_files = get(os.RelPath("scala-cli/static_files.sc"))
+ val html_scalatags = get(os.RelPath("scala-cli/html_scalatags.sc"))
+ val html_hepek = get(os.RelPath("scala-cli/html_hepek.sc"))
+ val htmx_load_snippet = get(os.RelPath("htmx/htmx_load_snippet.sc"))
+ val form_handling = get(os.RelPath("scala-cli/form_handling.sc"))
+ val json_api = get(os.RelPath("scala-cli/json_api.sc"))
+ val json_api_test = get(os.RelPath("scala-cli/json_api.test.scala"))
- val sql_db = get("sql_db.sc")
+ val sql_db = get(os.RelPath("scala-cli/sql_db.sc"))
- val validation = get("validation.sc")
+ val validation = get(os.RelPath("scala-cli/validation.sc"))
private def get(chunk: os.PathChunk) =
// os.pwd is sandboxed, this is called from plugin !
val wd = os.Path(System.getenv("MILL_WORKSPACE_ROOT"))
- os.read(wd / "examples" / "scala-cli" / chunk)
+ os.read(wd / "examples" / chunk).replace("${", "\\${") // escaping for nodejs shiki
diff --git a/docs/src/utils/package.scala b/docs/src/utils/package.scala
index 3e26f72..dc185c2 100644
--- a/docs/src/utils/package.scala
+++ b/docs/src/utils/package.scala
@@ -1,59 +1,35 @@
package utils
+import scalatags.Text.all.*
import ba.sake.hepek.core.RelativePath
-import ba.sake.hepek.html.statik.BlogPostPage
-import ba.sake.hepek.bootstrap5.statik.BootstrapStaticBundle
+import ba.sake.hepek.html.statik
-val Bundle = locally {
- val b = BootstrapStaticBundle.default
- import b.*
+type Section = statik.Section
+val Section = statik.Section
- val ratios = Ratios.default.withSingle(1, 2, 1).withHalf(1, 1).withThird(1, 2, 1)
- val grid = Grid.withScreenRatios(
- Grid.screenRatios.withSm(None).withXs(None).withLg(ratios).withMd(ratios)
- )
- b.withGrid(grid)
-}
-
-val FA = ba.sake.hepek.fontawesome5.FA
+def pager(thisSp: statik.BlogPostPage)(using caller: RelativePath) = {
-def pager(thisSp: BlogPostPage)(using caller: RelativePath) = {
- import Bundle.Tags.*
-
- def bsNavigation(navLinks: Frag*) = tag("nav")(
- ul(cls := "pagination justify-content-center")(navLinks)
+ def picoButtons(navLinks: Frag*) = tag("nav")(
+ div(role := "group")(navLinks)
)
val posts = thisSp.categoryPosts
val indexOfThis = posts.indexOf(thisSp)
if posts.length > 1 && indexOfThis >= 0 then {
-
if indexOfThis == 0 then
- bsNavigation(
- li(cls := "disabled page-item")(
- a(href := "#", cls := "page-link")("Previous")
- ),
- li(title := posts(indexOfThis + 1).pageSettings.label, cls := "page-item")(
- a(href := posts(indexOfThis + 1).ref, cls := "page-link")("Next")
- )
+ picoButtons(
+ a(href := "#", disabled, role := "button", cls := "outline")("Previous"),
+ a(href := posts(indexOfThis + 1).ref, role := "button", cls := "outline")("Next")
)
else if indexOfThis == posts.length - 1 then
- bsNavigation(
- li(title := posts(indexOfThis - 1).pageSettings.label, cls := "page-item")(
- a(href := posts(indexOfThis - 1).ref, cls := "page-link")("Previous")
- ),
- li(cls := "disabled page-item")(
- a(href := "#", cls := "page-link")("Next")
- )
+ picoButtons(
+ a(href := posts(indexOfThis - 1).ref, role := "button", cls := "outline")("Previous"),
+ a(href := "#", disabled, role := "button", cls := "outline")("Next")
)
else
- bsNavigation(
- li(title := posts(indexOfThis - 1).pageSettings.label, cls := "page-item")(
- a(href := posts(indexOfThis - 1).ref, cls := "page-link")("Previous")
- ),
- li(title := posts(indexOfThis + 1).pageSettings.label, cls := "page-item")(
- a(href := posts(indexOfThis + 1).ref, cls := "page-link")("Next")
- )
+ picoButtons(
+ a(href := posts(indexOfThis - 1).ref, role := "button", cls := "outline")("Previous"),
+ a(href := posts(indexOfThis + 1).ref, role := "button", cls := "outline")("Next")
)
} else frag()
diff --git a/docs/src/utils/templates.scala b/docs/src/utils/templates.scala
index 31fd4cc..4586dbf 100644
--- a/docs/src/utils/templates.scala
+++ b/docs/src/utils/templates.scala
@@ -1,12 +1,51 @@
package utils
-import ba.sake.hepek.prismjs.PrismDependencies
-import ba.sake.hepek.theme.bootstrap5.*
+import scalatags.Text.all.*
+import scalatags.Text.tags2.{aside, main, nav, section}
import ba.sake.hepek.anchorjs.AnchorjsDependencies
-import ba.sake.hepek.fontawesome5.FADependencies
-import Bundle.*, Tags.*
+import ba.sake.hepek.html.statik.{BlogPostPage, ShikiSettings, StaticPage}
+import files.SearchResults
+
+trait DocPage extends DocStaticPage with BlogPostPage {
+
+ override def mainContent: Frag = div(cls := "blog-post")(
+ aside(id := "left-menu")(
+ nav(
+ ul(
+ for sameCatPost <- categoryPosts
+ yield li(
+ a(
+ href := sameCatPost.ref,
+ Option.when(this.relPath == sameCatPost.relPath)(attr("aria-current") := "page")
+ )(
+ sameCatPost.pageSettings.label
+ )
+ )
+ )
+ )
+ ),
+ div(cls := "main-content")(
+ pager(this),
+ renderSections(blogSettings.sections, 2)
+ )
+ )
+
+ private def renderSections(secs: List[Section], depth: Int): List[Frag] =
+ secs.map { s =>
+ // h2, h3...
+ val hTag = tag("h" + depth)
+ section(id := s.id)(
+ hTag(s.name),
+ s.content,
+ renderSections(s.children, depth + 1)
+ )
+ }
+}
+
+trait DocStaticPage extends StaticPage with AnchorjsDependencies {
+
+ def currentCategoryPage: Option[StaticPage] = None
-trait DocStaticPage extends StaticPage with AnchorjsDependencies with FADependencies {
override def staticSiteSettings = super.staticSiteSettings
.withIndexPage(files.Index)
.withMainPages(
@@ -18,29 +57,75 @@ trait DocStaticPage extends StaticPage with AnchorjsDependencies with FADependen
override def siteSettings = super.siteSettings
.withName(Consts.ProjectName)
- .withFaviconNormal(files.images.`favicon.svg`.ref)
- .withFaviconInverted(files.images.`favicon.svg`.ref)
-
- override def bodyContent = frag(
- super.bodyContent,
- footer(Classes.txtAlignCenter, Classes.bgInfo, cls := "fixed-bottom")(
- a(href := Consts.GhUrl, Classes.btnClass)(FA.github()),
- a(href := "https://discord.gg/g9KVY3WkMG", Classes.btnClass)(FA.discord())
+ .withFaviconNormal(files.images.`favicon.png`.ref)
+
+ override def shikiSettings = super.shikiSettings.withTheme("material-theme-ocean")
+
+ override def styleURLs =
+ List("https://cdn.jsdelivr.net/npm/@picocss/pico@2.1.1/css/pico.cyan.min.css", files.styles.`main.css`.ref)
+
+ override def pageContent = frag(
+ header(cls := "container")(
+ topNavbar
+ ),
+ main(cls := "container")(
+ mainContent
+ ),
+ footer(cls := "container flex-centered")(
+ a(href := "https://github.com/sake92/sharaf")(
+ raw("""
+
+
+ """)
+ ),
+ a(href := "https://discord.gg/g9KVY3WkMG")(
+ raw("""
+
+
+ """)
+ )
)
)
- override def styleURLs = super.styleURLs
- .appended(files.styles.`main.css`.ref)
+ private def topNavbar = nav(
+ ul(
+ siteSettings.faviconNormal.map { fav =>
+ li(img(src := fav))
+ },
+ li(a(href := "https://sake92.github.io/sharaf/")("Sharaf Docs"))
+ ),
+ ul(
+ li(
+ form(action := SearchResults.ref, method := "GET")(
+ input(
+ name := "q",
+ tpe := "search",
+ placeholder := "Search"
+ )
+ )
+ )
+ ),
+ ul(
+ for
+ mainPage <- staticSiteSettings.mainPages
+ labela = mainPage.pageCategory.getOrElse(mainPage.pageSettings.label)
+ yield li(
+ a(
+ href := mainPage.ref,
+ Option.when(currentCategoryPage.map(_.relPath).contains(mainPage.relPath))(
+ attr("aria-current") := "true"
+ )
+ )(labela)
+ )
+ )
+ )
override def scriptURLs = super.scriptURLs
.appended(files.scripts.`main.js`.ref)
}
-
-trait DocPage extends DocStaticPage with HepekBootstrap5BlogPage with PrismDependencies {
-
- override def tocSettings = Some(TocSettings(tocType = TocType.Scrollspy(offset = 60)))
-
- override def pageHeader = Some(pager(this))
-
-}
diff --git a/examples/scala-cli/htmx/README.md b/examples/htmx/README.md
similarity index 64%
rename from examples/scala-cli/htmx/README.md
rename to examples/htmx/README.md
index ab7b906..e590e0a 100644
--- a/examples/scala-cli/htmx/README.md
+++ b/examples/htmx/README.md
@@ -3,12 +3,7 @@ Example implementations of https://htmx.org/examples/
Run any of these from this folder:
```sh
-scala-cli htmx_load_snippet.sc
-```
-
-For examples that use images and static resources:
-```sh
-scala-cli htmx_click_to_load.sc --resource-dir resources
+scala-cli htmx_load_snippet.sc --resource-dir resources
```
If you want to restart the server when files change, just add the `--restart` flag:
diff --git a/examples/scala-cli/htmx/htmx_active_search.sc b/examples/htmx/htmx_active_search.sc
similarity index 96%
rename from examples/scala-cli/htmx/htmx_active_search.sc
rename to examples/htmx/htmx_active_search.sc
index e4270df..5b6dd75 100644
--- a/examples/scala-cli/htmx/htmx_active_search.sc
+++ b/examples/htmx/htmx_active_search.sc
@@ -1,12 +1,11 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/active-search/
-// scala htmx_active_search.sc --resource-dir resources
-import io.undertow.Undertow
import ba.sake.formson.FormDataRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -17,11 +16,7 @@ val routes = Routes:
val contactsSlice = allContacts.filter(_.matches(formData.search))
Response.withBody(views.contactsRows(contactsSlice))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_animations.sc b/examples/htmx/htmx_animations.sc
similarity index 91%
rename from examples/scala-cli/htmx/htmx_animations.sc
rename to examples/htmx/htmx_animations.sc
index 1f0471b..b52e0f6 100644
--- a/examples/scala-cli/htmx/htmx_animations.sc
+++ b/examples/htmx/htmx_animations.sc
@@ -1,13 +1,12 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/animations/
-// scala htmx_animations.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -38,11 +37,7 @@ val routes = Routes:
Thread.sleep(1000) // simulate sloww
Response.withBody("Submitted!")
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_bulk_update.sc b/examples/htmx/htmx_bulk_update.sc
similarity index 91%
rename from examples/scala-cli/htmx/htmx_bulk_update.sc
rename to examples/htmx/htmx_bulk_update.sc
index 3d79f7b..c20199c 100644
--- a/examples/scala-cli/htmx/htmx_bulk_update.sc
+++ b/examples/htmx/htmx_bulk_update.sc
@@ -1,12 +1,11 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/bulk-update/
-// scala htmx_bulk_update.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
import ba.sake.formson.FormDataRW
import ba.sake.hepek.htmx.*
@@ -26,11 +25,7 @@ val routes = Routes:
}
Response.withBody(views.contactsRows(currentContacts, AffectedContacts(formData.ids, false)))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_cascading_selects.sc b/examples/htmx/htmx_cascading_selects.sc
similarity index 88%
rename from examples/scala-cli/htmx/htmx_cascading_selects.sc
rename to examples/htmx/htmx_cascading_selects.sc
index 014bf9b..ba5c2e8 100644
--- a/examples/scala-cli/htmx/htmx_cascading_selects.sc
+++ b/examples/htmx/htmx_cascading_selects.sc
@@ -1,13 +1,13 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/value-select/
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
import ba.sake.querson.QueryStringRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -17,11 +17,7 @@ val routes = Routes:
val qp = Request.current.queryParams[ModelsQP]
Response.withBody(views.cascadingSelect(qp.make))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_click_edit.sc b/examples/htmx/htmx_click_edit.sc
similarity index 89%
rename from examples/scala-cli/htmx/htmx_click_edit.sc
rename to examples/htmx/htmx_click_edit.sc
index 8396713..5519251 100644
--- a/examples/scala-cli/htmx/htmx_click_edit.sc
+++ b/examples/htmx/htmx_click_edit.sc
@@ -1,11 +1,12 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/click-to-edit/
-import io.undertow.Undertow
+
import scalatags.Text.all.{param =>_, *}
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
import ba.sake.formson.FormDataRW
var currentValue = ContactForm("Joe", "Blow", "joe@blow.com")
@@ -22,11 +23,7 @@ val routes = Routes:
currentValue = formData
Response.withBody(views.contactView(currentValue))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_click_to_load.sc b/examples/htmx/htmx_click_to_load.sc
similarity index 87%
rename from examples/scala-cli/htmx/htmx_click_to_load.sc
rename to examples/htmx/htmx_click_to_load.sc
index d55747a..db99778 100644
--- a/examples/scala-cli/htmx/htmx_click_to_load.sc
+++ b/examples/htmx/htmx_click_to_load.sc
@@ -1,15 +1,14 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/click-to-load/
-// scala htmx_click_to_load.sc --resource-dir resources
import java.util.UUID
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
import ba.sake.querson.QueryStringRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val PageSize = 5
@@ -26,11 +25,7 @@ val routes = Routes:
val contactsSlice = allContacts.slice(qp.page * PageSize, qp.page * PageSize + PageSize)
Response.withBody(views.contactsRowsWithButton(contactsSlice, qp.page))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_delete_row.sc b/examples/htmx/htmx_delete_row.sc
similarity index 83%
rename from examples/scala-cli/htmx/htmx_delete_row.sc
rename to examples/htmx/htmx_delete_row.sc
index 29cd2d1..96307ba 100644
--- a/examples/scala-cli/htmx/htmx_delete_row.sc
+++ b/examples/htmx/htmx_delete_row.sc
@@ -1,13 +1,12 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/delete-row/
-// scala htmx_delete_row.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
var allContacts = Seq(
Contact("1", "Angie MacDowell", "angie@macdowell.org"),
@@ -22,11 +21,7 @@ val routes = Routes:
allContacts = allContacts.filterNot(_.id == id)
Response.withBody("") // empty string, remove that
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_dialogs_bootstrap.sc b/examples/htmx/htmx_dialogs_bootstrap.sc
similarity index 85%
rename from examples/scala-cli/htmx/htmx_dialogs_bootstrap.sc
rename to examples/htmx/htmx_dialogs_bootstrap.sc
index 1562153..b77e260 100644
--- a/examples/scala-cli/htmx/htmx_dialogs_bootstrap.sc
+++ b/examples/htmx/htmx_dialogs_bootstrap.sc
@@ -1,13 +1,12 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/modal-bootstrap/
-// scala htmx_dialogs_bootstrap.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -15,11 +14,7 @@ val routes = Routes:
case GET -> Path("modal") =>
Response.withBody(views.bsDialog())
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_dialogs_bootstrap_form.sc b/examples/htmx/htmx_dialogs_bootstrap_form.sc
similarity index 87%
rename from examples/scala-cli/htmx/htmx_dialogs_bootstrap_form.sc
rename to examples/htmx/htmx_dialogs_bootstrap_form.sc
index 91f211b..c90d60a 100644
--- a/examples/scala-cli/htmx/htmx_dialogs_bootstrap_form.sc
+++ b/examples/htmx/htmx_dialogs_bootstrap_form.sc
@@ -1,14 +1,13 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// example of BS5 modal with a form
-// scala htmx_dialogs_bootstrap_form.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
import ba.sake.formson.FormDataRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -20,11 +19,7 @@ val routes = Routes:
val formData = Request.current.bodyForm[DialogForm]
Response.withBody(div(s"You submitted: $formData"))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_dialogs_browser.sc b/examples/htmx/htmx_dialogs_browser.sc
similarity index 75%
rename from examples/scala-cli/htmx/htmx_dialogs_browser.sc
rename to examples/htmx/htmx_dialogs_browser.sc
index 02aeceb..003f66f 100644
--- a/examples/scala-cli/htmx/htmx_dialogs_browser.sc
+++ b/examples/htmx/htmx_dialogs_browser.sc
@@ -1,13 +1,12 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/dialogs/
-// scala htmx_dialogs_browser.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
import ba.sake.sharaf.htmx.*
val routes = Routes:
@@ -22,11 +21,7 @@ val routes = Routes:
)
)
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_edit_row.sc b/examples/htmx/htmx_edit_row.sc
similarity index 91%
rename from examples/scala-cli/htmx/htmx_edit_row.sc
rename to examples/htmx/htmx_edit_row.sc
index 1309bca..80373ed 100644
--- a/examples/scala-cli/htmx/htmx_edit_row.sc
+++ b/examples/htmx/htmx_edit_row.sc
@@ -1,14 +1,13 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/edit-row/
-// scala htmx_edit_row.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
import ba.sake.formson.FormDataRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
var allContacts = Seq(
Contact("1", "Joe Smith", "joe@smith.org"),
@@ -38,11 +37,7 @@ val routes = Routes:
allContacts = allContacts.updated(idx, updatedContact)
Response.withBody(views.viewContactRow(updatedContact))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_file_upload_js.sc b/examples/htmx/htmx_file_upload_js.sc
similarity index 84%
rename from examples/scala-cli/htmx/htmx_file_upload_js.sc
rename to examples/htmx/htmx_file_upload_js.sc
index fe30b0d..302e91a 100644
--- a/examples/scala-cli/htmx/htmx_file_upload_js.sc
+++ b/examples/htmx/htmx_file_upload_js.sc
@@ -1,11 +1,11 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
import ba.sake.formson.FormDataRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
// https://htmx.org/examples/file-upload/
// scala htmx_file_upload_js.sc --resource-dir resources
@@ -18,11 +18,7 @@ val routes = Routes:
val fileUpload = Request.current.bodyForm[FileUpload]
Response.withBody(div(s"Upload done!"))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_infinite_scroll.sc b/examples/htmx/htmx_infinite_scroll.sc
similarity index 87%
rename from examples/scala-cli/htmx/htmx_infinite_scroll.sc
rename to examples/htmx/htmx_infinite_scroll.sc
index 6791beb..1414282 100644
--- a/examples/scala-cli/htmx/htmx_infinite_scroll.sc
+++ b/examples/htmx/htmx_infinite_scroll.sc
@@ -1,15 +1,14 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/click-to-load/
-// scala htmx_infinite_scroll.sc --resource-dir resources
import java.util.UUID
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
import ba.sake.querson.QueryStringRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val PageSize = 10
@@ -26,11 +25,7 @@ val routes = Routes:
val contactsSlice = allContacts.slice(qp.page * PageSize, qp.page * PageSize + PageSize)
Response.withBody(views.contactsRows(contactsSlice, qp.page))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_inline_validation.sc b/examples/htmx/htmx_inline_validation.sc
similarity index 88%
rename from examples/scala-cli/htmx/htmx_inline_validation.sc
rename to examples/htmx/htmx_inline_validation.sc
index ce67d68..02ac2df 100644
--- a/examples/scala-cli/htmx/htmx_inline_validation.sc
+++ b/examples/htmx/htmx_inline_validation.sc
@@ -1,13 +1,12 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/inline-validation/
-// scala htmx_inline_validation.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
import ba.sake.formson.FormDataRW
val routes = Routes:
@@ -22,11 +21,7 @@ val routes = Routes:
val formData = Request.current.bodyForm[ContactForm]
Response.withBody(views.contactForm(formData))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_lazy_load.sc b/examples/htmx/htmx_lazy_load.sc
similarity index 76%
rename from examples/scala-cli/htmx/htmx_lazy_load.sc
rename to examples/htmx/htmx_lazy_load.sc
index a21614b..7f99100 100644
--- a/examples/scala-cli/htmx/htmx_lazy_load.sc
+++ b/examples/htmx/htmx_lazy_load.sc
@@ -1,13 +1,12 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
// https://htmx.org/examples/lazy-load/
-// scala htmx_lazy_load.sc --resource-dir resources
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -17,11 +16,7 @@ val routes = Routes:
val graph = img(src := "/img/tokyo.png")
Response.withBody(graph)
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_load_snippet.sc b/examples/htmx/htmx_load_snippet.sc
similarity index 65%
rename from examples/scala-cli/htmx/htmx_load_snippet.sc
rename to examples/htmx/htmx_load_snippet.sc
index d220baf..9e89de8 100644
--- a/examples/scala-cli/htmx/htmx_load_snippet.sc
+++ b/examples/htmx/htmx_load_snippet.sc
@@ -1,12 +1,10 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-// scala htmx_load_snippet.sc --resource-dir resources
-
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -19,11 +17,7 @@ val routes = Routes:
)
)
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_progress_bar.sc b/examples/htmx/htmx_progress_bar.sc
similarity index 91%
rename from examples/scala-cli/htmx/htmx_progress_bar.sc
rename to examples/htmx/htmx_progress_bar.sc
index 5badb51..f15c681 100644
--- a/examples/scala-cli/htmx/htmx_progress_bar.sc
+++ b/examples/htmx/htmx_progress_bar.sc
@@ -1,15 +1,14 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
import java.util.concurrent.TimeUnit
// https://htmx.org/examples/progress-bar/
-// scala htmx_progress_bar.sc --resource-dir resources
import java.util.concurrent.Executors
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
import ba.sake.sharaf.htmx.ResponseHeaders
var percentage = 0
@@ -40,11 +39,7 @@ val routes = Routes:
then Response.withBody(bar).settingHeader(ResponseHeaders.Trigger, "done")
else Response.withBody(bar)
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/htmx_tabs_hateoas.sc b/examples/htmx/htmx_tabs_hateoas.sc
similarity index 79%
rename from examples/scala-cli/htmx/htmx_tabs_hateoas.sc
rename to examples/htmx/htmx_tabs_hateoas.sc
index 56af18a..cdc27c8 100644
--- a/examples/scala-cli/htmx/htmx_tabs_hateoas.sc
+++ b/examples/htmx/htmx_tabs_hateoas.sc
@@ -1,12 +1,10 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-// scala htmx_tabs_hateoas.sc --resource-dir resources
-
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.htmx.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -18,11 +16,7 @@ val routes = Routes:
case GET -> Path("tab3") =>
Response.withBody(tabSnippet(3))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/htmx/resources/public/img/bars.svg b/examples/htmx/resources/public/img/bars.svg
similarity index 100%
rename from examples/scala-cli/htmx/resources/public/img/bars.svg
rename to examples/htmx/resources/public/img/bars.svg
diff --git a/examples/scala-cli/htmx/resources/public/img/tokyo.png b/examples/htmx/resources/public/img/tokyo.png
similarity index 100%
rename from examples/scala-cli/htmx/resources/public/img/tokyo.png
rename to examples/htmx/resources/public/img/tokyo.png
diff --git a/examples/scala-cli/README.md b/examples/scala-cli/README.md
new file mode 100644
index 0000000..65674f8
--- /dev/null
+++ b/examples/scala-cli/README.md
@@ -0,0 +1,17 @@
+
+Example implementations of https://htmx.org/examples/
+
+Run any of these from this folder:
+```sh
+scala-cli hello.sc --resource-dir resources
+```
+
+If you want to restart the server when files change, just add the `--restart` flag:
+```sh
+scala-cli hello.sc --resource-dir resources --restart
+```
+
+
+
+
+
diff --git a/examples/scala-cli/demo.sc b/examples/scala-cli/demo.sc
index cb0080e..5c4fc7b 100644
--- a/examples/scala-cli/demo.sc
+++ b/examples/scala-cli/demo.sc
@@ -1,11 +1,11 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import ba.sake.querson.QueryStringRW
import ba.sake.tupson.JsonRW
import ba.sake.validson.Validator
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path("cars") =>
@@ -20,12 +20,8 @@ val routes = Routes:
CarsDb.add(newCar)
Response.withBody(newCar)
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(
- SharafHandler(routes).withExceptionMapper(ExceptionMapper.json)
- )
- .build
+UndertowSharafServer("localhost", 8181, routes)
+ .withExceptionMapper(ExceptionMapper.json)
.start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/form_handling.sc b/examples/scala-cli/form_handling.sc
index 8bec4ef..36f24e7 100644
--- a/examples/scala-cli/form_handling.sc
+++ b/examples/scala-cli/form_handling.sc
@@ -1,11 +1,10 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.formson.FormDataRW
-import ba.sake.sharaf.*, routing.*
-
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -14,11 +13,7 @@ val routes = Routes:
val formData = Request.current.bodyForm[ContactUsForm]
Response.withBody(s"Got form data: ${formData}")
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println("Server started at http://localhost:8181")
diff --git a/examples/scala-cli/hello.sc b/examples/scala-cli/hello.sc
index cda7cff..c9d81eb 100644
--- a/examples/scala-cli/hello.sc
+++ b/examples/scala-cli/hello.sc
@@ -1,17 +1,13 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path("hello", name) =>
Response.withBody(s"Hello $name")
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/html_hepek.sc b/examples/scala-cli/html_hepek.sc
index 0ed2e54..5063c1c 100644
--- a/examples/scala-cli/html_hepek.sc
+++ b/examples/scala-cli/html_hepek.sc
@@ -1,10 +1,10 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import scalatags.Text.all.*
import ba.sake.hepek.html.HtmlPage
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.{*, given}
val routes = Routes:
case GET -> Path() =>
@@ -12,11 +12,7 @@ val routes = Routes:
case GET -> Path("hello", name) =>
Response.withBody(HelloView(name))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/html_scalatags.sc b/examples/scala-cli/html_scalatags.sc
index aea52e2..fa2e3ed 100644
--- a/examples/scala-cli/html_scalatags.sc
+++ b/examples/scala-cli/html_scalatags.sc
@@ -1,9 +1,9 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import scalatags.Text.all.*
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
@@ -11,11 +11,7 @@ val routes = Routes:
case GET -> Path("hello", name) =>
Response.withBody(HelloView(name))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/json_api.sc b/examples/scala-cli/json_api.sc
index 48e31ee..8bb2976 100644
--- a/examples/scala-cli/json_api.sc
+++ b/examples/scala-cli/json_api.sc
@@ -1,9 +1,18 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import ba.sake.tupson.JsonRW
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
+
+case class Car(brand: String, model: String, quantity: Int) derives JsonRW
+
+object CarsDb {
+ var db: Seq[Car] = Seq()
+ def findAll(): Seq[Car] = db
+ def findByBrand(brand: String): Seq[Car] = db.filter(_.brand == brand)
+ def add(car: Car): Unit = db = db.appended(car)
+}
val routes = Routes:
case GET -> Path("cars") =>
@@ -18,21 +27,8 @@ val routes = Routes:
CarsDb.add(reqBody)
Response.withBody(reqBody)
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(
- SharafHandler(routes).withExceptionMapper(ExceptionMapper.json)
- )
- .build
+UndertowSharafServer("localhost", 8181, routes)
+ .withExceptionMapper(ExceptionMapper.json)
.start()
println("Server started at http://localhost:8181")
-
-case class Car(brand: String, model: String, quantity: Int) derives JsonRW
-
-object CarsDb {
- var db: Seq[Car] = Seq()
- def findAll(): Seq[Car] = db
- def findByBrand(brand: String): Seq[Car] = db.filter(_.brand == brand)
- def add(car: Car): Unit = db = db.appended(car)
-}
\ No newline at end of file
diff --git a/examples/scala-cli/json_api.test.scala b/examples/scala-cli/json_api.test.scala
index 60f5eab..541e66e 100644
--- a/examples/scala-cli/json_api.test.scala
+++ b/examples/scala-cli/json_api.test.scala
@@ -1,6 +1,7 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
-//> using test.dep org.scalameta::munit::1.1.0
+//> using scala "3.7.0"
+//> using dep ba.sake::tupson:0.13.0
+//> using dep com.lihaoyi::requests:0.9.0
+//> using test.dep org.scalameta::munit::1.1.1
import ba.sake.tupson.*
@@ -15,7 +16,7 @@ class JsonApiSuite extends munit.FunSuite {
val res = requests.get(s"$baseUrl/cars")
val resBody = res.text.parseJson[Seq[Car]]
assertEquals(res.statusCode, 200)
- assertEquals(res.headers("content-type"), Seq("application/json"))
+ assertEquals(res.headers("content-type"), Seq("application/json; charset=utf-8"))
assertEquals(res.text.parseJson[Seq[Car]], Seq.empty)
}
@@ -29,7 +30,7 @@ class JsonApiSuite extends munit.FunSuite {
val res = requests.get(s"$baseUrl/cars/Mercedes")
val resBody = res.text.parseJson[Seq[Car]]
assertEquals(res.statusCode, 200)
- assertEquals(res.headers("content-type"), Seq("application/json"))
+ assertEquals(res.headers("content-type"), Seq("application/json; charset=utf-8"))
assertEquals(resBody, Seq(Car("Mercedes", "ML350", 1)))
}
}
diff --git a/examples/scala-cli/path_params.sc b/examples/scala-cli/path_params.sc
index 773861a..de1bb41 100644
--- a/examples/scala-cli/path_params.sc
+++ b/examples/scala-cli/path_params.sc
@@ -1,8 +1,8 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path("string", x) =>
@@ -11,10 +11,6 @@ val routes = Routes:
case GET -> Path("int", param[Int](x)) =>
Response.withBody(s"int = ${x}")
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/query_params.sc b/examples/scala-cli/query_params.sc
index a10663a..45f1868 100644
--- a/examples/scala-cli/query_params.sc
+++ b/examples/scala-cli/query_params.sc
@@ -1,10 +1,9 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import ba.sake.querson.QueryStringRW
-import ba.sake.sharaf.*, routing.*
-
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path("raw") =>
@@ -16,10 +15,6 @@ val routes = Routes:
val qp = Request.current.queryParams[SearchParams]
Response.withBody(s"params = ${qp}")
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/sql_db.sc b/examples/scala-cli/sql_db.sc
index 94f058f..63d9a6e 100644
--- a/examples/scala-cli/sql_db.sc
+++ b/examples/scala-cli/sql_db.sc
@@ -1,13 +1,13 @@
-//> using scala "3.6.4"
+//> using scala "3.7.0"
//> using dep org.postgresql:postgresql:42.7.5
//> using dep com.zaxxer:HikariCP:6.3.0
-//> using dep ba.sake::sharaf:0.9.2
+//> using dep ba.sake::sharaf-undertow:0.10.0
//> using dep ba.sake::squery:0.7.0
-import io.undertow.Undertow
import ba.sake.tupson.JsonRW
import ba.sake.squery.{*, given}
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val ds = com.zaxxer.hikari.HikariDataSource()
ds.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres")
@@ -35,10 +35,6 @@ val routes = Routes:
}
Response.withBody(customer)
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/static_files.sc b/examples/scala-cli/static_files.sc
index 575d6ce..c7d3acf 100644
--- a/examples/scala-cli/static_files.sc
+++ b/examples/scala-cli/static_files.sc
@@ -1,17 +1,13 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path() =>
Response.withBody("Try /example.js")
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(SharafHandler(routes))
- .build
- .start()
+UndertowSharafServer("localhost", 8181, routes).start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/scala-cli/validation.sc b/examples/scala-cli/validation.sc
index a574ab0..c60d393 100644
--- a/examples/scala-cli/validation.sc
+++ b/examples/scala-cli/validation.sc
@@ -1,11 +1,11 @@
-//> using scala "3.6.4"
-//> using dep ba.sake::sharaf:0.9.2
+//> using scala "3.7.0"
+//> using dep ba.sake::sharaf-undertow:0.10.0
-import io.undertow.Undertow
import ba.sake.querson.QueryStringRW
import ba.sake.tupson.JsonRW
import ba.sake.validson.Validator
-import ba.sake.sharaf.*, routing.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.undertow.UndertowSharafServer
val routes = Routes:
case GET -> Path("cars") =>
@@ -16,12 +16,8 @@ val routes = Routes:
val json = Request.current.bodyJsonValidated[Car]
Response.withBody(CarApiResult(s"JSON body OK: ${json}"))
-Undertow.builder
- .addHttpListener(8181, "localhost")
- .setHandler(
- SharafHandler(routes).withExceptionMapper(ExceptionMapper.json)
- )
- .build
+UndertowSharafServer("localhost", 8181, routes)
+ .withExceptionMapper(ExceptionMapper.json)
.start()
println(s"Server started at http://localhost:8181")
diff --git a/examples/snunit/README.md b/examples/snunit/README.md
new file mode 100644
index 0000000..3f5d3b3
--- /dev/null
+++ b/examples/snunit/README.md
@@ -0,0 +1,46 @@
+
+You need `clang` for Scala Native: `sudo apt install clang`.
+
+The following steps are done from root of this git repo.
+Build the app:
+
+```shell
+./mill -i examples.snunit.nativeLink
+```
+
+
+## Run and configure unitd
+
+```shell
+sudo unitd --no-daemon --log /dev/stdout --control unix:control.sock
+```
+
+Make `config.json` in with this content:
+
+```json
+{
+ "listeners": {
+ "*:8081": {
+ "pass": "applications/myapp"
+ }
+ },
+ "applications": {
+ "myapp": {
+ "type": "external",
+ "executable": "out/examples/snunit/nativeLink.dest/out"
+ }
+ }
+}
+```
+
+Then in another shell:
+
+```shell
+curl -X PUT --unix-socket control.sock -d @config.json localhost/config
+
+curl localhost:8081
+# should return "Hello Snunit!"
+```
+
+
+
diff --git a/examples/snunit/src/Main.scala b/examples/snunit/src/Main.scala
new file mode 100644
index 0000000..7087f01
--- /dev/null
+++ b/examples/snunit/src/Main.scala
@@ -0,0 +1,13 @@
+import ba.sake.sharaf.*
+import ba.sake.sharaf.snunit.*
+
+@main def main: Unit =
+
+ val routes = Routes { case _ =>
+ Response.withBody("Hello Snunit!")
+ }
+ val server = _root_.snunit.SyncServerBuilder
+ .setRequestHandler(SharafRequestHandler(routes))
+ .build()
+
+ server.listen()
diff --git a/mill b/mill
index d087ac0..555d7fc 100755
--- a/mill
+++ b/mill
@@ -1,20 +1,39 @@
#!/usr/bin/env sh
-# This is a wrapper script, that automatically download mill from GitHub release pages
-# You can give the required mill version with --mill-version parameter
-# If no version is given, it falls back to the value of DEFAULT_MILL_VERSION
+# This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages.
#
-# Original Project page: https://github.com/lefou/millw
-# Script Version: 0.4.12
+# This script determines the Mill version to use by trying these sources
+# - env-variable `MILL_VERSION`
+# - local file `.mill-version`
+# - local file `.config/mill-version`
+# - `mill-version` from YAML fronmatter of current buildfile
+# - if accessible, find the latest stable version available on Maven Central (https://repo1.maven.org/maven2)
+# - env-variable `DEFAULT_MILL_VERSION`
+#
+# If a version has the suffix '-native' a native binary will be used.
+# If a version has the suffix '-jvm' an executable jar file will be used, requiring an already installed Java runtime.
+# If no such suffix is found, the script will pick a default based on version and platform.
+#
+# Once a version was determined, it tries to use either
+# - a system-installed mill, if found and it's version matches
+# - an already downloaded version under ~/.cache/mill/download
+#
+# If no working mill version was found on the system,
+# this script downloads a binary file from Maven Central or Github Pages (this is version dependent)
+# into a cache location (~/.cache/mill/download).
+#
+# Mill Project URL: https://github.com/com-lihaoyi/mill
+# Script Version: 1.0.0-M1-49-ac90e3
#
# If you want to improve this script, please also contribute your changes back!
+# This script was generated from: dist/scripts/src/mill.sh
#
# Licensed under the Apache License, Version 2.0
set -e
if [ -z "${DEFAULT_MILL_VERSION}" ] ; then
- DEFAULT_MILL_VERSION="0.11.4"
+ DEFAULT_MILL_VERSION=0.12.14
fi
@@ -31,16 +50,17 @@ fi
# Explicit commandline argument takes precedence over all other methods
if [ "$1" = "--mill-version" ] ; then
- shift
- if [ "x$1" != "x" ] ; then
- MILL_VERSION="$1"
- shift
- else
- echo "You specified --mill-version without a version." 1>&2
- echo "Please provide a version that matches one provided on" 1>&2
- echo "${MILL_REPO_URL}/releases" 1>&2
- false
- fi
+ echo "The --mill-version option is no longer supported." 1>&2
+fi
+
+MILL_BUILD_SCRIPT=""
+
+if [ -f "build.mill" ] ; then
+ MILL_BUILD_SCRIPT="build.mill"
+elif [ -f "build.mill.scala" ] ; then
+ MILL_BUILD_SCRIPT="build.mill.scala"
+elif [ -f "build.sc" ] ; then
+ MILL_BUILD_SCRIPT="build.sc"
fi
# Please note, that if a MILL_VERSION is already set in the environment,
@@ -52,6 +72,8 @@ if [ -z "${MILL_VERSION}" ] ; then
MILL_VERSION="$(tr '\r' '\n' < .mill-version | head -n 1 2> /dev/null)"
elif [ -f ".config/mill-version" ] ; then
MILL_VERSION="$(tr '\r' '\n' < .config/mill-version | head -n 1 2> /dev/null)"
+ elif [ -n "${MILL_BUILD_SCRIPT}" ] ; then
+ MILL_VERSION="$(cat ${MILL_BUILD_SCRIPT} | grep '//[|] *mill-version: *' | sed 's;//| *mill-version: *;;')"
fi
fi
@@ -65,7 +87,7 @@ fi
if [ -z "${MILL_VERSION}" ] ; then
# TODO: try to load latest version from release page
echo "No mill version specified." 1>&2
- echo "You should provide a version via '.mill-version' file or --mill-version option." 1>&2
+ echo "You should provide a version via a '//| mill-version: ' comment or a '.mill-version' file." 1>&2
mkdir -p "${MILL_DOWNLOAD_PATH}"
LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || (
@@ -101,7 +123,60 @@ if [ -z "${MILL_VERSION}" ] ; then
fi
fi
-MILL="${MILL_DOWNLOAD_PATH}/${MILL_VERSION}"
+MILL_NATIVE_SUFFIX="-native"
+MILL_JVM_SUFFIX="-jvm"
+FULL_MILL_VERSION=$MILL_VERSION
+ARTIFACT_SUFFIX=""
+set_artifact_suffix(){
+ if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" = "Linux" ]; then
+ if [ "$(uname -m)" = "aarch64" ]; then
+ ARTIFACT_SUFFIX="-native-linux-aarch64"
+ else
+ ARTIFACT_SUFFIX="-native-linux-amd64"
+ fi
+ elif [ "$(uname)" = "Darwin" ]; then
+ if [ "$(uname -m)" = "arm64" ]; then
+ ARTIFACT_SUFFIX="-native-mac-aarch64"
+ else
+ ARTIFACT_SUFFIX="-native-mac-amd64"
+ fi
+ else
+ echo "This native mill launcher supports only Linux and macOS." 1>&2
+ exit 1
+ fi
+}
+
+case "$MILL_VERSION" in
+ *"$MILL_NATIVE_SUFFIX")
+ MILL_VERSION=${MILL_VERSION%"$MILL_NATIVE_SUFFIX"}
+ set_artifact_suffix
+ ;;
+
+ *"$MILL_JVM_SUFFIX")
+ MILL_VERSION=${MILL_VERSION%"$MILL_JVM_SUFFIX"}
+ ;;
+
+ *)
+ case "$MILL_VERSION" in
+ 0.1.*) ;;
+ 0.2.*) ;;
+ 0.3.*) ;;
+ 0.4.*) ;;
+ 0.5.*) ;;
+ 0.6.*) ;;
+ 0.7.*) ;;
+ 0.8.*) ;;
+ 0.9.*) ;;
+ 0.10.*) ;;
+ 0.11.*) ;;
+ 0.12.*) ;;
+ *)
+ set_artifact_suffix
+ esac
+ ;;
+esac
+
+MILL="${MILL_DOWNLOAD_PATH}/$MILL_VERSION$ARTIFACT_SUFFIX"
try_to_use_system_mill() {
if [ "$(uname)" != "Linux" ]; then
@@ -174,49 +249,59 @@ EOF
try_to_use_system_mill
# If not already downloaded, download it
-if [ ! -s "${MILL}" ] ; then
-
- # support old non-XDG download dir
- MILL_OLD_DOWNLOAD_PATH="${HOME}/.mill/download"
- OLD_MILL="${MILL_OLD_DOWNLOAD_PATH}/${MILL_VERSION}"
- if [ -x "${OLD_MILL}" ] ; then
- MILL="${OLD_MILL}"
+if [ ! -s "${MILL}" ] || [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then
+ case $MILL_VERSION in
+ 0.0.* | 0.1.* | 0.2.* | 0.3.* | 0.4.* )
+ DOWNLOAD_SUFFIX=""
+ DOWNLOAD_FROM_MAVEN=0
+ ;;
+ 0.5.* | 0.6.* | 0.7.* | 0.8.* | 0.9.* | 0.10.* | 0.11.0-M* )
+ DOWNLOAD_SUFFIX="-assembly"
+ DOWNLOAD_FROM_MAVEN=0
+ ;;
+ *)
+ DOWNLOAD_SUFFIX="-assembly"
+ DOWNLOAD_FROM_MAVEN=1
+ ;;
+ esac
+ case $MILL_VERSION in
+ 0.12.0 | 0.12.1 | 0.12.2 | 0.12.3 | 0.12.4 | 0.12.5 | 0.12.6 | 0.12.7 | 0.12.8 | 0.12.9 | 0.12.10 | 0.12.11 )
+ DOWNLOAD_EXT="jar"
+ ;;
+ 0.12.* )
+ DOWNLOAD_EXT="exe"
+ ;;
+ 0.* )
+ DOWNLOAD_EXT="jar"
+ ;;
+ *)
+ DOWNLOAD_EXT="exe"
+ ;;
+ esac
+
+ DOWNLOAD_FILE=$(mktemp mill.XXXXXX)
+ if [ "$DOWNLOAD_FROM_MAVEN" = "1" ] ; then
+ DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist${ARTIFACT_SUFFIX}/${MILL_VERSION}/mill-dist${ARTIFACT_SUFFIX}-${MILL_VERSION}.${DOWNLOAD_EXT}"
else
- case $MILL_VERSION in
- 0.0.* | 0.1.* | 0.2.* | 0.3.* | 0.4.* )
- DOWNLOAD_SUFFIX=""
- DOWNLOAD_FROM_MAVEN=0
- ;;
- 0.5.* | 0.6.* | 0.7.* | 0.8.* | 0.9.* | 0.10.* | 0.11.0-M* )
- DOWNLOAD_SUFFIX="-assembly"
- DOWNLOAD_FROM_MAVEN=0
- ;;
- *)
- DOWNLOAD_SUFFIX="-assembly"
- DOWNLOAD_FROM_MAVEN=1
- ;;
- esac
-
- DOWNLOAD_FILE=$(mktemp mill.XXXXXX)
-
- if [ "$DOWNLOAD_FROM_MAVEN" = "1" ] ; then
- DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist/${MILL_VERSION}/mill-dist-${MILL_VERSION}.jar"
- else
- MILL_VERSION_TAG=$(echo "$MILL_VERSION" | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/')
- DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}"
- unset MILL_VERSION_TAG
- fi
-
- # TODO: handle command not found
- echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2
- ${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}"
- chmod +x "${DOWNLOAD_FILE}"
- mkdir -p "${MILL_DOWNLOAD_PATH}"
- mv "${DOWNLOAD_FILE}" "${MILL}"
+ MILL_VERSION_TAG=$(echo "$MILL_VERSION" | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/')
+ DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}"
+ unset MILL_VERSION_TAG
+ fi
- unset DOWNLOAD_FILE
- unset DOWNLOAD_SUFFIX
+ if [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then
+ echo $DOWNLOAD_URL
+ echo $MILL
+ exit 0
fi
+ # TODO: handle command not found
+ echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2
+ ${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}"
+ chmod +x "${DOWNLOAD_FILE}"
+ mkdir -p "${MILL_DOWNLOAD_PATH}"
+ mv "${DOWNLOAD_FILE}" "${MILL}"
+
+ unset DOWNLOAD_FILE
+ unset DOWNLOAD_SUFFIX
fi
if [ -z "$MILL_MAIN_CLI" ] ; then
@@ -236,6 +321,7 @@ unset OLD_MILL
unset MILL_VERSION
unset MILL_REPO_URL
+# -D mill.main.cli is for compatibility with Mill 0.10.9 - 0.13.0-M2
# We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes
# shellcheck disable=SC2086
-exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"
\ No newline at end of file
+exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"
diff --git a/mill.bat b/mill.bat
index 6957369..85f9605 100644
--- a/mill.bat
+++ b/mill.bat
@@ -1,13 +1,32 @@
@echo off
-rem This is a wrapper script, that automatically download mill from GitHub release pages
-rem You can give the required mill version with --mill-version parameter
-rem If no version is given, it falls back to the value of DEFAULT_MILL_VERSION
+rem This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages.
rem
-rem Original Project page: https://github.com/lefou/millw
-rem Script Version: 0.4.12
+rem This script determines the Mill version to use by trying these sources
+rem - env-variable `MILL_VERSION`
+rem - local file `.mill-version`
+rem - local file `.config/mill-version`
+rem - `mill-version` from YAML fronmatter of current buildfile
+rem - if accessible, find the latest stable version available on Maven Central (https://repo1.maven.org/maven2)
+rem - env-variable `DEFAULT_MILL_VERSION`
+rem
+rem If a version has the suffix '-native' a native binary will be used.
+rem If a version has the suffix '-jvm' an executable jar file will be used, requiring an already installed Java runtime.
+rem If no such suffix is found, the script will pick a default based on version and platform.
+rem
+rem Once a version was determined, it tries to use either
+rem - a system-installed mill, if found and it's version matches
+rem - an already downloaded version under %USERPROFILE%\.mill\download
+rem
+rem If no working mill version was found on the system,
+rem this script downloads a binary file from Maven Central or Github Pages (this is version dependent)
+rem into a cache location (%USERPROFILE%\.mill\download).
+rem
+rem Mill Project URL: https://github.com/com-lihaoyi/mill
+rem Script Version: 1.0.0-M1-49-ac90e3
rem
rem If you want to improve this script, please also contribute your changes back!
+rem This script was generated from: dist/scripts/src/mill.bat
rem
rem Licensed under the Apache License, Version 2.0
@@ -15,153 +34,224 @@ rem setlocal seems to be unavailable on Windows 95/98/ME
rem but I don't think we need to support them in 2019
setlocal enabledelayedexpansion
-if [!DEFAULT_MILL_VERSION!]==[] (
- set "DEFAULT_MILL_VERSION=0.11.4"
-)
+if [!DEFAULT_MILL_VERSION!]==[] ( set "DEFAULT_MILL_VERSION=0.12.10" )
-if [!GITHUB_RELEASE_CDN!]==[] (
- set "GITHUB_RELEASE_CDN="
-)
+if [!MILL_GITHUB_RELEASE_CDN!]==[] ( set "MILL_GITHUB_RELEASE_CDN=" )
-if [!MILL_MAIN_CLI!]==[] (
- set "MILL_MAIN_CLI=%~f0"
-)
+if [!MILL_MAIN_CLI!]==[] ( set "MILL_MAIN_CLI=%~f0" )
set "MILL_REPO_URL=https://github.com/com-lihaoyi/mill"
-rem %~1% removes surrounding quotes
-if [%~1%]==[--mill-version] (
- if not [%~2%]==[] (
- set MILL_VERSION=%~2%
- rem shift command doesn't work within parentheses
- set "STRIP_VERSION_PARAMS=true"
- ) else (
- echo You specified --mill-version without a version. 1>&2
- echo Please provide a version that matches one provided on 1>&2
- echo %MILL_REPO_URL%/releases 1>&2
- exit /b 1
- )
-)
+SET MILL_BUILD_SCRIPT=
-if not defined STRIP_VERSION_PARAMS GOTO AfterStripVersionParams
-rem strip the: --mill-version {version}
-shift
-shift
-:AfterStripVersionParams
+if exist "build.mill" (
+ set MILL_BUILD_SCRIPT=build.mill
+) else (
+ if exist "build.mill.scala" (
+ set MILL_BUILD_SCRIPT=build.mill.scala
+ ) else (
+ if exist "build.sc" (
+ set MILL_BUILD_SCRIPT=build.sc
+ ) else (
+ rem no-op
+ )
+ )
+)
if [!MILL_VERSION!]==[] (
if exist .mill-version (
- set /p MILL_VERSION=<.mill-version
+ set /p MILL_VERSION=<.mill-version
) else (
if exist .config\mill-version (
set /p MILL_VERSION=<.config\mill-version
+ ) else (
+ if not "%MILL_BUILD_SCRIPT%"=="" (
+ for /f "tokens=1-2*" %%a in ('findstr /C:"//| mill-version:" %MILL_BUILD_SCRIPT%') do (
+ set "MILL_VERSION=%%c"
+ )
+ ) else (
+ rem no-op
+ )
)
)
)
-if [!MILL_VERSION!]==[] (
- set MILL_VERSION=%DEFAULT_MILL_VERSION%
-)
+if [!MILL_VERSION!]==[] set MILL_VERSION=%DEFAULT_MILL_VERSION%
-if [!MILL_DOWNLOAD_PATH!]==[] (
- set MILL_DOWNLOAD_PATH=%USERPROFILE%\.mill\download
-)
+if [!MILL_DOWNLOAD_PATH!]==[] set MILL_DOWNLOAD_PATH=%USERPROFILE%\.mill\download
rem without bat file extension, cmd doesn't seem to be able to run it
-set MILL=%MILL_DOWNLOAD_PATH%\!MILL_VERSION!.bat
-if not exist "%MILL%" (
- set VERSION_PREFIX=%MILL_VERSION:~0,4%
- rem Since 0.5.0
- set DOWNLOAD_SUFFIX=-assembly
- rem Since 0.11.0
- set DOWNLOAD_FROM_MAVEN=1
- if [!VERSION_PREFIX!]==[0.0.] (
- set DOWNLOAD_SUFFIX=
- set DOWNLOAD_FROM_MAVEN=0
- )
- if [!VERSION_PREFIX!]==[0.1.] (
- set DOWNLOAD_SUFFIX=
- set DOWNLOAD_FROM_MAVEN=0
- )
- if [!VERSION_PREFIX!]==[0.2.] (
- set DOWNLOAD_SUFFIX=
- set DOWNLOAD_FROM_MAVEN=0
- )
- if [!VERSION_PREFIX!]==[0.3.] (
- set DOWNLOAD_SUFFIX=
- set DOWNLOAD_FROM_MAVEN=0
- )
- if [!VERSION_PREFIX!]==[0.4.] (
- set DOWNLOAD_SUFFIX=
- set DOWNLOAD_FROM_MAVEN=0
+set "MILL_NATIVE_SUFFIX=-native"
+set "MILL_JVM_SUFFIX=-jvm"
+set "FULL_MILL_VERSION=%MILL_VERSION%"
+set "MILL_EXT=.bat"
+set "ARTIFACT_SUFFIX="
+REM Check if MILL_VERSION contains MILL_NATIVE_SUFFIX
+echo !MILL_VERSION! | findstr /C:"%MILL_NATIVE_SUFFIX%" >nul
+if !errorlevel! equ 0 (
+ set "MILL_VERSION=%MILL_VERSION:-native=%"
+ REM -native images compiled with graal do not support windows-arm
+ REM https://github.com/oracle/graal/issues/9215
+ IF /I NOT "%PROCESSOR_ARCHITECTURE%"=="ARM64" (
+ set "ARTIFACT_SUFFIX=-native-windows-amd64"
+ set "MILL_EXT=.exe"
+ ) else (
+ rem no-op
)
- if [!VERSION_PREFIX!]==[0.5.] (
- set DOWNLOAD_FROM_MAVEN=0
+) else (
+ echo !MILL_VERSION! | findstr /C:"%MILL_JVM_SUFFIX%" >nul
+ if !errorlevel! equ 0 (
+ set "MILL_VERSION=%MILL_VERSION:-jvm=%"
+ ) else (
+ set "SKIP_VERSION=false"
+ set "MILL_PREFIX=%MILL_VERSION:~0,4%"
+ if "!MILL_PREFIX!"=="0.1." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.2." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.3." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.4." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.5." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.6." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.7." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.8." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.9." set "SKIP_VERSION=true"
+ set "MILL_PREFIX=%MILL_VERSION:~0,5%"
+ if "!MILL_PREFIX!"=="0.10." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.11." set "SKIP_VERSION=true"
+ if "!MILL_PREFIX!"=="0.12." set "SKIP_VERSION=true"
+
+ if "!SKIP_VERSION!"=="false" (
+ IF /I NOT "%PROCESSOR_ARCHITECTURE%"=="ARM64" (
+ set "ARTIFACT_SUFFIX=-native-windows-amd64"
+ set "MILL_EXT=.exe"
+ )
+ ) else (
+ rem no-op
+ )
)
- if [!VERSION_PREFIX!]==[0.6.] (
- set DOWNLOAD_FROM_MAVEN=0
+)
+
+set MILL=%MILL_DOWNLOAD_PATH%\!FULL_MILL_VERSION!!MILL_EXT!
+
+set MILL_RESOLVE_DOWNLOAD=
+
+if not exist "%MILL%" (
+ set MILL_RESOLVE_DOWNLOAD=true
+) else (
+ if defined MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT (
+ set MILL_RESOLVE_DOWNLOAD=true
+ ) else (
+ rem no-op
)
- if [!VERSION_PREFIX!]==[0.7.] (
- set DOWNLOAD_FROM_MAVEN=0
+)
+
+
+if [!MILL_RESOLVE_DOWNLOAD!]==[true] (
+ set MILL_VERSION_PREFIX=%MILL_VERSION:~0,4%
+ set MILL_SHORT_VERSION_PREFIX=%MILL_VERSION:~0,2%
+ rem Since 0.5.0
+ set MILL_DOWNLOAD_SUFFIX=-assembly
+ rem Since 0.11.0
+ set MILL_DOWNLOAD_FROM_MAVEN=1
+ if [!MILL_VERSION_PREFIX!]==[0.0.] (
+ set MILL_DOWNLOAD_SUFFIX=
+ set MILL_DOWNLOAD_FROM_MAVEN=0
)
- if [!VERSION_PREFIX!]==[0.8.] (
- set DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.1.] (
+ set MILL_DOWNLOAD_SUFFIX=
+ set MILL_DOWNLOAD_FROM_MAVEN=0
)
- if [!VERSION_PREFIX!]==[0.9.] (
- set DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.2.] (
+ set MILL_DOWNLOAD_SUFFIX=
+ set MILL_DOWNLOAD_FROM_MAVEN=0
)
- set VERSION_PREFIX=%MILL_VERSION:~0,5%
- if [!VERSION_PREFIX!]==[0.10.] (
- set DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.3.] (
+ set MILL_DOWNLOAD_SUFFIX=
+ set MILL_DOWNLOAD_FROM_MAVEN=0
)
- set VERSION_PREFIX=%MILL_VERSION:~0,8%
- if [!VERSION_PREFIX!]==[0.11.0-M] (
- set DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.4.] (
+ set MILL_DOWNLOAD_SUFFIX=
+ set MILL_DOWNLOAD_FROM_MAVEN=0
)
- set VERSION_PREFIX=
+ if [!MILL_VERSION_PREFIX!]==[0.5.] set MILL_DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.6.] set MILL_DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.7.] set MILL_DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.8.] set MILL_DOWNLOAD_FROM_MAVEN=0
+ if [!MILL_VERSION_PREFIX!]==[0.9.] set MILL_DOWNLOAD_FROM_MAVEN=0
+
+ set MILL_VERSION_PREFIX=%MILL_VERSION:~0,5%
+ if [!MILL_VERSION_PREFIX!]==[0.10.] set MILL_DOWNLOAD_FROM_MAVEN=0
+
+ set MILL_VERSION_PREFIX=%MILL_VERSION:~0,8%
+ if [!MILL_VERSION_PREFIX!]==[0.11.0-M] set MILL_DOWNLOAD_FROM_MAVEN=0
+
+ set MILL_VERSION_PREFIX=%MILL_VERSION:~0,5%
+ set DOWNLOAD_EXT=exe
+ if [!MILL_SHORT_VERSION_PREFIX!]==[0.] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION_PREFIX!]==[0.12.] set DOWNLOAD_EXT=exe
+ if [!MILL_VERSION!]==[0.12.0] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.1] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.2] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.3] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.4] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.5] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.6] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.7] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.8] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.9] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.10] set DOWNLOAD_EXT=jar
+ if [!MILL_VERSION!]==[0.12.11] set DOWNLOAD_EXT=jar
+
+ set MILL_VERSION_PREFIX=
+ set MILL_SHORT_VERSION_PREFIX=
for /F "delims=- tokens=1" %%A in ("!MILL_VERSION!") do set MILL_VERSION_BASE=%%A
+ set MILL_VERSION_MILESTONE=
for /F "delims=- tokens=2" %%A in ("!MILL_VERSION!") do set MILL_VERSION_MILESTONE=%%A
- set VERSION_MILESTONE_START=!MILL_VERSION_MILESTONE:~0,1!
- if [!VERSION_MILESTONE_START!]==[M] (
- set MILL_VERSION_TAG="!MILL_VERSION_BASE!-!MILL_VERSION_MILESTONE!"
+ set MILL_VERSION_MILESTONE_START=!MILL_VERSION_MILESTONE:~0,1!
+ if [!MILL_VERSION_MILESTONE_START!]==[M] (
+ set MILL_VERSION_TAG=!MILL_VERSION_BASE!-!MILL_VERSION_MILESTONE!
) else (
set MILL_VERSION_TAG=!MILL_VERSION_BASE!
)
-
- rem there seems to be no way to generate a unique temporary file path (on native Windows)
- set DOWNLOAD_FILE=%MILL%.tmp
-
- if [!DOWNLOAD_FROM_MAVEN!]==[1] (
- set DOWNLOAD_URL=https://repo1.maven.org/maven2/com/lihaoyi/mill-dist/!MILL_VERSION!/mill-dist-!MILL_VERSION!.jar
+ if [!MILL_DOWNLOAD_FROM_MAVEN!]==[1] (
+ set MILL_DOWNLOAD_URL=https://repo1.maven.org/maven2/com/lihaoyi/mill-dist!ARTIFACT_SUFFIX!/!MILL_VERSION!/mill-dist!ARTIFACT_SUFFIX!-!MILL_VERSION!.!DOWNLOAD_EXT!
) else (
- set DOWNLOAD_URL=!GITHUB_RELEASE_CDN!%MILL_REPO_URL%/releases/download/!MILL_VERSION_TAG!/!MILL_VERSION!!DOWNLOAD_SUFFIX!
+ set MILL_DOWNLOAD_URL=!MILL_GITHUB_RELEASE_CDN!%MILL_REPO_URL%/releases/download/!MILL_VERSION_TAG!/!MILL_VERSION!!MILL_DOWNLOAD_SUFFIX!
+ )
+
+ if defined MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT (
+ echo !MILL_DOWNLOAD_URL!
+ echo !MILL!
+ exit /b 0
)
- echo Downloading mill %MILL_VERSION% from !DOWNLOAD_URL! ... 1>&2
+ rem there seems to be no way to generate a unique temporary file path (on native Windows)
+ set MILL_DOWNLOAD_FILE=%MILL%.tmp
+
+ echo Downloading mill !MILL_VERSION! from !MILL_DOWNLOAD_URL! ... 1>&2
if not exist "%MILL_DOWNLOAD_PATH%" mkdir "%MILL_DOWNLOAD_PATH%"
rem curl is bundled with recent Windows 10
rem but I don't think we can expect all the users to have it in 2019
where /Q curl
- if %ERRORLEVEL% EQU 0 (
- curl -f -L "!DOWNLOAD_URL!" -o "!DOWNLOAD_FILE!"
+ if !ERRORLEVEL! EQU 0 (
+ curl -f -L "!MILL_DOWNLOAD_URL!" -o "!MILL_DOWNLOAD_FILE!"
) else (
rem bitsadmin seems to be available on Windows 7
rem without /dynamic, github returns 403
rem bitsadmin is sometimes needlessly slow but it looks better with /priority foreground
- bitsadmin /transfer millDownloadJob /dynamic /priority foreground "!DOWNLOAD_URL!" "!DOWNLOAD_FILE!"
+ bitsadmin /transfer millDownloadJob /dynamic /priority foreground "!MILL_DOWNLOAD_URL!" "!MILL_DOWNLOAD_FILE!"
)
- if not exist "!DOWNLOAD_FILE!" (
- echo Could not download mill %MILL_VERSION% 1>&2
+ if not exist "!MILL_DOWNLOAD_FILE!" (
+ echo Could not download mill !MILL_VERSION! 1>&2
exit /b 1
)
- move /y "!DOWNLOAD_FILE!" "%MILL%"
+ move /y "!MILL_DOWNLOAD_FILE!" "%MILL%"
- set DOWNLOAD_FILE=
- set DOWNLOAD_SUFFIX=
+ set MILL_DOWNLOAD_FILE=
+ set MILL_DOWNLOAD_SUFFIX=
)
set MILL_DOWNLOAD_PATH=
@@ -197,24 +287,10 @@ if [%~1%]==[--bsp] (
set "MILL_PARAMS=%*%"
if not [!MILL_FIRST_ARG!]==[] (
- if defined STRIP_VERSION_PARAMS (
- for /f "tokens=1-3*" %%a in ("%*") do (
- set "MILL_PARAMS=%%d"
- )
- ) else (
- for /f "tokens=1*" %%a in ("%*") do (
- set "MILL_PARAMS=%%b"
- )
- )
-) else (
- if defined STRIP_VERSION_PARAMS (
- for /f "tokens=1-2*" %%a in ("%*") do (
- rem strip %%a - It's the "--mill-version" option.
- rem strip %%b - it's the version number that comes after the option.
- rem keep %%c - It's the remaining options.
- set "MILL_PARAMS=%%c"
- )
+ for /f "tokens=1*" %%a in ("%*") do (
+ set "MILL_PARAMS=%%b"
)
)
-"%MILL%" %MILL_FIRST_ARG% -D "mill.main.cli=%MILL_MAIN_CLI%" %MILL_PARAMS%
\ No newline at end of file
+rem -D mill.main.cli is for compatibility with Mill 0.10.9 - 0.13.0-M2
+"%MILL%" %MILL_FIRST_ARG% -D "mill.main.cli=%MILL_MAIN_CLI%" %MILL_PARAMS%
diff --git a/sharaf-snunit/src/ba/sake/sharaf/snunit/ResponseUtils.scala b/sharaf-snunit/src/ba/sake/sharaf/snunit/ResponseUtils.scala
new file mode 100644
index 0000000..3c40e78
--- /dev/null
+++ b/sharaf-snunit/src/ba/sake/sharaf/snunit/ResponseUtils.scala
@@ -0,0 +1,3 @@
+package ba.sake.sharaf.snunit
+
+
diff --git a/sharaf-snunit/src/ba/sake/sharaf/snunit/SharafRequestHandler.scala b/sharaf-snunit/src/ba/sake/sharaf/snunit/SharafRequestHandler.scala
new file mode 100644
index 0000000..412e538
--- /dev/null
+++ b/sharaf-snunit/src/ba/sake/sharaf/snunit/SharafRequestHandler.scala
@@ -0,0 +1,51 @@
+package ba.sake.sharaf.snunit
+
+import snunit.{Request as SnunitRequest, *}
+import ba.sake.sharaf.*
+import ba.sake.sharaf.routing.*
+import java.io.ByteArrayOutputStream
+
+class SharafRequestHandler(routes: Routes) extends RequestHandler {
+ override def handleRequest(snunitRequest: SnunitRequest): Unit = {
+ given Request = SnunitSharafRequest.create(snunitRequest)
+ val reqParams = fillReqParams(snunitRequest)
+ routes.definition.lift(reqParams) match {
+ case Some(res) =>
+ val headers = buildHeaders(res.headerUpdates)
+ res.body match {
+ case Some(body) =>
+ val aos = new ByteArrayOutputStream
+ res.rw.write(body, aos)
+ send(snunitRequest)(StatusCode(res.status.code), aos.toByteArray(), headers)
+ case None =>
+ send(snunitRequest)(StatusCode(res.status.code), "", headers)
+ }
+ case None =>
+ // will be catched by ExceptionHandler
+ throw exceptions.NotFoundException("route")
+ }
+ }
+
+ private def buildHeaders(hu: HeaderUpdates): Headers = {
+ val headerValues = hu.updates.flatMap {
+ case HeaderUpdate.Set(name, values) =>
+ Seq(name.value -> values.head)
+ case _ => Seq.empty
+ }
+ Headers(headerValues*)
+ }
+
+ private def fillReqParams(req: SnunitRequest): RequestParams = {
+ val method = HttpMethod.valueOf(req.method)
+ val originalPath = req.path
+ val relPath =
+ if originalPath.startsWith("/") then originalPath.drop(1)
+ else originalPath
+ val pathSegments = relPath.split("/")
+ val path =
+ if pathSegments.size == 1 && pathSegments.head == ""
+ then Path()
+ else Path(pathSegments*)
+ (method, path)
+ }
+}
diff --git a/sharaf-snunit/src/ba/sake/sharaf/snunit/SnunitSharafRequest.scala b/sharaf-snunit/src/ba/sake/sharaf/snunit/SnunitSharafRequest.scala
new file mode 100644
index 0000000..e2ae99b
--- /dev/null
+++ b/sharaf-snunit/src/ba/sake/sharaf/snunit/SnunitSharafRequest.scala
@@ -0,0 +1,44 @@
+package ba.sake.sharaf.snunit
+
+import java.nio.charset.StandardCharsets
+import scala.jdk.CollectionConverters.*
+import scala.jdk.StreamConverters.*
+import snunit.{Request as SnunitRequest, *}
+import ba.sake.formson.*
+import ba.sake.querson.*
+import ba.sake.sharaf.*
+import ba.sake.sharaf.exceptions.*
+
+class SnunitSharafRequest(underlyingRequest: SnunitRequest) extends Request {
+
+ /* *** HEADERS *** */
+ def headers: Map[HttpString, Seq[String]] =
+ val underlyingHeaders = underlyingRequest.headers
+ underlyingHeaders.toMap
+ .map { (headerName, headerValue) =>
+ HttpString(headerName) -> Seq(headerValue)
+ }
+
+ def cookies: Seq[Cookie] = ??? // TODO
+ // underlyingHttpServerExchange.requestCookies().asScala.map(CookieUtils.fromUndertow).toSeq
+
+ /* *** QUERY *** */
+ override lazy val queryParamsRaw: QueryStringMap =
+ underlyingRequest.query.split("&").flatMap( _.split("=") match {
+ case Array(key, value) => Seq(key -> Seq(value))
+ case _ => Seq.empty
+ })
+ .toMap
+
+ /* *** BODY *** */
+ override lazy val bodyString: String =
+ String(underlyingRequest.contentRaw(), StandardCharsets.UTF_8)
+
+ def bodyFormRaw: FormDataMap = ??? // TODO
+}
+
+object SnunitSharafRequest {
+
+ def create(underlyingRequest: SnunitRequest): SnunitSharafRequest =
+ SnunitSharafRequest(underlyingRequest)
+}
diff --git a/sharaf-snunit/test/src/.gitkeep b/sharaf-snunit/test/src/.gitkeep
new file mode 100644
index 0000000..e69de29