From 2f218d0d744581d6d3f771b67767cf4d680f0bcd Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Thu, 23 Oct 2025 09:52:41 +0100 Subject: [PATCH 01/11] Mill build --- .github/workflows/ci.yml | 3 +- .github/workflows/manual-build-all.yml | 34 -- .jvmopts | 4 - build.mill | 118 +++++ build.sbt | 451 ------------------ build.sh | 8 +- flake.nix | 9 +- localbuild.sh | 6 +- mill | 339 +++++++++++++ project/Dependancies.scala | 18 - project/Misc.scala | 40 -- project/TyrianVersion.scala | 27 -- project/build.properties | 1 - project/plugins.sbt | 12 - project/project/plugins.sbt | 1 - release.sh | 8 +- sandbox-next/package.mill | 18 + .../scala => src-js}/example/AppEvent.scala | 0 .../scala => src-js}/example/Counter.scala | 0 .../example/CounterManager.scala | 0 .../scala => src-js}/example/MarkerIds.scala | 0 .../main/scala => src-js}/example/Model.scala | 0 .../example/SandboxNext.scala | 0 .../example/TextReverse.scala | 0 .../scala => src-js}/example/TopNav.scala | 0 sandbox-next/tyrianapp.js | 2 +- sandbox-ssr/package.mill | 23 + .../example/CorvidDatabase.scala | 0 .../example/GameOfLife.scala | 0 .../example/InfiniteScroll.scala | 0 .../scala => src-jvm}/example/Routes.scala | 0 .../example/SandboxSSR.scala | 0 .../example/SearchPage.scala | 0 .../example/TabbedPage.scala | 0 .../example/WebSocketsPage.scala | 0 sandbox-zio/package.mill | 22 + .../scala => src-js}/example/SandboxZIO.scala | 0 sandbox-zio/tyrianapp.js | 2 +- sandbox/package.mill | 17 + .../scala => src-js}/example/Sandbox.scala | 0 sandbox/tyrianapp.js | 2 +- .../src/test/scala/tyrian/HttpTests.scala | 108 ----- .../src/test/scala/tyrian/ChromeTests.scala | 31 -- .../src/test/scala/tyrian/FirefoxTests.scala | 32 -- .../HtmxAttributes.mill | 20 +- tyrian-htmx/package.mill | 52 ++ .../scala => src}/tyrian/htmx/Event.scala | 0 .../main/scala => src}/tyrian/htmx/Html.scala | 0 .../scala => src}/tyrian/htmx/Modifier.scala | 0 .../scala => src}/tyrian/htmx/Trigger.scala | 0 tyrian-io/package.mill | 21 + .../scala => src-js}/tyrian/TyrianIOApp.scala | 0 tyrian-next/package.mill | 21 + .../scala => src-js}/tyrian/next/Action.scala | 0 .../scala => src-js}/tyrian/next/Batch.scala | 0 .../tyrian/next/GlobalMsg.scala | 0 .../tyrian/next/HtmlFragment.scala | 0 .../tyrian/next/HtmlRoot.scala | 0 .../scala => src-js}/tyrian/next/Marker.scala | 0 .../tyrian/next/MarkerId.scala | 0 .../tyrian/next/Outcome.scala | 0 .../tyrian/next/TyrianNext.scala | 0 .../tyrian/next/Watcher.scala | 0 .../scala => src-js}/tyrian/next/syntax.scala | 0 .../src-js}/tyrian/next/ActionTests.scala | 0 .../tyrian/next/ActionWatchUtils.scala | 0 .../tyrian/next/BatchSpecification.scala | 0 .../src-js}/tyrian/next/BatchTests.scala | 0 .../tyrian/next/HtmlFragmentTests.scala | 0 .../src-js}/tyrian/next/HtmlRootTests.scala | 0 .../src-js}/tyrian/next/OutcomeTests.scala | 0 .../src-js}/tyrian/next/WatcherTests.scala | 0 .../AttributeGen.mill | 13 +- .../CSSGen.scala => tyrian-tags/CSSGen.mill | 13 +- .../CompleteHtmlEntityLists.mill | 16 +- .../HtmlEntityGen.mill | 13 +- .../TagGen.scala => tyrian-tags/TagGen.mill | 139 +++--- .../js/src/main/scala/tyrian/syntax.scala | 11 - tyrian-tags/package.mill | 50 ++ .../tyrian/LocationPlatform.scala | 0 .../main/scala => src-js}/tyrian/Tyrian.scala | 0 tyrian-tags/src-js/tyrian/syntax.scala | 13 + .../tyrian/LocationPlatform.scala | 0 .../scala => src-jvm}/tyrian/Tyrian.scala | 0 .../src/main/scala => src}/tyrian/Attr.scala | 0 .../scala => src}/tyrian/HTMLRendering.scala | 0 .../src/main/scala => src}/tyrian/Html.scala | 0 .../main/scala => src}/tyrian/Location.scala | 0 .../tyrian/LocationDetails.scala | 0 .../src/main/scala => src}/tyrian/Style.scala | 0 .../src-js}/tyrian/HtmlTests.scala | 2 +- .../scala => test/src}/tyrian/AttrTests.scala | 0 .../src}/tyrian/HTMLRenderingTests.scala | 0 .../src}/tyrian/LocationDetailsTests.scala | 0 .../src}/tyrian/LocationTests.scala | 0 .../src}/tyrian/StyleTests.scala | 0 tyrian-zio/package.mill | 22 + .../tyrian/TyrianZIOApp.scala | 0 tyrian/package.mill | 23 + .../main/scala => src-js}/tyrian/Cmd.scala | 0 .../scala => src-js}/tyrian/HotReload.scala | 0 .../main/scala => src-js}/tyrian/Nav.scala | 0 .../scala => src-js}/tyrian/Routing.scala | 0 .../main/scala => src-js}/tyrian/Sub.scala | 0 .../scala => src-js}/tyrian/TyrianApp.scala | 0 .../scala => src-js}/tyrian/cmds/Dom.scala | 0 .../tyrian/cmds/Download.scala | 0 .../scala => src-js}/tyrian/cmds/File.scala | 0 .../tyrian/cmds/FileReader.scala | 0 .../tyrian/cmds/ImageLoader.scala | 0 .../tyrian/cmds/LocalStorage.scala | 0 .../scala => src-js}/tyrian/cmds/Logger.scala | 0 .../scala => src-js}/tyrian/cmds/Random.scala | 0 .../tyrian/http/Decoder.scala | 0 .../scala => src-js}/tyrian/http/Http.scala | 0 .../scala => src-js}/tyrian/http/Models.scala | 0 .../tyrian/http/Request.scala | 0 .../tyrian/runtime/CmdHelper.scala | 0 .../tyrian/runtime/Renderer.scala | 0 .../tyrian/runtime/RendererState.scala | 0 .../tyrian/runtime/Rendering.scala | 0 .../tyrian/runtime/SubHelper.scala | 0 .../tyrian/runtime/TyrianRuntime.scala | 0 .../main/scala => src-js}/tyrian/syntax.scala | 4 +- .../tyrian/websocket/WebSocket.scala | 0 .../tyrian/websocket/WebSocketEvent.scala | 0 .../scala => src-js}/util/Functions.scala | 0 .../src-js}/tyrian/CmdLawsTest.scala | 0 .../src-js}/tyrian/CmdSubUtils.scala | 0 .../src-js}/tyrian/CmdTests.scala | 0 .../src-js}/tyrian/SubLawsTest.scala | 0 .../src-js}/tyrian/SubTests.scala | 0 .../src-js}/tyrian/cmds/RandomTests.scala | 0 133 files changed, 880 insertions(+), 889 deletions(-) delete mode 100644 .github/workflows/manual-build-all.yml delete mode 100644 .jvmopts create mode 100644 build.mill delete mode 100644 build.sbt create mode 100755 mill delete mode 100644 project/Dependancies.scala delete mode 100644 project/Misc.scala delete mode 100644 project/TyrianVersion.scala delete mode 100644 project/build.properties delete mode 100644 project/plugins.sbt delete mode 100644 project/project/plugins.sbt create mode 100644 sandbox-next/package.mill rename sandbox-next/{src/main/scala => src-js}/example/AppEvent.scala (100%) rename sandbox-next/{src/main/scala => src-js}/example/Counter.scala (100%) rename sandbox-next/{src/main/scala => src-js}/example/CounterManager.scala (100%) rename sandbox-next/{src/main/scala => src-js}/example/MarkerIds.scala (100%) rename sandbox-next/{src/main/scala => src-js}/example/Model.scala (100%) rename sandbox-next/{src/main/scala => src-js}/example/SandboxNext.scala (100%) rename sandbox-next/{src/main/scala => src-js}/example/TextReverse.scala (100%) rename sandbox-next/{src/main/scala => src-js}/example/TopNav.scala (100%) create mode 100644 sandbox-ssr/package.mill rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/CorvidDatabase.scala (100%) rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/GameOfLife.scala (100%) rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/InfiniteScroll.scala (100%) rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/Routes.scala (100%) rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/SandboxSSR.scala (100%) rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/SearchPage.scala (100%) rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/TabbedPage.scala (100%) rename sandbox-ssr/{.jvm/src/main/scala => src-jvm}/example/WebSocketsPage.scala (100%) create mode 100644 sandbox-zio/package.mill rename sandbox-zio/{src/main/scala => src-js}/example/SandboxZIO.scala (100%) create mode 100644 sandbox/package.mill rename sandbox/{src/main/scala => src-js}/example/Sandbox.scala (100%) delete mode 100644 tyrian-browser-tests/src/test/scala/tyrian/HttpTests.scala delete mode 100644 tyrian-chrome-tests/src/test/scala/tyrian/ChromeTests.scala delete mode 100644 tyrian-firefox-tests/src/test/scala/tyrian/FirefoxTests.scala rename project/HtmxAttributes.scala => tyrian-htmx/HtmxAttributes.mill (88%) create mode 100644 tyrian-htmx/package.mill rename tyrian-htmx/{shared/src/main/scala => src}/tyrian/htmx/Event.scala (100%) rename tyrian-htmx/{shared/src/main/scala => src}/tyrian/htmx/Html.scala (100%) rename tyrian-htmx/{shared/src/main/scala => src}/tyrian/htmx/Modifier.scala (100%) rename tyrian-htmx/{shared/src/main/scala => src}/tyrian/htmx/Trigger.scala (100%) create mode 100644 tyrian-io/package.mill rename tyrian-io/{src/main/scala => src-js}/tyrian/TyrianIOApp.scala (100%) create mode 100644 tyrian-next/package.mill rename tyrian-next/{src/main/scala => src-js}/tyrian/next/Action.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/Batch.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/GlobalMsg.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/HtmlFragment.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/HtmlRoot.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/Marker.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/MarkerId.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/Outcome.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/TyrianNext.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/Watcher.scala (100%) rename tyrian-next/{src/main/scala => src-js}/tyrian/next/syntax.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/ActionTests.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/ActionWatchUtils.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/BatchSpecification.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/BatchTests.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/HtmlFragmentTests.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/HtmlRootTests.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/OutcomeTests.scala (100%) rename tyrian-next/{src/test/scala => test/src-js}/tyrian/next/WatcherTests.scala (100%) rename project/AttributeGen.scala => tyrian-tags/AttributeGen.mill (98%) rename project/CSSGen.scala => tyrian-tags/CSSGen.mill (96%) rename project/CompleteHtmlEntityLists.scala => tyrian-tags/CompleteHtmlEntityLists.mill (99%) rename project/HtmlEntityGen.scala => tyrian-tags/HtmlEntityGen.mill (76%) rename project/TagGen.scala => tyrian-tags/TagGen.mill (75%) delete mode 100644 tyrian-tags/js/src/main/scala/tyrian/syntax.scala create mode 100644 tyrian-tags/package.mill rename tyrian-tags/{js/src/main/scala => src-js}/tyrian/LocationPlatform.scala (100%) rename tyrian-tags/{js/src/main/scala => src-js}/tyrian/Tyrian.scala (100%) create mode 100644 tyrian-tags/src-js/tyrian/syntax.scala rename tyrian-tags/{jvm/src/main/scala => src-jvm}/tyrian/LocationPlatform.scala (100%) rename tyrian-tags/{jvm/src/main/scala => src-jvm}/tyrian/Tyrian.scala (100%) rename tyrian-tags/{shared/src/main/scala => src}/tyrian/Attr.scala (100%) rename tyrian-tags/{shared/src/main/scala => src}/tyrian/HTMLRendering.scala (100%) rename tyrian-tags/{shared/src/main/scala => src}/tyrian/Html.scala (100%) rename tyrian-tags/{shared/src/main/scala => src}/tyrian/Location.scala (100%) rename tyrian-tags/{shared/src/main/scala => src}/tyrian/LocationDetails.scala (100%) rename tyrian-tags/{shared/src/main/scala => src}/tyrian/Style.scala (100%) rename tyrian-tags/{js/src/test/scala => test/src-js}/tyrian/HtmlTests.scala (98%) rename tyrian-tags/{shared/src/test/scala => test/src}/tyrian/AttrTests.scala (100%) rename tyrian-tags/{shared/src/test/scala => test/src}/tyrian/HTMLRenderingTests.scala (100%) rename tyrian-tags/{shared/src/test/scala => test/src}/tyrian/LocationDetailsTests.scala (100%) rename tyrian-tags/{shared/src/test/scala => test/src}/tyrian/LocationTests.scala (100%) rename tyrian-tags/{shared/src/test/scala => test/src}/tyrian/StyleTests.scala (100%) create mode 100644 tyrian-zio/package.mill rename tyrian-zio/{src/main/scala => src-js}/tyrian/TyrianZIOApp.scala (100%) create mode 100644 tyrian/package.mill rename tyrian/{src/main/scala => src-js}/tyrian/Cmd.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/HotReload.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/Nav.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/Routing.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/Sub.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/TyrianApp.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/Dom.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/Download.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/File.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/FileReader.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/ImageLoader.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/LocalStorage.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/Logger.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/cmds/Random.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/http/Decoder.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/http/Http.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/http/Models.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/http/Request.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/runtime/CmdHelper.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/runtime/Renderer.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/runtime/RendererState.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/runtime/Rendering.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/runtime/SubHelper.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/runtime/TyrianRuntime.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/syntax.scala (87%) rename tyrian/{src/main/scala => src-js}/tyrian/websocket/WebSocket.scala (100%) rename tyrian/{src/main/scala => src-js}/tyrian/websocket/WebSocketEvent.scala (100%) rename tyrian/{src/main/scala => src-js}/util/Functions.scala (100%) rename tyrian/{src/test/scala => test/src-js}/tyrian/CmdLawsTest.scala (100%) rename tyrian/{src/test/scala => test/src-js}/tyrian/CmdSubUtils.scala (100%) rename tyrian/{src/test/scala => test/src-js}/tyrian/CmdTests.scala (100%) rename tyrian/{src/test/scala => test/src-js}/tyrian/SubLawsTest.scala (100%) rename tyrian/{src/test/scala => test/src-js}/tyrian/SubTests.scala (100%) rename tyrian/{src/test/scala => test/src-js}/tyrian/cmds/RandomTests.scala (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4069da1..8a88d452 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,5 @@ jobs: - uses: coursier/setup-action@v1 with: java-version: adopt@1.11 - - uses: sbt/setup-sbt@v1 - name: Tyrian Compile & Test - run: sbt clean compile scalafmtCheckAll test + run: bash build.sh diff --git a/.github/workflows/manual-build-all.yml b/.github/workflows/manual-build-all.yml deleted file mode 100644 index d09a9366..00000000 --- a/.github/workflows/manual-build-all.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Manual Build All -on: [workflow_dispatch] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: olafurpg/setup-scala@v11 - with: - java-version: adopt@1.11 - - uses: jodersky/setup-mill@master - with: - mill-version: 0.10.10 - - uses: sbt/setup-sbt@v1 - - name: Tyrian Compile & Test - run: sbt compile scalafmtCheckAll test +publishLocal gendocs - - name: Build SBT Examples - run: | - pwd - cd examples - sbt buildExamples - - name: Build Mill Examples - run: | - pwd - cd examples/mill - mill counter.compile - mill counter.test - - name: Build Server Examples - run: | - pwd - cd examples/server-examples - export NODE_OPTIONS=--openssl-legacy-provider - sbt buildAll - diff --git a/.jvmopts b/.jvmopts deleted file mode 100644 index 3457f79c..00000000 --- a/.jvmopts +++ /dev/null @@ -1,4 +0,0 @@ --Xss8m --Xms1G --Xmx8G --XX:+UseG1GC diff --git a/build.mill b/build.mill new file mode 100644 index 00000000..477d6a19 --- /dev/null +++ b/build.mill @@ -0,0 +1,118 @@ +//| mill-version: 1.0.6 +//| mvnDeps: [ +//| "com.goyeau::mill-scalafix::0.6.0", +//| "org.typelevel::scalac-options:0.1.8" +//| ] + +package build + +import mill.* +import mill.scalalib.* +import mill.scalalib.publish.* +import mill.scalalib.scalafmt.* +import mill.scalajslib.* +import mill.api.BuildCtx +import org.typelevel.scalacoptions.* +import com.goyeau.mill.scalafix.ScalafixModule + +trait Shared extends ScalafmtModule, ScalafixModule: + def scalaVersion = "3.7.3" + + override def scalacOptions = Task { + super.scalacOptions() ++ + ScalacOptions.tokensForVersion( + ScalaVersion.unsafeFromString(scalaVersion()), + ScalacOptions.default ++ ScalacOptions.fatalWarningOptions + ) + } + +trait SharedJVM extends Shared, ScalaModule: + object test extends ScalaTests: + def mvnDeps = Seq( + mvn"org.scalameta::munit::1.2.0", + mvn"org.typelevel::munit-cats-effect::${Dependencies.munitCatsEffect3}", + mvn"org.typelevel::discipline-munit::${Dependencies.disciplineMUnit}", + mvn"org.typelevel::cats-laws::${Dependencies.catsLaws}" + ) + + def testFramework = Task("munit.Framework") + +trait SharedJS extends Shared, ScalaJSModule: + def scalaJSVersion = Task("1.20.1") + + object test extends ScalaJSTests: + def mvnDeps = Seq( + mvn"org.scalameta::munit::1.2.0", + mvn"org.typelevel::munit-cats-effect::${Dependencies.munitCatsEffect3}", + mvn"org.typelevel::discipline-munit::${Dependencies.disciplineMUnit}", + mvn"org.typelevel::cats-laws::${Dependencies.catsLaws}" + ) + + override def moduleKind = Task(mill.scalajslib.api.ModuleKind.CommonJSModule) + + def testFramework = Task("munit.Framework") + +trait SharedPublish extends PublishModule: + + def tyrianVersion = Task.Input(TyrianVersion.getVersion(BuildCtx.workspaceRoot)) + + def publishVersion = tyrianVersion() + + def pomSettings = + PomSettings( + description = "tyrian", + organization = "io.indigoengine", + url = "https://github.com/PurpleKingdomGames/tyrian", + licenses = Seq(License.MIT), + versionControl = VersionControl.github("PurpleKingdomGames", "tyrian"), + developers = Seq( + Developer("davesmith00000", "David Smith", "https://github.com/davesmith00000") + ) + ) + +// --- Utils --- + +object TyrianVersion: + + def getVersion(workspaceDir: os.Path): String = { + def rec(wd: os.Path, file: String, levels: Int, version: Option[String]): String = { + val msg = "ERROR: Couldn't find tyrian version." + version match { + case Some(v) => + println(s"""Tyrian version set to '$v'""") + v + + case None if levels < 3 => + try { + val v = os.read.lines(wd / file).head + rec(wd, file, levels, Some(v)) + } catch { + case _: Throwable => + rec(wd / os.RelPath.up, file, levels + 1, None) + } + + case None => + println(msg) + throw new Exception(msg) + } + } + + rec(workspaceDir, ".tyrian-version", 0, None) + } + +object Dependencies: + + val catsEffect = "3.6.3" + val circe = "0.14.15" + val fs2 = "3.12.2" + val scalajsDomVersion = "2.8.1" + val munitCatsEffect3 = "2.1.0" + val disciplineMUnit = "2.0.0" + val scalajsSnabbdom = "0.2.0-M3" + val zio = "2.1.21" + val zioInteropCats = "23.1.0.5" + val scalaJavaTime = "2.6.0" + val catsLaws = "2.13.0" + val http4sCirce = "0.23.30" + val http4sDom = "0.2.11" + val http4sServer = "0.23.32" diff --git a/build.sbt b/build.sbt deleted file mode 100644 index e8465744..00000000 --- a/build.sbt +++ /dev/null @@ -1,451 +0,0 @@ -import Misc._ - -import scala.language.postfixOps -import org.openqa.selenium.chrome.ChromeOptions -import org.openqa.selenium.firefox.FirefoxOptions -import org.scalajs.jsenv.selenium.SeleniumJSEnv -import org.typelevel.scalacoptions.ScalacOptions - -Global / onChangedBuildSource := ReloadOnSourceChanges -Global / semanticdbEnabled := true - -Global / resolvers += "Sonatype S01 OSS Snapshots" at "https://s01.oss.sonatype.org/content/repositories/snapshots" - -ThisBuild / versionScheme := Some("early-semver") - -ThisBuild / scalaVersion := scala3Version - -lazy val tyrianVersion = TyrianVersion.getVersion -lazy val scala3Version = "3.7.3" - -lazy val commonSettings: Seq[sbt.Def.Setting[?]] = Seq( - version := tyrianVersion, - organization := "io.indigoengine", - libraryDependencies ++= Seq( - "org.typelevel" %%% "munit-cats-effect" % Dependencies.munitCatsEffect3 % Test, - "org.typelevel" %%% "discipline-munit" % Dependencies.disciplineMUnit % Test, - "org.typelevel" %%% "cats-laws" % Dependencies.catsLaws % Test - ), - testFrameworks += new TestFramework("munit.Framework"), - scalacOptions ++= Seq("-language:strictEquality"), - scalafixOnCompile := true, - semanticdbEnabled := true, - semanticdbVersion := scalafixSemanticdb.revision, - autoAPIMappings := true -) - -lazy val commonScalacOptions = Def.setting { - // Map the sourcemaps to github paths instead of local directories - val localSourcesPath = (LocalRootProject / baseDirectory).value.toURI - val headCommit = git.gitHeadCommit.value.get - scmInfo.value.map { info => - val remoteSourcesPath = - s"${info.browseUrl.toString - .replace("github.com", "raw.githubusercontent.com")}/$headCommit" - s"-scalajs-mapSourceURI:$localSourcesPath->$remoteSourcesPath" - } -} - -lazy val commonJsSettings: Seq[sbt.Def.Setting[?]] = Seq( - Test / scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }, - scalacOptions ++= commonScalacOptions.value -) - -lazy val commonBrowserTestJsSettings: Seq[sbt.Def.Setting[?]] = Seq( - scalacOptions ++= commonScalacOptions.value, - libraryDependencies ++= Seq( - "org.scala-js" %%% "scalajs-dom" % Dependencies.scalajsDomVersion, - "org.typelevel" %%% "cats-effect" % Dependencies.catsEffect, - "io.circe" %%% "circe-core" % Dependencies.circe, - "io.circe" %%% "circe-parser" % Dependencies.circe - ) -) - -lazy val firefoxJsSettings: Seq[sbt.Def.Setting[?]] = Seq( - jsEnv := { - val options = new FirefoxOptions() - options.setHeadless(true) - new SeleniumJSEnv(options) - } -) - -lazy val chromeJsSettings: Seq[sbt.Def.Setting[?]] = Seq( - jsEnv := { - val options = new ChromeOptions() - options.setHeadless(true) - new SeleniumJSEnv(options) - } -) - -lazy val neverPublish = Seq( - publish / skip := true, - publishLocal / skip := true -) - -lazy val publishSettings = { - import xerial.sbt.Sonatype._ - Seq( - publishTo := sonatypePublishToBundle.value, - publishMavenStyle := true, - sonatypeProfileName := "io.indigoengine", - licenses := Seq("MIT" -> url("https://opensource.org/licenses/MIT")), - sonatypeProjectHosting := Some(GitHubHosting("PurpleKingdomGames", "tyrian", "indigo@purplekingdomgames.com")), - developers := List( - Developer( - id = "davesmith00000", - name = "David Smith", - email = "indigo@purplekingdomgames.com", - url = url("https://github.com/davesmith00000") - ) - ), - sonatypeCredentialHost := "oss.sonatype.org", - sonatypeRepository := "https://oss.sonatype.org/service/local" - ) -} - -lazy val tyrianProject = - project - .in(file(".")) - .settings( - neverPublish, - commonSettings, - name := "Tyrian", - usefulTasks := customTasksAliases, - logoSettings(version) - ) - .aggregate( - tyrianTags.js, - tyrianTags.jvm, - tyrian.js, - tyrianIO.js, - tyrianNext.js, - tyrianZIO.js, - sandbox.js, - sandboxNext.js, - sandboxZIO.js, - firefoxTests.js, - chromeTests.js, - tyrianHtmx.js, - tyrianHtmx.jvm, - sandboxSSR.jvm - ) - -lazy val tyrianTags = - crossProject(JSPlatform, JVMPlatform) - .crossType(CrossType.Full) - .in(file("tyrian-tags")) - .settings( - name := "tyrian-tags", - commonSettings ++ publishSettings, - Compile / sourceGenerators += codeGen("tyrian", TagGen.gen).taskValue, - Compile / sourceGenerators += codeGen("tyrian", AttributeGen.gen).taskValue, - Compile / sourceGenerators += codeGen("tyrian", HtmlEntityGen.gen).taskValue, - Compile / sourceGenerators += codeGen("CSS", "tyrian", CSSGen.gen).taskValue - ) - .jsSettings( - commonJsSettings, - libraryDependencies ++= Seq( - "org.scala-js" %%% "scalajs-dom" % Dependencies.scalajsDomVersion - ) - ) - -lazy val tyrian = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .settings( - name := "tyrian", - commonSettings ++ publishSettings - ) - .jsSettings( - commonJsSettings, - libraryDependencies ++= Seq( - "org.typelevel" %%% "cats-effect-kernel" % Dependencies.catsEffect, - "co.fs2" %%% "fs2-core" % Dependencies.fs2, - "io.github.buntec" %%% "scala-js-snabbdom" % Dependencies.scalajsSnabbdom - ) - ) - .dependsOn(tyrianTags) - -lazy val tyrianIO = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .in(file("tyrian-io")) - .settings( - name := "tyrian-io", - commonSettings ++ publishSettings - ) - .jsSettings( - commonJsSettings, - libraryDependencies ++= Seq( - "org.scala-js" %%% "scalajs-dom" % Dependencies.scalajsDomVersion, - "org.typelevel" %%% "cats-effect" % Dependencies.catsEffect - ) - ) - .dependsOn(tyrian) - -lazy val tyrianNext = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .in(file("tyrian-next")) - .settings( - name := "tyrian-next", - commonSettings ++ publishSettings - ) - .jsSettings( - commonJsSettings, - libraryDependencies ++= Seq( - "org.scala-js" %%% "scalajs-dom" % Dependencies.scalajsDomVersion, - "org.typelevel" %%% "cats-effect" % Dependencies.catsEffect - ) - ) - .dependsOn(tyrian) - -lazy val tyrianZIO = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .in(file("tyrian-zio")) - .settings( - name := "tyrian-zio", - commonSettings ++ publishSettings - ) - .jsSettings( - commonJsSettings, - libraryDependencies ++= Seq( - "org.scala-js" %%% "scalajs-dom" % Dependencies.scalajsDomVersion, - "io.github.cquiroz" %%% "scala-java-time" % Dependencies.scalaJavaTime, - "dev.zio" %%% "zio" % Dependencies.zio - ) - ) - .dependsOn(tyrian) - -lazy val sandbox = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .dependsOn(tyrianIO) - .settings( - neverPublish, - commonSettings, - name := "sandbox", - scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }, - scalacOptions -= "-language:strictEquality" - ) - -lazy val sandboxNext = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .in(file("sandbox-next")) - .dependsOn(tyrianNext) - .settings( - neverPublish, - commonSettings, - name := "sandbox-next", - scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }, - scalacOptions -= "-language:strictEquality" - ) - -lazy val sandboxZIO = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .in(file("sandbox-zio")) - .dependsOn(tyrianZIO) - .settings( - neverPublish, - commonSettings, - name := "Sandbox ZIO", - scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }, - libraryDependencies ++= Seq( - "dev.zio" %%% "zio-interop-cats" % Dependencies.zioInteropCats - ), - scalacOptions -= "-language:strictEquality" - ) - -lazy val sandboxSSR = - crossProject(JVMPlatform) - .crossType(CrossType.Pure) - .dependsOn(tyrianTags, tyrianHtmx) - .in(file("sandbox-ssr")) - .settings( - neverPublish, - commonSettings, - name := "sandbox-ssr", - scalacOptions -= "-language:strictEquality", - libraryDependencies ++= Seq( - "org.http4s" %% "http4s-ember-server" % Dependencies.http4sServer, - "org.http4s" %% "http4s-dsl" % Dependencies.http4sServer - ), - run / fork := true - ) - -lazy val firefoxTests = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .in(file("tyrian-firefox-tests")) - .settings( - name := "tyrian-firefox-tests", - neverPublish, - Test / unmanagedSourceDirectories += - (LocalRootProject / baseDirectory).value / "tyrian-browser-tests" / "src" / "test" / "scala", - commonSettings ++ publishSettings ++ firefoxJsSettings - ) - .jsSettings(commonBrowserTestJsSettings) - .dependsOn(tyrian) - -lazy val chromeTests = - crossProject(JSPlatform) - .crossType(CrossType.Pure) - .withoutSuffixFor(JSPlatform) - .in(file("tyrian-chrome-tests")) - .settings( - name := "tyrian-chrome-tests", - neverPublish, - Test / unmanagedSourceDirectories += - (LocalRootProject / baseDirectory).value / "tyrian-browser-tests" / "src" / "test" / "scala", - commonSettings ++ publishSettings ++ chromeJsSettings - ) - .jsSettings(commonBrowserTestJsSettings) - .dependsOn(tyrian) - -lazy val tyrianHtmx = - crossProject(JSPlatform, JVMPlatform) - .crossType(CrossType.Full) - .in(file("tyrian-htmx")) - .settings( - name := "tyrian-htmx", - commonSettings ++ publishSettings, - Compile / sourceGenerators += codeGen( - "tyrian.htmx", - (fullyQualifiedPath, sourceManagedDir) => - List(HtmxAttributes.gen(fullyQualifiedPath, sourceManagedDir)(HtmxAttributes.htmxAttrsList)) - ).taskValue - ) - .jsSettings( - commonJsSettings - ) - .dependsOn(tyrianTags) - -addCommandAlias( - "sandboxBuild", - List( - "sandbox/fastLinkJS" - ).mkString("", ";", ";") -) -addCommandAlias( - "sandboxNextBuild", - List( - "sandboxNext/fastLinkJS" - ).mkString("", ";", ";") -) -addCommandAlias( - "sandboxZIOBuild", - List( - "sandboxZIO/fastLinkJS" - ).mkString("", ";", ";") -) -addCommandAlias( - "sandboxSSRBuild", - List( - "sandboxSSRJVM/compile" - ).mkString("", ";", ";") -) -addCommandAlias( - "sandboxSSRServer", - List( - "sandboxSSRJVM/run" - ).mkString("", ";", ";") -) - -addCommandAlias( - "cleanAll", - List( - "clean", - "tyrianTagsJS/clean", - "tyrianTagsJVM/clean", - "tyrian/clean", - "tyrianIO/clean", - "tyrianNext/clean", - "tyrianZIO/clean", - "sandbox/clean", - "sandboxNext/clean", - "sandboxZIO/clean", - "firefoxTests/clean", - "chromeTests/clean" - ).mkString(";", ";", "") -) - -addCommandAlias( - "compileAll", - List( - "tyrianTagsJS/compile", - "tyrianTagsJVM/compile", - "tyrian/compile", - "tyrianIO/compile", - "tyrianNext/compile", - "tyrianZIO/compile", - "sandbox/compile", - "sandboxNext/compile", - "sandboxZIO/compile" - ).mkString(";", ";", "") -) - -addCommandAlias( - "testAll", - List( - "tyrianTagsJS/test", - "tyrianTagsJVM/test", - "tyrian/test", - "tyrianIO/test", - "tyrianNext/test", - "tyrianZIO/test", - "sandbox/test", - "sandboxNext/test", - "sandboxZIO/test", - "firefoxTests/test", - "chromeTests/test" - ).mkString(";", ";", "") -) - -addCommandAlias( - "testAllUnit", - List( - "tyrianTagsJS/test", - "tyrianTagsJVM/test", - "tyrian/test", - "tyrianIO/test", - "tyrianNext/test", - "tyrianZIO/test", - "sandbox/test", - "sandboxNext/test", - "sandboxZIO/test" - ).mkString(";", ";", "") -) - -addCommandAlias( - "testRelease", - List( - "tyrianTagsJS/test", - "tyrianTagsJVM/test", - "tyrian/test", - "tyrianIO/test", - "tyrianNext/test", - "tyrianZIO/test" - ).mkString(";", ";", "") -) - -addCommandAlias( - "localPublish", - "+publishLocal" -) - -def codeGen(path: String, makeFiles: (String, File) => Seq[File]) = - Def.task(makeFiles(path, (Compile / sourceManaged).value)) - -def codeGen(moduleName: String, path: String, makeFiles: (String, String, File) => Seq[File]) = - Def.task(makeFiles(moduleName, path, (Compile / sourceManaged).value)) diff --git a/build.sh b/build.sh index eb4fc72f..637b11bf 100644 --- a/build.sh +++ b/build.sh @@ -2,4 +2,10 @@ set -e -sbt clean update compile test +publishLocal +./mill clean +./mill __.compile +./mill __.test +./mill __.checkFormat +./mill __.fix --check +./mill -j2 __.fastLinkJS +./mill __.publshLocal diff --git a/flake.nix b/flake.nix index 22a72644..91f0e84b 100644 --- a/flake.nix +++ b/flake.nix @@ -14,22 +14,15 @@ overlays = [ (f: p: { mill = p.mill.override { jre = p.jdk17_headless; }; - sbt = p.sbt.override { jre = p.jdk17_headless; }; }) ]; }; jdk = pkgs.jdk17_headless; - commonInputs = with pkgs; [ - chromedriver - geckodriver - ]; - jvmInputs = with pkgs; [ jdk coursier mill - sbt ]; jvmHook = '' JAVA_HOME="${jdk}" @@ -47,7 +40,7 @@ { devShells.default = pkgs.mkShell { name = "tyrian-dev-shell"; - buildInputs = commonInputs ++ jvmInputs ++ jsInputs; + buildInputs = jvmInputs ++ jsInputs; shellHook = jvmHook + jsHook; }; } diff --git a/localbuild.sh b/localbuild.sh index 8b653a56..b0ff5c61 100644 --- a/localbuild.sh +++ b/localbuild.sh @@ -2,4 +2,8 @@ set -e -sbt clean update compile testAllUnit +publishLocal +./mill clean +./mill __.compile +./mill __.test +./mill -j2 __.fastLinkJS +./mill __.publshLocal \ No newline at end of file diff --git a/mill b/mill new file mode 100755 index 00000000..136be4df --- /dev/null +++ b/mill @@ -0,0 +1,339 @@ +#!/usr/bin/env sh + +# This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages. +# +# 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 frontmatter 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.6 +# +# 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="1.0.6" +fi + + +if [ -z "${GITHUB_RELEASE_CDN}" ] ; then + GITHUB_RELEASE_CDN="" +fi + + +MILL_REPO_URL="https://github.com/com-lihaoyi/mill" + +if [ -z "${CURL_CMD}" ] ; then + CURL_CMD=curl +fi + +# Explicit commandline argument takes precedence over all other methods +if [ "$1" = "--mill-version" ] ; then + 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, +# We reuse it's value and skip searching for a value. + +# If not already set, read .mill-version file +if [ -z "${MILL_VERSION}" ] ; then + if [ -f ".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 + # `s/.*://`: + # This is a greedy match that removes everything from the beginning of the line up to (and including) the last + # colon (:). This effectively isolates the value part of the declaration. + # + # `s/#.*//`: + # This removes any comments at the end of the line. + # + # `s/['\"]//g`: + # This removes all single and double quotes from the string, wherever they appear (g is for "global"). + # + # `s/^[[:space:]]*//; s/[[:space:]]*$//`: + # These two expressions trim any leading or trailing whitespace ([[:space:]] matches spaces and tabs). + MILL_VERSION="$(grep -E "//\|.*mill-version" "${MILL_BUILD_SCRIPT}" | sed -E "s/.*://; s/#.*//; s/['\"]//g; s/^[[:space:]]*//; s/[[:space:]]*$//")" + fi +fi + +MILL_USER_CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/mill" + +if [ -z "${MILL_DOWNLOAD_PATH}" ] ; then + MILL_DOWNLOAD_PATH="${MILL_USER_CACHE_DIR}/download" +fi + +# If not already set, try to fetch newest from Github +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 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 || ( + # we might be on OSX or BSD which don't have -d option for touch + # but probably a -A [-][[hh]mm]SS + touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) || ( + # in case we still failed, we retry the first touch command with the intention + # to show the (previously suppressed) error message + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) + + # POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993 + # if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then + if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then + # we know a current latest version + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # we don't know a current latest version + echo "Retrieving latest mill version ..." 1>&2 + LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest" + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # Last resort + MILL_VERSION="${DEFAULT_MILL_VERSION}" + echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2 + else + echo "Using mill version ${MILL_VERSION}" 1>&2 + fi +fi + +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 + return 0 + fi + + MILL_IN_PATH="$(command -v mill || true)" + + if [ -z "${MILL_IN_PATH}" ]; then + return 0 + fi + + SYSTEM_MILL_FIRST_TWO_BYTES=$(head --bytes=2 "${MILL_IN_PATH}") + if [ "${SYSTEM_MILL_FIRST_TWO_BYTES}" = "#!" ]; then + # MILL_IN_PATH is (very likely) a shell script and not the mill + # executable, ignore it. + return 0 + fi + + SYSTEM_MILL_PATH=$(readlink -e "${MILL_IN_PATH}") + SYSTEM_MILL_SIZE=$(stat --format=%s "${SYSTEM_MILL_PATH}") + SYSTEM_MILL_MTIME=$(stat --format=%y "${SYSTEM_MILL_PATH}") + + if [ ! -d "${MILL_USER_CACHE_DIR}" ]; then + mkdir -p "${MILL_USER_CACHE_DIR}" + fi + + SYSTEM_MILL_INFO_FILE="${MILL_USER_CACHE_DIR}/system-mill-info" + if [ -f "${SYSTEM_MILL_INFO_FILE}" ]; then + parseSystemMillInfo() { + LINE_NUMBER="${1}" + # Select the line number of the SYSTEM_MILL_INFO_FILE, cut the + # variable definition in that line in two halves and return + # the value, and finally remove the quotes. + sed -n "${LINE_NUMBER}p" "${SYSTEM_MILL_INFO_FILE}" |\ + cut -d= -f2 |\ + sed 's/"\(.*\)"/\1/' + } + + CACHED_SYSTEM_MILL_PATH=$(parseSystemMillInfo 1) + CACHED_SYSTEM_MILL_VERSION=$(parseSystemMillInfo 2) + CACHED_SYSTEM_MILL_SIZE=$(parseSystemMillInfo 3) + CACHED_SYSTEM_MILL_MTIME=$(parseSystemMillInfo 4) + + if [ "${SYSTEM_MILL_PATH}" = "${CACHED_SYSTEM_MILL_PATH}" ] \ + && [ "${SYSTEM_MILL_SIZE}" = "${CACHED_SYSTEM_MILL_SIZE}" ] \ + && [ "${SYSTEM_MILL_MTIME}" = "${CACHED_SYSTEM_MILL_MTIME}" ]; then + if [ "${CACHED_SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${SYSTEM_MILL_PATH}" + return 0 + else + return 0 + fi + fi + fi + + SYSTEM_MILL_VERSION=$(${SYSTEM_MILL_PATH} --version | head -n1 | sed -n 's/^Mill.*version \(.*\)/\1/p') + + cat < "${SYSTEM_MILL_INFO_FILE}" +CACHED_SYSTEM_MILL_PATH="${SYSTEM_MILL_PATH}" +CACHED_SYSTEM_MILL_VERSION="${SYSTEM_MILL_VERSION}" +CACHED_SYSTEM_MILL_SIZE="${SYSTEM_MILL_SIZE}" +CACHED_SYSTEM_MILL_MTIME="${SYSTEM_MILL_MTIME}" +EOF + + if [ "${SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${SYSTEM_MILL_PATH}" + fi +} +try_to_use_system_mill + +# If not already downloaded, download it +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 + 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 + + 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 + MILL_MAIN_CLI="${0}" +fi + +MILL_FIRST_ARG="" +if [ "$1" = "--bsp" ] || [ "${1#"-i"}" != "$1" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--no-daemon" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then + # Need to preserve the first position of those listed options + MILL_FIRST_ARG=$1 + shift +fi + +unset MILL_DOWNLOAD_PATH +unset MILL_OLD_DOWNLOAD_PATH +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}" "$@" diff --git a/project/Dependancies.scala b/project/Dependancies.scala deleted file mode 100644 index f25f65ff..00000000 --- a/project/Dependancies.scala +++ /dev/null @@ -1,18 +0,0 @@ -object Dependencies { - - val catsEffect = "3.6.3" - val circe = "0.14.15" - val fs2 = "3.12.2" - val scalajsDomVersion = "2.8.1" - val munitCatsEffect3 = "2.1.0" - val disciplineMUnit = "2.0.0" - val scalajsSnabbdom = "0.2.0-M3" - val zio = "2.1.21" - val zioInteropCats = "23.1.0.5" - val scalaJavaTime = "2.6.0" - val catsLaws = "2.13.0" - val http4sCirce = "0.23.30" - val http4sDom = "0.2.11" - val http4sServer = "0.23.32" - -} diff --git a/project/Misc.scala b/project/Misc.scala deleted file mode 100644 index 58b87eda..00000000 --- a/project/Misc.scala +++ /dev/null @@ -1,40 +0,0 @@ -import sbt.{Def, _} -import sbtwelcome.UsefulTask -import sbtwelcome.WelcomePlugin.autoImport._ - -import scala.sys.process._ - -object Misc { - - lazy val customTasksAliases = Seq( - UsefulTask("cleanAll", "Clean all (JS + JVM)"), - UsefulTask("compileAll", "Compile all (JS + JVM)"), - UsefulTask("testAllUnit", "Test all unit (JS + JVM)"), - UsefulTask("testAll", "Test all (JS + JVM)"), - UsefulTask("localPublish", "Locally publish the core modules (JS + JVM)"), - UsefulTask("sandboxBuild", "Build the sandbox project"), - UsefulTask("sandboxZIOBuild", "Build the zio sandbox project"), - UsefulTask("sandboxSSRBuild", "Build the sandbox SSR project"), - UsefulTask("sandboxSSRServer", "Run the sandbox SSR server"), - UsefulTask("scalafmtCheckAll", "") - ) - - def logoSettings(version: SettingKey[String]): Seq[Def.Setting[String]] = { - val rawLogo: String = - """ - | _____ _ - | |_ _| _ _ _(_)__ _ _ _ - | | || || | '_| / _` | ' \ - | |_| \_, |_| |_\__,_|_||_| - | |__/ - |""".stripMargin - - Seq( - logo := rawLogo + s"version ${version.value}", - logoColor := scala.Console.MAGENTA, - aliasColor := scala.Console.BLUE, - commandColor := scala.Console.CYAN, - descriptionColor := scala.Console.WHITE - ) - } -} diff --git a/project/TyrianVersion.scala b/project/TyrianVersion.scala deleted file mode 100644 index 7556a3fb..00000000 --- a/project/TyrianVersion.scala +++ /dev/null @@ -1,27 +0,0 @@ -object TyrianVersion { - def getVersion: String = { - def rec(path: String, levels: Int, version: Option[String]): String = { - val msg = "ERROR: Couldn't find Tyrian version." - version match { - case Some(v) => - println(s"""Tyrian version set to '$v'""") - v - - case None if levels < 3 => - try { - val v = scala.io.Source.fromFile(path).getLines.toList.head - rec(path, levels, Some(v)) - } catch { - case _: Throwable => - rec("../" + path, levels + 1, None) - } - - case None => - println(msg) - throw new Exception(msg) - } - } - - rec(".tyrian-version", 0, None) - } -} diff --git a/project/build.properties b/project/build.properties deleted file mode 100644 index 01a16ed1..00000000 --- a/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.11.7 diff --git a/project/plugins.sbt b/project/plugins.sbt deleted file mode 100644 index e8c9f480..00000000 --- a/project/plugins.sbt +++ /dev/null @@ -1,12 +0,0 @@ -addSbtPlugin("org.xerial.sbt" %% "sbt-sonatype" % "3.12.2") -addSbtPlugin("com.github.sbt" %% "sbt-pgp" % "2.3.1") -addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.20.1") -addSbtPlugin("org.typelevel" % "sbt-tpolecat" % "0.5.2") -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.14.4") -addSbtPlugin("com.github.reibitto" % "sbt-welcome" % "0.5.0") -addSbtPlugin("com.github.sbt" % "sbt-git" % "2.1.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") -addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.4") - -libraryDependencies += "org.scala-js" %% "scalajs-env-selenium" % "1.1.1" diff --git a/project/project/plugins.sbt b/project/project/plugins.sbt deleted file mode 100644 index 6ddcba50..00000000 --- a/project/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.4") diff --git a/release.sh b/release.sh index 991d9aeb..738616bd 100644 --- a/release.sh +++ b/release.sh @@ -8,4 +8,10 @@ export GPG_TTY=$(tty) source credentials.sh -sbt clean update compile testRelease +publishSigned sonatypeBundleRelease +./mill clean +./mill __.compile +./mill __.test +./mill __.checkFormat +./mill __.fix --check +./mill -j2 __.fastLinkJS +./mill __.publishSonatypeCentral diff --git a/sandbox-next/package.mill b/sandbox-next/package.mill new file mode 100644 index 00000000..63e87d11 --- /dev/null +++ b/sandbox-next/package.mill @@ -0,0 +1,18 @@ +package build.`sandbox-next` + +import mill.* +import mill.scalalib.* +import mill.scalajslib.* +import mill.scalajslib.api.* + +import build.SharedJS +import build.Dependencies + +object `package` extends Module: + + object js extends SharedJS, PlatformScalaModule: + + def moduleDeps = Seq(build.`tyrian-next`.js) + + override def moduleKind = ModuleKind.CommonJSModule + diff --git a/sandbox-next/src/main/scala/example/AppEvent.scala b/sandbox-next/src-js/example/AppEvent.scala similarity index 100% rename from sandbox-next/src/main/scala/example/AppEvent.scala rename to sandbox-next/src-js/example/AppEvent.scala diff --git a/sandbox-next/src/main/scala/example/Counter.scala b/sandbox-next/src-js/example/Counter.scala similarity index 100% rename from sandbox-next/src/main/scala/example/Counter.scala rename to sandbox-next/src-js/example/Counter.scala diff --git a/sandbox-next/src/main/scala/example/CounterManager.scala b/sandbox-next/src-js/example/CounterManager.scala similarity index 100% rename from sandbox-next/src/main/scala/example/CounterManager.scala rename to sandbox-next/src-js/example/CounterManager.scala diff --git a/sandbox-next/src/main/scala/example/MarkerIds.scala b/sandbox-next/src-js/example/MarkerIds.scala similarity index 100% rename from sandbox-next/src/main/scala/example/MarkerIds.scala rename to sandbox-next/src-js/example/MarkerIds.scala diff --git a/sandbox-next/src/main/scala/example/Model.scala b/sandbox-next/src-js/example/Model.scala similarity index 100% rename from sandbox-next/src/main/scala/example/Model.scala rename to sandbox-next/src-js/example/Model.scala diff --git a/sandbox-next/src/main/scala/example/SandboxNext.scala b/sandbox-next/src-js/example/SandboxNext.scala similarity index 100% rename from sandbox-next/src/main/scala/example/SandboxNext.scala rename to sandbox-next/src-js/example/SandboxNext.scala diff --git a/sandbox-next/src/main/scala/example/TextReverse.scala b/sandbox-next/src-js/example/TextReverse.scala similarity index 100% rename from sandbox-next/src/main/scala/example/TextReverse.scala rename to sandbox-next/src-js/example/TextReverse.scala diff --git a/sandbox-next/src/main/scala/example/TopNav.scala b/sandbox-next/src-js/example/TopNav.scala similarity index 100% rename from sandbox-next/src/main/scala/example/TopNav.scala rename to sandbox-next/src-js/example/TopNav.scala diff --git a/sandbox-next/tyrianapp.js b/sandbox-next/tyrianapp.js index c86aa6df..41ba2ada 100644 --- a/sandbox-next/tyrianapp.js +++ b/sandbox-next/tyrianapp.js @@ -1,3 +1,3 @@ -import { TyrianApp } from "./.js/target/scala-3.7.3/sandbox-next-fastopt/main.js"; +import { TyrianApp } from "../out/sandbox-next/js/fastLinkJS.dest/main.js"; TyrianApp.launch("myapp"); diff --git a/sandbox-ssr/package.mill b/sandbox-ssr/package.mill new file mode 100644 index 00000000..687bc21f --- /dev/null +++ b/sandbox-ssr/package.mill @@ -0,0 +1,23 @@ +package build.`sandbox-ssr` + +import mill.* +import mill.scalalib.* +import mill.scalajslib.* + +import build.SharedJVM +import build.Dependencies + +object `package` extends Module: + + object jvm extends SharedJVM, PlatformScalaModule: + + def moduleDeps = Seq( + build.`tyrian-tags`.jvm, + build.`tyrian-htmx`.jvm + ) + + def mvnDeps = Seq( + mvn"org.http4s::http4s-ember-server::${Dependencies.http4sServer}", + mvn"org.http4s::http4s-dsl::${Dependencies.http4sServer}" + ) + diff --git a/sandbox-ssr/.jvm/src/main/scala/example/CorvidDatabase.scala b/sandbox-ssr/src-jvm/example/CorvidDatabase.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/CorvidDatabase.scala rename to sandbox-ssr/src-jvm/example/CorvidDatabase.scala diff --git a/sandbox-ssr/.jvm/src/main/scala/example/GameOfLife.scala b/sandbox-ssr/src-jvm/example/GameOfLife.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/GameOfLife.scala rename to sandbox-ssr/src-jvm/example/GameOfLife.scala diff --git a/sandbox-ssr/.jvm/src/main/scala/example/InfiniteScroll.scala b/sandbox-ssr/src-jvm/example/InfiniteScroll.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/InfiniteScroll.scala rename to sandbox-ssr/src-jvm/example/InfiniteScroll.scala diff --git a/sandbox-ssr/.jvm/src/main/scala/example/Routes.scala b/sandbox-ssr/src-jvm/example/Routes.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/Routes.scala rename to sandbox-ssr/src-jvm/example/Routes.scala diff --git a/sandbox-ssr/.jvm/src/main/scala/example/SandboxSSR.scala b/sandbox-ssr/src-jvm/example/SandboxSSR.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/SandboxSSR.scala rename to sandbox-ssr/src-jvm/example/SandboxSSR.scala diff --git a/sandbox-ssr/.jvm/src/main/scala/example/SearchPage.scala b/sandbox-ssr/src-jvm/example/SearchPage.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/SearchPage.scala rename to sandbox-ssr/src-jvm/example/SearchPage.scala diff --git a/sandbox-ssr/.jvm/src/main/scala/example/TabbedPage.scala b/sandbox-ssr/src-jvm/example/TabbedPage.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/TabbedPage.scala rename to sandbox-ssr/src-jvm/example/TabbedPage.scala diff --git a/sandbox-ssr/.jvm/src/main/scala/example/WebSocketsPage.scala b/sandbox-ssr/src-jvm/example/WebSocketsPage.scala similarity index 100% rename from sandbox-ssr/.jvm/src/main/scala/example/WebSocketsPage.scala rename to sandbox-ssr/src-jvm/example/WebSocketsPage.scala diff --git a/sandbox-zio/package.mill b/sandbox-zio/package.mill new file mode 100644 index 00000000..74c41208 --- /dev/null +++ b/sandbox-zio/package.mill @@ -0,0 +1,22 @@ +package build.`sandbox-zio` + +import mill.* +import mill.scalalib.* +import mill.scalajslib.* +import mill.scalajslib.api.* + +import build.SharedJS +import build.Dependencies + +object `package` extends Module: + + object js extends SharedJS, PlatformScalaModule: + + def moduleDeps = Seq(build.`tyrian-zio`.js) + + def mvnDeps = Seq( + mvn"dev.zio::zio-interop-cats::${Dependencies.zioInteropCats}" + ) + + override def moduleKind = ModuleKind.CommonJSModule + diff --git a/sandbox-zio/src/main/scala/example/SandboxZIO.scala b/sandbox-zio/src-js/example/SandboxZIO.scala similarity index 100% rename from sandbox-zio/src/main/scala/example/SandboxZIO.scala rename to sandbox-zio/src-js/example/SandboxZIO.scala diff --git a/sandbox-zio/tyrianapp.js b/sandbox-zio/tyrianapp.js index b2afb2f7..d575c968 100644 --- a/sandbox-zio/tyrianapp.js +++ b/sandbox-zio/tyrianapp.js @@ -1,3 +1,3 @@ -import { TyrianApp } from "./.js/target/scala-3.7.3/sandbox-zio-fastopt/main.js"; +import { TyrianApp } from "../out/sandbox-zio/js/fastLinkJS.dest/main.js"; TyrianApp.launch("myapp"); diff --git a/sandbox/package.mill b/sandbox/package.mill new file mode 100644 index 00000000..d3e58bea --- /dev/null +++ b/sandbox/package.mill @@ -0,0 +1,17 @@ +package build.sandbox + +import mill.* +import mill.scalalib.* +import mill.scalajslib.* +import mill.scalajslib.api.* + +import build.SharedJS +import build.Dependencies + +object `package` extends Module: + + object js extends SharedJS, PlatformScalaModule: + + def moduleDeps = Seq(build.`tyrian-io`.js) + + override def moduleKind = ModuleKind.CommonJSModule diff --git a/sandbox/src/main/scala/example/Sandbox.scala b/sandbox/src-js/example/Sandbox.scala similarity index 100% rename from sandbox/src/main/scala/example/Sandbox.scala rename to sandbox/src-js/example/Sandbox.scala diff --git a/sandbox/tyrianapp.js b/sandbox/tyrianapp.js index 040557c8..7c976c17 100644 --- a/sandbox/tyrianapp.js +++ b/sandbox/tyrianapp.js @@ -1,4 +1,4 @@ -import { TyrianApp } from "./.js/target/scala-3.7.3/sandbox-fastopt/main.js"; +import { TyrianApp } from "../out/sandbox/js/fastLinkJS.dest/main.js"; TyrianApp.launch(document.getElementById("myapp"), { message: "Hello, Tyrian!", diff --git a/tyrian-browser-tests/src/test/scala/tyrian/HttpTests.scala b/tyrian-browser-tests/src/test/scala/tyrian/HttpTests.scala deleted file mode 100644 index 694e81f3..00000000 --- a/tyrian-browser-tests/src/test/scala/tyrian/HttpTests.scala +++ /dev/null @@ -1,108 +0,0 @@ -package tyrian - -import cats.effect.IO -import io.circe.parser.* -import tyrian.http.* - -import scala.annotation.nowarn - -@nowarn -class HttpTests extends munit.CatsEffectSuite { - - type Msg = Either[HttpError, Response] - private val msgDecoder = Decoder(Right(_), Left(_)) - - private def getBodyData(response: Response): Option[String] = - parse(response.body).toOption - .flatMap(_.hcursor.get[String]("data").toOption) - - private def getBodyHeader(response: Response, header: String): Option[String] = - parse(response.body).toOption - .flatMap(_.hcursor.downField("headers").get[String](header).toOption) - - private def runCmd[Msg](cmd: Cmd[IO, Msg]): IO[Msg] = - cmd match - case c: Cmd.Run[IO, ?, ?] => - c.task.map(c.toMsg) - - case Cmd.Emit(msg) => - IO(msg) - - case _ => - IO.raiseError(new Exception("failed, was not a run task")) - - test("!!!Http tests disabled!!!") { - // These tests work great, but http://httpbin.org is unreliable, it seems. - // So we either need an HTTP mock server compatible with Scala.js, or to use - // containers (I'd rather not, but...). In the meantime these failing tests - // are lowering build confidence, so I've disabled them. - assert(1 == 1) - } - - // test("HEAD") { - // val result = runCmd( - // Http.send( - // Request(Method.Head, "http://httpbin.org/get"), - // msgDecoder - // ) - // ).map(_.toOption.map(_.status)) - - // result.assertEquals(Some(Status(200, "OK"))) - // } - - // test("POST") { - // val result = runCmd( - // Http.send( - // Request(Method.Post, "http://httpbin.org/post", Body.plainText("stuff")), - // msgDecoder - // ) - // ).map(_.toOption.flatMap(getBodyData)) - - // result.assertEquals(Some("stuff")) - // } - - // test("PUT") { - // val result = runCmd( - // Http.send( - // Request(Method.Put, "http://httpbin.org/put", Body.plainText("stuff")), - // msgDecoder - // ) - // ).map(_.toOption.flatMap(getBodyData)) - - // result.assertEquals(Some("stuff")) - // } - - // test("PATCH") { - // val result = runCmd( - // Http.send( - // Request(Method.Patch, "http://httpbin.org/patch", Body.plainText("stuff")), - // msgDecoder - // ) - // ).map(_.toOption.flatMap(getBodyData)) - - // result.assertEquals(Some("stuff")) - // } - - // test("DELETE") { - // val result = runCmd( - // Http.send( - // Request(Method.Delete, "http://httpbin.org/delete", Body.plainText("stuff")), - // msgDecoder - // ) - // ).map(_.toOption.flatMap(getBodyData)) - - // result.assertEquals(Some("stuff")) - // } - - // test("GET with headers") { - // val result = runCmd( - // Http.send( - // Request(Method.Get, "http://httpbin.org/headers").addHeaders(Header("Test-Header", "123")), - // msgDecoder - // ) - // ).map(_.toOption.flatMap(getBodyHeader(_, "Test-Header"))) - - // result - // .assertEquals(Some("123")) - // } -} diff --git a/tyrian-chrome-tests/src/test/scala/tyrian/ChromeTests.scala b/tyrian-chrome-tests/src/test/scala/tyrian/ChromeTests.scala deleted file mode 100644 index e84c3dc5..00000000 --- a/tyrian-chrome-tests/src/test/scala/tyrian/ChromeTests.scala +++ /dev/null @@ -1,31 +0,0 @@ -package tyrian - -import cats.effect.IO -import tyrian.http.* - -class ChromeTests extends munit.CatsEffectSuite { - - type Msg = Either[HttpError, Response] - private val msgDecoder = Decoder(Right(_), Left(_)) - - private def runCmd[Msg](cmd: Cmd[IO, Msg]): IO[Msg] = - cmd match - case c: Cmd.Run[IO, ?, ?] => - c.task.map(c.toMsg) - - case Cmd.Emit(msg) => - IO(msg) - - case _ => - IO.raiseError(new Exception("failed, was not a run task")) - - test("Fail to fetch") { - val result = runCmd( - Http.send( - Request.get("http://whatever:1234"), - msgDecoder - ) - ) - result.map(_.isLeft).assert - } -} diff --git a/tyrian-firefox-tests/src/test/scala/tyrian/FirefoxTests.scala b/tyrian-firefox-tests/src/test/scala/tyrian/FirefoxTests.scala deleted file mode 100644 index 8e70c6dc..00000000 --- a/tyrian-firefox-tests/src/test/scala/tyrian/FirefoxTests.scala +++ /dev/null @@ -1,32 +0,0 @@ -package tyrian - -import cats.effect.IO -import tyrian.http.* - -class FirefoxTests extends munit.CatsEffectSuite { - - type Msg = Either[HttpError, Response] - private val msgDecoder = Decoder(Right(_), Left(_)) - - private def runCmd[Msg](cmd: Cmd[IO, Msg]): IO[Msg] = - cmd match - case c: Cmd.Run[IO, ?, ?] => - c.task.map(c.toMsg) - - case Cmd.Emit(msg) => - IO(msg) - - case _ => - IO.raiseError(new Exception("failed, was not a run task")) - - test("NetworkError") { - val result = runCmd( - Http.send( - Request.get("http://whatever:1234"), - msgDecoder - ) - ) - result - .assertEquals(Left(HttpError.NetworkError)) - } -} diff --git a/project/HtmxAttributes.scala b/tyrian-htmx/HtmxAttributes.mill similarity index 88% rename from project/HtmxAttributes.scala rename to tyrian-htmx/HtmxAttributes.mill index 22ccead4..ff722283 100644 --- a/project/HtmxAttributes.scala +++ b/tyrian-htmx/HtmxAttributes.mill @@ -1,5 +1,11 @@ -import sbt._ -import scala.sys.process._ +package build.`tyrian-htmx` + +import build.`tyrian-tags`.AttributeType +import build.`tyrian-tags`.Normal +import build.`tyrian-tags`.NoValue +import build.`tyrian-tags`.EventEmitting +import build.`tyrian-tags`.AttributeGen +import build.`tyrian-tags`.AttributesList object HtmxAttributes { lazy val htmxAttrs = List( @@ -88,13 +94,13 @@ object HtmxAttributes { |} """.stripMargin - def gen(fullyQualifiedPath: String, sourceManagedDir: File)(attributesList: AttributesList): File = + def gen(fullyQualifiedPath: String, sourceManagedDir: os.Path)(attributesList: AttributesList): os.Path = attributesList match { case AttributesList(attrs, props, name) => - val file: File = + val file: os.Path = sourceManagedDir / s"$name.scala" - if (!file.exists()) { + if (!os.exists(file)) { println("Generating Html Attributes") val contents: String = @@ -107,9 +113,9 @@ object HtmxAttributes { val newContents: String = template(name, fullyQualifiedPath, contents) - IO.write(file, newContents) + os.write(file, newContents) - println("Written: " + file.getCanonicalPath) + println("Written: " + file.toString) } file diff --git a/tyrian-htmx/package.mill b/tyrian-htmx/package.mill new file mode 100644 index 00000000..0af07576 --- /dev/null +++ b/tyrian-htmx/package.mill @@ -0,0 +1,52 @@ +package build.`tyrian-htmx` + +import mill.* +import mill.scalalib.* +import mill.scalalib.publish.* +import mill.scalalib.scalafmt.* +import mill.scalajslib.* + +import build.SharedJVM +import build.SharedJS +import build.SharedPublish +import build.Dependencies + +object `package` extends Module: + + // TODO: Only re-run if not already generated. + private def _customHtmxGeneratedSources = Task { + HtmxAttributes.gen("tyrian.htmx", Task.dest)(HtmxAttributes.htmxAttrsList) + + Seq(PathRef(Task.dest)) + } + + private def moveGeneratedSources(sources: Seq[PathRef], dest: os.Path): Seq[PathRef] = + sources.flatMap: p => + os.list(p.path) + .map: from => + os.copy(from, dest / from.last) + PathRef(dest / from.last) + + object jvm extends SharedJVM, PlatformScalaModule, SharedPublish: + + def moduleDeps = Seq(build.`tyrian-tags`.jvm) + + override def generatedSources = + Task { + super.generatedSources() ++ + moveGeneratedSources(_customHtmxGeneratedSources(), Task.dest) + } + + object js extends SharedJS, PlatformScalaModule, SharedPublish: + + def moduleDeps = Seq(build.`tyrian-tags`.js) + + def mvnDeps = Seq( + mvn"org.scala-js::scalajs-dom::${Dependencies.scalajsDomVersion}" + ) + + override def generatedSources = + Task { + super.generatedSources() ++ + moveGeneratedSources(_customHtmxGeneratedSources(), Task.dest) + } diff --git a/tyrian-htmx/shared/src/main/scala/tyrian/htmx/Event.scala b/tyrian-htmx/src/tyrian/htmx/Event.scala similarity index 100% rename from tyrian-htmx/shared/src/main/scala/tyrian/htmx/Event.scala rename to tyrian-htmx/src/tyrian/htmx/Event.scala diff --git a/tyrian-htmx/shared/src/main/scala/tyrian/htmx/Html.scala b/tyrian-htmx/src/tyrian/htmx/Html.scala similarity index 100% rename from tyrian-htmx/shared/src/main/scala/tyrian/htmx/Html.scala rename to tyrian-htmx/src/tyrian/htmx/Html.scala diff --git a/tyrian-htmx/shared/src/main/scala/tyrian/htmx/Modifier.scala b/tyrian-htmx/src/tyrian/htmx/Modifier.scala similarity index 100% rename from tyrian-htmx/shared/src/main/scala/tyrian/htmx/Modifier.scala rename to tyrian-htmx/src/tyrian/htmx/Modifier.scala diff --git a/tyrian-htmx/shared/src/main/scala/tyrian/htmx/Trigger.scala b/tyrian-htmx/src/tyrian/htmx/Trigger.scala similarity index 100% rename from tyrian-htmx/shared/src/main/scala/tyrian/htmx/Trigger.scala rename to tyrian-htmx/src/tyrian/htmx/Trigger.scala diff --git a/tyrian-io/package.mill b/tyrian-io/package.mill new file mode 100644 index 00000000..b4c90352 --- /dev/null +++ b/tyrian-io/package.mill @@ -0,0 +1,21 @@ +package build.`tyrian-io` + +import mill.* +import mill.scalalib.* +import mill.scalalib.publish.* +import mill.scalalib.scalafmt.* +import mill.scalajslib.* + +import build.SharedJS +import build.SharedPublish +import build.Dependencies + +object `package` extends Module: + + object js extends SharedJS, PlatformScalaModule, SharedPublish: + + def moduleDeps = Seq(build.tyrian.js) + + def mvnDeps = Seq( + mvn"org.typelevel::cats-effect::${Dependencies.catsEffect}" + ) diff --git a/tyrian-io/src/main/scala/tyrian/TyrianIOApp.scala b/tyrian-io/src-js/tyrian/TyrianIOApp.scala similarity index 100% rename from tyrian-io/src/main/scala/tyrian/TyrianIOApp.scala rename to tyrian-io/src-js/tyrian/TyrianIOApp.scala diff --git a/tyrian-next/package.mill b/tyrian-next/package.mill new file mode 100644 index 00000000..2725f438 --- /dev/null +++ b/tyrian-next/package.mill @@ -0,0 +1,21 @@ +package build.`tyrian-next` + +import mill.* +import mill.scalalib.* +import mill.scalalib.publish.* +import mill.scalalib.scalafmt.* +import mill.scalajslib.* + +import build.SharedJS +import build.SharedPublish +import build.Dependencies + +object `package` extends Module: + + object js extends SharedJS, PlatformScalaModule, SharedPublish: + + def moduleDeps = Seq(build.tyrian.js) + + def mvnDeps = Seq( + mvn"org.typelevel::cats-effect::${Dependencies.catsEffect}" + ) diff --git a/tyrian-next/src/main/scala/tyrian/next/Action.scala b/tyrian-next/src-js/tyrian/next/Action.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/Action.scala rename to tyrian-next/src-js/tyrian/next/Action.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/Batch.scala b/tyrian-next/src-js/tyrian/next/Batch.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/Batch.scala rename to tyrian-next/src-js/tyrian/next/Batch.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/GlobalMsg.scala b/tyrian-next/src-js/tyrian/next/GlobalMsg.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/GlobalMsg.scala rename to tyrian-next/src-js/tyrian/next/GlobalMsg.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/HtmlFragment.scala b/tyrian-next/src-js/tyrian/next/HtmlFragment.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/HtmlFragment.scala rename to tyrian-next/src-js/tyrian/next/HtmlFragment.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/HtmlRoot.scala b/tyrian-next/src-js/tyrian/next/HtmlRoot.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/HtmlRoot.scala rename to tyrian-next/src-js/tyrian/next/HtmlRoot.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/Marker.scala b/tyrian-next/src-js/tyrian/next/Marker.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/Marker.scala rename to tyrian-next/src-js/tyrian/next/Marker.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/MarkerId.scala b/tyrian-next/src-js/tyrian/next/MarkerId.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/MarkerId.scala rename to tyrian-next/src-js/tyrian/next/MarkerId.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/Outcome.scala b/tyrian-next/src-js/tyrian/next/Outcome.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/Outcome.scala rename to tyrian-next/src-js/tyrian/next/Outcome.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/TyrianNext.scala b/tyrian-next/src-js/tyrian/next/TyrianNext.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/TyrianNext.scala rename to tyrian-next/src-js/tyrian/next/TyrianNext.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/Watcher.scala b/tyrian-next/src-js/tyrian/next/Watcher.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/Watcher.scala rename to tyrian-next/src-js/tyrian/next/Watcher.scala diff --git a/tyrian-next/src/main/scala/tyrian/next/syntax.scala b/tyrian-next/src-js/tyrian/next/syntax.scala similarity index 100% rename from tyrian-next/src/main/scala/tyrian/next/syntax.scala rename to tyrian-next/src-js/tyrian/next/syntax.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/ActionTests.scala b/tyrian-next/test/src-js/tyrian/next/ActionTests.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/ActionTests.scala rename to tyrian-next/test/src-js/tyrian/next/ActionTests.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/ActionWatchUtils.scala b/tyrian-next/test/src-js/tyrian/next/ActionWatchUtils.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/ActionWatchUtils.scala rename to tyrian-next/test/src-js/tyrian/next/ActionWatchUtils.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/BatchSpecification.scala b/tyrian-next/test/src-js/tyrian/next/BatchSpecification.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/BatchSpecification.scala rename to tyrian-next/test/src-js/tyrian/next/BatchSpecification.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/BatchTests.scala b/tyrian-next/test/src-js/tyrian/next/BatchTests.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/BatchTests.scala rename to tyrian-next/test/src-js/tyrian/next/BatchTests.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/HtmlFragmentTests.scala b/tyrian-next/test/src-js/tyrian/next/HtmlFragmentTests.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/HtmlFragmentTests.scala rename to tyrian-next/test/src-js/tyrian/next/HtmlFragmentTests.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/HtmlRootTests.scala b/tyrian-next/test/src-js/tyrian/next/HtmlRootTests.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/HtmlRootTests.scala rename to tyrian-next/test/src-js/tyrian/next/HtmlRootTests.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/OutcomeTests.scala b/tyrian-next/test/src-js/tyrian/next/OutcomeTests.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/OutcomeTests.scala rename to tyrian-next/test/src-js/tyrian/next/OutcomeTests.scala diff --git a/tyrian-next/src/test/scala/tyrian/next/WatcherTests.scala b/tyrian-next/test/src-js/tyrian/next/WatcherTests.scala similarity index 100% rename from tyrian-next/src/test/scala/tyrian/next/WatcherTests.scala rename to tyrian-next/test/src-js/tyrian/next/WatcherTests.scala diff --git a/project/AttributeGen.scala b/tyrian-tags/AttributeGen.mill similarity index 98% rename from project/AttributeGen.scala rename to tyrian-tags/AttributeGen.mill index e5f37bfc..2e97abc8 100644 --- a/project/AttributeGen.scala +++ b/tyrian-tags/AttributeGen.mill @@ -1,5 +1,4 @@ -import sbt._ -import scala.sys.process._ +package build.`tyrian-tags` object AttributeGen { @@ -73,12 +72,12 @@ object AttributeGen { |} """.stripMargin - def gen(fullyQualifiedPath: String, sourceManagedDir: File): Seq[File] = + def gen(fullyQualifiedPath: String, sourceManagedDir: os.Path): Seq[os.Path] = Seq(htmlAttrsList, svgAttrsList, ariaAttrsList).map { case AttributesList(attrs, props, name) => - val file: File = + val file: os.Path = sourceManagedDir / s"$name.scala" - if (!file.exists()) { + if (!os.exists(file)) { println("Generating Html Attributes") val contents: String = @@ -90,9 +89,9 @@ object AttributeGen { val newContents: String = template(name, fullyQualifiedPath, contents) - IO.write(file, newContents) + os.write(file, newContents) - println("Written: " + file.getCanonicalPath) + println("Written: " + file.toString) } file diff --git a/project/CSSGen.scala b/tyrian-tags/CSSGen.mill similarity index 96% rename from project/CSSGen.scala rename to tyrian-tags/CSSGen.mill index d77ea0cb..dc067c9e 100644 --- a/project/CSSGen.scala +++ b/tyrian-tags/CSSGen.mill @@ -1,5 +1,4 @@ -import sbt._ -import scala.sys.process._ +package build.`tyrian-tags` object CSSGen { @@ -33,11 +32,11 @@ object CSSGen { |} """.stripMargin - def gen(moduleName: String, fullyQualifiedPath: String, sourceManagedDir: File): Seq[File] = { - val file: File = + def gen(moduleName: String, fullyQualifiedPath: String, sourceManagedDir: os.Path): Seq[os.Path] = { + val file: os.Path = sourceManagedDir / (moduleName + ".scala") - if (!file.exists()) { + if (!os.exists(file)) { println("Generating CSS Properties") val contents: String = @@ -46,9 +45,9 @@ object CSSGen { val newContents: String = template(moduleName, fullyQualifiedPath, contents) - IO.write(file, newContents) + os.write(file, newContents) - println("Written: " + file.getCanonicalPath) + println("Written: " + file.toString) } Seq(file) diff --git a/project/CompleteHtmlEntityLists.scala b/tyrian-tags/CompleteHtmlEntityLists.mill similarity index 99% rename from project/CompleteHtmlEntityLists.scala rename to tyrian-tags/CompleteHtmlEntityLists.mill index 51098da7..32d8ed5a 100644 --- a/project/CompleteHtmlEntityLists.scala +++ b/tyrian-tags/CompleteHtmlEntityLists.mill @@ -1,8 +1,15 @@ +package build.`tyrian-tags` + // Exhaustive HTML5 named entity set, as per WHATWG living standard. // Source: https://html.spec.whatwg.org/entities.json object CompleteHtmlEntityLists { - val all: List[(String, String)] = + + // Too long to be compiled in a single list + def all: List[(String, String)] = + part1Uppercase ++ part2Lowercase + + lazy val part1Uppercase: List[(String, String)] = Set( "AElig" -> "\u00C6", "AElig" -> "\u00C6", @@ -637,7 +644,12 @@ object CompleteHtmlEntityLists { "Zeta" -> "\u0396", "Zfr" -> "\u2128", "Zopf" -> "\u2124", - "Zscr" -> "\u1D4B5", + "Zscr" -> "\u1D4B5" + ).toList + + + lazy val part2Lowercase: List[(String, String)] = + Set( "aacute" -> "\u00E1", "aacute" -> "\u00E1", "abreve" -> "\u0103", diff --git a/project/HtmlEntityGen.scala b/tyrian-tags/HtmlEntityGen.mill similarity index 76% rename from project/HtmlEntityGen.scala rename to tyrian-tags/HtmlEntityGen.mill index c92c9334..95fda2fc 100644 --- a/project/HtmlEntityGen.scala +++ b/tyrian-tags/HtmlEntityGen.mill @@ -1,5 +1,4 @@ -import sbt.* -import scala.sys.process.* +package build.`tyrian-tags` object HtmlEntityGen { @@ -12,14 +11,14 @@ object HtmlEntityGen { |} """.stripMargin - def gen(fullyQualifiedPath: String, sourceManagedDir: File): Seq[File] = { + def gen(fullyQualifiedPath: String, sourceManagedDir: os.Path): Seq[os.Path] = { val name = "HtmlEntities" - val file: File = + val file: os.Path = sourceManagedDir / s"$name.scala" - if (!file.exists()) { + if (!os.exists(file)) { println("Generating Html Entities") val contents: String = { @@ -36,9 +35,9 @@ object HtmlEntityGen { val newContents: String = template(name, fullyQualifiedPath, contents) - IO.write(file, newContents) + os.write(file, newContents) - println("Written: " + file.getCanonicalPath) + println("Written: " + file.toString) } Seq(file) diff --git a/project/TagGen.scala b/tyrian-tags/TagGen.mill similarity index 75% rename from project/TagGen.scala rename to tyrian-tags/TagGen.mill index d144c88d..65b5a62a 100644 --- a/project/TagGen.scala +++ b/tyrian-tags/TagGen.mill @@ -1,5 +1,4 @@ -import sbt._ -import scala.sys.process._ +package build.`tyrian-tags` object TagGen { @@ -69,12 +68,12 @@ object TagGen { |} """.stripMargin - def gen(fullyQualifiedPath: String, sourceManagedDir: File): Seq[File] = + def gen(fullyQualifiedPath: String, sourceManagedDir: os.Path): Seq[os.Path] = Seq(htmlTagList, svgTagList).map { case TagList(tags, name) => - val file: File = + val file: os.Path = sourceManagedDir / s"$name.scala" - if (!file.exists()) { + if (!os.exists(file)) { println("Generating Html Tags") val contents: String = @@ -83,9 +82,9 @@ object TagGen { val newContents: String = template(name, fullyQualifiedPath, contents) - IO.write(file, newContents) + os.write(file, newContents) - println("Written: " + file.getCanonicalPath) + println("Written: " + file.toString) } file @@ -207,70 +206,70 @@ object TagGen { HasChildren("wbr") ) - def svgTags: List[TagType] = - List( - NoChildren("animate"), - NoChildren("animateColor"), - NoChildren("animateMotion"), - NoChildren("animateTransform"), - NoChildren("circle"), - HasChildren("clipPath"), - HasChildren("defs"), - HasChildren("desc"), - NoChildren("ellipse"), - NoChildren("feBlend"), - NoChildren("feColorMatrix"), - HasChildren("feComponentTransfer"), - NoChildren("feComposite"), - NoChildren("feConvolveMatrix"), - HasChildren("feDiffuseLighting"), - NoChildren("feDisplacementMap"), - NoChildren("feDistantLight"), - NoChildren("feFlood"), - NoChildren("feFuncA"), - NoChildren("feFuncB"), - NoChildren("feFuncG"), - NoChildren("feFuncR"), - NoChildren("feGaussianBlur"), - NoChildren("feImage"), - HasChildren("feMerge"), - NoChildren("feMergeNode"), - NoChildren("feMorphology"), - NoChildren("feOffset"), - NoChildren("fePointLight"), - HasChildren("feSpecularLighting"), - NoChildren("feSpotLight"), - HasChildren("feTile"), - NoChildren("feTurbulence"), - HasChildren("filter"), - HasChildren("foreignObject"), - HasChildren("g"), - NoChildren("image"), - NoChildren("line"), - HasChildren("linearGradient"), - HasChildren("marker"), - HasChildren("mask"), - HasChildren("metadata"), - NoChildren("mpath"), - NoChildren("path"), - HasChildren("pattern"), - NoChildren("polygon"), - NoChildren("polyline"), - HasChildren("radialGradient"), - NoChildren("rect"), - NoChildren("set"), - NoChildren("stop"), - HasChildren("switch"), - HasChildren("symbol"), - HasChildren("textTag", "text"), - HasChildren("textPath"), - HasChildren("tspan"), - NoChildren("use"), - NoChildren("view") - ) + def svgTags: List[TagType] = + List( + NoChildren("animate"), + NoChildren("animateColor"), + NoChildren("animateMotion"), + NoChildren("animateTransform"), + NoChildren("circle"), + HasChildren("clipPath"), + HasChildren("defs"), + HasChildren("desc"), + NoChildren("ellipse"), + NoChildren("feBlend"), + NoChildren("feColorMatrix"), + HasChildren("feComponentTransfer"), + NoChildren("feComposite"), + NoChildren("feConvolveMatrix"), + HasChildren("feDiffuseLighting"), + NoChildren("feDisplacementMap"), + NoChildren("feDistantLight"), + NoChildren("feFlood"), + NoChildren("feFuncA"), + NoChildren("feFuncB"), + NoChildren("feFuncG"), + NoChildren("feFuncR"), + NoChildren("feGaussianBlur"), + NoChildren("feImage"), + HasChildren("feMerge"), + NoChildren("feMergeNode"), + NoChildren("feMorphology"), + NoChildren("feOffset"), + NoChildren("fePointLight"), + HasChildren("feSpecularLighting"), + NoChildren("feSpotLight"), + HasChildren("feTile"), + NoChildren("feTurbulence"), + HasChildren("filter"), + HasChildren("foreignObject"), + HasChildren("g"), + NoChildren("image"), + NoChildren("line"), + HasChildren("linearGradient"), + HasChildren("marker"), + HasChildren("mask"), + HasChildren("metadata"), + NoChildren("mpath"), + NoChildren("path"), + HasChildren("pattern"), + NoChildren("polygon"), + NoChildren("polyline"), + HasChildren("radialGradient"), + NoChildren("rect"), + NoChildren("set"), + NoChildren("stop"), + HasChildren("switch"), + HasChildren("symbol"), + HasChildren("textTag", "text"), + HasChildren("textPath"), + HasChildren("tspan"), + NoChildren("use"), + NoChildren("view") + ) - def htmlTagList = TagList(htmlTags, "HtmlTags") - def svgTagList = TagList(svgTags, "SVGTags") + def htmlTagList = TagList(htmlTags, "HtmlTags") + def svgTagList = TagList(svgTags, "SVGTags") } sealed trait TagType diff --git a/tyrian-tags/js/src/main/scala/tyrian/syntax.scala b/tyrian-tags/js/src/main/scala/tyrian/syntax.scala deleted file mode 100644 index bd2aabfc..00000000 --- a/tyrian-tags/js/src/main/scala/tyrian/syntax.scala +++ /dev/null @@ -1,11 +0,0 @@ -package tyrian - -import tyrian.Html.text - -object syntax: - - extension [M](oa: Option[Elem[M]]) def orEmpty: Elem[M] = oa.getOrElse(tyrian.Empty) - - given Conversion[String, Text] = text(_) - given Conversion[Int, Text] = n => text(n.toString) - given Conversion[Double, Text] = d => text(d.toString) diff --git a/tyrian-tags/package.mill b/tyrian-tags/package.mill new file mode 100644 index 00000000..a374ea27 --- /dev/null +++ b/tyrian-tags/package.mill @@ -0,0 +1,50 @@ +package build.`tyrian-tags` + +import mill.* +import mill.scalalib.* +import mill.scalalib.publish.* +import mill.scalalib.scalafmt.* +import mill.scalajslib.* + +import build.SharedJVM +import build.SharedJS +import build.SharedPublish +import build.Dependencies + +object `package` extends Module: + + // TODO: Only re-run if not already generated. + private def _customGeneratedSources = Task { + AttributeGen.gen("tyrian", Task.dest) + HtmlEntityGen.gen("tyrian", Task.dest) + CSSGen.gen("CSS", "tyrian", Task.dest) + TagGen.gen("tyrian", Task.dest) + + Seq(PathRef(Task.dest)) + } + + private def moveGeneratedSources(sources: Seq[PathRef], dest: os.Path): Seq[PathRef] = + sources.flatMap: p => + os.list(p.path) + .map: from => + os.copy(from, dest / from.last) + PathRef(dest / from.last) + + object jvm extends SharedJVM, PlatformScalaModule, SharedPublish: + + override def generatedSources = + Task { + super.generatedSources() ++ + moveGeneratedSources(_customGeneratedSources(), Task.dest) + } + + object js extends SharedJS, PlatformScalaModule, SharedPublish: + def mvnDeps = Seq( + mvn"org.scala-js::scalajs-dom::${Dependencies.scalajsDomVersion}" + ) + + override def generatedSources = + Task { + super.generatedSources() ++ + moveGeneratedSources(_customGeneratedSources(), Task.dest) + } diff --git a/tyrian-tags/js/src/main/scala/tyrian/LocationPlatform.scala b/tyrian-tags/src-js/tyrian/LocationPlatform.scala similarity index 100% rename from tyrian-tags/js/src/main/scala/tyrian/LocationPlatform.scala rename to tyrian-tags/src-js/tyrian/LocationPlatform.scala diff --git a/tyrian-tags/js/src/main/scala/tyrian/Tyrian.scala b/tyrian-tags/src-js/tyrian/Tyrian.scala similarity index 100% rename from tyrian-tags/js/src/main/scala/tyrian/Tyrian.scala rename to tyrian-tags/src-js/tyrian/Tyrian.scala diff --git a/tyrian-tags/src-js/tyrian/syntax.scala b/tyrian-tags/src-js/tyrian/syntax.scala new file mode 100644 index 00000000..93095c21 --- /dev/null +++ b/tyrian-tags/src-js/tyrian/syntax.scala @@ -0,0 +1,13 @@ +package tyrian + +import tyrian.Html.text + +object tags: + + object syntax: + + extension [M](oa: Option[Elem[M]]) def orEmpty: Elem[M] = oa.getOrElse(tyrian.Empty) + + given Conversion[String, Text] = text(_) + given Conversion[Int, Text] = n => text(n.toString) + given Conversion[Double, Text] = d => text(d.toString) diff --git a/tyrian-tags/jvm/src/main/scala/tyrian/LocationPlatform.scala b/tyrian-tags/src-jvm/tyrian/LocationPlatform.scala similarity index 100% rename from tyrian-tags/jvm/src/main/scala/tyrian/LocationPlatform.scala rename to tyrian-tags/src-jvm/tyrian/LocationPlatform.scala diff --git a/tyrian-tags/jvm/src/main/scala/tyrian/Tyrian.scala b/tyrian-tags/src-jvm/tyrian/Tyrian.scala similarity index 100% rename from tyrian-tags/jvm/src/main/scala/tyrian/Tyrian.scala rename to tyrian-tags/src-jvm/tyrian/Tyrian.scala diff --git a/tyrian-tags/shared/src/main/scala/tyrian/Attr.scala b/tyrian-tags/src/tyrian/Attr.scala similarity index 100% rename from tyrian-tags/shared/src/main/scala/tyrian/Attr.scala rename to tyrian-tags/src/tyrian/Attr.scala diff --git a/tyrian-tags/shared/src/main/scala/tyrian/HTMLRendering.scala b/tyrian-tags/src/tyrian/HTMLRendering.scala similarity index 100% rename from tyrian-tags/shared/src/main/scala/tyrian/HTMLRendering.scala rename to tyrian-tags/src/tyrian/HTMLRendering.scala diff --git a/tyrian-tags/shared/src/main/scala/tyrian/Html.scala b/tyrian-tags/src/tyrian/Html.scala similarity index 100% rename from tyrian-tags/shared/src/main/scala/tyrian/Html.scala rename to tyrian-tags/src/tyrian/Html.scala diff --git a/tyrian-tags/shared/src/main/scala/tyrian/Location.scala b/tyrian-tags/src/tyrian/Location.scala similarity index 100% rename from tyrian-tags/shared/src/main/scala/tyrian/Location.scala rename to tyrian-tags/src/tyrian/Location.scala diff --git a/tyrian-tags/shared/src/main/scala/tyrian/LocationDetails.scala b/tyrian-tags/src/tyrian/LocationDetails.scala similarity index 100% rename from tyrian-tags/shared/src/main/scala/tyrian/LocationDetails.scala rename to tyrian-tags/src/tyrian/LocationDetails.scala diff --git a/tyrian-tags/shared/src/main/scala/tyrian/Style.scala b/tyrian-tags/src/tyrian/Style.scala similarity index 100% rename from tyrian-tags/shared/src/main/scala/tyrian/Style.scala rename to tyrian-tags/src/tyrian/Style.scala diff --git a/tyrian-tags/js/src/test/scala/tyrian/HtmlTests.scala b/tyrian-tags/test/src-js/tyrian/HtmlTests.scala similarity index 98% rename from tyrian-tags/js/src/test/scala/tyrian/HtmlTests.scala rename to tyrian-tags/test/src-js/tyrian/HtmlTests.scala index d06aed04..e17d1563 100644 --- a/tyrian-tags/js/src/test/scala/tyrian/HtmlTests.scala +++ b/tyrian-tags/test/src-js/tyrian/HtmlTests.scala @@ -85,7 +85,7 @@ class HtmlTests extends munit.FunSuite { } test("literal values : text, number implicit conversion") { - import tyrian.syntax.given + import tyrian.tags.syntax.given trait Msg diff --git a/tyrian-tags/shared/src/test/scala/tyrian/AttrTests.scala b/tyrian-tags/test/src/tyrian/AttrTests.scala similarity index 100% rename from tyrian-tags/shared/src/test/scala/tyrian/AttrTests.scala rename to tyrian-tags/test/src/tyrian/AttrTests.scala diff --git a/tyrian-tags/shared/src/test/scala/tyrian/HTMLRenderingTests.scala b/tyrian-tags/test/src/tyrian/HTMLRenderingTests.scala similarity index 100% rename from tyrian-tags/shared/src/test/scala/tyrian/HTMLRenderingTests.scala rename to tyrian-tags/test/src/tyrian/HTMLRenderingTests.scala diff --git a/tyrian-tags/shared/src/test/scala/tyrian/LocationDetailsTests.scala b/tyrian-tags/test/src/tyrian/LocationDetailsTests.scala similarity index 100% rename from tyrian-tags/shared/src/test/scala/tyrian/LocationDetailsTests.scala rename to tyrian-tags/test/src/tyrian/LocationDetailsTests.scala diff --git a/tyrian-tags/shared/src/test/scala/tyrian/LocationTests.scala b/tyrian-tags/test/src/tyrian/LocationTests.scala similarity index 100% rename from tyrian-tags/shared/src/test/scala/tyrian/LocationTests.scala rename to tyrian-tags/test/src/tyrian/LocationTests.scala diff --git a/tyrian-tags/shared/src/test/scala/tyrian/StyleTests.scala b/tyrian-tags/test/src/tyrian/StyleTests.scala similarity index 100% rename from tyrian-tags/shared/src/test/scala/tyrian/StyleTests.scala rename to tyrian-tags/test/src/tyrian/StyleTests.scala diff --git a/tyrian-zio/package.mill b/tyrian-zio/package.mill new file mode 100644 index 00000000..ba5e0bd0 --- /dev/null +++ b/tyrian-zio/package.mill @@ -0,0 +1,22 @@ +package build.`tyrian-zio` + +import mill.* +import mill.scalalib.* +import mill.scalalib.publish.* +import mill.scalalib.scalafmt.* +import mill.scalajslib.* + +import build.SharedJS +import build.SharedPublish +import build.Dependencies + +object `package` extends Module: + + object js extends SharedJS, PlatformScalaModule, SharedPublish: + + def moduleDeps = Seq(build.tyrian.js) + + def mvnDeps = Seq( + mvn"io.github.cquiroz::scala-java-time::${Dependencies.scalaJavaTime}", + mvn"dev.zio::zio::${Dependencies.zio}" + ) diff --git a/tyrian-zio/src/main/scala/tyrian/TyrianZIOApp.scala b/tyrian-zio/src-js/tyrian/TyrianZIOApp.scala similarity index 100% rename from tyrian-zio/src/main/scala/tyrian/TyrianZIOApp.scala rename to tyrian-zio/src-js/tyrian/TyrianZIOApp.scala diff --git a/tyrian/package.mill b/tyrian/package.mill new file mode 100644 index 00000000..b87b8a2f --- /dev/null +++ b/tyrian/package.mill @@ -0,0 +1,23 @@ +package build.tyrian + +import mill.* +import mill.scalalib.* +import mill.scalalib.publish.* +import mill.scalalib.scalafmt.* +import mill.scalajslib.* + +import build.SharedJS +import build.SharedPublish +import build.Dependencies + +object `package` extends Module: + + object js extends SharedJS, PlatformScalaModule, SharedPublish: + + def moduleDeps = Seq(build.`tyrian-tags`.js) + + def mvnDeps = Seq( + mvn"org.typelevel::cats-effect-kernel::${Dependencies.catsEffect}", + mvn"co.fs2::fs2-core::${Dependencies.fs2}", + mvn"io.github.buntec::scala-js-snabbdom::${Dependencies.scalajsSnabbdom}" + ) diff --git a/tyrian/src/main/scala/tyrian/Cmd.scala b/tyrian/src-js/tyrian/Cmd.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/Cmd.scala rename to tyrian/src-js/tyrian/Cmd.scala diff --git a/tyrian/src/main/scala/tyrian/HotReload.scala b/tyrian/src-js/tyrian/HotReload.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/HotReload.scala rename to tyrian/src-js/tyrian/HotReload.scala diff --git a/tyrian/src/main/scala/tyrian/Nav.scala b/tyrian/src-js/tyrian/Nav.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/Nav.scala rename to tyrian/src-js/tyrian/Nav.scala diff --git a/tyrian/src/main/scala/tyrian/Routing.scala b/tyrian/src-js/tyrian/Routing.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/Routing.scala rename to tyrian/src-js/tyrian/Routing.scala diff --git a/tyrian/src/main/scala/tyrian/Sub.scala b/tyrian/src-js/tyrian/Sub.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/Sub.scala rename to tyrian/src-js/tyrian/Sub.scala diff --git a/tyrian/src/main/scala/tyrian/TyrianApp.scala b/tyrian/src-js/tyrian/TyrianApp.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/TyrianApp.scala rename to tyrian/src-js/tyrian/TyrianApp.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/Dom.scala b/tyrian/src-js/tyrian/cmds/Dom.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/Dom.scala rename to tyrian/src-js/tyrian/cmds/Dom.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/Download.scala b/tyrian/src-js/tyrian/cmds/Download.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/Download.scala rename to tyrian/src-js/tyrian/cmds/Download.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/File.scala b/tyrian/src-js/tyrian/cmds/File.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/File.scala rename to tyrian/src-js/tyrian/cmds/File.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/FileReader.scala b/tyrian/src-js/tyrian/cmds/FileReader.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/FileReader.scala rename to tyrian/src-js/tyrian/cmds/FileReader.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/ImageLoader.scala b/tyrian/src-js/tyrian/cmds/ImageLoader.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/ImageLoader.scala rename to tyrian/src-js/tyrian/cmds/ImageLoader.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/LocalStorage.scala b/tyrian/src-js/tyrian/cmds/LocalStorage.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/LocalStorage.scala rename to tyrian/src-js/tyrian/cmds/LocalStorage.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/Logger.scala b/tyrian/src-js/tyrian/cmds/Logger.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/Logger.scala rename to tyrian/src-js/tyrian/cmds/Logger.scala diff --git a/tyrian/src/main/scala/tyrian/cmds/Random.scala b/tyrian/src-js/tyrian/cmds/Random.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/cmds/Random.scala rename to tyrian/src-js/tyrian/cmds/Random.scala diff --git a/tyrian/src/main/scala/tyrian/http/Decoder.scala b/tyrian/src-js/tyrian/http/Decoder.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/http/Decoder.scala rename to tyrian/src-js/tyrian/http/Decoder.scala diff --git a/tyrian/src/main/scala/tyrian/http/Http.scala b/tyrian/src-js/tyrian/http/Http.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/http/Http.scala rename to tyrian/src-js/tyrian/http/Http.scala diff --git a/tyrian/src/main/scala/tyrian/http/Models.scala b/tyrian/src-js/tyrian/http/Models.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/http/Models.scala rename to tyrian/src-js/tyrian/http/Models.scala diff --git a/tyrian/src/main/scala/tyrian/http/Request.scala b/tyrian/src-js/tyrian/http/Request.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/http/Request.scala rename to tyrian/src-js/tyrian/http/Request.scala diff --git a/tyrian/src/main/scala/tyrian/runtime/CmdHelper.scala b/tyrian/src-js/tyrian/runtime/CmdHelper.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/runtime/CmdHelper.scala rename to tyrian/src-js/tyrian/runtime/CmdHelper.scala diff --git a/tyrian/src/main/scala/tyrian/runtime/Renderer.scala b/tyrian/src-js/tyrian/runtime/Renderer.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/runtime/Renderer.scala rename to tyrian/src-js/tyrian/runtime/Renderer.scala diff --git a/tyrian/src/main/scala/tyrian/runtime/RendererState.scala b/tyrian/src-js/tyrian/runtime/RendererState.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/runtime/RendererState.scala rename to tyrian/src-js/tyrian/runtime/RendererState.scala diff --git a/tyrian/src/main/scala/tyrian/runtime/Rendering.scala b/tyrian/src-js/tyrian/runtime/Rendering.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/runtime/Rendering.scala rename to tyrian/src-js/tyrian/runtime/Rendering.scala diff --git a/tyrian/src/main/scala/tyrian/runtime/SubHelper.scala b/tyrian/src-js/tyrian/runtime/SubHelper.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/runtime/SubHelper.scala rename to tyrian/src-js/tyrian/runtime/SubHelper.scala diff --git a/tyrian/src/main/scala/tyrian/runtime/TyrianRuntime.scala b/tyrian/src-js/tyrian/runtime/TyrianRuntime.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/runtime/TyrianRuntime.scala rename to tyrian/src-js/tyrian/runtime/TyrianRuntime.scala diff --git a/tyrian/src/main/scala/tyrian/syntax.scala b/tyrian/src-js/tyrian/syntax.scala similarity index 87% rename from tyrian/src/main/scala/tyrian/syntax.scala rename to tyrian/src-js/tyrian/syntax.scala index 98665d93..3a3c55df 100644 --- a/tyrian/src/main/scala/tyrian/syntax.scala +++ b/tyrian/src-js/tyrian/syntax.scala @@ -6,6 +6,8 @@ import cats.effect.Sync object syntax: + export tyrian.tags.syntax.* + /** Make a side effect cmd from any `F[Unit]` */ extension [F[_]: Sync](task: F[Unit]) @@ -23,5 +25,3 @@ object syntax: extension [F[_]: Async, A](stream: fs2.Stream[F, A]) def toSub(id: String): Sub[F, A] = Sub.make(id, stream) - - extension [M](oa: Option[Elem[M]]) def orEmpty: Elem[M] = oa.getOrElse(tyrian.Empty) diff --git a/tyrian/src/main/scala/tyrian/websocket/WebSocket.scala b/tyrian/src-js/tyrian/websocket/WebSocket.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/websocket/WebSocket.scala rename to tyrian/src-js/tyrian/websocket/WebSocket.scala diff --git a/tyrian/src/main/scala/tyrian/websocket/WebSocketEvent.scala b/tyrian/src-js/tyrian/websocket/WebSocketEvent.scala similarity index 100% rename from tyrian/src/main/scala/tyrian/websocket/WebSocketEvent.scala rename to tyrian/src-js/tyrian/websocket/WebSocketEvent.scala diff --git a/tyrian/src/main/scala/util/Functions.scala b/tyrian/src-js/util/Functions.scala similarity index 100% rename from tyrian/src/main/scala/util/Functions.scala rename to tyrian/src-js/util/Functions.scala diff --git a/tyrian/src/test/scala/tyrian/CmdLawsTest.scala b/tyrian/test/src-js/tyrian/CmdLawsTest.scala similarity index 100% rename from tyrian/src/test/scala/tyrian/CmdLawsTest.scala rename to tyrian/test/src-js/tyrian/CmdLawsTest.scala diff --git a/tyrian/src/test/scala/tyrian/CmdSubUtils.scala b/tyrian/test/src-js/tyrian/CmdSubUtils.scala similarity index 100% rename from tyrian/src/test/scala/tyrian/CmdSubUtils.scala rename to tyrian/test/src-js/tyrian/CmdSubUtils.scala diff --git a/tyrian/src/test/scala/tyrian/CmdTests.scala b/tyrian/test/src-js/tyrian/CmdTests.scala similarity index 100% rename from tyrian/src/test/scala/tyrian/CmdTests.scala rename to tyrian/test/src-js/tyrian/CmdTests.scala diff --git a/tyrian/src/test/scala/tyrian/SubLawsTest.scala b/tyrian/test/src-js/tyrian/SubLawsTest.scala similarity index 100% rename from tyrian/src/test/scala/tyrian/SubLawsTest.scala rename to tyrian/test/src-js/tyrian/SubLawsTest.scala diff --git a/tyrian/src/test/scala/tyrian/SubTests.scala b/tyrian/test/src-js/tyrian/SubTests.scala similarity index 100% rename from tyrian/src/test/scala/tyrian/SubTests.scala rename to tyrian/test/src-js/tyrian/SubTests.scala diff --git a/tyrian/src/test/scala/tyrian/cmds/RandomTests.scala b/tyrian/test/src-js/tyrian/cmds/RandomTests.scala similarity index 100% rename from tyrian/src/test/scala/tyrian/cmds/RandomTests.scala rename to tyrian/test/src-js/tyrian/cmds/RandomTests.scala From 4468e5a15c1048f8e8c4e390378d5f81d7d482b8 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Thu, 23 Oct 2025 10:10:22 +0100 Subject: [PATCH 02/11] Reduce parallelism in ci builds --- .github/workflows/ci.yml | 2 +- build.sh | 4 +--- ci.sh | 11 +++++++++++ localbuild.sh | 9 --------- 4 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 ci.sh delete mode 100644 localbuild.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a88d452..6fe5f60c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,4 +10,4 @@ jobs: with: java-version: adopt@1.11 - name: Tyrian Compile & Test - run: bash build.sh + run: bash ci.sh diff --git a/build.sh b/build.sh index 637b11bf..6ea6b53a 100644 --- a/build.sh +++ b/build.sh @@ -4,8 +4,6 @@ set -e ./mill clean ./mill __.compile -./mill __.test -./mill __.checkFormat -./mill __.fix --check +./mill -j2 __.test ./mill -j2 __.fastLinkJS ./mill __.publshLocal diff --git a/ci.sh b/ci.sh new file mode 100644 index 00000000..d7b40dc9 --- /dev/null +++ b/ci.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +./mill clean +./mill -j1 __.compile +./mill -j1 __.test +./mill -j1 __.checkFormat +./mill -j1 __.fix --check +./mill -j1 __.fastLinkJS +./mill -j1 __.publshLocal diff --git a/localbuild.sh b/localbuild.sh deleted file mode 100644 index b0ff5c61..00000000 --- a/localbuild.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -e - -./mill clean -./mill __.compile -./mill __.test -./mill -j2 __.fastLinkJS -./mill __.publshLocal \ No newline at end of file From 91744fb1e075f21d8af8ea4d3e8fe934dad4d5da Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Thu, 23 Oct 2025 10:18:11 +0100 Subject: [PATCH 03/11] A typo and a copy+pate fail --- build.sh | 2 +- ci.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 6ea6b53a..6bf083f5 100644 --- a/build.sh +++ b/build.sh @@ -6,4 +6,4 @@ set -e ./mill __.compile ./mill -j2 __.test ./mill -j2 __.fastLinkJS -./mill __.publshLocal +./mill __.publishLocal diff --git a/ci.sh b/ci.sh index d7b40dc9..4e7e7057 100644 --- a/ci.sh +++ b/ci.sh @@ -8,4 +8,4 @@ set -e ./mill -j1 __.checkFormat ./mill -j1 __.fix --check ./mill -j1 __.fastLinkJS -./mill -j1 __.publshLocal +./mill -j1 __.publishLocal From 4d1722b19ac4c56f9ffb0c0ab9abeac476ecd235 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 08:16:18 +0100 Subject: [PATCH 04/11] Tweak ci.sh --- ci.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index 4e7e7057..96089890 100644 --- a/ci.sh +++ b/ci.sh @@ -3,9 +3,8 @@ set -e ./mill clean -./mill -j1 __.compile -./mill -j1 __.test -./mill -j1 __.checkFormat -./mill -j1 __.fix --check +./mill -j2 __.compile ./mill -j1 __.fastLinkJS -./mill -j1 __.publishLocal +./mill -j2 __.test +./mill -j2 __.checkFormat +./mill -j1 __.fix --check From 5c90f5dbd4cbcf81e9da14d622d3e8b55c97f251 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 08:45:42 +0100 Subject: [PATCH 05/11] Breaking up the sandbox module --- build.sh | 4 +- sandbox/src-js/example/Counter.scala | 25 +++ sandbox/src-js/example/Fruit.scala | 3 + sandbox/src-js/example/HttpDetails.scala | 29 +++ sandbox/src-js/example/Model.scala | 66 +++++++ sandbox/src-js/example/Msg.scala | 62 +++++++ sandbox/src-js/example/Page.scala | 24 +++ sandbox/src-js/example/Sandbox.scala | 221 +---------------------- sandbox/src-js/example/Time.scala | 5 + sandbox/src-js/example/Vector2.scala | 3 + sandbox/src-js/example/WSStatus.scala | 13 ++ 11 files changed, 243 insertions(+), 212 deletions(-) create mode 100644 sandbox/src-js/example/Counter.scala create mode 100644 sandbox/src-js/example/Fruit.scala create mode 100644 sandbox/src-js/example/HttpDetails.scala create mode 100644 sandbox/src-js/example/Model.scala create mode 100644 sandbox/src-js/example/Msg.scala create mode 100644 sandbox/src-js/example/Page.scala create mode 100644 sandbox/src-js/example/Time.scala create mode 100644 sandbox/src-js/example/Vector2.scala create mode 100644 sandbox/src-js/example/WSStatus.scala diff --git a/build.sh b/build.sh index 6bf083f5..e1ac1420 100644 --- a/build.sh +++ b/build.sh @@ -4,6 +4,8 @@ set -e ./mill clean ./mill __.compile -./mill -j2 __.test ./mill -j2 __.fastLinkJS +./mill -j2 __.test +./mill -j2 __.checkFormat +./mill -j1 __.fix --check ./mill __.publishLocal diff --git a/sandbox/src-js/example/Counter.scala b/sandbox/src-js/example/Counter.scala new file mode 100644 index 00000000..b71f9b7f --- /dev/null +++ b/sandbox/src-js/example/Counter.scala @@ -0,0 +1,25 @@ +package example + +import tyrian.* +import tyrian.Html.* + +object Counter: + + opaque type Model = Int + + def init: Model = 0 + + enum Msg: + case Increment, Decrement + + def view(model: Model): Html[Msg] = + div( + button(onClick(Msg.Decrement))(text("-")), + div(text(model.toString)), + button(onClick(Msg.Increment))(text("+")) + ) + + def update(msg: Msg, model: Model): Model = + msg match + case Msg.Increment => model + 1 + case Msg.Decrement => model - 1 diff --git a/sandbox/src-js/example/Fruit.scala b/sandbox/src-js/example/Fruit.scala new file mode 100644 index 00000000..4dbb20dd --- /dev/null +++ b/sandbox/src-js/example/Fruit.scala @@ -0,0 +1,3 @@ +package example + +final case class Fruit(name: String, available: Boolean) diff --git a/sandbox/src-js/example/HttpDetails.scala b/sandbox/src-js/example/HttpDetails.scala new file mode 100644 index 00000000..ba626592 --- /dev/null +++ b/sandbox/src-js/example/HttpDetails.scala @@ -0,0 +1,29 @@ +package example + +import tyrian.http.* + +final case class HttpDetails( + method: Method, + url: Option[String], + body: String, + response: Option[Response], + error: Option[String], + timeout: Double, + credentials: RequestCredentials, + headers: List[(String, String)], + cache: RequestCache +) + +object HttpDetails: + val initial: HttpDetails = + HttpDetails( + Method.Get, + Option("http://httpbin.org/get"), + "", + None, + None, + 10000, + RequestCredentials.SameOrigin, + List(), + RequestCache.Default + ) diff --git a/sandbox/src-js/example/Model.scala b/sandbox/src-js/example/Model.scala new file mode 100644 index 00000000..c5bb22e9 --- /dev/null +++ b/sandbox/src-js/example/Model.scala @@ -0,0 +1,66 @@ +package example + +import cats.effect.IO +import tyrian.websocket.* + +import scala.scalajs.js + +final case class Model( + page: Page, + echoSocket: Option[WebSocket[IO]], + socketUrl: String, + field: String, + components: List[Counter.Model], + log: List[String], + error: Option[String], + tmpSaveData: String, + saveData: Option[String], + currentTime: js.Date, + http: HttpDetails, + time: Time, + mousePosition: (Int, Int), + flavour: Option[String], + fruit: List[Fruit], + fruitInput: String, + loadedImage: Option[String], + loadedText: Option[String], + loadedBytes: Option[IArray[Byte]], + imageLoadingUrl: String, + imageLoadingError: Option[String] +) + +object Model: + // val echoServer = "ws://ws.ifelse.io" // public echo server + val echoServer = "ws://localhost:8080/wsecho" + + val init: Model = + Model( + Page.Page1, + None, + echoServer, + "", + Nil, + Nil, + None, + "", + None, + new js.Date(), + HttpDetails.initial, + Time(0.0d, 0.0d), + (0, 0), + None, + Nil, + "", + None, + None, + None, + "https://openmoji.org/php/download_asset.php?type=emoji&emoji_hexcode=1F9A6&emoji_variant=color", + None + ) + + // We're only saving/loading the input field contents as an example + def encode(model: Model): String = model.field + def decode: Option[String] => Either[String, Model] = + case None => Left("No snapshot found") + case Some(data) => + Right(Model.init.copy(field = data)) diff --git a/sandbox/src-js/example/Msg.scala b/sandbox/src-js/example/Msg.scala new file mode 100644 index 00000000..526acae4 --- /dev/null +++ b/sandbox/src-js/example/Msg.scala @@ -0,0 +1,62 @@ +package example + +import org.scalajs.dom +import tyrian.cmds.ImageLoader +import tyrian.http.Response + +import scala.scalajs.js + +enum Msg: + case NewContent(content: String) + case Insert + case Remove + case Modify(i: Int, msg: Counter.Msg) + case FromSocket(message: String) + case ToSocket(message: String) + case FocusOnInputField + case Log(msg: String) + case WebSocketStatus(status: WSStatus) + case Clear + case StageSaveData(content: String) + case Save(key: String, value: String) + case Load(key: String) + case ClearStorage(key: String) + case DataLoaded(data: String) + case NavigateTo(page: Page) + case NavigateToUrl(href: String) + case JumpToHomePage + case OverwriteModel(model: Model) + case TakeSnapshot + case NewTime(time: js.Date) + case MakeHttpRequest + case GotHttpResult(response: Response) + case GotHttpError(message: String) + case UpdateHttpDetails(newUrl: String) + case UpdateHttpBody(body: String) + case UpdateHttpMethod(method: String) + case UpdateHttpCredentials(credentials: String) + case UpdateHttpTimeout(timeout: String) + case UpdateHeaderKey(headerIndex: Int, key: String) + case UpdateHeaderValue(headerIndex: Int, value: String) + case UpdateHeaderAdd + case UpdateHeaderRemove(headerIndex: Int) + case UpdateHttpCache(cache: String) + case FrameTick(runningTime: Double) + case MouseMove(to: (Int, Int)) + case NewFlavour(name: String) + case AddFruit + case UpdateFruitInput(input: String) + case ToggleFruitAvailability(name: String) + case SelectImageFile + case ReadImageFile(file: dom.File) + case FileImageRead(fileData: String) + case SelectTextFile + case ReadTextFile(file: dom.File) + case FileTextRead(fileData: String) + case SelectBytesFile + case ReadBytesFile(file: dom.File) + case FileBytesRead(fileData: IArray[Byte]) + case LoadImage + case UpdateImageUrl(url: String) + case ImageLoaded(result: ImageLoader.Result) + case NoOp diff --git a/sandbox/src-js/example/Page.scala b/sandbox/src-js/example/Page.scala new file mode 100644 index 00000000..ec9c8d55 --- /dev/null +++ b/sandbox/src-js/example/Page.scala @@ -0,0 +1,24 @@ +package example + +enum Page: + case Page1, Page2, Page3, Page4, Page5, Page6, Page7 + + def toNavLabel: String = + this match + case Page1 => "Input fields" + case Page2 => "Counters" + case Page3 => "WebSockets" + case Page4 => "Clock" + case Page5 => "Http" + case Page6 => "Form" + case Page7 => "File Select" + + def toUrlPath: String = + this match + case Page1 => "/page1" + case Page2 => "/page2" + case Page3 => "/page3" + case Page4 => "/page4" + case Page5 => "/page5" + case Page6 => "/page6" + case Page7 => "/page7" diff --git a/sandbox/src-js/example/Sandbox.scala b/sandbox/src-js/example/Sandbox.scala index 3d6a51e7..d1d8ffa0 100644 --- a/sandbox/src-js/example/Sandbox.scala +++ b/sandbox/src-js/example/Sandbox.scala @@ -253,15 +253,15 @@ object Sandbox extends TyrianIOApp[Msg, Model]: (model.copy(components = cs), Cmd.None) - case Msg.WebSocketStatus(Status.ConnectionError(err)) => + case Msg.WebSocketStatus(WSStatus.ConnectionError(err)) => val log = IO.println(s"Failed to open WebSocket connection: $err").toCmd (model.copy(error = Some(err)), log) - case Msg.WebSocketStatus(Status.Connected(ws)) => + case Msg.WebSocketStatus(WSStatus.Connected(ws)) => val log = IO.println("WS connected").toCmd (model.copy(echoSocket = Some(ws)), log) - case Msg.WebSocketStatus(Status.Connecting) => + case Msg.WebSocketStatus(WSStatus.Connecting) => val log = IO.println("Establishing WS connection").toCmd ( model, @@ -272,13 +272,13 @@ object Sandbox extends TyrianIOApp[Msg, Model]: onOpenMessage = "Connect me!", keepAliveSettings = KeepAliveSettings.default ) { - case WebSocketConnect.Error(err) => Status.ConnectionError(err).asMsg - case WebSocketConnect.Socket(ws) => Status.Connected(ws).asMsg + case WebSocketConnect.Error(err) => WSStatus.ConnectionError(err).asMsg + case WebSocketConnect.Socket(ws) => WSStatus.Connected(ws).asMsg } ) ) - case Msg.WebSocketStatus(Status.Disconnecting) => + case Msg.WebSocketStatus(WSStatus.Disconnecting) => val log = IO.println("Graceful shutdown of WS connection").toCmd ( model.copy(echoSocket = None), @@ -288,7 +288,7 @@ object Sandbox extends TyrianIOApp[Msg, Model]: ) ) - case Msg.WebSocketStatus(Status.Disconnected) => + case Msg.WebSocketStatus(WSStatus.Disconnected) => val log = IO.println("WebSocket not connected yet").toCmd (model, log) @@ -420,8 +420,8 @@ object Sandbox extends TyrianIOApp[Msg, Model]: ) ++ counters val connect = - if model.echoSocket.isEmpty then div(myStyle)(button(onClick(Status.Connecting.asMsg))(text("Connect"))) - else div(myStyle)(button(onClick(Status.Disconnecting.asMsg))(text("Disconnect"))) + if model.echoSocket.isEmpty then div(myStyle)(button(onClick(WSStatus.Connecting.asMsg))(text("Connect"))) + else div(myStyle)(button(onClick(WSStatus.Disconnecting.asMsg))(text("Disconnect"))) val contents = model.page match @@ -687,7 +687,7 @@ object Sandbox extends TyrianIOApp[Msg, Model]: def subscriptions(model: Model): Sub[IO, Msg] = val webSocketSubs = - model.echoSocket.fold(Sub.emit[IO, Msg](Status.Disconnected.asMsg)) { + model.echoSocket.fold(Sub.emit[IO, Msg](WSStatus.Disconnected.asMsg)) { _.subscribe { case WebSocketEvent.Error(errorMesage) => Msg.FromSocket(errorMesage) @@ -726,204 +726,3 @@ object Sandbox extends TyrianIOApp[Msg, Model]: Msg.FrameTick(t) } ) - -enum Msg: - case NewContent(content: String) - case Insert - case Remove - case Modify(i: Int, msg: Counter.Msg) - case FromSocket(message: String) - case ToSocket(message: String) - case FocusOnInputField - case Log(msg: String) - case WebSocketStatus(status: Status) - case Clear - case StageSaveData(content: String) - case Save(key: String, value: String) - case Load(key: String) - case ClearStorage(key: String) - case DataLoaded(data: String) - case NavigateTo(page: Page) - case NavigateToUrl(href: String) - case JumpToHomePage - case OverwriteModel(model: Model) - case TakeSnapshot - case NewTime(time: js.Date) - case MakeHttpRequest - case GotHttpResult(response: Response) - case GotHttpError(message: String) - case UpdateHttpDetails(newUrl: String) - case UpdateHttpBody(body: String) - case UpdateHttpMethod(method: String) - case UpdateHttpCredentials(credentials: String) - case UpdateHttpTimeout(timeout: String) - case UpdateHeaderKey(headerIndex: Int, key: String) - case UpdateHeaderValue(headerIndex: Int, value: String) - case UpdateHeaderAdd - case UpdateHeaderRemove(headerIndex: Int) - case UpdateHttpCache(cache: String) - case FrameTick(runningTime: Double) - case MouseMove(to: (Int, Int)) - case NewFlavour(name: String) - case AddFruit - case UpdateFruitInput(input: String) - case ToggleFruitAvailability(name: String) - case SelectImageFile - case ReadImageFile(file: dom.File) - case FileImageRead(fileData: String) - case SelectTextFile - case ReadTextFile(file: dom.File) - case FileTextRead(fileData: String) - case SelectBytesFile - case ReadBytesFile(file: dom.File) - case FileBytesRead(fileData: IArray[Byte]) - case LoadImage - case UpdateImageUrl(url: String) - case ImageLoaded(result: ImageLoader.Result) - case NoOp - -enum Status: - case Connecting - case Connected(ws: WebSocket[IO]) - case ConnectionError(msg: String) - case Disconnecting - case Disconnected - - def asMsg: Msg = Msg.WebSocketStatus(this) - -object Counter: - - opaque type Model = Int - - def init: Model = 0 - - enum Msg: - case Increment, Decrement - - def view(model: Model): Html[Msg] = - div( - button(onClick(Msg.Decrement))(text("-")), - div(text(model.toString)), - button(onClick(Msg.Increment))(text("+")) - ) - - def update(msg: Msg, model: Model): Model = - msg match - case Msg.Increment => model + 1 - case Msg.Decrement => model - 1 - -final case class Model( - page: Page, - echoSocket: Option[WebSocket[IO]], - socketUrl: String, - field: String, - components: List[Counter.Model], - log: List[String], - error: Option[String], - tmpSaveData: String, - saveData: Option[String], - currentTime: js.Date, - http: HttpDetails, - time: Time, - mousePosition: (Int, Int), - flavour: Option[String], - fruit: List[Fruit], - fruitInput: String, - loadedImage: Option[String], - loadedText: Option[String], - loadedBytes: Option[IArray[Byte]], - imageLoadingUrl: String, - imageLoadingError: Option[String] -) - -final case class Fruit(name: String, available: Boolean) - -final case class Time(running: Double, delta: Double): - def next(t: Double): Time = - this.copy(running = t, delta = t - running) - -enum Page: - case Page1, Page2, Page3, Page4, Page5, Page6, Page7 - - def toNavLabel: String = - this match - case Page1 => "Input fields" - case Page2 => "Counters" - case Page3 => "WebSockets" - case Page4 => "Clock" - case Page5 => "Http" - case Page6 => "Form" - case Page7 => "File Select" - - def toUrlPath: String = - this match - case Page1 => "/page1" - case Page2 => "/page2" - case Page3 => "/page3" - case Page4 => "/page4" - case Page5 => "/page5" - case Page6 => "/page6" - case Page7 => "/page7" - -object Model: - // val echoServer = "ws://ws.ifelse.io" // public echo server - val echoServer = "ws://localhost:8080/wsecho" - - val init: Model = - Model( - Page.Page1, - None, - echoServer, - "", - Nil, - Nil, - None, - "", - None, - new js.Date(), - HttpDetails.initial, - Time(0.0d, 0.0d), - (0, 0), - None, - Nil, - "", - None, - None, - None, - "https://openmoji.org/php/download_asset.php?type=emoji&emoji_hexcode=1F9A6&emoji_variant=color", - None - ) - - // We're only saving/loading the input field contents as an example - def encode(model: Model): String = model.field - def decode: Option[String] => Either[String, Model] = - case None => Left("No snapshot found") - case Some(data) => - Right(Model.init.copy(field = data)) - -final case class HttpDetails( - method: Method, - url: Option[String], - body: String, - response: Option[Response], - error: Option[String], - timeout: Double, - credentials: RequestCredentials, - headers: List[(String, String)], - cache: RequestCache -) -object HttpDetails: - val initial: HttpDetails = - HttpDetails( - Method.Get, - Option("http://httpbin.org/get"), - "", - None, - None, - 10000, - RequestCredentials.SameOrigin, - List(), - RequestCache.Default - ) - -final case class Vector2(x: Double, y: Double) diff --git a/sandbox/src-js/example/Time.scala b/sandbox/src-js/example/Time.scala new file mode 100644 index 00000000..ff4f86f3 --- /dev/null +++ b/sandbox/src-js/example/Time.scala @@ -0,0 +1,5 @@ +package example + +final case class Time(running: Double, delta: Double): + def next(t: Double): Time = + this.copy(running = t, delta = t - running) diff --git a/sandbox/src-js/example/Vector2.scala b/sandbox/src-js/example/Vector2.scala new file mode 100644 index 00000000..45904e25 --- /dev/null +++ b/sandbox/src-js/example/Vector2.scala @@ -0,0 +1,3 @@ +package example + +final case class Vector2(x: Double, y: Double) diff --git a/sandbox/src-js/example/WSStatus.scala b/sandbox/src-js/example/WSStatus.scala new file mode 100644 index 00000000..bd4f4f08 --- /dev/null +++ b/sandbox/src-js/example/WSStatus.scala @@ -0,0 +1,13 @@ +package example + +import cats.effect.IO +import tyrian.websocket.WebSocket + +enum WSStatus: + case Connecting + case Connected(ws: WebSocket[IO]) + case ConnectionError(msg: String) + case Disconnecting + case Disconnected + + def asMsg: Msg = Msg.WebSocketStatus(this) From 170da9a307bef0eef458741f9955bdd94be7783b Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 08:59:45 +0100 Subject: [PATCH 06/11] Moving sandbox modules to a sub package --- sandbox/src-js/example/Model.scala | 4 ++++ sandbox/src-js/example/Msg.scala | 2 ++ sandbox/src-js/example/Sandbox.scala | 4 ++++ sandbox/src-js/example/{ => models}/Fruit.scala | 2 +- sandbox/src-js/example/{ => models}/HttpDetails.scala | 2 +- sandbox/src-js/example/{ => models}/Page.scala | 2 +- sandbox/src-js/example/{ => models}/Time.scala | 2 +- sandbox/src-js/example/{ => models}/Vector2.scala | 2 +- sandbox/src-js/example/{ => models}/WSStatus.scala | 3 ++- 9 files changed, 17 insertions(+), 6 deletions(-) rename sandbox/src-js/example/{ => models}/Fruit.scala (71%) rename sandbox/src-js/example/{ => models}/HttpDetails.scala (96%) rename sandbox/src-js/example/{ => models}/Page.scala (96%) rename sandbox/src-js/example/{ => models}/Time.scala (85%) rename sandbox/src-js/example/{ => models}/Vector2.scala (67%) rename sandbox/src-js/example/{ => models}/WSStatus.scala (85%) diff --git a/sandbox/src-js/example/Model.scala b/sandbox/src-js/example/Model.scala index c5bb22e9..b76dcfab 100644 --- a/sandbox/src-js/example/Model.scala +++ b/sandbox/src-js/example/Model.scala @@ -2,6 +2,10 @@ package example import cats.effect.IO import tyrian.websocket.* +import example.models.Fruit +import example.models.Time +import example.models.HttpDetails +import example.models.Page import scala.scalajs.js diff --git a/sandbox/src-js/example/Msg.scala b/sandbox/src-js/example/Msg.scala index 526acae4..bac91aa8 100644 --- a/sandbox/src-js/example/Msg.scala +++ b/sandbox/src-js/example/Msg.scala @@ -5,6 +5,8 @@ import tyrian.cmds.ImageLoader import tyrian.http.Response import scala.scalajs.js +import example.models.WSStatus +import example.models.Page enum Msg: case NewContent(content: String) diff --git a/sandbox/src-js/example/Sandbox.scala b/sandbox/src-js/example/Sandbox.scala index d1d8ffa0..89512b42 100644 --- a/sandbox/src-js/example/Sandbox.scala +++ b/sandbox/src-js/example/Sandbox.scala @@ -15,6 +15,10 @@ import scala.concurrent.duration.* import scala.scalajs.js import scala.scalajs.js.annotation.* import scala.util.Random +import example.models.Fruit +import example.models.Vector2 +import example.models.WSStatus +import example.models.Page @JSExportTopLevel("TyrianApp") object Sandbox extends TyrianIOApp[Msg, Model]: diff --git a/sandbox/src-js/example/Fruit.scala b/sandbox/src-js/example/models/Fruit.scala similarity index 71% rename from sandbox/src-js/example/Fruit.scala rename to sandbox/src-js/example/models/Fruit.scala index 4dbb20dd..10664156 100644 --- a/sandbox/src-js/example/Fruit.scala +++ b/sandbox/src-js/example/models/Fruit.scala @@ -1,3 +1,3 @@ -package example +package example.models final case class Fruit(name: String, available: Boolean) diff --git a/sandbox/src-js/example/HttpDetails.scala b/sandbox/src-js/example/models/HttpDetails.scala similarity index 96% rename from sandbox/src-js/example/HttpDetails.scala rename to sandbox/src-js/example/models/HttpDetails.scala index ba626592..5d114e05 100644 --- a/sandbox/src-js/example/HttpDetails.scala +++ b/sandbox/src-js/example/models/HttpDetails.scala @@ -1,4 +1,4 @@ -package example +package example.models import tyrian.http.* diff --git a/sandbox/src-js/example/Page.scala b/sandbox/src-js/example/models/Page.scala similarity index 96% rename from sandbox/src-js/example/Page.scala rename to sandbox/src-js/example/models/Page.scala index ec9c8d55..6d5f682f 100644 --- a/sandbox/src-js/example/Page.scala +++ b/sandbox/src-js/example/models/Page.scala @@ -1,4 +1,4 @@ -package example +package example.models enum Page: case Page1, Page2, Page3, Page4, Page5, Page6, Page7 diff --git a/sandbox/src-js/example/Time.scala b/sandbox/src-js/example/models/Time.scala similarity index 85% rename from sandbox/src-js/example/Time.scala rename to sandbox/src-js/example/models/Time.scala index ff4f86f3..3d02286e 100644 --- a/sandbox/src-js/example/Time.scala +++ b/sandbox/src-js/example/models/Time.scala @@ -1,4 +1,4 @@ -package example +package example.models final case class Time(running: Double, delta: Double): def next(t: Double): Time = diff --git a/sandbox/src-js/example/Vector2.scala b/sandbox/src-js/example/models/Vector2.scala similarity index 67% rename from sandbox/src-js/example/Vector2.scala rename to sandbox/src-js/example/models/Vector2.scala index 45904e25..38f85025 100644 --- a/sandbox/src-js/example/Vector2.scala +++ b/sandbox/src-js/example/models/Vector2.scala @@ -1,3 +1,3 @@ -package example +package example.models final case class Vector2(x: Double, y: Double) diff --git a/sandbox/src-js/example/WSStatus.scala b/sandbox/src-js/example/models/WSStatus.scala similarity index 85% rename from sandbox/src-js/example/WSStatus.scala rename to sandbox/src-js/example/models/WSStatus.scala index bd4f4f08..1799a676 100644 --- a/sandbox/src-js/example/WSStatus.scala +++ b/sandbox/src-js/example/models/WSStatus.scala @@ -1,7 +1,8 @@ -package example +package example.models import cats.effect.IO import tyrian.websocket.WebSocket +import example.Msg enum WSStatus: case Connecting From d27f867e83411411fa2e696e44f83b843dee1897 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 09:00:52 +0100 Subject: [PATCH 07/11] Scalafmt/Scalafix --- sandbox/src-js/example/Model.scala | 4 ++-- sandbox/src-js/example/Msg.scala | 4 ++-- sandbox/src-js/example/Sandbox.scala | 8 ++++---- sandbox/src-js/example/models/WSStatus.scala | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sandbox/src-js/example/Model.scala b/sandbox/src-js/example/Model.scala index b76dcfab..5d3e24fe 100644 --- a/sandbox/src-js/example/Model.scala +++ b/sandbox/src-js/example/Model.scala @@ -1,11 +1,11 @@ package example import cats.effect.IO -import tyrian.websocket.* import example.models.Fruit -import example.models.Time import example.models.HttpDetails import example.models.Page +import example.models.Time +import tyrian.websocket.* import scala.scalajs.js diff --git a/sandbox/src-js/example/Msg.scala b/sandbox/src-js/example/Msg.scala index bac91aa8..1972ce38 100644 --- a/sandbox/src-js/example/Msg.scala +++ b/sandbox/src-js/example/Msg.scala @@ -1,12 +1,12 @@ package example +import example.models.Page +import example.models.WSStatus import org.scalajs.dom import tyrian.cmds.ImageLoader import tyrian.http.Response import scala.scalajs.js -import example.models.WSStatus -import example.models.Page enum Msg: case NewContent(content: String) diff --git a/sandbox/src-js/example/Sandbox.scala b/sandbox/src-js/example/Sandbox.scala index 89512b42..b746eaae 100644 --- a/sandbox/src-js/example/Sandbox.scala +++ b/sandbox/src-js/example/Sandbox.scala @@ -1,6 +1,10 @@ package example import cats.effect.IO +import example.models.Fruit +import example.models.Page +import example.models.Vector2 +import example.models.WSStatus import org.scalajs.dom import org.scalajs.dom.document import tyrian.* @@ -15,10 +19,6 @@ import scala.concurrent.duration.* import scala.scalajs.js import scala.scalajs.js.annotation.* import scala.util.Random -import example.models.Fruit -import example.models.Vector2 -import example.models.WSStatus -import example.models.Page @JSExportTopLevel("TyrianApp") object Sandbox extends TyrianIOApp[Msg, Model]: diff --git a/sandbox/src-js/example/models/WSStatus.scala b/sandbox/src-js/example/models/WSStatus.scala index 1799a676..0a6d606b 100644 --- a/sandbox/src-js/example/models/WSStatus.scala +++ b/sandbox/src-js/example/models/WSStatus.scala @@ -1,8 +1,8 @@ package example.models import cats.effect.IO -import tyrian.websocket.WebSocket import example.Msg +import tyrian.websocket.WebSocket enum WSStatus: case Connecting From b70e3abfd7cce9eca4bf3b00d6708bbabb5b2a96 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 09:09:53 +0100 Subject: [PATCH 08/11] Change CI trigger --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fe5f60c..f5fd6d01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,9 @@ name: CI -on: [workflow_dispatch, push, pull_request] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] jobs: build: runs-on: ubuntu-latest From b5737236df0a0816688a11debedb8ee2844e9bf7 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 09:10:04 +0100 Subject: [PATCH 09/11] Sandbox emits an ESModule --- sandbox/package.mill | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sandbox/package.mill b/sandbox/package.mill index d3e58bea..852f1167 100644 --- a/sandbox/package.mill +++ b/sandbox/package.mill @@ -14,4 +14,4 @@ object `package` extends Module: def moduleDeps = Seq(build.`tyrian-io`.js) - override def moduleKind = ModuleKind.CommonJSModule + override def moduleKind = ModuleKind.ESModule From 2c4dace65e9526c7f6c19b40845bfe221a8a77db Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 09:31:50 +0100 Subject: [PATCH 10/11] More CI tuning --- .github/workflows/ci.yml | 2 ++ ci.sh | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5fd6d01..8c1643a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,8 @@ on: jobs: build: runs-on: ubuntu-latest + env: + JAVA_OPTS: -Xmx4G -XX:+UseG1GC steps: - uses: actions/checkout@v4 - uses: coursier/cache-action@v6 diff --git a/ci.sh b/ci.sh index 96089890..be299b40 100644 --- a/ci.sh +++ b/ci.sh @@ -2,9 +2,9 @@ set -e -./mill clean -./mill -j2 __.compile -./mill -j1 __.fastLinkJS -./mill -j2 __.test -./mill -j2 __.checkFormat -./mill -j1 __.fix --check +./mill --no-server --disable-ticker clean +./mill --no-server --disable-ticker -j2 __.compile +./mill --no-server --disable-ticker -j1 __.fastLinkJS +./mill --no-server --disable-ticker -j2 __.test +./mill --no-server --disable-ticker -j2 __.checkFormat +./mill --no-server --disable-ticker -j1 __.fix --check From 48f1fb7156938126ba5220fb398e4b34242683e9 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Fri, 24 Oct 2025 09:40:22 +0100 Subject: [PATCH 11/11] Add Xss 8m for larger thread stack --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c1643a7..5b340c49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: build: runs-on: ubuntu-latest env: - JAVA_OPTS: -Xmx4G -XX:+UseG1GC + JAVA_OPTS: -Xmx4G -Xss8m -XX:+UseG1GC steps: - uses: actions/checkout@v4 - uses: coursier/cache-action@v6